controls work and stuff now

This commit is contained in:
goyuken 2013-12-16 01:58:40 +00:00
parent a818710589
commit a6cbd85930
9 changed files with 522 additions and 7 deletions

View File

@ -364,6 +364,10 @@ namespace BizHawk.Client.Common
{
return "|.|"; // TODO
}
else if (_controlType == "GPGX Genesis Controller")
{
return "|.|"; // TODO
}
var input = new StringBuilder("|");

View File

@ -542,6 +542,11 @@ namespace BizHawk.Client.Common
// TODO
return;
}
else if (ControlType == "GPGX Genesis Controller")
{
// TODO
return;
}
MnemonicChecker c = new MnemonicChecker(mnemonic);

View File

@ -3221,7 +3221,7 @@ namespace BizHawk.Client.EmuHawk
case "GEN":
{
//nextEmulator = new Genesis(nextComm, game, rom.RomData);
nextEmulator = new BizHawk.Emulation.Cores.Consoles.Sega.gpgx.GPGX(nextComm, rom.RomData, "GEN");
nextEmulator = new BizHawk.Emulation.Cores.Consoles.Sega.gpgx.GPGX(nextComm, rom.RomData, "GEN", true, Emulation.Cores.Consoles.Sega.gpgx.GPGX.ControlType.Normal);
break;
}
case "TI83":

View File

@ -409,6 +409,7 @@
<Compile Include="Consoles\Sega\Genesis\Input.cs" />
<Compile Include="Consoles\Sega\Genesis\Native68000\Musashi.cs" />
<Compile Include="Consoles\Sega\gpgx\GPGX.cs" />
<Compile Include="Consoles\Sega\gpgx\GPGXControlConverter.cs" />
<Compile Include="Consoles\Sega\gpgx\LibGPGX.cs" />
<Compile Include="Consoles\Sega\Saturn\FilePiping.cs" />
<Compile Include="Consoles\Sega\Saturn\LibYabause.cs" />

View File

@ -21,8 +21,25 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
LibGPGX.load_archive_cb LoadCallback = null;
public GPGX(CoreComm NextComm, byte[] romfile, string romextension)
LibGPGX.InputData input = new LibGPGX.InputData();
// still working out what all the possibilities are here
public enum ControlType
{
None,
OnePlayer,
Normal,
Xea1p,
Activator,
Teamplayer,
Wayplay
};
public GPGX(CoreComm NextComm, byte[] romfile, string romextension, bool sixbutton, ControlType controls)
{
// three or six button?
// http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds
try
{
CoreComm = NextComm;
@ -39,8 +56,54 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
this.romfile = romfile;
if (!LibGPGX.gpgx_init(romextension, LoadCallback))
LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE;
LibGPGX.INPUT_SYSTEM system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE;
switch (controls)
{
case ControlType.None:
default:
break;
case ControlType.Activator:
system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR;
system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR;
break;
case ControlType.Normal:
system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD;
system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD;
break;
case ControlType.OnePlayer:
system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD;
break;
case ControlType.Xea1p:
system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P;
break;
case ControlType.Teamplayer:
system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER;
system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER;
break;
case ControlType.Wayplay:
system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY;
system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY;
break;
}
if (!LibGPGX.gpgx_init(romextension, LoadCallback, sixbutton, system_a, system_b))
throw new Exception("gpgx_init() failed");
{
int fpsnum = 60;
int fpsden = 1;
LibGPGX.gpgx_get_fps(ref fpsnum, ref fpsden);
CoreComm.VsyncNum = fpsnum;
CoreComm.VsyncDen = fpsden;
}
savebuff = new byte[LibGPGX.gpgx_state_size()];
savebuff2 = new byte[savebuff.Length + 13];
SetControllerDefinition();
}
catch
{
@ -97,18 +160,45 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
#region controller
public ControllerDefinition ControllerDefinition { get { return NullEmulator.NullController; } }
GPGXControlConverter ControlConverter;
public ControllerDefinition ControllerDefinition { get; private set; }
public IController Controller { get; set; }
void SetControllerDefinition()
{
if (!LibGPGX.gpgx_get_control(input))
throw new Exception("gpgx_get_control() failed");
ControlConverter = new GPGXControlConverter(input);
ControllerDefinition = ControlConverter.ControllerDef;
}
#endregion
// TODO: use render and rendersound
public void FrameAdvance(bool render, bool rendersound = true)
{
// do we really have to get each time? nothing has changed
if (!LibGPGX.gpgx_get_control(input))
throw new Exception("gpgx_get_control() failed!");
ControlConverter.Convert(Controller, input);
if (!LibGPGX.gpgx_put_control(input))
throw new Exception("gpgx_put_control() failed!");
IsLagFrame = true;
Frame++;
LibGPGX.gpgx_advance();
update_video();
update_audio();
IsLagFrame = false; // TODO
if (IsLagFrame)
LagCount++;
}
public int Frame { get; private set; }
@ -161,6 +251,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
#region savestates
private byte[] savebuff;
private byte[] savebuff2;
public void SaveStateText(System.IO.TextWriter writer)
{
}
@ -171,15 +264,39 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
public void SaveStateBinary(System.IO.BinaryWriter writer)
{
if (!LibGPGX.gpgx_state_save(savebuff, savebuff.Length))
throw new Exception("gpgx_state_save() returned false");
writer.Write(savebuff.Length);
writer.Write(savebuff);
// other variables
writer.Write(Frame);
writer.Write(LagCount);
writer.Write(IsLagFrame);
}
public void LoadStateBinary(System.IO.BinaryReader reader)
{
int newlen = reader.ReadInt32();
if (newlen != savebuff.Length)
throw new Exception("Unexpected state size");
reader.Read(savebuff, 0, savebuff.Length);
if (!LibGPGX.gpgx_state_load(savebuff, savebuff.Length))
throw new Exception("gpgx_state_load() returned false");
// other variables
Frame = reader.ReadInt32();
LagCount = reader.ReadInt32();
IsLagFrame = reader.ReadBoolean();
}
public byte[] SaveStateBinary()
{
return new byte[0];
var ms = new System.IO.MemoryStream(savebuff2, true);
var bw = new System.IO.BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
ms.Close();
return savebuff2;
}
public bool BinarySaveStatesPreferred { get { return true; } }

View File

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{
public class GPGXControlConverter
{
// this isn't all done
struct CName
{
public string Name;
public LibGPGX.INPUT_KEYS Key;
public CName(string Name, LibGPGX.INPUT_KEYS Key)
{
this.Name = Name;
this.Key = Key;
}
}
static CName[] Genesis3 =
{
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
new CName("B", LibGPGX.INPUT_KEYS.INPUT_B),
new CName("C", LibGPGX.INPUT_KEYS.INPUT_C),
new CName("A", LibGPGX.INPUT_KEYS.INPUT_A),
new CName("Start", LibGPGX.INPUT_KEYS.INPUT_START),
};
static CName[] Genesis6 =
{
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
new CName("B", LibGPGX.INPUT_KEYS.INPUT_B),
new CName("C", LibGPGX.INPUT_KEYS.INPUT_C),
new CName("A", LibGPGX.INPUT_KEYS.INPUT_A),
new CName("Start", LibGPGX.INPUT_KEYS.INPUT_START),
new CName("Z", LibGPGX.INPUT_KEYS.INPUT_Z),
new CName("Y", LibGPGX.INPUT_KEYS.INPUT_Y),
new CName("X", LibGPGX.INPUT_KEYS.INPUT_X),
new CName("Mode", LibGPGX.INPUT_KEYS.INPUT_MODE),
};
static CName[] Mouse =
{
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_MOUSE_LEFT),
new CName("Center", LibGPGX.INPUT_KEYS.INPUT_MOUSE_CENTER),
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_MOUSE_RIGHT),
};
static ControllerDefinition.FloatRange FullShort = new ControllerDefinition.FloatRange(-32767, 0, 32767);
LibGPGX.InputData target = null;
IController source = null;
List<Action> Converts = new List<Action>();
public ControllerDefinition ControllerDef { get; private set; }
void AddToController(int idx, int player, IEnumerable<CName> Buttons)
{
foreach (var Button in Buttons)
{
string Name = string.Format("P{0} {1}", player, Button.Name);
ControllerDef.BoolButtons.Add(Name);
var ButtonFlag = Button.Key;
Converts.Add(delegate()
{
if (source.IsPressed(Name))
target.pad[idx] |= ButtonFlag;
});
}
}
void DoMouseAnalog(int idx, int player)
{
string NX = string.Format("P{0} X", player);
string NY = string.Format("P{0} Y", player);
ControllerDef.FloatControls.Add(NX);
ControllerDef.FloatControls.Add(NY);
ControllerDef.FloatRanges.Add(FullShort);
ControllerDef.FloatRanges.Add(FullShort);
Converts.Add(delegate()
{
target.analog[idx,0] = (short)source.GetFloat(NX);
target.analog[idx,1] = (short)source.GetFloat(NY);
});
}
public GPGXControlConverter(LibGPGX.InputData input)
{
Console.WriteLine("Genesis Controller report:");
foreach (var e in input.system)
Console.WriteLine("S:{0}", e);
foreach (var e in input.dev)
Console.WriteLine("D:{0}", e);
int player = 1;
ControllerDef = new ControllerDefinition();
for (int i = 0; i < LibGPGX.MAX_DEVICES; i++)
{
switch (input.dev[i])
{
case LibGPGX.INPUT_DEVICE.DEVICE_PAD3B:
AddToController(i, player, Genesis3);
player++;
break;
case LibGPGX.INPUT_DEVICE.DEVICE_PAD6B:
AddToController(i, player, Genesis6);
player++;
break;
case LibGPGX.INPUT_DEVICE.DEVICE_MOUSE:
AddToController(i, player, Mouse);
DoMouseAnalog(i, player);
player++;
break;
}
}
ControllerDef.Name = "GPGX Genesis Controller";
}
public void Convert(IController source, LibGPGX.InputData target)
{
this.source = source;
this.target = target;
target.ClearAllBools();
foreach (var f in Converts)
f();
this.source = null;
this.target = null;
}
}
}

View File

@ -21,7 +21,177 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
public static extern void gpgx_advance();
[DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool gpgx_init(string feromextension, load_archive_cb feload_archive_cb);
public static extern bool gpgx_init(string feromextension, load_archive_cb feload_archive_cb, bool sixbutton, INPUT_SYSTEM system_a, INPUT_SYSTEM system_b);
[DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void gpgx_get_fps(ref int num, ref int den);
[DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int gpgx_state_size();
[DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool gpgx_state_save(byte[] dest, int size);
[DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool gpgx_state_load(byte[] src, int size);
[DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool gpgx_get_control(IntPtr dest, int bytes);
[DllImport("libgenplusgx.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool gpgx_put_control(IntPtr src, int bytes);
public static bool gpgx_get_control(InputData dest)
{
int bytes = Marshal.SizeOf(typeof(InputData));
IntPtr p = Marshal.AllocHGlobal(bytes);
bool succeed = gpgx_get_control(p, bytes);
if (succeed)
Marshal.PtrToStructure(p, dest);
Marshal.FreeHGlobal(p);
return succeed;
}
public static bool gpgx_put_control(InputData src)
{
int bytes = Marshal.SizeOf(typeof(InputData));
IntPtr p = Marshal.AllocHGlobal(bytes);
Marshal.StructureToPtr(src, p, false);
bool succeed = gpgx_put_control(p, bytes);
Marshal.FreeHGlobal(p);
return succeed;
}
public const int MAX_DEVICES = 8;
public enum INPUT_SYSTEM : byte
{
SYSTEM_NONE = 0, // unconnected port
SYSTEM_MD_GAMEPAD = 1, // single 3-buttons or 6-buttons Control Pad
SYSTEM_MOUSE = 2, // Sega Mouse
SYSTEM_MENACER = 3, // Sega Menacer -- port B only
SYSTEM_JUSTIFIER = 4, // Konami Justifiers -- port B only
SYSTEM_XE_A1P = 5, // XE-A1P analog controller -- port A only
SYSTEM_ACTIVATOR = 6, // Sega Activator
SYSTEM_MS_GAMEPAD = 7, // single 2-buttons Control Pad -- Master System
SYSTEM_LIGHTPHASER = 8, // Sega Light Phaser -- Master System
SYSTEM_PADDLE = 9, // Sega Paddle Control -- Master System
SYSTEM_SPORTSPAD = 10, // Sega Sports Pad -- Master System
SYSTEM_TEAMPLAYER = 11, // Multi Tap -- Sega TeamPlayer
SYSTEM_WAYPLAY = 12, // Multi Tap -- EA 4-Way Play -- use both ports
};
public enum INPUT_DEVICE : byte
{
DEVICE_NONE = 0xff, // unconnected device = fixed ID for Team Player)
DEVICE_PAD3B = 0x00, // 3-buttons Control Pad = fixed ID for Team Player)
DEVICE_PAD6B = 0x01, // 6-buttons Control Pad = fixed ID for Team Player)
DEVICE_PAD2B = 0x02, // 2-buttons Control Pad
DEVICE_MOUSE = 0x03, // Sega Mouse
DEVICE_LIGHTGUN = 0x04, // Sega Light Phaser, Menacer or Konami Justifiers
DEVICE_PADDLE = 0x05, // Sega Paddle Control
DEVICE_SPORTSPAD = 0x06,// Sega Sports Pad
DEVICE_PICO = 0x07, // PICO tablet
DEVICE_TEREBI = 0x08, // Terebi Oekaki tablet
DEVICE_XE_A1P = 0x09, // XE-A1P analog controller
DEVICE_ACTIVATOR = 0x0a,// Activator
};
/// <summary>
/// not every flag is valid for every device!
/// </summary>
[Flags]
public enum INPUT_KEYS : ushort
{
/* Default Input bitmasks */
INPUT_MODE = 0x0800,
INPUT_X = 0x0400,
INPUT_Y = 0x0200,
INPUT_Z = 0x0100,
INPUT_START = 0x0080,
INPUT_A = 0x0040,
INPUT_C = 0x0020,
INPUT_B = 0x0010,
INPUT_RIGHT = 0x0008,
INPUT_LEFT = 0x0004,
INPUT_DOWN = 0x0002,
INPUT_UP = 0x0001,
/* Master System specific bitmasks */
INPUT_BUTTON2 = 0x0020,
INPUT_BUTTON1 = 0x0010,
/* Mega Mouse specific bitmask */
INPUT_MOUSE_CENTER = 0x0040,
INPUT_MOUSE_RIGHT = 0x0020,
INPUT_MOUSE_LEFT = 0x0010,
/* Pico hardware specific bitmask */
INPUT_PICO_PEN = 0x0080,
INPUT_PICO_RED = 0x0010,
/* XE-1AP specific bitmask */
INPUT_XE_E1 = 0x0800,
INPUT_XE_E2 = 0x0400,
INPUT_XE_START = 0x0200,
INPUT_XE_SELECT = 0x0100,
INPUT_XE_A = 0x0080,
INPUT_XE_B = 0x0040,
INPUT_XE_C = 0x0020,
INPUT_XE_D = 0x0010,
/* Activator specific bitmasks */
INPUT_ACTIVATOR_8U = 0x8000,
INPUT_ACTIVATOR_8L = 0x4000,
INPUT_ACTIVATOR_7U = 0x2000,
INPUT_ACTIVATOR_7L = 0x1000,
INPUT_ACTIVATOR_6U = 0x0800,
INPUT_ACTIVATOR_6L = 0x0400,
INPUT_ACTIVATOR_5U = 0x0200,
INPUT_ACTIVATOR_5L = 0x0100,
INPUT_ACTIVATOR_4U = 0x0080,
INPUT_ACTIVATOR_4L = 0x0040,
INPUT_ACTIVATOR_3U = 0x0020,
INPUT_ACTIVATOR_3L = 0x0010,
INPUT_ACTIVATOR_2U = 0x0008,
INPUT_ACTIVATOR_2L = 0x0004,
INPUT_ACTIVATOR_1U = 0x0002,
INPUT_ACTIVATOR_1L = 0x0001,
};
[StructLayout(LayoutKind.Sequential)]
public class InputData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public readonly INPUT_SYSTEM[] system = new INPUT_SYSTEM[2];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICES)]
public readonly INPUT_DEVICE[] dev = new INPUT_DEVICE[MAX_DEVICES];
/// <summary>
/// digital inputs
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICES)]
public readonly INPUT_KEYS[] pad = new INPUT_KEYS[MAX_DEVICES];
/// <summary>
/// analog (x/y)
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICES * 2)]
public readonly short[,] analog = new short[MAX_DEVICES, 2];
/// <summary>
/// gun horizontal offset
/// </summary>
public int x_offset;
/// <summary>
/// gun vertical offset
/// </summary>
public int y_offset;
public void ClearAllBools()
{
for (int i = 0; i < pad.Length; i++)
pad[i] = 0;
}
}
}
}

View File

@ -76,6 +76,45 @@ GPGX_EX void gpgx_get_audio(int *n, void **buffer)
*buffer = soundbuffer;
}
// this is most certainly wrong for interlacing
GPGX_EX void gpgx_get_fps(int *num, int *den)
{
if (vdp_pal)
{
if (num)
*num = 53203424;
if (den)
*den = 3420 * 313;
}
else
{
if (num)
*num = 53693175;
if (den)
*den = 3420 * 262;
}
}
GPGX_EX int gpgx_state_size(void)
{
return STATE_SIZE;
}
GPGX_EX int gpgx_state_save(void *dest, int size)
{
if (size != STATE_SIZE)
return 0;
return !!state_save((unsigned char*) dest);
}
GPGX_EX int gpgx_state_load(void *src, int size)
{
if (size != STATE_SIZE)
return 0;
return !!state_load((unsigned char *) src);
}
void osd_input_update(void)
{
@ -94,6 +133,21 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten
return load_archive_cb(filename, buffer, maxsize);
}
GPGX_EX int gpgx_get_control(t_input *dest, int bytes)
{
if (bytes != sizeof(t_input))
return 0;
memcpy(dest, &input, sizeof(t_input));
return 1;
}
GPGX_EX int gpgx_put_control(t_input *src, int bytes)
{
if (bytes != sizeof(t_input))
return 0;
memcpy(&input, src, sizeof(t_input));
}
GPGX_EX void gpgx_advance(void)
{
if (system_hw == SYSTEM_MCD)
@ -113,7 +167,7 @@ GPGX_EX void gpgx_advance(void)
}
GPGX_EX int gpgx_init(const char *feromextension, int (*feload_archive_cb)(const char *filename, unsigned char *buffer, int maxsize))
GPGX_EX int gpgx_init(const char *feromextension, int (*feload_archive_cb)(const char *filename, unsigned char *buffer, int maxsize), int sixbutton, char system_a, char system_b)
{
memset(&bitmap, 0, sizeof(bitmap));
memset(bitmap_data_, 0, sizeof(bitmap_data_));
@ -160,6 +214,23 @@ GPGX_EX int gpgx_init(const char *feromextension, int (*feload_archive_cb)(const
config.ntsc = 0;
config.render= 0;
// set overall input system type
// usual is MD GAMEPAD or NONE
// TEAMPLAYER, WAYPLAY, ACTIVATOR, XEA1P, MOUSE need to be specified
// everything else is auto or master system only
// XEA1P is port 1 only
// WAYPLAY is both ports at same time only
input.system[0] = system_a;
input.system[1] = system_b;
// apparently, the only part of config.input used is the padtype identifier,
// and that's used only for choosing pad type when system_md
{
int i;
for (i = 0; i < MAX_INPUTS; i++)
config.input[i].padtype = sixbutton ? DEVICE_PAD6B : DEVICE_PAD3B;
}
if (!load_rom("PRIMARY_ROM"))
return 0;

Binary file not shown.