progress, or regress, or somegress

This commit is contained in:
nattthebear 2020-05-23 18:36:42 -04:00
parent 24286be735
commit 257aa991fd
13 changed files with 388 additions and 279 deletions

Binary file not shown.

View File

@ -978,7 +978,9 @@ namespace BizHawk.Client.Common
if (core != null)
{
// use CoreInventory
nextEmulator = core.Create(nextComm, game, rom.RomData, rom.FileData, Deterministic, GetCoreSettings(core.Type), GetCoreSyncSettings(core.Type));
nextEmulator = core.Create(
nextComm, game, rom.RomData, rom.FileData, Deterministic,
GetCoreSettings(core.Type), GetCoreSyncSettings(core.Type), rom.Extension);
}
}

View File

@ -7,7 +7,7 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
<DefineConstants>$(DefineConstants);EXE_PROJECT</DefineConstants>
<OutputPath>$(ProjectDir)../../output</OutputPath>
<OutputType>WinExe</OutputType>
<OutputType>Exe</OutputType>
<TargetFramework>net48</TargetFramework>
<TargetName>EmuHawk</TargetName>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>

View File

@ -7,13 +7,14 @@ namespace BizHawk.Emulation.Cores.Consoles.NEC.PCE
public class TerboGrafix : NymaCore, IRegionable
{
[CoreConstructor("PCE")]
public TerboGrafix(GameInfo game, byte[] rom, CoreComm comm)
public TerboGrafix(GameInfo game, byte[] rom, CoreComm comm, string extension)
: base(game, rom, comm, new Configuration
{
SystemId = "PCE" // whatever
// TODO: This stuff isn't used so much
})
{
DoInit<LibNymaCore>(game, rom, "pce.wbx");
DoInit<LibNymaCore>(game, rom, "pce.wbx", extension);
}
}
}

View File

@ -28,20 +28,21 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
[CoreConstructor("DNGP")]
public DualNeoGeoPort(CoreComm comm, byte[] rom, bool deterministic)
{
// this will throw on construct: we need to compile two different copies of ngp at different starts
CoreComm = comm;
_left = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
_right = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
_linkCable = new LinkCable();
_leftEnd = new LinkInterop(_left, _linkCable.LeftIn, _linkCable.LeftOut);
_rightEnd = new LinkInterop(_right, _linkCable.RightIn, _linkCable.RightOut);
throw new NotImplementedException();
// // this will throw on construct: we need to compile two different copies of ngp at different starts
// CoreComm = comm;
// _left = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
// _right = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, WaterboxHost.CanonicalStart);
// _linkCable = new LinkCable();
// _leftEnd = new LinkInterop(_left, _linkCable.LeftIn, _linkCable.LeftOut);
// _rightEnd = new LinkInterop(_right, _linkCable.RightIn, _linkCable.RightOut);
_serviceProvider = new BasicServiceProvider(this);
_soundProvider = new DualSyncSound(_left, _right);
_serviceProvider.Register<ISoundProvider>(_soundProvider);
_videoProvider = new SideBySideVideo(_left, _right);
_serviceProvider.Register<IVideoProvider>(_videoProvider);
// _serviceProvider = new BasicServiceProvider(this);
// _soundProvider = new DualSyncSound(_left, _right);
// _serviceProvider.Register<ISoundProvider>(_soundProvider);
// _videoProvider = new SideBySideVideo(_left, _right);
// _serviceProvider.Register<IVideoProvider>(_videoProvider);
}
public bool FrameAdvance(IController controller, bool render, bool rendersound = true)

View File

@ -80,7 +80,8 @@ namespace BizHawk.Emulation.Cores
byte[] file,
bool deterministic,
object settings,
object syncSettings
object syncSettings,
string extension
)
{
object[] o = new object[_paramMap.Count];
@ -91,6 +92,7 @@ namespace BizHawk.Emulation.Cores
Bp(o, "deterministic", deterministic);
Bp(o, "settings", settings);
Bp(o, "syncsettings", syncSettings);
Bp(o, "extension", extension);
return (IEmulator)CTor.Invoke(o);
}

View File

@ -137,7 +137,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
var actuallySaved = allocated.Where(a => a.LoadAddress + a.Size > _saveStart);
var oopsSaved = actuallySaved.Except(saveable);
foreach (var s in oopsSaved)
throw new InvalidOperationException($"ElfLoader: Section {s.Name} will be saved, but that was not expected");
{
Console.WriteLine($"ElfLoader: Section {s.Name} will be saved, but that was not expected");
}
}
PrintSections();

View File

@ -70,69 +70,36 @@ namespace BizHawk.Emulation.Cores.Waterbox
public byte* InputPortData;
}
/// <summary>
/// Gets raw layer data to be handled by NymaCore.GetLayerData
/// </summary>
[BizImport(CC)]
public abstract byte* GetLayerData();
/// <summary>
/// Gets a string array of valid layers to pass to SetLayers, or null if that method should not be called
/// TODO: This needs to be in NymaCore under a monitor lock
/// Set enabled layers (or is it disabled layers?). Only call if NymaCore.GetLayerData() returned non null
/// </summary>
public string[] GetLayerDataReal()
{
var p = GetLayerData();
if (p == null)
return null;
var ret = new List<string>();
var q = p;
while (true)
{
if (*q == 0)
{
if (q > p)
ret.Add(Marshal.PtrToStringAnsi((IntPtr)p));
else
break;
p = ++q;
}
q++;
}
return ret.ToArray();
}
/// <summary>
/// Set enabled layers (or is it disabled layers?). Only call if GetLayerDataReal() returned non null
/// </summary>
/// <param name="layers">bitmask in order defined by GetLayerDataReal</param>
/// <param name="layers">bitmask in order defined by NymaCore.GetLayerData</param>
[BizImport(CC)]
public abstract void SetLayers(ulong layers);
public enum InputType : byte
{
PADDING = 0, // n-bit, zero
BUTTON, // 1-bit
BUTTON_CAN_RAPID, // 1-bit
SWITCH, // ceil(log2(n))-bit
// Current switch position(default 0).
// Persistent, and bidirectional communication(can be modified driver side, and Mednafen core and emulation module side)
STATUS, // ceil(log2(n))-bit
// emulation module->driver communication
AXIS, // 16-bits; 0 through 65535; 32768 is centered position
POINTER_X, // mouse pointer, 16-bits, signed - in-screen/window range before scaling/offseting normalized coordinates: [0.0, 1.0)
POINTER_Y, // see: mouse_scale_x, mouse_scale_y, mouse_offs_x, mouse_offs_y
AXIS_REL, // mouse relative motion, 16-bits, signed
BYTE_SPECIAL,
RESET_BUTTON, // 1-bit
BUTTON_ANALOG, // 16-bits, 0 - 65535
RUMBLE, // 16-bits, lower 8 bits are weak rumble(0-255), next 8 bits are strong rumble(0-255), 0=no rumble, 255=max rumble. Somewhat subjective, too...
}
@ -155,91 +122,119 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
[StructLayout(LayoutKind.Sequential)]
public class NPortInfos
public struct NPortInfo
{
[MarshalAs(UnmanagedType.LPArray, SizeConst = 16)]
public NPortInfo[] Infos;
public IntPtr _shortName;
public IntPtr _fullName;
public IntPtr _defaultDeviceShortName;
public uint NumDevices;
public string ShortName => Marshal.PtrToStringAnsi(_shortName);
public string FullName => Marshal.PtrToStringAnsi(_fullName);
public string DefaultDeviceShortName => Marshal.PtrToStringAnsi(_defaultDeviceShortName);
}
[StructLayout(LayoutKind.Sequential)]
public class NPortInfo
public struct NDeviceInfo
{
public string ShortName;
public string FullName;
public string DefaultDeviceShortName;
public IntPtr _shortName;
public IntPtr _fullName;
public IntPtr _description;
public DeviceFlags Flags;
public uint ByteLength;
public uint NumInputs;
public string ShortName => Marshal.PtrToStringAnsi(_shortName);
public string FullName => Marshal.PtrToStringAnsi(_fullName);
public string Description => Marshal.PtrToStringAnsi(_description);
}
[StructLayout(LayoutKind.Sequential)]
public struct NInputInfo
{
public IntPtr _settingName;
public IntPtr _name;
public short ConfigOrder;
public ushort BitOffset;
public InputType Type;
public AxisFlags Flags;
public byte BitSize;
public string SettingName => Marshal.PtrToStringAnsi(_settingName);
public string Name => Marshal.PtrToStringAnsi(_name);
}
[StructLayout(LayoutKind.Sequential)]
public struct NButtonInfo
{
public IntPtr _excludeName;
public string ExcludeName => Marshal.PtrToStringAnsi(_excludeName);
}
[StructLayout(LayoutKind.Sequential)]
public struct NAxisInfo
{
public IntPtr _settingsNameNeg;
public IntPtr _settingsNamePos;
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);
}
[StructLayout(LayoutKind.Sequential)]
public struct NSwitchInfo
{
public uint NumPositions;
public uint DefaultPosition;
[StructLayout(LayoutKind.Sequential)]
public class NDeviceInfo
public struct Position
{
public string ShortName;
public string FullName;
public string Description;
public DeviceFlags Flags;
public uint ByteLength;
[StructLayout(LayoutKind.Sequential)]
public class NInput
{
public string SettingName;
public string Name;
public short ConfigOrder;
public ushort BitOffset;
public InputType Type;
public AxisFlags Flags;
public byte BitSize;
public byte _Padding;
[StructLayout(LayoutKind.Sequential)]
public class Button
{
public string ExcludeName;
}
[StructLayout(LayoutKind.Sequential)]
public class Axis
{
public string SettingsNameNeg;
public string SettingsNamePos;
public string NameNeg;
public string NamePos;
}
[StructLayout(LayoutKind.Sequential)]
public class Switch
{
[StructLayout(LayoutKind.Sequential)]
public class Position
{
public string SettingName;
public string Name;
public string Description;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public Position[] Positions;
public uint NumPositions;
public uint DefaultPosition;
}
[StructLayout(LayoutKind.Sequential)]
public class Status
{
public class State
{
public IntPtr ShortName;
public IntPtr Name;
public int Color; // (msb)0RGB(lsb), -1 for unused.
public int _Padding;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public State[] States;
public uint NumStates;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 400)]
public byte[] UnionData;
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public NInput[] Inputs;
public IntPtr _settingName;
public IntPtr _name;
public IntPtr _description;
public string SettingName => Marshal.PtrToStringAnsi(_settingName);
public string Name => Marshal.PtrToStringAnsi(_name);
public string Description => Marshal.PtrToStringAnsi(_description);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct NStatusInfo
{
public uint NumStates;
[StructLayout(LayoutKind.Sequential)]
public struct State
{
public IntPtr _shortName;
public IntPtr _name;
public int Color; // (msb)0RGB(lsb), -1 for unused.
public int _Padding;
public string ShortName => Marshal.PtrToStringAnsi(_shortName);
public string Name => Marshal.PtrToStringAnsi(_name);
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public NDeviceInfo[] Devices;
}
[BizImport(CC, Compatibility = true)]
public abstract NPortInfos GetInputDevices();
public abstract uint GetNumPorts();
[BizImport(CC, Compatibility = true)]
public abstract NPortInfo* GetPort(uint port);
[BizImport(CC, Compatibility = true)]
public abstract NDeviceInfo* GetDevice(uint port, uint dev);
[BizImport(CC, Compatibility = true)]
public abstract NInputInfo* GetInput(uint port, uint dev, uint input);
[BizImport(CC, Compatibility = true)]
public abstract NButtonInfo* GetButton(uint port, uint dev, uint input);
[BizImport(CC, Compatibility = true)]
public abstract NSwitchInfo* GetSwitch(uint port, uint dev, uint input);
[BizImport(CC, Compatibility = true)]
public abstract NSwitchInfo.Position* GetSwitchPosition(uint port, uint dev, uint input, int i);
[BizImport(CC, Compatibility = true)]
public abstract NStatusInfo* GetStatus(uint port, uint dev, uint input);
[BizImport(CC, Compatibility = true)]
public abstract NStatusInfo.State* GetStatusState(uint port, uint dev, uint input, int i);
[BizImport(CC, Compatibility = true)]
public abstract NAxisInfo* GetAxis(uint port, uint dev, uint input);
[BizImport(CC, Compatibility = true)]
public abstract void SetInputDevices(string[] devices);

View File

@ -18,7 +18,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
private ControllerAdapter _controllerAdapter;
private readonly byte[] _inputPortData = new byte[16 * 16];
protected T DoInit<T>(GameInfo game, byte[] rom, string filename)
protected T DoInit<T>(GameInfo game, byte[] rom, string filename, string extension)
where T : LibNymaCore
{
var t = PreInit<T>(new WaterboxOptions
@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
// TODO: Set these as some cores need them
FileNameBase = "",
FileNameExt = "",
FileNameExt = extension.Trim('.').ToLowerInvariant(),
FileNameFull = fn
});
@ -76,7 +76,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
VsyncNumerator = info.FpsFixed;
VsyncDenominator = 1 << 24;
_controllerAdapter = new ControllerAdapter(_nyma.GetInputDevices().Infos, new string[0]);
_controllerAdapter = new ControllerAdapter(_nyma, new string[0]);
_nyma.SetInputDevices(_controllerAdapter.Devices);
PostInit();
@ -105,21 +105,13 @@ namespace BizHawk.Emulation.Cores.Waterbox
_frameAdvanceInputLock.Free();
}
private static T ControllerData<T>(byte[] data)
{
fixed(byte *p = data)
{
return (T)Marshal.PtrToStructure((IntPtr)p, typeof(T));
}
}
protected delegate void ControllerThunk(IController c, byte[] b);
protected class ControllerAdapter
{
public string[] Devices { get; }
public ControllerDefinition Definition { get; }
public ControllerAdapter(LibNymaCore.NPortInfo[] portInfos, string[] devices)
public ControllerAdapter(LibNymaCore core, string[] config)
{
var ret = new ControllerDefinition
{
@ -128,17 +120,36 @@ namespace BizHawk.Emulation.Cores.Waterbox
var finalDevices = new List<string>();
for (int i = 0, devByteStart = 0; i < portInfos.Length && portInfos[i].ShortName != null; i++)
var numPorts = core.GetNumPorts();
for (uint i = 0, devByteStart = 0; i < numPorts; i++)
{
var port = portInfos[i];
var devName = i < devices.Length ? devices[i] : port.DefaultDeviceShortName;
var port = *core.GetPort(i);
var devName = i < config.Length ? config[i] : port.DefaultDeviceShortName;
finalDevices.Add(devName);
var dev = port.Devices.SingleOrDefault(d => d.ShortName == 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;
foreach (var input in dev.Inputs.OrderBy(i => i.ConfigOrder))
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;
@ -153,7 +164,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
case LibNymaCore.InputType.BUTTON:
case LibNymaCore.InputType.BUTTON_CAN_RAPID:
{
var data = ControllerData<LibNymaCore.NPortInfo.NDeviceInfo.NInput.Button>(input.UnionData);
var data = *core.GetButton(i, device.Index, (uint)inputzz.Index);
// TODO: Wire up data.ExcludeName
ret.BoolButtons.Add(name);
_thunks.Add((c, b) =>
@ -165,7 +176,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
case LibNymaCore.InputType.SWITCH:
{
var data = ControllerData<LibNymaCore.NPortInfo.NDeviceInfo.NInput.Switch>(input.UnionData);
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(
@ -179,7 +190,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
case LibNymaCore.InputType.AXIS:
{
var data = ControllerData<LibNymaCore.NPortInfo.NDeviceInfo.NInput.Axis>(input.UnionData);
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
@ -194,7 +205,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
case LibNymaCore.InputType.AXIS_REL:
{
var data = ControllerData<LibNymaCore.NPortInfo.NDeviceInfo.NInput.Axis>(input.UnionData);
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
@ -221,13 +232,14 @@ namespace BizHawk.Emulation.Cores.Waterbox
// 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 += (int)dev.ByteLength;
devByteStart += dev.ByteLength;
}
Definition = ret;
Devices = finalDevices.ToArray();
@ -244,5 +256,33 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
public DisplayType Region { get; protected set; }
/// <summary>
/// Gets a string array of valid layers to pass to SetLayers, or null if that method should not be called
/// </summary>
private string[] GetLayerData()
{
using (_exe.EnterExit())
{
var p = _nyma.GetLayerData();
if (p == null)
return null;
var ret = new List<string>();
var q = p;
while (true)
{
if (*q == 0)
{
if (q > p)
ret.Add(Marshal.PtrToStringAnsi((IntPtr)p));
else
break;
p = ++q;
}
q++;
}
return ret.ToArray();
}
}
}
}

View File

@ -229,7 +229,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
_disposeList.Add(_mmapheap);
}
Console.WriteLine("About to enter unmanaged code");
System.Diagnostics.Debug.WriteLine($"About to enter unmanaged code for {opt.Filename}");
if (!OSTailoredCode.IsUnixHost && !System.Diagnostics.Debugger.IsAttached && Win32Imports.IsDebuggerPresent())
{
// this means that GDB or another unconventional debugger is attached.

View File

@ -0,0 +1,20 @@
{
"configurations": [
{
"name": "Waterbox",
"includePath": [
"${workspaceFolder}",
"${workspaceFolder}/mednafen/include",
"${workspaceFolder}/common",
"${workspaceFolder}/mednafen/src/trio",
"${workspaceFolder}/../sysroot/include",
"${workspaceFolder}/../sysroot/include/c++/v1",
"${workspaceFolder}/../emulibc"
],
"defines": [
],
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}

View File

@ -62,24 +62,50 @@ namespace Mednafen
abort();
}
static const MDFNSetting* GetSetting(const char* name)
{
const MDFNSetting* s;
for (int i = 0; s = &MDFNGameInfo->Settings[i], s->name; i++)
{
if (strcmp(s->name, name) == 0)
return s;
}
return nullptr;
}
uint64 MDFN_GetSettingUI(const char *name)
{
auto s = GetSetting(name);
if (s)
return strtoul(s->default_value, nullptr, 10);
return 0;
}
int64 MDFN_GetSettingI(const char *name)
{
auto s = GetSetting(name);
if (s)
return strtol(s->default_value, nullptr, 10);
return 0;
}
double MDFN_GetSettingF(const char *name)
{
auto s = GetSetting(name);
if (s)
return strtod(s->default_value, nullptr);
return 0;
}
bool MDFN_GetSettingB(const char *name)
{
return false;
auto s = GetSetting(name);
if (s)
return strtol(s->default_value, nullptr, 10) != 0;
return 0;
}
std::string MDFN_GetSettingS(const char *name)
{
auto s = GetSetting(name);
if (s)
return s->default_value;
return "";
}

View File

@ -146,7 +146,12 @@ ECL_EXPORT void SetLayers(uint64_t layers)
}
ECL_EXPORT void GetMemoryAreas(MemoryArea* m)
{}
{
m[0].Data = (void*)pixels;
m[0].Name = "PEWP";
m[0].Size = Game->fb_width * Game->fb_height * 4;
m[0].Flags = MEMORYAREA_FLAGS_PRIMARY | MEMORYAREA_FLAGS_WORDSIZE4;
}
ECL_EXPORT void SetInputCallback(void (*cb)())
{}
@ -157,140 +162,155 @@ struct NPortInfo
const char* ShortName;
const char* FullName;
const char* DefaultDeviceShortName;
struct NDeviceInfo
uint32_t NumDevices;
};
struct NDeviceInfo
{
const char* ShortName;
const char* FullName;
const char* Description;
uint32_t Flags;
uint32_t ByteLength;
uint32_t NumInputs;
};
struct NInputInfo
{
const char* SettingName;
const char* Name;
int16_t ConfigOrder;
uint16_t BitOffset;
InputDeviceInputType Type; // uint8_t
uint8_t Flags;
uint8_t BitSize;
};
struct NButtonInfo
{
const char* ExcludeName;
};
struct NAxisInfo
{
// negative, then positive
const char* SettingName[2];
const char* Name[2];
};
struct NSwitchInfo
{
uint32_t NumPositions;
uint32_t DefaultPosition;
struct Position
{
const char* SettingName;
const char* Name;
const char* Description;
};
};
struct NStatusInfo
{
uint32_t NumStates;
struct State
{
const char* ShortName;
const char* FullName;
const char* Description;
uint32_t Flags;
uint32_t ByteLength;
struct NInput
{
const char* SettingName;
const char* Name;
int16_t ConfigOrder;
uint16_t BitOffset;
InputDeviceInputType Type; // uint8_t
uint8_t Flags;
uint8_t BitSize;
uint8_t _Padding;
union
{
struct
{
const char* ExcludeName;
} Button;
struct
{
// negative, then positive
const char* SettingName[2];
const char* Name[2];
} Axis;
struct
{
struct
{
const char* SettingName;
const char* Name;
const char* Description;
} Positions[16];
uint32_t NumPositions;
uint32_t DefaultPosition;
} Switch;
struct
{
struct
{
const char* ShortName;
const char* Name;
int32_t Color; // (msb)0RGB(lsb), -1 for unused.
int32_t _Padding;
} States[16];
uint32_t NumStates;
} Status;
uint8_t _Padding2[400];
};
} Inputs[256];
} Devices[32];
const char* Name;
int32_t Color; // (msb)0RGB(lsb), -1 for unused.
int32_t _Padding;
};
};
NPortInfo PortInfos[MAX_PORTS] = {};
ECL_EXPORT NPortInfo* GetInputDevices()
ECL_EXPORT uint32_t GetNumPorts()
{
for (unsigned port = 0; port < MAX_PORTS && port < Game->PortInfo.size(); port++)
{
auto& a = PortInfos[port];
auto& x = Game->PortInfo[port];
a.ShortName = x.ShortName;
a.FullName = x.FullName;
a.DefaultDeviceShortName = x.DefaultDevice;
for (unsigned dev = 0; dev < 32 && dev < x.DeviceInfo.size(); dev++)
{
auto& b = a.Devices[dev];
auto& y = x.DeviceInfo[dev];
b.ShortName = y.ShortName;
b.FullName = y.FullName;
b.Description = y.Description;
b.Flags = y.Flags;
b.ByteLength = y.IDII.InputByteSize;
for (unsigned input = 0; input < 256 && input < y.IDII.size(); input++)
{
auto& c = b.Inputs[input];
auto& z = y.IDII[input];
c.SettingName = z.SettingName;
c.Name = z.Name;
c.ConfigOrder = z.ConfigOrder;
c.BitOffset = z.BitOffset;
c.Type = z.Type;
c.Flags = z.Flags;
c.BitSize = z.BitSize;
switch (z.Type)
{
case IDIT_BUTTON:
case IDIT_BUTTON_CAN_RAPID:
c.Button.ExcludeName = z.Button.ExcludeName;
break;
case IDIT_SWITCH:
c.Switch.NumPositions = z.Switch.NumPos;
c.Switch.DefaultPosition = z.Switch.DefPos;
for (unsigned i = 0; i < 16 && i < z.Switch.NumPos; i++)
{
c.Switch.Positions[i].SettingName = z.Switch.Pos[i].SettingName;
c.Switch.Positions[i].Name = z.Switch.Pos[i].Name;
c.Switch.Positions[i].Description = z.Switch.Pos[i].Description;
}
break;
case IDIT_STATUS:
c.Status.NumStates = z.Status.NumStates;
for (unsigned i = 0; i < 16 && i < z.Status.NumStates; i++)
{
c.Status.States[i].ShortName = z.Status.States[i].ShortName;
c.Status.States[i].Name = z.Status.States[i].Name;
c.Status.States[i].Color = z.Status.States[i].Color;
}
break;
case IDIT_AXIS:
case IDIT_AXIS_REL:
c.Axis.SettingName[0] = z.Axis.sname_dir[0];
c.Axis.SettingName[1] = z.Axis.sname_dir[1];
c.Axis.Name[0] = z.Axis.name_dir[0];
c.Axis.Name[1] = z.Axis.name_dir[1];
break;
default:
// other types have no extended information
break;
}
}
}
}
return PortInfos;
return Game->PortInfo.size();
}
ECL_EXPORT NPortInfo& GetPort(uint32_t port)
{
auto& a = *(NPortInfo*)InputPortData;
auto& x = Game->PortInfo[port];
a.ShortName = x.ShortName;
a.FullName = x.FullName;
a.DefaultDeviceShortName = x.DefaultDevice;
a.NumDevices = x.DeviceInfo.size();
return a;
}
ECL_EXPORT NDeviceInfo& GetDevice(uint32_t port, uint32_t dev)
{
auto& b = *(NDeviceInfo*)InputPortData;
auto& y = Game->PortInfo[port].DeviceInfo[dev];
b.ShortName = y.ShortName;
b.FullName = y.FullName;
b.Description = y.Description;
b.Flags = y.Flags;
b.ByteLength = y.IDII.InputByteSize;
b.NumInputs = y.IDII.size();
return b;
}
ECL_EXPORT NInputInfo& GetInput(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NInputInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input];
c.SettingName = z.SettingName;
c.Name = z.Name;
c.ConfigOrder = z.ConfigOrder;
c.BitOffset = z.BitOffset;
c.Type = z.Type;
c.Flags = z.Flags;
c.BitSize = z.BitSize;
return c;
}
ECL_EXPORT NButtonInfo& GetButton(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NButtonInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Button;
c.ExcludeName = z.ExcludeName;
return c;
}
ECL_EXPORT NSwitchInfo& GetSwitch(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NSwitchInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Switch;
c.NumPositions = z.NumPos;
c.DefaultPosition = z.DefPos;
return c;
}
ECL_EXPORT NSwitchInfo::Position& GetSwitchPosition(uint32_t port, uint32_t dev, uint32_t input, int i)
{
auto& c = *(NSwitchInfo::Position*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Switch;
c.SettingName = z.Pos[i].SettingName;
c.Name = z.Pos[i].Name;
c.Description = z.Pos[i].Description;
return c;
}
ECL_EXPORT NStatusInfo& GetStatus(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NStatusInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Status;
c.NumStates = z.NumStates;
return c;
}
ECL_EXPORT NStatusInfo::State& GetStatusState(uint32_t port, uint32_t dev, uint32_t input, int i)
{
auto& c = *(NStatusInfo::State*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Status;
c.ShortName = z.States[i].ShortName;
c.Name = z.States[i].Name;
c.Color = z.States[i].Color;
return c;
}
ECL_EXPORT NAxisInfo& GetAxis(uint32_t port, uint32_t dev, uint32_t input)
{
auto& c = *(NAxisInfo*)InputPortData;
auto& z = Game->PortInfo[port].DeviceInfo[dev].IDII[input].Axis;
c.SettingName[0] = z.sname_dir[0];
c.SettingName[1] = z.sname_dir[1];
c.Name[0] = z.name_dir[0];
c.Name[1] = z.name_dir[1];
return c;
}
ECL_EXPORT void SetInputDevices(const char** devices)
{
for (unsigned port = 0; port < MAX_PORTS && devices[port]; port++)
{
Game->SetInput(port, devices[port], &InputPortData[port * MAX_PORT_DATA]);
std::string dev(devices[port]);
Game->SetInput(port, dev.c_str(), &InputPortData[port * MAX_PORT_DATA]);
}
}