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;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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 \
|
||||
-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
|
||||
# -fprofile-generate
|
||||
|
|
|
@ -149,6 +149,7 @@
|
|||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>..\core\source\quickerNES\core;..\core\extern\jaffarCommon\include;$(IncludePath)</IncludePath>
|
||||
<OutDir>..\Assets\dll</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>..\core\source\quickerNES\core;..\core\extern\jaffarCommon\include;$(IncludePath)</IncludePath>
|
||||
|
@ -159,7 +160,7 @@
|
|||
<Optimization>Disabled</Optimization>
|
||||
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
||||
<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>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
|
@ -179,7 +180,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<DisableSpecificWarnings>4244;4800;4804;4996</DisableSpecificWarnings>
|
||||
<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>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
/// <param name="pad2">pad 2 input</param>
|
||||
/// <returns>string error</returns>
|
||||
[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>
|
||||
/// blit to rgb32
|
||||
/// </summary>
|
||||
|
|
|
@ -156,6 +156,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
Gamepad = 0x1,
|
||||
FourScore = 0x2,
|
||||
//FourScore2 = 0x3, // not available for port 1
|
||||
ArkanoidNES = 0x4,
|
||||
ArkanoidFamicom = 0x5,
|
||||
}
|
||||
|
||||
public enum Port2PeripheralOption : byte
|
||||
|
|
|
@ -82,21 +82,84 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
private void SetControllerDefinition()
|
||||
{
|
||||
ControllerDefinition def = new("NES Controller");
|
||||
|
||||
// Function to add gamepad buttons
|
||||
void AddButtons(IEnumerable<(string PrefixedName, uint Bitmask)> entries)
|
||||
=> def.BoolButtons.AddRange(entries.Select(static p => p.PrefixedName));
|
||||
AddButtons(_syncSettings.Port1 switch
|
||||
|
||||
// Parsing Port1 inputs
|
||||
|
||||
switch (_syncSettings.Port1)
|
||||
{
|
||||
Port1PeripheralOption.Gamepad => GamepadButtons[0],
|
||||
Port1PeripheralOption.FourScore => FourScoreButtons[0],
|
||||
_ => Enumerable.Empty<(string PrefixedName, uint Bitmask)>()
|
||||
});
|
||||
AddButtons(_syncSettings.Port2 switch
|
||||
case Port1PeripheralOption.Gamepad:
|
||||
|
||||
// Adding set of gamepad buttons (P1)
|
||||
AddButtons(GamepadButtons[0]);
|
||||
|
||||
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],
|
||||
Port2PeripheralOption.FourScore2 => FourScoreButtons[1],
|
||||
_ => Enumerable.Empty<(string PrefixedName, uint Bitmask)>()
|
||||
});
|
||||
case Port2PeripheralOption.Gamepad:
|
||||
|
||||
// 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
|
||||
|
||||
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)
|
||||
{
|
||||
static uint PackGamepadButtonsFor(int portNumber, IController controller)
|
||||
|
@ -198,6 +260,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
switch (_syncSettings.Port1)
|
||||
{
|
||||
case Port1PeripheralOption.Gamepad:
|
||||
case Port1PeripheralOption.ArkanoidFamicom:
|
||||
j1 = PackGamepadButtonsFor(0, controller);
|
||||
break;
|
||||
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)
|
||||
{
|
||||
CheckDisposed();
|
||||
|
@ -228,7 +299,47 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
|||
|
||||
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;
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
|
|
Loading…
Reference in New Issue