mirror of https://github.com/AxioDL/metaforce.git
Finish CDolphinController imp, ready for integration
This commit is contained in:
parent
7e1b1ef248
commit
be79334465
|
@ -25,15 +25,16 @@ enum class EAnalogButton {
|
||||||
};
|
};
|
||||||
|
|
||||||
class CControllerButton {
|
class CControllerButton {
|
||||||
bool x0_;
|
bool x0_pressed;
|
||||||
bool x1_pressed;
|
bool x1_pressEvent;
|
||||||
bool x2_;
|
bool x2_releaseEvent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void SetIsPressed(bool pressed) { x1_pressed = pressed; }
|
void SetIsPressed(bool pressed) { x0_pressed = pressed; }
|
||||||
[[nodiscard]] bool GetIsPressed() const { return x1_pressed; }
|
[[nodiscard]] bool GetIsPressed() const { return x0_pressed; }
|
||||||
void SetPressEvent(bool press);
|
void SetPressEvent(bool press){ x1_pressEvent = press; }
|
||||||
[[nodiscard]] bool GetPressEvent() const;
|
[[nodiscard]] bool GetPressEvent() const{ return x1_pressEvent; }
|
||||||
void SetReleaseEvent(bool release);
|
void SetReleaseEvent(bool release) { x2_releaseEvent = release;};
|
||||||
|
[[nodiscard]] bool GetReleaseEvent() const { return x2_releaseEvent; }
|
||||||
};
|
};
|
||||||
} // namespace metaforce
|
} // namespace metaforce
|
|
@ -4,11 +4,16 @@ namespace metaforce {
|
||||||
CDolphinController::CDolphinController() {
|
CDolphinController::CDolphinController() {
|
||||||
static bool sIsInitialized = false;
|
static bool sIsInitialized = false;
|
||||||
if (!sIsInitialized) {
|
if (!sIsInitialized) {
|
||||||
// PADSetSpec(5);
|
PADSetSpec(5);
|
||||||
// PADInit();
|
PADInit();
|
||||||
sIsInitialized = true;
|
sIsInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDolphinController::Poll() {
|
||||||
|
ReadDevices();
|
||||||
|
ProcessInputData();
|
||||||
|
}
|
||||||
void CDolphinController::SetMotorState(EIOPort port, EMotorState state) { x194_motorStates[u32(port)] = state; }
|
void CDolphinController::SetMotorState(EIOPort port, EMotorState state) { x194_motorStates[u32(port)] = state; }
|
||||||
|
|
||||||
float CDolphinController::GetAnalogStickMaxValue(EJoyAxis axis) {
|
float CDolphinController::GetAnalogStickMaxValue(EJoyAxis axis) {
|
||||||
|
@ -23,6 +28,66 @@ float CDolphinController::GetAnalogStickMaxValue(EJoyAxis axis) {
|
||||||
return 0.f;
|
return 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDolphinController::ReadDevices() {
|
||||||
|
std::array<PADStatus, 4> 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) {
|
void CDolphinController::ProcessAxis(u32 controller, EJoyAxis axis) {
|
||||||
const auto maxAxisValue = GetAnalogStickMaxValue(axis);
|
const auto maxAxisValue = GetAnalogStickMaxValue(axis);
|
||||||
auto& data = x34_gamepadStates[controller].GetAxis(axis);
|
auto& data = x34_gamepadStates[controller].GetAxis(axis);
|
||||||
|
@ -72,8 +137,48 @@ void CDolphinController::ProcessButtons(u32 controller) {
|
||||||
ProcessAnalogButton(x4_status[controller].x7_triggerR,
|
ProcessAnalogButton(x4_status[controller].x7_triggerR,
|
||||||
x34_gamepadStates[controller].GetAnalogButton(EAnalogButton::Right));
|
x34_gamepadStates[controller].GetAnalogButton(EAnalogButton::Right));
|
||||||
}
|
}
|
||||||
void CDolphinController::ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping) {}
|
void CDolphinController::ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping) {
|
||||||
void CDolphinController::ProcessAnalogButton(float value, CControllerAxis& axis) {}
|
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<const u32*>(x194_motorStates.data()));
|
||||||
|
Poll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} // namespace metaforce
|
} // namespace metaforce
|
|
@ -6,32 +6,38 @@
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
|
|
||||||
class CDolphinController : public IController {
|
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<PADStatus, 4> x4_status;
|
std::array<PADStatus, 4> x4_status{};
|
||||||
std::array<CControllerGamepadData, 4> x34_gamepadStates{};
|
std::array<CControllerGamepadData, 4> x34_gamepadStates{};
|
||||||
std::array<EMotorState, 4> x194_motorStates;
|
std::array<EMotorState, 4> x194_motorStates{};
|
||||||
std::array<u32, 4> x1a4_controllerTypes{};
|
std::array<u32, 4> x1a4_controllerTypes{};
|
||||||
std::array<u32, 4> x1b4_{};
|
std::array<u32, 4> x1b4_{};
|
||||||
u32 x1c4_ = 0xf0000000;
|
u32 x1c4_ = 0xf0000000;
|
||||||
u32 x1c8_ = 0;
|
u32 x1c8_invalidControllers = 0;
|
||||||
u32 x1cc_ = 0;
|
u32 x1cc_ = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDolphinController();
|
CDolphinController();
|
||||||
void Poll() override{};
|
void Poll() override;
|
||||||
[[nodiscard]] u32 GetDeviceCount() const override { return 4; };
|
[[nodiscard]] u32 GetDeviceCount() const override { return 4; };
|
||||||
[[nodiscard]] CControllerGamepadData& GetGamepadData(u32 controller) override {
|
[[nodiscard]] CControllerGamepadData& GetGamepadData(u32 controller) override {
|
||||||
return x34_gamepadStates[controller];
|
return x34_gamepadStates[controller];
|
||||||
};
|
};
|
||||||
[[nodiscard]] u32 GetControllerType(u32 controller) const override { return x1a4_controllerTypes[controller]; }
|
[[nodiscard]] u32 GetControllerType(u32 controller) const override { return x1a4_controllerTypes[controller]; }
|
||||||
void SetMotorState(EIOPort port, EMotorState state) override;
|
void SetMotorState(EIOPort port, EMotorState state) override;
|
||||||
|
|
||||||
float GetAnalogStickMaxValue(EJoyAxis axis);
|
float GetAnalogStickMaxValue(EJoyAxis axis);
|
||||||
|
bool Initialize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ReadDevices();
|
||||||
|
void ProcessInputData();
|
||||||
void ProcessAxis(u32 controller, EJoyAxis axis);
|
void ProcessAxis(u32 controller, EJoyAxis axis);
|
||||||
void ProcessButtons(u32 controller);
|
void ProcessButtons(u32 controller);
|
||||||
void ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping);
|
void ProcessDigitalButton(u32 controller, CControllerButton& button, u16 mapping);
|
||||||
void ProcessAnalogButton(float value, CControllerAxis& axis);
|
void ProcessAnalogButton(float value, CControllerAxis& axis);
|
||||||
|
|
||||||
void Initialize();
|
|
||||||
};
|
};
|
||||||
} // namespace metaforce
|
} // namespace metaforce
|
|
@ -51,8 +51,11 @@ enum CHAN : u32 {
|
||||||
} // namespace PAD
|
} // namespace PAD
|
||||||
|
|
||||||
namespace SI {
|
namespace SI {
|
||||||
|
constexpr u32 ERROR_UNKNOWN = 0x0040;
|
||||||
|
constexpr u32 ERROR_BUSY = 0x0080;
|
||||||
constexpr u32 ERROR_NO_RESPONSE = 0x0008;
|
constexpr u32 ERROR_NO_RESPONSE = 0x0008;
|
||||||
constexpr u32 TYPE_GC = 0x08000000;
|
constexpr u32 TYPE_GC = 0x08000000;
|
||||||
|
constexpr u32 GBA = 0x00040000;
|
||||||
constexpr u32 GC_STANDARD = 0x01000000;
|
constexpr u32 GC_STANDARD = 0x01000000;
|
||||||
constexpr u32 GC_WIRELESS = 0x80000000;
|
constexpr u32 GC_WIRELESS = 0x80000000;
|
||||||
constexpr u32 WIRELESS_STATE = 0x02000000;
|
constexpr u32 WIRELESS_STATE = 0x02000000;
|
||||||
|
@ -63,15 +66,15 @@ constexpr u32 GC_WAVEBIRD = (TYPE_GC | GC_WIRELESS | GC_STANDARD | WIRELESS_STAT
|
||||||
} // namespace SI
|
} // namespace SI
|
||||||
|
|
||||||
using PADSamplingCallback = void (*)(void);
|
using PADSamplingCallback = void (*)(void);
|
||||||
constexpr bool PADButtonDown(u16 lastButton, u16 button) { return ((lastButton ^ button) & button) != 0; }
|
constexpr bool PADButtonDown(bool lastButton, bool button) { return ((lastButton ^ button) & button) != 0; }
|
||||||
constexpr bool PADButtonUp(u16 lastButton, u16 button) { return ((lastButton ^ button) & lastButton) != 0; }
|
constexpr bool PADButtonUp(bool lastButton, bool button) { return ((lastButton ^ button) & lastButton) != 0; }
|
||||||
void PADClamp(PAD::Status* status);
|
void PADClamp(PAD::Status* status);
|
||||||
void PADClampCircle(PAD::Status* status);
|
void PADClampCircle(PAD::Status* status);
|
||||||
void PADInit();
|
void PADInit();
|
||||||
bool PADIsBarrel(s32 chan);
|
bool PADIsBarrel(s32 chan);
|
||||||
u32 PADRead(PAD::Status* status);
|
u32 PADRead(PAD::Status* status);
|
||||||
bool PADRecalibrate(u32 mask);
|
static bool PADRecalibrate(u32 mask) { return true; }
|
||||||
bool PADReset(u32 mask);
|
static bool PADReset(u32 mask) { return true; }
|
||||||
void PADSetAnalog(u32 mode);
|
void PADSetAnalog(u32 mode);
|
||||||
void PADSetSpec(s32 spec);
|
void PADSetSpec(s32 spec);
|
||||||
void PADSetSamplingCallback(PADSamplingCallback callback);
|
void PADSetSamplingCallback(PADSamplingCallback callback);
|
||||||
|
|
Loading…
Reference in New Issue