diff --git a/configure.py b/configure.py index 17361954..4320904d 100644 --- a/configure.py +++ b/configure.py @@ -795,19 +795,20 @@ def MatchingFor(*versions): Object(NonMatching, "MarioUtil/EffectUtil.cpp"), Object(NonMatching, "MarioUtil/ModelUtil.cpp"), Object(NonMatching, "MarioUtil/RumbleMgr.cpp"), - Object(NonMatching, "MarioUtil/RumbleData.cpp"), + Object(Matching, "MarioUtil/RumbleData.cpp"), Object(Matching, "MarioUtil/RumbleType.cpp"), Object(NonMatching, "MarioUtil/PacketUtil.cpp"), Object(Matching, "MarioUtil/GDUtil.cpp"), Object(Matching, "MarioUtil/TexUtil.cpp"), Object(Matching, "MarioUtil/MapUtil.cpp"), - Object(NonMatching, "MarioUtil/ToolData.cpp"), + Object(Matching, "MarioUtil/ToolData.cpp"), ], }, { "lib": "M3DUtil", "mw_version": "GC/1.2.5", "cflags": [*cflags_system, "-inline deferred"], + "progress_category": "game", "objects": [ Object(NonMatching, "M3DUtil/M3UJoint.cpp"), Object(NonMatching, "M3DUtil/M3UModel.cpp"), @@ -826,6 +827,7 @@ def MatchingFor(*versions): "lib": "System", "mw_version": "GC/1.2.5", "cflags": cflags_system, + "progress_category": "game", "objects": [ Object(Matching, "System/BaseParam.cpp"), Object(NonMatching, "System/EmitterViewObj.cpp"), diff --git a/include/GC2D/MovieRumble.hpp b/include/GC2D/MovieRumble.hpp new file mode 100644 index 00000000..d328f2cc --- /dev/null +++ b/include/GC2D/MovieRumble.hpp @@ -0,0 +1,46 @@ +#ifndef GC2D_MOVIE_RUMBLE_HPP +#define GC2D_MOVIE_RUMBLE_HPP + +#include +#include +#include +#include + +class TMovieRumble : public JDrama::TViewObj { +public: + TMovieRumble(const TTHPRender* thpRender); + virtual ~TMovieRumble(); + void init(const char* subtitleName); + virtual void perform(u32 flags, JDrama::TGraphics* graphics); + void checkRumbleOff(); + +public: + const TTHPRender* thpRenderer; + Koga::ToolData* toolData; // this is supposedly the only usage of tooldata + // in the entire game lmao + s32 entryIndex; + s32 startFrame; + s32 endFrame; + s32 rumbleTypeIndex; + bool isRumbleActive; + +private: + inline void updateRumbleState(Koga::ToolData* toolData, s32 entryIndex) + { + const char* rumbleTypeString; + s32 theEntryIndex = entryIndex; + bool isDataValid = (toolData != nullptr) && (theEntryIndex >= 0); + + if (isDataValid && toolData->isIndexValid(theEntryIndex)) { + // get this rumble entry's data, and update this instance + toolData->GetValue(theEntryIndex, "start_frame", startFrame); + toolData->GetValue(theEntryIndex, "end_frame", endFrame); + toolData->GetValue(theEntryIndex, "type", rumbleTypeString); + rumbleTypeIndex = RumbleType::getIndex((char*)rumbleTypeString); + } else { + rumbleTypeIndex = -1; + } + } +}; + +#endif // GC2D_MOVIE_RUMBLE_HPP diff --git a/include/MarioUtil/RumbleMgr.hpp b/include/MarioUtil/RumbleMgr.hpp index 6696c4c9..72365e73 100644 --- a/include/MarioUtil/RumbleMgr.hpp +++ b/include/MarioUtil/RumbleMgr.hpp @@ -2,43 +2,57 @@ #define MARIO_UTIL_RUMBLE_MGR_HPP #include +#include +#include -class RumbleBase { -public: - void init(); - void stop(); - void update(f32, bool); -}; +#define MAX_RUMBLE_ID (25) +#define MAX_RUMBLE_CHANNELS (32) -class RumbleChannelDataMgr { -public: - void init(); - void getChannelDataTbl(int); +struct RumbleChannelData { + int* point; + float* frame; + float* power; }; +extern const RumbleChannelData channelDataTbl[]; +extern int channelNum; + +// RumbleMgr + class RumbleChannelMgr { public: RumbleChannelMgr(); - void init(RumbleChannelDataMgr*); - void reset(); - void repeat(); - void start(int, int, f32*); - void start(int, int, Vec*); - void update(); + f32 update(); + +public: + /* 0x00 */ f32 mElapsedTime; /* inferred */ + /* 0x04 */ f32 mCurrentIntensity; /* inferred */ + /* 0x08 */ s32 mChannelID; /* inferred */ + /* 0x0C */ s32 mLoopCount; /* inferred */ + /* 0x10 */ f32* mExternalDampenPtr; /* inferred */ + /* 0x14 */ Vec* mPositionalSourcePtr; /* inferred */ + /* 0x18 */ const RumbleChannelData* rumbleData; /* inferred */ + /* 0x1C */ void* unk20; /* inferred */ }; class RumbleControllerMgr { public: - RumbleControllerMgr(); - void init(); void reset(); - void start(int, int, f32*); - void start(int, int, Vec*); - void stop(); - void stop(int); + void start(int channelId, int loopCount, float* externalDampenPtr); + void start(int channelId, int loopCount, Vec* positionalSourcePtr); + void stop(int channelId); void channelMgrIsAllFree(); void updateMotorCount(); - void update(); + f32 update(); + +public: + f32 currentPower; // 0x00 + RumbleChannelMgr* channels; // 0x04 + RumbleChannelMgr* unk8; // 0x08 + u32 unkC; // 0x0C + u16 motorTime; // 0x10 + bool unk12; // 0x12 + u8 padding_13; // 0x13 }; class RumbleMgr; @@ -66,8 +80,28 @@ class RumbleMgr { void setActive(bool); void startPause(); void finishPause(); - void changePause(); - void changeMode(); + +public: + struct RumbleControllerState { + f32 m_currentIntensityL; // 0x00 + f32 m_currentIntensityR; // 0x04 + s32 m_controllerIndex; // 0x08 + }; + + f32 m_masterIntensityL; // 0x00 + f32 m_masterIntensityR; // 0x04 + bool m_isInitialized; // 0x08 + bool m_flags; // 0x09 + bool unkA; // 0x0A + bool unkB; // 0x0B + RumbleControllerState* m_controllerStates[4]; // 0x0C + RumbleControllerMgr* m_controllerManagers[4]; // 0x1C + const RumbleChannelData** m_rumbleOutput; // 0x2C + +public: + static u32 mMotorCountLimit; + static u16 mMotorTimerPeriod; + static f32 mPowerThreshold; }; #endif diff --git a/include/MarioUtil/RumbleType.hpp b/include/MarioUtil/RumbleType.hpp index eb610e48..7dff1dba 100644 --- a/include/MarioUtil/RumbleType.hpp +++ b/include/MarioUtil/RumbleType.hpp @@ -2,6 +2,7 @@ #define MARIO_UTIL_RUMBLE_TYPE_HPP class RumbleType { +public: float foo; static int getIndex(char* strIn); }; diff --git a/include/MarioUtil/ToolData.hpp b/include/MarioUtil/ToolData.hpp new file mode 100644 index 00000000..fdc1c74b --- /dev/null +++ b/include/MarioUtil/ToolData.hpp @@ -0,0 +1,117 @@ +#ifndef MARIO_UTIL_TOOL_DATA_HPP +#define MARIO_UTIL_TOOL_DATA_HPP +#include + +namespace Koga { +/** + * @brief ToolData is a class that reads BCSV data. Usage is as follows: + * Create a ToolData instance, fetch the BCSV data from disk and attach it. + * One can then call GetValue to retrieve data from the file. + * + * The structures and parsing logic are based off the Mario Galaxy decomp's + * handling of JMap files + */ +class ToolData { +public: + ToolData(); + virtual ~ToolData(); // if not explicitly defined its not generated ok + BOOL Attach(const void* bcsvFileData); + // returns TRUE if the value was found, otherwise FALSE + BOOL GetValue(int entryIndex, const char* key, long& pValueOut) const; + // returns TRUE if the value was found, otherwise FALSE + BOOL GetValue(int entryIndex, const char* key, + const char*& pValueOut) const; + + inline bool dataExists() const { return !!mData; } + + inline bool isIndexValid(s32 entryIndex) + { + return entryIndex < mData->mNumEntries; + } + +// JMAP value types, ignored in sunshine +#define JMAP_VALUE_TYPE_LONG 0 +#define JMAP_VALUE_TYPE_STRING 1 +#define JMAP_VALUE_TYPE_FLOAT 2 +#define JMAP_VALUE_TYPE_LONG_2 3 +#define JMAP_VALUE_TYPE_SHORT 4 +#define JMAP_VALUE_TYPE_BYTE 5 +#define JMAP_VALUE_TYPE_STRING_PTR 6 +#define JMAP_VALUE_TYPE_NULL 7 + + struct JMapItem { + u32 mHash; // 0x0 + u32 mMask; // 0x4 + u16 mOffsData; // 0x8 + u8 mShift; // 0xA + u8 mType; // 0xB + }; + + struct JMapData { + s32 mNumEntries; // 0x0 + s32 mNumFields; // 0x4 + s32 mDataOffset; // 0x8 + u32 mEntrySize; // 0xC + const JMapItem mItems[]; // 0x10 + }; + +private: + inline u32 hashString(const char* key) const + { + u32 stringHash = 0; + char current_char; + + while ((current_char = *key) != 0) { + key++; + stringHash = (current_char + (stringHash << 8)) % 0x1FFFFD9; + } + return stringHash; + } + + inline s32 searchItemInfo(const char* pKey) const + { + s32 nFields = mData->mNumFields; + u32 hash = hashString(pKey); + + for (int i = 0; i < nFields; ++i) { + if (hash == mData->mItems[i].mHash) { + return i; + } + } + + return -1; + } + + inline const char* getEntryAddress(const JMapData* pData, + const s32 dataOffset, + const int entryIndex) const + { + return reinterpret_cast(pData) + dataOffset + + entryIndex * pData->mEntrySize; + } + + inline BOOL getValue(const int entryIndex, const int itemIndex, + s32* pValueOut) const + { + const JMapItem* item = &mData->mItems[itemIndex]; + const char* valuePtr + = getEntryAddress(mData, mData->mDataOffset, entryIndex) + + item->mOffsData; + *pValueOut = *reinterpret_cast(valuePtr); + return TRUE; + } + + inline BOOL getValue(const int entryIndex, const int itemIndex, + const char** pValueOut) const + { + const JMapItem* item = &mData->mItems[itemIndex]; + *pValueOut = getEntryAddress(mData, mData->mDataOffset, entryIndex) + + item->mOffsData; + return TRUE; + } + +public: + const JMapData* mData; +}; +} // namespace Koga +#endif diff --git a/include/System/THPRender.hpp b/include/System/THPRender.hpp index 0f2d02c9..43893e90 100644 --- a/include/System/THPRender.hpp +++ b/include/System/THPRender.hpp @@ -10,14 +10,17 @@ class TTHPRender : public JDrama::TViewObj { public: - virtual void perform(u32, JDrama::TGraphics*); /* override */ + void perform(u32, JDrama::TGraphics*); /* override */ TTHPRender(const char* name); + ~TTHPRender(); + + inline s32 getFrameNumber() const { return frameNumber; } /* 0x10 */ u32 x; /* 0x14 */ u32 y; /* 0x18 */ u32 polyW; /* 0x1c */ u32 polyH; - /* 0x20 */ u32 frameNumber; + /* 0x20 */ s32 frameNumber; }; #endif // SYSTEM_THP_RENDER_HPP diff --git a/src/GC2D/MovieRumble.cpp b/src/GC2D/MovieRumble.cpp index e69de29b..f3c17682 100644 --- a/src/GC2D/MovieRumble.cpp +++ b/src/GC2D/MovieRumble.cpp @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +TMovieRumble::TMovieRumble(const TTHPRender* thpRender) +{ + thpRenderer = thpRender; +} + +void TMovieRumble::init(const char* subtitleName) +{ + char szSubtitlePath[128]; + sprintf(szSubtitlePath, "/subtitle/rnbl/%s", subtitleName); + char* szSubtitlePathExtension = (char*)strrchr(szSubtitlePath, '.'); + char* result = strcpy(szSubtitlePathExtension, ".bcr"); + + Koga::ToolData* data = new Koga::ToolData; + toolData = data; + void* glbResource = JKRFileLoader::getGlbResource(szSubtitlePath); + toolData->Attach(glbResource); + + if (toolData->dataExists() == FALSE) + entryIndex = -1; + else + entryIndex = 0; + + Koga::ToolData* pData = toolData; + s32 nextEntryIndex = entryIndex; + + updateRumbleState(pData, nextEntryIndex); + + isRumbleActive = false; +} + +void TMovieRumble::perform(u32 flags, JDrama::TGraphics* graphics) +{ + if ((flags & 1) != 0) { + if (isRumbleActive) { + checkRumbleOff(); + } else { + bool rumbleTypeValid = rumbleTypeIndex != -1; + if (rumbleTypeValid + && startFrame <= thpRenderer->getFrameNumber()) { + SMSRumbleMgr->start(rumbleTypeIndex, -1, (float*)0); + isRumbleActive = true; + } + } + } +} + +#pragma dont_inline on +void TMovieRumble::checkRumbleOff() +{ + bool rumbleTypeValid = rumbleTypeIndex != -1; + if (rumbleTypeValid) { + if (endFrame <= thpRenderer->getFrameNumber()) { + SMSRumbleMgr->stop(); + entryIndex++; + + Koga::ToolData* pData = toolData; + s32 nextEntryIndex = entryIndex; + updateRumbleState(pData, nextEntryIndex); + isRumbleActive = false; + } + } +} +#pragma dont_inline off + +TMovieRumble::~TMovieRumble() { } diff --git a/src/MarioUtil/RumbleData.cpp b/src/MarioUtil/RumbleData.cpp index e69de29b..35954507 100644 --- a/src/MarioUtil/RumbleData.cpp +++ b/src/MarioUtil/RumbleData.cpp @@ -0,0 +1,277 @@ +#include + +static int rumblePoint_00 = 11; +static float rumbleFrame_00[] = { + 0.0f, 0.05f, 0.1f, 0.15f, 0.2f, 0.25f, 0.25f, 0.33f, 0.4f, 0.5f, 0.6f, +}; +static float rumblePower_00[] = { + 1.0f, 1.0f, 1.0f, 0.9f, 0.0f, 0.0f, 0.6f, 0.6f, 0.5f, 0.2f, 0.0f, +}; + +static int rumblePoint_01 = 24; +static float rumbleFrame_01[] = { + 0.0f, 0.16f, 0.19f, 0.24f, 0.26f, 0.37f, 0.4f, 0.45f, + 0.46f, 0.54f, 0.56f, 0.61f, 0.62f, 0.7f, 0.73f, 0.78f, + 0.79f, 0.86f, 0.92f, 0.96f, 1.03f, 1.13f, 1.17f, 1.4f, +}; +static float rumblePower_01[] = { + 1.0f, 1.0f, 0.0f, 0.0f, 0.95f, 0.85f, 0.0f, 0.0f, + 0.8f, 0.73f, 0.0f, 0.0f, 0.64f, 0.53f, 0.0f, 0.0f, + 0.44f, 0.35f, 0.0f, 0.27f, 0.02f, 0.16f, 0.01f, 0.0f, +}; + +static int rumblePoint_02 = 2; +static float rumbleFrame_02[] = { + 0.0f, + 0.1f, +}; +static float rumblePower_02[] = { + 0.8f, + 0.6f, +}; + +static int rumblePoint_03 = 2; +static float rumbleFrame_03[] = { + 0.0f, + 0.1f, +}; +static float rumblePower_03[] = { + 1.0f, + 1.0f, +}; + +static int rumblePoint_04 = 7; +static float rumbleFrame_04[] = { + 0.0f, 0.1f, 0.15f, 0.2f, 0.25f, 0.3f, 0.5f, +}; +static float rumblePower_04[] = { + 1.0f, 1.0f, 0.0f, 0.8f, 0.8f, 0.0f, 0.0f, +}; + +static int rumblePoint_05 = 21; +static float rumbleFrame_05[] = { + 0.0f, 0.18f, 0.21f, 0.28f, 0.28f, 0.4f, 0.45f, 0.51f, 0.52f, 0.64f, 0.69f, + 0.75f, 0.83f, 0.89f, 0.99f, 1.03f, 1.12f, 1.19f, 1.25f, 1.3f, 1.4f, +}; +static float rumblePower_05[] = { + 1.0f, 0.92f, 0.0f, 0.0f, 0.79f, 0.63f, 0.0f, 0.02f, 0.45f, 0.31f, 0.02f, + 0.24f, 0.03f, 0.18f, 0.04f, 0.13f, 0.04f, 0.1f, 0.04f, 0.06f, 0.0f, +}; + +static int rumblePoint_06 = 10; +static float rumbleFrame_06[] = { + 0.0f, 0.09f, 0.09f, 0.1f, 0.17f, 0.17f, 0.18f, 0.26f, 0.26f, 0.5f, +}; +static float rumblePower_06[] = { + 0.85f, 0.85f, 0.1f, 0.45f, 0.45f, 0.05f, 0.25f, 0.25f, 0.01f, 0.0f, +}; + +static int rumblePoint_07 = 20; +static float rumbleFrame_07[] = { + 0.0f, 0.11f, 0.12f, 0.13f, 0.2f, 0.21f, 0.29f, 0.31f, 0.33f, 0.41f, + 0.42f, 0.52f, 0.53f, 0.54f, 0.62f, 0.64f, 0.72f, 0.74f, 0.75f, 1.0f, +}; +static float rumblePower_07[] = { + 0.95f, 0.97f, 0.85f, 0.0f, 0.0f, 0.75f, 0.73f, 0.55f, 0.0f, 0.0f, + 0.6f, 0.63f, 0.32f, 0.0f, 0.0f, 0.51f, 0.48f, 0.19f, 0.02f, 0.0f, +}; + +static int rumblePoint_08 = 4; +static float rumbleFrame_08[] = { + 0.0f, 0.3f, 0.5f, 0.7f, 1.0f, +}; +static float rumblePower_08[] = { + 1.0f, 0.5f, 0.35f, 0.5f, 1.0f, +}; + +static int rumblePoint_09 = 4; +static float rumbleFrame_09[] = { + 0.0f, + 0.3f, + 0.5f, + 0.7f, +}; +static float rumblePower_09[] = { + 0.5f, + 0.24f, + 0.18f, + 0.23f, +}; + +static int rumblePoint_10 = 1; +static float rumbleFrame_10[] = { + 0.0f, +}; +static float rumblePower_10[] = { + 0.0f, +}; + +static int rumblePoint_11 = 1; +static float rumbleFrame_11[] = { + 0.0f, +}; +static float rumblePower_11[] = { + 0.0f, +}; + +static int rumblePoint_12 = 1; +static float rumbleFrame_12[] = { + 0.0f, +}; +static float rumblePower_12[] = { + 0.0f, +}; + +static int rumblePoint_13 = 1; +static float rumbleFrame_13[] = { + 0.0f, +}; +static float rumblePower_13[] = { + 0.0f, +}; + +static int rumblePoint_14 = 1; +static float rumbleFrame_14[] = { + 0.0f, +}; +static float rumblePower_14[] = { + 0.0f, +}; + +static int rumblePoint_15 = 1; +static float rumbleFrame_15[] = { + 0.0f, +}; +static float rumblePower_15[] = { + 0.0f, +}; + +static int rumblePoint_16 = 1; +static float rumbleFrame_16[] = { + 0.0f, +}; +static float rumblePower_16[] = { + 0.0f, +}; + +static int rumblePoint_17 = 1; +static float rumbleFrame_17[] = { + 0.0f, +}; +static float rumblePower_17[] = { + 0.0f, +}; + +static int rumblePoint_18 = 1; +static float rumbleFrame_18[] = { + 0.0f, +}; +static float rumblePower_18[] = { + 0.0f, +}; + +static int rumblePoint_19 = 5; +static float rumbleFrame_19[] = { + 0.0f, 0.11f, 0.2f, 0.32f, 0.4f, +}; +static float rumblePower_19[] = { + 0.6f, 0.4f, 0.6f, 0.4f, 0.6f, +}; + +static int rumblePoint_20 = 2; +static float rumbleFrame_20[] = { + 0.0f, + 0.01666666666f, +}; +static float rumblePower_20[] = { + 0.5f, + 0.5f, +}; + +static int rumblePoint_21 = 2; +static float rumbleFrame_21[] = { + 0.0f, + 0.01666666666f, +}; +static float rumblePower_21[] = { + 0.75f, + 0.75f, +}; + +static int rumblePoint_22 = 2; +static float rumbleFrame_22[] = { + 0.0f, + 2.0f, +}; +static float rumblePower_22[] = { + 0.75f, + 0.75f, +}; + +static int rumblePoint_23 = 77; +static float rumbleFrame_23[] = { + 0.0f, 0.07f, 0.13f, 0.25f, 0.26f, 1.02f, 1.03f, 1.14f, 1.14f, + 1.2f, 1.21f, 1.29f, 1.33f, 3.75f, 3.81f, 3.92f, 3.94f, 4.0f, + 4.16f, 4.17f, 4.36f, 4.4f, 4.44f, 4.44f, 4.58f, 4.69f, 5.16f, + 5.18f, 5.28f, 5.32f, 5.4f, 5.41f, 5.52f, 5.56f, 5.58f, 5.66f, + 5.68f, 6.35f, 6.36f, 6.57f, 6.68f, 6.85f, 6.88f, 7.11f, 7.18f, + 7.5f, 7.66f, 8.09f, 8.67f, 9.08f, 9.1f, 9.63f, 9.64f, 9.65f, + 9.81f, 9.84f, 9.89f, 9.91f, 10.02f, 10.04f, 10.05f, 10.06f, 10.19f, + 10.21f, 10.22f, 10.23f, 10.35f, 10.38f, 10.43f, 10.45f, 10.51f, 10.57f, + 10.61f, 10.68f, 10.78f, 10.82f, 11.0f, +}; +static float rumblePower_23[] = { + 0.8f, 1.0f, 0.95f, 0.8f, 0.0f, 0.0f, 0.95f, 0.95f, 0.41f, 0.44f, 0.72f, + 0.58f, 0.0f, 0.0f, 0.81f, 0.9f, 0.69f, 0.0f, 0.0f, 0.98f, 0.95f, 0.53f, + 0.5f, 0.87f, 0.7f, 0.0f, 0.0f, 0.87f, 0.84f, 0.32f, 0.27f, 0.69f, 0.55f, + 0.0f, 0.34f, 0.27f, 0.0f, 0.0f, 0.78f, 0.71f, 0.0f, 0.0f, 0.78f, 0.68f, + 0.0f, 0.0f, 0.42f, 0.72f, 0.87f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 0.95f, 0.85f, 0.0f, 0.0f, 0.8f, 0.73f, 0.0f, 0.0f, 0.64f, + 0.53f, 0.0f, 0.0f, 0.44f, 0.35f, 0.0f, 0.27f, 0.02f, 0.16f, 0.01f, 0.0f, +}; + +static int rumblePoint_24 = 37; +static float rumbleFrame_24[] = { + 0.0f, 0.07f, 0.13f, 0.25f, 0.26f, 1.02f, 1.03f, 1.14f, 1.14f, 1.2f, + 1.21f, 1.29f, 1.33f, 3.75f, 3.81f, 3.92f, 3.94f, 4.0f, 4.16f, 4.17f, + 4.36f, 4.4f, 4.44f, 4.44f, 4.58f, 4.69f, 5.16f, 5.18f, 5.28f, 5.32f, + 5.4f, 5.41f, 5.52f, 5.56f, 5.58f, 5.66f, 5.68f, +}; +static float rumblePower_24[] = { + 0.8f, 1.0f, 0.95f, 0.8f, 0.0f, 0.0f, 0.95f, 0.95f, 0.41f, 0.44f, + 0.72f, 0.58f, 0.0f, 0.0f, 0.81f, 0.9f, 0.69f, 0.0f, 0.0f, 0.98f, + 0.95f, 0.53f, 0.5f, 0.87f, 0.7f, 0.0f, 0.0f, 0.87f, 0.84f, 0.32f, + 0.27f, 0.69f, 0.55f, 0.0f, 0.34f, 0.27f, 0.0f, +}; + +// clang-format off +const RumbleChannelData channelDataTbl[] = { + { &rumblePoint_00, rumbleFrame_00, rumblePower_00, }, + { &rumblePoint_01, rumbleFrame_01, rumblePower_01, }, + { &rumblePoint_02, rumbleFrame_02, rumblePower_02, }, + { &rumblePoint_03, rumbleFrame_03, rumblePower_03, }, + { &rumblePoint_04, rumbleFrame_04, rumblePower_04, }, + { &rumblePoint_05, rumbleFrame_05, rumblePower_05, }, + { &rumblePoint_06, rumbleFrame_06, rumblePower_06, }, + { &rumblePoint_07, rumbleFrame_07, rumblePower_07, }, + { &rumblePoint_08, rumbleFrame_08, rumblePower_08, }, + { &rumblePoint_09, rumbleFrame_09, rumblePower_09, }, + { &rumblePoint_10, rumbleFrame_10, rumblePower_10, }, + { &rumblePoint_11, rumbleFrame_11, rumblePower_11, }, + { &rumblePoint_12, rumbleFrame_12, rumblePower_12, }, + { &rumblePoint_13, rumbleFrame_13, rumblePower_13, }, + { &rumblePoint_14, rumbleFrame_14, rumblePower_14, }, + { &rumblePoint_15, rumbleFrame_15, rumblePower_15, }, + { &rumblePoint_16, rumbleFrame_16, rumblePower_16, }, + { &rumblePoint_17, rumbleFrame_17, rumblePower_17, }, + { &rumblePoint_18, rumbleFrame_18, rumblePower_18, }, + { &rumblePoint_19, rumbleFrame_19, rumblePower_19, }, + { &rumblePoint_20, rumbleFrame_20, rumblePower_20, }, + { &rumblePoint_21, rumbleFrame_21, rumblePower_21, }, + { &rumblePoint_22, rumbleFrame_22, rumblePower_22, }, + { &rumblePoint_23, rumbleFrame_23, rumblePower_23, }, + { &rumblePoint_24, rumbleFrame_24, rumblePower_24, }, +}; +// clang-format on + +int channelNum = MAX_RUMBLE_ID; diff --git a/src/MarioUtil/RumbleMgr.cpp b/src/MarioUtil/RumbleMgr.cpp index e69de29b..60890972 100644 --- a/src/MarioUtil/RumbleMgr.cpp +++ b/src/MarioUtil/RumbleMgr.cpp @@ -0,0 +1,588 @@ +#include "dolphin/types.h" +#include +#include +#include +#include +#include + +RumbleMgr* SMSRumbleMgr; + +u32 RumbleMgr::mMotorCountLimit = 900; +u16 RumbleMgr::mMotorTimerPeriod = 80; +f32 RumbleMgr::mPowerThreshold = 0.5f; + +RumbleChannelMgr::RumbleChannelMgr() +{ + mElapsedTime = 0.0f; + mCurrentIntensity = 0.0f; + mChannelID = -1; + mLoopCount = 0; + mExternalDampenPtr = 0; + mPositionalSourcePtr = 0; + rumbleData = 0; +} + +f32 RumbleChannelMgr::update() +{ + f32 dampenFactor; + f32* externalDampenSource = this->mExternalDampenPtr; + f32 targetFrameTime = 1.0f / SMSGetVSyncTimesPerSec(); + if (externalDampenSource != NULL) { + dampenFactor = *mExternalDampenPtr; + if (dampenFactor >= 0.0f) { + if (dampenFactor > 1.0f) + dampenFactor = 1.0f; + } else { + dampenFactor = 0.0f; + } + } else { + if (this->mPositionalSourcePtr != NULL) { + f32 distance + = (SMS_GetMarioPos() - *this->mPositionalSourcePtr).length(); + const f32 kScaleFactor = 1.0f / 3000.0f; + distance = -((kScaleFactor * (distance - 300.0f)) - 1.0f); + dampenFactor = distance; + if (distance >= 0.0f) { + if (distance > 1.0f) + dampenFactor = 1.0f; + } else { + dampenFactor = 0.0f; + } + } else { + dampenFactor = 1.0f; + } + } + + this->mCurrentIntensity = 0.0f; + if (!this->mLoopCount) { + this->mElapsedTime = 0.0f; + this->mCurrentIntensity = 0.0f; + this->mChannelID = -1; + this->mLoopCount = 0; + this->mExternalDampenPtr = 0; + this->mPositionalSourcePtr = 0; + this->rumbleData = 0; + } + + if (this->rumbleData) { + int totalRumblePoints = 0; + int rumblePointIterator = 0; + int keyframeIndex = 0; + + this->mElapsedTime = this->mElapsedTime + targetFrameTime; + + while (true) { + totalRumblePoints = *this->rumbleData->point; + if (rumblePointIterator >= totalRumblePoints - 1) + break; + float* currentFrame = this->rumbleData->frame; + + if (this->mElapsedTime > this->rumbleData->frame[keyframeIndex]) { + float lerpFactor = 1.0f; + if ((this->rumbleData->frame[keyframeIndex + 1] + - this->rumbleData->frame[keyframeIndex]) + <= 0.0) + lerpFactor = 1.0f; + else + lerpFactor = ((this->mElapsedTime + - this->rumbleData->frame[keyframeIndex]) + / (this->rumbleData->frame[keyframeIndex + 1] + - this->rumbleData->frame[keyframeIndex])); + this->mCurrentIntensity + = ((1.0f - lerpFactor) * rumbleData->power[keyframeIndex]) + + (lerpFactor * rumbleData->power[keyframeIndex + 1]); + } + + ++rumblePointIterator; + ++keyframeIndex; + break; + } + + if (this->mElapsedTime > rumbleData->frame[totalRumblePoints - 1]) { + if (this->mLoopCount <= 1) { + this->mElapsedTime = 0.0f; + if (mLoopCount >= 0) { + this->mCurrentIntensity = 0.0f; + this->mChannelID = -1; + this->mLoopCount = 0; + this->mExternalDampenPtr = 0; + this->mPositionalSourcePtr = 0; + this->rumbleData = 0; + } + } else { + this->mElapsedTime = 0.0f; + --this->mLoopCount; + } + } + } + + this->mCurrentIntensity *= dampenFactor; + return this->mCurrentIntensity; +} + +void RumbleControllerMgr::reset() +{ + currentPower = 0.0f; + + // @FIXME: registers arent being assigned correctly during the unroll + for (u32 i = 0; i < MAX_RUMBLE_CHANNELS; ++i) { + RumbleChannelMgr* channel = &channels[i]; + channel->mElapsedTime = 0.0f; + channel->mCurrentIntensity = 0.0f; + channel->mChannelID = -1; + channel->mLoopCount = 0; + channel->mExternalDampenPtr = 0; + channel->mPositionalSourcePtr = 0; + channel->rumbleData = 0; + } + + unkC = 0; + motorTime = 0; + unk12 = false; +} + +#pragma dont_inline on +void RumbleControllerMgr::start(int channelId, int loopCount, + float* externalDampenPtr) +{ + for (s32 i = 0; i < MAX_RUMBLE_CHANNELS; ++i) { + RumbleChannelMgr* channel = &this->channels[i]; + + if (channel->rumbleData == NULL) { + channel->mElapsedTime = 0.0f; + channel->rumbleData = &channelDataTbl[channelId]; + channel->mChannelID = channelId; + channel->mLoopCount = loopCount; + channel->mExternalDampenPtr = externalDampenPtr; + return; // Found a slot and started the rumble, so we exit + } + } +} + +void RumbleControllerMgr::start(int channelId, int loopCount, + Vec* positionalSourcePtr) +{ + for (s32 i = 0; i < MAX_RUMBLE_CHANNELS; ++i) { + RumbleChannelMgr* channel = &this->channels[i]; + + if (channel->rumbleData == NULL) { + channel->mElapsedTime = 0.0f; + channel->rumbleData = &channelDataTbl[channelId]; + channel->mChannelID = channelId; + channel->mLoopCount = loopCount; + channel->mPositionalSourcePtr = positionalSourcePtr; + return; // Found a slot and started the rumble, so we exit + } + } +} + +void RumbleControllerMgr::stop(int channelId) +{ + for (u32 i = 0; i < MAX_RUMBLE_CHANNELS; ++i) { + RumbleChannelMgr* channel = &channels[i]; + if (channel->rumbleData && channelId == channel->mChannelID) { + channel->mElapsedTime = 0.0f; + channel->mCurrentIntensity = 0.0f; + channel->mChannelID = -1; + channel->mLoopCount = 0; + channel->mExternalDampenPtr = 0; + channel->mPositionalSourcePtr = 0; + channel->rumbleData = 0; + } + } +} +#pragma dont_inline off + +void RumbleControllerMgr::updateMotorCount() +{ + u16 temp_r4_2; + u32 temp_r4; + + if ((s8)unk12 != 0) { + temp_r4 = unkC; + if (temp_r4 != 0U) { + unkC = temp_r4 - 1; + return; + } + unk12 = 0; + motorTime = 0; + return; + } + if (unkC > RumbleMgr::mMotorCountLimit) { + unk12 = 1; + return; + } + temp_r4_2 = motorTime; + if (temp_r4_2 != 0) { + motorTime = temp_r4_2 - 1; + unkC += 1; + return; + } + unkC = 0U; +} +#define CLAMP(val, min, max) \ + ((val) > (max) ? (max) : (val) < (min) ? (min) : (val)) + +inline f32 clamp(f32 val, f32 min, f32 max) { + float value = val; + if (val > max) + return max; + return value; + if (val < min) + value = min; + return value; +} + +f32 RumbleControllerMgr::update() +{ + float maxCurrentPower = 0.0f; + + for (int channelIdx = 0; channelIdx < MAX_RUMBLE_CHANNELS; ++channelIdx) { + RumbleChannelMgr* currChannelManager = &this->channels[channelIdx]; + + if (currChannelManager->rumbleData) { + this->currentPower = currChannelManager->update(); + + if (this->currentPower > maxCurrentPower) { + maxCurrentPower = this->currentPower; + } + } + } + + // this->currentPower = CLAMP(maxCurrentPower, 0.0f, 1.0f); + this->currentPower = clamp(maxCurrentPower, 0.0f, 1.0f); + + if (this->currentPower > RumbleMgr::mPowerThreshold) + this->motorTime = RumbleMgr::mMotorTimerPeriod; + if (this->unk12) + this->currentPower = 0.0f; + return this->currentPower; +} + +RumbleMgr::RumbleMgr(bool bController1Avail, bool bController2Avail, + bool bController3Avail, bool bController4Avail) +{ + bool aControllers[4]; + this->m_masterIntensityL = 0.0f; + this->m_masterIntensityR = 0.0f; + aControllers[0] = bController1Avail; + aControllers[1] = bController2Avail; + aControllers[2] = bController3Avail; + aControllers[3] = bController4Avail; + + for (int i = 0; i < 4; ++i) { + if (aControllers[i]) { + RumbleControllerMgr* pMgr = new RumbleControllerMgr(); + if (pMgr) { + pMgr->currentPower = 0.0f; + pMgr->channels = new RumbleChannelMgr[MAX_RUMBLE_CHANNELS]; + } + this->m_controllerManagers[i] = pMgr; + + RumbleControllerState* pState = new RumbleControllerState(); + if (pState) { + pState->m_currentIntensityL = 0.0f; + pState->m_currentIntensityR = 0.0f; + pState->m_controllerIndex = i; + } + this->m_controllerStates[i] = pState; + } + } + + const RumbleChannelData** pOutput = (const RumbleChannelData**)new int; + if (pOutput != nullptr) { + *pOutput = 0; + } + + this->m_rumbleOutput = pOutput; + this->m_isInitialized = TRUE; + this->m_flags = 1; +} + +void RumbleMgr::init() +{ + this->m_masterIntensityL = 0.0f; + this->m_masterIntensityR = 0.0f; + + for (int i = 0; i < 4; ++i) { + RumbleControllerMgr* pControllerMgr = this->m_controllerManagers[i]; + + if (pControllerMgr != nullptr) { + pControllerMgr->currentPower = 0.0f; + for (int ch = 0; ch < MAX_RUMBLE_CHANNELS; ++ch) { + void* unk20 = pControllerMgr->unk8; + RumbleChannelMgr& channel = pControllerMgr->channels[ch]; + + channel.mElapsedTime = 0.0f; + channel.mCurrentIntensity = 0.0f; + channel.mChannelID = -1; + channel.mLoopCount = 0; + channel.mExternalDampenPtr = nullptr; + channel.mPositionalSourcePtr = nullptr; + channel.rumbleData = nullptr; + channel.unk20 = unk20; + } + + RumbleControllerState* pState = this->m_controllerStates[i]; + pState->m_currentIntensityL = 0.0f; + pState->m_currentIntensityR = 0.0f; + } + } + + *this->m_rumbleOutput = channelDataTbl; + this->m_isInitialized = true; + + this->m_flags = true; + this->unkA = false; +} + +void RumbleMgr::reset() +{ + this->m_masterIntensityL = 0.0f; + this->m_masterIntensityR = 0.0f; + + for (int i = 0; i < 4; ++i) { + RumbleControllerMgr* pMgr = this->m_controllerManagers[i]; + + if (pMgr != nullptr) { + pMgr->currentPower = 0.0f; + for (int ch = 0; ch < MAX_RUMBLE_CHANNELS; ++ch) { + RumbleChannelMgr& channel = pMgr->channels[ch]; + + channel.mElapsedTime = 0.0f; + channel.mCurrentIntensity = 0.0f; + channel.mChannelID = -1; + channel.mLoopCount = 0; + channel.mExternalDampenPtr = nullptr; + channel.mPositionalSourcePtr = nullptr; + channel.rumbleData = nullptr; + } + + pMgr->unkC = 0; + pMgr->motorTime = 0; + pMgr->unk12 = false; + + RumbleControllerState* pState = this->m_controllerStates[i]; + PADControlMotor(pState->m_controllerIndex, PAD_MOTOR_STOP_HARD); + + pState->m_currentIntensityL = 0.0f; + pState->m_currentIntensityR = 0.0f; + } + } + + this->m_flags = false; +} + +void RumbleMgr::start(int channelId, float* externalDampenPtr) +{ + int index = 0; + + if (!this->m_flags && this->m_isInitialized) { + if (this->m_controllerManagers[index]) { + this->m_controllerManagers[index]->start(channelId, 1, externalDampenPtr); + } + } +} + +void RumbleMgr::start(int channelId, Vec* positionalSourcePtr) +{ + int index = 0; + + if (!this->m_flags && this->m_isInitialized) { + if (this->m_controllerManagers[index]) { + this->m_controllerManagers[index]->start(channelId, 1, positionalSourcePtr); + } + } +} + +void RumbleMgr::start(int channelId, int loopCount, f32* externalDampenPtr) +{ + int index = 0; + + if (!this->m_flags && this->m_isInitialized) { + if (this->m_controllerManagers[index]) { + this->m_controllerManagers[index]->start(channelId, loopCount, externalDampenPtr); + } + } +} + +void RumbleMgr::start(int channelId, int loopCount, Vec* positionalSourcePtr) +{ + int index = 0; + + if (!this->m_flags && this->m_isInitialized) { + if (this->m_controllerManagers[index]) { + this->m_controllerManagers[index]->start(channelId, loopCount, positionalSourcePtr); + } + } +} + +void RumbleMgr::stop() +{ + for (int controllerPort = 0; controllerPort < 4; controllerPort++) { + RumbleControllerMgr* controllerMgr + = this->m_controllerManagers[controllerPort]; + + if (controllerMgr != nullptr) { + for (int rumbleChannel = 0; rumbleChannel < MAX_RUMBLE_CHANNELS; + rumbleChannel++) { + RumbleChannelMgr& channel + = controllerMgr->channels[rumbleChannel]; + + if (channel.rumbleData != nullptr) { + channel.mElapsedTime = 0.0f; + channel.mCurrentIntensity = 0.0f; + channel.mChannelID = -1; + channel.mLoopCount = 0; + channel.mExternalDampenPtr = nullptr; + channel.mPositionalSourcePtr = nullptr; + channel.rumbleData = nullptr; + } + } + } + } +} + +void RumbleMgr::stop(int channelId) +{ + int index = 0; + + if (!this->m_flags && this->m_isInitialized) { + if (this->m_controllerManagers[index]) { + this->m_controllerManagers[index]->stop(channelId); + } + } +} + +void RumbleMgr::update() +{ + float delta = 1.0f / SMSGetVSyncTimesPerSec(); + + if (!this->m_flags && this->m_isInitialized) { + for (int i = 0; i < 4; ++i) { + RumbleControllerMgr* controller = this->m_controllerManagers[i]; + + if (controller) { + bool isSilent = true; + for (int ch = 0; ch < MAX_RUMBLE_CHANNELS; ch++) { + RumbleChannelMgr& channel = controller->channels[ch]; + if (channel.rumbleData != nullptr + || channel.mElapsedTime != 0.0f) { + isSilent = false; + break; + } + } + + RumbleControllerState* state = this->m_controllerStates[i]; + + if (isSilent) { + PADControlMotor(state->m_controllerIndex, + PAD_MOTOR_STOP_HARD); + state->m_currentIntensityL = 0.0f; + state->m_currentIntensityR = 0.0f; + } else { + this->m_masterIntensityL = controller->update(); + + if (this->m_masterIntensityR > 0.0f) { + this->m_masterIntensityL + = this->m_masterIntensityL + * ((1.0f - this->m_masterIntensityL) + * (this->m_masterIntensityR / 0.5f) + + 1.0f); + } + + if (this->m_masterIntensityL <= 1.0f) { + if (this->m_masterIntensityL < 0.0f) { + this->m_masterIntensityL = 0.0f; + } + } else { + this->m_masterIntensityL = 1.0f; + } + + state->m_currentIntensityL = this->m_masterIntensityL; + state->m_currentIntensityR += state->m_currentIntensityL; + + if (state->m_currentIntensityL > 0.0f) { + if (state->m_currentIntensityR >= 1.0f) { + state->m_currentIntensityR -= 1.0f; + PADControlMotor(state->m_controllerIndex, + PAD_MOTOR_RUMBLE); + } else { + if (this->unkA) + PADControlMotor(state->m_controllerIndex, + PAD_MOTOR_STOP_HARD); + else + PADControlMotor(state->m_controllerIndex, + PAD_MOTOR_STOP); + } + } else { + if (this->unkA) + PADControlMotor(state->m_controllerIndex, + PAD_MOTOR_STOP_HARD); + else + PADControlMotor(state->m_controllerIndex, + PAD_MOTOR_STOP); + } + } + controller->updateMotorCount(); + } + } + + if (this->m_masterIntensityR > 0.0f) { + this->m_masterIntensityR = this->m_masterIntensityR - delta; + } + } +} + +void RumbleMgr::setActive(bool activeState) +{ + int v3; // r30 + int v4; // r31 + RumbleControllerMgr* v5; // r3 + RumbleControllerState* v6; // r29 + float* v7; // r3 + + this->m_isInitialized = activeState; + if (!this->m_isInitialized) { + v3 = 0; + v4 = 0; + this->m_masterIntensityL = 0.0; + this->m_masterIntensityR = 0.0; + do { + v5 = this->m_controllerManagers[v4]; + if (v5) { + v5->reset(); + v6 = m_controllerStates[v4]; + PADControlMotor(v6->m_controllerIndex, PAD_MOTOR_STOP_HARD); + v6->m_currentIntensityL = 0.0f; + v6->m_currentIntensityR = 0.0f; + } + ++v3; + ++v4; + } while (v3 < 4); + this->m_flags = 0; + } +} + +void RumbleMgr::startPause() +{ + int padIter; // r31 + int i; // r30 + RumbleControllerState* theControllerState; // r3 + + padIter = 0; + for (i = 0; i < 4; ++i) { + theControllerState = this->m_controllerStates[padIter]; + if (theControllerState) + PADControlMotor(theControllerState->m_controllerIndex, + PAD_MOTOR_STOP_HARD); + ++padIter; + } + this->m_flags = 1; +} + +void RumbleMgr::finishPause() +{ + this->m_masterIntensityR = 0.5; + this->m_flags = 0; +} diff --git a/src/MarioUtil/RumbleType.cpp b/src/MarioUtil/RumbleType.cpp index 7691718e..8a6541c5 100644 --- a/src/MarioUtil/RumbleType.cpp +++ b/src/MarioUtil/RumbleType.cpp @@ -1,11 +1,12 @@ #include #include +#include extern int channelNum; struct UnkStruct3B0378 { unsigned int unk0; - char* str; + const char* str; }; // Enum To Str? @@ -44,5 +45,9 @@ int RumbleType::getIndex(char* strIn) return _info[i].unk0; } } + ASSERTMSGLINE( + __LINE__, -1, + "Invalid RumbleType"); // this feels more correct but the string is + // getting omitted by the preprocessor return -1; } diff --git a/src/MarioUtil/ToolData.cpp b/src/MarioUtil/ToolData.cpp index e69de29b..8e3fd04c 100644 --- a/src/MarioUtil/ToolData.cpp +++ b/src/MarioUtil/ToolData.cpp @@ -0,0 +1,34 @@ +#include +#include + +namespace Koga { +ToolData::ToolData() { mData = nullptr; } +ToolData::~ToolData() { } + +BOOL ToolData::Attach(const void* jmapData) +{ + if (!jmapData) + return FALSE; + this->mData = (JMapData*)jmapData; + return TRUE; +} + +BOOL ToolData::GetValue(int entryIndex, const char* key, long& pValueOut) const +{ + s32 itemIndex = searchItemInfo(key); + if (itemIndex < 0) { + return FALSE; + } + return getValue(entryIndex, itemIndex, &pValueOut); +} + +BOOL ToolData::GetValue(int entryIndex, const char* key, + const char*& pValueOut) const +{ + s32 itemIndex = searchItemInfo(key); + if (itemIndex < 0) { + return FALSE; + } + return getValue(entryIndex, itemIndex, &pValueOut); +} +} // namespace Koga diff --git a/src/System/THPRender.cpp b/src/System/THPRender.cpp index ba804864..8fad89f4 100644 --- a/src/System/THPRender.cpp +++ b/src/System/THPRender.cpp @@ -1,5 +1,7 @@ #include +TTHPRender::~TTHPRender() { } + void TTHPRender::perform(u32 flags, JDrama::TGraphics* gfx) { if ((flags & 8)) {