Migrate to new CInputGenerator and rename old

This commit is contained in:
Phillip Stephens 2022-03-22 12:04:57 -07:00
parent 9804543327
commit 42dde9187b
Signed by: Antidote
GPG Key ID: F8BEE4C83DACA60D
15 changed files with 406 additions and 383 deletions

View File

@ -316,7 +316,7 @@ public:
if (auto* input = g_InputGenerator) { if (auto* input = g_InputGenerator) {
if (!m_deferredControllers.empty()) { if (!m_deferredControllers.empty()) {
for (const auto which : m_deferredControllers) { for (const auto which : m_deferredControllers) {
input->controllerAdded(which); //input->controllerAdded(which);
} }
m_deferredControllers.clear(); m_deferredControllers.clear();
} }
@ -432,19 +432,19 @@ public:
void onControllerButton(uint32_t idx, aurora::ControllerButton button, bool pressed) noexcept override { void onControllerButton(uint32_t idx, aurora::ControllerButton button, bool pressed) noexcept override {
if (auto* input = g_InputGenerator) { 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 { void onControllerAxis(uint32_t idx, aurora::ControllerAxis axis, int16_t value) noexcept override {
if (auto* input = g_InputGenerator) { if (auto* input = g_InputGenerator) {
input->controllerAxis(idx, axis, value); //input->controllerAxis(idx, axis, value);
} }
} }
void onControllerAdded(uint32_t which) noexcept override { void onControllerAdded(uint32_t which) noexcept override {
if (auto* input = g_InputGenerator) { if (auto* input = g_InputGenerator) {
input->controllerAdded(which); //input->controllerAdded(which);
} else { } else {
m_deferredControllers.emplace_back(which); m_deferredControllers.emplace_back(which);
} }
@ -452,7 +452,7 @@ public:
void onControllerRemoved(uint32_t which) noexcept override { void onControllerRemoved(uint32_t which) noexcept override {
if (auto* input = g_InputGenerator) { if (auto* input = g_InputGenerator) {
input->controllerRemoved(which); //input->controllerRemoved(which);
} }
} }

View File

@ -17,6 +17,7 @@ class CCubeRenderer* g_Renderer = nullptr;
class CStringTable* g_MainStringTable = nullptr; class CStringTable* g_MainStringTable = nullptr;
class CTextureCache* g_TextureCache = nullptr; class CTextureCache* g_TextureCache = nullptr;
class CInputGenerator* g_InputGenerator = nullptr; class CInputGenerator* g_InputGenerator = nullptr;
class IController* g_Controller = nullptr;
class CStateManager* g_StateManager = nullptr; class CStateManager* g_StateManager = nullptr;
ITweakGame* g_tweakGame = nullptr; ITweakGame* g_tweakGame = nullptr;

View File

@ -54,6 +54,7 @@ extern class CCubeRenderer* g_Renderer;
extern class CStringTable* g_MainStringTable; extern class CStringTable* g_MainStringTable;
extern class CTextureCache* g_TextureCache; extern class CTextureCache* g_TextureCache;
extern class CInputGenerator* g_InputGenerator; extern class CInputGenerator* g_InputGenerator;
extern class IController* g_Controller;
extern class CStateManager* g_StateManager; extern class CStateManager* g_StateManager;
#if USE_DOWNCAST_TWEAKS #if USE_DOWNCAST_TWEAKS

View File

@ -1,131 +1,52 @@
#include "Runtime/Input/CInputGenerator.hpp" #include "Runtime/Input/CInputGenerator.hpp"
#include "Runtime/CArchitectureMessage.hpp" #include "Runtime/Input/IController.hpp"
#include "Runtime/Input/CFinalInput.hpp"
#include "Runtime/CArchitectureQueue.hpp" #include "Runtime/CArchitectureQueue.hpp"
#include <magic_enum.hpp>
namespace metaforce { 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) { 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 #if 0
auto input = CFinalInput(idx, dt, m_data, m_lastUpdate); if (!x0_context.Update()) {
// Merge controller input with kb/m input return;
auto state = m_state[idx]; }
state.clamp();
input |= CFinalInput(idx, dt, state, m_lastUpdate, m_leftDiv, m_rightDiv);
m_lastUpdate = input;
#endif #endif
return m_lastUpdate;
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;
} }
} // namespace metaforce 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

View File

@ -0,0 +1,131 @@
#include "Runtime/Input/CInputGenerator.hpp"
#include "Runtime/CArchitectureMessage.hpp"
#include "Runtime/CArchitectureQueue.hpp"
#include <magic_enum.hpp>
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

View File

@ -1,162 +1,32 @@
#pragma once #pragma once
#include <array> #include <memory>
#include <atomic>
#include <mutex>
#include "Runtime/Input/InputTypes.hpp" #include "Runtime/Input/IController.hpp"
#include "Runtime/Input/CFinalInput.hpp" #include "Runtime/Input/CFinalInput.hpp"
#include "Runtime/Input/CKeyboardMouseController.hpp"
namespace metaforce { namespace metaforce {
class CArchitectureQueue; struct COsContext {
bool GetOsKeyState(int key) { return false; }
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<SAuroraControllerState, 4> 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<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();
// }
void SetMotorState(EIOPort port, EMotorState state);
void ControlAllMotors(const std::array<EMotorState, 4>& 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; }
}; };
class CArchitectureQueue;
class CInputGenerator {
// COsContext& x0_context;
std::unique_ptr<IController> x4_controller;
std::array<bool, 4> 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 } // namespace metaforce

View File

@ -0,0 +1,162 @@
#pragma once
#include <array>
#include <atomic>
#include <mutex>
#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<SAuroraControllerState, 4> 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<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();
// }
void SetMotorState(EIOPort port, EMotorState state);
void ControlAllMotors(const std::array<EMotorState, 4>& 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

View File

@ -7,7 +7,6 @@ set(INPUT_SOURCES
CDolphinController.hpp CDolphinController.cpp CDolphinController.hpp CDolphinController.cpp
CKeyboardMouseController.hpp CKeyboardMouseController.hpp
ControlMapper.hpp ControlMapper.cpp ControlMapper.hpp ControlMapper.cpp
NewCInputGenerator.hpp NewCInputGenerator.cpp
CInputGenerator.hpp CInputGenerator.cpp CInputGenerator.hpp CInputGenerator.cpp
CFinalInput.hpp CFinalInput.cpp CFinalInput.hpp CFinalInput.cpp
CRumbleManager.hpp CRumbleManager.cpp CRumbleManager.hpp CRumbleManager.cpp

View File

@ -69,17 +69,18 @@ void CRumbleGenerator::Update(float dt) {
} }
} }
} }
if (updated) if (updated) {
g_InputGenerator->ControlAllMotors(xe0_commandArray); PADControlAllMotors(reinterpret_cast<const u32*>(xe0_commandArray.data()));
}
} }
} }
void CRumbleGenerator::HardStopAll() { void CRumbleGenerator::HardStopAll() {
static constexpr std::array HardStopCommands{ static constexpr std::array HardStopCommands{
EMotorState::StopHard, (u32)EMotorState::StopHard,
EMotorState::StopHard, (u32)EMotorState::StopHard,
EMotorState::StopHard, (u32)EMotorState::StopHard,
EMotorState::StopHard, (u32)EMotorState::StopHard,
}; };
xc0_periodTime.fill(0.0f); xc0_periodTime.fill(0.0f);
@ -89,7 +90,8 @@ void CRumbleGenerator::HardStopAll() {
voice.HardReset(); voice.HardReset();
} }
g_InputGenerator->ControlAllMotors(HardStopCommands); // TODO(phil): switch this to g_InputGenerator->GetContoller()->SetMotorState?
PADControlAllMotors(static_cast<const u32*>(HardStopCommands.data()));
} }
s16 CRumbleGenerator::Rumble(const SAdsrData& adsr, float gain, ERumblePriority prio, EIOPort port) { s16 CRumbleGenerator::Rumble(const SAdsrData& adsr, float gain, ERumblePriority prio, EIOPort port) {

View File

@ -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

View File

@ -1,32 +0,0 @@
#pragma once
#include <memory>
#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<IController> 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

View File

@ -15,6 +15,7 @@
#include "Runtime/GuiSys/CGuiModel.hpp" #include "Runtime/GuiSys/CGuiModel.hpp"
#include "Runtime/GuiSys/CGuiWidgetDrawParms.hpp" #include "Runtime/GuiSys/CGuiWidgetDrawParms.hpp"
#include "Runtime/Input/CInputGenerator.hpp" #include "Runtime/Input/CInputGenerator.hpp"
#include "Runtime/Input/IController.hpp"
#include "Runtime/MP1/CSamusHud.hpp" #include "Runtime/MP1/CSamusHud.hpp"
#include "Runtime/Particle/CGenDescription.hpp" #include "Runtime/Particle/CGenDescription.hpp"
#include "Runtime/World/CPlayer.hpp" #include "Runtime/World/CPlayer.hpp"
@ -629,7 +630,7 @@ void CInGameGuiManager::ShowPauseGameHudMessage(CStateManager& stateMgr, CAssetI
} }
void CInGameGuiManager::PauseGame(CStateManager& stateMgr, EInGameGuiState state) { 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); CSfxManager::SetChannel(CSfxManager::ESfxChannels::PauseScreen);
BeginStateTransition(state, stateMgr); BeginStateTransition(state, stateMgr);
} }

View File

@ -94,12 +94,12 @@ CGameArchitectureSupport::CGameArchitectureSupport(CMain& parent, boo::IAudioVoi
amuse::IBackendVoiceAllocator& backend) amuse::IBackendVoiceAllocator& backend)
: m_parent(parent) : m_parent(parent)
, x0_audioSys(voiceEngine, backend, 0, 0, 0, 0, 0) , x0_audioSys(voiceEngine, backend, 0, 0, 0, 0, 0)
, x30_newInputGenerator(/*osCtx, */ g_tweakPlayer->GetLeftLogicalThreshold(), g_tweakPlayer->GetRightLogicalThreshold()) , x30_inputGenerator(/*osCtx, */ g_tweakPlayer->GetLeftLogicalThreshold(), g_tweakPlayer->GetRightLogicalThreshold())
, x30_inputGenerator(g_tweakPlayer->GetLeftLogicalThreshold(), g_tweakPlayer->GetRightLogicalThreshold())
, x44_guiSys(*g_ResFactory, *g_SimplePool, CGuiSys::EUsageMode::Zero) { , x44_guiSys(*g_ResFactory, *g_SimplePool, CGuiSys::EUsageMode::Zero) {
auto* m = static_cast<CMain*>(g_Main); auto* m = static_cast<CMain*>(g_Main);
g_InputGenerator = &x30_inputGenerator; g_InputGenerator = &x30_inputGenerator;
g_Controller = x30_inputGenerator.GetController();
CAudioSys::SysSetVolume(0x7f); CAudioSys::SysSetVolume(0x7f);
CAudioSys::SetDefaultVolumeScale(0x75); CAudioSys::SetDefaultVolumeScale(0x75);
@ -136,8 +136,7 @@ void CGameArchitectureSupport::UpdateTicks(float dt) {
void CGameArchitectureSupport::Update(float dt) { void CGameArchitectureSupport::Update(float dt) {
g_GameState->GetWorldTransitionManager()->TouchModels(); 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)); x4_archQueue.Push(MakeMsg::CreateFrameEnd(EArchMsgTarget::Game, x78_gameFrameCount));
x58_ioWinManager.PumpMessages(x4_archQueue); x58_ioWinManager.PumpMessages(x4_archQueue);
} }
@ -224,15 +223,15 @@ CGameArchitectureSupport::~CGameArchitectureSupport() {
} }
void CGameArchitectureSupport::charKeyDown(uint8_t charCode, aurora::ModifierKey mods, bool isRepeat) { 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) { 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) { 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) CMain::CMain(IFactory* resFactory, CSimplePool* resStore)

View File

@ -19,7 +19,6 @@
#include "Runtime/Particle/CGenDescription.hpp" #include "Runtime/Particle/CGenDescription.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp" #include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/Audio/CAudioSys.hpp" #include "Runtime/Audio/CAudioSys.hpp"
#include "Runtime/Input/NewCInputGenerator.hpp"
#include "Runtime/Input/CInputGenerator.hpp" #include "Runtime/Input/CInputGenerator.hpp"
#include "Runtime/GuiSys/CGuiSys.hpp" #include "Runtime/GuiSys/CGuiSys.hpp"
#include "Runtime/CIOWinManager.hpp" #include "Runtime/CIOWinManager.hpp"
@ -116,7 +115,6 @@ class CGameArchitectureSupport {
CMain& m_parent; CMain& m_parent;
CArchitectureQueue x4_archQueue; CArchitectureQueue x4_archQueue;
CAudioSys x0_audioSys; CAudioSys x0_audioSys;
WIP::CInputGenerator x30_newInputGenerator;
CInputGenerator x30_inputGenerator; CInputGenerator x30_inputGenerator;
CGuiSys x44_guiSys; CGuiSys x44_guiSys;
CIOWinManager x58_ioWinManager; CIOWinManager x58_ioWinManager;
@ -141,20 +139,30 @@ public:
~CGameArchitectureSupport(); ~CGameArchitectureSupport();
void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) { 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) { 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 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 specialKeyDown(aurora::SpecialKey key, aurora::ModifierKey mods, bool isRepeat);
void specialKeyUp(aurora::SpecialKey key, aurora::ModifierKey mods); void specialKeyUp(aurora::SpecialKey key, aurora::ModifierKey mods);
void modKeyDown(aurora::ModifierKey mod, bool isRepeat) { x30_inputGenerator.modKeyDown(mod, isRepeat); } void modKeyDown(aurora::ModifierKey mod, bool isRepeat) {
void modKeyUp(aurora::ModifierKey mod) { x30_inputGenerator.modKeyUp(mod); } // x30_inputGenerator.modKeyDown(mod, isRepeat);
}
void modKeyUp(aurora::ModifierKey mod) {
// x30_inputGenerator.modKeyUp(mod);
}
void PreloadAudio(); void PreloadAudio();
bool LoadAudio(); bool LoadAudio();

View File

@ -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) { void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min) {
s8 x = *px; s32 x = *px;
s8 y = *py; s32 y = *py;
s8 signX = 0; s32 signX = 0;
if (0 <= x) { if (0 <= x) {
signX = 1; signX = 1;
} else { } else {
@ -577,13 +577,13 @@ void ClampStick(s8* px, s8* py, s8 max, s8 xy, s8 min) {
} }
if (xy * y <= xy * x) { if (xy * y <= xy * x) {
s8 d = xy * x + (max - xy) * y; s32 d = xy * x + (max - xy) * y;
if (xy * max < d) { if (xy * max < d) {
x = (xy * max * x / d); x = (xy * max * x / d);
y = (xy * max * y / d); y = (xy * max * y / d);
} }
} else { } else {
s8 d = xy * y + (max - xy) * x; s32 d = xy * y + (max - xy) * x;
if (xy * max < d) { if (xy * max < d) {
x = (xy * max * x / d); x = (xy * max * x / d);
y = (xy * max * y / d); y = (xy * max * y / d);