2018-10-07 03:42:33 +00:00
|
|
|
#pragma once
|
2015-08-18 05:54:43 +00:00
|
|
|
|
2020-03-18 03:23:13 +00:00
|
|
|
#include <array>
|
2015-08-29 01:30:47 +00:00
|
|
|
#include <atomic>
|
2019-09-22 21:52:05 +00:00
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
#include "Runtime/Input/CFinalInput.hpp"
|
|
|
|
#include "Runtime/Input/CKeyboardMouseController.hpp"
|
|
|
|
|
2015-08-28 00:11:31 +00:00
|
|
|
#include <boo/boo.hpp>
|
|
|
|
|
2021-04-10 08:42:06 +00:00
|
|
|
namespace metaforce {
|
2015-08-29 01:30:47 +00:00
|
|
|
class CArchitectureQueue;
|
2015-08-18 05:54:43 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
enum class EIOPort { Zero, One, Two, Three };
|
2017-12-16 00:19:15 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
enum class EMotorState { Stop, Rumble, StopHard };
|
2015-08-29 01:30:47 +00:00
|
|
|
|
2022-02-08 01:48:08 +00:00
|
|
|
class CInputGenerator /*: public boo::DeviceFinder*/ {
|
2018-12-08 05:30:43 +00:00
|
|
|
enum class EStatusChange { NoChange = 0, Connected = 1, Disconnected = 2 };
|
2015-08-28 00:11:31 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
/* 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;
|
2022-02-08 01:48:08 +00:00
|
|
|
SAuroraControllerState m_state;
|
2015-08-28 00:11:31 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
CFinalInput m_lastUpdate;
|
|
|
|
const CFinalInput& getFinalInput(unsigned idx, float dt) {
|
2022-02-08 01:48:08 +00:00
|
|
|
auto input = CFinalInput(idx, dt, m_data, m_lastUpdate);
|
|
|
|
// Merge controller input with kb/m input
|
|
|
|
input |= CFinalInput(idx, dt, m_state, m_lastUpdate, m_leftDiv, m_rightDiv);
|
|
|
|
m_lastUpdate = input;
|
2018-12-08 05:30:43 +00:00
|
|
|
return m_lastUpdate;
|
|
|
|
}
|
2015-08-28 00:11:31 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
bool m_firstFrame = true;
|
2015-08-29 01:30:47 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
public:
|
|
|
|
CInputGenerator(float leftDiv, float rightDiv)
|
2022-02-08 01:48:08 +00:00
|
|
|
: /*boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}),*/ m_leftDiv(leftDiv), m_rightDiv(rightDiv) {}
|
|
|
|
|
|
|
|
// ~CInputGenerator() override {
|
|
|
|
// if (smashAdapter) {
|
|
|
|
// smashAdapter->setCallback(nullptr);
|
|
|
|
// smashAdapter->closeDevice();
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
void controllerButton(uint32_t idx, aurora::ControllerButton button, bool pressed) noexcept {
|
|
|
|
// TODO check idx
|
|
|
|
m_state.m_btns.set(size_t(button), pressed);
|
|
|
|
}
|
|
|
|
void controllerAxis(uint32_t idx, aurora::ControllerAxis axis, int16_t value) noexcept {
|
|
|
|
// TODO check idx
|
|
|
|
m_state.m_axes[size_t(axis)] = value;
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 boo::SWindowCoord&, boo::EMouseButton button, boo::EModifierKey) {
|
2019-10-01 05:25:19 +00:00
|
|
|
m_data.m_mouseButtons[size_t(button)] = true;
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
|
|
|
void mouseUp(const boo::SWindowCoord&, boo::EMouseButton button, boo::EModifierKey) {
|
2019-10-01 05:25:19 +00:00
|
|
|
m_data.m_mouseButtons[size_t(button)] = false;
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
|
|
|
void mouseMove(const boo::SWindowCoord& coord) { m_data.m_mouseCoord = coord; }
|
|
|
|
void scroll(const boo::SWindowCoord&, const boo::SScrollDelta& scroll) { m_data.m_accumScroll += scroll; }
|
|
|
|
|
|
|
|
void charKeyDown(unsigned long charCode, boo::EModifierKey, bool) {
|
|
|
|
charCode = tolower(charCode);
|
|
|
|
if (charCode > 255)
|
|
|
|
return;
|
|
|
|
m_data.m_charKeys[charCode] = true;
|
|
|
|
}
|
|
|
|
void charKeyUp(unsigned long charCode, boo::EModifierKey mods) {
|
|
|
|
charCode = tolower(charCode);
|
|
|
|
if (charCode > 255)
|
|
|
|
return;
|
|
|
|
m_data.m_charKeys[charCode] = false;
|
|
|
|
}
|
2019-10-01 05:25:19 +00:00
|
|
|
void specialKeyDown(boo::ESpecialKey key, boo::EModifierKey, bool) { m_data.m_specialKeys[size_t(key)] = true; }
|
|
|
|
void specialKeyUp(boo::ESpecialKey key, boo::EModifierKey) { m_data.m_specialKeys[size_t(key)] = false; }
|
2018-12-08 05:30:43 +00:00
|
|
|
void modKeyDown(boo::EModifierKey mod, bool) { m_data.m_modMask = m_data.m_modMask | mod; }
|
|
|
|
void modKeyUp(boo::EModifierKey mod) { m_data.m_modMask = m_data.m_modMask & ~mod; }
|
|
|
|
|
|
|
|
void reset() { m_data.m_accumScroll.zeroOut(); }
|
|
|
|
|
2022-02-08 01:48:08 +00:00
|
|
|
// /* 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<std::atomic<EStatusChange>, 4> m_statusChanges;
|
|
|
|
// std::array<bool, 4> m_connected{};
|
|
|
|
// std::array<boo::DolphinControllerState, 4> 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<CFinalInput, 4> 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<boo::DolphinSmashAdapter> 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<boo::DolphinSmashAdapter>(tok.openAndGetDevice());
|
|
|
|
// smashAdapter->setCallback(&m_dolphinCb);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) override {
|
|
|
|
// if (smashAdapter.get() == device)
|
|
|
|
// smashAdapter.reset();
|
|
|
|
// }
|
2018-12-08 05:30:43 +00:00
|
|
|
void SetMotorState(EIOPort port, EMotorState state) {
|
2022-02-08 01:48:08 +00:00
|
|
|
// TODO aurora
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2020-03-18 03:23:13 +00:00
|
|
|
void ControlAllMotors(const std::array<EMotorState, 4>& states) {
|
2022-02-08 01:48:08 +00:00
|
|
|
// TODO aurora
|
2018-12-08 05:30:43 +00:00
|
|
|
}
|
2015-08-29 01:30:47 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
/* This is where the game thread enters */
|
|
|
|
void Update(float dt, CArchitectureQueue& queue);
|
2021-05-30 07:52:20 +00:00
|
|
|
CFinalInput GetLastInput() const { return m_lastUpdate; }
|
2015-08-18 05:54:43 +00:00
|
|
|
};
|
|
|
|
|
2021-04-10 08:42:06 +00:00
|
|
|
} // namespace metaforce
|