diff --git a/DataSpec/DNACommon/CMakeLists.txt b/DataSpec/DNACommon/CMakeLists.txt index 924139334..ef3870c2a 100644 --- a/DataSpec/DNACommon/CMakeLists.txt +++ b/DataSpec/DNACommon/CMakeLists.txt @@ -9,4 +9,5 @@ add_library(DNACommon TXTR.hpp TXTR.cpp ANCS.hpp ANIM.hpp ANIM.cpp + Tweaks/ITweakPlayer.hpp Tweaks/ITweakPlayerControl.hpp) diff --git a/DataSpec/DNACommon/Tweaks/ITweakPlayer.hpp b/DataSpec/DNACommon/Tweaks/ITweakPlayer.hpp new file mode 100644 index 000000000..e65c7fc11 --- /dev/null +++ b/DataSpec/DNACommon/Tweaks/ITweakPlayer.hpp @@ -0,0 +1,17 @@ +#ifndef __DNACOMMON_ITWEAKPLAYER_HPP__ +#define __DNACOMMON_ITWEAKPLAYER_HPP__ + +#include "../DNACommon.hpp" + +namespace Retro +{ + +struct ITweakPlayer : BigYAML +{ + virtual float GetLeftLogicalThreshold() const=0; + virtual float GetRightLogicalThreshold() const=0; +}; + +} + +#endif // __DNACOMMON_ITWEAKPLAYER_HPP__ diff --git a/DataSpec/DNAMP1/CMakeLists.txt b/DataSpec/DNAMP1/CMakeLists.txt index 0aaa62983..b6a36f63b 100644 --- a/DataSpec/DNAMP1/CMakeLists.txt +++ b/DataSpec/DNAMP1/CMakeLists.txt @@ -10,6 +10,7 @@ make_dnalist(liblist CMDLMaterials MREA Tweaks/CTweakParticle + Tweaks/CTweakPlayer Tweaks/CTweakPlayerControl) add_library(DNAMP1 DNAMP1.hpp DNAMP1.cpp diff --git a/DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp new file mode 100644 index 000000000..8a0f85446 --- /dev/null +++ b/DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp @@ -0,0 +1,24 @@ +#ifndef _DNAMP1_CTWEAKPLAYER_HPP_ +#define _DNAMP1_CTWEAKPLAYER_HPP_ + +#include "../../DNACommon/Tweaks/ITweakPlayer.hpp" + +namespace Retro +{ +namespace DNAMP1 +{ + +struct CTweakPlayer : ITweakPlayer +{ + DECL_YAML + Value m_leftDiv; + Value m_rightDiv; + float GetLeftLogicalThreshold() const {return m_leftDiv;} + float GetRightLogicalThreshold() const {return m_rightDiv;} + CTweakPlayer(Athena::io::IStreamReader& reader) {this->read(reader);} +}; + +} +} + +#endif // _DNAMP1_CTWEAKPLAYER_HPP_ diff --git a/MathLib b/MathLib index 2e3512b80..151b0e633 160000 --- a/MathLib +++ b/MathLib @@ -1 +1 @@ -Subproject commit 2e3512b80098eb0c3facd4fd3ab6433fe424c4f7 +Subproject commit 151b0e63338a8f8645f908e48fb7423795224690 diff --git a/Runtime/CArchitectureMessage.hpp b/Runtime/CArchitectureMessage.hpp index 566dab2c0..32d047eea 100644 --- a/Runtime/CArchitectureMessage.hpp +++ b/Runtime/CArchitectureMessage.hpp @@ -11,7 +11,8 @@ class CIOWin; enum EArchMsgTarget { - TargetIOWinManager = 0 + TargetIOWinManager = 0, + TargetGame = 1 }; enum EArchMsgType diff --git a/Runtime/CIOWinManager.cpp b/Runtime/CIOWinManager.cpp index e84b74a14..9bf5011ae 100644 --- a/Runtime/CIOWinManager.cpp +++ b/Runtime/CIOWinManager.cpp @@ -1,5 +1,6 @@ #include "CIOWinManager.hpp" #include "CArchitectureMessage.hpp" +#include "CIOWin.hpp" namespace Retro { diff --git a/Runtime/GameGlobalObjects.hpp b/Runtime/GameGlobalObjects.hpp index bfedb4a6a..36a37ca8d 100644 --- a/Runtime/GameGlobalObjects.hpp +++ b/Runtime/GameGlobalObjects.hpp @@ -13,6 +13,7 @@ extern class CGameState* g_GameState; extern class CInGameTweakManagerBase* g_TweakManager; extern class CBooRenderer* g_Renderer; +extern class ITweakPlayer* g_tweakPlayer; extern class ITweakPlayerControl* g_tweakPlayerControl; } diff --git a/Runtime/Input/CDolphinController.hpp b/Runtime/Input/CDolphinController.hpp deleted file mode 100644 index 8b19a3174..000000000 --- a/Runtime/Input/CDolphinController.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __RETRO_CDOLPHINCONTROLLER_HPP__ -#define __RETRO_CDOLPHINCONTROLLER_HPP__ - -#include "IController.hpp" - -namespace Retro -{ - -class CDolphinController : public IController -{ -}; - -} - -#endif // __RETRO_CDOLPHINCONTROLLER_HPP__ diff --git a/Runtime/Input/CFinalInput.cpp b/Runtime/Input/CFinalInput.cpp index fd451d810..d665761e9 100644 --- a/Runtime/Input/CFinalInput.cpp +++ b/Runtime/Input/CFinalInput.cpp @@ -1,8 +1,250 @@ +#include #include "CFinalInput.hpp" namespace Retro { +CFinalInput::CFinalInput() +: x0_dt(0.0), + x4_controllerIdx(0), + x8_anaLeftX(0.0), + xc_anaLeftY(0.0), + x10_anaRightX(0.0), + x14_anaRightY(0.0), + x18_anaLeftTrigger(0.0), + x1c_anaRightTrigger(0.0), + x20_enableAnaLeftXP(false), + x20_enableAnaLeftNegXP(false), + x21_enableAnaLeftYP(false), + x21_enableAnaLeftNegYP(false), + x22_enableAnaRightXP(false), + x22_enableAnaRightNegXP(false), + x23_enableAnaRightYP(false), + x23_enableAnaRightNegYP(false), + x24_anaLeftTriggerP(false), + x28_anaRightTriggerP(false), + x2c_b24_A(false), + x2c_b25_B(false), + x2c_b26_X(false), + x2c_b27_Y(false), + x2c_b28_Z(false), + x2c_b29_L(false), + x2c_b30_R(false), + x2c_b31_DPUp(false), + x2d_b24_DPRight(false), + x2d_b25_DPDown(false), + x2d_b26_DPLeft(false), + x2d_b27_Start(false), + x2d_b28_PA(false), + x2d_b29_PB(false), + x2d_b30_PX(false), + x2d_b31_PY(false), + x2e_b24_PZ(false), + x2e_b25_PL(false), + x2e_b26_PR(false), + x2e_b27_PDPUp(false), + x2e_b28_PDPRight(false), + x2e_b29_PDPDown(false), + x2e_b30_PDPLeft(false), + x2e_b31_PStart(false) {} +CFinalInput::CFinalInput(int cIdx, float dt, + const boo::DolphinControllerState& data, + const CFinalInput& prevInput, + float leftDiv, float rightDiv) +: x0_dt(dt), + x4_controllerIdx(cIdx), + x8_anaLeftX(Math::clamp(-1.0, data.m_leftStick[0] / 72.0 / leftDiv, 1.0)), + xc_anaLeftY(Math::clamp(-1.0, data.m_leftStick[1] / 72.0 / leftDiv, 1.0)), + x10_anaRightX(Math::clamp(-1.0, data.m_rightStick[0] / 59.0 / rightDiv, 1.0)), + x14_anaRightY(Math::clamp(-1.0, data.m_rightStick[0] / 59.0 / rightDiv, 1.0)), + x18_anaLeftTrigger(data.m_analogTriggers[0] * 0.0066666668), + x1c_anaRightTrigger(data.m_analogTriggers[1] * 0.0066666668), + x20_enableAnaLeftXP(DLARight() && !prevInput.DLARight()), + x20_enableAnaLeftNegXP(DLALeft() && !prevInput.DLALeft()), + x21_enableAnaLeftYP(DLAUp() && !prevInput.DLAUp()), + x21_enableAnaLeftNegYP(DLADown() && !prevInput.DLADown()), + x22_enableAnaRightXP(DRARight() && !prevInput.DRARight()), + x22_enableAnaRightNegXP(DRALeft() && !prevInput.DRALeft()), + x23_enableAnaRightYP(DRAUp() && !prevInput.DRAUp()), + x23_enableAnaRightNegYP(DRADown() && !prevInput.DRADown()), + x24_anaLeftTriggerP(DLTrigger() && !prevInput.DLTrigger()), + x28_anaRightTriggerP(DRTrigger() && !prevInput.DRTrigger()), + x2c_b24_A(data.m_btns & boo::DOL_A), + x2c_b25_B(data.m_btns & boo::DOL_B), + x2c_b26_X(data.m_btns & boo::DOL_X), + x2c_b27_Y(data.m_btns & boo::DOL_Y), + x2c_b28_Z(data.m_btns & boo::DOL_Z), + x2c_b29_L(data.m_btns & boo::DOL_L), + x2c_b30_R(data.m_btns & boo::DOL_R), + x2c_b31_DPUp(data.m_btns & boo::DOL_UP), + x2d_b24_DPRight(data.m_btns & boo::DOL_RIGHT), + x2d_b25_DPDown(data.m_btns & boo::DOL_DOWN), + x2d_b26_DPLeft(data.m_btns & boo::DOL_LEFT), + x2d_b27_Start(data.m_btns & boo::DOL_START), + x2d_b28_PA(DA() && !prevInput.DA()), + x2d_b29_PB(DB() && !prevInput.DB()), + x2d_b30_PX(DX() && !prevInput.DX()), + x2d_b31_PY(DY() && !prevInput.DY()), + x2e_b24_PZ(DZ() && !prevInput.DZ()), + x2e_b25_PL(DL() && !prevInput.DL()), + x2e_b26_PR(DR() && !prevInput.DR()), + x2e_b27_PDPUp(DDPUp() && !prevInput.DDPUp()), + x2e_b28_PDPRight(DDPRight() && !prevInput.DDPRight()), + x2e_b29_PDPDown(DDPDown() && !prevInput.DDPDown()), + x2e_b30_PDPLeft(DDPLeft() && !prevInput.DDPLeft()), + x2e_b31_PStart(DStart() && !prevInput.DStart()) {} + +static float KBToAnaLeftX(const CKeyboardMouseControllerData& data) +{ + float retval = 0.0; + if (data.m_charKeys['a']) + retval -= 1.0; + if (data.m_charKeys['d']) + retval += 1.0; + return retval; +} + +static float KBToAnaLeftY(const CKeyboardMouseControllerData& data) +{ + float retval = 0.0; + if (data.m_charKeys['s']) + retval -= 1.0; + if (data.m_charKeys['w']) + retval += 1.0; + return retval; +} + +static float KBToAnaRightX(const CKeyboardMouseControllerData& data) +{ + float retval = 0.0; + if (data.m_charKeys['2']) + retval -= 1.0; + if (data.m_charKeys['4']) + retval += 1.0; + return retval; +} + +static float KBToAnaRightY(const CKeyboardMouseControllerData& data) +{ + float retval = 0.0; + if (data.m_charKeys['3']) + retval -= 1.0; + if (data.m_charKeys['1']) + retval += 1.0; + return retval; +} + +CFinalInput::CFinalInput(int cIdx, float dt, + const CKeyboardMouseControllerData& data, + const CFinalInput& prevInput) +: x0_dt(dt), + x4_controllerIdx(cIdx), + x8_anaLeftX(KBToAnaLeftX(data)), + xc_anaLeftY(KBToAnaLeftY(data)), + x10_anaRightX(KBToAnaRightX(data)), + x14_anaRightY(KBToAnaRightY(data)), + x18_anaLeftTrigger(data.m_charKeys['q'] ? 1.0 : 0.0), + x1c_anaRightTrigger(data.m_charKeys['e'] ? 1.0 : 0.0), + x20_enableAnaLeftXP(DLARight() && !prevInput.DLARight()), + x20_enableAnaLeftNegXP(DLALeft() && !prevInput.DLALeft()), + x21_enableAnaLeftYP(DLAUp() && !prevInput.DLAUp()), + x21_enableAnaLeftNegYP(DLADown() && !prevInput.DLADown()), + x22_enableAnaRightXP(DRARight() && !prevInput.DRARight()), + x22_enableAnaRightNegXP(DRALeft() && !prevInput.DRALeft()), + x23_enableAnaRightYP(DRAUp() && !prevInput.DRAUp()), + x23_enableAnaRightNegYP(DRADown() && !prevInput.DRADown()), + x24_anaLeftTriggerP(DLTrigger() && !prevInput.DLTrigger()), + x28_anaRightTriggerP(DRTrigger() && !prevInput.DRTrigger()), + x2c_b24_A(data.m_mouseButtons[boo::IWindowCallback::BUTTON_PRIMARY]), + x2c_b25_B(data.m_charKeys[' ']), + x2c_b26_X(data.m_charKeys['c']), + x2c_b27_Y(data.m_mouseButtons[boo::IWindowCallback::BUTTON_SECONDARY]), + x2c_b28_Z(data.m_charKeys['\t']), + x2c_b29_L(data.m_charKeys['q']), + x2c_b30_R(data.m_charKeys['e']), + x2c_b31_DPUp(data.m_specialKeys[boo::IWindowCallback::KEY_UP]), + x2d_b24_DPRight(data.m_specialKeys[boo::IWindowCallback::KEY_RIGHT]), + x2d_b25_DPDown(data.m_specialKeys[boo::IWindowCallback::KEY_DOWN]), + x2d_b26_DPLeft(data.m_specialKeys[boo::IWindowCallback::KEY_LEFT]), + x2d_b27_Start(data.m_specialKeys[boo::IWindowCallback::KEY_ESC]), + x2d_b28_PA(DA() && !prevInput.DA()), + x2d_b29_PB(DB() && !prevInput.DB()), + x2d_b30_PX(DX() && !prevInput.DX()), + x2d_b31_PY(DY() && !prevInput.DY()), + x2e_b24_PZ(DZ() && !prevInput.DZ()), + x2e_b25_PL(DL() && !prevInput.DL()), + x2e_b26_PR(DR() && !prevInput.DR()), + x2e_b27_PDPUp(DDPUp() && !prevInput.DDPUp()), + x2e_b28_PDPRight(DDPRight() && !prevInput.DDPRight()), + x2e_b29_PDPDown(DDPDown() && !prevInput.DDPDown()), + x2e_b30_PDPLeft(DDPLeft() && !prevInput.DDPLeft()), + x2e_b31_PStart(DStart() && !prevInput.DStart()) +{ + if (x8_anaLeftX || xc_anaLeftY) + { + float len = sqrtf(x8_anaLeftX * x8_anaLeftX + xc_anaLeftY * xc_anaLeftY); + x8_anaLeftX /= len; + xc_anaLeftY /= len; + } + if (x10_anaRightX || x14_anaRightY) + { + float len = sqrtf(x10_anaRightX * x10_anaRightX + x14_anaRightY * x14_anaRightY); + x10_anaRightX /= len; + x14_anaRightY /= len; + } +} + +CFinalInput& CFinalInput::operator|=(const CFinalInput& other) +{ + if (fabsf(other.x8_anaLeftX) > fabsf(x8_anaLeftX)) + x8_anaLeftX = other.x8_anaLeftX; + if (fabsf(other.xc_anaLeftY) > fabsf(xc_anaLeftY)) + xc_anaLeftY = other.xc_anaLeftY; + if (fabsf(other.x10_anaRightX) > fabsf(x10_anaRightX)) + x10_anaRightX = other.x10_anaRightX; + if (fabsf(other.x14_anaRightY) > fabsf(x14_anaRightY)) + x14_anaRightY = other.x14_anaRightY; + if (fabsf(other.x18_anaLeftTrigger) > fabsf(x18_anaLeftTrigger)) + x18_anaLeftTrigger = other.x18_anaLeftTrigger; + if (fabsf(other.x1c_anaRightTrigger) > fabsf(x1c_anaRightTrigger)) + x1c_anaRightTrigger = other.x1c_anaRightTrigger; + x20_enableAnaLeftXP |= other.x20_enableAnaLeftXP; + x20_enableAnaLeftNegXP |= other.x20_enableAnaLeftNegXP; + x21_enableAnaLeftYP |= other.x21_enableAnaLeftYP; + x21_enableAnaLeftNegYP |= other.x21_enableAnaLeftNegYP; + x22_enableAnaRightXP |= other.x22_enableAnaRightXP; + x22_enableAnaRightNegXP |= other.x22_enableAnaRightNegXP; + x23_enableAnaRightYP |= other.x23_enableAnaRightYP; + x23_enableAnaRightNegYP |= other.x23_enableAnaRightNegYP; + x24_anaLeftTriggerP |= other.x24_anaLeftTriggerP; + x28_anaRightTriggerP |= other.x28_anaRightTriggerP; + x2c_b24_A |= other.x2c_b24_A; + x2c_b25_B |= other.x2c_b25_B; + x2c_b26_X |= other.x2c_b26_X; + x2c_b27_Y |= other.x2c_b27_Y; + x2c_b28_Z |= other.x2c_b28_Z; + x2c_b29_L |= other.x2c_b29_L; + x2c_b30_R |= other.x2c_b30_R; + x2c_b31_DPUp |= other.x2c_b31_DPUp; + x2d_b24_DPRight |= other.x2d_b24_DPRight; + x2d_b25_DPDown |= other.x2d_b25_DPDown; + x2d_b26_DPLeft |= other.x2d_b26_DPLeft; + x2d_b27_Start |= other.x2d_b27_Start; + x2d_b28_PA |= other.x2d_b28_PA; + x2d_b29_PB |= other.x2d_b29_PB; + x2d_b30_PX |= other.x2d_b30_PX; + x2d_b31_PY |= other.x2d_b31_PY; + x2e_b24_PZ |= other.x2e_b24_PZ; + x2e_b25_PL |= other.x2e_b25_PL; + x2e_b26_PR |= other.x2e_b26_PR; + x2e_b27_PDPUp |= other.x2e_b27_PDPUp; + x2e_b28_PDPRight |= other.x2e_b28_PDPRight; + x2e_b29_PDPDown |= other.x2e_b29_PDPDown; + x2e_b30_PDPLeft |= other.x2e_b30_PDPLeft; + x2e_b31_PStart |= other.x2e_b31_PStart; + return *this; +} + } diff --git a/Runtime/Input/CFinalInput.hpp b/Runtime/Input/CFinalInput.hpp index 137b60cc6..2b4adb13d 100644 --- a/Runtime/Input/CFinalInput.hpp +++ b/Runtime/Input/CFinalInput.hpp @@ -2,6 +2,8 @@ #define __RETRO_CFINALINPUT_HPP__ #include "../RetroTypes.hpp" +#include "CKeyboardMouseController.hpp" +#include namespace Retro { @@ -16,12 +18,23 @@ class CFinalInput float x14_anaRightY; float x18_anaLeftTrigger; float x1c_anaRightTrigger; - bool x20_enableAnaLeftXP; - bool x21_enableAnaLeftYP; - bool x22_enableAnaRightXP; - bool x23_enableAnaRightYP; - float x24_anaLeftTriggerP; - float x28_anaRightTriggerP; + + /* These were originally per-axis bools, requiring two logical tests + * at read-time; now they're logical cardinal-direction states + * (negative values indicated) */ + bool x20_enableAnaLeftXP:1; + bool x20_enableAnaLeftNegXP:1; + bool x21_enableAnaLeftYP:1; + bool x21_enableAnaLeftNegYP:1; + bool x22_enableAnaRightXP:1; + bool x22_enableAnaRightNegXP:1; + bool x23_enableAnaRightYP:1; + bool x23_enableAnaRightNegYP:1; + + /* These were originally redundantly-compared floats; + * now the logical state is stored directly */ + bool x24_anaLeftTriggerP:1; + bool x28_anaRightTriggerP:1; bool x2c_b24_A:1; bool x2c_b25_B:1; @@ -50,6 +63,16 @@ class CFinalInput bool x2e_b31_PStart:1; public: + CFinalInput(); + CFinalInput(int cIdx, float dt, + const boo::DolphinControllerState& data, + const CFinalInput& prevInput, + float leftDiv, float rightDiv); + CFinalInput(int cIdx, float dt, + const CKeyboardMouseControllerData& data, + const CFinalInput& prevInput); + CFinalInput& operator|=(const CFinalInput& other); + bool PStart() const {return x2e_b31_PStart;} bool PR() const {return x2e_b26_PR;} bool PL() const {return x2e_b25_PL;} @@ -62,16 +85,16 @@ public: bool PDPLeft() const {return x2e_b30_PDPLeft;} bool PDPDown() const {return x2e_b29_PDPDown;} bool PDPUp() const {return x2e_b27_PDPUp;} - bool PRTrigger() const {return x28_anaRightTriggerP > 0.050000001;} - bool PLTrigger() const {return x24_anaLeftTriggerP > 0.050000001;} - bool PRARight() const {return x22_enableAnaRightXP && x10_anaRightX > 0.69999999;} - bool PRALeft() const {return x22_enableAnaRightXP && x10_anaRightX < -0.69999999;} - bool PRADown() const {return x23_enableAnaRightYP && x14_anaRightY < -0.69999999;} - bool PRAUp() const {return x23_enableAnaRightYP && x14_anaRightY > 0.69999999;} - bool PLARight() const {return x20_enableAnaLeftXP && x8_anaLeftX > 0.69999999;} - bool PLALeft() const {return x20_enableAnaLeftXP && x8_anaLeftX < -0.69999999;} - bool PLADown() const {return x21_enableAnaLeftYP && xc_anaLeftY < -0.69999999;} - bool PLAUp() const {return x21_enableAnaLeftYP && xc_anaLeftY > 0.69999999;} + bool PRTrigger() const {return x28_anaRightTriggerP;} + bool PLTrigger() const {return x24_anaLeftTriggerP;} + bool PRARight() const {return x22_enableAnaRightXP;} + bool PRALeft() const {return x22_enableAnaRightNegXP;} + bool PRADown() const {return x23_enableAnaRightNegYP;} + bool PRAUp() const {return x23_enableAnaRightYP;} + bool PLARight() const {return x20_enableAnaLeftXP;} + bool PLALeft() const {return x20_enableAnaLeftNegXP;} + bool PLADown() const {return x21_enableAnaLeftNegYP;} + bool PLAUp() const {return x21_enableAnaLeftYP;} bool DStart() const {return x2d_b27_Start;} bool DR() const {return x2c_b30_R;} bool DL() const {return x2c_b29_L;} diff --git a/Runtime/Input/CInputGenerator.cpp b/Runtime/Input/CInputGenerator.cpp index cefa0ff3c..5e321d9ee 100644 --- a/Runtime/Input/CInputGenerator.cpp +++ b/Runtime/Input/CInputGenerator.cpp @@ -1,8 +1,38 @@ #include "CInputGenerator.hpp" +#include "../CArchitectureMessage.hpp" +#include "../CArchitectureQueue.hpp" namespace Retro { +void CInputGenerator::Update(float dt, CArchitectureQueue& queue) +{ + /* Keyboard/Mouse first */ + CFinalInput kbInput = m_windowCb.getFinalInput(0, dt); + bool kbUsed = false; + /* Dolphin controllers next */ + for (int i=0 ; i<4 ; ++i) + { + bool connected; + EStatusChange change = m_dolphinCb.getStatusChange(i, connected); + if (change) + queue.Push(std::move(MakeMsg::CreateControllerStatus(TargetGame, 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; + } + queue.Push(std::move(MakeMsg::CreateUserInput(TargetGame, input))); + } + } + + /* Send straight keyboard input if no first controller present */ + if (!kbUsed) + queue.Push(std::move(MakeMsg::CreateUserInput(TargetGame, kbInput))); +} } diff --git a/Runtime/Input/CInputGenerator.hpp b/Runtime/Input/CInputGenerator.hpp index 6aee98da8..f2e94f502 100644 --- a/Runtime/Input/CInputGenerator.hpp +++ b/Runtime/Input/CInputGenerator.hpp @@ -1,114 +1,181 @@ #ifndef __RETRO_CINPUTGENERATOR_HPP__ #define __RETRO_CINPUTGENERATOR_HPP__ +#include #include +#include "CFinalInput.hpp" +#include "CKeyboardMouseController.hpp" namespace Retro { +class CArchitectureQueue; - - -class CInputGenerator +class CInputGenerator : public boo::DeviceFinder { + enum EStatusChange + { + StatusNoChange = 0, + StatusConnected = 1, + StatusDisconnected = 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; +public: + CInputGenerator(float leftDiv, float rightDiv) + : boo::DeviceFinder({typeid(boo::DolphinSmashAdapter)}), + m_leftDiv(leftDiv), + m_rightDiv(rightDiv) {} + + /* 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. */ struct WindowCallback : boo::IWindowCallback { - void mouseDown(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + CKeyboardMouseControllerData m_data; + + void mouseDown(const SWindowCoord&, EMouseButton button, EModifierKey) { - fprintf(stderr, "Mouse Down %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]); + m_data.m_mouseButtons[button] = true; } - void mouseUp(const SWindowCoord& coord, EMouseButton button, EModifierKey mods) + void mouseUp(const SWindowCoord&, EMouseButton button, EModifierKey) { - fprintf(stderr, "Mouse Up %d (%f,%f)\n", button, coord.norm[0], coord.norm[1]); + m_data.m_mouseButtons[button] = false; } void mouseMove(const SWindowCoord& coord) { - //fprintf(stderr, "Mouse Move (%f,%f)\n", coord.norm[0], coord.norm[1]); + m_data.m_mouseCoord = coord; } - void scroll(const SWindowCoord& coord, const SScrollDelta& scroll) + void scroll(const SWindowCoord&, const SScrollDelta& scroll) { - fprintf(stderr, "Mouse Scroll (%f,%f) (%f,%f)\n", coord.norm[0], coord.norm[1], scroll.delta[0], scroll.delta[1]); + m_data.m_accumScroll += scroll; } - void touchDown(const STouchCoord& coord, uintptr_t tid) + void charKeyDown(unsigned long charCode, EModifierKey, bool) { - //fprintf(stderr, "Touch Down %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); - } - void touchUp(const STouchCoord& coord, uintptr_t tid) - { - //fprintf(stderr, "Touch Up %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); - } - void touchMove(const STouchCoord& coord, uintptr_t tid) - { - //fprintf(stderr, "Touch Move %16lX (%f,%f)\n", tid, coord.coord[0], coord.coord[1]); - } - - void charKeyDown(unsigned long charCode, EModifierKey mods, bool isRepeat) - { - + charCode = tolower(charCode); + if (charCode > 255) + return; + m_data.m_charKeys[charCode] = true; } void charKeyUp(unsigned long charCode, EModifierKey mods) { - + charCode = tolower(charCode); + if (charCode > 255) + return; + m_data.m_charKeys[charCode] = false; } - void specialKeyDown(ESpecialKey key, EModifierKey mods, bool isRepeat) + void specialKeyDown(ESpecialKey key, EModifierKey, bool) { - + m_data.m_specialKeys[key] = true; } - void specialKeyUp(ESpecialKey key, EModifierKey mods) + void specialKeyUp(ESpecialKey key, EModifierKey) { - + m_data.m_specialKeys[key] = false; } - void modKeyDown(EModifierKey mod, bool isRepeat) + void modKeyDown(EModifierKey mod, bool) { - + m_data.m_modMask = EModifierKey(m_data.m_modMask | mod); } void modKeyUp(EModifierKey mod) { - + m_data.m_modMask = EModifierKey(m_data.m_modMask & ~mod); } + void reset() + { + m_data.m_accumScroll.zeroOut(); + } + + CFinalInput m_lastUpdate; + const CFinalInput& getFinalInput(unsigned idx, float dt) + { + m_lastUpdate = CFinalInput(idx, dt, m_data, m_lastUpdate); + return m_lastUpdate; + } } m_windowCb; + /* 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::atomic m_statusChanges[4]; + bool m_connected[4] = {}; + boo::DolphinControllerState m_states[4]; + std::mutex m_stateLock; void controllerConnected(unsigned idx, boo::EDolphinControllerType) { - printf("CONTROLLER %u CONNECTED\n", idx); + /* Controller thread */ + m_statusChanges[idx].store(StatusConnected); } void controllerDisconnected(unsigned idx, boo::EDolphinControllerType) { - printf("CONTROLLER %u DISCONNECTED\n", idx); + /* Controller thread */ + std::unique_lock lk(m_stateLock); + m_statusChanges[idx].store(StatusDisconnected); + m_states[idx].reset(); } void controllerUpdate(unsigned idx, boo::EDolphinControllerType, const boo::DolphinControllerState& state) { - printf("CONTROLLER %u UPDATE %d %d\n", idx, state.m_leftStick[0], state.m_leftStick[1]); + /* Controller thread */ + std::unique_lock lk(m_stateLock); + m_states[idx] = state; } - }; - class ApplicationDeviceFinder : public boo::DeviceFinder + CFinalInput m_lastUpdates[4]; + 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(StatusNoChange); + if (ch == StatusConnected) + m_connected[idx] = true; + else if (ch == StatusDisconnected) + 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::unique_ptr smashAdapter = NULL; + void deviceConnected(boo::DeviceToken& tok) { - std::unique_ptr smashAdapter = NULL; - DolphinSmashAdapterCallback m_cb; - public: - ApplicationDeviceFinder() - : boo::DeviceFinder({typeid(boo::DolphinSmashAdapter)}) - {} - void deviceConnected(boo::DeviceToken& tok) + /* Device listener thread */ + if (!smashAdapter) { - if (!smashAdapter) - { - smashAdapter.reset(dynamic_cast(tok.openAndGetDevice())); - smashAdapter->setCallback(&m_cb); - smashAdapter->startRumble(0); - } + smashAdapter.reset(dynamic_cast(tok.openAndGetDevice())); + smashAdapter->setCallback(&m_dolphinCb); } - void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) - { - if (smashAdapter.get() == device) - smashAdapter.reset(nullptr); - } - }; + } + void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) + { + if (smashAdapter.get() == device) + smashAdapter.reset(nullptr); + } + + /* This is where the game thread enters */ + void Update(float dt, CArchitectureQueue& queue); }; diff --git a/Runtime/Input/CKeyboardController.hpp b/Runtime/Input/CKeyboardController.hpp deleted file mode 100644 index afe6a3c23..000000000 --- a/Runtime/Input/CKeyboardController.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __RETRO_CKEYBOARDCONTROLLER_HPP__ -#define __RETRO_CKEYBOARDCONTROLLER_HPP__ - -#include "IController.hpp" - -namespace Retro -{ - -class CKeyboardController : public IController -{ -}; - -} - -#endif // __RETRO_CKEYBOARDCONTROLLER_HPP__ diff --git a/Runtime/Input/CKeyboardMouseController.hpp b/Runtime/Input/CKeyboardMouseController.hpp new file mode 100644 index 000000000..df64fb068 --- /dev/null +++ b/Runtime/Input/CKeyboardMouseController.hpp @@ -0,0 +1,21 @@ +#ifndef __RETRO_CKEYBOARDMOUSECONTROLLER_HPP__ +#define __RETRO_CKEYBOARDMOUSECONTROLLER_HPP__ + +#include + +namespace Retro +{ + +struct CKeyboardMouseControllerData +{ + bool m_charKeys[256] = {}; + bool m_specialKeys[26] = {}; + bool m_mouseButtons[6] = {}; + boo::IWindowCallback::EModifierKey m_modMask = boo::IWindowCallback::MKEY_NONE; + boo::IWindowCallback::SWindowCoord m_mouseCoord; + boo::IWindowCallback::SScrollDelta m_accumScroll; +}; + +} + +#endif // __RETRO_CKEYBOARDMOUSECONTROLLER_HPP__ diff --git a/Runtime/Input/CMakeLists.txt b/Runtime/Input/CMakeLists.txt index 1f2785db8..a09f2b6e2 100644 --- a/Runtime/Input/CMakeLists.txt +++ b/Runtime/Input/CMakeLists.txt @@ -1,8 +1,6 @@ add_library(RuntimeCommonInput IController.hpp - CDolphinController.hpp - CKeyboardController.hpp - CMouseController.hpp + CKeyboardMouseController.hpp ControlMapper.hpp ControlMapper.cpp CInputGenerator.hpp CInputGenerator.cpp CFinalInput.hpp CFinalInput.cpp) diff --git a/Runtime/Input/CMouseController.hpp b/Runtime/Input/CMouseController.hpp deleted file mode 100644 index 7a4784ddb..000000000 --- a/Runtime/Input/CMouseController.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __RETRO_CMOUSECONTROLLER_HPP__ -#define __RETRO_CMOUSECONTROLLER_HPP__ - -#include "IController.hpp" - -namespace Retro -{ - -class CMouseController : public IController -{ -}; - -} - -#endif // __RETRO_CMOUSECONTROLLER_HPP__ diff --git a/Runtime/Input/IController.hpp b/Runtime/Input/IController.hpp index 3f5cafdd9..8cc43a3f9 100644 --- a/Runtime/Input/IController.hpp +++ b/Runtime/Input/IController.hpp @@ -1,25 +1,22 @@ #ifndef __RETRO_ICONTROLLER_HPP__ #define __RETRO_ICONTROLLER_HPP__ +#include "../RetroTypes.hpp" + namespace Retro { class IController { public: - class CControllerAxis + enum EMotorState { + MotorStop = 0, + MotorRumble = 1, + MotorStopHard = 2 }; - class CControllerButton - { - }; - class IControllerGamepadData - { - }; - - void Poll(); - u32 GetDeviceCount(); - + virtual void Poll()=0; + virtual void SetMotorState(EMotorState state)=0; }; } diff --git a/Runtime/MP1/CMakeLists.txt b/Runtime/MP1/CMakeLists.txt index da5202074..e32e666b8 100644 --- a/Runtime/MP1/CMakeLists.txt +++ b/Runtime/MP1/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(mp1 main.cpp) target_link_libraries(mp1 RuntimeCommonCharacter + RuntimeCommonInput RuntimeCommon DNAMP1 DNACommon diff --git a/Runtime/MP1/CTweaks.cpp b/Runtime/MP1/CTweaks.cpp index ed674b6b3..e967deef8 100644 --- a/Runtime/MP1/CTweaks.cpp +++ b/Runtime/MP1/CTweaks.cpp @@ -3,10 +3,12 @@ #include "CResFactory.hpp" #include "CResLoader.hpp" #include "GameGlobalObjects.hpp" +#include "DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp" #include "DataSpec/DNAMP1/Tweaks/CTweakPlayerControl.hpp" namespace Retro { +ITweakPlayer* g_tweakPlayer = nullptr; ITweakPlayerControl* g_tweakPlayerControl = nullptr; namespace MP1 @@ -28,6 +30,10 @@ void CTweaks::RegisterTweaks() CResLoader& loader = factory.GetLoader(); std::unique_ptr strm; + strm.reset(loader.LoadNewResourceSync(IDFromFactory(factory, "Player"), nullptr)); + TOneStatic player(*strm); + g_tweakPlayer = player.GetAllocSpace(); + strm.reset(loader.LoadNewResourceSync(IDFromFactory(factory, "PlayerControls"), nullptr)); TOneStatic playerControl(*strm); g_tweakPlayerControl = playerControl.GetAllocSpace(); diff --git a/Runtime/MP1/main.cpp b/Runtime/MP1/main.cpp index 72ee20378..7f4cd5086 100644 --- a/Runtime/MP1/main.cpp +++ b/Runtime/MP1/main.cpp @@ -24,6 +24,8 @@ #include "CArchitectureQueue.hpp" #include "CMain.hpp" +#include "DataSpec/DNAMP1/Tweaks/CTweakPlayer.hpp" + namespace Retro { CMemoryCardSys* g_MemoryCardSys = nullptr; @@ -98,7 +100,9 @@ class CGameArchitectureSupport CAudioStateWin m_audioStateWin; public: CGameArchitectureSupport() - : m_audioSys(0,0,0,0,0) + : m_audioSys(0,0,0,0,0), + m_inputGenerator(g_tweakPlayer->GetLeftLogicalThreshold(), + g_tweakPlayer->GetRightLogicalThreshold()) { } bool Update() diff --git a/libBoo b/libBoo index 12e5948d3..f9c4ed076 160000 --- a/libBoo +++ b/libBoo @@ -1 +1 @@ -Subproject commit 12e5948d3178df7f689d9676e103760dbb89d07d +Subproject commit f9c4ed076157c78fd131f83c5d0f3bc4c95ae13a