From 42dde9187bd572616ee8f033ebe9608bf1665815 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Tue, 22 Mar 2022 12:04:57 -0700 Subject: [PATCH] Migrate to new CInputGenerator and rename old --- Runtime/CMain.cpp | 10 +- Runtime/GameGlobalObjects.cpp | 1 + Runtime/GameGlobalObjects.hpp | 1 + Runtime/Input/CInputGenerator.cpp | 163 ++++++----------------- Runtime/Input/CInputGenerator.cpp.old | 131 +++++++++++++++++++ Runtime/Input/CInputGenerator.hpp | 178 ++++---------------------- Runtime/Input/CInputGenerator.hpp.old | 162 +++++++++++++++++++++++ Runtime/Input/CMakeLists.txt | 1 - Runtime/Input/CRumbleGenerator.cpp | 16 ++- Runtime/Input/NewCInputGenerator.cpp | 40 ------ Runtime/Input/NewCInputGenerator.hpp | 32 ----- Runtime/MP1/CInGameGuiManager.cpp | 3 +- Runtime/MP1/MP1.cpp | 13 +- Runtime/MP1/MP1.hpp | 28 ++-- aurora/lib/input.cpp | 10 +- 15 files changed, 406 insertions(+), 383 deletions(-) create mode 100644 Runtime/Input/CInputGenerator.cpp.old create mode 100644 Runtime/Input/CInputGenerator.hpp.old delete mode 100644 Runtime/Input/NewCInputGenerator.cpp delete mode 100644 Runtime/Input/NewCInputGenerator.hpp diff --git a/Runtime/CMain.cpp b/Runtime/CMain.cpp index 2d5edc62c..7fd0a5994 100644 --- a/Runtime/CMain.cpp +++ b/Runtime/CMain.cpp @@ -316,7 +316,7 @@ public: if (auto* input = g_InputGenerator) { if (!m_deferredControllers.empty()) { for (const auto which : m_deferredControllers) { - input->controllerAdded(which); + //input->controllerAdded(which); } m_deferredControllers.clear(); } @@ -432,19 +432,19 @@ public: void onControllerButton(uint32_t idx, aurora::ControllerButton button, bool pressed) noexcept override { if (auto* input = g_InputGenerator) { - input->controllerButton(idx, button, pressed); + //input->controllerButton(idx, button, pressed); } } void onControllerAxis(uint32_t idx, aurora::ControllerAxis axis, int16_t value) noexcept override { if (auto* input = g_InputGenerator) { - input->controllerAxis(idx, axis, value); + //input->controllerAxis(idx, axis, value); } } void onControllerAdded(uint32_t which) noexcept override { if (auto* input = g_InputGenerator) { - input->controllerAdded(which); + //input->controllerAdded(which); } else { m_deferredControllers.emplace_back(which); } @@ -452,7 +452,7 @@ public: void onControllerRemoved(uint32_t which) noexcept override { if (auto* input = g_InputGenerator) { - input->controllerRemoved(which); + //input->controllerRemoved(which); } } diff --git a/Runtime/GameGlobalObjects.cpp b/Runtime/GameGlobalObjects.cpp index d95ff730b..597b23a91 100644 --- a/Runtime/GameGlobalObjects.cpp +++ b/Runtime/GameGlobalObjects.cpp @@ -17,6 +17,7 @@ class CCubeRenderer* g_Renderer = nullptr; class CStringTable* g_MainStringTable = nullptr; class CTextureCache* g_TextureCache = nullptr; class CInputGenerator* g_InputGenerator = nullptr; +class IController* g_Controller = nullptr; class CStateManager* g_StateManager = nullptr; ITweakGame* g_tweakGame = nullptr; diff --git a/Runtime/GameGlobalObjects.hpp b/Runtime/GameGlobalObjects.hpp index 918b3c4a1..a861c8abc 100644 --- a/Runtime/GameGlobalObjects.hpp +++ b/Runtime/GameGlobalObjects.hpp @@ -54,6 +54,7 @@ extern class CCubeRenderer* g_Renderer; extern class CStringTable* g_MainStringTable; extern class CTextureCache* g_TextureCache; extern class CInputGenerator* g_InputGenerator; +extern class IController* g_Controller; extern class CStateManager* g_StateManager; #if USE_DOWNCAST_TWEAKS diff --git a/Runtime/Input/CInputGenerator.cpp b/Runtime/Input/CInputGenerator.cpp index a1c0dd047..4da3c51b6 100644 --- a/Runtime/Input/CInputGenerator.cpp +++ b/Runtime/Input/CInputGenerator.cpp @@ -1,131 +1,52 @@ #include "Runtime/Input/CInputGenerator.hpp" -#include "Runtime/CArchitectureMessage.hpp" +#include "Runtime/Input/IController.hpp" +#include "Runtime/Input/CFinalInput.hpp" + #include "Runtime/CArchitectureQueue.hpp" -#include - namespace metaforce { -static logvisor::Module Log("CInputGenerator"); +CInputGenerator::CInputGenerator(/*COsContext& context, */ float leftDiv, float rightDiv) +/*: x0_context(context) */ { + x4_controller.reset(IController::Create()); + xc_leftDiv = leftDiv; + x10_rightDiv = rightDiv; +} void CInputGenerator::Update(float dt, CArchitectureQueue& queue) { - if (m_firstFrame) { - m_firstFrame = false; - return; - } - - const CFinalInput& kbInput = getFinalInput(0, dt); - queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, kbInput)); - - /* Dolphin controllers next */ - // for (int i = 0; i < 4; ++i) { - // bool connected; - // EStatusChange change = m_dolphinCb.getStatusChange(i, connected); - // if (change != EStatusChange::NoChange) - // queue.Push(MakeMsg::CreateControllerStatus(EArchMsgTarget::Game, i, connected)); - // if (connected) { - // CFinalInput input = m_dolphinCb.getFinalInput(i, dt, m_leftDiv, m_rightDiv); - // if (i == 0) /* Merge KB input with first controller */ - // { - // input |= kbInput; - // kbUsed = true; - // } - // m_lastUpdate = input; - // queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, input)); - // } - // } - - // /* Send straight keyboard input if no first controller present */ - // if (!kbUsed) { - // m_lastUpdate = kbInput; - // } -} - -void CInputGenerator::controllerAdded(uint32_t which) noexcept { - s32 player = aurora::get_controller_player_index(which); - if (player < 0) { - player = 0; - aurora::set_controller_player_index(which, 0); - } - - if (m_state[player].m_hasRumble && m_state[player].m_isGamecube) { - /* The GameCube controller can get stuck in a state where it's always rumbling if the game crashes - * (this can actually happen on hardware in certain cases) - * so lets toggle the motors to ensure they're off, this happens so quickly the player doesn't notice - */ - aurora::controller_rumble(which, 1, 1); - aurora::controller_rumble(which, 0, 0); - } - m_state[player] = - SAuroraControllerState(which, aurora::is_controller_gamecube(which), aurora::controller_has_rumble(which)); -} - -void CInputGenerator::controllerRemoved(uint32_t which) noexcept { - auto it = std::find_if(m_state.begin(), m_state.end(), [&which](const auto& s) { return s.m_which == which; }); - if (it == m_state.end()) { - return; - } - - (*it) = SAuroraControllerState(); -} - -void CInputGenerator::controllerButton(uint32_t which, aurora::ControllerButton button, bool pressed) noexcept { - s32 player = aurora::get_controller_player_index(which); - if (player < 0) { - return; - } - m_state[player].m_btns.set(size_t(button), pressed); -} - -void CInputGenerator::controllerAxis(uint32_t which, aurora::ControllerAxis axis, int16_t value) noexcept { - s32 player = aurora::get_controller_player_index(which); - if (player < 0) { - return; - } - - switch (axis) { - case aurora::ControllerAxis::LeftY: - case aurora::ControllerAxis::RightY: - /* Value is inverted compared to what we expect on the Y axis */ - value = int16_t(-(value + 1)); - [[fallthrough]]; - case aurora::ControllerAxis::LeftX: - case aurora::ControllerAxis::RightX: - value /= int16_t(256); - break; - case aurora::ControllerAxis::TriggerLeft: - case aurora::ControllerAxis::TriggerRight: - value /= int16_t(128); - break; - default: - break; - } - - 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) { #if 0 - auto input = CFinalInput(idx, dt, m_data, m_lastUpdate); - // Merge controller input with kb/m input - auto state = m_state[idx]; - state.clamp(); - input |= CFinalInput(idx, dt, state, m_lastUpdate, m_leftDiv, m_rightDiv); - m_lastUpdate = input; + if (!x0_context.Update()) { + return; + } #endif - return m_lastUpdate; -} -} // namespace metaforce + u32 availSlot = 0; + bool firstController = false; + if (x4_controller) { + x4_controller->Poll(); + for (u32 i = 0; i < x4_controller->GetDeviceCount(); ++i) { + auto cont = x4_controller->GetGamepadData(i); + if (cont.DeviceIsPresent()) { + if (i == 0) { + firstController = true; + } + m_lastInput = CFinalInput(i, dt, cont, xc_leftDiv, x10_rightDiv); + queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, m_lastInput)); + ++availSlot; + } + + if (x8_connectedControllers[i] != cont.DeviceIsPresent()) { + queue.Push(MakeMsg::CreateControllerStatus(EArchMsgTarget::Game, i, cont.DeviceIsPresent())); + x8_connectedControllers[i] = cont.DeviceIsPresent(); + } + } + } +#if 0 + if (firstController) { + queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, CFinalInput(availSlot, dt, x0_osContext))); + } else { + queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, CFinalInput(0, dt, x0_osContext))); + } +#endif +} +} // namespace metaforce::WIP diff --git a/Runtime/Input/CInputGenerator.cpp.old b/Runtime/Input/CInputGenerator.cpp.old new file mode 100644 index 000000000..a1c0dd047 --- /dev/null +++ b/Runtime/Input/CInputGenerator.cpp.old @@ -0,0 +1,131 @@ +#include "Runtime/Input/CInputGenerator.hpp" + +#include "Runtime/CArchitectureMessage.hpp" +#include "Runtime/CArchitectureQueue.hpp" + +#include + +namespace metaforce { +static logvisor::Module Log("CInputGenerator"); + +void CInputGenerator::Update(float dt, CArchitectureQueue& queue) { + if (m_firstFrame) { + m_firstFrame = false; + return; + } + + const CFinalInput& kbInput = getFinalInput(0, dt); + queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, kbInput)); + + /* Dolphin controllers next */ + // for (int i = 0; i < 4; ++i) { + // bool connected; + // EStatusChange change = m_dolphinCb.getStatusChange(i, connected); + // if (change != EStatusChange::NoChange) + // queue.Push(MakeMsg::CreateControllerStatus(EArchMsgTarget::Game, i, connected)); + // if (connected) { + // CFinalInput input = m_dolphinCb.getFinalInput(i, dt, m_leftDiv, m_rightDiv); + // if (i == 0) /* Merge KB input with first controller */ + // { + // input |= kbInput; + // kbUsed = true; + // } + // m_lastUpdate = input; + // queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, input)); + // } + // } + + // /* Send straight keyboard input if no first controller present */ + // if (!kbUsed) { + // m_lastUpdate = kbInput; + // } +} + +void CInputGenerator::controllerAdded(uint32_t which) noexcept { + s32 player = aurora::get_controller_player_index(which); + if (player < 0) { + player = 0; + aurora::set_controller_player_index(which, 0); + } + + if (m_state[player].m_hasRumble && m_state[player].m_isGamecube) { + /* The GameCube controller can get stuck in a state where it's always rumbling if the game crashes + * (this can actually happen on hardware in certain cases) + * so lets toggle the motors to ensure they're off, this happens so quickly the player doesn't notice + */ + aurora::controller_rumble(which, 1, 1); + aurora::controller_rumble(which, 0, 0); + } + m_state[player] = + SAuroraControllerState(which, aurora::is_controller_gamecube(which), aurora::controller_has_rumble(which)); +} + +void CInputGenerator::controllerRemoved(uint32_t which) noexcept { + auto it = std::find_if(m_state.begin(), m_state.end(), [&which](const auto& s) { return s.m_which == which; }); + if (it == m_state.end()) { + return; + } + + (*it) = SAuroraControllerState(); +} + +void CInputGenerator::controllerButton(uint32_t which, aurora::ControllerButton button, bool pressed) noexcept { + s32 player = aurora::get_controller_player_index(which); + if (player < 0) { + return; + } + m_state[player].m_btns.set(size_t(button), pressed); +} + +void CInputGenerator::controllerAxis(uint32_t which, aurora::ControllerAxis axis, int16_t value) noexcept { + s32 player = aurora::get_controller_player_index(which); + if (player < 0) { + return; + } + + switch (axis) { + case aurora::ControllerAxis::LeftY: + case aurora::ControllerAxis::RightY: + /* Value is inverted compared to what we expect on the Y axis */ + value = int16_t(-(value + 1)); + [[fallthrough]]; + case aurora::ControllerAxis::LeftX: + case aurora::ControllerAxis::RightX: + value /= int16_t(256); + break; + case aurora::ControllerAxis::TriggerLeft: + case aurora::ControllerAxis::TriggerRight: + value /= int16_t(128); + break; + default: + break; + } + + 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) { +#if 0 + auto input = CFinalInput(idx, dt, m_data, m_lastUpdate); + // Merge controller input with kb/m input + auto state = m_state[idx]; + state.clamp(); + input |= CFinalInput(idx, dt, state, m_lastUpdate, m_leftDiv, m_rightDiv); + m_lastUpdate = input; +#endif + return m_lastUpdate; +} + +} // namespace metaforce diff --git a/Runtime/Input/CInputGenerator.hpp b/Runtime/Input/CInputGenerator.hpp index be1328dc8..22428d4ed 100644 --- a/Runtime/Input/CInputGenerator.hpp +++ b/Runtime/Input/CInputGenerator.hpp @@ -1,162 +1,32 @@ #pragma once -#include -#include -#include +#include -#include "Runtime/Input/InputTypes.hpp" +#include "Runtime/Input/IController.hpp" #include "Runtime/Input/CFinalInput.hpp" -#include "Runtime/Input/CKeyboardMouseController.hpp" namespace metaforce { -class CArchitectureQueue; - -class CInputGenerator /*: public boo::DeviceFinder*/ { - enum class EStatusChange { NoChange = 0, Connected = 1, Disconnected = 2 }; - - /* When the sticks are used as logical (digital) input, - * these thresholds determine the vector magnitude indicating - * the logical state */ - float m_leftDiv; - float m_rightDiv; - CKeyboardMouseControllerData m_data; - std::array m_state; - - CFinalInput m_lastUpdate; - const CFinalInput& getFinalInput(unsigned idx, float dt); - - bool m_firstFrame = true; - -public: - CInputGenerator(float leftDiv, float rightDiv) - : /*boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}),*/ m_leftDiv(leftDiv), m_rightDiv(rightDiv) {} - -// ~CInputGenerator() override { -// if (smashAdapter) { -// smashAdapter->setCallback(nullptr); -// smashAdapter->closeDevice(); -// } -// } - - void controllerAdded(uint32_t which) noexcept; - - void controllerRemoved(uint32_t which) noexcept; - - void controllerButton(uint32_t which, aurora::ControllerButton button, bool pressed) noexcept; - - void controllerAxis(uint32_t which, aurora::ControllerAxis axis, int16_t value) noexcept; - - - /* Keyboard and mouse events are delivered on the main game - * thread as part of the app's main event loop. The OS is responsible - * for buffering events in its own way, then boo flushes the buffer - * at the start of each frame, invoking these methods. No atomic locking - * is necessary, only absolute state tracking. */ - - void mouseDown(const SWindowCoord&, EMouseButton button, EModifierKey) { - m_data.m_mouseButtons[size_t(button)] = true; - } - void mouseUp(const SWindowCoord&, EMouseButton button, EModifierKey) { - m_data.m_mouseButtons[size_t(button)] = false; - } - void mouseMove(const SWindowCoord& coord) { m_data.m_mouseCoord = coord; } - void scroll(const SWindowCoord&, const SScrollDelta& scroll) { m_data.m_accumScroll += scroll; } - - void charKeyDown(uint8_t charCode, aurora::ModifierKey, bool) { - charCode = tolower(charCode); - if (charCode > 255) - return; - m_data.m_charKeys[charCode] = true; - } - void charKeyUp(uint8_t charCode, aurora::ModifierKey mods) { - charCode = tolower(charCode); - if (charCode > 255) - return; - m_data.m_charKeys[charCode] = false; - } - void specialKeyDown(aurora::SpecialKey key, aurora::ModifierKey, bool) { m_data.m_specialKeys[size_t(key)] = true; } - void specialKeyUp(aurora::SpecialKey key, aurora::ModifierKey) { m_data.m_specialKeys[size_t(key)] = false; } - void modKeyDown(aurora::ModifierKey mod, bool) { m_data.m_modMask = m_data.m_modMask | mod; } - void modKeyUp(aurora::ModifierKey mod) { m_data.m_modMask = m_data.m_modMask & ~mod; } - - void reset() { m_data.m_accumScroll.zeroOut(); } - -// /* Input via the smash adapter is received asynchronously on a USB -// * report thread. This class atomically exchanges that data to the -// * game thread as needed */ -// struct DolphinSmashAdapterCallback : boo::IDolphinSmashAdapterCallback { -// std::array, 4> m_statusChanges; -// std::array m_connected{}; -// std::array m_states; -// std::mutex m_stateLock; -// void controllerConnected(unsigned idx, boo::EDolphinControllerType) override { -// /* Controller thread */ -// m_statusChanges[idx].store(EStatusChange::Connected); -// } -// void controllerDisconnected(unsigned idx) override { -// /* Controller thread */ -// std::unique_lock lk{m_stateLock}; -// m_statusChanges[idx].store(EStatusChange::Disconnected); -// m_states[idx].reset(); -// } -// void controllerUpdate(unsigned idx, boo::EDolphinControllerType, -// const boo::DolphinControllerState& state) override { -// /* Controller thread */ -// std::unique_lock lk{m_stateLock}; -// m_states[idx] = state; -// } -// -// std::array m_lastUpdates; -// const CFinalInput& getFinalInput(unsigned idx, float dt, float leftDiv, float rightDiv) { -// /* Game thread */ -// std::unique_lock lk{m_stateLock}; -// boo::DolphinControllerState state = m_states[idx]; -// lk.unlock(); -// state.clamp(); /* PADClamp equivalent */ -// m_lastUpdates[idx] = CFinalInput(idx, dt, state, m_lastUpdates[idx], leftDiv, rightDiv); -// return m_lastUpdates[idx]; -// } -// EStatusChange getStatusChange(unsigned idx, bool& connected) { -// /* Game thread */ -// EStatusChange ch = m_statusChanges[idx].exchange(EStatusChange::NoChange); -// if (ch == EStatusChange::Connected) -// m_connected[idx] = true; -// else if (ch == EStatusChange::Disconnected) -// m_connected[idx] = false; -// connected = m_connected[idx]; -// return ch; -// } -// } m_dolphinCb; - -// /* Device connection/disconnection events are handled on a separate thread -// * using the relevant OS API. This thread blocks in a loop until an event is -// * received. Device pointers should only be manipulated by this thread using -// * the deviceConnected() and deviceDisconnected() callbacks. */ -// std::shared_ptr smashAdapter; -// void deviceConnected(boo::DeviceToken& tok) override { -// /* Device listener thread */ -// if (!smashAdapter) { -// auto dev = tok.openAndGetDevice(); -// if (dev && dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) { -// smashAdapter = std::static_pointer_cast(tok.openAndGetDevice()); -// smashAdapter->setCallback(&m_dolphinCb); -// } -// } -// } -// void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) override { -// if (smashAdapter.get() == device) -// smashAdapter.reset(); -// } - void SetMotorState(EIOPort port, EMotorState state); - void ControlAllMotors(const std::array& states) { - for (u32 i = 0; i <= size_t(EIOPort::Player4); ++i ) { - SetMotorState(EIOPort(i), states[i]); - } - } - - /* This is where the game thread enters */ - void Update(float dt, CArchitectureQueue& queue); - CFinalInput GetLastInput() const { return m_lastUpdate; } +struct COsContext { + bool GetOsKeyState(int key) { return false; } }; -} // namespace metaforce +class CArchitectureQueue; + +class CInputGenerator { + // COsContext& x0_context; + std::unique_ptr x4_controller; + std::array x8_connectedControllers{}; + float xc_leftDiv; + float x10_rightDiv; + + CFinalInput m_lastInput; + +public: + CInputGenerator(/*COsContext& context, */ float leftDiv, float rightDiv); + + void Update(float dt, CArchitectureQueue& queue); + + IController* GetController() const { return x4_controller.get(); } + CFinalInput GetLastInput() const { return m_lastInput; } +}; +} // namespace metaforce \ No newline at end of file diff --git a/Runtime/Input/CInputGenerator.hpp.old b/Runtime/Input/CInputGenerator.hpp.old new file mode 100644 index 000000000..be1328dc8 --- /dev/null +++ b/Runtime/Input/CInputGenerator.hpp.old @@ -0,0 +1,162 @@ +#pragma once + +#include +#include +#include + +#include "Runtime/Input/InputTypes.hpp" +#include "Runtime/Input/CFinalInput.hpp" +#include "Runtime/Input/CKeyboardMouseController.hpp" + +namespace metaforce { +class CArchitectureQueue; + +class CInputGenerator /*: public boo::DeviceFinder*/ { + enum class EStatusChange { NoChange = 0, Connected = 1, Disconnected = 2 }; + + /* When the sticks are used as logical (digital) input, + * these thresholds determine the vector magnitude indicating + * the logical state */ + float m_leftDiv; + float m_rightDiv; + CKeyboardMouseControllerData m_data; + std::array m_state; + + CFinalInput m_lastUpdate; + const CFinalInput& getFinalInput(unsigned idx, float dt); + + bool m_firstFrame = true; + +public: + CInputGenerator(float leftDiv, float rightDiv) + : /*boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}),*/ m_leftDiv(leftDiv), m_rightDiv(rightDiv) {} + +// ~CInputGenerator() override { +// if (smashAdapter) { +// smashAdapter->setCallback(nullptr); +// smashAdapter->closeDevice(); +// } +// } + + void controllerAdded(uint32_t which) noexcept; + + void controllerRemoved(uint32_t which) noexcept; + + void controllerButton(uint32_t which, aurora::ControllerButton button, bool pressed) noexcept; + + void controllerAxis(uint32_t which, aurora::ControllerAxis axis, int16_t value) noexcept; + + + /* Keyboard and mouse events are delivered on the main game + * thread as part of the app's main event loop. The OS is responsible + * for buffering events in its own way, then boo flushes the buffer + * at the start of each frame, invoking these methods. No atomic locking + * is necessary, only absolute state tracking. */ + + void mouseDown(const SWindowCoord&, EMouseButton button, EModifierKey) { + m_data.m_mouseButtons[size_t(button)] = true; + } + void mouseUp(const SWindowCoord&, EMouseButton button, EModifierKey) { + m_data.m_mouseButtons[size_t(button)] = false; + } + void mouseMove(const SWindowCoord& coord) { m_data.m_mouseCoord = coord; } + void scroll(const SWindowCoord&, const SScrollDelta& scroll) { m_data.m_accumScroll += scroll; } + + void charKeyDown(uint8_t charCode, aurora::ModifierKey, bool) { + charCode = tolower(charCode); + if (charCode > 255) + return; + m_data.m_charKeys[charCode] = true; + } + void charKeyUp(uint8_t charCode, aurora::ModifierKey mods) { + charCode = tolower(charCode); + if (charCode > 255) + return; + m_data.m_charKeys[charCode] = false; + } + void specialKeyDown(aurora::SpecialKey key, aurora::ModifierKey, bool) { m_data.m_specialKeys[size_t(key)] = true; } + void specialKeyUp(aurora::SpecialKey key, aurora::ModifierKey) { m_data.m_specialKeys[size_t(key)] = false; } + void modKeyDown(aurora::ModifierKey mod, bool) { m_data.m_modMask = m_data.m_modMask | mod; } + void modKeyUp(aurora::ModifierKey mod) { m_data.m_modMask = m_data.m_modMask & ~mod; } + + void reset() { m_data.m_accumScroll.zeroOut(); } + +// /* Input via the smash adapter is received asynchronously on a USB +// * report thread. This class atomically exchanges that data to the +// * game thread as needed */ +// struct DolphinSmashAdapterCallback : boo::IDolphinSmashAdapterCallback { +// std::array, 4> m_statusChanges; +// std::array m_connected{}; +// std::array m_states; +// std::mutex m_stateLock; +// void controllerConnected(unsigned idx, boo::EDolphinControllerType) override { +// /* Controller thread */ +// m_statusChanges[idx].store(EStatusChange::Connected); +// } +// void controllerDisconnected(unsigned idx) override { +// /* Controller thread */ +// std::unique_lock lk{m_stateLock}; +// m_statusChanges[idx].store(EStatusChange::Disconnected); +// m_states[idx].reset(); +// } +// void controllerUpdate(unsigned idx, boo::EDolphinControllerType, +// const boo::DolphinControllerState& state) override { +// /* Controller thread */ +// std::unique_lock lk{m_stateLock}; +// m_states[idx] = state; +// } +// +// std::array m_lastUpdates; +// const CFinalInput& getFinalInput(unsigned idx, float dt, float leftDiv, float rightDiv) { +// /* Game thread */ +// std::unique_lock lk{m_stateLock}; +// boo::DolphinControllerState state = m_states[idx]; +// lk.unlock(); +// state.clamp(); /* PADClamp equivalent */ +// m_lastUpdates[idx] = CFinalInput(idx, dt, state, m_lastUpdates[idx], leftDiv, rightDiv); +// return m_lastUpdates[idx]; +// } +// EStatusChange getStatusChange(unsigned idx, bool& connected) { +// /* Game thread */ +// EStatusChange ch = m_statusChanges[idx].exchange(EStatusChange::NoChange); +// if (ch == EStatusChange::Connected) +// m_connected[idx] = true; +// else if (ch == EStatusChange::Disconnected) +// m_connected[idx] = false; +// connected = m_connected[idx]; +// return ch; +// } +// } m_dolphinCb; + +// /* Device connection/disconnection events are handled on a separate thread +// * using the relevant OS API. This thread blocks in a loop until an event is +// * received. Device pointers should only be manipulated by this thread using +// * the deviceConnected() and deviceDisconnected() callbacks. */ +// std::shared_ptr smashAdapter; +// void deviceConnected(boo::DeviceToken& tok) override { +// /* Device listener thread */ +// if (!smashAdapter) { +// auto dev = tok.openAndGetDevice(); +// if (dev && dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) { +// smashAdapter = std::static_pointer_cast(tok.openAndGetDevice()); +// smashAdapter->setCallback(&m_dolphinCb); +// } +// } +// } +// void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) override { +// if (smashAdapter.get() == device) +// smashAdapter.reset(); +// } + void SetMotorState(EIOPort port, EMotorState state); + void ControlAllMotors(const std::array& states) { + for (u32 i = 0; i <= size_t(EIOPort::Player4); ++i ) { + SetMotorState(EIOPort(i), states[i]); + } + } + + /* This is where the game thread enters */ + void Update(float dt, CArchitectureQueue& queue); + CFinalInput GetLastInput() const { return m_lastUpdate; } +}; + +} // namespace metaforce diff --git a/Runtime/Input/CMakeLists.txt b/Runtime/Input/CMakeLists.txt index 6d123cb15..fbe376aab 100644 --- a/Runtime/Input/CMakeLists.txt +++ b/Runtime/Input/CMakeLists.txt @@ -7,7 +7,6 @@ set(INPUT_SOURCES CDolphinController.hpp CDolphinController.cpp CKeyboardMouseController.hpp ControlMapper.hpp ControlMapper.cpp - NewCInputGenerator.hpp NewCInputGenerator.cpp CInputGenerator.hpp CInputGenerator.cpp CFinalInput.hpp CFinalInput.cpp CRumbleManager.hpp CRumbleManager.cpp diff --git a/Runtime/Input/CRumbleGenerator.cpp b/Runtime/Input/CRumbleGenerator.cpp index c9fe4be5f..315e53510 100644 --- a/Runtime/Input/CRumbleGenerator.cpp +++ b/Runtime/Input/CRumbleGenerator.cpp @@ -69,17 +69,18 @@ void CRumbleGenerator::Update(float dt) { } } } - if (updated) - g_InputGenerator->ControlAllMotors(xe0_commandArray); + if (updated) { + PADControlAllMotors(reinterpret_cast(xe0_commandArray.data())); + } } } void CRumbleGenerator::HardStopAll() { static constexpr std::array HardStopCommands{ - EMotorState::StopHard, - EMotorState::StopHard, - EMotorState::StopHard, - EMotorState::StopHard, + (u32)EMotorState::StopHard, + (u32)EMotorState::StopHard, + (u32)EMotorState::StopHard, + (u32)EMotorState::StopHard, }; xc0_periodTime.fill(0.0f); @@ -89,7 +90,8 @@ void CRumbleGenerator::HardStopAll() { voice.HardReset(); } - g_InputGenerator->ControlAllMotors(HardStopCommands); + // TODO(phil): switch this to g_InputGenerator->GetContoller()->SetMotorState? + PADControlAllMotors(static_cast(HardStopCommands.data())); } s16 CRumbleGenerator::Rumble(const SAdsrData& adsr, float gain, ERumblePriority prio, EIOPort port) { diff --git a/Runtime/Input/NewCInputGenerator.cpp b/Runtime/Input/NewCInputGenerator.cpp deleted file mode 100644 index 6e8eba66b..000000000 --- a/Runtime/Input/NewCInputGenerator.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Runtime/Input/NewCInputGenerator.hpp" - -#include "Runtime/Input/IController.hpp" -#include "Runtime/Input/CFinalInput.hpp" - -#include "Runtime/CArchitectureQueue.hpp" - -namespace metaforce::WIP { -CInputGenerator::CInputGenerator(/*COsContext& context, */ float leftDiv, float rightDiv) -/*: x0_context(context) */ { - x4_controller.reset(IController::Create()); - xc_leftDiv = leftDiv; - x10_rightDiv = rightDiv; -} - -void CInputGenerator::Update(float dt, CArchitectureQueue& queue) { -#if 0 - if (!x0_context.Update()) { - return; - } -#endif - - bool firstController = false; - if (x4_controller) { - x4_controller->Poll(); - for (u32 i = 0; i < x4_controller->GetDeviceCount(); ++i) { - auto cont = x4_controller->GetGamepadData(i); - if (!cont.DeviceIsPresent()) { - continue; - } - if (i == 0) { - firstController = true; - } - - queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, CFinalInput(i, dt, cont, xc_leftDiv, x10_rightDiv))); - // TODO: Finish - } - } -} -} // namespace metaforce::WIP diff --git a/Runtime/Input/NewCInputGenerator.hpp b/Runtime/Input/NewCInputGenerator.hpp deleted file mode 100644 index 41a2874c1..000000000 --- a/Runtime/Input/NewCInputGenerator.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include "Runtime/Input/IController.hpp" - -namespace metaforce { -struct COsContext { - bool GetOsKeyState(int key) { return false; } -}; - -class CArchitectureQueue; - -namespace WIP { -class CInputGenerator { - //COsContext& x0_context; - std::unique_ptr x4_controller; - bool x8_ = false; - bool x9_ = false; - bool xa_ = false; - bool xb_ = false; - float xc_leftDiv; - float x10_rightDiv; - -public: - CInputGenerator(/*COsContext& context, */float leftDiv, float rightDiv); - - void Update(float dt, CArchitectureQueue& queue); -}; - -} // namespace WIP -} // namespace metaforce \ No newline at end of file diff --git a/Runtime/MP1/CInGameGuiManager.cpp b/Runtime/MP1/CInGameGuiManager.cpp index 3e0ec29c5..5e4a7fec5 100644 --- a/Runtime/MP1/CInGameGuiManager.cpp +++ b/Runtime/MP1/CInGameGuiManager.cpp @@ -15,6 +15,7 @@ #include "Runtime/GuiSys/CGuiModel.hpp" #include "Runtime/GuiSys/CGuiWidgetDrawParms.hpp" #include "Runtime/Input/CInputGenerator.hpp" +#include "Runtime/Input/IController.hpp" #include "Runtime/MP1/CSamusHud.hpp" #include "Runtime/Particle/CGenDescription.hpp" #include "Runtime/World/CPlayer.hpp" @@ -629,7 +630,7 @@ void CInGameGuiManager::ShowPauseGameHudMessage(CStateManager& stateMgr, CAssetI } void CInGameGuiManager::PauseGame(CStateManager& stateMgr, EInGameGuiState state) { - g_InputGenerator->SetMotorState(EIOPort::Player1, EMotorState::Stop); + g_Controller->SetMotorState(EIOPort::Player1, EMotorState::Stop); CSfxManager::SetChannel(CSfxManager::ESfxChannels::PauseScreen); BeginStateTransition(state, stateMgr); } diff --git a/Runtime/MP1/MP1.cpp b/Runtime/MP1/MP1.cpp index b7c3c01aa..b99e0bd8c 100644 --- a/Runtime/MP1/MP1.cpp +++ b/Runtime/MP1/MP1.cpp @@ -94,12 +94,12 @@ CGameArchitectureSupport::CGameArchitectureSupport(CMain& parent, boo::IAudioVoi amuse::IBackendVoiceAllocator& backend) : m_parent(parent) , x0_audioSys(voiceEngine, backend, 0, 0, 0, 0, 0) -, x30_newInputGenerator(/*osCtx, */ g_tweakPlayer->GetLeftLogicalThreshold(), g_tweakPlayer->GetRightLogicalThreshold()) -, x30_inputGenerator(g_tweakPlayer->GetLeftLogicalThreshold(), g_tweakPlayer->GetRightLogicalThreshold()) +, x30_inputGenerator(/*osCtx, */ g_tweakPlayer->GetLeftLogicalThreshold(), g_tweakPlayer->GetRightLogicalThreshold()) , x44_guiSys(*g_ResFactory, *g_SimplePool, CGuiSys::EUsageMode::Zero) { auto* m = static_cast(g_Main); g_InputGenerator = &x30_inputGenerator; + g_Controller = x30_inputGenerator.GetController(); CAudioSys::SysSetVolume(0x7f); CAudioSys::SetDefaultVolumeScale(0x75); @@ -136,8 +136,7 @@ void CGameArchitectureSupport::UpdateTicks(float dt) { void CGameArchitectureSupport::Update(float dt) { g_GameState->GetWorldTransitionManager()->TouchModels(); - x30_newInputGenerator.Update(dt, x4_archQueue); - // x30_inputGenerator.Update(dt, x4_archQueue); + x30_inputGenerator.Update(dt, x4_archQueue); x4_archQueue.Push(MakeMsg::CreateFrameEnd(EArchMsgTarget::Game, x78_gameFrameCount)); x58_ioWinManager.PumpMessages(x4_archQueue); } @@ -224,15 +223,15 @@ CGameArchitectureSupport::~CGameArchitectureSupport() { } void CGameArchitectureSupport::charKeyDown(uint8_t charCode, aurora::ModifierKey mods, bool isRepeat) { - x30_inputGenerator.charKeyDown(charCode, mods, isRepeat); + // x30_inputGenerator.charKeyDown(charCode, mods, isRepeat); } void CGameArchitectureSupport::specialKeyDown(aurora::SpecialKey key, aurora::ModifierKey mods, bool isRepeat) { - x30_inputGenerator.specialKeyDown(key, mods, isRepeat); + // x30_inputGenerator.specialKeyDown(key, mods, isRepeat); } void CGameArchitectureSupport::specialKeyUp(aurora::SpecialKey key, aurora::ModifierKey mods) { - x30_inputGenerator.specialKeyUp(key, mods); + // x30_inputGenerator.specialKeyUp(key, mods); } CMain::CMain(IFactory* resFactory, CSimplePool* resStore) diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index a6f3942be..3e1066a3a 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -19,7 +19,6 @@ #include "Runtime/Particle/CGenDescription.hpp" #include "Runtime/Graphics/CCubeRenderer.hpp" #include "Runtime/Audio/CAudioSys.hpp" -#include "Runtime/Input/NewCInputGenerator.hpp" #include "Runtime/Input/CInputGenerator.hpp" #include "Runtime/GuiSys/CGuiSys.hpp" #include "Runtime/CIOWinManager.hpp" @@ -116,7 +115,6 @@ class CGameArchitectureSupport { CMain& m_parent; CArchitectureQueue x4_archQueue; CAudioSys x0_audioSys; - WIP::CInputGenerator x30_newInputGenerator; CInputGenerator x30_inputGenerator; CGuiSys x44_guiSys; CIOWinManager x58_ioWinManager; @@ -141,20 +139,30 @@ public: ~CGameArchitectureSupport(); void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) { - x30_inputGenerator.mouseDown(coord, button, mods); + // x30_inputGenerator.mouseDown(coord, button, mods); } void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) { - x30_inputGenerator.mouseUp(coord, button, mods); + // x30_inputGenerator.mouseUp(coord, button, mods); + } + void mouseMove(const SWindowCoord& coord) { + // x30_inputGenerator.mouseMove(coord); + } + void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) { + // x30_inputGenerator.scroll(coord, scroll); } - void mouseMove(const SWindowCoord& coord) { x30_inputGenerator.mouseMove(coord); } - void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) { x30_inputGenerator.scroll(coord, scroll); } void charKeyDown(uint8_t charCode, aurora::ModifierKey mods, bool isRepeat); - void charKeyUp(uint8_t charCode, aurora::ModifierKey mods) { x30_inputGenerator.charKeyUp(charCode, mods); } + void charKeyUp(uint8_t charCode, aurora::ModifierKey mods) { + // x30_inputGenerator.charKeyUp(charCode, mods); + } void specialKeyDown(aurora::SpecialKey key, aurora::ModifierKey mods, bool isRepeat); void specialKeyUp(aurora::SpecialKey key, aurora::ModifierKey mods); - void modKeyDown(aurora::ModifierKey mod, bool isRepeat) { x30_inputGenerator.modKeyDown(mod, isRepeat); } - void modKeyUp(aurora::ModifierKey mod) { x30_inputGenerator.modKeyUp(mod); } + void modKeyDown(aurora::ModifierKey mod, bool isRepeat) { + // x30_inputGenerator.modKeyDown(mod, isRepeat); + } + void modKeyUp(aurora::ModifierKey mod) { + // x30_inputGenerator.modKeyUp(mod); + } void PreloadAudio(); bool LoadAudio(); @@ -248,7 +256,7 @@ public: bool Proc(float dt) override; void Draw() override; void Shutdown() override; -// boo::IWindow* GetMainWindow() const override; + // boo::IWindow* GetMainWindow() const override; void MemoryCardInitializePump(); diff --git a/aurora/lib/input.cpp b/aurora/lib/input.cpp index 3b2328e24..621da3359 100644 --- a/aurora/lib/input.cpp +++ b/aurora/lib/input.cpp @@ -541,10 +541,10 @@ void ClampCircle(s8* px, s8* py, s8 radius, s8 min) { } void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min) { - s8 x = *px; - s8 y = *py; + s32 x = *px; + s32 y = *py; - s8 signX = 0; + s32 signX = 0; if (0 <= x) { signX = 1; } else { @@ -577,13 +577,13 @@ void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min) { } if (xy * y <= xy * x) { - s8 d = xy * x + (max - xy) * y; + s32 d = xy * x + (max - xy) * y; if (xy * max < d) { x = (xy * max * x / d); y = (xy * max * y / d); } } else { - s8 d = xy * y + (max - xy) * x; + s32 d = xy * y + (max - xy) * x; if (xy * max < d) { x = (xy * max * x / d); y = (xy * max * y / d);