From 40669f4dc963b7f7bb49112c243b3a23989dc1a5 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Tue, 22 Feb 2022 01:12:15 -0800 Subject: [PATCH] Add initial rumble support, use modified SDL branch to support all GC controller rumble modes --- Runtime/Input/CFinalInput.hpp | 9 ++-- Runtime/Input/CInputGenerator.cpp | 15 ++++++- Runtime/Input/CInputGenerator.hpp | 8 ++-- aurora/include/aurora/aurora.hpp | 2 + aurora/lib/aurora.cpp | 18 ++++---- aurora/lib/input.cpp | 74 +++++++++++++++++++------------ aurora/lib/input.hpp | 29 ++++++------ extern/SDL | 2 +- 8 files changed, 99 insertions(+), 58 deletions(-) diff --git a/Runtime/Input/CFinalInput.hpp b/Runtime/Input/CFinalInput.hpp index 9e3c82d18..dc4e32d09 100644 --- a/Runtime/Input/CFinalInput.hpp +++ b/Runtime/Input/CFinalInput.hpp @@ -10,11 +10,13 @@ namespace metaforce { struct SAuroraControllerState { u32 m_which = -1; bool m_isGamecube = false; + bool m_hasRumble = false; std::array m_axes{}; std::bitset m_btns{}; SAuroraControllerState() = default; - SAuroraControllerState(uint32_t which, bool isGamecube) : m_which(which), m_isGamecube(isGamecube) {} + SAuroraControllerState(uint32_t which, bool isGamecube, bool hasRumble) + : m_which(which), m_isGamecube(isGamecube), m_hasRumble(hasRumble) {} void clamp(); }; @@ -82,8 +84,9 @@ struct CFinalInput { u32 m_which = -1; CFinalInput(); -// CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& data, const CFinalInput& prevInput, float leftDiv, -// float rightDiv); + // CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& data, const CFinalInput& prevInput, float + // leftDiv, + // float rightDiv); CFinalInput(int cIdx, float dt, const SAuroraControllerState& data, const CFinalInput& prevInput, float leftDiv, float rightDiv); CFinalInput(int cIdx, float dt, const CKeyboardMouseControllerData& data, const CFinalInput& prevInput); diff --git a/Runtime/Input/CInputGenerator.cpp b/Runtime/Input/CInputGenerator.cpp index 97daf6713..0dea298c7 100644 --- a/Runtime/Input/CInputGenerator.cpp +++ b/Runtime/Input/CInputGenerator.cpp @@ -45,7 +45,8 @@ void CInputGenerator::controllerAdded(uint32_t which) noexcept { aurora::set_controller_player_index(which, 0); } - m_state[player] = SAuroraControllerState(which, aurora::is_controller_gamecube(which)); + m_state[player] = + SAuroraControllerState(which, aurora::is_controller_gamecube(which), aurora::controller_has_rumble(which)); } void CInputGenerator::controllerRemoved(uint32_t which) noexcept { @@ -93,6 +94,18 @@ void CInputGenerator::controllerAxis(uint32_t which, aurora::ControllerAxis axis m_state[player].m_axes[size_t(axis)] = value; } +void CInputGenerator::SetMotorState(EIOPort port, EMotorState state) { + if (m_state[size_t(port)].m_hasRumble && m_state[size_t(port)].m_isGamecube) { + if (state == EMotorState::Rumble) { + aurora::controller_rumble(m_state[size_t(port)].m_which, 1, 1); + } else if (state == EMotorState::Stop) { + aurora::controller_rumble(m_state[size_t(port)].m_which, 0, 1); + } else if (state == EMotorState::StopHard) { + aurora::controller_rumble(m_state[size_t(port)].m_which, 0, 0); + } + } // TODO: Figure out good intensity values for generic controllers with rumble, support HAPTIC? +} + const CFinalInput& CInputGenerator::getFinalInput(unsigned int idx, float dt) { auto input = CFinalInput(idx, dt, m_data, m_lastUpdate); // Merge controller input with kb/m input diff --git a/Runtime/Input/CInputGenerator.hpp b/Runtime/Input/CInputGenerator.hpp index 4c7afb07f..651ed6da9 100644 --- a/Runtime/Input/CInputGenerator.hpp +++ b/Runtime/Input/CInputGenerator.hpp @@ -152,11 +152,11 @@ public: // if (smashAdapter.get() == device) // smashAdapter.reset(); // } - void SetMotorState(EIOPort port, EMotorState state) { - // TODO aurora - } + void SetMotorState(EIOPort port, EMotorState state); void ControlAllMotors(const std::array& states) { - // TODO aurora + for (u32 i = 0; i <= size_t(EIOPort::Three); ++i ) { + SetMotorState(EIOPort(i), states[i]); + } } /* This is where the game thread enters */ diff --git a/aurora/include/aurora/aurora.hpp b/aurora/include/aurora/aurora.hpp index 5c94aa013..b41970b68 100644 --- a/aurora/include/aurora/aurora.hpp +++ b/aurora/include/aurora/aurora.hpp @@ -247,5 +247,7 @@ void set_fullscreen(bool fullscreen) noexcept; [[nodiscard]] int32_t get_controller_player_index(uint32_t which) noexcept; void set_controller_player_index(uint32_t which, int32_t index) noexcept; [[nodiscard]] bool is_controller_gamecube(uint32_t which) noexcept; +[[nodiscard]] bool controller_has_rumble(uint32_t which) noexcept; +void controller_rumble(uint32_t which, uint16_t low_freq_intensity, uint16_t high_freq_intensity, uint32_t duration_ms = 0) noexcept; [[nodiscard]] std::string get_controller_name(uint32_t which) noexcept; } // namespace aurora diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index f2cedfb76..2b08afcc3 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -393,17 +393,19 @@ void set_fullscreen(bool fullscreen) noexcept { SDL_SetWindowFullscreen(g_Window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0); } -int32_t get_controller_player_index(uint32_t which) noexcept { - return input::player_index(which); +int32_t get_controller_player_index(uint32_t instance) noexcept { return input::player_index(instance); } + +void set_controller_player_index(uint32_t instance, int32_t index) noexcept { + input::set_player_index(instance, index); } -void set_controller_player_index(uint32_t which, int32_t index) noexcept { input::set_player_index(which, index); } +bool is_controller_gamecube(uint32_t instance) noexcept { return input::is_gamecube(instance); } -bool is_controller_gamecube(uint32_t which) noexcept { - return input::is_gamecube(which); -} +bool controller_has_rumble(uint32_t instance) noexcept { return input::controller_has_rumble(instance); } -std::string get_controller_name(uint32_t instance) noexcept { - return input::controller_name(instance); +void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t high_freq_intensity, + uint32_t duration_ms) noexcept { + input::controller_rumble(instance, low_freq_intensity, high_freq_intensity, duration_ms); } +std::string get_controller_name(uint32_t instance) noexcept { return input::controller_name(instance); } } // namespace aurora diff --git a/aurora/lib/input.cpp b/aurora/lib/input.cpp index 8a1369d39..7b626c9e7 100644 --- a/aurora/lib/input.cpp +++ b/aurora/lib/input.cpp @@ -1,14 +1,16 @@ #include "input.hpp" +#include namespace aurora::input { struct GameController { - SDL_GameController* m_controller; + SDL_GameController* m_controller = nullptr; bool m_isGameCube = false; - Sint32 m_index; + Sint32 m_index = -1; + bool m_hasRumble = false; }; std::unordered_map g_GameControllers; -Sint32 add_controller(Uint32 which) { +Sint32 add_controller(Sint32 which) noexcept { auto* ctrl = SDL_GameControllerOpen(which); if (ctrl != nullptr) { GameController controller; @@ -16,7 +18,7 @@ Sint32 add_controller(Uint32 which) { controller.m_index = which; controller.m_isGameCube = SDL_GameControllerGetVendor(ctrl) == 0x057E && SDL_GameControllerGetProduct(ctrl) == 0x0337; - + controller.m_hasRumble = (SDL_GameControllerHasRumble(ctrl) != 0u); Sint32 instance = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ctrl)); g_GameControllers[instance] = controller; return instance; @@ -25,44 +27,60 @@ Sint32 add_controller(Uint32 which) { return -1; } -void remove_controller(Uint32 which) { - if (g_GameControllers.find(which) != g_GameControllers.end()) { - SDL_GameControllerClose(g_GameControllers[which].m_controller); - g_GameControllers.erase(which); +void remove_controller(Uint32 instance) noexcept { + if (g_GameControllers.find(instance) != g_GameControllers.end()) { + SDL_GameControllerClose(g_GameControllers[instance].m_controller); + g_GameControllers.erase(instance); } } -bool is_gamecube(Uint32 which) { - if (g_GameControllers.find(which) != g_GameControllers.end()) { - return g_GameControllers[which].m_isGameCube; +bool is_gamecube(Uint32 instance) noexcept { + if (g_GameControllers.find(instance) != g_GameControllers.end()) { + return g_GameControllers[instance].m_isGameCube; } return false; } -int32_t player_index(Uint32 which) { - if (g_GameControllers.find(which) != g_GameControllers.end()) { - return SDL_GameControllerGetPlayerIndex(g_GameControllers[which].m_controller); +int32_t player_index(Uint32 instance) noexcept { + if (g_GameControllers.find(instance) != g_GameControllers.end()) { + return SDL_GameControllerGetPlayerIndex(g_GameControllers[instance].m_controller); } return -1; } -void set_player_index(Uint32 which, Sint32 index) { - if (g_GameControllers.find(which) != g_GameControllers.end()) { - SDL_GameControllerSetPlayerIndex(g_GameControllers[which].m_controller, index); +void set_player_index(Uint32 instance, Sint32 index) noexcept { + if (g_GameControllers.find(instance) != g_GameControllers.end()) { + SDL_GameControllerSetPlayerIndex(g_GameControllers[instance].m_controller, index); } } -std::string controller_name(Uint32 which) { - if (g_GameControllers.find(which) != g_GameControllers.end()) { - auto* name = SDL_GameControllerName(g_GameControllers[which].m_controller); - if (name) { - return std::string(name); +std::string controller_name(Uint32 instance) noexcept { + if (g_GameControllers.find(instance) != g_GameControllers.end()) { + const auto* name = SDL_GameControllerName(g_GameControllers[instance].m_controller); + if (name != nullptr) { + return {name}; } } return {}; } -ControllerButton translate_controller_button(SDL_GameControllerButton btn) { +bool controller_has_rumble(Uint32 instance) noexcept { + if (g_GameControllers.find(instance) != g_GameControllers.end()) { + return g_GameControllers[instance].m_hasRumble; + } + + return false; +} + +void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t high_freq_intensity, + uint16_t duration_ms) noexcept { + + if (g_GameControllers.find(instance) != g_GameControllers.end()) { + SDL_GameControllerRumble(g_GameControllers[instance].m_controller, low_freq_intensity, high_freq_intensity, + duration_ms); + } +} +ControllerButton translate_controller_button(SDL_GameControllerButton btn) noexcept { switch (btn) { case SDL_CONTROLLER_BUTTON_A: return ControllerButton::A; @@ -99,7 +117,7 @@ ControllerButton translate_controller_button(SDL_GameControllerButton btn) { } } -ControllerAxis translate_controller_axis(SDL_GameControllerAxis axis) { +ControllerAxis translate_controller_axis(SDL_GameControllerAxis axis) noexcept { switch (axis) { case SDL_CONTROLLER_AXIS_LEFTX: return ControllerAxis::LeftX; @@ -118,7 +136,7 @@ ControllerAxis translate_controller_axis(SDL_GameControllerAxis axis) { } } -char translate_key(SDL_Keysym sym, SpecialKey& specialSym, ModifierKey& modifierSym) { +char translate_key(SDL_Keysym sym, SpecialKey& specialSym, ModifierKey& modifierSym) noexcept { specialSym = SpecialKey::None; modifierSym = ModifierKey::None; if (sym.sym >= SDLK_F1 && sym.sym <= SDLK_F12) { @@ -171,7 +189,7 @@ char translate_key(SDL_Keysym sym, SpecialKey& specialSym, ModifierKey& modifier return 0; } -ModifierKey translate_modifiers(Uint16 mods) { +ModifierKey translate_modifiers(Uint16 mods) noexcept { ModifierKey ret = ModifierKey::None; if ((mods & SDLK_LSHIFT) != 0) { ret |= ModifierKey::LeftShift; @@ -195,7 +213,7 @@ ModifierKey translate_modifiers(Uint16 mods) { return ret; } -MouseButton translate_mouse_button(Uint8 button) { +MouseButton translate_mouse_button(Uint8 button) noexcept { if (button == 1) { return MouseButton::Primary; } @@ -215,7 +233,7 @@ MouseButton translate_mouse_button(Uint8 button) { return MouseButton::None; } -MouseButton translate_mouse_button_state(Uint8 state) { +MouseButton translate_mouse_button_state(Uint8 state) noexcept { auto ret = MouseButton::None; if ((state & 0x01) != 0) { ret |= MouseButton::Primary; diff --git a/aurora/lib/input.hpp b/aurora/lib/input.hpp index 1a2a61937..1a52d0f99 100644 --- a/aurora/lib/input.hpp +++ b/aurora/lib/input.hpp @@ -7,16 +7,19 @@ #include "SDL_keycode.h" #include "SDL_mouse.h" namespace aurora::input { -Sint32 add_controller(Uint32 which); -void remove_controller(Uint32 which); -Sint32 player_index(Uint32 which); -void set_player_index(Uint32 which, Sint32 index); -std::string controller_name(Uint32 which); -bool is_gamecube(Uint32 which); -ControllerButton translate_controller_button(SDL_GameControllerButton button); -ControllerAxis translate_controller_axis(SDL_GameControllerAxis axis); -char translate_key(SDL_Keysym sym, SpecialKey& specialSym, ModifierKey& modifierSym); -ModifierKey translate_modifiers(Uint16 mods); -MouseButton translate_mouse_button(Uint8 button); -MouseButton translate_mouse_button_state(Uint8 state); -} \ No newline at end of file +Sint32 add_controller(Sint32 which) noexcept; +void remove_controller(Uint32 instance) noexcept; +Sint32 player_index(Uint32 instance) noexcept; +void set_player_index(Uint32 instance, Sint32 index) noexcept; +std::string controller_name(Uint32 instance) noexcept; +bool is_gamecube(Uint32 instance) noexcept; +bool controller_has_rumble(Uint32 instance) noexcept; +void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t high_freq_intensity, + uint16_t duration_ms) noexcept; +ControllerButton translate_controller_button(SDL_GameControllerButton button) noexcept; +ControllerAxis translate_controller_axis(SDL_GameControllerAxis axis) noexcept; +char translate_key(SDL_Keysym sym, SpecialKey& specialSym, ModifierKey& modifierSym) noexcept; +ModifierKey translate_modifiers(Uint16 mods) noexcept; +MouseButton translate_mouse_button(Uint8 button) noexcept; +MouseButton translate_mouse_button_state(Uint8 state) noexcept; +} // namespace aurora::input \ No newline at end of file diff --git a/extern/SDL b/extern/SDL index 53091e36a..b1fafe65d 160000 --- a/extern/SDL +++ b/extern/SDL @@ -1 +1 @@ -Subproject commit 53091e36a3b418e33133bae2f018954c006f86b8 +Subproject commit b1fafe65d63a947d262e750afccbc6eee28cace1