From 593642ff5707a2b1e93b5fe51adaaf50ae02c1e7 Mon Sep 17 00:00:00 2001 From: Adrian Siekierka Date: Wed, 30 Oct 2024 22:50:07 +0100 Subject: [PATCH] Add retail Motion Pak emulation, Guitar Grip emulation --- src/GBACart.cpp | 31 ++++++- src/GBACart.h | 50 ++++++++++-- src/GBACartMotionPak.cpp | 80 +++++++++++++++++-- src/NDS.h | 4 +- src/Platform.h | 12 +++ src/frontend/qt_sdl/Config.cpp | 8 ++ src/frontend/qt_sdl/EmuInstance.cpp | 8 +- src/frontend/qt_sdl/EmuInstance.h | 6 ++ src/frontend/qt_sdl/EmuInstanceInput.cpp | 7 +- .../qt_sdl/InputConfig/InputConfigDialog.h | 8 ++ src/frontend/qt_sdl/Platform.cpp | 12 +++ src/frontend/qt_sdl/Window.cpp | 9 ++- 12 files changed, 214 insertions(+), 21 deletions(-) diff --git a/src/GBACart.cpp b/src/GBACart.cpp index 0bfb7358..5e0a261a 100644 --- a/src/GBACart.cpp +++ b/src/GBACart.cpp @@ -724,6 +724,27 @@ void CartRumblePak::ROMWrite(u32 addr, u16 val) } } +CartGuitarGrip::CartGuitarGrip(void* userdata) : + CartCommon(GuitarGrip), + UserData(userdata) +{ +} + +CartGuitarGrip::~CartGuitarGrip() = default; + +u16 CartGuitarGrip::ROMRead(u32 addr) const +{ + return 0xF9FF; +} + +u8 CartGuitarGrip::SRAMRead(u32 addr) +{ + return ~((Platform::Addon_KeyDown(Platform::KeyGuitarGripGreen, UserData) ? 0x40 : 0) + | (Platform::Addon_KeyDown(Platform::KeyGuitarGripRed, UserData) ? 0x20 : 0) + | (Platform::Addon_KeyDown(Platform::KeyGuitarGripYellow, UserData) ? 0x10 : 0) + | (Platform::Addon_KeyDown(Platform::KeyGuitarGripBlue, UserData) ? 0x08 : 0)); +} + GBACartSlot::GBACartSlot(melonDS::NDS& nds, std::unique_ptr&& cart) noexcept : NDS(nds), Cart(std::move(cart)) { } @@ -874,8 +895,14 @@ void GBACartSlot::LoadAddon(void* userdata, int type) noexcept case GBAAddon_RumblePak: Cart = std::make_unique(userdata); break; - case GBAAddon_MotionPak: - Cart = std::make_unique(userdata); + case GBAAddon_MotionPakHomebrew: + Cart = std::make_unique(userdata); + break; + case GBAAddon_MotionPakRetail: + Cart = std::make_unique(userdata); + break; + case GBAAddon_GuitarGrip: + Cart = std::make_unique(userdata); break; default: diff --git a/src/GBACart.h b/src/GBACart.h index 26ec4d06..9ab42f1a 100644 --- a/src/GBACart.h +++ b/src/GBACart.h @@ -33,7 +33,9 @@ enum CartType GameSolarSensor = 0x102, RAMExpansion = 0x201, RumblePak = 0x202, - MotionPak = 0x203, + MotionPakHomebrew = 0x203, + MotionPakRetail = 0x204, + GuitarGrip = 0x205, }; // CartCommon -- base code shared by all cart types @@ -212,12 +214,26 @@ private: u16 RumbleState = 0; }; -// CartMotionPak -- DS Motion Pak (Kionix/homebrew) -class CartMotionPak : public CartCommon +// CartGuitarGrip -- DS Guitar Grip (used in various NDS games) +class CartGuitarGrip : public CartCommon { public: - CartMotionPak(void* userdata); - ~CartMotionPak() override; + CartGuitarGrip(void* userdata); + ~CartGuitarGrip() override; + + u16 ROMRead(u32 addr) const override; + u8 SRAMRead(u32 addr) override; + +private: + void* UserData; +}; + +// CartMotionPakHomebrew -- DS Motion Pak (Homebrew) +class CartMotionPakHomebrew : public CartCommon +{ +public: + CartMotionPakHomebrew(void* userdata); + ~CartMotionPakHomebrew() override; void Reset() override; @@ -231,11 +247,35 @@ private: u16 ShiftVal = 0; }; +// CartMotionPakRetail -- DS Motion Pack (Retail) +class CartMotionPakRetail : public CartCommon +{ +public: + CartMotionPakRetail(void* userdata); + ~CartMotionPakRetail() override; + + void Reset() override; + + void DoSavestate(Savestate* file) override; + + u16 ROMRead(u32 addr) const override; + u8 SRAMRead(u32 addr) override; + +private: + void* UserData; + u8 Value; + u8 Step = 16; +}; + // possible inputs for GBA carts that might accept user input enum { Input_SolarSensorDown = 0, Input_SolarSensorUp, + Input_GuitarGripGreen, + Input_GuitarGripRed, + Input_GuitarGripYellow, + Input_GuitarGripBlue, }; class GBACartSlot diff --git a/src/GBACartMotionPak.cpp b/src/GBACartMotionPak.cpp index 7d3e17a4..9d564622 100644 --- a/src/GBACartMotionPak.cpp +++ b/src/GBACartMotionPak.cpp @@ -31,28 +31,28 @@ using Platform::LogLevel; namespace GBACart { -CartMotionPak::CartMotionPak(void* userdata) : - CartCommon(MotionPak), +CartMotionPakHomebrew::CartMotionPakHomebrew(void* userdata) : + CartCommon(MotionPakHomebrew), UserData(userdata) { } -CartMotionPak::~CartMotionPak() = default; +CartMotionPakHomebrew::~CartMotionPakHomebrew() = default; -void CartMotionPak::Reset() +void CartMotionPakHomebrew::Reset() { ShiftVal = 0; } -void CartMotionPak::DoSavestate(Savestate* file) +void CartMotionPakHomebrew::DoSavestate(Savestate* file) { CartCommon::DoSavestate(file); file->Var16(&ShiftVal); } -u16 CartMotionPak::ROMRead(u32 addr) const +u16 CartMotionPakHomebrew::ROMRead(u32 addr) const { - // CHECKME: Does this apply to the Kionix/homebrew cart as well? + // CHECKME: Does this apply to the homebrew cart as well? return 0xFCFF; } @@ -80,7 +80,7 @@ static int RotationToMotionPak(float rot) ); } -u8 CartMotionPak::SRAMRead(u32 addr) +u8 CartMotionPakHomebrew::SRAMRead(u32 addr) { // CHECKME: SRAM address mask addr &= 0xFFFF; @@ -129,6 +129,70 @@ u8 CartMotionPak::SRAMRead(u32 addr) return val; } +static int AccelerationToMotionPakRetail(float accel) +{ + // Formula provided by xperia64 (melonDS/#74) + const float GRAVITY_M_S2 = 9.80665f; + const float VOLTAGE = 3.3f; + + return std::clamp( + (int) ((accel * (VOLTAGE / 5) / GRAVITY_M_S2 + (VOLTAGE / 2)) * 256 / VOLTAGE), + 0, 254 + ); +} + +CartMotionPakRetail::CartMotionPakRetail(void* userdata) : + CartCommon(MotionPakRetail), + UserData(userdata) +{ +} + +CartMotionPakRetail::~CartMotionPakRetail() = default; + +void CartMotionPakRetail::Reset() +{ + Value = 0; + Step = 16; +} + +void CartMotionPakRetail::DoSavestate(Savestate* file) +{ + CartCommon::DoSavestate(file); + file->Var8(&Value); + file->Var8(&Step); +} + +u16 CartMotionPakRetail::ROMRead(u32 addr) const +{ + return 0xFCFF; +} + +u8 CartMotionPakRetail::SRAMRead(u32 addr) +{ + switch (Step) + { + case 0: // Synchronization - read 0xFF + Value = 0xFF; + break; + case 4: // X acceleration + Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationX, UserData)); + break; + case 8: // Y acceleration + Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationY, UserData)); + break; + case 12: // Z acceleration + Value = AccelerationToMotionPakRetail(Platform::Addon_MotionQuery(Platform::MotionAccelerationZ, UserData)); + break; + case 16: // Synchronization - read 0b00 + Step = 0; + return 0; + } + + int shift = 6 - ((Step & 3) * 2); + Step++; + return (Value >> shift) & 0x03; +} + } } diff --git a/src/NDS.h b/src/NDS.h index 218a33b2..3dfed01d 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -211,7 +211,9 @@ enum { GBAAddon_RAMExpansion = 1, GBAAddon_RumblePak = 2, - GBAAddon_MotionPak = 3, + GBAAddon_MotionPakHomebrew = 3, + GBAAddon_MotionPakRetail = 4, + GBAAddon_GuitarGrip = 5, }; class SPU; diff --git a/src/Platform.h b/src/Platform.h index ee714378..d7108b20 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -322,6 +322,18 @@ void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, v // interface for addon inputs +enum KeyType +{ + KeyGuitarGripGreen, + KeyGuitarGripRed, + KeyGuitarGripYellow, + KeyGuitarGripBlue, +}; + +// Check if a given key is being pressed. +// @param type The type of the key to check. +bool Addon_KeyDown(KeyType type, void* userdata); + // Called by the DS Rumble Pak emulation to start the necessary // rumble effects on the connected game controller, if available. // @param len The duration of the controller rumble effect in milliseconds. diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp index 02be5b65..90eb6a6c 100644 --- a/src/frontend/qt_sdl/Config.cpp +++ b/src/frontend/qt_sdl/Config.cpp @@ -169,6 +169,10 @@ LegacyEntry LegacyFile[] = {"HKKey_PowerButton", 0, "Keyboard.HK_PowerButton", true}, {"HKKey_VolumeUp", 0, "Keyboard.HK_VolumeUp", true}, {"HKKey_VolumeDown", 0, "Keyboard.HK_VolumeDown", true}, + {"HKKey_GuitarGripGreen", 0, "Keyboard.HK_GuitarGripGreen", true}, + {"HKKey_GuitarGripRed", 0, "Keyboard.HK_GuitarGripRed", true}, + {"HKKey_GuitarGripYellow", 0, "Keyboard.HK_GuitarGripYellow", true}, + {"HKKey_GuitarGripBlue", 0, "Keyboard.HK_GuitarGripBlue", true}, {"HKJoy_Lid", 0, "Joystick.HK_Lid", true}, {"HKJoy_Mic", 0, "Joystick.HK_Mic", true}, @@ -185,6 +189,10 @@ LegacyEntry LegacyFile[] = {"HKJoy_PowerButton", 0, "Joystick.HK_PowerButton", true}, {"HKJoy_VolumeUp", 0, "Joystick.HK_VolumeUp", true}, {"HKJoy_VolumeDown", 0, "Joystick.HK_VolumeDown", true}, + {"HKJoy_GuitarGripGreen", 0, "Joystick.HK_GuitarGripGreen", true}, + {"HKJoy_GuitarGripRed", 0, "Joystick.HK_GuitarGripRed", true}, + {"HKJoy_GuitarGripYellow", 0, "Joystick.HK_GuitarGripYellow", true}, + {"HKJoy_GuitarGripBlue", 0, "Joystick.HK_GuitarGripBlue", true}, {"JoystickID", 0, "JoystickID", true}, diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 3ea44c7c..07a4a41d 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -2090,8 +2090,12 @@ QString EmuInstance::gbaAddonName(int addon) return "Rumble Pak"; case GBAAddon_RAMExpansion: return "Memory expansion"; - case GBAAddon_MotionPak: - return "Motion Pak"; + case GBAAddon_MotionPakHomebrew: + return "Motion Pak (Homebrew)"; + case GBAAddon_MotionPakRetail: + return "Motion Pack (Retail)"; + case GBAAddon_GuitarGrip: + return "Guitar Grip"; } return "???"; diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index e299bdf7..4752eb12 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -51,6 +51,10 @@ enum HK_SlowMo, HK_FastForwardToggle, HK_SlowMoToggle, + HK_GuitarGripGreen, + HK_GuitarGripRed, + HK_GuitarGripYellow, + HK_GuitarGripBlue, HK_MAX }; @@ -143,6 +147,8 @@ public: void inputLoadConfig(); void inputRumbleStart(melonDS::u32 len_ms); void inputRumbleStop(); + + bool inputHotkeyDown(int id) { return hotkeyDown(id); } float inputMotionQuery(melonDS::Platform::MotionQueryType type); void setJoystick(int id); diff --git a/src/frontend/qt_sdl/EmuInstanceInput.cpp b/src/frontend/qt_sdl/EmuInstanceInput.cpp index d76f8a0e..eb47635f 100644 --- a/src/frontend/qt_sdl/EmuInstanceInput.cpp +++ b/src/frontend/qt_sdl/EmuInstanceInput.cpp @@ -62,7 +62,11 @@ const char* EmuInstance::hotkeyNames[HK_MAX] = "HK_VolumeDown", "HK_SlowMo", "HK_FastForwardToggle", - "HK_SlowMoToggle" + "HK_SlowMoToggle", + "HK_GuitarGripGreen", + "HK_GuitarGripRed", + "HK_GuitarGripYellow", + "HK_GuitarGripBlue" }; @@ -208,7 +212,6 @@ void EmuInstance::closeJoystick() hasAccelerometer = false; hasGyroscope = false; } - if (joystick) { SDL_JoystickClose(joystick); diff --git a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h index 3337228f..5f016b5b 100644 --- a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h +++ b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h @@ -32,12 +32,20 @@ static constexpr std::initializer_list hk_addons = { HK_SolarSensorIncrease, HK_SolarSensorDecrease, + HK_GuitarGripGreen, + HK_GuitarGripRed, + HK_GuitarGripYellow, + HK_GuitarGripBlue, }; static constexpr std::initializer_list hk_addons_labels = { "[Boktai] Sunlight + ", "[Boktai] Sunlight - ", + "[Guitar Grip] Green", + "[Guitar Grip] Red", + "[Guitar Grip] Yellow", + "[Guitar Grip] Blue", }; static_assert(hk_addons.size() == hk_addons_labels.size()); diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 5a912f13..f7f44d1e 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -550,6 +550,18 @@ void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv, v return camManager[num]->captureFrame(frame, width, height, yuv); } +static const int hotkeyMap[] = { + HK_GuitarGripGreen, + HK_GuitarGripRed, + HK_GuitarGripYellow, + HK_GuitarGripBlue, +}; + +bool Addon_KeyDown(KeyType type, void* userdata) +{ + return ((EmuInstance*)userdata)->inputHotkeyDown(hotkeyMap[type]); +} + void Addon_RumbleStart(u32 len, void* userdata) { ((EmuInstance*)userdata)->inputRumbleStart(len); diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 4a80ad90..f90cad3d 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -320,7 +320,14 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : QMenu * submenu = menu->addMenu("Insert add-on cart"); QAction *act; - int addons[] = {GBAAddon_RAMExpansion, GBAAddon_RumblePak, GBAAddon_MotionPak, -1}; + int addons[] = { + GBAAddon_RAMExpansion, + GBAAddon_RumblePak, + GBAAddon_MotionPakHomebrew, + GBAAddon_MotionPakRetail, + GBAAddon_GuitarGrip, + -1 + }; for (int i = 0; addons[i] != -1; i++) { int addon = addons[i];