2017-08-29 13:18:28 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
using BizHawk.Common;
|
|
|
|
|
using BizHawk.Emulation.Common;
|
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Represents a GB add on
|
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IPort
|
|
|
|
|
{
|
|
|
|
|
byte Read(IController c);
|
|
|
|
|
|
2018-04-03 22:18:41 +00:00
|
|
|
|
ushort ReadAccX(IController c);
|
|
|
|
|
|
|
|
|
|
ushort ReadAccY(IController c);
|
|
|
|
|
|
2017-08-29 13:18:28 +00:00
|
|
|
|
ControllerDefinition Definition { get; }
|
|
|
|
|
|
|
|
|
|
void SyncState(Serializer ser);
|
|
|
|
|
|
|
|
|
|
int PortNum { get; }
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-19 20:16:15 +00:00
|
|
|
|
[DisplayName("Gameboy Controller")]
|
2017-08-29 13:18:28 +00:00
|
|
|
|
public class StandardControls : IPort
|
|
|
|
|
{
|
|
|
|
|
public StandardControls(int portNum)
|
|
|
|
|
{
|
|
|
|
|
PortNum = portNum;
|
|
|
|
|
Definition = new ControllerDefinition
|
|
|
|
|
{
|
2018-10-08 23:54:12 +00:00
|
|
|
|
Name = "Gameboy Controller H",
|
2017-08-29 13:18:28 +00:00
|
|
|
|
BoolButtons = BaseDefinition
|
|
|
|
|
.Select(b => "P" + PortNum + " " + b)
|
|
|
|
|
.ToList()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int PortNum { get; }
|
|
|
|
|
|
|
|
|
|
public ControllerDefinition Definition { get; }
|
|
|
|
|
|
|
|
|
|
public byte Read(IController c)
|
|
|
|
|
{
|
|
|
|
|
byte result = 0xFF;
|
2018-01-17 22:17:43 +00:00
|
|
|
|
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[0]))
|
|
|
|
|
{
|
|
|
|
|
result -= 4;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[1]))
|
|
|
|
|
{
|
|
|
|
|
result -= 8;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[2]))
|
|
|
|
|
{
|
|
|
|
|
result -= 2;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[3]))
|
|
|
|
|
{
|
|
|
|
|
result -= 1;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[4]))
|
|
|
|
|
{
|
|
|
|
|
result -= 128;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[5]))
|
|
|
|
|
{
|
|
|
|
|
result -= 64;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[6]))
|
|
|
|
|
{
|
|
|
|
|
result -= 32;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[7]))
|
2017-08-29 13:18:28 +00:00
|
|
|
|
{
|
2018-01-17 22:17:43 +00:00
|
|
|
|
result -= 16;
|
2017-08-29 13:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-03 22:18:41 +00:00
|
|
|
|
public ushort ReadAccX(IController c)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ushort ReadAccY(IController c)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static readonly string[] BaseDefinition =
|
|
|
|
|
{
|
|
|
|
|
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public void SyncState(Serializer ser)
|
|
|
|
|
{
|
|
|
|
|
//nothing
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-28 17:14:40 +00:00
|
|
|
|
[DisplayName("Gameboy Controller + Tilt")]
|
|
|
|
|
public class StandardTilt : IPort
|
2018-04-03 22:18:41 +00:00
|
|
|
|
{
|
2018-05-28 17:14:40 +00:00
|
|
|
|
public StandardTilt(int portNum)
|
2018-04-03 22:18:41 +00:00
|
|
|
|
{
|
|
|
|
|
PortNum = portNum;
|
|
|
|
|
Definition = new ControllerDefinition
|
|
|
|
|
{
|
2018-05-28 17:14:40 +00:00
|
|
|
|
Name = "Gameboy Controller + Tilt",
|
2018-04-03 22:18:41 +00:00
|
|
|
|
BoolButtons = BaseDefinition
|
|
|
|
|
.Select(b => "P" + PortNum + " " + b)
|
|
|
|
|
.ToList(),
|
|
|
|
|
FloatControls = { "P" + PortNum + " Tilt X", "P" + PortNum + " Tilt Y" },
|
2018-04-06 23:11:21 +00:00
|
|
|
|
FloatRanges = { new[] { -45.0f, 0, 45.0f }, new[] { -45.0f, 0, 45.0f } }
|
2018-04-03 22:18:41 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int PortNum { get; }
|
|
|
|
|
|
2018-05-28 17:14:40 +00:00
|
|
|
|
public float theta, phi, theta_prev, phi_prev;
|
|
|
|
|
|
2018-04-03 22:18:41 +00:00
|
|
|
|
public ControllerDefinition Definition { get; }
|
|
|
|
|
|
|
|
|
|
public byte Read(IController c)
|
|
|
|
|
{
|
|
|
|
|
byte result = 0xFF;
|
|
|
|
|
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[0]))
|
|
|
|
|
{
|
|
|
|
|
result -= 4;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[1]))
|
|
|
|
|
{
|
|
|
|
|
result -= 8;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[2]))
|
|
|
|
|
{
|
|
|
|
|
result -= 2;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[3]))
|
|
|
|
|
{
|
|
|
|
|
result -= 1;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[4]))
|
|
|
|
|
{
|
|
|
|
|
result -= 128;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[5]))
|
|
|
|
|
{
|
|
|
|
|
result -= 64;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[6]))
|
|
|
|
|
{
|
|
|
|
|
result -= 32;
|
|
|
|
|
}
|
|
|
|
|
if (c.IsPressed(Definition.BoolButtons[7]))
|
|
|
|
|
{
|
|
|
|
|
result -= 16;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-06 23:11:21 +00:00
|
|
|
|
// acc x is the result of rotating around body y AFTER rotating around body x
|
|
|
|
|
// therefore this control scheme gives decreasing sensitivity in X as Y rotation inscreases
|
2018-04-03 22:18:41 +00:00
|
|
|
|
public ushort ReadAccX(IController c)
|
|
|
|
|
{
|
2018-05-28 17:14:40 +00:00
|
|
|
|
theta_prev = theta;
|
|
|
|
|
phi_prev = phi;
|
|
|
|
|
|
|
|
|
|
theta = (float)(c.GetFloat(Definition.FloatControls[1]) * Math.PI / 180.0);
|
|
|
|
|
phi = (float)(c.GetFloat(Definition.FloatControls[0]) * Math.PI / 180.0);
|
2018-04-06 23:11:21 +00:00
|
|
|
|
|
|
|
|
|
float temp = (float)(Math.Cos(theta) * Math.Sin(phi));
|
|
|
|
|
|
2018-05-28 17:14:40 +00:00
|
|
|
|
// here we add in rates of change parameters.
|
|
|
|
|
// a typical rate of change for a fast rotation is guessed at 0.5 rad / frame
|
|
|
|
|
// since rotations about X have less of a moment arm compared to by, we take 1/5 of the effect as a baseline
|
|
|
|
|
float temp2 = (float)((phi - phi_prev) / 0.5 * 25);
|
|
|
|
|
|
|
|
|
|
return (ushort)(0x81D0 - Math.Floor(temp * 125) - temp2);
|
2018-04-03 22:18:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-06 23:11:21 +00:00
|
|
|
|
// acc y is just the sine of the angle
|
2018-05-28 17:14:40 +00:00
|
|
|
|
// we assume that ReadAccX is called first, which updates the the states
|
2018-04-03 22:18:41 +00:00
|
|
|
|
public ushort ReadAccY(IController c)
|
|
|
|
|
{
|
2018-05-28 17:14:40 +00:00
|
|
|
|
float temp = (float)Math.Sin(theta);
|
|
|
|
|
|
|
|
|
|
// here we add in rates of change parameters.
|
|
|
|
|
// a typical rate of change for a fast rotation is guessed at 0.5 rad / frame
|
|
|
|
|
// further it will be assumed that the resulting acceleration is roughly eqvuivalent to gravity
|
|
|
|
|
float temp2 = (float)((theta - theta_prev)/0.5 * 125);
|
|
|
|
|
|
|
|
|
|
return (ushort)(0x81D0 - Math.Floor(temp * 125) + temp2);
|
2018-04-03 22:18:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-29 13:18:28 +00:00
|
|
|
|
private static readonly string[] BaseDefinition =
|
|
|
|
|
{
|
2018-01-17 14:41:59 +00:00
|
|
|
|
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
|
2017-08-29 13:18:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public void SyncState(Serializer ser)
|
|
|
|
|
{
|
2018-05-28 17:14:40 +00:00
|
|
|
|
// since we need rate of change of angle, need to savestate them
|
|
|
|
|
ser.Sync("theta", ref theta);
|
2017-08-29 13:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|