diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index d0f907b6..6e601e2e 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -22199,7 +22199,7 @@ PSMTXTrans = .text:0x803B8770; // type:function size:0x34 fn_803B87B0 = .text:0x803B87B0; // type:function size:0x4C fn_803B8800 = .text:0x803B8800; // type:function size:0x28 fn_803B8830 = .text:0x803B8830; // type:function size:0x58 -fn_803B8890 = .text:0x803B8890; // type:function size:0xA4 +PSMTXQuat = .text:0x803B8890; // type:function size:0xA4 fn_803B8940 = .text:0x803B8940; // type:function size:0x174 fn_803B8AC0 = .text:0x803B8AC0; // type:function size:0xA4 C_MTXLightPerspective = .text:0x803B8B70; // type:function size:0xF8 diff --git a/configure.py b/configure.py index c7f04a70..b072e5f1 100644 --- a/configure.py +++ b/configure.py @@ -348,7 +348,7 @@ def nw4rLib(lib_name, objects, extra_cflags=[]): Object(NonMatching, "m/m3d/m_bmdl.cpp"), Object(Matching, "m/m3d/m_calc_ratio.cpp"), Object(NonMatching, "m/m3d/m_fanm.cpp"), - Object(NonMatching, "m/m3d/m_mdl.cpp"), + Object(Matching, "m/m3d/m_mdl.cpp"), Object(NonMatching, "m/m3d/m_scnLeaf.cpp"), Object(Matching, "m/m3d/m_smdl.cpp"), Object(Matching, "m/m_allocator.cpp"), diff --git a/include/m/m3d/m_mdl.h b/include/m/m3d/m_mdl.h index 66193ff7..d118e841 100644 --- a/include/m/m3d/m_mdl.h +++ b/include/m/m3d/m_mdl.h @@ -22,10 +22,7 @@ class callback_c { class mdl_c : public smdl_c { public: - // TODO this is not the correct callback class, since NSMBW has - // the A, B, C names and also the _CALC_X from IScnObjCallback, - // so there must be a different callback interface - class mdlCallback_c : public nw4r::g3d::IScnObjCallback { + class mdlCallback_c : public nw4r::g3d::ICalcWorldCallback { public: mdlCallback_c(); virtual ~mdlCallback_c(); diff --git a/include/nw4r/g3d/g3d_calcworld.h b/include/nw4r/g3d/g3d_calcworld.h index 7ea59a78..7c9ef69d 100644 --- a/include/nw4r/g3d/g3d_calcworld.h +++ b/include/nw4r/g3d/g3d_calcworld.h @@ -23,6 +23,17 @@ struct FuncObjCalcWorld { class WorldMtxManip {}; +// Name from ketteiban +class ICalcWorldCallback { +public: + virtual ~ICalcWorldCallback() {} + + virtual void ExecCallbackA(nw4r::g3d::ChrAnmResult *, nw4r::g3d::ResMdl, nw4r::g3d::FuncObjCalcWorld *) {} + virtual void ExecCallbackB(nw4r::g3d::WorldMtxManip *, nw4r::g3d::ResMdl, nw4r::g3d::FuncObjCalcWorld *) {} + virtual void ExecCallbackC(nw4r::math::MTX34 *, nw4r::g3d::ResMdl, nw4r::g3d::FuncObjCalcWorld *) {} +}; + + void CalcWorld(math::MTX34 *, u32 *, const u8 *, const math::MTX34 *, ResMdl, AnmObjChr *, FuncObjCalcWorld *, u32); void CalcWorld(math::MTX34 *, u32 *, const u8 *, const math::MTX34 *, ResMdl, AnmObjChr *, FuncObjCalcWorld *); diff --git a/include/nw4r/g3d/g3d_scnmdlsmpl.h b/include/nw4r/g3d/g3d_scnmdlsmpl.h index f788a0e9..8082a4a2 100644 --- a/include/nw4r/g3d/g3d_scnmdlsmpl.h +++ b/include/nw4r/g3d/g3d_scnmdlsmpl.h @@ -4,6 +4,7 @@ #include "nw4r/math/math_types.h" #include "nw4r/g3d/g3d_resmdl.h" #include "nw4r/g3d/g3d_scnobj.h" +#include "nw4r/g3d/g3d_calcworld.h" namespace nw4r { namespace g3d { @@ -75,6 +76,10 @@ class ScnMdlSimple : public ScnLeaf { return mNumViewMtx; } + void SetCalcWorldCallback(ICalcWorldCallback *cb) { + mpCalcWorldCallback = cb; + } + private: ResMdl mResMdl; // at 0xE8 math::MTX34 *mWldMatrixArray; // at 0xEC @@ -90,6 +95,8 @@ class ScnMdlSimple : public ScnLeaf { void *mByteCodeMix; // at 0x10C void *mByteCodeDrawOpa; // at 0x110 void *mByteCodeDrawXlu; // at 0x114 + UNKWORD WORD_0x118; + ICalcWorldCallback *mpCalcWorldCallback; // at 0x11C NW4R_G3D_TYPE_OBJ_DECL(ScnMdlSimple); }; diff --git a/src/m/m3d/m_mdl.cpp b/src/m/m3d/m_mdl.cpp index acd027e0..9d908857 100644 --- a/src/m/m3d/m_mdl.cpp +++ b/src/m/m3d/m_mdl.cpp @@ -14,7 +14,8 @@ mdl_c::mdlCallback_c::~mdlCallback_c() {} void mdl_c::mdlCallback_c::ExecCallbackA(nw4r::g3d::ChrAnmResult *result, nw4r::g3d::ResMdl mdl, nw4r::g3d::FuncObjCalcWorld *o) { - nw4r::g3d::ChrAnmResult *resPtr = &mpNodes[o->GetNodeId()]; + u16 nodeId = o->GetNodeId(); + nw4r::g3d::ChrAnmResult *resPtr = &mpNodes[nodeId]; if (mCalcRatio.is0x18() && !mCalcRatio.isEnd()) { if (!mCalcRatio.is0x19()) { *result = *resPtr; @@ -23,7 +24,8 @@ void mdl_c::mdlCallback_c::ExecCallbackA(nw4r::g3d::ChrAnmResult *result, nw4r:: f32 f2 = mCalcRatio.get0x10(); f32 f1 = mCalcRatio.get0x14(); - // TODO the math operators cause ps inline assembly + // TODO clean up this code, what does it even do, why do operators + // break if ((flags & 8) == 0) { result->VEC3_0x4.x = (result->VEC3_0x4.x * f1 + resPtr->VEC3_0x4.x * f2); result->VEC3_0x4.y = (result->VEC3_0x4.y * f1 + resPtr->VEC3_0x4.y * f2); @@ -36,8 +38,8 @@ void mdl_c::mdlCallback_c::ExecCallbackA(nw4r::g3d::ChrAnmResult *result, nw4r:: nw4r::math::QUAT q1; nw4r::math::QUAT q2; + C_QUATMtx(q1, resPtr->mMtx); - // TODO ... if ((flags & 0x20) == 0) { C_QUATMtx(q2, result->mMtx); } else { @@ -46,12 +48,28 @@ void mdl_c::mdlCallback_c::ExecCallbackA(nw4r::g3d::ChrAnmResult *result, nw4r:: q2.z = 0.0f; q2.w = 1.0f; } - nw4r::math::QUAT q3; - C_QUATSlerp(q1, q2, q3, f1); - PSMTXQuat(result->mMtx, q3); - result->VEC3_0x10 = (flags & 0x40) == 0 ? - nw4r::math::VEC3(result->VEC3_0x10.x * f1, result->VEC3_0x10.y * f1, result->VEC3_0x10.z * f1) : - result->VEC3_0x10; + + C_QUATSlerp(q1, q2, q1, f1); + // TODO weird hacks to force register order, probably more inlines + f32 tmp3, tmp2, tmp1; + tmp1 = result->mMtx._03; + tmp2 = result->mMtx._13; + tmp3 = result->mMtx._23; + nw4r::math::VEC3 tmp(tmp1, tmp2, tmp3); + PSMTXQuat(result->mMtx, q1); + result->mMtx._03 = tmp.x; + result->mMtx._13 = tmp.y; + result->mMtx._23 = tmp.z; + if ((flags & 0x40) == 0) { + result->mMtx._03 = tmp.x * f1; + result->mMtx._13 = tmp.y * f1; + result->mMtx._23 = tmp.z * f1; + } + u32 flags2 = result->mFlags & ~(0x80000000 | 0x80000040 | 0x80000020 | 0x80000008); + result->mMtx._03 += resPtr->mMtx._03 * f2; + result->mMtx._13 += resPtr->mMtx._13 * f2; + result->mMtx._23 += resPtr->mMtx._23 * f2; + result->mFlags = flags2; *resPtr = *result; } } else { @@ -59,7 +77,7 @@ void mdl_c::mdlCallback_c::ExecCallbackA(nw4r::g3d::ChrAnmResult *result, nw4r:: } if (mpBaseCallback != nullptr) { - mpBaseCallback->timingA(mNumNode, result, mdl); + mpBaseCallback->timingA(nodeId, result, mdl); } } @@ -69,9 +87,11 @@ void mdl_c::mdlCallback_c::ExecCallbackB(nw4r::g3d::WorldMtxManip *m, nw4r::g3d: if (mpBaseCallback != nullptr) { mpBaseCallback->timingB(nodeId, m, mdl); } + // Not sure what this does u32 num = mdl.GetResNodeNumEntries(); - u32 numInc = num + 1; - o->SetNodeId(numInc - (numInc / num) * num); + u32 nodeInc = nodeId + 1; + u32 tmp = (nodeInc / num); + o->SetNodeId(nodeInc - tmp * num); } void mdl_c::mdlCallback_c::ExecCallbackC(nw4r::math::MTX34 *mat, nw4r::g3d::ResMdl mdl, nw4r::g3d::FuncObjCalcWorld *) { @@ -185,7 +205,7 @@ bool mdl_c::create(nw4r::g3d::ResMdl mdl, mdl_c::mdlCallback_c *cb, mAllocator_c } nw4r::g3d::ScnMdlSimple *sMdl; sMdl = nw4r::g3d::G3dObj::DynamicCast(mpScnLeaf); - sMdl->SetCallback(mpCallback); + sMdl->SetCalcWorldCallback(mpCallback); sMdl->EnableScnObjCallbackTiming(nw4r::g3d::ScnObj::TIMING_ALL); setCallback(nullptr); return true;