diff --git a/data/file_list.yml b/data/file_list.yml index 4e5084faa6..33a63e19ba 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -288849,37 +288849,37 @@ Project/Anim/AnimInfo.o: label: - _ZN2al11AnimResInfoC1Ev - _ZN2al11AnimResInfoC2Ev - status: NotDecompiled + status: Matching - offset: 0xa3b85c size: 12 label: _ZNK2al11AnimResInfo11getFrameMaxEv - status: NotDecompiled + status: Matching - offset: 0xa3b868 size: 8 label: _ZNK2al11AnimResInfo6isLoopEv - status: NotDecompiled + status: Matching - offset: 0xa3b870 size: 116 label: - _ZN2al13AnimInfoTableC1Ei - _ZN2al13AnimInfoTableC2Ei - status: NotDecompiled + status: Matching - offset: 0xa3b8e4 size: 116 label: _ZN2al13AnimInfoTable3addEPKcPvfb - status: NotDecompiled + status: Matching - offset: 0xa3b958 size: 224 label: _ZNK2al13AnimInfoTable12findAnimInfoEPKc - status: NotDecompiled + status: Matching - offset: 0xa3ba38 size: 224 label: _ZNK2al13AnimInfoTable15tryFindAnimInfoEPKc - status: NotDecompiled + status: NonMatchingMajor - offset: 0xa3bb18 size: 564 label: _ZN2al13AnimInfoTable4sortEv - status: NotDecompiled + status: Matching Project/Anim/AnimPlayerSimple.o: '.text': - offset: 0xa3bd4c @@ -288894,75 +288894,75 @@ Project/Anim/AnimPlayerSimple.o: - offset: 0xa3bd6c size: 68 label: _ZN2al16AnimPlayerSimpleC2Ev - status: NotDecompiled + status: Matching - offset: 0xa3bdb0 size: 88 label: _ZN2al16AnimPlayerSimple9startAnimEPKc - status: NotDecompiled + status: Matching - offset: 0xa3be08 size: 76 label: _ZN2al16AnimPlayerSimple6updateEv - status: NotDecompiled + status: Matching - offset: 0xa3be54 size: 20 label: _ZN2al16AnimPlayerSimple9clearAnimEv - status: NotDecompiled + status: Matching - offset: 0xa3be68 size: 20 label: _ZNK2al16AnimPlayerSimple12getAnimFrameEv - status: NotDecompiled + status: Matching - offset: 0xa3be7c size: 80 label: _ZN2al16AnimPlayerSimple12setAnimFrameEf - status: NotDecompiled + status: Matching - offset: 0xa3becc size: 20 label: _ZNK2al16AnimPlayerSimple15getAnimFrameMaxEv - status: NotDecompiled + status: Matching - offset: 0xa3bee0 size: 28 label: _ZNK2al16AnimPlayerSimple15getAnimFrameMaxEPKc - status: NotDecompiled + status: Matching - offset: 0xa3befc size: 20 label: _ZNK2al16AnimPlayerSimple16getAnimFrameRateEv - status: NotDecompiled + status: Matching - offset: 0xa3bf10 size: 64 label: _ZN2al16AnimPlayerSimple16setAnimFrameRateEf - status: NotDecompiled + status: Matching - offset: 0xa3bf50 size: 32 label: _ZNK2al16AnimPlayerSimple11isAnimExistEPKc - status: NotDecompiled + status: Matching - offset: 0xa3bf70 size: 48 label: _ZNK2al16AnimPlayerSimple9isAnimEndEv - status: NotDecompiled + status: Matching - offset: 0xa3bfa0 size: 36 label: _ZNK2al16AnimPlayerSimple13isAnimOneTimeEv - status: NotDecompiled + status: Matching - offset: 0xa3bfc4 size: 36 label: _ZNK2al16AnimPlayerSimple13isAnimOneTimeEPKc - status: NotDecompiled + status: Matching - offset: 0xa3bfe8 size: 16 label: _ZNK2al16AnimPlayerSimple13isAnimPlayingEv - status: NotDecompiled + status: Matching - offset: 0xa3bff8 size: 28 label: _ZNK2al16AnimPlayerSimple18getPlayingAnimNameEv - status: NotDecompiled + status: Matching - offset: 0xa3c014 size: 156 label: _ZN2al16AnimPlayerSimple22calcNeedUpdateAnimNextEv - status: NotDecompiled + status: Matching - offset: 0xa3c0b0 size: 64 label: _ZN2al16AnimPlayerSimple7applyToEv - status: NotDecompiled + status: Matching - offset: 0xa3c0f0 size: 164 label: _ZN2al13AnimPlayerMat9tryCreateEPKNS_18AnimPlayerInitInfoEi diff --git a/lib/NintendoSDK b/lib/NintendoSDK index 92b288975a..6b28b1f259 160000 --- a/lib/NintendoSDK +++ b/lib/NintendoSDK @@ -1 +1 @@ -Subproject commit 92b288975ad26a089dac4c0a405cfaec06d81297 +Subproject commit 6b28b1f259114ea91bef682832192d2ea761549d diff --git a/lib/al/Project/Action/InitResourceDataActionAnim.cpp b/lib/al/Project/Action/InitResourceDataActionAnim.cpp index 8b84bfcb6e..bd9db84904 100644 --- a/lib/al/Project/Action/InitResourceDataActionAnim.cpp +++ b/lib/al/Project/Action/InitResourceDataActionAnim.cpp @@ -128,12 +128,12 @@ const al::AnimInfoTable* createAnimInfoTableIfNeed(const al::AnimInfoTable* tabl for (s32 i = 0; i < table1->getInfoCount(); i++) { const al::AnimResInfo& entry = table1->getResInfo(i); - newTable->add(entry.name, entry.resMaterialAnim, entry.frameMax, entry.isLoop); + newTable->add(entry.name, entry.buffer, entry.frameMax, entry.isLooping); } for (s32 i = 0; i < table2->getInfoCount(); i++) { const al::AnimResInfo& entry = table2->getResInfo(i); - newTable->add(entry.name, entry.resMaterialAnim, entry.frameMax, entry.isLoop); + newTable->add(entry.name, entry.buffer, entry.frameMax, entry.isLooping); } newTable->sort(); diff --git a/lib/al/Project/Anim/AnimInfo.cpp b/lib/al/Project/Anim/AnimInfo.cpp new file mode 100644 index 0000000000..8c7ce93a0d --- /dev/null +++ b/lib/al/Project/Anim/AnimInfo.cpp @@ -0,0 +1,121 @@ +#include "Project/Anim/AnimInfo.h" + +#include "Library/Base/StringUtil.h" + +namespace al { + +AnimResInfo::AnimResInfo() = default; + +s32 AnimResInfo::getFrameMax() const { + return static_cast(frameMax); +} + +bool AnimResInfo::isLoop() const { + return isLooping; +} + +AnimInfoTable::AnimInfoTable(s32 capacity) { + mInfoEntries = new AnimResInfo[capacity]; +} + +void AnimInfoTable::add(const char* name, void* buffer, f32 frameMax, bool isLoop) { + // BUG: Is sorted flag is not cleared and no bounds check + AnimResInfo* info = &mInfoEntries[mSize]; + info->name = createStringIfInStack(name); + info->buffer = buffer; + info->frameMax = frameMax; + info->isLooping = isLoop; + mSize++; +} + +AnimResInfo* AnimInfoTable::findAnimInfo(const char* name) const { + if (mIsSorted) { + s32 low = 0; + s32 high = mSize; + while (low < high) { + s32 mid = (high + low - 1) >> 1; + AnimResInfo* info = &mInfoEntries[mid]; + s32 cmp = strcmp(info->name, name); + + if (cmp > 0) { + high = mid; + continue; + } + + if (cmp == 0) + return info; + + low = mid + 1; + } + return nullptr; + } + + for (s32 i = 0; i < mSize; i++) { + AnimResInfo* info = &mInfoEntries[i]; + if (isEqualString(info->name, name)) + return info; + } + return nullptr; +} + +// NON-MATCHING: Different register somehow https://decomp.me/scratch/ZxdNk +AnimResInfo* AnimInfoTable::tryFindAnimInfo(const char* name) const { + return findAnimInfo(name); +} + +inline void heapify(AnimResInfo* entries, s32 n, const AnimResInfo& temp, s32 parent) { + s32 child = parent * 2; + while (child <= n) { + if (child < n && strcmp(entries[child - 1].name, entries[child].name) < 0) + child++; + + if (strcmp(temp.name, entries[child - 1].name) >= 0) + break; + + entries[parent - 1] = entries[child - 1]; + parent = child; + child = parent * 2; + } + entries[parent - 1] = temp; +} + +void AnimInfoTable::sort() { + s32 n = mSize; + AnimResInfo* entries = mInfoEntries; + + if (n < 2 || !entries) { + mIsSorted = true; + return; + } + + AnimResInfo temp; + + for (s32 i = n / 2; i >= 1; i--) { + temp = entries[i - 1]; + heapify(entries, n, temp, i); + } + + // TODO: Figure out how to apply heapify here as well + for (s32 i = n; i >= 2; i--) { + temp = entries[i - 1]; + entries[i - 1] = entries[0]; + s32 parent = 1; + s32 child = parent * 2; + while (child < i) { + if (child < i - 1 && strcmp(entries[child - 1].name, entries[child].name) < 0) + child++; + + if (strcmp(temp.name, entries[child - 1].name) >= 0) + break; + + entries[parent - 1] = entries[child - 1]; + parent = child; + child = parent * 2; + } + entries[parent - 1] = temp; + } + + mIsSorted = true; +} + +} // namespace al diff --git a/lib/al/Project/Anim/AnimInfo.h b/lib/al/Project/Anim/AnimInfo.h index 4c5a67d81c..85e64b91c0 100644 --- a/lib/al/Project/Anim/AnimInfo.h +++ b/lib/al/Project/Anim/AnimInfo.h @@ -3,30 +3,41 @@ #include namespace al { + struct AnimResInfo { - const char* name; - void* resMaterialAnim; - f32 frameMax; - bool isLoop; + AnimResInfo(); + + s32 getFrameMax() const; + bool isLoop() const; + + const char* name = nullptr; + void* buffer = nullptr; + f32 frameMax = 0.0f; + bool isLooping = false; }; +static_assert(sizeof(AnimResInfo) == 0x18); + class AnimInfoTable { public: - AnimInfoTable(u32); + AnimInfoTable(u32 capacity); const AnimResInfo& findAnimInfo(const char* name) const; bool tryFindAnimInfo(const char* name) const; - void add(const char* name, void*, f32 frameMax, bool isLoop); + void add(const char* name, void* buffer, f32 frameMax, bool isLoop); void sort(); - s32 getInfoCount() const { return mInfoCount; } + s32 getInfoCount() const { return mSize; } - const AnimResInfo& getResInfo(s32 index) const { return mResInfos[index]; } + const AnimResInfo& getResInfo(s32 index) const { return mInfoEntries[index]; } private: - s32 mInfoCount; - AnimResInfo* mResInfos; - bool mIsSorted; + s32 mSize = 0; + AnimResInfo* mInfoEntries = nullptr; + bool mIsSorted = false; }; + +static_assert(sizeof(AnimInfoTable) == 0x18); + } // namespace al diff --git a/lib/al/Project/Anim/AnimPlayerBase.h b/lib/al/Project/Anim/AnimPlayerBase.h index 5bed96f7d8..3001aa0ee8 100644 --- a/lib/al/Project/Anim/AnimPlayerBase.h +++ b/lib/al/Project/Anim/AnimPlayerBase.h @@ -13,7 +13,15 @@ class AnimPlayerBase : public HioNode { virtual bool calcNeedUpdateAnimNext() = 0; - AnimInfoTable* getAnimInfoTable() { return mInfoTable; } + AnimInfoTable* getAnimInfoTable() const { return mInfoTable; } + + bool is10() const { return _10; }; + + void set10(bool value) { _10 = value; } + + bool is11() const { return _11; }; + + void set11(bool value) { _11 = value; } private: AnimInfoTable* mInfoTable = nullptr; diff --git a/lib/al/Project/Anim/AnimPlayerSimple.cpp b/lib/al/Project/Anim/AnimPlayerSimple.cpp new file mode 100644 index 0000000000..d2256f89e9 --- /dev/null +++ b/lib/al/Project/Anim/AnimPlayerSimple.cpp @@ -0,0 +1,104 @@ +#include "Project/Anim/AnimPlayerSimple.h" + +#include +#include + +#include "Project/Anim/AnimInfo.h" + +namespace al { +AnimPlayerSimple::AnimPlayerSimple() { + mModelInfo = new ModelInfo(); +} + +void AnimPlayerSimple::applyTo() { + mModelInfo->boneAnimObj->Calculate(); + mModelInfo->boneAnimObj->ApplyTo(mModelInfo->modelObj); +} + +bool AnimPlayerSimple::calcNeedUpdateAnimNext() { + if (!is11()) + return false; + + applyTo(); + + if (getAnimFrameRate() <= 0 || (isAnimOneTime() && isAnimEnd())) { + setAnimToModel(nullptr); + set11(false); + } + return true; +} + +void AnimPlayerSimple::startAnim(const char* name) { + mResInfo = getAnimInfoTable()->findAnimInfo(name); + setAnimToModel(mResInfo); + applyTo(); + set10(true); + set11(true); +} + +void AnimPlayerSimple::update() { + if (is11() && !is10()) + mModelInfo->boneAnimObj->getFrameCtrlPtr()->update(); +} + +void AnimPlayerSimple::clearAnim() { + mModelInfo->boneAnimObj->ClearResult(); +} + +f32 AnimPlayerSimple::getAnimFrame() const { + return mModelInfo->boneAnimObj->getFrameCtrlPtr()->getFrame(); +} + +void AnimPlayerSimple::setAnimFrame(f32 frame) { + mModelInfo->boneAnimObj->getFrameCtrlPtr()->setFrame(frame); + applyTo(); + set10(true); + set11(true); +} + +f32 AnimPlayerSimple::getAnimFrameMax() const { + return mModelInfo->boneAnimObj->getFrameCtrlPtr()->getFrameMax(); +} + +f32 AnimPlayerSimple::getAnimFrameMax(const char* name) const { + return getAnimInfoTable()->findAnimInfo(name)->frameMax; +} + +f32 AnimPlayerSimple::getAnimFrameRate() const { + return mModelInfo->boneAnimObj->getFrameCtrlPtr()->getFrameRate(); +} + +void AnimPlayerSimple::setAnimFrameRate(f32 rate) { + mModelInfo->boneAnimObj->getFrameCtrlPtr()->setFrameRate(rate); + applyTo(); + set11(true); +} + +bool AnimPlayerSimple::isAnimExist(const char* name) const { + return getAnimInfoTable()->tryFindAnimInfo(name) != nullptr; +} + +bool AnimPlayerSimple::isAnimEnd() const { + if (!isAnimPlaying()) + return true; + + return mModelInfo->boneAnimObj->getFrameCtrlPtr()->isEnd(); +} + +bool AnimPlayerSimple::isAnimOneTime() const { + return mModelInfo->boneAnimObj->getFrameCtrlPtr()->isOneTime(); +} + +bool AnimPlayerSimple::isAnimOneTime(const char* name) const { + return !getAnimInfoTable()->findAnimInfo(name)->isLooping; +} + +bool AnimPlayerSimple::isAnimPlaying() const { + return mResInfo != nullptr; +} + +const char* AnimPlayerSimple::getPlayingAnimName() const { + return isAnimPlaying() ? mResInfo->name : ""; +} + +} // namespace al diff --git a/lib/al/Project/Anim/AnimPlayerSimple.h b/lib/al/Project/Anim/AnimPlayerSimple.h index d1c95c433b..56ef18c8a6 100644 --- a/lib/al/Project/Anim/AnimPlayerSimple.h +++ b/lib/al/Project/Anim/AnimPlayerSimple.h @@ -4,6 +4,11 @@ #include "Project/Anim/AnimPlayerBase.h" +namespace nn::g3d { +class ModelObj; +class BoneVisibilityAnimObj; +} // namespace nn::g3d + namespace al { struct AnimPlayerInitInfo; struct AnimResInfo; @@ -12,31 +17,36 @@ class AnimPlayerSimple : public AnimPlayerBase { public: AnimPlayerSimple(); - virtual void init(const AnimPlayerInitInfo*) = 0; - virtual void setAnimToModel(const AnimResInfo*) = 0; + virtual void init(const AnimPlayerInitInfo* info) = 0; + virtual void setAnimToModel(const AnimResInfo* resInfo) = 0; virtual void applyTo(); bool calcNeedUpdateAnimNext() override; - void startAnim(const char*); + void startAnim(const char* name); void update(); void clearAnim(); f32 getAnimFrame() const; - void setAnimFrame(f32); + void setAnimFrame(f32 frame); f32 getAnimFrameMax() const; - f32 getAnimFrameMax(const char*) const; + f32 getAnimFrameMax(const char* name) const; f32 getAnimFrameRate() const; - void setAnimFrameRate(f32); - bool isAnimExist(const char*) const; + void setAnimFrameRate(f32 rate); + bool isAnimExist(const char* name) const; bool isAnimEnd() const; bool isAnimOneTime() const; - bool isAnimOneTime(const char*) const; + bool isAnimOneTime(const char* name) const; bool isAnimPlaying() const; const char* getPlayingAnimName() const; private: - void* _18; - const char* mPlayingAnimName; + struct ModelInfo { + nn::g3d::ModelObj* modelObj = nullptr; + nn::g3d::BoneVisibilityAnimObj* boneAnimObj = nullptr; + }; + + ModelInfo* mModelInfo = nullptr; + AnimResInfo* mResInfo = nullptr; }; static_assert(sizeof(AnimPlayerSimple) == 0x28);