From 37921c45b2c465aabd7490426d128b00e75cf82e Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Mon, 27 Nov 2023 14:48:08 -0500 Subject: [PATCH] Implement & link JUTGamePad.cpp --- common.py | 2 +- config/analysis_overrides.yml | 2 +- config/assets.yml | 2 + config/disasm_overrides.yml | 3 +- config/dol_slices.yml | 9 + config/symbols.yml | 1 + include/JSystem/JUtility/JUTAssertion.h | 50 ++- include/JSystem/JUtility/JUTGamePad.h | 286 ++++++++++---- include/MSL_C/w_math.h | 8 + include/dolphin/os.h | 2 +- include/dolphin/os/OSTime.h | 1 - include/dolphin/pad.h | 2 + src/JSystem/JKernel/JKRExpHeap.cpp | 3 +- src/JSystem/JKernel/JKRHeap.cpp | 11 +- src/JSystem/JUtility/JUTGamePad.cpp | 479 ++++++++++++++++++++++++ 15 files changed, 781 insertions(+), 80 deletions(-) create mode 100644 src/JSystem/JUtility/JUTGamePad.cpp diff --git a/common.py b/common.py index f9f9e2d5..a0942ee0 100644 --- a/common.py +++ b/common.py @@ -400,7 +400,7 @@ JSYSTEM_BASE = [ "-lang=c++", "-inline on", "-fp fmadd", - "-fp_contract on", + #"-fp_contract on", #"-pool off", # this is wrong "-Cpp_exceptions off", "-RTTI on", diff --git a/config/analysis_overrides.yml b/config/analysis_overrides.yml index 13bf633d..aecbd216 100644 --- a/config/analysis_overrides.yml +++ b/config/analysis_overrides.yml @@ -403,4 +403,4 @@ forced_types: 0x800a8138: ENTRY 0x800a8140: ENTRY 0x800a8148: ENTRY - 0x800ab260: ENTRY \ No newline at end of file +# 0x800ab260: ENTRY \ No newline at end of file diff --git a/config/assets.yml b/config/assets.yml index bee9e0d9..4c7c430e 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -138,6 +138,8 @@ config/dol.yml: bootdata/logo_nin_v: addrs: [0x800c30c0, 0x800c3100] type: vtx + JSystem/JUtility/FontData/Ascfont_fix12.bfn: + addrs: [0x800ab260, 0x800af3c0] config/rel.yml: wipe1_v: diff --git a/config/disasm_overrides.yml b/config/disasm_overrides.yml index 5c4cbf97..134af42f 100644 --- a/config/disasm_overrides.yml +++ b/config/disasm_overrides.yml @@ -5,4 +5,5 @@ symbol_aligns: 0x800b9140: 32 # align gam_win_moji1_tex to 32 bytes 0x801f71c0: 32 # align texture_buffer_data to 32 bytes 0x800daaa0: 32 # align texture_cache_data_func to 32 bytes - 0x80206f30: 16 # malloc.c align 16 bytes \ No newline at end of file + 0x80206f30: 16 # malloc.c align 16 bytes + 0x800ab260: 32 \ No newline at end of file diff --git a/config/dol_slices.yml b/config/dol_slices.yml index cd06096b..c36022c8 100644 --- a/config/dol_slices.yml +++ b/config/dol_slices.yml @@ -230,6 +230,15 @@ JSystem/JSupport/JSUInputStream.cpp: # .text: [0x8006e3e4, 0x8006e604] # .data: [0x800dedb8, 0x800dee60] # .sdata: [0x80218068, 0x80218088] +JSystem/JUtility/JUTGamePad.cpp: + .text: [0x80070274, 0x800713b0] + .ctors: [0x800a97ac, 0x800a97b0] + .rodata: [0x800ab240, 0x800ab260] + .data: [0x800def60, 0x800defa0] + .bss: [0x802070e0, 0x80207268] + .sdata: [0x802180b8, 0x802180d0] + .sbss: [0x80218808, 0x80218838] + .sdata2: [0x802192c0, 0x80219300] dolphin/BASE/ppcarch.c: .text: [0x8007867c, 0x80078718] dolphin/os/OSArena.c: diff --git a/config/symbols.yml b/config/symbols.yml index a135f92f..c6e6b186 100644 --- a/config/symbols.yml +++ b/config/symbols.yml @@ -2927,6 +2927,7 @@ global: 0x800ab010: tblc 0x800ab110: pows 0x800ab170: saoAboutEncoding___10JUTResFont + 0x800ab260: JUTResFONT_Ascfont_fix12 0x800af3c0: __constants 0x800af4e0: two_over_pi 0x800af5e8: npio2_hw diff --git a/include/JSystem/JUtility/JUTAssertion.h b/include/JSystem/JUtility/JUTAssertion.h index 4ce59dc9..b273397f 100644 --- a/include/JSystem/JUtility/JUTAssertion.h +++ b/include/JSystem/JUtility/JUTAssertion.h @@ -2,26 +2,70 @@ #define _JSYSTEM_JUT_JUTASSERTION_H #include "types.h" +#include "dolphin/os.h" #ifdef __cplusplus extern "C" { #endif -void JC_JUTAssertion_changeDevice(u32); +namespace JUTAssertion +{ + void create(); + void flushMessage(); + void flushMessage_dbPrint(); + u32 getSDevice(void); + + void showAssert_f(u32 device, char const *file, int line, char const *errormsg, ...); + inline void showAssert(u32 device, char const *file, int line, char const *errormsg) { + showAssert_f(device, file, line, "%s", errormsg); + } + + void setConfirmMessage(u32 device, char *file, int line, bool condition, const char *msg); + void setWarningMessage_f(u32 device, char *file, int line, char const *, ...); + inline void setWarningMessage(u32 device, char *file, int line, char const *errormsg) { + setWarningMessage_f(device, file, line, "%s", errormsg); + } + + void setLogMessage_f(u32 device, char *file, int line, char const *fmt, ...); + extern "C" + { + void showAssert_f_va(u32 device, const char *file, int line, const char *fmt, va_list vl); + void setWarningMessage_f_va(u32 device, char *file, int line, const char *fmt, va_list vl); + void setLogMessage_f_va(u32 device, char *file, int line, const char *fmt, va_list vl); + } +} #define JUT_PANIC(...) #define JUT_PANIC_F(...) #define JUT_CONFIRM_MESSAGE(...) #define JUT_WARNING(...) #define JUT_WARNING_F(...) -#define JUT_ASSERT(...) -#define JUT_ASSERT_F(...) #define JUT_ASSERT_MSG(...) #define JUT_MINMAX_ASSERT(...) #define JUT_MAX_ASSERT(...) #define JUT_LOG_F(...) +#ifndef DEBUG +#define JUT_ASSERT(...) +#define JUT_ASSERT_F(...) +#else + +#define JUT_ASSERT(COND) \ + if ((COND) == false) \ + { \ + JUTAssertion::showAssert(JUTAssertion::getSDevice(), __FILE__, __LINE__, #COND); \ + OSHalt("Halt"); \ + } + +#define JUT_ASSERT_F(COND, ...) \ + if ((COND) == false) \ + { \ + JUTAssertion::showAssert_f(JUTAssertion::getSDevice(), __FILE__, __LINE__, __VA_ARGS__); \ + OSHalt("Halt"); \ + } +#endif + #ifdef __cplusplus } #endif diff --git a/include/JSystem/JUtility/JUTGamePad.h b/include/JSystem/JUtility/JUTGamePad.h index cef2d8f7..8299425a 100644 --- a/include/JSystem/JUtility/JUTGamePad.h +++ b/include/JSystem/JUtility/JUTGamePad.h @@ -6,11 +6,28 @@ #include "dolphin/os/OSTime.h" #include "dolphin/pad.h" #include "JSystem/JKernel/JKRDisposer.h" +#include "JSystem/JUtility/JUTAssertion.h" #ifdef __cplusplus extern "C" { #endif +class JUTGamePadRecordBase +{ +public: + JUTGamePadRecordBase(); + virtual ~JUTGamePadRecordBase(); + virtual void read(PADStatus* status) = 0; + virtual void write(PADStatus* status) = 0; + + bool mActive; + /* more that are unknown */ + + bool isActive() { + return this->mActive; + } +}; + typedef void (*JUTResetBtnCb)(int, void*); class JUTGamePad : public JKRDisposer { @@ -56,6 +73,13 @@ public: Clamped }; + enum EClampMode + { + NoClamp, + Clamp, + ClampCircle + }; + enum EWhichStick { WhichStick_MainStick, @@ -67,7 +91,7 @@ public: virtual ~JUTGamePad(); void assign(); - void checkResetSwitch(); + void checkResetCallback(OSTime time); void clearForReset(); static void init(); void initList(); @@ -75,60 +99,181 @@ public: static bool recalibrate(u32); void setButtonRepeat(u32, u32, u32); void update(); + void clear(); - static void setResetCallback(JUTResetBtnCb callback, void *param_0) - { - C3ButtonReset::sCallback = callback; - C3ButtonReset::sCallbackArg = param_0; + static void checkResetSwitch(); + + static bool mListInitialized; + static u8 mPadAssign[PAD_CONTROLLER_NUM]; + static u32 mSuppressPadReset; + static u32 sAnalogMode; + + static void setAnalogMode(u32 mode) { + JUTGamePad::sAnalogMode = mode; + PADSetAnalogMode(mode); } + static void setResetCallback(JUTResetBtnCb callback, void* arg) { + C3ButtonReset::sCallback = callback; + C3ButtonReset::sCallbackArg = arg; + } + + static void clearResetOccurred() { + C3ButtonReset::sResetOccurred = false; + } + + static EClampMode getClampMode() { + return JUTGamePad::sClampMode; + } + + static s8 getPortStatus(EPadPort port) { + JUT_ASSERT(0 <= port && port < 4); + return mPadStatus[port].err; + } + + bool isPushing3ButtonReset() const { + bool pushing = false; + + if (this->mPortNum != -1 && this->mButtonReset.mReset != false) { + pushing = true; + } + + return pushing; + } + + int getErrorStatus() const { + return this->mErrorStatus; + } + + u8 getAnalogR() const { + return this->mButtons.mAnalogR; + } + + f32 getAnalogRf() const { + return this->mButtons.mAnalogRf; + } + + u8 getAnalogL() const { + return this->mButtons.mAnalogL; + } + + f32 getAnalogLf() const { + return this->mButtons.mAnalogLf; + } + + u8 getAnalogB() const { + return this->mButtons.mAnalogB; + } + + u8 getAnalogA() const { + return this->mButtons.mAnalogA; + } + + int getSubStickAngle() const { + return this->mSubStick.mAngle; + } + + f32 getSubStickValue() const { + return this->mSubStick.mValue; + } + + f32 getSubStickY() const { + return this->mSubStick.mY; + } + + f32 getSubStickX() const { + return this->mSubStick.mX; + } + + int getMainStickAngle() const { + return this->mMainStick.mAngle; + } + + f32 getMainStickValue() const { + return this->mMainStick.mValue; + } + + f32 getMainStickY() const { + return this->mMainStick.mY; + } + + f32 getMainStickX() const { + return this->mMainStick.mX; + } + + u32 getTrigger() const { + return this->mButtons.mTrigger; + } + + u32 getButton() const { + return this->mButtons.mButton; + } + + u32 getRelease() const { + return this->mButtons.mRelease; + } + + u32 getRepeat() const { + return this->mButtons.mRepeat; + } bool testButton(u32 mask) const { - return mButtons.mButton & mask; + return this->mButtons.mButton & mask; } bool testTrigger(u32 mask) const { - return mButtons.mTrigger & mask; + return this->mButtons.mTrigger & mask; } + s16 getPortNum() const { + return this->mPortNum; + } + + JUTGamePadRecordBase* getPadRecord() const { + return this->mPadRecord; + } + + JUTGamePadRecordBase* getPadReplay() const { + return this->mPadReplay; + } + class CButton { public: - CButton(); + CButton() { this->clear(); }; void clear(); - void update(const PADStatus*, u32); - void setRepeat(u32, u32, u32); + void update(const PADStatus* padStatus, u32 buttons); + void setRepeat(u32 mask, u32 delay, u32 frequency); - u32 mButton; // _0 - u32 mTrigger; - u32 mRelease; - u8 mAnalogA; // _C - u8 mAnalogB; // _D - u8 mAnalogL; // _E - u8 mAnalogR; // _F - f32 mAnalogLf; // _10 - f32 mAnalogRf; // _14 - u32 mRepeat; - u32 _1C; - u32 _20; - u32 _24; - u32 _28; - u32 _2C; + u32 mButton; // buttons held down + u32 mTrigger; // buttons newly pressed this frame + u32 mRelease; // buttons released this frame + u8 mAnalogA; // + u8 mAnalogB; // + u8 mAnalogL; // left trigger percent + u8 mAnalogR; // right trigger percent + f32 mAnalogLf; // left trigger analog percent + f32 mAnalogRf; // right trigger analog percent + u32 mRepeat; // buttons currently marked as "repeated" triggers when held + u32 mRepeatTimer; // frames since current button combo has been held + u32 mRepeatLastButton; // last buttons pressed + u32 mRepeatMask; // button mask to allow repeating trigger inputs + u32 mRepeatDelay; // delay before beginning repeated input + u32 mRepeatFrequency; // repeat input every X frames }; class CStick { public: - CStick(); + CStick() { this->clear(); } void clear(); u32 update(s8 x, s8 y, JUTGamePad::EStickMode, JUTGamePad::EWhichStick); - u32 update(s8 x, s8 y, JUTGamePad::EStickMode, JUTGamePad::EWhichStick, u32); u32 getButton(); - f32 mStickX; - f32 mStickY; + f32 mX; + f32 mY; f32 mValue; s16 mAngle; }; @@ -136,16 +281,34 @@ public: class CRumble { public: - void clear(JUTGamePad*); - static void stopMotor(s32); - static void stopMotorHard(s32); - void update(u16); + enum ERumble { + Rumble0, + Rumble1, + Rumble2 + }; + + CRumble(JUTGamePad* gamePad) { this->clear(gamePad); } + + static u8 mStatus[PAD_CONTROLLER_NUM]; + static u32 mEnabled; + + static void startMotor(int port); + static void stopMotor(int port); + static void stopMotorHard(int port); + + static bool isEnabled(u32 channel) { + return (JUTGamePad::CRumble::mEnabled & channel) != 0; + } + + void clear(); + void clear(JUTGamePad* gamePad); + void update(s16); void setEnable(u32); - u32 _0; - u32 _4; - u32 _8; - u32 _C; + u32 mFrame; + u32 mLength; + u8* mData; + u32 mFrameCount; }; class C3ButtonReset { @@ -154,52 +317,41 @@ public: static u32 sResetPattern; static u32 sResetMaskPattern; - static JUTResetBtnCb sCallback; - static void *sCallbackArg; - static OSTime sThreshold; - static s32 sResetOccurredPort; - static bool sResetOccurred; - static bool sResetSwitchPushing; - private: + static JUTResetBtnCb sCallback; + static void* sCallbackArg; + static OSTime sThreshold; + static bool sResetSwitchPushing; + static bool sResetOccurred; + static s32 sResetOccurredPort; + bool mReset; }; - static bool isPadOk() { // fabricated - bool ret = false; - switch(mPadStatus[0].err) { - case -1: - case 0: - ret = true; - break; - } - return ret; - } - static PADStatus *getPadStatus(int idx) { return &mPadStatus[idx]; } + static JSUList mPadList; + static CButton mPadButton[PAD_CONTROLLER_NUM]; + static CStick mPadMStick[PAD_CONTROLLER_NUM]; + static CStick mPadSStick[PAD_CONTROLLER_NUM]; static EStickMode sStickMode; + static EClampMode sClampMode; + static f32 sPressPoint; + static f32 sReleasePoint; + static PADStatus mPadStatus[PAD_CONTROLLER_NUM]; - static PADStatus mPadStatus[4]; CButton mButtons; // _18 CStick mMainStick; // _48 CStick mSubStick; // _58 CRumble mRumble; // _68 - u16 mPort; // _78 + s16 mPortNum; // _78 s8 mErrorStatus; // _7A - JSULink mPtrLink; // _7C - u32 _8C; - u32 _90; + JSULink mLink; // _7C + JUTGamePadRecordBase* mPadRecord; + JUTGamePadRecordBase* mPadReplay; u32 _94; C3ButtonReset mButtonReset; // _98 - u8 _99; - u8 _9A; - u8 _9B; - u8 _9C; - u8 _9D; // padding? - u8 _9E; // ^^ - u8 _9F; // ^^ OSTime mResetTime; // _A0 }; diff --git a/include/MSL_C/w_math.h b/include/MSL_C/w_math.h index 7161021d..bae7af79 100644 --- a/include/MSL_C/w_math.h +++ b/include/MSL_C/w_math.h @@ -67,7 +67,15 @@ inline float fabsf(float x) { return (float)fabs((double)x); } +#ifdef __cplusplus +extern "C" { +#endif + f64 atan2(f64, f64); f64 acos(f32); +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/include/dolphin/os.h b/include/dolphin/os.h index 02b32f29..24db7148 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -63,7 +63,7 @@ void OSInit(void); u32 OSGetConsoleType(); #define OS_CONSOLE_IS_DEV() ((OSGetConsoleType() & OS_CONSOLE_DEV_MASK) != 0) - +#define OSHalt(msg) OSPanic(__FILE__, __LINE__, msg) typedef void (*OSExceptionHandler)(u8, OSContext*); OSExceptionHandler __OSSetExceptionHandler(u8, OSExceptionHandler); diff --git a/include/dolphin/os/OSTime.h b/include/dolphin/os/OSTime.h index 46472dd3..ba759c5f 100644 --- a/include/dolphin/os/OSTime.h +++ b/include/dolphin/os/OSTime.h @@ -16,7 +16,6 @@ u32 __busclock AT_ADDRESS(0x800000F8); #define OS_TIMER_CLOCK (OS_BUS_CLOCK / 4) -#define OSTicksToCycles(ticks) (((ticks) * ((OS_CORE_CLOCK * 2) / OS_TIMER_CLOCK)) / 2) #define OSTicksToSeconds(ticks) ((ticks) / OS_TIMER_CLOCK) #define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK / 1000)) #define OSTicksToMicroseconds(ticks) (((ticks)*8) / (OS_TIMER_CLOCK / 125000)) diff --git a/include/dolphin/pad.h b/include/dolphin/pad.h index 25fabe4a..69c79193 100644 --- a/include/dolphin/pad.h +++ b/include/dolphin/pad.h @@ -7,6 +7,8 @@ extern "C" { #endif +#define PAD_CONTROLLER_NUM 4 + #define PAD_MOTOR_STOP 0 #define PAD_MOTOR_RUMBLE 1 #define PAD_MOTOR_STOP_HARD 2 diff --git a/src/JSystem/JKernel/JKRExpHeap.cpp b/src/JSystem/JKernel/JKRExpHeap.cpp index 2efb3740..5f63d63c 100644 --- a/src/JSystem/JKernel/JKRExpHeap.cpp +++ b/src/JSystem/JKernel/JKRExpHeap.cpp @@ -619,7 +619,8 @@ s32 JKRExpHeap::getUsedSize(u8 groupId) const bool JKRExpHeap::isEmpty() { u32 newSize; - JUT_ASSERT(1269, newSize > 0); + #line 1269 + JUT_ASSERT(newSize > 0); return true; } diff --git a/src/JSystem/JKernel/JKRHeap.cpp b/src/JSystem/JKernel/JKRHeap.cpp index 264d1b76..7af4f6ed 100644 --- a/src/JSystem/JKernel/JKRHeap.cpp +++ b/src/JSystem/JKernel/JKRHeap.cpp @@ -98,7 +98,8 @@ JKRHeap* JKRHeap::becomeCurrentHeap() void JKRHeap::destroy(JKRHeap* heap) { - JUT_ASSERT(200, heap != 0); + #line 200 + JUT_ASSERT(heap != 0); heap->destroy(); } @@ -399,13 +400,15 @@ JKRHeap::TState::TState(const JKRHeap::TState &other, const JKRHeap::TState::TLo void JKRHeap::state_register(JKRHeap::TState* p, u32) const { - JUT_ASSERT(1132, p != 0); - JUT_ASSERT(1133, p->getHeap() == this); + #line 1132 + JUT_ASSERT(p != 0); + JUT_ASSERT(p->getHeap() == this); } bool JKRHeap::state_compare(const JKRHeap::TState& r1, const JKRHeap::TState& r2) const { - JUT_ASSERT(1141, r1.getHeap() == r2.getHeap()); + #line 1141 + JUT_ASSERT(r1.getHeap() == r2.getHeap()); return (r1.getCheckCode() == r2.getCheckCode()); } diff --git a/src/JSystem/JUtility/JUTGamePad.cpp b/src/JSystem/JUtility/JUTGamePad.cpp new file mode 100644 index 00000000..177a587e --- /dev/null +++ b/src/JSystem/JUtility/JUTGamePad.cpp @@ -0,0 +1,479 @@ +#include "JSystem/JUtility/JUTGamePad.h" + +#include "MSL_C/w_math.h" +#include "MSL_C/math.h" + +static u32 channel_mask[PAD_CONTROLLER_NUM] = { + 0x80000000 >> 0, + 0x80000000 >> 1, + 0x80000000 >> 2, + 0x80000000 >> 3 +}; + +JUTGamePad::EStickMode JUTGamePad::sStickMode = Clamped; +u32 JUTGamePad::C3ButtonReset::sResetPattern = START | X | B; +f32 JUTGamePad::sPressPoint = 0.5f; +f32 JUTGamePad::sReleasePoint = 0.25f; +u32 JUTGamePad::C3ButtonReset::sResetMaskPattern = 0xFFFF; + +JSUList JUTGamePad::mPadList(false); +PADStatus JUTGamePad::mPadStatus[PAD_CONTROLLER_NUM]; +JUTGamePad::CButton JUTGamePad::mPadButton[PAD_CONTROLLER_NUM]; +JUTGamePad::CStick JUTGamePad::mPadMStick[PAD_CONTROLLER_NUM]; +JUTGamePad::CStick JUTGamePad::mPadSStick[PAD_CONTROLLER_NUM]; + +bool JUTGamePad::mListInitialized = false; +u8 JUTGamePad::mPadAssign[PAD_CONTROLLER_NUM]; +u32 JUTGamePad::mSuppressPadReset = 0; +u32 JUTGamePad::sAnalogMode = 0; +u8 JUTGamePad::CRumble::mStatus[PAD_CONTROLLER_NUM]; +u32 JUTGamePad::CRumble::mEnabled = 0; +JUTResetBtnCb JUTGamePad::C3ButtonReset::sCallback = nullptr; +void* JUTGamePad::C3ButtonReset::sCallbackArg = nullptr; +OSTime JUTGamePad::C3ButtonReset::sThreshold = (OSTime)(OS_TIMER_CLOCK / 60) * 30; +bool JUTGamePad::C3ButtonReset::sResetSwitchPushing = false; +bool JUTGamePad::C3ButtonReset::sResetOccurred = false; +s32 JUTGamePad::C3ButtonReset::sResetOccurredPort = 0; + +JUTGamePad::JUTGamePad(EPadPort port) + : mButtons(), + mMainStick(), + mSubStick(), + mRumble(this), + mLink(this), + mButtonReset() { + this->mPortNum = port; + mPadAssign[port]++; + this->initList(); + JUTGamePad::mPadList.append(&this->mLink); + this->update(); + this->mPadRecord = nullptr; + this->mPadReplay = nullptr; +} + +JUTGamePad::JUTGamePad() + : mButtons(), + mMainStick(), + mSubStick(), + mRumble(this), + mLink(this), + mButtonReset() { + this->mPortNum = -1; + this->initList(); + JUTGamePad::mPadList.append(&this->mLink); + this->mPadRecord = nullptr; + this->mPadReplay = nullptr; + this->clear(); +} + +JUTGamePad::~JUTGamePad() { + if (this->mPortNum != -1) { + mPadAssign[this->mPortNum]--; + this->mPortNum = -1; + } + + JUTGamePad::mPadList.remove(&this->mLink); +} + +void JUTGamePad::initList() { + if (!JUTGamePad::mListInitialized) { + JUTGamePad::mPadList.initiate(); + JUTGamePad::mListInitialized = true; + } +} + +void JUTGamePad::init() { + PADSetSpec(5); + JUTGamePad::sAnalogMode = 3; + PADSetAnalogMode(3); + PADInit(); +} + +void JUTGamePad::clear() { + this->mButtonReset.mReset = false; +} + +void JUTGamePad::read() { + PADRead(JUTGamePad::mPadStatus); + PADClamp(JUTGamePad::mPadStatus); + + u32 mask; + u32 resetControllerMask = 0; + + for (s32 i = 0; i < PAD_CONTROLLER_NUM; i++) { + mask = 0x80000000 >> i; + + if (JUTGamePad::mPadStatus[i].err == 0) { + PADStatus* status = &JUTGamePad::mPadStatus[i]; + u32 buttons; + + buttons = (JUTGamePad::mPadMStick[i].update(status->stickX, status->stickY, JUTGamePad::sStickMode, WhichStick_MainStick) << 24); + buttons |= (JUTGamePad::mPadSStick[i].update(status->substickX, status->substickY, JUTGamePad::sStickMode, WhichStick_SubStick) << 16); + JUTGamePad::mPadButton[i].update(status, buttons); + } + else if (JUTGamePad::mPadStatus[i].err == -1) { + JUTGamePad::mPadMStick[i].update(0, 0, JUTGamePad::sStickMode, WhichStick_MainStick); + JUTGamePad::mPadSStick[i].update(0, 0, JUTGamePad::sStickMode, WhichStick_SubStick); + JUTGamePad::mPadButton[i].update(nullptr, 0); + + if ((JUTGamePad::mSuppressPadReset & mask) == 0) { + resetControllerMask |= mask; + } + } + else { + JUTGamePad::mPadButton[i].mTrigger = 0; + JUTGamePad::mPadButton[i].mRelease = 0; + JUTGamePad::mPadButton[i].mRepeat = 0; + } + } + + JSUListIterator it; + for (it = JUTGamePad::mPadList.getFirst(); it != JUTGamePad::mPadList.getEnd(); it++) { + if (it->getPadReplay() != nullptr) { + PADStatus status; + u32 buttons; + + it->getPadReplay()->read(&status); + buttons = it->mMainStick.update(status.stickX, status.stickY, JUTGamePad::sStickMode, WhichStick_MainStick) << 24; + buttons |= it->mSubStick.update(status.substickX, status.substickY, JUTGamePad::sStickMode, WhichStick_SubStick) << 16; + it->mButtons.update(&status, buttons); + } + else { + if (it->mPortNum == -1) { + it->assign(); + } + + it->update(); + } + + if (it->getPadRecord() != nullptr && it->mPortNum != -1) { + int port = it->mPortNum; + + if (JUTGamePad::mPadStatus[port].err == 0) { + it->getPadRecord()->write(&JUTGamePad::mPadStatus[port]); + } + } + } + + if (resetControllerMask != 0) { + PADReset(resetControllerMask); + } + + JUTGamePad::checkResetSwitch(); +} + +void JUTGamePad::assign() { + for (s32 i = 0; i < PAD_CONTROLLER_NUM; i++) { + if (JUTGamePad::mPadStatus[i].err == 0 && JUTGamePad::mPadAssign[i] == 0) { + this->mPortNum = i; + JUTGamePad::mPadAssign[i] = 1; + JUTGamePad::mPadButton[i].setRepeat(this->mButtons.mRepeatMask, this->mButtons.mRepeatDelay, this->mButtons.mRepeatFrequency); + this->mRumble.clear(this); + break; + } + } +} + +void JUTGamePad::checkResetCallback(OSTime time) { + if (this->mPortNum != -1 && time >= JUTGamePad::C3ButtonReset::sThreshold) { + JUTGamePad::C3ButtonReset::sResetOccurred = true; + JUTGamePad::C3ButtonReset::sResetOccurredPort = this->mPortNum; + + if (JUTGamePad::C3ButtonReset::sCallback != NULL) { + (*JUTGamePad::C3ButtonReset::sCallback)(this->mPortNum, JUTGamePad::C3ButtonReset::sCallbackArg); + } + } +} + +void JUTGamePad::update() { + if (this->mPortNum != -1) { + this->mButtons = JUTGamePad::mPadButton[this->mPortNum]; + this->mMainStick = JUTGamePad::mPadMStick[this->mPortNum]; + this->mSubStick = JUTGamePad::mPadSStick[this->mPortNum]; + this->mErrorStatus = JUTGamePad::mPadStatus[this->mPortNum].err; + + if (JUTGamePad::C3ButtonReset::sResetOccurred == false) { + if (JUTGamePad::C3ButtonReset::sResetPattern == (JUTGamePad::C3ButtonReset::sResetPattern & this->mButtons.mButton)) { + if (this->mButtonReset.mReset == true) { + this->checkResetCallback(OSGetTime() - this->mResetTime); + } + else { + this->mButtonReset.mReset = true; + this->mResetTime = OSGetTime(); + } + } + else { + this->mButtonReset.mReset = false; + } + } + + this->mRumble.update(this->mPortNum); + } +} + +void JUTGamePad::checkResetSwitch() { + if (!JUTGamePad::C3ButtonReset::sResetOccurred) { + if (OSGetResetSwitchState() != 0) { + JUTGamePad::C3ButtonReset::sResetSwitchPushing = true; + } + else { + if (JUTGamePad::C3ButtonReset::sResetSwitchPushing == true) { + JUTGamePad::C3ButtonReset::sResetOccurred = true; + JUTGamePad::C3ButtonReset::sResetOccurredPort = -1; + + if (*JUTGamePad::C3ButtonReset::sCallback != nullptr) { + (*JUTGamePad::C3ButtonReset::sCallback)(-1, JUTGamePad::C3ButtonReset::sCallbackArg); + } + } + + JUTGamePad::C3ButtonReset::sResetSwitchPushing = false; + } + } +} + +void JUTGamePad::CButton::clear() { + this->mButton = 0; + this->mTrigger = 0; + this->mRelease = 0; + this->mRepeat = 0; + this->mAnalogA = 0; + this->mAnalogB = 0; + this->mAnalogL = 0; + this->mAnalogR = 0; + this->mRepeatTimer = 0; + this->mRepeatLastButton = 0; + this->mRepeatMask = 0; + this->mRepeatDelay = 0; + this->mRepeatFrequency = 0; +} + +void JUTGamePad::CButton::update(const PADStatus* padStatus, u32 stick_buttons) { + u32 tempButtons; + u32 buttons; + + if (padStatus != nullptr) { + tempButtons = padStatus->button; + } + else { + tempButtons = 0; + } + + buttons = stick_buttons | tempButtons; + this->mRepeat = 0; + + if (this->mRepeatDelay != 0) { + if (this->mRepeatMask != 0) { + u32 repeatButtons = buttons & this->mRepeatMask; + this->mRepeat = 0; + + if (repeatButtons == 0) { + this->mRepeatLastButton = 0; + this->mRepeatTimer = 0; + } + else if (this->mRepeatLastButton == repeatButtons) { + this->mRepeatTimer++; + if ( + this->mRepeatTimer == this->mRepeatDelay || + (this->mRepeatTimer > this->mRepeatDelay && ((this->mRepeatTimer - this->mRepeatDelay) % this->mRepeatFrequency) == 0) + ) { + this->mRepeat = repeatButtons; + } + } + else { + this->mRepeat = repeatButtons & (this->mRepeatLastButton ^ 0xFFFFFFFF); + this->mRepeatLastButton = repeatButtons; + this->mRepeatTimer = 0; + } + } + } + + this->mTrigger = buttons & (buttons ^ this->mButton); + this->mRelease = this->mButton & (buttons ^ this->mButton); + this->mButton = buttons; + this->mRepeat |= (this->mRepeatMask ^ 0xFFFFFFFF) & this->mTrigger; + + if (padStatus != nullptr) { + this->mAnalogA = padStatus->analogA; + this->mAnalogB = padStatus->analogB; + this->mAnalogL = padStatus->triggerLeft; + this->mAnalogR = padStatus->triggerRight; + } + else { + this->mAnalogA = 0; + this->mAnalogB = 0; + this->mAnalogL = 0; + this->mAnalogR = 0; + } + + this->mAnalogLf = (f32)(int)this->mAnalogL / 150.0f; + this->mAnalogRf = (f32)(int)this->mAnalogR / 150.0f; +} + +void JUTGamePad::CStick::clear() { + this->mX = 0.0f; + this->mY = 0.0f; + this->mValue = 0.0f; + this->mAngle = 0; +} + +u32 JUTGamePad::CStick::update(s8 x, s8 y, EStickMode stickMode, EWhichStick whichStick) { + int stickMax = whichStick == WhichStick_MainStick ? 54 : 42; + + this->mX = (f32)x / (f32)stickMax; + this->mY = (f32)y / (f32)stickMax; + this->mValue = sqrtf(this->mX * this->mX + this->mY * this->mY); + + if (this->mValue > 1.0f) { + if (stickMode == Clamped) { + this->mX /= this->mValue; + this->mY /= this->mValue; + } + + this->mValue = 1.0f; + } + + if (this->mValue > 0.0f) { + if (this->mY == 0.0f) { + if (this->mX > 0.0f) { + this->mAngle = 0x4000; + } + else { + this->mAngle = -0x4000; + } + } + else { + f32 angle = atan2(this->mX, -this->mY); + this->mAngle = angle * 10430.379f; //((f32)0x8000 / F_PI); + } + } + + return this->getButton(); +} + +u32 JUTGamePad::CStick::getButton() { + u32 button = 0; + + if (-0.25f < this->mX && this->mX < 0.25f) { + button &= ~(DPAD_LEFT | DPAD_RIGHT); + } + else if (this->mX <= -0.5f) { + button |= DPAD_LEFT; + } + else if (this->mX >= 0.5f) { + button |= DPAD_RIGHT; + } + + if (-0.25f < this->mY && this->mY < 0.25f) { + button &= ~(DPAD_DOWN | DPAD_UP); + } + else if (this->mY <= -0.5f) { + button |= DPAD_DOWN; + } + else if (this->mY >= 0.5f) { + button |= DPAD_UP; + } + + return button; +} + +void JUTGamePad::CRumble::clear() { + this->mFrame = 0; + this->mLength = 0; + this->mData = nullptr; + this->mFrameCount = 0; + JUTGamePad::CRumble::mEnabled = 0xF0000000; +} + +void JUTGamePad::CRumble::clear(JUTGamePad* gamePad) { + if (0 <= gamePad->getPortNum() && gamePad->getPortNum() < PAD_CONTROLLER_NUM) { + JUTGamePad::CRumble::mStatus[gamePad->getPortNum()] = 0; + this->stopMotorHard(gamePad->getPortNum()); + } + + this->clear(); +} + +void JUTGamePad::CRumble::startMotor(int port) { + if (JUTGamePad::CRumble::isEnabled(channel_mask[port])) { + PADControlMotor(port, PAD_MOTOR_RUMBLE); + JUTGamePad::CRumble::mStatus[port] = 1; + } +} + +void JUTGamePad::CRumble::stopMotor(int port) { + if (JUTGamePad::CRumble::isEnabled(channel_mask[port])) { + PADControlMotor(port, PAD_MOTOR_STOP); + JUTGamePad::CRumble::mStatus[port] = 0; + } +} + +void JUTGamePad::CRumble::stopMotorHard(int port) { + if (JUTGamePad::CRumble::isEnabled(channel_mask[port])) { + PADControlMotor(port, PAD_MOTOR_STOP_HARD); + JUTGamePad::CRumble::mStatus[port] = 0; + } +} + +static inline u8 getNumBit(const u8* data, int bit) { + return (((0x80 >> (bit & 7)) & data[(u32)bit >> 3]) & 0xFF); +} + +void JUTGamePad::CRumble::update(s16 port) { + if (!JUTGamePad::CRumble::isEnabled(channel_mask[port])) { + this->mFrame = 0; + this->mLength = 0; + this->mData = nullptr; + this->mFrameCount = 0; + } + + if (this->mLength != 0) { + if (this->mFrame >= this->mLength) { + JUTGamePad::CRumble::stopMotorHard(port); + this->mLength = 0; + } + else { + if (this->mFrameCount == 0) { + if (JUTGamePad::CRumble::mStatus[port] == 0) { + JUTGamePad::CRumble::startMotor(port); + } + + return; + } + + u8 bit = getNumBit(this->mData, this->mFrame % this->mFrameCount); + if (bit != 0 && JUTGamePad::CRumble::mStatus[port] == 0) { + JUTGamePad::CRumble::startMotor(port); + } + else if (bit == 0 && JUTGamePad::CRumble::mStatus[port] != 0) { + JUTGamePad::CRumble::stopMotorHard(port); + } + } + + this->mFrame++; + } +} + +void JUTGamePad::CButton::setRepeat(u32 repeatMask, u32 repeatDelay, u32 repeatFreq) { + this->mRepeatLastButton = 0; + this->mRepeatTimer = 0; + this->mRepeatMask = repeatMask; + this->mRepeatDelay = repeatDelay; + this->mRepeatFrequency = repeatFreq; +} + +bool JUTGamePad::recalibrate(u32 channels) { + u32 channelMasks[PAD_CONTROLLER_NUM] = { + 0x80000000 >> 0, + 0x80000000 >> 1, + 0x80000000 >> 2, + 0x80000000 >> 3 + }; + + for (int i = 0; i < PAD_CONTROLLER_NUM; i++) { + if ((JUTGamePad::mSuppressPadReset & channelMasks[i]) != 0) { + channels &= channelMasks[i] ^ 0xFFFFFFFF; + } + } + + return PADRecalibrate(channels); +}