diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt index afd2eae7..374697d0 100644 --- a/config/SOUE01/splits.txt +++ b/config/SOUE01/splits.txt @@ -280,6 +280,11 @@ m/m3d/m_anmchrblend.cpp: .text start:0x802E4DA0 end:0x802E5260 .data start:0x805424E8 end:0x80542500 +m/m3d/m_anmmatclr.cpp: + .text start:0x802E5260 end:0x802E5D94 + .data start:0x80542500 end:0x80542530 + .sdata2 start:0x8057CCD0 end:0x8057CCE0 + m/m3d/m_anmtexsrt.cpp: .text start:0x802E6EC0 end:0x802E7A54 .data start:0x80542598 end:0x805425C8 diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index fb49d727..6c020fc7 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -17454,30 +17454,30 @@ attach__Q23m3d13anmChrBlend_cFiPQ23m3d8anmChr_cf = .text:0x802E4FB0; // type:fun detach__Q23m3d13anmChrBlend_cFi = .text:0x802E5070; // type:function size:0xA0 setWeight__Q23m3d13anmChrBlend_cFif = .text:0x802E5110; // type:function size:0xB0 getWeight__Q23m3d13anmChrBlend_cCFi = .text:0x802E51C0; // type:function size:0xA0 -fn_802E5260 = .text:0x802E5260; // type:function size:0x58 -fn_802E52C0 = .text:0x802E52C0; // type:function size:0x8 -fn_802E52D0 = .text:0x802E52D0; // type:function size:0x7C -fn_802E5350 = .text:0x802E5350; // type:function size:0x11C -fn_802E5470 = .text:0x802E5470; // type:function size:0xB4 -fn_802E5530 = .text:0x802E5530; // type:function size:0x5C -fn_802E5590 = .text:0x802E5590; // type:function size:0x68 -fn_802E5600 = .text:0x802E5600; // type:function size:0xE0 -fn_802E56E0 = .text:0x802E56E0; // type:function size:0x23C -fn_802E5920 = .text:0x802E5920; // type:function size:0x6C -fn_802E5990 = .text:0x802E5990; // type:function size:0x8 -fn_802E59A0 = .text:0x802E59A0; // type:function size:0xEC -fn_802E5A90 = .text:0x802E5A90; // type:function size:0x140 -fn_802E5BD0 = .text:0x802E5BD0; // type:function size:0xAC -fn_802E5C80 = .text:0x802E5C80; // type:function size:0x60 -fn_802E5CE0 = .text:0x802E5CE0; // type:function size:0x10 -fn_802E5CF0 = .text:0x802E5CF0; // type:function size:0x10 -fn_802E5D00 = .text:0x802E5D00; // type:function size:0x10 -fn_802E5D10 = .text:0x802E5D10; // type:function size:0x10 -fn_802E5D20 = .text:0x802E5D20; // type:function size:0x10 -fn_802E5D30 = .text:0x802E5D30; // type:function size:0x10 -fn_802E5D40 = .text:0x802E5D40; // type:function size:0x14 -fn_802E5D60 = .text:0x802E5D60; // type:function size:0x14 -fn_802E5D80 = .text:0x802E5D80; // type:function size:0x14 +__dt__Q33m3d11anmMatClr_c7child_cFv = .text:0x802E5260; // type:function size:0x58 +getType__Q33m3d11anmMatClr_c7child_cFv = .text:0x802E52C0; // type:function size:0x8 +heapCost__Q33m3d11anmMatClr_c7child_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d9ResAnmClrb = .text:0x802E52D0; // type:function size:0x7C +create__Q33m3d11anmMatClr_c7child_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d9ResAnmClrP12mAllocator_cPUl = .text:0x802E5350; // type:function size:0x11C +setAnm__Q33m3d11anmMatClr_c7child_cFRQ23m3d6bmdl_cQ34nw4r3g3d9ResAnmClrQ23m3d10playMode_e = .text:0x802E5470; // type:function size:0xB4 +releaseAnm__Q33m3d11anmMatClr_c7child_cFv = .text:0x802E5530; // type:function size:0x5C +setFrmCtrlDefault__Q33m3d11anmMatClr_c7child_cFRQ34nw4r3g3d9ResAnmClrQ23m3d10playMode_e = .text:0x802E5590; // type:function size:0x68 +heapCost__Q23m3d11anmMatClr_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d9ResAnmClrlb = .text:0x802E5600; // type:function size:0xE0 +create__Q23m3d11anmMatClr_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d9ResAnmClrP12mAllocator_cPUll = .text:0x802E56E0; // type:function size:0x23C +__dt__Q23m3d11anmMatClr_cFv = .text:0x802E5920; // type:function size:0x6C +getType__Q23m3d11anmMatClr_cFv = .text:0x802E5990; // type:function size:0x8 +remove__Q23m3d11anmMatClr_cFv = .text:0x802E59A0; // type:function size:0xEC +setAnm__Q23m3d11anmMatClr_cFRQ23m3d6bmdl_cQ34nw4r3g3d9ResAnmClrlQ23m3d10playMode_e = .text:0x802E5A90; // type:function size:0x140 +play__Q23m3d11anmMatClr_cFv = .text:0x802E5BD0; // type:function size:0xAC +play__Q23m3d11anmMatClr_cFl = .text:0x802E5C80; // type:function size:0x60 +getFrame__Q23m3d11anmMatClr_cCFl = .text:0x802E5CE0; // type:function size:0x10 +setFrame__Q23m3d11anmMatClr_cFfl = .text:0x802E5CF0; // type:function size:0x10 +getRate__Q23m3d11anmMatClr_cCFl = .text:0x802E5D00; // type:function size:0x10 +setRate__Q23m3d11anmMatClr_cFfl = .text:0x802E5D10; // type:function size:0x10 +isStop__Q23m3d11anmMatClr_cCFl = .text:0x802E5D20; // type:function size:0x10 +checkFrame__Q23m3d11anmMatClr_cCFfl = .text:0x802E5D30; // type:function size:0x10 +setPlayMode__Q23m3d11anmMatClr_cFQ23m3d10playMode_el = .text:0x802E5D40; // type:function size:0x14 +getFrameMax__Q23m3d11anmMatClr_cCFl = .text:0x802E5D60; // type:function size:0x14 +getFrameStart__Q23m3d11anmMatClr_cCFl = .text:0x802E5D80; // type:function size:0x14 fn_802E5DA0 = .text:0x802E5DA0; // type:function size:0x68 fn_802E5E10 = .text:0x802E5E10; // type:function size:0x14 fn_802E5E30 = .text:0x802E5E30; // type:function size:0x8 @@ -17494,7 +17494,7 @@ fn_802E6140 = .text:0x802E6140; // type:function size:0x120 fn_802E6260 = .text:0x802E6260; // type:function size:0xEC fn_802E6350 = .text:0x802E6350; // type:function size:0x68 fn_802E63C0 = .text:0x802E63C0; // type:function size:0x8 -__dt__Q33m3d11anmMatClr_c7child_cFv = .text:0x802E63D0; // type:function size:0x58 +fn_802E63D0 = .text:0x802E63D0; // type:function size:0x58 heapCost__Q33m3d11anmTexPat_c7child_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d12ResAnmTexPatb = .text:0x802E6430; // type:function size:0x7C create__Q33m3d11anmTexPat_c7child_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d12ResAnmTexPatP12mAllocator_cPUl = .text:0x802E64B0; // type:function size:0x11C fn_802E65D0 = .text:0x802E65D0; // type:function size:0xB4 @@ -24473,9 +24473,9 @@ fn_80443B40 = .text:0x80443B40; // type:function size:0x54 fn_80443BA0 = .text:0x80443BA0; // type:function size:0xF4 fn_80443CA0 = .text:0x80443CA0; // type:function size:0xB8 fn_80443D60 = .text:0x80443D60; // type:function size:0x7C -fn_80443DE0 = .text:0x80443DE0; // type:function size:0x134 +Construct__Q34nw4r3g3d20AnmObjMatClrOverrideFP12MEMAllocatorPUlQ34nw4r3g3d6ResMdli = .text:0x80443DE0; // type:function size:0x134 fn_80443F20 = .text:0x80443F20; // type:function size:0xB0 -fn_80443FD0 = .text:0x80443FD0; // type:function size:0x1F0 +Construct__Q34nw4r3g3d15AnmObjMatClrResFP12MEMAllocatorPUlQ34nw4r3g3d9ResAnmClrQ34nw4r3g3d6ResMdlb = .text:0x80443FD0; // type:function size:0x1F0 fn_804441C0 = .text:0x804441C0; // type:function size:0xC0 fn_80444280 = .text:0x80444280; // type:function size:0x8 fn_80444290 = .text:0x80444290; // type:function size:0xB4 @@ -29091,8 +29091,8 @@ lbl_804F7070 = .rodata:0x804F7070; // type:object size:0x10 lbl_804F7080 = .rodata:0x804F7080; // type:object size:0x18 lbl_804F7098 = .rodata:0x804F7098; // type:object size:0x18 lbl_804F70B0 = .rodata:0x804F70B0; // type:object size:0x18 -lbl_804F70C8 = .rodata:0x804F70C8; // type:object size:0x20 -lbl_804F70E8 = .rodata:0x804F70E8; // type:object size:0x18 +TYPE_NAME__Q34nw4r3g3d20AnmObjMatClrOverride = .rodata:0x804F70C8; // type:object size:0x20 +TYPE_NAME__Q34nw4r3g3d15AnmObjMatClrRes = .rodata:0x804F70E8; // type:object size:0x18 lbl_804F7100 = .rodata:0x804F7100; // type:object size:0x18 lbl_804F7118 = .rodata:0x804F7118; // type:object size:0x18 lbl_804F7130 = .rodata:0x804F7130; // type:object size:0x20 @@ -35684,8 +35684,8 @@ lbl_80542460 = .data:0x80542460; // type:object size:0x40 lbl_805424A0 = .data:0x805424A0; // type:object size:0x30 __vt__Q23m3d8anmChr_c = .data:0x805424D0; // type:object size:0x18 __vt__Q23m3d13anmChrBlend_c = .data:0x805424E8; // type:object size:0x18 -lbl_80542500 = .data:0x80542500; // type:object size:0x18 -lbl_80542518 = .data:0x80542518; // type:object size:0x18 +__vt__Q23m3d11anmMatClr_c = .data:0x80542500; // type:object size:0x18 +__vt__Q33m3d11anmMatClr_c7child_c = .data:0x80542518; // type:object size:0x18 lbl_80542530 = .data:0x80542530; // type:object size:0x20 lbl_80542550 = .data:0x80542550; // type:object size:0x18 lbl_80542568 = .data:0x80542568; // type:object size:0x18 diff --git a/configure.py b/configure.py index 6263320c..1b00a4b9 100644 --- a/configure.py +++ b/configure.py @@ -338,6 +338,7 @@ def nw4rLib(lib_name, objects, extra_cflags=[]): Object(Matching, "m/m3d/m_anmchr.cpp"), Object(Matching, "m/m3d/m_anmchrblend.cpp"), Object(Matching, "m/m3d/m_anmtexsrt.cpp"), + Object(Matching, "m/m3d/m_anmmatclr.cpp"), Object(Matching, "m/m3d/m_anmvis.cpp"), Object(Matching, "m/m3d/m_banm.cpp"), Object(NonMatching, "m/m3d/m_bmdl.cpp"), diff --git a/include/m/m3d/m_anmmatclr.h b/include/m/m3d/m_anmmatclr.h new file mode 100644 index 00000000..c12bf296 --- /dev/null +++ b/include/m/m3d/m_anmmatclr.h @@ -0,0 +1,57 @@ +#ifndef M3D_M_ANMTEXSRT_H +#define M3D_M_ANMTEXSRT_H + +#include +#include +#include + +namespace m3d { + +class anmMatClr_c : public banm_c { + class child_c : public fanm_c { + public: + child_c() {} + virtual ~child_c(); + virtual int getType() override; + + static u32 heapCost(nw4r::g3d::ResMdl, nw4r::g3d::ResAnmClr, bool); + bool create(nw4r::g3d::ResMdl, nw4r::g3d::ResAnmClr, mAllocator_c *, u32 *); + void setAnm(bmdl_c &, nw4r::g3d::ResAnmClr, playMode_e); + void releaseAnm(); + void setFrmCtrlDefault(nw4r::g3d::ResAnmClr &, playMode_e); + }; + +public: + anmMatClr_c() : mpChildren(nullptr) {} + virtual ~anmMatClr_c(); + + virtual int getType() override; + virtual void remove() override; + virtual void play() override; + + bool create(nw4r::g3d::ResMdl, nw4r::g3d::ResAnmClr, mAllocator_c *, u32 *, s32); + static u32 heapCost(nw4r::g3d::ResMdl, nw4r::g3d::ResAnmClr, s32, bool); + + void setAnm(bmdl_c &, nw4r::g3d::ResAnmClr, s32, playMode_e); + + void play(s32); + f32 getFrame(s32) const; + void setFrame(f32, s32); + f32 getRate(s32) const; + void setRate(f32, s32); + bool isStop(s32) const; + + bool checkFrame(f32, s32) const; + + void setPlayMode(playMode_e, s32); + f32 getFrameMax(s32) const; + void setFrameStart(f32, s32); + f32 getFrameStart(s32) const; + +private: + child_c *mpChildren; +}; + +} // namespace m3d + +#endif diff --git a/include/nw4r/g3d/g3d_anmclr.h b/include/nw4r/g3d/g3d_anmclr.h index 6a009f19..892abe70 100644 --- a/include/nw4r/g3d/g3d_anmclr.h +++ b/include/nw4r/g3d/g3d_anmclr.h @@ -1,6 +1,8 @@ #ifndef NW4R_G3D_ANMCLR_H #define NW4R_G3D_ANMCLR_H #include "common.h" +#include "nw4r/g3d/g3d_anmobj.h" +#include "nw4r/g3d/g3d_resanmclr.h" namespace nw4r { namespace g3d { @@ -11,6 +13,73 @@ struct ClrAnmResult { u32 COLORS_0x4[ANM_COUNT]; UNKWORD WORDS_0x30[ANM_COUNT]; }; + +class AnmObjMatClrRes; + +class AnmObjMatClr : public AnmObj { +public: + static const G3dObj::TypeObj GetTypeObjStatic() { + return TypeObj(TYPE_NAME); + } + + virtual ClrAnmResult *GetResult(); // at 0x38 + virtual void Attach(s32, AnmObjMatClrRes *res); // at 0x3C + virtual void Detach(s32); // at 0x40 + +private: + int mChildrenArraySize; + u16 *mpChildrenArray; + + NW4R_G3D_TYPE_OBJ_DECL(AnmObjMatClr); +}; + +class AnmObjMatClrNode : public AnmObjMatClr { +public: + static const G3dObj::TypeObj GetTypeObjStatic() { + return TypeObj(TYPE_NAME); + } + + inline int Size() { + return mNodeArraySize; + } + + AnmObjMatClrRes *GetNode(int i) { + return mpNodes[i]; + } + +private: + int mNodeArraySize; + AnmObjMatClrRes **mpNodes; + + NW4R_G3D_TYPE_OBJ_DECL(AnmObjMatClrNode); +}; + +class AnmObjMatClrRes : public AnmObjMatClr, public FrameCtrl { +public: + static const G3dObj::TypeObj GetTypeObjStatic() { + return TypeObj(TYPE_NAME); + } + + static AnmObjMatClrRes *Construct(MEMAllocator *, u32 *, ResAnmClr, ResMdl, bool); + +private: + ResAnmClr mRes; + TexSrtAnmResult *mpResultCache; + + NW4R_G3D_TYPE_OBJ_DECL(AnmObjMatClrRes); +}; + +class AnmObjMatClrOverride : public AnmObjMatClrNode { +public: + static const G3dObj::TypeObj GetTypeObjStatic() { + return TypeObj(TYPE_NAME); + } + + static AnmObjMatClrOverride *Construct(MEMAllocator *, u32 *, ResMdl, int); + + NW4R_G3D_TYPE_OBJ_DECL(AnmObjMatClrOverride); +}; + } // namespace g3d } // namespace nw4r diff --git a/include/nw4r/g3d/g3d_resanmclr.h b/include/nw4r/g3d/g3d_resanmclr.h index 85c5327c..78feba26 100644 --- a/include/nw4r/g3d/g3d_resanmclr.h +++ b/include/nw4r/g3d/g3d_resanmclr.h @@ -33,6 +33,9 @@ namespace nw4r char UNK_0xC[0x4]; s32 mMatDictOffset; // at 0x10 ResAnmClrInfoData mInfo; // at 0x14 + char UNK_0x1E[0x2]; + u16 mNumFrames; // at 0x20 + AnmPolicy mAnmPolicy; // at 0x24 }; struct ResAnmClr @@ -55,6 +58,16 @@ namespace nw4r { return ref().mRevision == REVISION; } + + AnmPolicy GetAnmPolicy() const + { + return ref().mAnmPolicy; + } + + int GetNumFrame() const + { + return ref().mNumFrames; + } inline const ResAnmClrMatData * GetMatAnm(u32 i) const { diff --git a/src/m/m3d/m_anmmatclr.cpp b/src/m/m3d/m_anmmatclr.cpp new file mode 100644 index 00000000..64012032 --- /dev/null +++ b/src/m/m3d/m_anmmatclr.cpp @@ -0,0 +1,203 @@ +#include +#include +#include +#include + +namespace m3d { + +anmMatClr_c::child_c::~child_c() {} + +int anmMatClr_c::child_c::getType() { + return 0x02; +} + +u32 anmMatClr_c::child_c::heapCost(nw4r::g3d::ResMdl mdl, nw4r::g3d::ResAnmClr clr, bool b) { + u32 size = 0; + nw4r::g3d::AnmObjMatClrRes::Construct(nullptr, &size, clr, mdl, false); + if (b) { + size = ROUND_UP(mHeap::frmHeapCost(size, 0x20), 0x20); + } + return size; +} + +bool anmMatClr_c::child_c::create(nw4r::g3d::ResMdl mdl, nw4r::g3d::ResAnmClr clr, mAllocator_c *alloc, u32 *pSize) { + if (alloc == nullptr) { + alloc = internal::l_allocator_p; + } + + u32 size; + if (pSize == nullptr) { + pSize = &size; + } + + *pSize = child_c::heapCost(mdl, clr, false); + if (!createAllocator(alloc, pSize)) { + return false; + } + + mpAnmObj = nw4r::g3d::AnmObjMatClrRes::Construct(&mAllocator, nullptr, clr, mdl, false); + + if (!mpAnmObj->Bind(mdl)) { + remove(); + return false; + } + setFrmCtrlDefault(clr, PLAY_MODE_4); + return true; +} + +void anmMatClr_c::child_c::setAnm(m3d::bmdl_c &mdl, nw4r::g3d::ResAnmClr clr, m3d::playMode_e mode) { + releaseAnm(); + mpAnmObj = nw4r::g3d::AnmObjMatClrRes::Construct(&mAllocator, nullptr, clr, mdl.getResMdl(), false); + mpAnmObj->Bind(mdl.getResMdl()); + setFrmCtrlDefault(clr, mode); +} + +void anmMatClr_c::child_c::releaseAnm() { + if (mpAnmObj != nullptr) { + mpAnmObj->Release(); + mpFrameHeap->free(3); + mpAnmObj = nullptr; + } +} + +void anmMatClr_c::child_c::setFrmCtrlDefault(nw4r::g3d::ResAnmClr &clr, playMode_e mode) { + if (mode == PLAY_MODE_4) { + mode = clr.GetAnmPolicy() == nw4r::g3d::ANM_POLICY_ONETIME ? PLAY_MODE_1 : PLAY_MODE_0; + } + set(clr.GetNumFrame(), mode, 1.0f, -1.0f); +} + +u32 anmMatClr_c::heapCost(nw4r::g3d::ResMdl mdl, nw4r::g3d::ResAnmClr clr, s32 num, bool b) { + u32 size = 0; + nw4r::g3d::AnmObjMatClrOverride::Construct(nullptr, &size, mdl, num); + size += ROUND_UP(num * sizeof(child_c), 0x20); + u32 childCost = child_c::heapCost(mdl, clr, true); + size += num * ROUND_UP(childCost, 0x20); + + if (b) { + size = ROUND_UP(mHeap::frmHeapCost(size, 0x20), 0x20); + } + return size; +} + +bool anmMatClr_c::create(nw4r::g3d::ResMdl mdl, nw4r::g3d::ResAnmClr clr, mAllocator_c *alloc, u32 *pSize, s32 num) { + if (alloc == nullptr) { + alloc = internal::l_allocator_p; + } + + u32 size = 0; + if (pSize == nullptr) { + pSize = &size; + } + + *pSize = heapCost(mdl, clr, num, false); + if (!createAllocator(alloc, pSize)) { + return false; + } + + mpAnmObj = nw4r::g3d::AnmObjMatClrOverride::Construct(&mAllocator, nullptr, mdl, num); + + // TODO inline? + mpChildren = (child_c *)MEMAllocFromAllocator(&mAllocator, ROUND_UP(num * sizeof(child_c), 0x20)); + + nw4r::g3d::AnmObjMatClrOverride *obj = nw4r::g3d::G3dObj::DynamicCast(mpAnmObj); + child_c *child = mpChildren; + for (int i = 0; i < num; i++) { + new (child) child_c(); + if (!child->create(mdl, clr, &mAllocator, nullptr)) { + mHeap::destroyFrmHeap(mpFrameHeap); + return false; + } + + if (i == 0) { + obj->Attach(i, nw4r::g3d::G3dObj::DynamicCast(child->getAnimObj())); + } else { + child->releaseAnm(); + } + child++; + } + + return true; +} + +anmMatClr_c::~anmMatClr_c() { + anmMatClr_c::remove(); +} + +int anmMatClr_c::getType() { + return 0x02; +} + +void anmMatClr_c::remove() { + nw4r::g3d::AnmObjMatClrOverride *o = nw4r::g3d::G3dObj::DynamicCast(mpAnmObj); + if (o != nullptr && mpChildren != 0) { + int size = o->Size(); + for (int i = 0; i < size; i++) { + mpChildren[i].remove(); + } + mpChildren = nullptr; + } + banm_c::remove(); +} + +void anmMatClr_c::setAnm(bmdl_c &mdl, nw4r::g3d::ResAnmClr clr, s32 idx, playMode_e mode) { + nw4r::g3d::AnmObjMatClrOverride *o = nw4r::g3d::G3dObj::DynamicCast(mpAnmObj); + o->Detach(idx); + mpChildren[idx].setAnm(mdl, clr, mode); + + nw4r::g3d::AnmObjMatClrRes *res = + nw4r::g3d::G3dObj::DynamicCast(mpChildren[idx].getAnimObj()); + o->Attach(idx, res); +} + +void anmMatClr_c::play() { + nw4r::g3d::AnmObjMatClrOverride *o = nw4r::g3d::G3dObj::DynamicCast(mpAnmObj); + int size = o->Size(); + for (int i = 0; i < size; i++) { + play(i); + } +} + +void anmMatClr_c::play(s32 idx) { + if (mpChildren[idx].IsBound()) { + mpChildren[idx].play(); + } +} + +f32 anmMatClr_c::getFrame(s32 idx) const { + return mpChildren[idx].getFrame(); +} + +void anmMatClr_c::setFrame(f32 f, s32 idx) { + mpChildren[idx].setFrameOnly(f); +} + +f32 anmMatClr_c::getRate(s32 idx) const { + mpChildren[idx].getRate(); +} + +void anmMatClr_c::setRate(f32 f, s32 idx) { + mpChildren[idx].setRate(f); +} + +bool anmMatClr_c::isStop(s32 idx) const { + return mpChildren[idx].isStop(); +} + +bool anmMatClr_c::checkFrame(f32 f, s32 idx) const { + return mpChildren[idx].checkFrame(f); +} + +void anmMatClr_c::setPlayMode(playMode_e mode, s32 idx) { + mpChildren[idx].setPlayState(mode); +} + +f32 anmMatClr_c::getFrameMax(s32 idx) const { + return mpChildren[idx].getEndFrame(); +} + +f32 anmMatClr_c::getFrameStart(s32 idx) const { + return mpChildren[idx].getStartFrame(); +} + +} // namespace m3d