Update quickerNES and add Arkanoid input support (squashed PR #3997)
* Update QuickerNES interface to accept arkanoid controllers * Updating * Updating quickernes to its latest version and now supporting ArkanoidNES and ArkanoidFamicom controllers * Apply suggestions from code review applying yoshi's suggestions Co-authored-by: James Groom <OSSYoshiRulz+GitHub@gmail.com> * Using proper C# * Updating based on Morilli's comments * Updating the linux core * Fixes based on Yoshi's comments --------- Co-authored-by: James Groom <OSSYoshiRulz+GitHub@gmail.com>
This commit is contained in:
parent
5e9d3cd2bc
commit
aa662eb930
Binary file not shown.
Binary file not shown.
|
@ -50,9 +50,45 @@ QN_EXPORT const char *qn_set_sample_rate(quickerNES::Emu *e, int rate)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QN_EXPORT const char *qn_emulate_frame(quickerNES::Emu *e, int pad1, int pad2)
|
|
||||||
|
QN_EXPORT const char *qn_emulate_frame(quickerNES::Emu *e, uint32_t pad1, uint32_t pad2, uint8_t arkanoidPosition, uint8_t arkanoidFire, int controllerType)
|
||||||
{
|
{
|
||||||
return e->emulate_frame((uint32_t)pad1, (uint32_t)pad2);
|
e->setControllerType((quickerNES::Core::controllerType_t)controllerType);
|
||||||
|
|
||||||
|
uint32_t arkanoidLatch = 0;
|
||||||
|
|
||||||
|
if ((quickerNES::Core::controllerType_t) controllerType == quickerNES::Core::controllerType_t::arkanoidNES_t ||
|
||||||
|
(quickerNES::Core::controllerType_t) controllerType == quickerNES::Core::controllerType_t::arkanoidFamicom_t)
|
||||||
|
{
|
||||||
|
e->setControllerType((quickerNES::Core::controllerType_t) controllerType);
|
||||||
|
|
||||||
|
// This is where we calculate the stream of bits required by the NES / Famicom to correctly interpret the Arkanoid potentiometer signal
|
||||||
|
// The logic and procedure were created based on the information in https://www.nesdev.org/wiki/Arkanoid_controller
|
||||||
|
// - The arkanoidPosition variable is the intended value
|
||||||
|
// - The centeringPotValue is a calibration parameter. The arkanoidPosition value is passed to the console as a relative value to this.
|
||||||
|
// This can be change tod calibrate a misaligned physical potentiomenter (not relevant in emulation)
|
||||||
|
// The minumum / maximum ranges for this values are (0x0D-0xAD) to (0x5C-0xFC). NesHawk seems to be calibrated at: 0xAB (171).
|
||||||
|
|
||||||
|
// The value of centeringPotValue is calibrated to coincide exactly with that of the NesHawk emulator
|
||||||
|
uint8_t centeringPotValue = 0xAB;
|
||||||
|
|
||||||
|
// Procedure, as expected by the console:
|
||||||
|
// 1) Obtain the relative value of arkanoidPosition from the centeringPotValue
|
||||||
|
uint8_t relativePosition = centeringPotValue - arkanoidPosition;
|
||||||
|
|
||||||
|
// 2) The result is bit-inverted (required by the console)
|
||||||
|
// The easiest solution is simply to do this per bit
|
||||||
|
if ((relativePosition & 128) > 0) arkanoidLatch += 1;
|
||||||
|
if ((relativePosition & 64) > 0) arkanoidLatch += 2;
|
||||||
|
if ((relativePosition & 32) > 0) arkanoidLatch += 4;
|
||||||
|
if ((relativePosition & 16) > 0) arkanoidLatch += 8;
|
||||||
|
if ((relativePosition & 8) > 0) arkanoidLatch += 16;
|
||||||
|
if ((relativePosition & 4) > 0) arkanoidLatch += 32;
|
||||||
|
if ((relativePosition & 2) > 0) arkanoidLatch += 64;
|
||||||
|
if ((relativePosition & 1) > 0) arkanoidLatch += 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
return e->emulate_frame(pad1, pad2, arkanoidLatch, arkanoidFire);
|
||||||
}
|
}
|
||||||
|
|
||||||
QN_EXPORT void qn_blit(quickerNES::Emu *e, int32_t *dest, const int32_t *colors, int cropleft, int croptop, int cropright, int cropbottom)
|
QN_EXPORT void qn_blit(quickerNES::Emu *e, int32_t *dest, const int32_t *colors, int cropleft, int croptop, int cropright, int cropbottom)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 027f63aee19840ac1bf571a5d00d7758ca517220
|
Subproject commit 61ff28710c44b75c170dff1ee8f89831296e34b5
|
|
@ -4,7 +4,7 @@ CP = cp
|
||||||
|
|
||||||
CXXFLAGS = -I../core/source/quickerNES/core/ -I../core/extern/jaffarCommon/include -Wall -Wfatal-errors -Werror \
|
CXXFLAGS = -I../core/source/quickerNES/core/ -I../core/extern/jaffarCommon/include -Wall -Wfatal-errors -Werror \
|
||||||
-std=c++20 -O3 -fomit-frame-pointer -flto -fvisibility=internal -fvisibility-inlines-hidden \
|
-std=c++20 -O3 -fomit-frame-pointer -flto -fvisibility=internal -fvisibility-inlines-hidden \
|
||||||
-D_GNU_SOURCE -D__INLINE__=inline -D_QUICKERNES_DETECT_JOYPAD_READS -D_QUICKERNES_ENABLE_TRACEBACK_SUPPORT
|
-D_GNU_SOURCE -D__INLINE__=inline -D_QUICKERNES_DETECT_JOYPAD_READS -D_QUICKERNES_ENABLE_TRACEBACK_SUPPORT -D_QUICKERNES_SUPPORT_ARKANOID_INPUTS
|
||||||
|
|
||||||
# TODO: include these as options in the Makefile
|
# TODO: include these as options in the Makefile
|
||||||
# -fprofile-generate
|
# -fprofile-generate
|
||||||
|
|
|
@ -149,6 +149,7 @@
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<IncludePath>..\core\source\quickerNES\core;..\core\extern\jaffarCommon\include;$(IncludePath)</IncludePath>
|
<IncludePath>..\core\source\quickerNES\core;..\core\extern\jaffarCommon\include;$(IncludePath)</IncludePath>
|
||||||
|
<OutDir>..\Assets\dll</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<IncludePath>..\core\source\quickerNES\core;..\core\extern\jaffarCommon\include;$(IncludePath)</IncludePath>
|
<IncludePath>..\core\source\quickerNES\core;..\core\extern\jaffarCommon\include;$(IncludePath)</IncludePath>
|
||||||
|
@ -159,7 +160,7 @@
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)\..</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)\..</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);_QUICKERNES_DETECT_JOYPAD_READS;_QUICKERNES_ENABLE_TRACEBACK_SUPPORT;</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);_QUICKERNES_DETECT_JOYPAD_READS;_QUICKERNES_ENABLE_TRACEBACK_SUPPORT;_QUICKERNES_SUPPORT_ARKANOID_INPUTS;__INLINE__=inline</PreprocessorDefinitions>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -179,7 +180,7 @@
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)\..</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)\..</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);_QUICKERNES_DETECT_JOYPAD_READS;_QUICKERNES_ENABLE_TRACEBACK_SUPPORT;</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_WINDLL;%(PreprocessorDefinitions);_QUICKERNES_DETECT_JOYPAD_READS;_QUICKERNES_ENABLE_TRACEBACK_SUPPORT;_QUICKERNES_SUPPORT_ARKANOID_INPUTS;__INLINE__=inline</PreprocessorDefinitions>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
/// <param name="pad2">pad 2 input</param>
|
/// <param name="pad2">pad 2 input</param>
|
||||||
/// <returns>string error</returns>
|
/// <returns>string error</returns>
|
||||||
[BizImport(CallingConvention.Cdecl)]
|
[BizImport(CallingConvention.Cdecl)]
|
||||||
public abstract IntPtr qn_emulate_frame(IntPtr e, uint pad1, uint pad2);
|
public abstract IntPtr qn_emulate_frame(IntPtr e, uint pad1, uint pad2, byte arkanoidPos, byte arkanoidFire, uint controllerType);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// blit to rgb32
|
/// blit to rgb32
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -156,6 +156,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
Gamepad = 0x1,
|
Gamepad = 0x1,
|
||||||
FourScore = 0x2,
|
FourScore = 0x2,
|
||||||
//FourScore2 = 0x3, // not available for port 1
|
//FourScore2 = 0x3, // not available for port 1
|
||||||
|
ArkanoidNES = 0x4,
|
||||||
|
ArkanoidFamicom = 0x5,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Port2PeripheralOption : byte
|
public enum Port2PeripheralOption : byte
|
||||||
|
|
|
@ -82,21 +82,84 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
private void SetControllerDefinition()
|
private void SetControllerDefinition()
|
||||||
{
|
{
|
||||||
ControllerDefinition def = new("NES Controller");
|
ControllerDefinition def = new("NES Controller");
|
||||||
|
|
||||||
|
// Function to add gamepad buttons
|
||||||
void AddButtons(IEnumerable<(string PrefixedName, uint Bitmask)> entries)
|
void AddButtons(IEnumerable<(string PrefixedName, uint Bitmask)> entries)
|
||||||
=> def.BoolButtons.AddRange(entries.Select(static p => p.PrefixedName));
|
=> def.BoolButtons.AddRange(entries.Select(static p => p.PrefixedName));
|
||||||
AddButtons(_syncSettings.Port1 switch
|
|
||||||
|
// Parsing Port1 inputs
|
||||||
|
|
||||||
|
switch (_syncSettings.Port1)
|
||||||
{
|
{
|
||||||
Port1PeripheralOption.Gamepad => GamepadButtons[0],
|
case Port1PeripheralOption.Gamepad:
|
||||||
Port1PeripheralOption.FourScore => FourScoreButtons[0],
|
|
||||||
_ => Enumerable.Empty<(string PrefixedName, uint Bitmask)>()
|
// Adding set of gamepad buttons (P1)
|
||||||
});
|
AddButtons(GamepadButtons[0]);
|
||||||
AddButtons(_syncSettings.Port2 switch
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Port1PeripheralOption.FourScore:
|
||||||
|
|
||||||
|
// Adding set of gamepad buttons (P1)
|
||||||
|
AddButtons(FourScoreButtons[0]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Port1PeripheralOption.ArkanoidNES:
|
||||||
|
|
||||||
|
// Adding Arkanoid Paddle potentiometer
|
||||||
|
def.AddAxis("P2 Paddle", 0.RangeTo(160), 80);
|
||||||
|
|
||||||
|
// Adding Arkanoid Fire button
|
||||||
|
def.BoolButtons.Add("P2 Fire");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Port1PeripheralOption.ArkanoidFamicom:
|
||||||
|
|
||||||
|
// Adding set of gamepad buttons (P1)
|
||||||
|
AddButtons(GamepadButtons[0]);
|
||||||
|
|
||||||
|
// Adding dummy set of P2 buttons (not yet supported)
|
||||||
|
def.BoolButtons.Add("P2 Up");
|
||||||
|
def.BoolButtons.Add("P2 Down");
|
||||||
|
def.BoolButtons.Add("P2 Left");
|
||||||
|
def.BoolButtons.Add("P2 Right");
|
||||||
|
def.BoolButtons.Add("P2 B");
|
||||||
|
def.BoolButtons.Add("P2 A");
|
||||||
|
def.BoolButtons.Add("P2 M"); // Microphone
|
||||||
|
|
||||||
|
// Adding Arkanoid Paddle potentiometer
|
||||||
|
def.AddAxis("P3 Paddle", 0.RangeTo(160), 80);
|
||||||
|
|
||||||
|
// Adding Arkanoid Fire button
|
||||||
|
def.BoolButtons.Add("P3 Fire");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing Port2 inputs
|
||||||
|
|
||||||
|
switch (_syncSettings.Port2)
|
||||||
{
|
{
|
||||||
Port2PeripheralOption.Gamepad => GamepadButtons[1],
|
case Port2PeripheralOption.Gamepad:
|
||||||
Port2PeripheralOption.FourScore2 => FourScoreButtons[1],
|
|
||||||
_ => Enumerable.Empty<(string PrefixedName, uint Bitmask)>()
|
// Adding set of gamepad buttons (P1)
|
||||||
});
|
AddButtons(GamepadButtons[1]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Port2PeripheralOption.FourScore2:
|
||||||
|
|
||||||
|
// Adding set of gamepad buttons (P2)
|
||||||
|
AddButtons(FourScoreButtons[1]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding console buttons
|
||||||
def.BoolButtons.AddRange(new[] { "Reset", "Power" }); // console buttons
|
def.BoolButtons.AddRange(new[] { "Reset", "Power" }); // console buttons
|
||||||
|
|
||||||
ControllerDefinition = def.MakeImmutable();
|
ControllerDefinition = def.MakeImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +230,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void SetPads(IController controller, out uint j1, out uint j2)
|
private void SetPads(IController controller, out uint j1, out uint j2)
|
||||||
{
|
{
|
||||||
static uint PackGamepadButtonsFor(int portNumber, IController controller)
|
static uint PackGamepadButtonsFor(int portNumber, IController controller)
|
||||||
|
@ -198,6 +260,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
switch (_syncSettings.Port1)
|
switch (_syncSettings.Port1)
|
||||||
{
|
{
|
||||||
case Port1PeripheralOption.Gamepad:
|
case Port1PeripheralOption.Gamepad:
|
||||||
|
case Port1PeripheralOption.ArkanoidFamicom:
|
||||||
j1 = PackGamepadButtonsFor(0, controller);
|
j1 = PackGamepadButtonsFor(0, controller);
|
||||||
break;
|
break;
|
||||||
case Port1PeripheralOption.FourScore:
|
case Port1PeripheralOption.FourScore:
|
||||||
|
@ -215,6 +278,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum QuickerNESInternalControllerTypeEnumeration : byte
|
||||||
|
{
|
||||||
|
None = 0x0,
|
||||||
|
Joypad = 0x1,
|
||||||
|
ArkanoidNES = 0x2,
|
||||||
|
ArkanoidFamicom = 0x3,
|
||||||
|
}
|
||||||
|
|
||||||
public bool FrameAdvance(IController controller, bool render, bool rendersound = true)
|
public bool FrameAdvance(IController controller, bool render, bool rendersound = true)
|
||||||
{
|
{
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
@ -228,7 +299,47 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
|
|
||||||
QN.qn_set_tracecb(Context, Tracer.IsEnabled() ? _traceCb : null);
|
QN.qn_set_tracecb(Context, Tracer.IsEnabled() ? _traceCb : null);
|
||||||
|
|
||||||
LibQuickNES.ThrowStringError(QN.qn_emulate_frame(Context, j1, j2));
|
// Getting correct internal controller type for QuickerNES
|
||||||
|
QuickerNESInternalControllerTypeEnumeration internalQuickerNESControllerType = QuickerNESInternalControllerTypeEnumeration.None;
|
||||||
|
|
||||||
|
// Handling Port2
|
||||||
|
switch (_syncSettings.Port2)
|
||||||
|
{
|
||||||
|
case Port2PeripheralOption.Gamepad:
|
||||||
|
case Port2PeripheralOption.FourScore2:
|
||||||
|
internalQuickerNESControllerType = QuickerNESInternalControllerTypeEnumeration.Joypad; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handling Port1 -- Using Arkanoid overrides the selection for Port2
|
||||||
|
switch (_syncSettings.Port1)
|
||||||
|
{
|
||||||
|
case Port1PeripheralOption.Gamepad:
|
||||||
|
case Port1PeripheralOption.FourScore:
|
||||||
|
internalQuickerNESControllerType = QuickerNESInternalControllerTypeEnumeration.Joypad; break;
|
||||||
|
case Port1PeripheralOption.ArkanoidNES:
|
||||||
|
internalQuickerNESControllerType = QuickerNESInternalControllerTypeEnumeration.ArkanoidNES; break;
|
||||||
|
case Port1PeripheralOption.ArkanoidFamicom:
|
||||||
|
internalQuickerNESControllerType = QuickerNESInternalControllerTypeEnumeration.ArkanoidFamicom; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing arkanoid inputs
|
||||||
|
byte arkanoidPos = 0;
|
||||||
|
byte arkanoidFire = 0;
|
||||||
|
|
||||||
|
switch (_syncSettings.Port1)
|
||||||
|
{
|
||||||
|
case Port1PeripheralOption.ArkanoidNES:
|
||||||
|
arkanoidPos = unchecked((byte)controller.AxisValue("P2 Paddle"));
|
||||||
|
arkanoidFire = controller.IsPressed("P2 Fire") ? (byte) 1 : (byte) 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Port1PeripheralOption.ArkanoidFamicom:
|
||||||
|
arkanoidPos = unchecked((byte)controller.AxisValue("P3 Paddle"));
|
||||||
|
arkanoidFire = controller.IsPressed("P3 Fire") ? (byte) 1 : (byte) 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LibQuickNES.ThrowStringError(QN.qn_emulate_frame(Context, j1, j2, arkanoidPos, arkanoidFire, (uint) internalQuickerNESControllerType));
|
||||||
IsLagFrame = QN.qn_get_joypad_read_count(Context) == 0;
|
IsLagFrame = QN.qn_get_joypad_read_count(Context) == 0;
|
||||||
if (IsLagFrame)
|
if (IsLagFrame)
|
||||||
LagCount++;
|
LagCount++;
|
||||||
|
|
Loading…
Reference in New Issue