diff --git a/Runtime/Input/CControllerButton.hpp b/Runtime/Input/CControllerButton.hpp index 362f4a64a..091e06c6a 100644 --- a/Runtime/Input/CControllerButton.hpp +++ b/Runtime/Input/CControllerButton.hpp @@ -25,15 +25,16 @@ enum class EAnalogButton { }; class CControllerButton { - bool x0_; - bool x1_pressed; - bool x2_; + bool x0_pressed; + bool x1_pressEvent; + bool x2_releaseEvent; public: - void SetIsPressed(bool pressed) { x1_pressed = pressed; } - [[nodiscard]] bool GetIsPressed() const { return x1_pressed; } - void SetPressEvent(bool press); - [[nodiscard]] bool GetPressEvent() const; - void SetReleaseEvent(bool release); + void SetIsPressed(bool pressed) { x0_pressed = pressed; } + [[nodiscard]] bool GetIsPressed() const { return x0_pressed; } + void SetPressEvent(bool press){ x1_pressEvent = press; } + [[nodiscard]] bool GetPressEvent() const{ return x1_pressEvent; } + void SetReleaseEvent(bool release) { x2_releaseEvent = release;}; + [[nodiscard]] bool GetReleaseEvent() const { return x2_releaseEvent; } }; } // namespace metaforce \ No newline at end of file diff --git a/Runtime/Input/CDolphinController.cpp b/Runtime/Input/CDolphinController.cpp index 5357e6acf..cfba128e0 100644 --- a/Runtime/Input/CDolphinController.cpp +++ b/Runtime/Input/CDolphinController.cpp @@ -4,11 +4,16 @@ namespace metaforce { CDolphinController::CDolphinController() { static bool sIsInitialized = false; if (!sIsInitialized) { - // PADSetSpec(5); - // PADInit(); + PADSetSpec(5); + PADInit(); sIsInitialized = true; } } + +void CDolphinController::Poll() { + ReadDevices(); + ProcessInputData(); +} void CDolphinController::SetMotorState(EIOPort port, EMotorState state) { x194_motorStates[u32(port)] = state; } float CDolphinController::GetAnalogStickMaxValue(EJoyAxis axis) { @@ -23,6 +28,66 @@ float CDolphinController::GetAnalogStickMaxValue(EJoyAxis axis) { return 0.f; } +void CDolphinController::ReadDevices() { + std::array status{}; + PADRead(status.data()); + if (status[0].xa_err == PAD::ERR_NONE) { + PADClamp(status.data()); + x4_status = status; + } else { + x4_status[0].xa_err = status[0].xa_err; + x4_status[1].xa_err = status[1].xa_err; + x4_status[2].xa_err = status[2].xa_err; + x4_status[3].xa_err = status[3].xa_err; + } + + for (u32 i = 0; i < 4; ++i) { + if (x4_status[i].xa_err != PAD::ERR_NOT_READY) { + if (x4_status[i].xa_err == PAD::ERR_NONE) { + x34_gamepadStates[i].SetDeviceIsPresent(true); + } else if (x4_status[i].xa_err == PAD::ERR_NO_CONTROLLER) { + x1c8_invalidControllers |= PAD::CHAN0_BIT >> i; + x34_gamepadStates[i].SetDeviceIsPresent(false); + } + } + + if (x1b4_[i] == 0) { + const auto type = SIProbe(i); + if ((type & (SI::ERROR_NO_RESPONSE | SI::ERROR_UNKNOWN | SI::ERROR_BUSY)) == 0) { + x1b4_[i] = 0x3c; + if (type == SI::GC_WIRELESS) { + x1a4_controllerTypes[i] = skTypeWavebird; + } else if (type == SI::GBA) { /* here for completeness, the GameCube adapter does not support GBA */ + x1a4_controllerTypes[i] = skTypeGBA; + } else if (type == SI::GC_STANDARD) { + x1a4_controllerTypes[i] = skTypeStandard; + } + } else { + x1a4_controllerTypes[i] = skTypeUnknown; + } + } else { + --x1b4_[i]; + } + } + + if (x1c8_invalidControllers != 0 && PADReset(x1c8_invalidControllers)) { + x1c8_invalidControllers = 0; + } +} + +void CDolphinController::ProcessInputData() { + for (u32 i = 0; i < 4; ++i) { + if (!x34_gamepadStates[i].DeviceIsPresent()) { + continue; + } + ProcessAxis(i, EJoyAxis::LeftX); + ProcessAxis(i, EJoyAxis::LeftY); + ProcessAxis(i, EJoyAxis::RightX); + ProcessAxis(i, EJoyAxis::RightY); + ProcessButtons(i); + } +} + void CDolphinController::ProcessAxis(u32 controller, EJoyAxis axis) { const auto maxAxisValue = GetAnalogStickMaxValue(axis); auto& data = x34_gamepadStates[controller].GetAxis(axis); @@ -72,8 +137,48 @@ void CDolphinController::ProcessButtons(u32 controller) { ProcessAnalogButton(x4_status[controller].x7_triggerR, x34_gamepadStates[controller].GetAnalogButton(EAnalogButton::Right)); } -void CDolphinController::ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping) {} -void CDolphinController::ProcessAnalogButton(float value, CControllerAxis& axis) {} +void CDolphinController::ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping) { + bool btnPressed = (x4_status[controller].x0_buttons & mapping) != 0; + button.SetPressEvent(PADButtonDown(button.GetIsPressed(), btnPressed)); + button.SetReleaseEvent(PADButtonUp(button.GetIsPressed(), btnPressed)); + button.SetPressEvent(btnPressed); +} +void CDolphinController::ProcessAnalogButton(float value, CControllerAxis& axis) { + float absolute = value * (1 / 150.f); + if (value * (1 / 150.f) > 1.f) { + absolute = kAbsoluteMaximum; + } -void CDolphinController::Initialize() {} + float relative = absolute - axis.GetAbsoluteValue(); + if (relative > kRelativeMaximum) { + relative = kRelativeMaximum; + } + + axis.SetRelativeValue(relative); + axis.SetAbsoluteValue(absolute); +} + +bool CDolphinController::Initialize() { + // GBAInit(); + memset(x4_status.data(), 0, sizeof(PADStatus) * x4_status.size()); + x34_gamepadStates[0].SetDeviceIsPresent(false); + x194_motorStates[0] = EMotorState::StopHard; + x1b4_[0] = 0; + x1a4_controllerTypes[0] = skTypeUnknown; + x34_gamepadStates[1].SetDeviceIsPresent(false); + x194_motorStates[1] = EMotorState::StopHard; + x1b4_[1] = 0; + x1a4_controllerTypes[0] = skTypeUnknown; + x34_gamepadStates[2].SetDeviceIsPresent(false); + x194_motorStates[2] = EMotorState::StopHard; + x1b4_[2] = 0; + x1a4_controllerTypes[0] = skTypeUnknown; + x34_gamepadStates[3].SetDeviceIsPresent(false); + x194_motorStates[3] = EMotorState::StopHard; + x1b4_[3] = 0; + x1a4_controllerTypes[0] = skTypeUnknown; + PADControlAllMotors(reinterpret_cast(x194_motorStates.data())); + Poll(); + return true; +} } // namespace metaforce \ No newline at end of file diff --git a/Runtime/Input/CDolphinController.hpp b/Runtime/Input/CDolphinController.hpp index 712dbcab0..61b387341 100644 --- a/Runtime/Input/CDolphinController.hpp +++ b/Runtime/Input/CDolphinController.hpp @@ -6,32 +6,38 @@ namespace metaforce { class CDolphinController : public IController { + static constexpr u32 skTypeUnknown = SBIG('UNKN'); + static constexpr u32 skTypeStandard = SBIG('STND'); + static constexpr u32 skTypeGBA = SBIG('GBA_'); + static constexpr u32 skTypeWavebird = SBIG('WAVE'); - std::array x4_status; + std::array x4_status{}; std::array x34_gamepadStates{}; - std::array x194_motorStates; + std::array x194_motorStates{}; std::array x1a4_controllerTypes{}; std::array x1b4_{}; u32 x1c4_ = 0xf0000000; - u32 x1c8_ = 0; + u32 x1c8_invalidControllers = 0; u32 x1cc_ = 0; public: CDolphinController(); - void Poll() override{}; + void Poll() override; [[nodiscard]] u32 GetDeviceCount() const override { return 4; }; [[nodiscard]] CControllerGamepadData& GetGamepadData(u32 controller) override { return x34_gamepadStates[controller]; }; [[nodiscard]] u32 GetControllerType(u32 controller) const override { return x1a4_controllerTypes[controller]; } void SetMotorState(EIOPort port, EMotorState state) override; - float GetAnalogStickMaxValue(EJoyAxis axis); + bool Initialize(); + +private: + void ReadDevices(); + void ProcessInputData(); void ProcessAxis(u32 controller, EJoyAxis axis); void ProcessButtons(u32 controller); void ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping); void ProcessAnalogButton(float value, CControllerAxis& axis); - - void Initialize(); }; } // namespace metaforce \ No newline at end of file diff --git a/aurora/include/aurora/pad.hpp b/aurora/include/aurora/pad.hpp index 2249fd314..5eabcde44 100644 --- a/aurora/include/aurora/pad.hpp +++ b/aurora/include/aurora/pad.hpp @@ -51,8 +51,11 @@ enum CHAN : u32 { } // namespace PAD namespace SI { +constexpr u32 ERROR_UNKNOWN = 0x0040; +constexpr u32 ERROR_BUSY = 0x0080; constexpr u32 ERROR_NO_RESPONSE = 0x0008; constexpr u32 TYPE_GC = 0x08000000; +constexpr u32 GBA = 0x00040000; constexpr u32 GC_STANDARD = 0x01000000; constexpr u32 GC_WIRELESS = 0x80000000; constexpr u32 WIRELESS_STATE = 0x02000000; @@ -63,15 +66,15 @@ constexpr u32 GC_WAVEBIRD = (TYPE_GC | GC_WIRELESS | GC_STANDARD | WIRELESS_STAT } // namespace SI using PADSamplingCallback = void (*)(void); -constexpr bool PADButtonDown(u16 lastButton, u16 button) { return ((lastButton ^ button) & button) != 0; } -constexpr bool PADButtonUp(u16 lastButton, u16 button) { return ((lastButton ^ button) & lastButton) != 0; } +constexpr bool PADButtonDown(bool lastButton, bool button) { return ((lastButton ^ button) & button) != 0; } +constexpr bool PADButtonUp(bool lastButton, bool button) { return ((lastButton ^ button) & lastButton) != 0; } void PADClamp(PAD::Status* status); void PADClampCircle(PAD::Status* status); void PADInit(); bool PADIsBarrel(s32 chan); u32 PADRead(PAD::Status* status); -bool PADRecalibrate(u32 mask); -bool PADReset(u32 mask); +static bool PADRecalibrate(u32 mask) { return true; } +static bool PADReset(u32 mask) { return true; } void PADSetAnalog(u32 mode); void PADSetSpec(s32 spec); void PADSetSamplingCallback(PADSamplingCallback callback);