diff --git a/Assets/dll/libsameboy.dll b/Assets/dll/libsameboy.dll index 6ca1d714bb..bb48b78dfa 100644 Binary files a/Assets/dll/libsameboy.dll and b/Assets/dll/libsameboy.dll differ diff --git a/Assets/dll/libsameboy.so b/Assets/dll/libsameboy.so index a9c982ac4b..d854cca180 100755 Binary files a/Assets/dll/libsameboy.so and b/Assets/dll/libsameboy.so differ diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index ebe302f062..a4d1ca11ef 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -182,7 +182,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy _cdCallback = new LibGambatte.CDCallback(CDCallbackProc); - ControllerDefinition = CreateControllerDefinition(sgb: IsSgb, sub: _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames, tilt: false); + ControllerDefinition = CreateControllerDefinition(sgb: IsSgb, sub: _syncSettings.FrameLength is GambatteSyncSettings.FrameLengthType.UserDefinedFrames, tilt: false, rumble: false); NewSaveCoreSetBuff(); } @@ -247,7 +247,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy public long CycleCount => (long)_cycleCount; public double ClockRate => TICKSPERSECOND; - public static ControllerDefinition CreateControllerDefinition(bool sgb, bool sub, bool tilt) + public static ControllerDefinition CreateControllerDefinition(bool sgb, bool sub, bool tilt, bool rumble) { var ret = new ControllerDefinition((sub ? "Subframe " : "") + "Gameboy Controller" + (tilt ? " + Tilt" : "")); if (sub) @@ -258,6 +258,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { ret.AddXYPair($"Tilt {{0}}", AxisPairOrientation.RightAndUp, (-90).RangeTo(90), 0); } + if (rumble) + { + ret.HapticsChannels.Add("Rumble"); + } if (sgb) { for (int i = 0; i < 4; i++) diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs index bf8cc183f9..1561299b06 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.cs @@ -49,7 +49,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy _linkedCores[i] = new Gameboy(lp.Comm, lp.Roms[i].Game, lp.Roms[i].RomData, _settings._linkedSettings[i], _syncSettings._linkedSyncSettings[i], lp.DeterministicEmulationRequested); _linkedCores[i].ConnectInputCallbackSystem(_inputCallbacks); _linkedCores[i].ConnectMemoryCallbackSystem(_memoryCallbacks, i); - _linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: false)); + _linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: false, rumble: false)); _linkedBlips[i] = new BlipBuffer(1024); _linkedBlips[i].SetRates(2097152 * 2, 44100); _linkedOverflow[i] = 0; diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/LibSameBoy.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/LibSameBoy.cs index 36e4e54d72..f8e1a8919e 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/LibSameBoy.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/LibSameBoy.cs @@ -53,6 +53,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy [BizImport(cc)] public abstract void sameboy_setinputcallback(IntPtr core, InputCallback callback); + [UnmanagedFunctionPointer(cc)] + public delegate void RumbleCallback(int amplitude); + + [BizImport(cc)] + public abstract void sameboy_setrumblecallback(IntPtr core, RumbleCallback callback); + [BizImport(cc)] public abstract void sameboy_frameadvance(IntPtr core, Buttons buttons, ushort x, ushort y, short[] soundbuf, ref int nsamps, int[] videobuf, bool render, bool border); @@ -81,7 +87,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy public abstract int sameboy_statelen(IntPtr core); [BizImport(cc)] - public abstract bool sameboy_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref int length); + public abstract bool sameboy_getmemoryarea(IntPtr core, MemoryAreas which, ref IntPtr data, ref long length); [BizImport(cc)] public abstract byte sameboy_cpuread(IntPtr core, ushort addr); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IEmulator.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IEmulator.cs index 2e15fada63..9875a35281 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IEmulator.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IEmulator.cs @@ -11,10 +11,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy public ControllerDefinition ControllerDefinition { get; } + private IController _controller = NullController.Instance; + private static readonly IReadOnlyList GB_BUTTON_ORDER_IN_BITMASK = new[] { "Start", "Select", "B", "A", "Down", "Up", "Left", "Right", }; private LibSameboy.Buttons FrameAdvancePrep(IController controller) { + _controller = controller; + uint b = 0; for (var i = 0; i < 8; i++) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IMemoryDomains.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IMemoryDomains.cs index 9216a39080..bb969e389d 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IMemoryDomains.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.IMemoryDomains.cs @@ -7,14 +7,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy { public partial class Sameboy { - private readonly List _memoryDomains = new List(); + private readonly List _memoryDomains = new(); private IMemoryDomains MemoryDomains { get; set; } private void CreateMemoryDomain(LibSameboy.MemoryAreas which, string name) { IntPtr data = IntPtr.Zero; - int length = 0; + long length = 0; if (!LibSameboy.sameboy_getmemoryarea(SameboyState, which, ref data, ref length)) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs index 1aa822dea8..6487653674 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.cs @@ -39,6 +39,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy private readonly LibSameboy.InputCallback _inputcb; + private readonly LibSameboy.RumbleCallback _rumblecb; + [CoreConstructor(VSystemID.Raw.GB)] [CoreConstructor(VSystemID.Raw.GBC)] public Sameboy(CoreComm comm, GameInfo game, byte[] file, SameboySettings settings, SameboySyncSettings syncSettings, bool deterministic) @@ -90,10 +92,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy InitMemoryCallbacks(); _inputcb = InputCallback; - LibSameboy.sameboy_setinputcallback(SameboyState, _inputcb); + _rumblecb = RumbleCallback; _tracecb = MakeTrace; - LibSameboy.sameboy_settracecallback(SameboyState, null); + LibSameboy.sameboy_setinputcallback(SameboyState, _inputcb); + LibSameboy.sameboy_setrumblecallback(SameboyState, _rumblecb); + + LibSameboy.sameboy_settracecallback(SameboyState, null); LibSameboy.sameboy_setscanlinecallback(SameboyState, null, 0); LibSameboy.sameboy_setprintercallback(SameboyState, null); @@ -112,7 +117,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy BoardName = MapperName(file); _hasAcc = BoardName is "MBC7 ROM+ACCEL+EEPROM"; - ControllerDefinition = Gameboy.Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: _hasAcc); + ControllerDefinition = Gameboy.Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: _hasAcc, rumble: true); LibSameboy.sameboy_setrtcdivisoroffset(SameboyState, _syncSettings.RTCDivisorOffset); CycleCount = 0; @@ -140,6 +145,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy _inputCallbacks.Call(); } + private void RumbleCallback(int amplitude) + { + _controller.SetHapticChannelStrength("Rumble", amplitude); + } + public bool LinkConnected { get => _printercb != null; @@ -187,7 +197,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy var _bgpal = IntPtr.Zero; var _sppal = IntPtr.Zero; var _oam = IntPtr.Zero; - int unused = 0; + long unused = 0; if (!LibSameboy.sameboy_getmemoryarea(SameboyState, LibSameboy.MemoryAreas.VRAM, ref _vram, ref unused) || !LibSameboy.sameboy_getmemoryarea(SameboyState, LibSameboy.MemoryAreas.BGPRGB, ref _bgpal, ref unused) || !LibSameboy.sameboy_getmemoryarea(SameboyState, LibSameboy.MemoryAreas.OBPRGB, ref _sppal, ref unused) diff --git a/submodules/sameboy/BizInterface.c b/submodules/sameboy/BizInterface.c index 30240450fb..4a5002814b 100644 --- a/submodules/sameboy/BizInterface.c +++ b/submodules/sameboy/BizInterface.c @@ -19,6 +19,7 @@ typedef uint32_t u32; typedef uint64_t u64; typedef void (*input_callback_t)(void); +typedef void (*rumble_callback_t)(u32); typedef void (*trace_callback_t)(u16); typedef void (*memory_callback_t)(u16); typedef void (*printer_callback_t)(u32*, u8, u8, u8, u8); @@ -36,6 +37,7 @@ typedef struct u32 obj_pal[0x20]; GB_palette_t custom_pal; input_callback_t input_cb; + rumble_callback_t rumble_cb; trace_callback_t trace_cb; memory_callback_t read_cb; memory_callback_t write_cb; @@ -77,17 +79,22 @@ static u32 rgb_cb(GB_gameboy_t *gb, u8 r, u8 g, u8 b) return (0xFF << 24) | (r << 16) | (g << 8) | b; } -static void vblank_cb(GB_gameboy_t *gb, GB_vblank_type_t type) +static void vblank_cb(GB_gameboy_t* gb, GB_vblank_type_t type) { ((biz_t*)gb)->vblank_occured = true; } -static u8 camera_pixel_cb(GB_gameboy_t *gb, u8 x, u8 y) +static u8 camera_pixel_cb(GB_gameboy_t* gb, u8 x, u8 y) { // stub for now (also needed for determinism) return 0; } +static void RumbleCallbackRelay(GB_gameboy_t* gb, double rumble_amplitude) +{ + ((biz_t*)gb)->rumble_cb(INT32_MAX * rumble_amplitude); +} + static u8 ReadCallbackRelay(GB_gameboy_t* gb, u16 addr, u8 data) { ((biz_t*)gb)->read_cb(addr); @@ -135,6 +142,8 @@ EXPORT biz_t* sameboy_create(u8* romdata, u32 romlen, u8* biosdata, u32 bioslen, GB_load_rom_from_buffer(&biz->gb, romdata, romlen); GB_load_boot_rom_from_buffer(&biz->gb, biosdata, bioslen); GB_set_sample_rate(&biz->gb, GB_get_clock_rate(&biz->gb) / 2 / 8); + GB_set_rumble_mode(&biz->gb, GB_RUMBLE_ALL_GAMES); + GB_set_rumble_callback(&biz->gb, RumbleCallbackRelay); GB_apu_set_sample_callback(&biz->gb, sample_cb); GB_set_rgb_encode_callback(&biz->gb, rgb_cb); GB_set_vblank_callback(&biz->gb, vblank_cb); @@ -163,6 +172,11 @@ EXPORT void sameboy_setinputcallback(biz_t* biz, input_callback_t callback) biz->input_cb = callback; } +EXPORT void sameboy_setrumblecallback(biz_t* biz, rumble_callback_t callback) +{ + biz->rumble_cb = callback; +} + static double FromRawToG(u16 raw) { return (raw - 0x81D0) / (0x70 * 1.0);