Skip to content

Commit

Permalink
Merge branch 'master' into stella
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioMartin86 committed Sep 8, 2024
2 parents 505b772 + e68243f commit 58eefcf
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 19 deletions.
Binary file modified Assets/dll/libquicknes.dll
Binary file not shown.
Binary file modified Assets/dll/libquicknes.so
Binary file not shown.
40 changes: 38 additions & 2 deletions quicknes/bizinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion quicknes/core
Submodule core updated 115 files
2 changes: 1 addition & 1 deletion quicknes/make/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions quicknes/msvc/libquicknes.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand All @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ public void SelectRow(int index, bool val)

public void SelectAll()
{
_selectedItems.Clear();
var oldFullRowVal = FullRowSelect;
FullRowSelect = true;
for (int i = 0; i < RowCount; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public abstract class LibQuickNES
/// <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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ public enum Port1PeripheralOption : byte
Gamepad = 0x1,
FourScore = 0x2,
//FourScore2 = 0x3, // not available for port 1
ArkanoidNES = 0x4,
ArkanoidFamicom = 0x5,
}

public enum Port2PeripheralOption : byte
Expand Down
135 changes: 123 additions & 12 deletions src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,84 @@ public QuickNES(byte[] file, QuickNESSettings settings, QuickNESSyncSettings syn
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();
}

Expand Down Expand Up @@ -167,7 +230,6 @@ private static readonly (string PrefixedName, uint Bitmask)[][] FourScoreButtons
};



private void SetPads(IController controller, out uint j1, out uint j2)
{
static uint PackGamepadButtonsFor(int portNumber, IController controller)
Expand Down Expand Up @@ -198,6 +260,7 @@ static uint PackFourscoreButtonsFor(int portNumber, IController controller)
switch (_syncSettings.Port1)
{
case Port1PeripheralOption.Gamepad:
case Port1PeripheralOption.ArkanoidFamicom:
j1 = PackGamepadButtonsFor(0, controller);
break;
case Port1PeripheralOption.FourScore:
Expand All @@ -215,6 +278,14 @@ static uint PackFourscoreButtonsFor(int portNumber, IController controller)
}
}

public enum QuickerNESInternalControllerTypeEnumeration : byte
{
None = 0x0,
Joypad = 0x1,
ArkanoidNES = 0x2,
ArkanoidFamicom = 0x3,
}

public bool FrameAdvance(IController controller, bool render, bool rendersound = true)
{
CheckDisposed();
Expand All @@ -228,7 +299,47 @@ public bool FrameAdvance(IController controller, bool render, bool rendersound =

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++;
Expand Down

0 comments on commit 58eefcf

Please sign in to comment.