Adding Opera (3DO) as emulation core in Bizhawk (#4264)
* Adding base * Progress with opera and adding 3do firmwares * Adding missing callbacks * Adding missing callbacks * 3DO core starting * Now passing inputs * Passing gamepad inputs * Fixing input names * Now supporting mouse * Adding mouse support * Added flightstick * Added flight stick * Adding last inputs and fixing audio * Adding controllers and fixing audio * Adding orbatak * Fixing mnemonics, added orbatak * Adding font roms * Adding font roms * Adding region * Adding region * Fixing mouse issue * Fixed initialization bug in fresh installs * Setting mouse to relative inputs * Using mouse as relative * Bypassing bios checks to enable bizhawk to pass whatever bios it wants * Adding default inputs for 3DO * Adding detection of nvram changes * Adding lag frame and nvram saving * Adding cd use detection * Adding cdrom light * Using cd callbacks * Using cd callbacks * Bypassing image name check * Adding multidisc support * Removing 3do-iso special extension * Fixing build * Attempting to add disc swapping * Trying to add multidisc support * Uncommenting cd functions * revert unrelated changes * misc unmanaged integration * Update waterbox-cores.yml * Added reset button, removed eject/insert * Added reset button, removed eject/insert * Fix line endings in `Bk2MnemonicLookup.cs` changes * Fix indentation * Fix spaces in `Opera.cs` * Alphabetise * Make `Opera`'s `ISaveRam` implementations `override` * Misc. code style changes * Fix casting array index to `uint` for comparisons * Adding default framerate and removing message duration parameter * Refactoring input parsing and fixing some errors * Fixing indentation * Exposing non volatile ram * Adding automatic sram management * Now letting bk manage saveram automatically * Fixing indentation and removing unncessary flag * Removing dead code * Removing dead code * Removing unnecessary mnemonic fallbacks * Keep fixing indentation errors * Removing struct for memory areas * Adding proper detection of input reading * Changing namespace to not have an underscore * fix whitespace in PlatformFrameRates * make waterbox function non-virtual * Update src/BizHawk.Emulation.Cores/Consoles/3DO/Opera.cs Co-authored-by: feos <vadosnaprimer@users.noreply.github.com> * Fixing controller mapping * Fixing controller mapping, 3DO->Panasonic3DO, added submenu * Fixing controller * Fixing controllers * Removing unnecessary function * Fixing namespace and default ctrls * Fixing 3DO detection * Adding submodule branch * Adding PAL framerate for opera * controller pic * Fixed firmware naming * Fix line endings * Recompress image * Realphabetise after namespace/sysID change * Move this `case` block up * Minor code style fixes * Renaming user-facing Panasonic3DO strings to 3DO --------- Co-authored-by: Morilli <35152647+Morilli@users.noreply.github.com> Co-authored-by: YoshiRulz <OSSYoshiRulz+git@gmail.com> Co-authored-by: feos <vadosnaprimer@users.noreply.github.com> Co-authored-by: feos <feykomylce@gmail.com>
This commit is contained in:
parent
42a96fb996
commit
654544b329
|
@ -37,6 +37,7 @@ jobs:
|
|||
git submodule update --init uae/libretro-uae;
|
||||
git submodule update --init stella/core;
|
||||
git submodule update --init dsda/core;
|
||||
git submodule update --init opera/opera-libretro;
|
||||
git submodule update --init --recursive dosbox/dosbox-x;
|
||||
- name: Install clang 18
|
||||
run: wget https://apt.llvm.org/llvm.sh;
|
||||
|
@ -70,6 +71,7 @@ jobs:
|
|||
Assets/dll/libsnes.wbx.zst
|
||||
Assets/dll/melonDS.wbx.zst
|
||||
Assets/dll/ngp.wbx.zst
|
||||
Assets/dll/opera.wbx.zst
|
||||
Assets/dll/pcfx.wbx.zst
|
||||
Assets/dll/picodrive.wbx.zst
|
||||
Assets/dll/shock.wbx.zst
|
||||
|
|
|
@ -93,3 +93,7 @@
|
|||
path = waterbox/dsda/core
|
||||
url = https://github.com/TASEmulators/dsda-doom.git
|
||||
branch = wbx
|
||||
[submodule "waterbox/opera/opera-libretro"]
|
||||
path = waterbox/opera/opera-libretro
|
||||
url = https://github.com/TASEmulators/opera-libretro.git
|
||||
branch = wbx
|
||||
|
|
|
@ -1109,6 +1109,48 @@
|
|||
"Deadzone": 0.0
|
||||
}
|
||||
},
|
||||
"3DO Controller": {
|
||||
"P1 Mouse X": {
|
||||
"Value": "RMouse X",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Mouse Y": {
|
||||
"Value": "RMouse Y",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Flight Stick Horizontal Axis": {
|
||||
"Value": "RMouse X",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Flight Stick Vertical Axis": {
|
||||
"Value": "RMouse Y",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Light Gun Screen X": {
|
||||
"Value": "RMouse X",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Light Gun Screen Y": {
|
||||
"Value": "RMouse Y",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Trackball X": {
|
||||
"Value": "RMouse X",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
},
|
||||
"P1 Trackball Y": {
|
||||
"Value": "RMouse Y",
|
||||
"Mult": 1.0,
|
||||
"Deadzone": 0.0
|
||||
}
|
||||
},
|
||||
"DOSBox Controller": {
|
||||
"Mouse Position X": {
|
||||
"Value": "WMouse X",
|
||||
|
|
Binary file not shown.
|
@ -261,6 +261,9 @@ namespace BizHawk.Client.Common
|
|||
case DiscType.MegaCD:
|
||||
game.System = VSystemID.Raw.GEN;
|
||||
break;
|
||||
case DiscType.Panasonic3DO:
|
||||
game.System = VSystemID.Raw.Panasonic3DO;
|
||||
break;
|
||||
case DiscType.PCFX:
|
||||
game.System = VSystemID.Raw.PCFX;
|
||||
break;
|
||||
|
@ -289,9 +292,6 @@ namespace BizHawk.Client.Common
|
|||
case DiscType.NeoGeoCD:
|
||||
NoCoreForSystem(VSystemID.Raw.NeoGeoCD);
|
||||
break;
|
||||
case DiscType.Panasonic3DO:
|
||||
NoCoreForSystem(VSystemID.Raw.Panasonic3DO);
|
||||
break;
|
||||
case DiscType.Playdia:
|
||||
NoCoreForSystem(VSystemID.Raw.Playdia);
|
||||
break;
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
private static readonly Dictionary<string, double> Rates = new Dictionary<string, double>
|
||||
{
|
||||
["Panasonic3DO"] = 60.0, // The emulator (Opera-Libretro) reports exact 60.0 for NTSC https://github.com/libretro/opera-libretro/blob/67a29e60a4d194b675c9272b21b61eaa022f3ba3/libopera/opera_region.c#L10
|
||||
["Panasonic3DO_PAL"] = 50.0, // The emulator (Opera-Libretro) reports exact 50.0 for PAL https://github.com/libretro/opera-libretro/blob/67a29e60a4d194b675c9272b21b61eaa022f3ba3/libopera/opera_region.c#L17
|
||||
["NES"] = 60.098813897440515, // per https://forums.nesdev.org/viewtopic.php?p=3783#p3783 the nominal value is (19687500/11) / ((341*262 - 0.5) / 3) = 39375000/655171 ≈ 60.09881389744051553 (so our chosen number, which is approximately 60.09881389744051461, is very close)
|
||||
["FDS"] = 60.098813897440515, // ditto
|
||||
["NES_PAL"] = 50.00697796826829, // per https://forums.nesdev.org/viewtopic.php?p=3783#p3783 the nominal value is 1662607 / (341*312/3.2) = 3325214/66495 ≈ 50.0069779682682908 (so our chosen number, which is approximately 50.0069779682682877, is very close)
|
||||
|
|
|
@ -36,6 +36,7 @@ using BizHawk.Emulation.Cores.Consoles.Nintendo.NDS;
|
|||
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.VB;
|
||||
using BizHawk.Emulation.Cores.Consoles.O2Hawk;
|
||||
using BizHawk.Emulation.Cores.Consoles.Panasonic3DO;
|
||||
using BizHawk.Emulation.Cores.Consoles.SNK;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.Saturn;
|
||||
|
@ -1370,6 +1371,9 @@ namespace BizHawk.Client.EmuHawk
|
|||
};
|
||||
items.Add(octoshockSubmenu);
|
||||
|
||||
// Opera
|
||||
items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.Opera, CreateGenericCoreConfigItem<Opera>(CoreNames.Opera)));
|
||||
|
||||
// PCEHawk
|
||||
items.Add(CreateCoreSubmenu(VSystemCategory.Consoles, CoreNames.PceHawk, CreateGenericCoreConfigItem<PCEngine>(CoreNames.PceHawk)));
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace BizHawk.Client.EmuHawk.Properties
|
|||
internal static readonly Lazy<Bitmap> SaturnController = new Lazy<Bitmap>(() => ReadEmbeddedBitmap("ControllerImages.SaturnController"));
|
||||
internal static readonly Lazy<Bitmap> SmsController = new Lazy<Bitmap>(() => ReadEmbeddedBitmap("ControllerImages.SMSController"));
|
||||
internal static readonly Lazy<Bitmap> SnesController = new Lazy<Bitmap>(() => ReadEmbeddedBitmap("ControllerImages.SNES_Controller"));
|
||||
internal static readonly Lazy<Bitmap> ThreeDOController = new Lazy<Bitmap>(() => ReadEmbeddedBitmap("ControllerImages.3DOController"));
|
||||
internal static readonly Lazy<Bitmap> TI83Controller = new Lazy<Bitmap>(() => ReadEmbeddedBitmap("ControllerImages.TI83_Controller"));
|
||||
internal static readonly Lazy<Bitmap> VBoyController = new Lazy<Bitmap>(() => ReadEmbeddedBitmap("ControllerImages.VBoyController"));
|
||||
internal static readonly Lazy<Bitmap> WonderSwanColor = new Lazy<Bitmap>(() => ReadEmbeddedBitmap("ControllerImages.WonderSwanColor"));
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
ControllerImages.Add("PC Engine Controller", Properties.Resources.PceController);
|
||||
ControllerImages.Add("Commodore 64 Controller", Properties.Resources.C64Joystick);
|
||||
ControllerImages.Add("TI83 Controller", Properties.Resources.TI83Controller);
|
||||
ControllerImages.Add("3DO Controller", Properties.Resources.ThreeDOController);
|
||||
|
||||
ControllerImages.Add("WonderSwan Controller", Properties.Resources.WonderSwanColor);
|
||||
ControllerImages.Add("Lynx Controller", Properties.Resources.Lynx);
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
// Redundant with SystemLookup? Not so fast. That data drives things. This is one step abstracted. Don't be such a smart guy. Keep this redundant list up to date.
|
||||
private static readonly Dictionary<string, string> SystemGroupNames = new Dictionary<string, string>
|
||||
{
|
||||
["3DO"] = "3DO / 3DO Arcade / 3DO M2",
|
||||
["Amiga"] = "Amiga",
|
||||
["NES"] = "NES",
|
||||
["SNES"] = "SNES",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 85 KiB |
|
@ -47,6 +47,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
VSystemID.Raw.N3DS,
|
||||
VSystemID.Raw.N64,
|
||||
VSystemID.Raw.NDS,
|
||||
VSystemID.Raw.Panasonic3DO,
|
||||
VSystemID.Raw.PCFX,
|
||||
VSystemID.Raw.PSX,
|
||||
VSystemID.Raw.SAT,
|
||||
|
|
|
@ -182,6 +182,25 @@ namespace BizHawk.Emulation.Common
|
|||
|
||||
private static readonly Dictionary<string, Dictionary<string, char>> SystemOverrides = new Dictionary<string, Dictionary<string, char>>
|
||||
{
|
||||
[VSystemID.Raw.Panasonic3DO] = new()
|
||||
{
|
||||
["LT"] = 'l',
|
||||
["RT"] = 'r',
|
||||
["P"] = 'P',
|
||||
["Trigger"] = 'T',
|
||||
["Reload"] = 'R',
|
||||
["Is Off-Screen"] = 'O',
|
||||
["Aux A"] = 'A',
|
||||
["Start P1"] = '1',
|
||||
["Start P2"] = '2',
|
||||
["Coin P1"] = 'C',
|
||||
["Coin P2"] = 'c',
|
||||
["Service"] = 'S',
|
||||
["Fourth Button"] = '4',
|
||||
["Next Disc"] = '>',
|
||||
["Prev Disc"] = '<',
|
||||
},
|
||||
|
||||
[VSystemID.Raw.NES] = new()
|
||||
{
|
||||
["FDS Eject"] = 'E',
|
||||
|
@ -964,6 +983,16 @@ namespace BizHawk.Emulation.Common
|
|||
|
||||
private static readonly Dictionary<string, Dictionary<string, string>> AxisSystemOverrides = new Dictionary<string, Dictionary<string, string>>
|
||||
{
|
||||
[VSystemID.Raw.Panasonic3DO] = new()
|
||||
{
|
||||
["Flight Stick Horizontal Axis"] = "fsX",
|
||||
["Flight Stick Vertical Axis"] = "fsY",
|
||||
["Flight Stick Altitude Axis"] = "fsZ",
|
||||
["Light Gun Screen X"] = "lgX",
|
||||
["Light Gun Screen Y"] = "lgY",
|
||||
["Trackball X"] = "tX",
|
||||
["Trackball Y"] = "tY",
|
||||
},
|
||||
[VSystemID.Raw.A78] = new()
|
||||
{
|
||||
["VPos"] = "X",
|
||||
|
|
|
@ -82,6 +82,60 @@ namespace BizHawk.Emulation.Common
|
|||
FirmwareAndOption("1E5B0B2441A4979B6966D942B20CC76C413B8C5E", 2048, "32X", "M", "32X_M_BIOS.BIN", "32x SH2 MASTER BIOS");
|
||||
FirmwareAndOption("4103668C1BBD66C5E24558E73D4F3F92061A109A", 1024, "32X", "S", "32X_S_BIOS.BIN", "32x SH2 SLAVE BIOS");
|
||||
|
||||
// 3DO
|
||||
// Information obtained from https://3dodev.com/software/roms
|
||||
|
||||
Firmware("3DO", "Panasonic_FZ1_U", "Panasonic FZ-1 (U)");
|
||||
Option("3DO", "Panasonic_FZ1_U", File("34BF189111295F74D7B7DFC1F304D98B8D36325A", 1048576, "panafz1.bin", "Panasonic FZ-1 (U)"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Panasonic_FZ1_U", File("DE3C55490733E6C69724D87E149B52ED955638ED", 1048576, "panafz1_dev_0.9.bin", "Panasonic FZ-1 (U) v0.9 dev build"));
|
||||
Option("3DO", "Panasonic_FZ1_U", File("4CB4EE36E0F5BC0995D34992B4F241C420D49B2E", 1048576, "panafz1_dev.bin", "Panasonic FZ-1 (U) dev build"));
|
||||
|
||||
Firmware("3DO", "Panasonic_FZ1_E", "Panasonic FZ-1 (E)");
|
||||
Option("3DO", "Panasonic_FZ1_E", File("1D0DB81E171EBC1D07CEFC8CE8AB082306186E56", 1048576, "panafz1e.bin", "Panasonic FZ-1 (E)"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Panasonic_FZ1_E", File("4696951E492E5526772A860EA2C0F35411A80927", 1048576, "panafz1e-unencrypted.bin", "Panasonic FZ-1 (E) (unencrypted)"));
|
||||
|
||||
Firmware("3DO", "Panasonic_FZ1_J", "Panasonic FZ-1 (J)");
|
||||
Option("3DO", "Panasonic_FZ1_J", File("EC7EC62D60EC0459A14ED56EBC66761EF3C80EFC", 1048576, "panafz1j.bin", "Panasonic FZ-1 (J)"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Panasonic_FZ1_J", File("A417587AE3B0B8EF00C830920C21AF8BEE88E419", 1048576, "panafz1j - norsa.bin", "Panasonic FZ-1(J)(RSA check disabled)"));
|
||||
|
||||
Firmware("3DO", "Panasonic_FZ10_U", "Panasonic FZ-10 (U)");
|
||||
Option("3DO", "Panasonic_FZ10_U", File("3C912300775D1AD730DC35757E279C274C0ACAAD", 1048576, "panafz10.bin", "Panasonic FZ-10 (U)"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Panasonic_FZ10_U", File("F05E642322C03694F06A809C0B90FC27AC73C002", 1048576, "panafz10-norsa.bin", "Panasonic FZ-10 (U) (RSA check disabled)"));
|
||||
|
||||
Firmware("3DO", "Panasonic_FZ10_E", "Panasonic FZ-10 (E)");
|
||||
Option("3DO", "Panasonic_FZ10_E", File("A900371F0CDCDC03F79557F11D406FD71251A5FD", 1048576, "panafz10e-anvil.bin", "Panasonic FZ-10 (E) [ANVIL]"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Panasonic_FZ10_E", File("2765C7B4557CC838B32567D2428D088980295159", 1048576, "panafz10e-anvil-norsa.bin", "Panasonic FZ-10 (E) [ANVIL] (RSA check disabled)"));
|
||||
|
||||
Firmware("3DO", "Panasonic_FZ10_J", "Panasonic FZ-10 (J)");
|
||||
Option("3DO", "Panasonic_FZ10_J", File("FE7F9C9C6A98910013BF13F2CF798DE9FEA52ACD", 1048576, "panafz10j.bin", "Panasonic FZ-10 (J)"), FirmwareOptionStatus.Ideal);
|
||||
|
||||
Firmware("3DO", "Goldstar_GDO101P", "Goldstar GDO-101P");
|
||||
Option("3DO", "Goldstar_GDO101P", File("C4A2E5336F77FB5F743DE1EEA2CDA43675EE2DE7", 1048576, "goldstar.bin", "Goldstar GDO-101P"), FirmwareOptionStatus.Ideal);
|
||||
|
||||
Firmware("3DO", "Goldstar_FC1", "Goldstar FC-1");
|
||||
Option("3DO", "Goldstar_FC1", File("8EF7503C948314D242DA47B7FDC272F68DAC2AEE", 1048576, "goldstar_fc1_enc.bin", "Goldstar FC-1 (encrypted)"), FirmwareOptionStatus.Ideal);
|
||||
|
||||
Firmware("3DO", "Sanyo_IMP21J_Try", "Sanyo IMP-21J Try");
|
||||
Option("3DO", "Sanyo_IMP21J_Try", File("B01C53DA256DDE43FFEC4AD3FC3ADFA8D635E943", 1048576, "sanyotry.bin", "Sanyo IMP-21J Try"), FirmwareOptionStatus.Ideal);
|
||||
|
||||
Firmware("3DO", "Sanyo_HC21", "Sanyo HC-21");
|
||||
Option("3DO", "Sanyo_HC21", File("C389AF32BCADF0D86826927DC3D20B7072F90069", 1048576, "sanyo_hc21_b3_unenc.bin", "Sanyo HC-21 B3 (unencrypted)"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Sanyo_HC21", File("29C40515DC1174FF13975BAA59EB532083E4A3D3", 1048576, "sanyo_hc21_alpha.bin", "Sanyo HC-21 (alpha 3/21/94)"));
|
||||
|
||||
Firmware("3DO", "Shootout_At_Old_Tucson", "(3DO Arcade) Shootout At Old Tucson");
|
||||
Option("3DO", "Shootout_At_Old_Tucson", File("520D3D1B5897800AF47F92EFD2444A26B7A7DEAD", 524288, "3do_arcade_saot.bin", "Shootout At Old Tucson"), FirmwareOptionStatus.Ideal);
|
||||
|
||||
Firmware("3DO", "3DO_NTSC_1fc2", "3DO-NTSC-1.0fc2");
|
||||
Option("3DO", "3DO_NTSC_1fc2", File("BD325C869E1DDE8A3872FC21565E0646A3D5B525", 1048576, "3do_devkit_1.0fc2.bin", "3DO-NTSC-1.0fc2 encrypted development kit"), FirmwareOptionStatus.Ideal);
|
||||
|
||||
Firmware("3DO", "Kanji_ROM_Panasonic_FZ1", "Kanji ROM for Panasonic FZ-1");
|
||||
Option("3DO", "Kanji_ROM_Panasonic_FZ1", File("ACD39A8FEE1B9D2950D5AB447846C11FB31AF63E", 933636, "panafz1-kanji.bin", "Kanji ROM for Panasonic FZ-1 (J)"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Kanji_ROM_Panasonic_FZ1", File("884515605EE243577AB20767EF8C1A7368E4E407", 1048576, "panafz1j-kanji.bin", "Kanji ROM for Panasonic FZ-1 (J) / Panasonic FZ-10 (J)"));
|
||||
|
||||
Firmware("3DO", "Kanji_ROM_Panasonic_FZ10", "Kanji ROM for Panasonic FZ-10");
|
||||
Option("3DO", "Kanji_ROM_Panasonic_FZ10", File("2E857B957803D0331FD229328DF01F3FFAB69EEE", 1048576, "panafz10ja-anvil-kanji.bin", "Kanji ROM for: Panasonic FZ-10 (J) [ANVIL]"), FirmwareOptionStatus.Ideal);
|
||||
Option("3DO", "Kanji_ROM_Panasonic_FZ10", File("884515605EE243577AB20767EF8C1A7368E4E407", 1048576, "panafz1j-kanji.bin", "Kanji ROM for Panasonic FZ-1 (J) / Panasonic FZ-10 (J)"));
|
||||
|
||||
// 3DS
|
||||
// bleh, undefined hash AND size...
|
||||
FirmwareAndOption(SHA1Checksum.Dummy, 0, "3DS", "aes_keys", "aes_keys.txt", "AES Keys");
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace BizHawk.Emulation.Common
|
|||
[VSystemID.Raw.NGP] = "Neo-Geo Pocket",
|
||||
// NULL
|
||||
[VSystemID.Raw.O2] = "Odyssey2",
|
||||
[VSystemID.Raw.Panasonic3DO] = "3DO",
|
||||
[VSystemID.Raw.PCE] = "TurboGrafx-16",
|
||||
[VSystemID.Raw.PCECD] = "TurboGrafx - 16(CD)",
|
||||
[VSystemID.Raw.PCFX] = "PCFX",
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace BizHawk.Emulation.Common
|
|||
public const string NGP = "NGP";
|
||||
public const string NULL = "NULL";
|
||||
public const string O2 = "O2";
|
||||
public const string Panasonic3DO = "Panasonic3DO";
|
||||
public const string Panasonic3DO = "3DO";
|
||||
public const string PCE = "PCE";
|
||||
public const string PCECD = "PCECD";
|
||||
public const string PCFX = "PCFX";
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Panasonic3DO
|
||||
{
|
||||
public abstract class LibOpera : LibWaterboxCore
|
||||
{
|
||||
// NTSC Specifications
|
||||
public const int NTSC_WIDTH = 320;
|
||||
public const int NTSC_HEIGHT = 240;
|
||||
public const int NTSC_VIDEO_NUMERATOR = 60;
|
||||
public const int NTSC_VIDEO_DENOMINATOR = 1;
|
||||
|
||||
// PAL1 Specifications
|
||||
public const int PAL1_WIDTH = 320;
|
||||
public const int PAL1_HEIGHT = 288;
|
||||
public const int PAL1_VIDEO_NUMERATOR = 50;
|
||||
public const int PAL1_VIDEO_DENOMINATOR = 1;
|
||||
|
||||
// PAL2 Specifications
|
||||
public const int PAL2_WIDTH = 384;
|
||||
public const int PAL2_HEIGHT = 288;
|
||||
public const int PAL2_VIDEO_NUMERATOR = 50;
|
||||
public const int PAL2_VIDEO_DENOMINATOR = 1;
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void CDReadCallback(int lba, IntPtr dst);
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate int CDSectorCountCallback();
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetCdCallbacks(CDReadCallback cdrc, CDSectorCountCallback cdscc);
|
||||
|
||||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract bool Init(string gameFile, string biosFile, string fontFile, int port1Type, int port2Type, int videoStandard);
|
||||
|
||||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract bool sram_changed();
|
||||
|
||||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract int get_sram_size();
|
||||
|
||||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract void get_sram(IntPtr sramBuffer);
|
||||
|
||||
[BizImport(CC, Compatibility = true)]
|
||||
public abstract void set_sram(IntPtr sramBuffer);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct GamepadInputs
|
||||
{
|
||||
public int up;
|
||||
public int down;
|
||||
public int left;
|
||||
public int right;
|
||||
public int buttonX;
|
||||
public int buttonP;
|
||||
public int buttonA;
|
||||
public int buttonB;
|
||||
public int buttonC;
|
||||
public int buttonL;
|
||||
public int buttonR;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MouseInputs
|
||||
{
|
||||
public int dX;
|
||||
public int dY;
|
||||
public int leftButton;
|
||||
public int middleButton;
|
||||
public int rightButton;
|
||||
public int fourthButton;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct FlightStickInputs
|
||||
{
|
||||
public int up;
|
||||
public int down;
|
||||
public int left;
|
||||
public int right;
|
||||
public int fire;
|
||||
public int buttonA;
|
||||
public int buttonB;
|
||||
public int buttonC;
|
||||
public int buttonX;
|
||||
public int buttonP;
|
||||
public int leftTrigger;
|
||||
public int rightTrigger;
|
||||
public int horizontalAxis;
|
||||
public int verticalAxis;
|
||||
public int altitudeAxis;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct LightGunInputs
|
||||
{
|
||||
public int trigger;
|
||||
public int select;
|
||||
public int reload;
|
||||
public int isOffScreen;
|
||||
public int screenX;
|
||||
public int screenY;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ArcadeLightGunInputs
|
||||
{
|
||||
public int trigger;
|
||||
public int select;
|
||||
public int start;
|
||||
public int reload;
|
||||
public int auxA;
|
||||
public int isOffScreen;
|
||||
public int screenX;
|
||||
public int screenY;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct OrbatakTrackballInputs
|
||||
{
|
||||
public int dX;
|
||||
public int dY;
|
||||
public int startP1;
|
||||
public int startP2;
|
||||
public int coinP1;
|
||||
public int coinP2;
|
||||
public int service;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct GameInput
|
||||
{
|
||||
public GamepadInputs gamepad;
|
||||
public MouseInputs mouse;
|
||||
public FlightStickInputs flightStick;
|
||||
public LightGunInputs lightGun;
|
||||
public ArcadeLightGunInputs arcadeLightGun;
|
||||
public OrbatakTrackballInputs orbatakTrackball;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public new class FrameInfo : LibWaterboxCore.FrameInfo
|
||||
{
|
||||
public GameInput port1;
|
||||
public GameInput port2;
|
||||
public int isReset = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
using BizHawk.Common.CollectionExtensions;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Panasonic3DO
|
||||
{
|
||||
public partial class Opera
|
||||
{
|
||||
private static ControllerDefinition CreateControllerDefinition(SyncSettings settings, bool isMultiDisc)
|
||||
{
|
||||
var controller = new ControllerDefinition("3DO Controller");
|
||||
setPortControllers(1, settings.Controller1Type, controller);
|
||||
setPortControllers(2, settings.Controller2Type, controller);
|
||||
|
||||
// If this is multi-disc, add a cd swap option
|
||||
if (isMultiDisc)
|
||||
{
|
||||
controller.BoolButtons.Add("Next Disc");
|
||||
controller.BoolButtons.Add("Prev Disc");
|
||||
}
|
||||
|
||||
// Adding Reset button
|
||||
controller.BoolButtons.Add("Reset");
|
||||
|
||||
return controller.MakeImmutable();
|
||||
}
|
||||
|
||||
public const int MOUSE_MIN_POS_X = -64;
|
||||
public const int MOUSE_MAX_POS_X = 64;
|
||||
public const int MOUSE_MIN_POS_Y = -64;
|
||||
public const int MOUSE_MAX_POS_Y = 64;
|
||||
|
||||
public const int POINTER_MIN_POS = -32768;
|
||||
public const int POINTER_MAX_POS = 32767;
|
||||
private static void setPortControllers(int port, ControllerType type, ControllerDefinition controller)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ControllerType.Gamepad:
|
||||
foreach (var button in JoystickButtonCollection) controller.BoolButtons.Add($"P{port} {button}");
|
||||
break;
|
||||
case ControllerType.Mouse:
|
||||
controller.BoolButtons.AddRange([
|
||||
$"P{port} {Inputs.MouseLeftButton}",
|
||||
$"P{port} {Inputs.MouseMiddleButton}",
|
||||
$"P{port} {Inputs.MouseRightButton}",
|
||||
$"P{port} {Inputs.MouseFourthButton}",
|
||||
]);
|
||||
controller.AddAxis($"P{port} {Inputs.MouseX}", MOUSE_MIN_POS_X.RangeTo(MOUSE_MAX_POS_X), (MOUSE_MIN_POS_X + MOUSE_MAX_POS_X) / 2)
|
||||
.AddAxis($"P{port} {Inputs.MouseY}", MOUSE_MIN_POS_Y.RangeTo(MOUSE_MAX_POS_Y), (MOUSE_MIN_POS_Y + MOUSE_MAX_POS_Y) / 2);
|
||||
break;
|
||||
case ControllerType.FlightStick:
|
||||
foreach (var button in FlightStickButtonCollection) controller.BoolButtons.Add($"P{port} {button}");
|
||||
controller.AddAxis($"P{port} {Inputs.FlighStickHorizontalAxis}", MOUSE_MIN_POS_X.RangeTo(MOUSE_MAX_POS_X), (MOUSE_MIN_POS_X + MOUSE_MAX_POS_X) / 2)
|
||||
.AddAxis($"P{port} {Inputs.FlighStickVerticalAxis}", MOUSE_MIN_POS_Y.RangeTo(MOUSE_MAX_POS_Y), (MOUSE_MIN_POS_Y + MOUSE_MAX_POS_Y) / 2)
|
||||
.AddAxis($"P{port} {Inputs.FlighStickAltitudeAxis}", MOUSE_MIN_POS_Y.RangeTo(MOUSE_MAX_POS_Y), (MOUSE_MIN_POS_Y + MOUSE_MAX_POS_Y) / 2);
|
||||
break;
|
||||
case ControllerType.LightGun:
|
||||
foreach (var button in LightGunButtonCollection) controller.BoolButtons.Add($"P{port} {button}");
|
||||
controller.AddAxis($"P{port} {Inputs.LightGunScreenX}", (POINTER_MIN_POS).RangeTo(POINTER_MAX_POS), 0)
|
||||
.AddAxis($"P{port} {Inputs.LightGunScreenY}", (POINTER_MIN_POS).RangeTo(POINTER_MAX_POS), 0);
|
||||
break;
|
||||
case ControllerType.ArcadeLightGun:
|
||||
foreach (var button in ArcadeLightGunButtonCollection) controller.BoolButtons.Add($"P{port} {button}");
|
||||
controller.AddAxis($"P{port} {Inputs.LightGunScreenX}", (POINTER_MIN_POS).RangeTo(POINTER_MAX_POS), 0)
|
||||
.AddAxis($"P{port} {Inputs.LightGunScreenY}", (POINTER_MIN_POS).RangeTo(POINTER_MAX_POS), 0);
|
||||
break;
|
||||
case ControllerType.OrbatakTrackball:
|
||||
foreach (var button in OrbatakTrackballCollection) controller.BoolButtons.Add($"P{port} {button}");
|
||||
controller.AddAxis($"P{port} {Inputs.TrackballPosX}", MOUSE_MIN_POS_X.RangeTo(MOUSE_MAX_POS_X), (MOUSE_MIN_POS_X + MOUSE_MAX_POS_X) / 2)
|
||||
.AddAxis($"P{port} {Inputs.TrackballPosY}", MOUSE_MIN_POS_Y.RangeTo(MOUSE_MAX_POS_Y), (MOUSE_MIN_POS_Y + MOUSE_MAX_POS_Y) / 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] JoystickButtonCollection = [
|
||||
JoystickButtons.Up,
|
||||
JoystickButtons.Down,
|
||||
JoystickButtons.Left,
|
||||
JoystickButtons.Right,
|
||||
JoystickButtons.ButtonX,
|
||||
JoystickButtons.ButtonP,
|
||||
JoystickButtons.ButtonA,
|
||||
JoystickButtons.ButtonB,
|
||||
JoystickButtons.ButtonC,
|
||||
JoystickButtons.ButtonL,
|
||||
JoystickButtons.ButtonR,
|
||||
];
|
||||
|
||||
private static string[] FlightStickButtonCollection = [
|
||||
FlightStickButtons.Up,
|
||||
FlightStickButtons.Down,
|
||||
FlightStickButtons.Left,
|
||||
FlightStickButtons.Right,
|
||||
FlightStickButtons.Fire,
|
||||
FlightStickButtons.ButtonA,
|
||||
FlightStickButtons.ButtonB,
|
||||
FlightStickButtons.ButtonX,
|
||||
FlightStickButtons.ButtonP,
|
||||
FlightStickButtons.LeftTrigger,
|
||||
FlightStickButtons.RightTrigger,
|
||||
];
|
||||
|
||||
private static string[] LightGunButtonCollection = [
|
||||
LightGunButtons.Trigger,
|
||||
LightGunButtons.Select,
|
||||
LightGunButtons.Reload,
|
||||
LightGunButtons.IsOffScreen,
|
||||
];
|
||||
|
||||
private static string[] ArcadeLightGunButtonCollection = [
|
||||
ArcadeLightGunButtons.Trigger,
|
||||
ArcadeLightGunButtons.Select,
|
||||
ArcadeLightGunButtons.Start,
|
||||
ArcadeLightGunButtons.Reload,
|
||||
ArcadeLightGunButtons.AuxA,
|
||||
ArcadeLightGunButtons.IsOffScreen,
|
||||
];
|
||||
|
||||
private static string[] OrbatakTrackballCollection = [
|
||||
OrbatakTrackballButtons.StartP1,
|
||||
OrbatakTrackballButtons.StartP2,
|
||||
OrbatakTrackballButtons.CoinP1,
|
||||
OrbatakTrackballButtons.CoinP2,
|
||||
OrbatakTrackballButtons.Service,
|
||||
];
|
||||
|
||||
private static class JoystickButtons
|
||||
{
|
||||
public const string Up = "Up";
|
||||
public const string Down = "Down";
|
||||
public const string Left = "Left";
|
||||
public const string Right = "Right";
|
||||
public const string ButtonX = "X";
|
||||
public const string ButtonP = "P";
|
||||
public const string ButtonA = "A";
|
||||
public const string ButtonB = "B";
|
||||
public const string ButtonC = "C";
|
||||
public const string ButtonL = "L";
|
||||
public const string ButtonR = "R";
|
||||
}
|
||||
private static class FlightStickButtons
|
||||
{
|
||||
public const string Up = "Up";
|
||||
public const string Down = "Down";
|
||||
public const string Left = "Left";
|
||||
public const string Right = "Right";
|
||||
public const string Fire = "Fire";
|
||||
public const string ButtonA = "A";
|
||||
public const string ButtonB = "B";
|
||||
public const string ButtonC = "C";
|
||||
public const string LeftTrigger = "LT";
|
||||
public const string RightTrigger = "RT";
|
||||
public const string ButtonP = "P";
|
||||
public const string ButtonX = "X";
|
||||
}
|
||||
|
||||
private static class LightGunButtons
|
||||
{
|
||||
public const string Trigger = "Trigger";
|
||||
public const string Select = "Select";
|
||||
public const string Reload = "Reload";
|
||||
public const string IsOffScreen = "Is Off-Screen";
|
||||
}
|
||||
private static class ArcadeLightGunButtons
|
||||
{
|
||||
public const string Trigger = "Trigger";
|
||||
public const string Select = "Select";
|
||||
public const string Start = "Start";
|
||||
public const string Reload = "Reload";
|
||||
public const string AuxA = "Aux A";
|
||||
public const string IsOffScreen = "Is Off-Screen";
|
||||
}
|
||||
|
||||
private static class OrbatakTrackballButtons
|
||||
{
|
||||
public const string StartP1 = "Start P1";
|
||||
public const string StartP2 = "Start P2";
|
||||
public const string CoinP1 = "Coin P1";
|
||||
public const string CoinP2 = "Coin P2";
|
||||
public const string Service = "Service";
|
||||
}
|
||||
|
||||
private static class Inputs
|
||||
{
|
||||
public const string Joystick = "Joystick";
|
||||
public const string MouseLeftButton = "Left Button";
|
||||
public const string MouseRightButton = "Right Button";
|
||||
public const string MouseMiddleButton = "Middle Button";
|
||||
public const string MouseFourthButton = "Fourth Button";
|
||||
public const string MouseX = "Mouse X";
|
||||
public const string MouseY = "Mouse Y";
|
||||
public const string FlighStickHorizontalAxis = "Flight Stick Horizontal Axis";
|
||||
public const string FlighStickVerticalAxis = "Flight Stick Vertical Axis";
|
||||
public const string FlighStickAltitudeAxis = "Flight Stick Altitude Axis";
|
||||
public const string LightGunScreenX = "Light Gun Screen X";
|
||||
public const string LightGunScreenY = "Light Gun Screen Y";
|
||||
public const string TrackballPosX = "Trackball X";
|
||||
public const string TrackballPosY = "Trackball Y";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Panasonic3DO
|
||||
{
|
||||
public partial class Opera : IDriveLight
|
||||
{
|
||||
public bool DriveLightEnabled { get; private set; }
|
||||
public bool DriveLightOn { get; private set; }
|
||||
public string DriveLightIconDescription => "Drive Activity";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Panasonic3DO
|
||||
{
|
||||
public partial class Opera : IRegionable
|
||||
{
|
||||
public DisplayType Region => _syncSettings.VideoStandard is VideoStandard.NTSC
|
||||
? DisplayType.NTSC
|
||||
: DisplayType.PAL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Panasonic3DO
|
||||
{
|
||||
public partial class Opera : ISettable<object, Opera.SyncSettings>
|
||||
{
|
||||
// System type determines the version of the console to run
|
||||
// The selection of the proper BIOS derives from this decision
|
||||
public enum SystemType
|
||||
{
|
||||
[Display(Name = "Panasonic FZ-1 (U)")]
|
||||
Panasonic_FZ1_U,
|
||||
[Display(Name = "Panasonic FZ-1 (E)")]
|
||||
Panasonic_FZ1_E,
|
||||
[Display(Name = "Panasonic FZ-1 (J)")]
|
||||
Panasonic_FZ1_J,
|
||||
[Display(Name = "Panasonic FZ-10 (U)")]
|
||||
Panasonic_FZ10_U,
|
||||
[Display(Name = "Panasonic FZ-10 (E)")]
|
||||
Panasonic_FZ10_E,
|
||||
[Display(Name = "Panasonic FZ-10 (J)")]
|
||||
Panasonic_FZ10_J,
|
||||
[Display(Name = "Goldstar GDO-101P")]
|
||||
Goldstar_GDO101P,
|
||||
[Display(Name = "Goldstar FC-1")]
|
||||
Goldstar_FC1,
|
||||
[Display(Name = "Sanyo IMP-21J Try")]
|
||||
Sanyo_IMP21J_Try,
|
||||
[Display(Name = "Sanyo HC-21")]
|
||||
Sanyo_HC21,
|
||||
[Display(Name = "(3DO Arcade) Shootout At Old Tucson")]
|
||||
Shootout_At_Old_Tucson,
|
||||
[Display(Name = "3DO-NTSC-1.0fc2")]
|
||||
_3DO_NTSC_1fc2,
|
||||
}
|
||||
|
||||
public enum FontROM
|
||||
{
|
||||
[Display(Name = "None")]
|
||||
None,
|
||||
[Display(Name = "Kanji ROM for Panasonic FZ-1")]
|
||||
Kanji_ROM_Panasonic_FZ1,
|
||||
[Display(Name = "Kanji ROM for Panasonic FZ-10")]
|
||||
Kanji_ROM_Panasonic_FZ10,
|
||||
}
|
||||
|
||||
public enum VideoStandard
|
||||
{
|
||||
[Display(Name = "NTSC")]
|
||||
NTSC = 0,
|
||||
[Display(Name = "PAL1")]
|
||||
PAL1 = 1,
|
||||
[Display(Name = "PAL2")]
|
||||
PAL2 = 2,
|
||||
}
|
||||
|
||||
public enum ControllerType
|
||||
{
|
||||
[Display(Name = "None")]
|
||||
None = 0,
|
||||
[Display(Name = "Joypad")]
|
||||
Gamepad = 1,
|
||||
[Display(Name = "Mouse")]
|
||||
Mouse = 2,
|
||||
[Display(Name = "Flight Stick")]
|
||||
FlightStick = 257,
|
||||
[Display(Name = "Light Gun")]
|
||||
LightGun = 4,
|
||||
[Display(Name = "Arcade Light Gun")]
|
||||
ArcadeLightGun = 260,
|
||||
[Display(Name = "Orbatak Trackball")]
|
||||
OrbatakTrackball = 513,
|
||||
}
|
||||
|
||||
public object GetSettings() => null;
|
||||
public PutSettingsDirtyBits PutSettings(object o) => PutSettingsDirtyBits.None;
|
||||
|
||||
private SyncSettings _syncSettings;
|
||||
public SyncSettings GetSyncSettings()
|
||||
=> _syncSettings.Clone();
|
||||
|
||||
public PutSettingsDirtyBits PutSyncSettings(SyncSettings o)
|
||||
{
|
||||
var ret = SyncSettings.NeedsReboot(_syncSettings, o);
|
||||
_syncSettings = o;
|
||||
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
||||
}
|
||||
|
||||
[CoreSettings]
|
||||
public class SyncSettings
|
||||
{
|
||||
[DisplayName("System Type")]
|
||||
[Description("Sets the version of the console to emulate. This choice determines the corresponding BIOS ROM to use.")]
|
||||
[DefaultValue(SystemType.Panasonic_FZ1_U)]
|
||||
[TypeConverter(typeof(SystemType))]
|
||||
public SystemType SystemType { get; set; }
|
||||
|
||||
[DisplayName("Font ROM")]
|
||||
[Description("Determines whether (if any) addition ROM to load for regional font support.")]
|
||||
[DefaultValue(FontROM.None)]
|
||||
[TypeConverter(typeof(FontROM))]
|
||||
public FontROM FontROM { get; set; }
|
||||
|
||||
[DisplayName("Video Standard")]
|
||||
[Description("Determines the resolution and video timing. It should be selected according to the game and console's region.")]
|
||||
[DefaultValue(VideoStandard.NTSC)]
|
||||
[TypeConverter(typeof(VideoStandard))]
|
||||
public VideoStandard VideoStandard { get; set; }
|
||||
|
||||
[DisplayName("Controller 1 Type")]
|
||||
[Description("Sets the type of controller connected to the console's port 1.")]
|
||||
[DefaultValue(ControllerType.Gamepad)]
|
||||
[TypeConverter(typeof(ControllerType))]
|
||||
public ControllerType Controller1Type { get; set; }
|
||||
|
||||
[DisplayName("Controller 2 Type")]
|
||||
[Description("Sets the type of controller connected to the console's port 2.")]
|
||||
[DefaultValue(ControllerType.None)]
|
||||
[TypeConverter(typeof(ControllerType))]
|
||||
public ControllerType Controller2Type { get; set; }
|
||||
|
||||
public SyncSettings()
|
||||
=> SettingsUtil.SetDefaultValues(this);
|
||||
|
||||
public SyncSettings Clone()
|
||||
=> (SyncSettings) MemberwiseClone();
|
||||
|
||||
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
|
||||
=> !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using BizHawk.Emulation.DiscSystem;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Panasonic3DO
|
||||
{
|
||||
[PortedCore(
|
||||
name: CoreNames.Opera,
|
||||
author: "Libretro Team",
|
||||
portedVersion: "2025.03.08 (67a29e6)",
|
||||
portedUrl: "https://github.com/libretro/opera-libretro",
|
||||
isReleased: false)]
|
||||
public partial class Opera : WaterboxCore
|
||||
{
|
||||
private static readonly Configuration ConfigNTSC = new Configuration
|
||||
{
|
||||
SystemId = VSystemID.Raw.Panasonic3DO,
|
||||
MaxSamples = 8 * 1024,
|
||||
DefaultWidth = LibOpera.NTSC_WIDTH,
|
||||
DefaultHeight = LibOpera.NTSC_HEIGHT,
|
||||
MaxWidth = LibOpera.PAL2_WIDTH,
|
||||
MaxHeight = LibOpera.PAL2_HEIGHT,
|
||||
DefaultFpsNumerator = LibOpera.NTSC_VIDEO_NUMERATOR,
|
||||
DefaultFpsDenominator = LibOpera.NTSC_VIDEO_DENOMINATOR,
|
||||
};
|
||||
|
||||
private static readonly Configuration ConfigPAL1 = new Configuration
|
||||
{
|
||||
SystemId = VSystemID.Raw.Panasonic3DO,
|
||||
MaxSamples = 8 * 1024,
|
||||
DefaultWidth = LibOpera.PAL1_WIDTH,
|
||||
DefaultHeight = LibOpera.PAL1_HEIGHT,
|
||||
MaxWidth = LibOpera.PAL1_WIDTH,
|
||||
MaxHeight = LibOpera.PAL1_HEIGHT,
|
||||
DefaultFpsNumerator = LibOpera.PAL1_VIDEO_NUMERATOR,
|
||||
DefaultFpsDenominator = LibOpera.PAL1_VIDEO_DENOMINATOR,
|
||||
};
|
||||
|
||||
private static readonly Configuration ConfigPAL2 = new Configuration
|
||||
{
|
||||
SystemId = VSystemID.Raw.Panasonic3DO,
|
||||
MaxSamples = 8 * 1024,
|
||||
DefaultWidth = LibOpera.PAL2_WIDTH,
|
||||
DefaultHeight = LibOpera.PAL2_HEIGHT,
|
||||
MaxWidth = LibOpera.PAL2_WIDTH,
|
||||
MaxHeight = LibOpera.PAL2_HEIGHT,
|
||||
DefaultFpsNumerator = LibOpera.PAL2_VIDEO_NUMERATOR,
|
||||
DefaultFpsDenominator = LibOpera.PAL2_VIDEO_DENOMINATOR,
|
||||
};
|
||||
|
||||
private readonly List<IDiscAsset> _discAssets;
|
||||
|
||||
public override int VirtualWidth => BufferHeight * 4 / 3;
|
||||
private LibOpera _libOpera;
|
||||
|
||||
// Image selection / swapping variables
|
||||
|
||||
[CoreConstructor(VSystemID.Raw.Panasonic3DO)]
|
||||
public Opera(CoreLoadParameters<object, SyncSettings> lp)
|
||||
: base(
|
||||
lp.Comm,
|
||||
lp.SyncSettings?.VideoStandard switch
|
||||
{
|
||||
null or VideoStandard.NTSC => ConfigNTSC,
|
||||
VideoStandard.PAL1 => ConfigPAL1,
|
||||
VideoStandard.PAL2 => ConfigPAL2,
|
||||
_ => throw new InvalidOperationException($"unexpected value for sync setting {nameof(SyncSettings.VideoStandard)}"),
|
||||
})
|
||||
{
|
||||
DriveLightEnabled = true;
|
||||
_discAssets = lp.Discs;
|
||||
|
||||
// If no discs loaded, then there's nothing to emulate
|
||||
if (_discAssets.Count == 0) throw new InvalidOperationException("No CDs provided for emulation");
|
||||
_isMultidisc = _discAssets.Count > 1;
|
||||
|
||||
_CDReadCallback = CDRead;
|
||||
_CDSectorCountCallback = CDSectorCount;
|
||||
_discIndex = 0;
|
||||
foreach (var disc in _discAssets) _cdReaders.Add(new(disc.DiscData));
|
||||
|
||||
Console.WriteLine($"[CD] Sector count: {_discAssets[0].DiscData.Session1.LeadoutLBA}");
|
||||
_syncSettings = lp.SyncSettings ?? new();
|
||||
ControllerDefinition = CreateControllerDefinition(_syncSettings, _isMultidisc);
|
||||
|
||||
_libOpera = PreInit<LibOpera>(
|
||||
new WaterboxOptions
|
||||
{
|
||||
Filename = "opera.wbx",
|
||||
SbrkHeapSizeKB = 256 * 1024,
|
||||
SealedHeapSizeKB = 1024,
|
||||
InvisibleHeapSizeKB = 1024,
|
||||
PlainHeapSizeKB = 1024,
|
||||
MmapHeapSizeKB = 256 * 1024,
|
||||
SkipCoreConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
|
||||
SkipMemoryConsistencyCheck = lp.Comm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
|
||||
},
|
||||
[ _CDReadCallback, _CDSectorCountCallback ]);
|
||||
|
||||
// Setting CD callbacks
|
||||
_libOpera.SetCdCallbacks(_CDReadCallback, _CDSectorCountCallback);
|
||||
|
||||
// Adding BIOS file
|
||||
string biosType = _syncSettings.SystemType switch
|
||||
{
|
||||
SystemType.Panasonic_FZ1_U => "Panasonic_FZ1_U",
|
||||
SystemType.Panasonic_FZ1_E => "Panasonic_FZ1_E",
|
||||
SystemType.Panasonic_FZ1_J => "Panasonic_FZ1_J",
|
||||
SystemType.Panasonic_FZ10_U => "Panasonic_FZ10_U",
|
||||
SystemType.Panasonic_FZ10_E => "Panasonic_FZ10_E",
|
||||
SystemType.Panasonic_FZ10_J => "Panasonic_FZ10_J",
|
||||
SystemType.Goldstar_GDO101P => "Goldstar_GDO101P",
|
||||
SystemType.Goldstar_FC1 => "Goldstar_FC1",
|
||||
SystemType.Sanyo_IMP21J_Try => "Sanyo_IMP21J_Try",
|
||||
SystemType.Sanyo_HC21 => "Sanyo_HC21",
|
||||
SystemType.Shootout_At_Old_Tucson => "Shootout_At_Old_Tucson",
|
||||
SystemType._3DO_NTSC_1fc2 => "3DO_NTSC_1fc2",
|
||||
_ => "None",
|
||||
};
|
||||
|
||||
var (biosData, biosInfo) = CoreComm.CoreFileProvider.GetFirmwareWithGameInfoOrThrow(new(VSystemID.Raw.Panasonic3DO, biosType), "BIOS ROM files are required!");
|
||||
string biosFileName = biosInfo.Name + ".bin";
|
||||
_exe.AddReadonlyFile(biosData, biosFileName);
|
||||
|
||||
// Adding Font ROM file, if required
|
||||
string fontROMType = _syncSettings.FontROM switch
|
||||
{
|
||||
FontROM.Kanji_ROM_Panasonic_FZ1 => "Kanji_ROM_Panasonic_FZ1",
|
||||
FontROM.Kanji_ROM_Panasonic_FZ10 => "Kanji_ROM_Panasonic_FZ10",
|
||||
_ => "None",
|
||||
};
|
||||
|
||||
string fontROMFileName = "None";
|
||||
if (fontROMType != "None")
|
||||
{
|
||||
var (fontROMData, fontROMInfo) = CoreComm.CoreFileProvider.GetFirmwareWithGameInfoOrThrow(new(VSystemID.Raw.Panasonic3DO, fontROMType), "Font ROM files are required!");
|
||||
_exe.AddReadonlyFile(fontROMData, fontROMInfo.Name);
|
||||
fontROMFileName = fontROMInfo.Name;
|
||||
}
|
||||
|
||||
////////////// Initializing Core
|
||||
string cdName = _discAssets[0].DiscName;
|
||||
Console.WriteLine($"Launching Core with Game: '{cdName}', BIOS ROM: '{biosFileName}', Font ROM: '{fontROMFileName}'");
|
||||
if (!_libOpera.Init(
|
||||
gameFile: cdName,
|
||||
biosFile: biosFileName,
|
||||
fontFile: fontROMFileName,
|
||||
port1Type: (int) _syncSettings.Controller1Type,
|
||||
port2Type: (int) _syncSettings.Controller2Type,
|
||||
videoStandard: (int) _syncSettings.VideoStandard))
|
||||
{
|
||||
throw new InvalidOperationException("Core rejected the rom!");
|
||||
}
|
||||
|
||||
PostInit();
|
||||
}
|
||||
|
||||
// CD Handling logic
|
||||
private bool _isMultidisc;
|
||||
private bool _discInserted = true;
|
||||
private readonly LibOpera.CDReadCallback _CDReadCallback;
|
||||
private readonly LibOpera.CDSectorCountCallback _CDSectorCountCallback;
|
||||
private int _discIndex;
|
||||
private readonly List<DiscSectorReader> _cdReaders = new List<DiscSectorReader>();
|
||||
private static int CD_SECTOR_SIZE = 2048;
|
||||
private readonly byte[] _sectorBuffer = new byte[CD_SECTOR_SIZE];
|
||||
|
||||
private void SelectNextDisc()
|
||||
{
|
||||
_discIndex++;
|
||||
if (_discIndex == _discAssets.Count) _discIndex = 0;
|
||||
CoreComm.Notify($"Selected CDROM {_discIndex}: {_discAssets[_discIndex].DiscName}", null);
|
||||
}
|
||||
|
||||
private void SelectPrevDisc()
|
||||
{
|
||||
_discIndex--;
|
||||
if (_discIndex < 0) _discIndex = _discAssets.Count - 1;
|
||||
CoreComm.Notify($"Selected CDROM {_discIndex}: {_discAssets[_discIndex].DiscName}", null);
|
||||
}
|
||||
|
||||
private void CDRead(int lba, IntPtr dest)
|
||||
{
|
||||
if (_discIndex < _discAssets.Count)
|
||||
{
|
||||
_cdReaders[_discIndex].ReadLBA_2048(lba, _sectorBuffer, 0);
|
||||
Marshal.Copy(_sectorBuffer, 0, dest, CD_SECTOR_SIZE);
|
||||
}
|
||||
DriveLightOn = true;
|
||||
}
|
||||
|
||||
private int CDSectorCount()
|
||||
{
|
||||
if (_discIndex < _discAssets.Count) return _discAssets[_discIndex].DiscData.Session1.LeadoutLBA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
var fi = new LibOpera.FrameInfo();
|
||||
|
||||
// Disc management
|
||||
if (_isMultidisc)
|
||||
{
|
||||
if (controller.IsPressed("Next Disc")) SelectNextDisc();
|
||||
if (controller.IsPressed("Prev Disc")) SelectPrevDisc();
|
||||
}
|
||||
|
||||
DriveLightOn = false;
|
||||
fi.port1 = ProcessController(1, _syncSettings.Controller1Type, controller);
|
||||
fi.port2 = ProcessController(2, _syncSettings.Controller2Type, controller);
|
||||
|
||||
// Game reset
|
||||
if (controller.IsPressed("Reset")) fi.isReset = 1;
|
||||
|
||||
return fi;
|
||||
}
|
||||
|
||||
private static LibOpera.GameInput ProcessController(int port, ControllerType type, IController controller)
|
||||
{
|
||||
LibOpera.GameInput gameInput = new LibOpera.GameInput();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ControllerType.Gamepad:
|
||||
gameInput.gamepad.up = controller.IsPressed($"P{port} {JoystickButtons.Up}") ? 1 : 0;
|
||||
gameInput.gamepad.down = controller.IsPressed($"P{port} {JoystickButtons.Down}") ? 1 : 0;
|
||||
gameInput.gamepad.left = controller.IsPressed($"P{port} {JoystickButtons.Left}") ? 1 : 0;
|
||||
gameInput.gamepad.right = controller.IsPressed($"P{port} {JoystickButtons.Right}") ? 1 : 0;
|
||||
gameInput.gamepad.buttonX = controller.IsPressed($"P{port} {JoystickButtons.ButtonX}") ? 1 : 0;
|
||||
gameInput.gamepad.buttonP = controller.IsPressed($"P{port} {JoystickButtons.ButtonP}") ? 1 : 0;
|
||||
gameInput.gamepad.buttonA = controller.IsPressed($"P{port} {JoystickButtons.ButtonA}") ? 1 : 0;
|
||||
gameInput.gamepad.buttonB = controller.IsPressed($"P{port} {JoystickButtons.ButtonB}") ? 1 : 0;
|
||||
gameInput.gamepad.buttonC = controller.IsPressed($"P{port} {JoystickButtons.ButtonC}") ? 1 : 0;
|
||||
gameInput.gamepad.buttonL = controller.IsPressed($"P{port} {JoystickButtons.ButtonL}") ? 1 : 0;
|
||||
gameInput.gamepad.buttonR = controller.IsPressed($"P{port} {JoystickButtons.ButtonR}") ? 1 : 0;
|
||||
break;
|
||||
|
||||
case ControllerType.Mouse:
|
||||
gameInput.mouse.dX = controller.AxisValue($"P{port} {Inputs.MouseX}");
|
||||
gameInput.mouse.dY = controller.AxisValue($"P{port} {Inputs.MouseY}");
|
||||
gameInput.mouse.leftButton = controller.IsPressed($"P{port} {Inputs.MouseLeftButton}") ? 1 : 0;
|
||||
gameInput.mouse.middleButton = controller.IsPressed($"P{port} {Inputs.MouseMiddleButton}") ? 1 : 0;
|
||||
gameInput.mouse.rightButton = controller.IsPressed($"P{port} {Inputs.MouseRightButton}") ? 1 : 0;
|
||||
gameInput.mouse.fourthButton = controller.IsPressed($"P{port} {Inputs.MouseFourthButton}") ? 1 : 0;
|
||||
break;
|
||||
|
||||
case ControllerType.FlightStick:
|
||||
gameInput.flightStick.up = controller.IsPressed($"P{port} {FlightStickButtons.Up}") ? 1 : 0;
|
||||
gameInput.flightStick.down = controller.IsPressed($"P{port} {FlightStickButtons.Down}") ? 1 : 0;
|
||||
gameInput.flightStick.left = controller.IsPressed($"P{port} {FlightStickButtons.Left}") ? 1 : 0;
|
||||
gameInput.flightStick.right = controller.IsPressed($"P{port} {FlightStickButtons.Right}") ? 1 : 0;
|
||||
gameInput.flightStick.fire = controller.IsPressed($"P{port} {FlightStickButtons.Fire}") ? 1 : 0;
|
||||
gameInput.flightStick.buttonA = controller.IsPressed($"P{port} {FlightStickButtons.ButtonA}") ? 1 : 0;
|
||||
gameInput.flightStick.buttonB = controller.IsPressed($"P{port} {FlightStickButtons.ButtonB}") ? 1 : 0;
|
||||
gameInput.flightStick.buttonC = controller.IsPressed($"P{port} {FlightStickButtons.ButtonC}") ? 1 : 0;
|
||||
gameInput.flightStick.buttonX = controller.IsPressed($"P{port} {FlightStickButtons.ButtonX}") ? 1 : 0;
|
||||
gameInput.flightStick.buttonP = controller.IsPressed($"P{port} {FlightStickButtons.ButtonP}") ? 1 : 0;
|
||||
gameInput.flightStick.leftTrigger = controller.IsPressed($"P{port} {FlightStickButtons.LeftTrigger}") ? 1 : 0;
|
||||
gameInput.flightStick.rightTrigger = controller.IsPressed($"P{port} {FlightStickButtons.RightTrigger}") ? 1 : 0;
|
||||
gameInput.flightStick.horizontalAxis = controller.AxisValue($"P{port} {Inputs.FlighStickHorizontalAxis}");
|
||||
gameInput.flightStick.verticalAxis = controller.AxisValue($"P{port} {Inputs.FlighStickVerticalAxis}");
|
||||
gameInput.flightStick.altitudeAxis = controller.AxisValue($"P{port} {Inputs.FlighStickAltitudeAxis}");
|
||||
break;
|
||||
|
||||
case ControllerType.LightGun:
|
||||
gameInput.lightGun.trigger = controller.IsPressed($"P{port} {LightGunButtons.Trigger}") ? 1 : 0;
|
||||
gameInput.lightGun.select = controller.IsPressed($"P{port} {LightGunButtons.Select}") ? 1 : 0;
|
||||
gameInput.lightGun.reload = controller.IsPressed($"P{port} {LightGunButtons.Reload}") ? 1 : 0;
|
||||
gameInput.lightGun.isOffScreen = controller.IsPressed($"P{port} {LightGunButtons.IsOffScreen}") ? 1 : 0;
|
||||
gameInput.lightGun.screenX = controller.AxisValue($"P{port} {Inputs.LightGunScreenX}");
|
||||
gameInput.lightGun.screenY = controller.AxisValue($"P{port} {Inputs.LightGunScreenY}");
|
||||
break;
|
||||
|
||||
case ControllerType.ArcadeLightGun:
|
||||
gameInput.arcadeLightGun.trigger = controller.IsPressed($"P{port} {ArcadeLightGunButtons.Trigger}") ? 1 : 0;
|
||||
gameInput.arcadeLightGun.select = controller.IsPressed($"P{port} {ArcadeLightGunButtons.Select}") ? 1 : 0;
|
||||
gameInput.arcadeLightGun.start = controller.IsPressed($"P{port} {ArcadeLightGunButtons.Start}") ? 1 : 0;
|
||||
gameInput.arcadeLightGun.reload = controller.IsPressed($"P{port} {ArcadeLightGunButtons.Reload}") ? 1 : 0;
|
||||
gameInput.arcadeLightGun.auxA = controller.IsPressed($"P{port} {ArcadeLightGunButtons.AuxA}") ? 1 : 0;
|
||||
gameInput.arcadeLightGun.isOffScreen = controller.IsPressed($"P{port} {ArcadeLightGunButtons.IsOffScreen}") ? 1 : 0;
|
||||
gameInput.arcadeLightGun.screenX = controller.AxisValue($"P{port} {Inputs.LightGunScreenX}");
|
||||
gameInput.arcadeLightGun.screenY = controller.AxisValue($"P{port} {Inputs.LightGunScreenY}");
|
||||
break;
|
||||
|
||||
case ControllerType.OrbatakTrackball:
|
||||
gameInput.orbatakTrackball.startP1 = controller.IsPressed($"P{port} {OrbatakTrackballButtons.StartP1}") ? 1 : 0;
|
||||
gameInput.orbatakTrackball.startP2 = controller.IsPressed($"P{port} {OrbatakTrackballButtons.StartP2}") ? 1 : 0;
|
||||
gameInput.orbatakTrackball.coinP1 = controller.IsPressed($"P{port} {OrbatakTrackballButtons.CoinP1}") ? 1 : 0;
|
||||
gameInput.orbatakTrackball.coinP2 = controller.IsPressed($"P{port} {OrbatakTrackballButtons.CoinP2}") ? 1 : 0;
|
||||
gameInput.orbatakTrackball.service = controller.IsPressed($"P{port} {OrbatakTrackballButtons.Service}") ? 1 : 0;
|
||||
gameInput.orbatakTrackball.dX = controller.AxisValue($"P{port} {Inputs.TrackballPosX}");
|
||||
gameInput.orbatakTrackball.dY = controller.AxisValue($"P{port} {Inputs.TrackballPosY}");
|
||||
break;
|
||||
}
|
||||
|
||||
return gameInput;
|
||||
}
|
||||
|
||||
protected override void FrameAdvancePost()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SaveStateBinaryInternal(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(_discIndex);
|
||||
writer.Write(_discInserted);
|
||||
}
|
||||
|
||||
protected override void LoadStateBinaryInternal(BinaryReader reader)
|
||||
{
|
||||
_discIndex = reader.ReadInt32();
|
||||
_discInserted = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@ namespace BizHawk.Emulation.Cores
|
|||
public const string Nymashock = "Nymashock";
|
||||
public const string O2Hawk = "O2Hawk";
|
||||
public const string Octoshock = "Octoshock";
|
||||
public const string Opera = "Opera";
|
||||
public const string PceHawk = "PCEHawk";
|
||||
public const string PicoDrive = "PicoDrive";
|
||||
public const string QuickNes = "quickerNES";
|
||||
|
|
|
@ -352,14 +352,21 @@ namespace BizHawk.Emulation.DiscSystem
|
|||
private bool Detect3DO()
|
||||
{
|
||||
var toc = _disc.TOC;
|
||||
for (var t = toc.FirstRecordedTrackNumber;
|
||||
t <= toc.LastRecordedTrackNumber;
|
||||
t++)
|
||||
for (var t = toc.FirstRecordedTrackNumber; t <= toc.LastRecordedTrackNumber; t++)
|
||||
{
|
||||
var track = _disc.TOC.TOCItems[t];
|
||||
if (track.IsData && SectorContains("iamaduckiamaduck", track.LBA))
|
||||
return true;
|
||||
// https://groups.google.com/g/rec.games.video.3do/c/1U3qrmLSYMQ?pli=1
|
||||
// The iamaduck is not mandatory and not present in all games
|
||||
if (track.IsData && SectorContains("iamaduckiamaduck", track.LBA)) return true;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
// The following sync pattern is present in 3DO games
|
||||
// https://github.com/trapexit/3dt/blob/84f1aa5a5e778f14c2216fc0c891e78625266cad/src/tdo_disc_label.hpp#L65
|
||||
if (SectorContains(Convert.ToChar(01) + "ZZZZZ" + Convert.ToChar(01), i)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ make -C dsda $1 -j
|
|||
make -C gpgx $1 -j
|
||||
make -C libsnes $1 -j
|
||||
make -C melon $1 -j
|
||||
make -C opera $1 -j
|
||||
make -C picodrive $1 -j
|
||||
make -C stella $1 -j
|
||||
make -C snes9x $1 -j
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
TARGET := opera.wbx
|
||||
CCFLAGS := -I. \
|
||||
-Iopera-libretro \
|
||||
-Iopera-libretro/libopera \
|
||||
-Iopera-libretro/libretro-common/include \
|
||||
-Iopera-libretro/deps \
|
||||
-Iopera-libretro/deps/lzma-19.00/include \
|
||||
-Iopera-libretro/deps/libchdr/include \
|
||||
-Iopera-libretro/deps/zlib-1.2.11 \
|
||||
-DHAVE_CHD \
|
||||
-D_7ZIP_ST \
|
||||
-DDR_FLAC_NO_STDIO \
|
||||
-D__LIBRETRO__ \
|
||||
-DNDEBUG \
|
||||
-DHAVE_CDROM \
|
||||
-DHAVE_STDINT_H \
|
||||
-DHAVE_STDLIB_H \
|
||||
-DHAVE_SYS_PARAM_H \
|
||||
-DINLINE=inline \
|
||||
-DTHREADED_DSP
|
||||
CXXFLAGS := $(CCFLAGS)
|
||||
SRCS = bizhawk.cpp \
|
||||
opera-libretro/lr_input.c \
|
||||
opera-libretro/libretro_core_options.c \
|
||||
opera-libretro/lr_input_crosshair.c \
|
||||
opera-libretro/opera_lr_nvram.c \
|
||||
opera-libretro/libopera/opera_mem.c \
|
||||
opera-libretro/libopera/opera_diag_port.c \
|
||||
opera-libretro/libopera/prng32.c \
|
||||
opera-libretro/libopera/opera_sport.c \
|
||||
opera-libretro/libopera/opera_arm.c \
|
||||
opera-libretro/libopera/opera_region.c \
|
||||
opera-libretro/libopera/opera_bios.c \
|
||||
opera-libretro/libopera/prng16.c \
|
||||
opera-libretro/libopera/opera_cdrom.c \
|
||||
opera-libretro/libopera/opera_clock.c \
|
||||
opera-libretro/libopera/opera_log.c \
|
||||
opera-libretro/libopera/opera_fixedpoint_math.c \
|
||||
opera-libretro/libopera/opera_nvram.c \
|
||||
opera-libretro/libopera/opera_3do.c \
|
||||
opera-libretro/libopera/opera_xbus_cdrom_plugin.c \
|
||||
opera-libretro/libopera/opera_madam.c \
|
||||
opera-libretro/libopera/opera_dsp.c \
|
||||
opera-libretro/libopera/opera_state.c \
|
||||
opera-libretro/libopera/opera_xbus.c \
|
||||
opera-libretro/libopera/opera_bitop.c \
|
||||
opera-libretro/libopera/opera_vdlp.c \
|
||||
opera-libretro/libopera/opera_clio.c \
|
||||
opera-libretro/libopera/opera_pbus.c \
|
||||
opera-libretro/libretro.c \
|
||||
opera-libretro/retro_cdimage.c \
|
||||
opera-libretro/opera_lr_callbacks.c \
|
||||
opera-libretro/opera_lr_opts.c \
|
||||
opera-libretro/deps/zlib-1.2.11/zutil.c \
|
||||
opera-libretro/deps/zlib-1.2.11/adler32.c \
|
||||
opera-libretro/deps/zlib-1.2.11/inflate.c \
|
||||
opera-libretro/deps/zlib-1.2.11/inftrees.c \
|
||||
opera-libretro/deps/zlib-1.2.11/crc32.c \
|
||||
opera-libretro/deps/zlib-1.2.11/infback.c \
|
||||
opera-libretro/deps/zlib-1.2.11/inffast.c \
|
||||
opera-libretro/deps/lzma-19.00/src/BraIA64.c \
|
||||
opera-libretro/deps/lzma-19.00/src/CpuArch.c \
|
||||
opera-libretro/deps/lzma-19.00/src/Sort.c \
|
||||
opera-libretro/deps/lzma-19.00/src/Bra86.c \
|
||||
opera-libretro/deps/lzma-19.00/src/Alloc.c \
|
||||
opera-libretro/deps/lzma-19.00/src/LzmaEnc.c \
|
||||
opera-libretro/deps/lzma-19.00/src/Lzma86Dec.c \
|
||||
opera-libretro/deps/lzma-19.00/src/Delta.c \
|
||||
opera-libretro/deps/lzma-19.00/src/LzmaDec.c \
|
||||
opera-libretro/deps/lzma-19.00/src/Lzma86Enc.c \
|
||||
opera-libretro/deps/lzma-19.00/src/LzFind.c \
|
||||
opera-libretro/deps/libchdr/src/libchdr_cdrom.c \
|
||||
opera-libretro/deps/libchdr/src/libchdr_flac.c \
|
||||
opera-libretro/deps/libchdr/src/libchdr_bitstream.c \
|
||||
opera-libretro/deps/libchdr/src/libchdr_chd.c \
|
||||
opera-libretro/deps/libchdr/src/libchdr_huffman.c \
|
||||
opera-libretro/cuefile.c \
|
||||
opera-libretro/opera_lr_dsp.c \
|
||||
opera-libretro/libretro-common/string/stdstring.c \
|
||||
opera-libretro/libretro-common/vfs/vfs_implementation_cdrom.c \
|
||||
opera-libretro/libretro-common/vfs/vfs_implementation.c \
|
||||
opera-libretro/libretro-common/encodings/encoding_utf.c \
|
||||
opera-libretro/libretro-common/file/retro_dirent.c \
|
||||
opera-libretro/libretro-common/file/file_path.c \
|
||||
opera-libretro/libretro-common/compat/compat_strl.c \
|
||||
opera-libretro/libretro-common/compat/fopen_utf8.c \
|
||||
opera-libretro/libretro-common/compat/compat_snprintf.c \
|
||||
opera-libretro/libretro-common/compat/compat_posix_string.c \
|
||||
opera-libretro/libretro-common/compat/compat_strcasestr.c \
|
||||
opera-libretro/libretro-common/streams/file_stream.c \
|
||||
opera-libretro/libretro-common/streams/chd_stream.c \
|
||||
opera-libretro/libretro-common/streams/interface_stream.c \
|
||||
opera-libretro/libretro-common/streams/file_stream_transforms.c \
|
||||
opera-libretro/libretro-common/streams/memory_stream.c \
|
||||
opera-libretro/libretro-common/rthreads/rthreads.c \
|
||||
opera-libretro/libretro-common/lists/dir_list.c \
|
||||
opera-libretro/libretro-common/lists/string_list.c \
|
||||
opera-libretro/libretro-common/cdrom/cdrom.c \
|
||||
opera-libretro/libretro-common/memmap/memalign.c \
|
||||
opera-libretro/libretro-common/memmap/memmap.c \
|
||||
opera-libretro/lr_input_descs.c
|
||||
|
||||
include ../common.mak
|
|
@ -0,0 +1,391 @@
|
|||
#include "bizhawk.hpp"
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <libretro.h>
|
||||
#include <lr_input.h>
|
||||
#include <opera_vdlp.h>
|
||||
#include <opera_mem.h>
|
||||
#include <opera_cdrom.h>
|
||||
#include <opera_xbus.h>
|
||||
|
||||
std::string _biosFilePath;
|
||||
std::string _gameFilePath;
|
||||
std::string _fontFilePath;
|
||||
int _port1Type;
|
||||
int _port2Type;
|
||||
controllerData_t _port1Value;
|
||||
controllerData_t _port2Value;
|
||||
uint32_t* _videoBuffer;
|
||||
size_t _videoHeight;
|
||||
size_t _videoWidth;
|
||||
size_t _videoPitch;
|
||||
int _region;
|
||||
int _nvramChanged;
|
||||
int _inputPortsRead;
|
||||
|
||||
#define _MAX_SAMPLES 4096
|
||||
#define _CHANNEL_COUNT 2
|
||||
int16_t _audioBuffer[_MAX_SAMPLES * _CHANNEL_COUNT];
|
||||
size_t _audioSamples;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void* xbus_cdrom_plugin(int proc_, void* data_);
|
||||
void opera_cdrom_set_callbacks(opera_cdrom_get_size_cb_t get_size_, opera_cdrom_set_sector_cb_t set_sector_, opera_cdrom_read_sector_cb_t read_sector_);
|
||||
void opera_nvram_init(void *buf, const int bufsize);
|
||||
void opera_lr_callbacks_set_audio_sample(retro_audio_sample_t cb);
|
||||
void opera_lr_callbacks_set_audio_sample_batch(retro_audio_sample_batch_t cb);
|
||||
void opera_lr_callbacks_set_environment(retro_environment_t cb);
|
||||
void opera_lr_callbacks_set_input_poll(retro_input_poll_t cb);
|
||||
void opera_lr_callbacks_set_input_state(retro_input_state_t cb);
|
||||
void opera_lr_callbacks_set_log_printf(retro_log_printf_t cb);
|
||||
void opera_lr_callbacks_set_video_refresh(retro_video_refresh_t cb);
|
||||
RETRO_API void *retro_get_memory_data(unsigned id);
|
||||
RETRO_API size_t retro_get_memory_size(unsigned id);
|
||||
void retro_set_controller_port_device(unsigned port_, unsigned device_);
|
||||
void retro_get_system_av_info(struct retro_system_av_info *info_);
|
||||
}
|
||||
|
||||
void RETRO_CALLCONV retro_video_refresh_callback(const void *data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
// printf("Video %p, w: %u, h: %u, p: %lu\n", data, width, height, pitch);
|
||||
_videoBuffer = (uint32_t*)data;
|
||||
_videoWidth = width;
|
||||
_videoHeight = height;
|
||||
_videoPitch = pitch;
|
||||
}
|
||||
|
||||
void RETRO_CALLCONV retro_log_printf_callback(enum retro_log_level level, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
printf(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
size_t RETRO_CALLCONV retro_audio_sample_batch_callback(const int16_t *data, size_t frames)
|
||||
{
|
||||
memcpy(_audioBuffer, data, sizeof(int16_t) * frames * _CHANNEL_COUNT);
|
||||
_audioSamples = frames;
|
||||
return frames;
|
||||
}
|
||||
|
||||
void RETRO_CALLCONV retro_input_poll_callback()
|
||||
{
|
||||
// printf("Libretro Input Poll Callback Called:\n");
|
||||
}
|
||||
|
||||
int16_t processController(const int portType, controllerData_t& portValue, const unsigned device, const unsigned index, const unsigned id)
|
||||
{
|
||||
switch (portType)
|
||||
{
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_JOYPAD_UP: return portValue.gamePad.up;
|
||||
case RETRO_DEVICE_ID_JOYPAD_DOWN: return portValue.gamePad.down;
|
||||
case RETRO_DEVICE_ID_JOYPAD_LEFT: return portValue.gamePad.left;
|
||||
case RETRO_DEVICE_ID_JOYPAD_RIGHT: return portValue.gamePad.right;
|
||||
case RETRO_DEVICE_ID_JOYPAD_L: return portValue.gamePad.buttonL;
|
||||
case RETRO_DEVICE_ID_JOYPAD_R: return portValue.gamePad.buttonR;
|
||||
case RETRO_DEVICE_ID_JOYPAD_SELECT: return portValue.gamePad.buttonX;
|
||||
case RETRO_DEVICE_ID_JOYPAD_START: return portValue.gamePad.buttonP;
|
||||
case RETRO_DEVICE_ID_JOYPAD_Y: return portValue.gamePad.buttonA;
|
||||
case RETRO_DEVICE_ID_JOYPAD_B: return portValue.gamePad.buttonB;
|
||||
case RETRO_DEVICE_ID_JOYPAD_A: return portValue.gamePad.buttonC;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_MOUSE_X: return portValue.mouse.dX;
|
||||
case RETRO_DEVICE_ID_MOUSE_Y: return portValue.mouse.dY;
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT: return portValue.mouse.leftButton;
|
||||
case RETRO_DEVICE_ID_MOUSE_MIDDLE: return portValue.mouse.middleButton;
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT: return portValue.mouse.rightButton;
|
||||
case RETRO_DEVICE_ID_MOUSE_BUTTON_4: return portValue.mouse.fourthButton;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
case RETRO_DEVICE_FLIGHTSTICK:
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_BUTTON)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_JOYPAD_R2: return portValue.flightStick.fire;
|
||||
case RETRO_DEVICE_ID_JOYPAD_Y: return portValue.flightStick.buttonA;
|
||||
case RETRO_DEVICE_ID_JOYPAD_B: return portValue.flightStick.buttonB;
|
||||
case RETRO_DEVICE_ID_JOYPAD_A: return portValue.flightStick.buttonC;
|
||||
case RETRO_DEVICE_ID_JOYPAD_UP: return portValue.flightStick.up;
|
||||
case RETRO_DEVICE_ID_JOYPAD_DOWN: return portValue.flightStick.down;
|
||||
case RETRO_DEVICE_ID_JOYPAD_LEFT: return portValue.flightStick.left;
|
||||
case RETRO_DEVICE_ID_JOYPAD_RIGHT: return portValue.flightStick.right;
|
||||
case RETRO_DEVICE_ID_JOYPAD_START: return portValue.flightStick.buttonP;
|
||||
case RETRO_DEVICE_ID_JOYPAD_SELECT: return portValue.flightStick.buttonX;
|
||||
case RETRO_DEVICE_ID_JOYPAD_L: return portValue.flightStick.leftTrigger;
|
||||
case RETRO_DEVICE_ID_JOYPAD_R: return portValue.flightStick.rightTrigger;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_ANALOG_X:
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_LEFT) return portValue.flightStick.horizontalAxis;
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) return portValue.flightStick.altitudeAxis;
|
||||
return 0;
|
||||
|
||||
case RETRO_DEVICE_ID_ANALOG_Y:
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_LEFT) return portValue.flightStick.verticalAxis;
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) return portValue.flightStick.altitudeAxis;
|
||||
return 0;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
case RETRO_DEVICE_LIGHTGUN:
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X: return portValue.lightGun.screenX;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y: return portValue.lightGun.screenY;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER: return portValue.lightGun.trigger;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_SELECT: return portValue.lightGun.select;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_RELOAD: return portValue.lightGun.reload;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN: return portValue.lightGun.isOffScreen;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
case RETRO_DEVICE_ARCADE_LIGHTGUN:
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X: return portValue.arcadeLightGun.screenX;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y: return portValue.arcadeLightGun.screenY;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER: return portValue.arcadeLightGun.trigger;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_SELECT: return portValue.arcadeLightGun.select;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_START: return portValue.arcadeLightGun.start;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_RELOAD: return portValue.arcadeLightGun.reload;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_AUX_A: return portValue.arcadeLightGun.auxA;
|
||||
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN: return portValue.arcadeLightGun.isOffScreen;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
case RETRO_DEVICE_ORBATAK_TRACKBALL:
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_ANALOG_X:
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_LEFT) return portValue.orbatakTrackball.dX;
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) return portValue.orbatakTrackball.dX;
|
||||
return 0;
|
||||
|
||||
case RETRO_DEVICE_ID_ANALOG_Y:
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_LEFT) return portValue.orbatakTrackball.dY;
|
||||
if (index == RETRO_DEVICE_INDEX_ANALOG_RIGHT) return portValue.orbatakTrackball.dY;
|
||||
return 0;
|
||||
|
||||
case RETRO_DEVICE_ID_JOYPAD_SELECT: return portValue.orbatakTrackball.startP1;
|
||||
case RETRO_DEVICE_ID_JOYPAD_START: return portValue.orbatakTrackball.startP2;
|
||||
case RETRO_DEVICE_ID_JOYPAD_L: return portValue.orbatakTrackball.coinP1;
|
||||
case RETRO_DEVICE_ID_JOYPAD_R: return portValue.orbatakTrackball.coinP2;
|
||||
case RETRO_DEVICE_ID_JOYPAD_R2: return portValue.orbatakTrackball.service;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t RETRO_CALLCONV retro_input_state_callback(unsigned port, unsigned device, unsigned index, unsigned id)
|
||||
{
|
||||
// printf("Libretro Input State Callback Called. Port: %u, Device: %u, Index: %u, Id: %u\n", port, device, index, id);
|
||||
if (port == 0) return processController(_port1Type, _port1Value, device, index, id);
|
||||
if (port == 1) return processController(_port2Type, _port2Value, device, index, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char _deviceCountOption[256];
|
||||
void configHandler(struct retro_variable *var)
|
||||
{
|
||||
printf("Variable Name: %s / Value: %s\n", var->key, var->value);
|
||||
|
||||
std::string key(var->key);
|
||||
|
||||
if (key == "opera_bios" && _biosFilePath != "None") var->value = _biosFilePath.c_str();
|
||||
if (key == "opera_font" && _fontFilePath != "None") var->value = _fontFilePath.c_str();
|
||||
if (key == "opera_region")
|
||||
{
|
||||
if (_region == 0) var->value = "ntsc";
|
||||
if (_region == 1) var->value = "pal1";
|
||||
if (_region == 2) var->value = "pal2";
|
||||
}
|
||||
if (key == "opera_active_devices")
|
||||
{
|
||||
int deviceCount = 0;
|
||||
if (_port1Type != RETRO_DEVICE_NONE) deviceCount++;
|
||||
if (_port2Type != RETRO_DEVICE_NONE) deviceCount++;
|
||||
sprintf(_deviceCountOption, "%d", deviceCount);
|
||||
var->value = _deviceCountOption;
|
||||
}
|
||||
}
|
||||
|
||||
const char* systemPath = ".";
|
||||
bool RETRO_CALLCONV retro_environment_callback(unsigned cmd, void *data)
|
||||
{
|
||||
// printf("Libretro Environment Callback Called: %u\n", cmd);
|
||||
|
||||
if (cmd == RETRO_ENVIRONMENT_GET_LOG_INTERFACE) { *((retro_log_printf_t*)data) = retro_log_printf_callback; return true; }
|
||||
if (cmd == RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL) { return true; }
|
||||
if (cmd == RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS) { return true; }
|
||||
if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE) { configHandler((struct retro_variable *)data); return true; }
|
||||
if (cmd == RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE) { return true; }
|
||||
if (cmd == RETRO_ENVIRONMENT_SET_PIXEL_FORMAT) { *((vdlp_pixel_format_e*) data) = VDLP_PIXEL_FORMAT_XRGB8888; return true; }
|
||||
if (cmd == RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY) { *((const char**)data) = systemPath; return true; }
|
||||
if (cmd == RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY) { *((const char**)data) = systemPath; return true; }
|
||||
|
||||
fprintf(stderr, "Unrecognized environment callback command: %u\n", cmd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// CD Management Logic Start
|
||||
#define CDIMAGE_SECTOR_SIZE 2048
|
||||
uint32_t _currentSector = 0;
|
||||
void (*cd_read_callback)(int32_t lba, void * dest);
|
||||
int (*cd_sector_count_callback)();
|
||||
ECL_EXPORT void SetCdCallbacks(void (*cdrc)(int32_t lba, void * dest), int (*cdscc)())
|
||||
{
|
||||
cd_read_callback = cdrc;
|
||||
cd_sector_count_callback = cdscc;
|
||||
}
|
||||
|
||||
uint32_t cd_get_size(void) { return cd_sector_count_callback(); }
|
||||
void cd_set_sector(const uint32_t sector_) { _currentSector = sector_; }
|
||||
void cd_read_sector(void *buf_) { cd_read_callback(_currentSector, buf_); }
|
||||
/// CD Management Logic End
|
||||
|
||||
// SRAM management start
|
||||
bool _sram_changed = false;
|
||||
ECL_EXPORT bool sram_changed() { return _nvramChanged; }
|
||||
ECL_EXPORT int get_sram_size() { return NVRAM_SIZE; }
|
||||
ECL_EXPORT uint8_t* get_sram_buffer() { return (uint8_t*) NVRAM; }
|
||||
ECL_EXPORT void get_sram(uint8_t* sramBuffer)
|
||||
{
|
||||
if (NVRAM == NULL) return;
|
||||
memcpy(sramBuffer, get_sram_buffer(), get_sram_size());
|
||||
}
|
||||
|
||||
ECL_EXPORT void set_sram(uint8_t* sramBuffer)
|
||||
{
|
||||
if (NVRAM == NULL) opera_nvram_init(NVRAM,NVRAM_SIZE);
|
||||
memcpy(get_sram_buffer(), sramBuffer, get_sram_size());
|
||||
}
|
||||
// SRAM Management end
|
||||
|
||||
ECL_EXPORT bool Init(const char* gameFilePath, const char* biosFilePath, const char* fontFilePath, int port1Type, int port2Type, int region)
|
||||
{
|
||||
_gameFilePath = gameFilePath;
|
||||
_biosFilePath = biosFilePath;
|
||||
_fontFilePath = fontFilePath;
|
||||
_port1Type = port1Type;
|
||||
_port2Type = port2Type;
|
||||
_region = region;
|
||||
|
||||
opera_lr_callbacks_set_environment(retro_environment_callback);
|
||||
opera_lr_callbacks_set_input_state(retro_input_state_callback);
|
||||
opera_lr_callbacks_set_input_poll(retro_input_poll_callback);
|
||||
opera_lr_callbacks_set_audio_sample_batch(retro_audio_sample_batch_callback);
|
||||
opera_lr_callbacks_set_video_refresh(retro_video_refresh_callback);
|
||||
|
||||
retro_set_controller_port_device(0, port1Type);
|
||||
retro_set_controller_port_device(1, port2Type);
|
||||
retro_init();
|
||||
|
||||
// Setting cd callbacks
|
||||
opera_cdrom_set_callbacks(cd_get_size, cd_set_sector, cd_read_sector);
|
||||
|
||||
// Loading game file
|
||||
struct retro_game_info game;
|
||||
game.path = _gameFilePath.c_str();
|
||||
auto loadResult = retro_load_game(&game);
|
||||
if (loadResult == false) { fprintf(stderr, "Could not load game: '%s'\n", _gameFilePath.c_str()); return false; }
|
||||
|
||||
// Getting av info
|
||||
struct retro_system_av_info info;
|
||||
retro_get_system_av_info(&info);
|
||||
printf("3DO Framerate: %f\n", info.timing.fps);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ECL_EXPORT void opera_get_video(int& w, int& h, int& pitch, uint8_t*& buffer)
|
||||
{
|
||||
buffer = (uint8_t*)_videoBuffer;
|
||||
w = _videoWidth;
|
||||
h = _videoHeight;
|
||||
pitch = _videoPitch;
|
||||
}
|
||||
|
||||
ECL_EXPORT void FrameAdvance(MyFrameInfo* f)
|
||||
{
|
||||
// Setting inputs
|
||||
_port1Value = f->port1;
|
||||
_port2Value = f->port2;
|
||||
|
||||
//printf("Mouse X%d(%d), Y%d(%d), L%d, M%d, B%d\n", _port1Value.mouse.posX, _port1Value.mouse.dX, _port1Value.mouse.posY, _port1Value.mouse.dY, _port1Value.mouse.leftButton, _port1Value.mouse.middleButton, _port1Value.mouse.rightButton);
|
||||
//fflush(stdout);
|
||||
|
||||
// Checking for changes in NVRAM
|
||||
_nvramChanged = false;
|
||||
|
||||
// Checking if ports have been read
|
||||
_inputPortsRead = 0;
|
||||
|
||||
// If resetting, do it now. Otherwise, running a single frame
|
||||
if (f->isReset == 1) retro_reset();
|
||||
else retro_run();
|
||||
|
||||
// The frame is lagged if no inputs were read
|
||||
f->base.Lagged = !_inputPortsRead;
|
||||
|
||||
// Setting video buffer
|
||||
f->base.Width = _videoWidth;
|
||||
f->base.Height = _videoHeight;
|
||||
memcpy(f->base.VideoBuffer, _videoBuffer, sizeof(uint32_t) * _videoWidth * _videoHeight);
|
||||
|
||||
// Setting audio buffer
|
||||
f->base.Samples = _audioSamples;
|
||||
memcpy(f->base.SoundBuffer, _audioBuffer, _audioSamples * sizeof(int16_t) * _CHANNEL_COUNT);
|
||||
}
|
||||
|
||||
ECL_EXPORT void GetMemoryAreas(MemoryArea *m)
|
||||
{
|
||||
int memAreaIdx = 0;
|
||||
|
||||
m[memAreaIdx].Data = retro_get_memory_data(RETRO_MEMORY_SYSTEM_RAM);
|
||||
m[memAreaIdx].Name = "System RAM";
|
||||
m[memAreaIdx].Size = retro_get_memory_size(RETRO_MEMORY_SYSTEM_RAM);
|
||||
m[memAreaIdx].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_PRIMARY;
|
||||
memAreaIdx++;
|
||||
|
||||
m[memAreaIdx].Data = retro_get_memory_data(RETRO_MEMORY_VIDEO_RAM);
|
||||
m[memAreaIdx].Name = "Video RAM";
|
||||
m[memAreaIdx].Size = retro_get_memory_size(RETRO_MEMORY_VIDEO_RAM);
|
||||
m[memAreaIdx].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE;
|
||||
memAreaIdx++;
|
||||
|
||||
m[memAreaIdx].Data = get_sram_buffer();
|
||||
m[memAreaIdx].Name = "Non-volatile RAM";
|
||||
m[memAreaIdx].Size = get_sram_size();
|
||||
m[memAreaIdx].Flags = MEMORYAREA_FLAGS_WORDSIZE1 | MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE;
|
||||
memAreaIdx++;
|
||||
}
|
||||
|
||||
void (*InputCallback)();
|
||||
ECL_EXPORT void SetInputCallback(void (*callback)())
|
||||
{
|
||||
InputCallback = callback;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
#pragma once
|
||||
|
||||
// system
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// waterbox
|
||||
#include "emulibc.h"
|
||||
#include "waterboxcore.h"
|
||||
|
||||
struct gamePad_t
|
||||
{
|
||||
int up;
|
||||
int down;
|
||||
int left;
|
||||
int right;
|
||||
int buttonX;
|
||||
int buttonP;
|
||||
int buttonA;
|
||||
int buttonB;
|
||||
int buttonC;
|
||||
int buttonL;
|
||||
int buttonR;
|
||||
};
|
||||
|
||||
struct mouse_t
|
||||
{
|
||||
int dX;
|
||||
int dY;
|
||||
int leftButton;
|
||||
int middleButton;
|
||||
int rightButton;
|
||||
int fourthButton;
|
||||
};
|
||||
|
||||
struct flightStick_t
|
||||
{
|
||||
int up;
|
||||
int down;
|
||||
int left;
|
||||
int right;
|
||||
int fire;
|
||||
int buttonA;
|
||||
int buttonB;
|
||||
int buttonC;
|
||||
int buttonX;
|
||||
int buttonP;
|
||||
int leftTrigger;
|
||||
int rightTrigger;
|
||||
int horizontalAxis;
|
||||
int verticalAxis;
|
||||
int altitudeAxis;
|
||||
};
|
||||
|
||||
struct lightGun_t
|
||||
{
|
||||
int trigger;
|
||||
int select;
|
||||
int reload;
|
||||
int isOffScreen;
|
||||
int screenX;
|
||||
int screenY;
|
||||
};
|
||||
|
||||
struct arcadeLightGun_t
|
||||
{
|
||||
int trigger;
|
||||
int select;
|
||||
int start;
|
||||
int reload;
|
||||
int auxA;
|
||||
int isOffScreen;
|
||||
int screenX;
|
||||
int screenY;
|
||||
};
|
||||
|
||||
struct OrbatakTrackball_t
|
||||
{
|
||||
int dX;
|
||||
int dY;
|
||||
int startP1;
|
||||
int startP2;
|
||||
int coinP1;
|
||||
int coinP2;
|
||||
int service;
|
||||
};
|
||||
|
||||
struct controllerData_t
|
||||
{
|
||||
gamePad_t gamePad;
|
||||
mouse_t mouse;
|
||||
flightStick_t flightStick;
|
||||
lightGun_t lightGun;
|
||||
arcadeLightGun_t arcadeLightGun;
|
||||
OrbatakTrackball_t orbatakTrackball;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FrameInfo base;
|
||||
controllerData_t port1;
|
||||
controllerData_t port2;
|
||||
int isReset;
|
||||
} MyFrameInfo;
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 536b8e2d4fae8b2aea97cbfa4c4e2d62843076ea
|
|
@ -39,6 +39,7 @@ It consists of a modified musl libc, and build scripts to tie it all together.
|
|||
* waterbox/uae/libretro-uae (required for uae)
|
||||
* waterbox/stella/core (required for stella)
|
||||
* waterbox/dsda/core (required for dsda)
|
||||
* waterbox/opera/opera-libretro (required for opera)
|
||||
* waterbox/dosbox/dosbox-x (required for DOSBox-x)
|
||||
* none of these submodules need to be cloned recursively
|
||||
|
||||
|
@ -80,6 +81,7 @@ It consists of a modified musl libc, and build scripts to tie it all together.
|
|||
cd nyma && make -f ss.mak install
|
||||
cd nyma && make -f shock.mak install
|
||||
cd nyma && make -f vb.mak install
|
||||
cd opera && make install
|
||||
cd picodrive && make install
|
||||
cd stella && make install
|
||||
cd snes9x && make install
|
||||
|
|
Loading…
Reference in New Issue