pce: basic rom loading and playing works
This commit is contained in:
parent
d82d67996f
commit
69d3dbc35f
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
public static class Mershul
|
||||
{
|
||||
/// <summary>
|
||||
/// TODO: Update to a version of .nyet that includes this
|
||||
/// </summary>
|
||||
public static unsafe string PtrToStringUtf8(IntPtr p)
|
||||
{
|
||||
byte* b = (byte*)p;
|
||||
int len = 0;
|
||||
while (*b++ != 0)
|
||||
len++;
|
||||
return Encoding.UTF8.GetString((byte*)p, len);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -195,10 +195,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// </summary>
|
||||
private bool IsSpecialReadonlySection(Section<ulong> sec)
|
||||
{
|
||||
// TODO: I don't think there are any more relro sections, right?
|
||||
return sec.Name.Contains(".rel.ro")
|
||||
|| sec.Name.StartsWith(".got")
|
||||
|| sec.Name == ".init_array"
|
||||
|| sec.Name == ".fini_array"
|
||||
|| sec.Name == ".tbss"
|
||||
|| sec == _imports
|
||||
|| sec == _sealed;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
|
@ -36,8 +37,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
[BizExport(CallingConvention.Cdecl, EntryPoint = "__w_debug_puts")]
|
||||
public void DebugPuts(IntPtr s)
|
||||
{
|
||||
// TODO: Should be PtrToStringUtf8
|
||||
Console.WriteLine(Marshal.PtrToStringAnsi(s));
|
||||
Console.WriteLine(Mershul.PtrToStringUtf8(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
|
@ -59,7 +60,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// <summary>
|
||||
/// true to skip video rendering
|
||||
/// </summary>
|
||||
public int SkipRendering;
|
||||
public short SkipRendering;
|
||||
/// <summary>
|
||||
/// true to skip audion rendering
|
||||
/// </summary>
|
||||
public short SkipSoundening;
|
||||
/// <summary>
|
||||
/// a single command to run at the start of this frame
|
||||
/// </summary>
|
||||
|
@ -129,9 +134,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public IntPtr _defaultDeviceShortName;
|
||||
public uint NumDevices;
|
||||
|
||||
public string ShortName => Marshal.PtrToStringAnsi(_shortName);
|
||||
public string FullName => Marshal.PtrToStringAnsi(_fullName);
|
||||
public string DefaultDeviceShortName => Marshal.PtrToStringAnsi(_defaultDeviceShortName);
|
||||
public string ShortName => Mershul.PtrToStringUtf8(_shortName);
|
||||
public string FullName => Mershul.PtrToStringUtf8(_fullName);
|
||||
public string DefaultDeviceShortName => Mershul.PtrToStringUtf8(_defaultDeviceShortName);
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NDeviceInfo
|
||||
|
@ -143,9 +148,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public uint ByteLength;
|
||||
public uint NumInputs;
|
||||
|
||||
public string ShortName => Marshal.PtrToStringAnsi(_shortName);
|
||||
public string FullName => Marshal.PtrToStringAnsi(_fullName);
|
||||
public string Description => Marshal.PtrToStringAnsi(_description);
|
||||
public string ShortName => Mershul.PtrToStringUtf8(_shortName);
|
||||
public string FullName => Mershul.PtrToStringUtf8(_fullName);
|
||||
public string Description => Mershul.PtrToStringUtf8(_description);
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NInputInfo
|
||||
|
@ -158,15 +163,15 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public AxisFlags Flags;
|
||||
public byte BitSize;
|
||||
|
||||
public string SettingName => Marshal.PtrToStringAnsi(_settingName);
|
||||
public string Name => Marshal.PtrToStringAnsi(_name);
|
||||
public string SettingName => Mershul.PtrToStringUtf8(_settingName);
|
||||
public string Name => Mershul.PtrToStringUtf8(_name);
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NButtonInfo
|
||||
{
|
||||
public IntPtr _excludeName;
|
||||
|
||||
public string ExcludeName => Marshal.PtrToStringAnsi(_excludeName);
|
||||
public string ExcludeName => Mershul.PtrToStringUtf8(_excludeName);
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NAxisInfo
|
||||
|
@ -176,10 +181,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public IntPtr _nameNeg;
|
||||
public IntPtr _namePos;
|
||||
|
||||
public string SettingsNameNeg => Marshal.PtrToStringAnsi(_settingsNameNeg);
|
||||
public string SettingsNamePos => Marshal.PtrToStringAnsi(_settingsNamePos);
|
||||
public string NameNeg => Marshal.PtrToStringAnsi(_nameNeg);
|
||||
public string NamePos => Marshal.PtrToStringAnsi(_namePos);
|
||||
public string SettingsNameNeg => Mershul.PtrToStringUtf8(_settingsNameNeg);
|
||||
public string SettingsNamePos => Mershul.PtrToStringUtf8(_settingsNamePos);
|
||||
public string NameNeg => Mershul.PtrToStringUtf8(_nameNeg);
|
||||
public string NamePos => Mershul.PtrToStringUtf8(_namePos);
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NSwitchInfo
|
||||
|
@ -193,9 +198,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public IntPtr _name;
|
||||
public IntPtr _description;
|
||||
|
||||
public string SettingName => Marshal.PtrToStringAnsi(_settingName);
|
||||
public string Name => Marshal.PtrToStringAnsi(_name);
|
||||
public string Description => Marshal.PtrToStringAnsi(_description);
|
||||
public string SettingName => Mershul.PtrToStringUtf8(_settingName);
|
||||
public string Name => Mershul.PtrToStringUtf8(_name);
|
||||
public string Description => Mershul.PtrToStringUtf8(_description);
|
||||
}
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
@ -210,8 +215,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public int Color; // (msb)0RGB(lsb), -1 for unused.
|
||||
public int _Padding;
|
||||
|
||||
public string ShortName => Marshal.PtrToStringAnsi(_shortName);
|
||||
public string Name => Marshal.PtrToStringAnsi(_name);
|
||||
public string ShortName => Mershul.PtrToStringUtf8(_shortName);
|
||||
public string Name => Mershul.PtrToStringUtf8(_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,6 +241,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract NAxisInfo* GetAxis(uint port, uint dev, uint input);
|
||||
|
||||
/// <summary>
|
||||
/// Set what input devices we're going to use
|
||||
/// </summary>
|
||||
/// <param name="devices">MUST end with a null string</param>
|
||||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract void SetInputDevices(string[] devices);
|
||||
|
||||
|
@ -249,7 +258,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class SystemInfo
|
||||
public struct SystemInfo
|
||||
{
|
||||
public int MaxWidth;
|
||||
public int MaxHeight;
|
||||
|
@ -260,6 +269,6 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
|
||||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract SystemInfo GetSystemInfo();
|
||||
public abstract SystemInfo* GetSystemInfo();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
public WaterboxMemoryDomain(MemoryArea m, IMonitor monitor)
|
||||
{
|
||||
Name = Marshal.PtrToStringAnsi(m.Name);
|
||||
Name = Mershul.PtrToStringUtf8(m.Name);
|
||||
EndianType = (m.Flags & MemoryDomainFlags.YugeEndian) != 0 ? Endian.Big : Endian.Little;
|
||||
_data = m.Data;
|
||||
Size = m.Size;
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
unsafe partial class NymaCore
|
||||
{
|
||||
private ControllerAdapter _controllerAdapter;
|
||||
private readonly byte[] _inputPortData = new byte[16 * 16];
|
||||
|
||||
private void InitControls()
|
||||
{
|
||||
_controllerAdapter = new ControllerAdapter(_nyma, new string[0]);
|
||||
_nyma.SetInputDevices(_controllerAdapter.Devices);
|
||||
ControllerDefinition = _controllerAdapter.Definition;
|
||||
}
|
||||
protected delegate void ControllerThunk(IController c, byte[] b);
|
||||
|
||||
protected class ControllerAdapter
|
||||
{
|
||||
/// <summary>
|
||||
/// allowed number of input ports. must match native
|
||||
/// </summary>
|
||||
private const int MAX_PORTS = 16;
|
||||
/// <summary>
|
||||
/// total maximum bytes on each input port. must match native
|
||||
/// </summary>
|
||||
private const int MAX_PORT_DATA = 16;
|
||||
|
||||
/// <summary>
|
||||
/// Device list suitable to pass back to the core
|
||||
/// </summary>
|
||||
public string[] Devices { get; }
|
||||
public ControllerDefinition Definition { get; }
|
||||
public ControllerAdapter(LibNymaCore core, string[] config)
|
||||
{
|
||||
var ret = new ControllerDefinition
|
||||
{
|
||||
Name = "TODO"
|
||||
};
|
||||
|
||||
var finalDevices = new List<string>();
|
||||
|
||||
var numPorts = core.GetNumPorts();
|
||||
if (numPorts > MAX_PORTS)
|
||||
throw new InvalidOperationException($"Too many input ports");
|
||||
for (uint port = 0, devByteStart = 0; port < numPorts; port++, devByteStart += MAX_PORT_DATA)
|
||||
{
|
||||
var portInfo = *core.GetPort(port);
|
||||
var deviceName = port < config.Length ? config[port] : portInfo.DefaultDeviceShortName;
|
||||
finalDevices.Add(deviceName);
|
||||
|
||||
var devices = Enumerable.Range(0, (int)portInfo.NumDevices)
|
||||
.Select(i => new { Index = (uint)i, Device = *core.GetDevice(port, (uint)i) })
|
||||
.ToList();
|
||||
|
||||
var device = devices.FirstOrDefault(a => a.Device.ShortName == deviceName);
|
||||
if (device == null)
|
||||
{
|
||||
Console.WriteLine($"Warn: unknown controller device {deviceName}");
|
||||
device = devices.FirstOrDefault(a => a.Device.ShortName == portInfo.DefaultDeviceShortName);
|
||||
if (device == null)
|
||||
throw new InvalidOperationException($"Fail: unknown controller device {portInfo.DefaultDeviceShortName}");
|
||||
}
|
||||
|
||||
var deviceInfo = device.Device;
|
||||
if (deviceInfo.ByteLength > MAX_PORT_DATA)
|
||||
throw new InvalidOperationException($"Input device {deviceInfo.ShortName} uses more than {MAX_PORT_DATA} bytes");
|
||||
var category = portInfo.FullName + " - " + deviceInfo.FullName;
|
||||
|
||||
var inputs = Enumerable.Range(0, (int)deviceInfo.NumInputs)
|
||||
.Select(i => new { Index = i, Data = *core.GetInput(port, device.Index, (uint)i) })
|
||||
.OrderBy(a => a.Data.ConfigOrder);
|
||||
|
||||
foreach (var input in inputs)
|
||||
{
|
||||
var inputInfo = input.Data;
|
||||
var bitSize = (int)inputInfo.BitSize;
|
||||
var bitOffset = (int)inputInfo.BitOffset;
|
||||
var byteStart = devByteStart + bitOffset / 8;
|
||||
bitOffset %= 8;
|
||||
var name = $"P{port + 1} {inputInfo.Name}";
|
||||
switch (inputInfo.Type)
|
||||
{
|
||||
case LibNymaCore.InputType.PADDING:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.BUTTON:
|
||||
case LibNymaCore.InputType.BUTTON_CAN_RAPID:
|
||||
{
|
||||
var data = *core.GetButton(port, device.Index, (uint)input.Index);
|
||||
// TODO: Wire up data.ExcludeName
|
||||
ret.BoolButtons.Add(name);
|
||||
_thunks.Add((c, b) =>
|
||||
{
|
||||
if (c.IsPressed(name))
|
||||
b[byteStart] |= (byte)(1 << bitOffset);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.SWITCH:
|
||||
{
|
||||
var data = *core.GetSwitch(port, device.Index, (uint)input.Index);
|
||||
// TODO: Possibly bulebutton for 2 states?
|
||||
ret.AxisControls.Add(name);
|
||||
ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
|
||||
0, (int)data.DefaultPosition, (int)data.NumPositions - 1));
|
||||
// HACK: Silently discard this until bizhawk fixes its shit
|
||||
// _thunks.Add((c, b) =>
|
||||
// {
|
||||
// var val = (int)Math.Round(c.AxisValue(name));
|
||||
// b[byteStart] |= (byte)(1 << bitOffset);
|
||||
// });
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.AXIS:
|
||||
{
|
||||
var data = core.GetAxis(port, device.Index, (uint)input.Index);
|
||||
ret.AxisControls.Add(name);
|
||||
ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
|
||||
0, 0x8000, 0xffff, (inputInfo.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0
|
||||
));
|
||||
_thunks.Add((c, b) =>
|
||||
{
|
||||
var val = (ushort)Math.Round(c.AxisValue(name));
|
||||
b[byteStart] = (byte)val;
|
||||
b[byteStart + 1] = (byte)(val >> 8);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.AXIS_REL:
|
||||
{
|
||||
var data = core.GetAxis(port, device.Index, (uint)input.Index);
|
||||
ret.AxisControls.Add(name);
|
||||
ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
|
||||
-0x8000, 0, 0x7fff, (inputInfo.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0
|
||||
));
|
||||
_thunks.Add((c, b) =>
|
||||
{
|
||||
var val = (short)Math.Round(c.AxisValue(name));
|
||||
b[byteStart] = (byte)val;
|
||||
b[byteStart + 1] = (byte)(val >> 8);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.POINTER_X:
|
||||
{
|
||||
throw new Exception("TODO: Axis ranges are ints????");
|
||||
// ret.AxisControls.Add(name);
|
||||
// ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1));
|
||||
// break;
|
||||
}
|
||||
case LibNymaCore.InputType.POINTER_Y:
|
||||
{
|
||||
throw new Exception("TODO: Axis ranges are ints????");
|
||||
// ret.AxisControls.Add(name);
|
||||
// ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1, true));
|
||||
// break;
|
||||
}
|
||||
// TODO: wire up statuses to something (not controller, of course)
|
||||
default:
|
||||
throw new NotImplementedException($"Unimplemented button type {inputInfo.Type}");
|
||||
}
|
||||
ret.CategoryLabels[name] = category;
|
||||
}
|
||||
}
|
||||
Definition = ret;
|
||||
finalDevices.Add(null);
|
||||
Devices = finalDevices.ToArray();
|
||||
}
|
||||
|
||||
private readonly List<Action<IController, byte[]>> _thunks = new List<Action<IController, byte[]>>();
|
||||
|
||||
public void SetBits(IController src, byte[] dest)
|
||||
{
|
||||
Array.Clear(dest, 0, dest.Length);
|
||||
foreach (var t in _thunks)
|
||||
t(src, dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ using BizHawk.Emulation.Common;
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Waterbox
|
||||
{
|
||||
public unsafe abstract class NymaCore : WaterboxCore
|
||||
public unsafe abstract partial class NymaCore : WaterboxCore
|
||||
{
|
||||
protected NymaCore(GameInfo game, byte[] rom, CoreComm comm, Configuration c)
|
||||
: base(comm, c)
|
||||
|
@ -15,9 +15,6 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
}
|
||||
|
||||
private LibNymaCore _nyma;
|
||||
private ControllerAdapter _controllerAdapter;
|
||||
private readonly byte[] _inputPortData = new byte[16 * 16];
|
||||
|
||||
protected T DoInit<T>(GameInfo game, byte[] rom, string filename, string extension)
|
||||
where T : LibNymaCore
|
||||
{
|
||||
|
@ -55,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
|
||||
_exe.RemoveReadonlyFile(fn);
|
||||
|
||||
var info = _nyma.GetSystemInfo();
|
||||
var info = *_nyma.GetSystemInfo();
|
||||
_videoBuffer = new int[info.MaxWidth * info.MaxHeight];
|
||||
BufferWidth = info.NominalWidth;
|
||||
BufferHeight = info.NominalHeight;
|
||||
|
@ -76,8 +73,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
VsyncNumerator = info.FpsFixed;
|
||||
VsyncDenominator = 1 << 24;
|
||||
|
||||
_controllerAdapter = new ControllerAdapter(_nyma, new string[0]);
|
||||
_nyma.SetInputDevices(_controllerAdapter.Devices);
|
||||
_soundBuffer = new short[22050 * 2];
|
||||
|
||||
InitControls();
|
||||
|
||||
PostInit();
|
||||
}
|
||||
|
@ -94,7 +92,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
_frameAdvanceInputLock = GCHandle.Alloc(_inputPortData, GCHandleType.Pinned);
|
||||
var ret = new LibNymaCore.FrameInfo
|
||||
{
|
||||
SkipRendering = render ? 0 : 1,
|
||||
SkipRendering = (short)(render ? 0 : 1),
|
||||
SkipSoundening =(short)(rendersound ? 0 : 1),
|
||||
Command = LibNymaCore.CommandType.NONE,
|
||||
InputPortData = (byte*)_frameAdvanceInputLock.AddrOfPinnedObject()
|
||||
};
|
||||
|
@ -105,156 +104,6 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
_frameAdvanceInputLock.Free();
|
||||
}
|
||||
|
||||
protected delegate void ControllerThunk(IController c, byte[] b);
|
||||
|
||||
protected class ControllerAdapter
|
||||
{
|
||||
public string[] Devices { get; }
|
||||
public ControllerDefinition Definition { get; }
|
||||
public ControllerAdapter(LibNymaCore core, string[] config)
|
||||
{
|
||||
var ret = new ControllerDefinition
|
||||
{
|
||||
Name = "TODO"
|
||||
};
|
||||
|
||||
var finalDevices = new List<string>();
|
||||
|
||||
var numPorts = core.GetNumPorts();
|
||||
for (uint i = 0, devByteStart = 0; i < numPorts; i++)
|
||||
{
|
||||
var port = *core.GetPort(i);
|
||||
var devName = i < config.Length ? config[i] : port.DefaultDeviceShortName;
|
||||
finalDevices.Add(devName);
|
||||
|
||||
var devices = Enumerable.Range(0, (int)port.NumDevices)
|
||||
.Select(j => new { Index = (uint)j, Device = *core.GetDevice(i, (uint)j) })
|
||||
.ToList();
|
||||
|
||||
var device = devices.FirstOrDefault(a => a.Device.ShortName == devName);
|
||||
if (device == null)
|
||||
{
|
||||
Console.WriteLine($"Warn: unknown controller device {devName}");
|
||||
device = devices.FirstOrDefault(a => a.Device.ShortName == port.DefaultDeviceShortName);
|
||||
if (device == null)
|
||||
throw new InvalidOperationException($"Fail: unknown controller device {port.DefaultDeviceShortName}");
|
||||
}
|
||||
|
||||
var dev = device.Device;
|
||||
var category = port.FullName + " - " + dev.FullName;
|
||||
|
||||
var inputs = Enumerable.Range(0, (int)dev.NumInputs)
|
||||
.Select(iix => new { Index = iix, Data = *core.GetInput(i, device.Index, (uint)iix) })
|
||||
.OrderBy(a => a.Data.ConfigOrder);
|
||||
|
||||
foreach (var inputzz in inputs)
|
||||
{
|
||||
var input = inputzz.Data;
|
||||
var bitSize = (int)input.BitSize;
|
||||
var bitOffset = (int)input.BitOffset;
|
||||
var byteStart = devByteStart + bitOffset / 8;
|
||||
bitOffset %= 8;
|
||||
var name = input.Name;
|
||||
switch (input.Type)
|
||||
{
|
||||
case LibNymaCore.InputType.PADDING:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.BUTTON:
|
||||
case LibNymaCore.InputType.BUTTON_CAN_RAPID:
|
||||
{
|
||||
var data = *core.GetButton(i, device.Index, (uint)inputzz.Index);
|
||||
// TODO: Wire up data.ExcludeName
|
||||
ret.BoolButtons.Add(name);
|
||||
_thunks.Add((c, b) =>
|
||||
{
|
||||
if (c.IsPressed(name))
|
||||
b[byteStart] |= (byte)(1 << bitOffset);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.SWITCH:
|
||||
{
|
||||
var data = *core.GetSwitch(i, device.Index, (uint)inputzz.Index);
|
||||
// TODO: Possibly bulebutton for 2 states?
|
||||
ret.AxisControls.Add(name);
|
||||
ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
|
||||
0, (int)data.DefaultPosition, (int)data.NumPositions - 1));
|
||||
_thunks.Add((c, b) =>
|
||||
{
|
||||
var val = (int)Math.Round(c.AxisValue(name));
|
||||
b[byteStart] |= (byte)(1 << bitOffset);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.AXIS:
|
||||
{
|
||||
var data = core.GetAxis(i, device.Index, (uint)inputzz.Index);
|
||||
ret.AxisControls.Add(name);
|
||||
ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
|
||||
0, 0x8000, 0xffff, (input.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0
|
||||
));
|
||||
_thunks.Add((c, b) =>
|
||||
{
|
||||
var val = (ushort)Math.Round(c.AxisValue(name));
|
||||
b[byteStart] = (byte)val;
|
||||
b[byteStart + 1] = (byte)(val >> 8);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.AXIS_REL:
|
||||
{
|
||||
var data = core.GetAxis(i, device.Index, (uint)inputzz.Index);
|
||||
ret.AxisControls.Add(name);
|
||||
ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
|
||||
-0x8000, 0, 0x7fff, (input.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0
|
||||
));
|
||||
_thunks.Add((c, b) =>
|
||||
{
|
||||
var val = (short)Math.Round(c.AxisValue(name));
|
||||
b[byteStart] = (byte)val;
|
||||
b[byteStart + 1] = (byte)(val >> 8);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case LibNymaCore.InputType.POINTER_X:
|
||||
{
|
||||
throw new Exception("TODO: Axis ranges are ints????");
|
||||
// ret.AxisControls.Add(name);
|
||||
// ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1));
|
||||
// break;
|
||||
}
|
||||
case LibNymaCore.InputType.POINTER_Y:
|
||||
{
|
||||
throw new Exception("TODO: Axis ranges are ints????");
|
||||
// ret.AxisControls.Add(name);
|
||||
// ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1, true));
|
||||
// break;
|
||||
}
|
||||
// TODO: wire up statuses to something (not controller, of course)
|
||||
default:
|
||||
throw new NotImplementedException($"Unimplemented button type {input.Type}");
|
||||
}
|
||||
ret.CategoryLabels[name] = category;
|
||||
}
|
||||
|
||||
devByteStart += dev.ByteLength;
|
||||
}
|
||||
Definition = ret;
|
||||
Devices = finalDevices.ToArray();
|
||||
}
|
||||
|
||||
private readonly List<Action<IController, byte[]>> _thunks = new List<Action<IController, byte[]>>();
|
||||
|
||||
public void SetBits(IController src, byte[] dest)
|
||||
{
|
||||
Array.Clear(dest, 0, dest.Length);
|
||||
foreach (var t in _thunks)
|
||||
t(src, dest);
|
||||
}
|
||||
}
|
||||
|
||||
public DisplayType Region { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -274,7 +123,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
if (*q == 0)
|
||||
{
|
||||
if (q > p)
|
||||
ret.Add(Marshal.PtrToStringAnsi((IntPtr)p));
|
||||
ret.Add(Mershul.PtrToStringUtf8((IntPtr)p));
|
||||
else
|
||||
break;
|
||||
p = ++q;
|
||||
|
|
|
@ -197,9 +197,19 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
LagCount++;
|
||||
AdvanceRtc();
|
||||
|
||||
BufferWidth = frame.Width;
|
||||
BufferHeight = frame.Height;
|
||||
_numSamples = frame.Samples;
|
||||
if (render)
|
||||
{
|
||||
BufferWidth = frame.Width;
|
||||
BufferHeight = frame.Height;
|
||||
}
|
||||
if (rendersound)
|
||||
{
|
||||
_numSamples = frame.Samples;
|
||||
}
|
||||
else
|
||||
{
|
||||
_numSamples = 0;
|
||||
}
|
||||
|
||||
FrameAdvancePost();
|
||||
}
|
||||
|
@ -319,7 +329,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
{
|
||||
}
|
||||
|
||||
protected readonly short[] _soundBuffer;
|
||||
protected short[] _soundBuffer;
|
||||
protected int _numSamples;
|
||||
public bool CanProvideAsync => false;
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
|
|
@ -36,12 +36,13 @@ ECL_EXPORT bool Init(const InitData& data)
|
|||
samples = new int16_t[22050 * 2];
|
||||
Surf = new MDFN_Surface(
|
||||
pixels, Game->fb_width, Game->fb_height, Game->fb_width,
|
||||
MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 0, 8, 16, 24)
|
||||
MDFN_PixelFormat(MDFN_COLORSPACE_RGB, 16, 8, 0, 24)
|
||||
);
|
||||
EES = new EmulateSpecStruct();
|
||||
EES->surface = Surf;
|
||||
EES->VideoFormatChanged = true;
|
||||
EES->LineWidths = new int32_t[Game->fb_height];
|
||||
memset(EES->LineWidths, 0xff, Game->fb_height * sizeof(int32_t));
|
||||
EES->SoundBuf = samples;
|
||||
EES->SoundBufMaxSize = 22050;
|
||||
EES->SoundFormatChanged = true;
|
||||
|
@ -71,7 +72,8 @@ ECL_EXPORT bool Init(const InitData& data)
|
|||
struct MyFrameInfo: public FrameInfo
|
||||
{
|
||||
// true to skip video rendering
|
||||
int32_t SkipRendering;
|
||||
int16_t SkipRendering;
|
||||
int16_t SkipSoundening;
|
||||
// a single MDFN_MSC_* command to run at the start of this frame; 0 if none
|
||||
int32_t Command;
|
||||
// raw data for each input port, assumed to be MAX_PORTS * MAX_PORT_DATA long
|
||||
|
@ -92,24 +94,43 @@ ECL_EXPORT void FrameAdvance(MyFrameInfo& frame)
|
|||
|
||||
EES->VideoFormatChanged = false;
|
||||
EES->SoundFormatChanged = false;
|
||||
frame.Cycles = EES->MasterCycles; // TODO: Was this supposed to be total or delta?
|
||||
memcpy(frame.SoundBuffer, EES->SoundBuf, EES->SoundBufSize * 4);
|
||||
frame.Samples = EES->SoundBufSize;
|
||||
|
||||
// TODO: Use linewidths
|
||||
int w = EES->DisplayRect.w;
|
||||
int h = EES->DisplayRect.h;
|
||||
frame.Width = w;
|
||||
frame.Height = h;
|
||||
int srcp = Game->fb_width;
|
||||
int dstp = Game->fb_height;
|
||||
uint32_t* src = pixels + EES->DisplayRect.x + EES->DisplayRect.y * srcp;
|
||||
uint32_t* dst = pixels;
|
||||
for (int line = 0; line < h; line++)
|
||||
frame.Cycles = EES->MasterCycles;
|
||||
if (!frame.SkipSoundening)
|
||||
{
|
||||
memcpy(dst, src, w * 4);
|
||||
src += srcp;
|
||||
dst += dstp;
|
||||
memcpy(frame.SoundBuffer, EES->SoundBuf, EES->SoundBufSize * 4);
|
||||
frame.Samples = EES->SoundBufSize;
|
||||
}
|
||||
if (!frame.SkipRendering)
|
||||
{
|
||||
int h = EES->DisplayRect.h;
|
||||
int lineStart = EES->DisplayRect.y;
|
||||
int lineEnd = lineStart + h;
|
||||
|
||||
auto multiWidth = EES->LineWidths[0] != -1;
|
||||
int w;
|
||||
if (multiWidth)
|
||||
{
|
||||
w = 0;
|
||||
for (int line = lineStart; line < lineEnd; line++)
|
||||
w = std::max(w, EES->LineWidths[line]);
|
||||
}
|
||||
else
|
||||
{
|
||||
w = EES->DisplayRect.w;
|
||||
}
|
||||
|
||||
frame.Width = w;
|
||||
frame.Height = h;
|
||||
int srcp = Game->fb_width;
|
||||
int dstp = w;
|
||||
uint32_t* src = pixels + EES->DisplayRect.x + EES->DisplayRect.y * srcp;
|
||||
uint32_t* dst = frame.VideoBuffer;
|
||||
for (int line = lineStart; line < lineEnd; line++)
|
||||
{
|
||||
memcpy(dst, src, (multiWidth ? EES->LineWidths[line] : w) * sizeof(uint32_t));
|
||||
src += srcp;
|
||||
dst += dstp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue