diff options
Diffstat (limited to 'src/m/m3d/m_mdl.cpp')
| -rw-r--r-- | src/m/m3d/m_mdl.cpp | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/m/m3d/m_mdl.cpp b/src/m/m3d/m_mdl.cpp new file mode 100644 index 00000000..a6879840 --- /dev/null +++ b/src/m/m3d/m_mdl.cpp @@ -0,0 +1,239 @@ +#include <m/m3d/m3d.h> +#include <m/m3d/m_mdl.h> +#include <nw4r/g3d/g3d_scnmdlsmpl.h> + +namespace m3d { + +mdl_c::mdlCallback_c::mdlCallback_c() { + mNumNode = 0; + mpNodes = nullptr; + mpBaseCallback = 0; + mpAlloc = nullptr; +} +mdl_c::mdlCallback_c::~mdlCallback_c() {} + +void mdl_c::mdlCallback_c::ExecCallbackA(nw4r::g3d::ChrAnmResult *result, nw4r::g3d::ResMdl mdl, + nw4r::g3d::FuncObjCalcWorld *o) { + u16 nodeId = o->GetNodeId(); + nw4r::g3d::ChrAnmResult *resPtr = &mpNodes[nodeId]; + if (mCalcRatio.is0x18() && !mCalcRatio.isEnd()) { + if (!mCalcRatio.is0x19()) { + *result = *resPtr; + } else { + u32 flags = result->mFlags; + f32 f2 = mCalcRatio.get0x10(); + f32 f1 = mCalcRatio.get0x14(); + + // 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); + result->VEC3_0x4.z = (result->VEC3_0x4.z * f1 + resPtr->VEC3_0x4.z * f2); + } else { + result->VEC3_0x4.x = (f1 + resPtr->VEC3_0x4.x * f2); + result->VEC3_0x4.y = (f1 + resPtr->VEC3_0x4.y * f2); + result->VEC3_0x4.z = (f1 + resPtr->VEC3_0x4.z * f2); + } + + nw4r::math::QUAT q1; + nw4r::math::QUAT q2; + + C_QUATMtx(q1, resPtr->mMtx); + if ((flags & 0x20) == 0) { + C_QUATMtx(q2, result->mMtx); + } else { + q2.x = 0.0f; + q2.y = 0.0f; + q2.z = 0.0f; + q2.w = 1.0f; + } + + C_QUATSlerp(q1, q2, q1, f1); + nw4r::math::VEC3 tmp; + tmp.x = result->mMtx._03; + tmp.y = result->mMtx._13; + tmp.z = result->mMtx._23; + 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; + } + result->mMtx._03 += resPtr->mMtx._03 * f2; + result->mMtx._13 += resPtr->mMtx._13 * f2; + result->mMtx._23 += resPtr->mMtx._23 * f2; + result->mFlags = result->mFlags & ~(0x80000000 | 0x00000040 | 0x00000020 | 0x00000008); + *resPtr = *result; + } + } else { + *resPtr = *result; + } + + if (mpBaseCallback != nullptr) { + mpBaseCallback->timingA(nodeId, result, mdl); + } +} + +void mdl_c::mdlCallback_c::ExecCallbackB(nw4r::g3d::WorldMtxManip *m, nw4r::g3d::ResMdl mdl, + nw4r::g3d::FuncObjCalcWorld *o) { + u16 nodeId = o->GetNodeId(); + if (mpBaseCallback != nullptr) { + mpBaseCallback->timingB(nodeId, m, mdl); + } + // Not sure what this does + u32 num = mdl.GetResNodeNumEntries(); + 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 *) { + if (mpBaseCallback != nullptr) { + mpBaseCallback->timingC(mat, mdl); + } + mCalcRatio.offUpdate(); +} + +bool mdl_c::mdlCallback_c::create(nw4r::g3d::ResMdl mdl, mAllocator_c *alloc, u32 *pSize) { + if (alloc == nullptr) { + alloc = internal::l_allocator_p; + } + + u32 size = 0; + if (pSize == nullptr) { + pSize = &size; + } + + mNumNode = mdl.GetResNodeNumEntries(); + size_t bufSize = mNumNode * sizeof(nw4r::g3d::ChrAnmResult); + mpNodes = (nw4r::g3d::ChrAnmResult *)MEMAllocFromAllocator(alloc, bufSize); + if (mpNodes == nullptr) { + return false; + } + + *pSize = ROUND_UP(bufSize + ROUND_UP(*pSize, 0x04), 0x04); + nw4r::g3d::ChrAnmResult *node = mpNodes; + for (int i = 0; i < mNumNode; i++) { + node->VEC3_0x4.x = 1.0f; + node->VEC3_0x4.y = 1.0f; + node->VEC3_0x4.z = 1.0f; + PSMTXIdentity(node->mMtx); + node++; + } + + mpAlloc = alloc; + return true; +} + +void mdl_c::mdlCallback_c::remove() { + mCalcRatio.remove(); + if (mpNodes != nullptr) { + // Probably an m_allocator inline + MEMFreeToAllocator(mpAlloc, mpNodes); + } + mpNodes = nullptr; + mpAlloc = nullptr; +} + +void mdl_c::mdlCallback_c::setBlendFrame(f32 frame) { + mCalcRatio.set(frame); +} +void mdl_c::mdlCallback_c::calcBlend() { + if (!mCalcRatio.isEnd()) { + mCalcRatio.calc(); + } +} + +mdl_c::mdl_c() : mpOwnedCallback(nullptr), mpCallback(nullptr) {} +mdl_c::~mdl_c() { + remove(); +} + +bool mdl_c::create(nw4r::g3d::ResMdl mdl, mAllocator_c *alloc, u32 bufferOption, int nView, u32 *pSize) { + return create(mdl, nullptr, alloc, bufferOption, nView, pSize); +} + +bool mdl_c::create(nw4r::g3d::ResMdl mdl, mdl_c::mdlCallback_c *cb, mAllocator_c *alloc, u32 bufferOption, int nView, + u32 *pSize) { + if (alloc == nullptr) { + alloc = internal::l_allocator_p; + } + + u32 tmp1; + u32 tmp2; + u32 *pSize1 = nullptr; + u32 *pSize2 = nullptr; + if (pSize != nullptr) { + pSize1 = &tmp1; + pSize2 = &tmp2; + } + + if (!smdl_c::create(mdl, alloc, bufferOption, nView, pSize1)) { + return false; + } + + if (cb == nullptr) { + mpOwnedCallback = (mdlCallback_c *)alloc->alloc(sizeof(mdlCallback_c)); + if (mpOwnedCallback == nullptr) { + remove(); + return false; + } + + new (mpOwnedCallback) mdlCallback_c(); + mpCallback = mpOwnedCallback; + } else { + mpCallback = cb; + } + if (!mpCallback->create(mdl, alloc, pSize2)) { + remove(); + return false; + } + + if (pSize != nullptr) { + *pSize = tmp1 + tmp2; + } + nw4r::g3d::ScnMdlSimple *sMdl; + sMdl = nw4r::g3d::G3dObj::DynamicCast<nw4r::g3d::ScnMdlSimple>(mpScnLeaf); + sMdl->SetCalcWorldCallback(mpCallback); + sMdl->EnableScnMdlCallbackTiming(nw4r::g3d::ScnObj::TIMING_ALL); + setCallback(nullptr); + return true; +} + +void mdl_c::remove() { + if (mpOwnedCallback != nullptr) { + mAllocator_c *alloc = mpOwnedCallback->getAllocator(); + mpOwnedCallback->remove(); + mpOwnedCallback->~mdlCallback_c(); + alloc->free(mpOwnedCallback); + mpOwnedCallback = nullptr; + mpCallback = nullptr; + } + bmdl_c::remove(); +} + +void mdl_c::setAnm(m3d::banm_c &anm) { + setAnm(anm, 0.0f); +} + +void mdl_c::play() { + bmdl_c::play(); + mpCallback->calcBlend(); +} + +void mdl_c::setAnm(m3d::banm_c &anm, f32 f) { + if (anm.getType() == nw4r::g3d::ScnMdlSimple::ANMOBJTYPE_CHR) { + mpCallback->setBlendFrame(f); + } + bmdl_c::setAnm(anm); +} + +void mdl_c::setCallback(callback_c *cb) { + mpCallback->setBaseCallback(cb); +} + +} // namespace m3d |
