mirror of https://github.com/AxioDL/metaforce.git
Migrate to new CInputGenerator and rename old
This commit is contained in:
parent
9804543327
commit
42dde9187b
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <magic_enum.hpp>
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -1,162 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#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<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; }
|
||||
struct COsContext {
|
||||
bool GetOsKeyState(int key) { return false; }
|
||||
};
|
||||
|
||||
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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -69,17 +69,18 @@ void CRumbleGenerator::Update(float dt) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (updated)
|
||||
g_InputGenerator->ControlAllMotors(xe0_commandArray);
|
||||
if (updated) {
|
||||
PADControlAllMotors(reinterpret_cast<const u32*>(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<const u32*>(HardStopCommands.data()));
|
||||
}
|
||||
|
||||
s16 CRumbleGenerator::Rumble(const SAdsrData& adsr, float gain, ERumblePriority prio, EIOPort port) {
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<CMain*>(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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue