#include "nw4r/g3d.h" // IWYU pragma: export #include namespace nw4r { namespace g3d { /****************************************************************************** * * Paired-single math implementation * ******************************************************************************/ namespace { // Allows struct offsets inside assembly using nw4r::math::MTX34; using nw4r::math::VEC3; const f32 norm_epsilon = 1e-18f; asm void GetModelLocalAxisY2( register math::VEC3 *pVec, register const math::MTX34 *pModelMtx, register const math::MTX34 *pParentModelMtx ) { // clang-format off nofralloc psq_l f0, MTX34._00(pParentModelMtx), 1, 0 psq_l f1, MTX34._01(pParentModelMtx), 0, 0 psq_l f2, MTX34._10(pParentModelMtx), 1, 0 ps_merge10 f6, f1, f0 psq_l f3, MTX34._11(pParentModelMtx), 0, 0 psq_l f4, MTX34._20(pParentModelMtx), 1, 0 ps_merge10 f7, f3, f2 psq_l f5, MTX34._21(pParentModelMtx), 0, 0 ps_mul f11, f3, f6 ps_mul f13, f5, f7 ps_merge10 f8, f5, f4 ps_msub f11, f1, f7, f11 ps_mul f12, f1, f8 ps_msub f13, f3, f8, f13 lis r12, norm_epsilon@ha psq_l f3, MTX34._12(pModelMtx), 1, 0 ps_msub f12, f5, f6, f12 addi r12, r12, norm_epsilon@l ps_mul f7, f0, f13 ps_mul f9, f0, f5 psq_l f6, 0x0(r12), 1, 0 ps_madd f7, f2, f12, f7 ps_sub f13, f13, f13 psq_l f2, MTX34._02(pModelMtx), 1, 0 ps_madd f7, f4, f11, f7 ps_msub f9, f1, f4, f9 psq_l f1, MTX34._10(pModelMtx), 0, 0 ps_abs f8, f7 psq_st f13, VEC3.z(pVec), 1, 0 ps_cmpo0 cr0, f8, f6 bge _lbl_8044F884 psq_st f13, VEC3.x(pVec), 0, 0 blr _lbl_8044F884: fres f8, f7 psq_l f0, MTX34._00(pModelMtx), 0, 0 ps_add f11, f8, f8 ps_mul f10, f7, f8 ps_merge00 f4, f0, f1 ps_nmsub f8, f8, f10, f11 ps_merge11 f5, f0, f1 ps_merge00 f6, f2, f3 ps_muls0 f12, f12, f8 ps_muls0 f9, f9, f8 ps_muls0 f0, f4, f12 ps_madds1 f0, f5, f12, f0 ps_madds0 f0, f6, f9, f0 psq_st f0, VEC3.x(pVec), 0, 0 blr // clang-format on } asm void GetModelLocalAxisY3( register math::VEC3 *pVec, register const math::MTX34 *pModelMtx, register const math::MTX34 *pParentModelMtx ) { // clang-format off nofralloc psq_l f0, MTX34._00(pParentModelMtx), 1, 0 psq_l f1, MTX34._01(pParentModelMtx), 0, 0 psq_l f2, MTX34._10(pParentModelMtx), 1, 0 ps_merge10 f6, f1, f0 psq_l f3, MTX34._11(pParentModelMtx), 0, 0 psq_l f4, MTX34._20(pParentModelMtx), 1, 0 ps_merge10 f7, f3, f2 psq_l f5, MTX34._21(pParentModelMtx), 0, 0 ps_mul f11, f3, f6 ps_mul f13, f5, f7 ps_merge10 f8, f5, f4 ps_msub f11, f1, f7, f11 ps_mul f12, f1, f8 ps_msub f13, f3, f8, f13 lis r12, norm_epsilon@ha psq_l f3, MTX34._12(pModelMtx), 1, 0 ps_msub f12, f5, f6, f12 addi r12, r12, norm_epsilon@l ps_mul f7, f0, f13 ps_mul f9, f0, f5 psq_l f6, 0x0(r12), 1, 0 ps_madd f7, f2, f12, f7 ps_sub f13, f13, f13 psq_l f2, MTX34._02(pModelMtx), 1, 0 ps_madd f7, f4, f11, f7 ps_msub f9, f1, f4, f9 psq_l f1, MTX34._10(pModelMtx), 0, 0 ps_abs f8, f7 psq_st f13, VEC3.z(pVec), 1, 0 ps_cmpo0 cr0, f8, f6 bge _lbl_8044F944 psq_st f13, VEC3.x(pVec), 0, 0 blr _lbl_8044F944: fres f8, f7 psq_l f0, MTX34._00(pModelMtx), 0, 0 ps_add f11, f8, f8 ps_mul f10, f7, f8 ps_merge00 f4, f0, f1 ps_nmsub f8, f8, f10, f11 ps_merge11 f5, f0, f1 ps_merge00 f6, f2, f3 ps_muls0 f12, f12, f8 psq_l f1, MTX34._20(pModelMtx), 0, 0 ps_muls0 f9, f9, f8 psq_l f2, MTX34._22(pModelMtx), 1, 0 ps_muls0 f0, f4, f12 ps_mul f1, f1, f9 ps_madds1 f0, f5, f12, f0 ps_sum0 f1, f1, f1, f1 ps_madds0 f0, f6, f9, f0 fmadds f1, f2, f9, f1 psq_st f0, VEC3.x(pVec), 0, 0 psq_st f1, VEC3.z(pVec), 1, 0 blr // clang-format on } inline void SetMdlViewMtxSR(register math::MTX34 *pViewPos, register const math::VEC3 &rRY, register f32 s) { register f32 work0, work1; register f32 c_zero = 0.0f; // clang-format off asm { psq_l work0, VEC3.x(rRY), 0, 0 ps_muls0 work0, work0, s ps_merge10 work1, work0, work0 psq_st work1, MTX34._00(pViewPos), 0, 0 ps_neg work1, work0 ps_merge01 work1, work1, work0 psq_st work1, MTX34._10(pViewPos), 0, 0 stfs c_zero, MTX34._02(pViewPos) stfs c_zero, MTX34._12(pViewPos) psq_st c_zero, MTX34._20(pViewPos), 0, 0 stfs s, MTX34._22(pViewPos) } // clang-format on } inline void SetMdlViewMtxSR( register math::MTX34 *pViewPos, register const math::VEC3 &rRY, register f32 sx, register f32 sy, register f32 sz ) { register f32 work0, work1, work2, work3; register f32 c_zero = 0.0f; // clang-format off asm { ps_merge00 work0, sx, sy psq_l work1, VEC3.x(rRY), 0, 0 ps_merge10 work3, work1, work1 ps_mul work3, work3, work0 psq_st work3, MTX34._00(pViewPos), 0, 0 ps_neg work2, work1 ps_merge01 work3, work2, work1 ps_mul work3, work3, work0 psq_st work3, MTX34._10(pViewPos), 0, 0 stfs c_zero, MTX34._02(pViewPos) stfs c_zero, MTX34._12(pViewPos) psq_st c_zero, MTX34._20(pViewPos), 0, 0 stfs sz, MTX34._22(pViewPos) } // clang-format on } inline void SetMdlViewMtxSR( register math::MTX34 *pViewPos, register const math::VEC3 &rRX, register const math::VEC3 &rRY, register const math::VEC3 &rRZ, register f32 sx, register f32 sy, register f32 sz ) { register f32 work0, work1, work2, work3; // clang-format off asm { psq_l work0, VEC3.x(rRX), 0, 0 psq_l work1, VEC3.x(rRY), 0, 0 ps_muls0 work0, work0, sx ps_muls0 work1, work1, sy ps_merge00 work2, work0, work1 ps_merge11 work3, work0, work1 psq_st work2, MTX34._00(pViewPos), 0, 0 psq_st work3, MTX34._10(pViewPos), 0, 0 psq_l work0, VEC3.x(rRZ), 0, 0 ps_muls0 work0, work0, sz stfs work0, MTX34._02(pViewPos) ps_merge11 work0, work0, work0 stfs work0, MTX34._12(pViewPos) lfs work0, VEC3.z(rRX) fmuls work0, work0, sx stfs work0, MTX34._20(pViewPos) lfs work0, VEC3.z(rRY) fmuls work0, work0, sy stfs work0, MTX34._21(pViewPos) lfs work0, VEC3.z(rRZ) fmuls work0, work0, sz stfs work0, MTX34._22(pViewPos) } // clang-format on } } // namespace /****************************************************************************** * * Billboard implementation * ******************************************************************************/ namespace { inline f32 GetMtx34Scale(const math::MTX34 &rMtx, int col) { return math::FSqrt( rMtx.m[0][col] * rMtx.m[0][col] + rMtx.m[1][col] * rMtx.m[1][col] + rMtx.m[2][col] * rMtx.m[2][col] ); } void Calc_BILLBOARD_STD( math::MTX34 *pViewPos, const math::MTX34 *pModelMtxArray, bool uniformScale, const math::MTX34 *pViewMtx, const ResMdl mdl, const u32 id ) { #pragma unused(pViewMtx) #pragma unused(mdl) math::VEC3 vy(pViewPos->_01, pViewPos->_11, 0.0f); if (math::FAbs(vy.x) >= norm_epsilon || math::FAbs(vy.y) >= norm_epsilon) { math::VEC3Normalize(&vy, &vy); if (uniformScale) { f32 s = GetMtx34Scale(pModelMtxArray[id], 0); SetMdlViewMtxSR(pViewPos, vy, s); } else { f32 sx = GetMtx34Scale(pModelMtxArray[id], 0); f32 sy = GetMtx34Scale(pModelMtxArray[id], 1); f32 sz = GetMtx34Scale(pModelMtxArray[id], 2); SetMdlViewMtxSR(pViewPos, vy, sx, sy, sz); } } else { math::MTX34Zero(pViewPos); } } void Calc_BILLBOARD_PERSP_STD( math::MTX34 *pViewPos, const math::MTX34 *pModelMtxArray, bool uniformScale, const math::MTX34 *pViewMtx, const ResMdl mdl, const u32 id ) { #pragma unused(pViewMtx) #pragma unused(mdl) math::VEC3 vx; math::VEC3 vy(pViewPos->_01, pViewPos->_11, pViewPos->_21); math::VEC3 vz(-pViewPos->_03, -pViewPos->_13, -pViewPos->_23); if (math::FAbs(vz.x) >= norm_epsilon || math::FAbs(vz.y) >= norm_epsilon || math::FAbs(vz.z) >= norm_epsilon) { math::VEC3Normalize(&vz, &vz); math::VEC3Cross(&vx, &vy, &vz); if (math::FAbs(vx.x) >= norm_epsilon || math::FAbs(vx.y) >= norm_epsilon || math::FAbs(vx.z) >= norm_epsilon) { math::VEC3Normalize(&vx, &vx); math::VEC3Cross(&vy, &vz, &vx); if (uniformScale) { f32 s = GetMtx34Scale(pModelMtxArray[id], 0); SetMdlViewMtxSR(pViewPos, vx, vy, vz, s, s, s); } else { f32 sx = GetMtx34Scale(pModelMtxArray[id], 0); f32 sy = GetMtx34Scale(pModelMtxArray[id], 1); f32 sz = GetMtx34Scale(pModelMtxArray[id], 2); SetMdlViewMtxSR(pViewPos, vx, vy, vz, sx, sy, sz); } return; } } math::MTX34Zero(pViewPos); } void Calc_BILLBOARD_ROT( math::MTX34 *pViewPos, const math::MTX34 *pModelMtxArray, bool uniformScale, const math::MTX34 *pViewMtx, const ResMdl mdl, const u32 id ) { #pragma unused(pViewMtx) math::VEC3 vy; int nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(id); if (nodeID >= 0) { ResNode node = mdl.GetResNode(nodeID); ResNode parent = node.GetParentNode(); if (parent.IsValid()) { u32 parentMtxID = parent.GetMtxID(); GetModelLocalAxisY2(&vy, &pModelMtxArray[id], &pModelMtxArray[parentMtxID]); } else { vy.x = pModelMtxArray[id]._01; vy.y = pModelMtxArray[id]._11; vy.z = 0.0f; } } else { vy.x = pModelMtxArray[id]._01; vy.y = pModelMtxArray[id]._11; vy.z = 0.0f; } if (math::FAbs(vy.x) >= norm_epsilon || math::FAbs(vy.y) >= norm_epsilon) { math::VEC3Normalize(&vy, &vy); if (uniformScale) { f32 s = GetMtx34Scale(pModelMtxArray[id], 0); SetMdlViewMtxSR(pViewPos, vy, s); } else { f32 sx = GetMtx34Scale(pModelMtxArray[id], 0); f32 sy = GetMtx34Scale(pModelMtxArray[id], 1); f32 sz = GetMtx34Scale(pModelMtxArray[id], 2); SetMdlViewMtxSR(pViewPos, vy, sx, sy, sz); } } else { math::MTX34Zero(pViewPos); } } void Calc_BILLBOARD_PERSP_ROT( math::MTX34 *pViewPos, const math::MTX34 *pModelMtxArray, bool uniformScale, const math::MTX34 *pViewMtx, const ResMdl mdl, const u32 id ) { #pragma unused(pViewMtx) math::VEC3 vx; math::VEC3 vy; math::VEC3 vz(-pViewPos->_03, -pViewPos->_13, -pViewPos->_23); int nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(id); if (nodeID >= 0) { ResNode node = mdl.GetResNode(nodeID); ResNode parent = node.GetParentNode(); if (parent.IsValid()) { u32 parentMtxID = parent.GetMtxID(); GetModelLocalAxisY3(&vy, &pModelMtxArray[id], &pModelMtxArray[parentMtxID]); } else { vy.x = pModelMtxArray[id]._01; vy.y = pModelMtxArray[id]._11; vy.z = pModelMtxArray[id]._21; } } else { vy.x = pModelMtxArray[id]._01; vy.y = pModelMtxArray[id]._11; vy.z = pModelMtxArray[id]._21; } if (math::FAbs(vz.x) >= norm_epsilon || math::FAbs(vz.y) >= norm_epsilon || math::FAbs(vz.z) >= norm_epsilon) { math::VEC3Normalize(&vz, &vz); math::VEC3Cross(&vx, &vy, &vz); if (math::FAbs(vx.x) >= norm_epsilon || math::FAbs(vx.y) >= norm_epsilon || math::FAbs(vx.z) >= norm_epsilon) { math::VEC3Normalize(&vx, &vx); math::VEC3Cross(&vy, &vz, &vx); if (uniformScale) { f32 s = GetMtx34Scale(pModelMtxArray[id], 0); SetMdlViewMtxSR(pViewPos, vx, vy, vz, s, s, s); } else { f32 sx = GetMtx34Scale(pModelMtxArray[id], 0); f32 sy = GetMtx34Scale(pModelMtxArray[id], 1); f32 sz = GetMtx34Scale(pModelMtxArray[id], 2); SetMdlViewMtxSR(pViewPos, vx, vy, vz, sx, sy, sz); } return; } } math::MTX34Zero(pViewPos); } void Calc_BILLBOARD_Y( math::MTX34 *pViewPos, const math::MTX34 *pModelMtxArray, bool uniformScale, const math::MTX34 *pViewMtx, const ResMdl mdl, const u32 id ) { #pragma unused(pViewMtx) #pragma unused(mdl) math::VEC3 vz; math::VEC3 vy(pViewPos->_01, pViewPos->_11, pViewPos->_21); math::VEC3 vx(vy.y, -vy.x, 0.0f); if (math::FAbs(vy.x) >= norm_epsilon || math::FAbs(vx.x) >= norm_epsilon || math::FAbs(vy.z) >= norm_epsilon) { f32 sy = GetMtx34Scale(pModelMtxArray[id], 1); f32 invSY = math::FInv(sy); vy *= invSY; if (math::FAbs(vx.x) >= norm_epsilon || math::FAbs(vx.y) >= norm_epsilon) { math::VEC3Normalize(&vx, &vx); math::VEC3Cross(&vz, &vx, &vy); if (uniformScale) { SetMdlViewMtxSR(pViewPos, vx, vy, vz, sy, sy, sy); } else { f32 sx = GetMtx34Scale(pModelMtxArray[id], 0); f32 sz = GetMtx34Scale(pModelMtxArray[id], 2); SetMdlViewMtxSR(pViewPos, vx, vy, vz, sx, sy, sz); } return; } } math::MTX34Zero(pViewPos); } void Calc_BILLBOARD_PERSP_Y( math::MTX34 *pViewPos, const math::MTX34 *pModelMtxArray, bool uniformScale, const math::MTX34 *pViewMtx, const ResMdl mdl, const u32 id ) { #pragma unused(pViewMtx) #pragma unused(mdl) math::VEC3 vx; math::VEC3 vy(pViewPos->_01, pViewPos->_11, pViewPos->_21); math::VEC3 vz(-pViewPos->_03, -pViewPos->_13, -pViewPos->_23); if (math::FAbs(vy.x) >= norm_epsilon || math::FAbs(vy.y) >= norm_epsilon || math::FAbs(vy.z) >= norm_epsilon) { f32 sy = GetMtx34Scale(pModelMtxArray[id], 1); f32 invSY = math::FInv(sy); vy *= invSY; math::VEC3Cross(&vx, &vy, &vz); if (math::FAbs(vx.x) >= norm_epsilon || math::FAbs(vx.y) >= norm_epsilon || math::FAbs(vx.z) >= norm_epsilon) { math::VEC3Normalize(&vx, &vx); math::VEC3Cross(&vz, &vx, &vy); if (uniformScale) { SetMdlViewMtxSR(pViewPos, vx, vy, vz, sy, sy, sy); } else { f32 sx = GetMtx34Scale(pModelMtxArray[id], 0); f32 sz = GetMtx34Scale(pModelMtxArray[id], 2); SetMdlViewMtxSR(pViewPos, vx, vy, vz, sx, sy, sz); } return; } } math::MTX34Zero(pViewPos); } typedef void (*BillBoardFunc)( math::MTX34 *pViewPos, const math::MTX34 *pModelMtxArray, bool uniformScale, const math::MTX34 *pViewMtx, const ResMdl mdl, const u32 id ); const BillBoardFunc bbFunc[ResNodeData::NUM_BILLBOARD] = { NULL, // BILLBOARD_OFF is ignored Calc_BILLBOARD_STD, // Calc_BILLBOARD_PERSP_STD, // Calc_BILLBOARD_ROT, // Calc_BILLBOARD_PERSP_ROT, // Calc_BILLBOARD_Y, // Calc_BILLBOARD_PERSP_Y // }; } // namespace /****************************************************************************** * * CalcView * ******************************************************************************/ void CalcView( math::MTX34 *pViewPosArray, math::MTX33 *pViewNrmArray, const math::MTX34 *pModelMtxArray, const u32 *pModelMtxAttribArray, u32 numMtx, const math::MTX34 *pViewMtx, const ResMdl mdl, math::MTX34 *pViewTexMtxArray ) { if (numMtx <= 0) { return; } math::MTX34 *pVArray; math::MTX33 *pNArray; math::MTX34 *pCurTArray; u32 sizeVArray = align32(numMtx * sizeof(math::MTX34)); u32 sizeNArray = align32(numMtx * sizeof(math::MTX33)); u32 sizeTArray = align32(numMtx * sizeof(math::MTX34)); pVArray = pViewPosArray; if (numMtx > 1) { math::MTX34MultArray(pVArray, pViewMtx, pModelMtxArray, numMtx); } else { math::MTX34Mult(pVArray, pViewMtx, pModelMtxArray); } math::MTX34 *pBbMtxArray = detail::workmem::GetBillboardMtxTemporary(); for (u32 i = 0; i < numMtx; i++) { u32 attr = pModelMtxAttribArray[i]; ResNodeData::Billboard bbType = detail::WorldMtxAttr::GetBillboard(attr); if (bbType != ResNodeData::BILLBOARD_OFF) { math::MTX34 &rVMtx = pVArray[i]; bbFunc[bbType](&rVMtx, pModelMtxArray, detail::WorldMtxAttr::IsAllScaleUniform(attr), pViewMtx, mdl, i); s32 nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(i); ResNode node = mdl.GetResNode(static_cast(nodeID)); if (node.IsValid() && node.GetChildNode().IsValid()) { math::MTX34 invWorld; u32 ret = detail::CalcInvWorldMtx(&invWorld, &pModelMtxArray[i]); if (ret == TRUE) { math::MTX34Mult(&pBbMtxArray[i], &pVArray[i], &invWorld); } else { math::MTX34Identity(&pBbMtxArray[i]); pBbMtxArray[i]._03 = pViewMtx->_03; pBbMtxArray[i]._13 = pViewMtx->_13; pBbMtxArray[i]._23 = pViewMtx->_23; } } } else { s32 nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(i); if (nodeID < 0) { continue; } ResNode node = mdl.GetResNode(static_cast(nodeID)); if (!node.IsValid()) { continue; } if (!(node.ref().flags & ResNodeData::FLAG_BILLBOARD_PARENT)) { continue; } u32 bbMtxID = mdl.GetResNode(node.ref().bbref_nodeid).GetMtxID(); math::MTX34Mult(&pVArray[i], &pBbMtxArray[bbMtxID], &pModelMtxArray[i]); } } pNArray = pViewNrmArray; pCurTArray = pViewTexMtxArray; if (pNArray != NULL) { for (u32 i = 0; i < numMtx; i++) { math::MTX34 &rVMtx = pVArray[i]; math::MTX33 &rNMtx = pNArray[i]; u32 attr = pModelMtxAttribArray[i]; if (detail::WorldMtxAttr::IsAllScaleUniform(attr)) { if (pCurTArray != NULL) { math::MTX34Copy(&pCurTArray[i], &rVMtx); pCurTArray[i]._03 = pCurTArray[i]._13 = pCurTArray[i]._23 = 0.0f; } math::MTX34ToMTX33(&rNMtx, &rVMtx); } else { if (pCurTArray != NULL) { detail::CalcViewTexMtx(&pCurTArray[i], &rVMtx); math::MTX34ToMTX33(&rNMtx, &pCurTArray[i]); } else { detail::CalcViewNrmMtx(&rNMtx, &rVMtx); } } } } DC::FlushRangeNoSync(pVArray, sizeVArray); if (pNArray != NULL) { DC::FlushRangeNoSync(pViewNrmArray, sizeNArray); if (pCurTArray != NULL) { DC::FlushRangeNoSync(pViewTexMtxArray, sizeTArray); } } } void CalcView_LC( math::MTX34 *pViewPosArray, math::MTX33 *pViewNrmArray, const math::MTX34 *pModelMtxArray, const u32 *pModelMtxAttribArray, u32 numMtx, const math::MTX34 *pViewMtx, const ResMdl mdl, math::MTX34 *pViewTexMtxArray ) { if (numMtx <= 0) { return; } detail::MtxCacheMap *pMtxCache = static_cast(ut::LC::GetBase()); math::MTX34 *pCurVArray = reinterpret_cast(pMtxCache->currViewArray); math::MTX33 *pCurNArray = reinterpret_cast(pMtxCache->currNrmArray); math::MTX34 *pCurTArray = reinterpret_cast(pMtxCache->currTexArray); math::MTX34 *pPrevVArray = reinterpret_cast(pMtxCache->prevViewArray); math::MTX33 *pPrevNArray = reinterpret_cast(pMtxCache->prevNrmArray); math::MTX34 *pPrevTArray = reinterpret_cast(pMtxCache->prevTexArray); u32 sizeVArray = align32(numMtx * sizeof(math::MTX34)); DC::InvalidateRange(pViewPosArray, sizeVArray); u32 queueLen = 1; u32 sizeNArray, sizeTArray; if (pViewNrmArray != NULL) { queueLen++; sizeNArray = align32(numMtx * sizeof(math::MTX33)); DC::InvalidateRange(pViewNrmArray, sizeNArray); if (pViewTexMtxArray != NULL) { queueLen++; sizeTArray = align32(numMtx * sizeof(math::MTX34)); DC::InvalidateRange(pViewTexMtxArray, sizeTArray); } } math::MTX34 *pBbMtxArray = detail::workmem::GetBillboardMtxTemporary(); ut::LC::QueueWait(0); u32 baseMtx; for (baseMtx = 0; baseMtx < numMtx; baseMtx += 40) { u32 remain = numMtx - baseMtx; u32 numBlocks, numBlocksNrm; if (remain > 40) { remain = 40; numBlocks = 60; numBlocksNrm = 45; } else { numBlocks = align32(remain * sizeof(math::MTX34)) / 32; numBlocksNrm = align32(remain * sizeof(math::MTX33)) / 32; } ut::LC::QueueWait(queueLen); if (remain > 1) { math::MTX34MultArray(pCurVArray, pViewMtx, &pModelMtxArray[baseMtx], remain); } else { math::MTX34Mult(pCurVArray, pViewMtx, &pModelMtxArray[baseMtx]); } for (u32 i = 0; i < remain; i++) { u32 attr = pModelMtxAttribArray[baseMtx + i]; ResNodeData::Billboard bbType = detail::WorldMtxAttr::GetBillboard(attr); if (bbType != ResNodeData::BILLBOARD_OFF) { math::MTX34 &rVMtx = pCurVArray[i]; bbFunc[bbType]( &rVMtx, pModelMtxArray, detail::WorldMtxAttr::IsAllScaleUniform(attr), pViewMtx, mdl, baseMtx + i ); s32 nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(baseMtx + i); ResNode node = mdl.GetResNode(static_cast(nodeID)); if (node.IsValid() && node.GetChildNode().IsValid()) { math::MTX34 invWorld; u32 ret = detail::CalcInvWorldMtx(&invWorld, &pModelMtxArray[baseMtx + i]); if (ret == TRUE) { math::MTX34Mult(&pBbMtxArray[baseMtx + i], &pCurVArray[i], &invWorld); } else { math::MTX34Identity(&pBbMtxArray[baseMtx + i]); pBbMtxArray[baseMtx + i]._03 = pViewMtx->_03; pBbMtxArray[baseMtx + i]._13 = pViewMtx->_13; pBbMtxArray[baseMtx + i]._23 = pViewMtx->_23; } } } else { s32 nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(baseMtx + i); if (nodeID < 0) { continue; } ResNode node = mdl.GetResNode(static_cast(nodeID)); if (!node.IsValid()) { continue; } if (!(node.ref().flags & ResNodeData::FLAG_BILLBOARD_PARENT)) { continue; } u32 bbMtxID = mdl.GetResNode(node.ref().bbref_nodeid).GetMtxID(); math::MTX34Mult(&pCurVArray[i], &pBbMtxArray[bbMtxID], &pModelMtxArray[baseMtx + i]); } } ut::LC::StoreBlocks(&pViewPosArray[baseMtx], pCurVArray, numBlocks); if (pViewNrmArray != NULL) { for (u32 i = 0; i < remain; i++) { math::MTX34 &rVMtx = pCurVArray[i]; math::MTX33 &rNMtx = pCurNArray[i]; u32 attr = pModelMtxAttribArray[baseMtx + i]; if (detail::WorldMtxAttr::IsAllScaleUniform(attr)) { if (pViewTexMtxArray != NULL) { math::MTX34Copy(&pCurTArray[i], &rVMtx); pCurTArray[i]._03 = pCurTArray[i]._13 = pCurTArray[i]._23 = 0.0f; } math::MTX34ToMTX33(&rNMtx, &rVMtx); } else { if (pViewTexMtxArray != NULL) { detail::CalcViewTexMtx(&pCurTArray[i], &rVMtx); math::MTX34ToMTX33(&rNMtx, &pCurTArray[i]); } else { detail::CalcViewNrmMtx(&rNMtx, &rVMtx); } } } } if (pViewNrmArray != NULL) { ut::LC::StoreBlocks(&pViewNrmArray[baseMtx], pCurNArray, numBlocksNrm); if (pViewTexMtxArray != NULL) { ut::LC::StoreBlocks(&pViewTexMtxArray[baseMtx], pCurTArray, numBlocks); } } std::swap(pCurVArray, pPrevVArray); std::swap(pCurNArray, pPrevNArray); std::swap(pCurTArray, pPrevTArray); } } void CalcView_LC_DMA_ModelMtx( math::MTX34 *pViewPosArray, math::MTX33 *pViewNrmArray, const math::MTX34 *pModelMtxArray, const u32 *pModelMtxAttribArray, u32 numMtx, const math::MTX34 *pViewMtx, const ResMdl mdl, math::MTX34 *pViewTexMtxArray ) { if (numMtx <= 0) { return; } detail::MtxCacheMap *pMtxCache = static_cast(ut::LC::GetBase()); math::MTX34 *pCurMArray = reinterpret_cast(pMtxCache->currDmaArray); math::MTX34 *pCurVArray = reinterpret_cast(pMtxCache->currViewArray); math::MTX33 *pCurNArray = reinterpret_cast(pMtxCache->currNrmArray); math::MTX34 *pCurTArray = reinterpret_cast(pMtxCache->currTexArray); math::MTX34 *pPrevMArray = reinterpret_cast(pMtxCache->prevDmaArray); math::MTX34 *pPrevVArray = reinterpret_cast(pMtxCache->prevViewArray); math::MTX33 *pPrevNArray = reinterpret_cast(pMtxCache->prevNrmArray); math::MTX34 *pPrevTArray = reinterpret_cast(pMtxCache->prevTexArray); u32 sizeVArray = align32(numMtx * sizeof(math::MTX34)); DC::InvalidateRange(pViewPosArray, sizeVArray); u32 queueLen = 1; u32 sizeNArray, sizeTArray; if (pViewNrmArray != NULL) { queueLen++; sizeNArray = align32(numMtx * sizeof(math::MTX33)); DC::InvalidateRange(pViewNrmArray, sizeNArray); if (pViewTexMtxArray != NULL) { queueLen++; sizeTArray = align32(numMtx * sizeof(math::MTX34)); DC::InvalidateRange(pViewTexMtxArray, sizeTArray); } } math::MTX34 *pBbMtxArray = detail::workmem::GetBillboardMtxTemporary(); ut::LC::QueueWait(0); u32 numBlocks; if (numMtx > 40) { numBlocks = 60; } else { numBlocks = align32(numMtx * sizeof(math::MTX34)) / 32; } ut::LC::LoadBlocks(pCurMArray, const_cast(pModelMtxArray), numBlocks); if (numMtx > 20) { ut::LC::QueueWaitEx(0); } else { ut::LC::QueueWait(0); } u32 baseMtx; for (baseMtx = 0; baseMtx < numMtx; baseMtx += 40) { u32 remain = numMtx - baseMtx; u32 numBlocks, numBlocksNrm; if (remain > 40) { remain = 40; numBlocks = 60; numBlocksNrm = 45; } else { numBlocks = align32(remain * sizeof(math::MTX34)) / 32; numBlocksNrm = align32(remain * sizeof(math::MTX33)) / 32; } ut::LC::QueueWait(queueLen); if (baseMtx + 40 < numMtx) { u32 n = numMtx - baseMtx - 40; u32 blocks; if (n > 40) { blocks = 60; } else { blocks = align32(n * sizeof(math::MTX34)) / 32; } ut::LC::LoadBlocks(pPrevMArray, const_cast(&pModelMtxArray[baseMtx + 40]), blocks); } if (remain > 1) { math::MTX34MultArray(pCurVArray, pViewMtx, pCurMArray, remain); } else { math::MTX34Mult(pCurVArray, pViewMtx, pCurMArray); } for (u32 i = 0; i < remain; i++) { u32 attr = pModelMtxAttribArray[baseMtx + i]; ResNodeData::Billboard bbType = detail::WorldMtxAttr::GetBillboard(attr); if (bbType != ResNodeData::BILLBOARD_OFF) { math::MTX34 &rVMtx = pCurVArray[i]; bbFunc[bbType]( &rVMtx, pModelMtxArray, detail::WorldMtxAttr::IsAllScaleUniform(attr), pViewMtx, mdl, baseMtx + i ); s32 nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(baseMtx + i); ResNode node = mdl.GetResNode(static_cast(nodeID)); if (node.IsValid() && node.GetChildNode().IsValid()) { math::MTX34 invWorld; u32 ret = detail::CalcInvWorldMtx(&invWorld, &pModelMtxArray[baseMtx + i]); if (ret == TRUE) { math::MTX34Mult(&pBbMtxArray[baseMtx + i], &pCurVArray[i], &invWorld); } else { math::MTX34Identity(&pBbMtxArray[baseMtx + i]); pBbMtxArray[baseMtx + i]._03 = pViewMtx->_03; pBbMtxArray[baseMtx + i]._13 = pViewMtx->_13; pBbMtxArray[baseMtx + i]._23 = pViewMtx->_23; } } } else { s32 nodeID = mdl.GetResMdlInfo().GetNodeIDFromMtxID(baseMtx + i); if (nodeID < 0) { continue; } ResNode node = mdl.GetResNode(static_cast(nodeID)); if (!node.IsValid()) { continue; } if (!(node.ref().flags & ResNodeData::FLAG_BILLBOARD_PARENT)) { continue; } u32 bbMtxID = mdl.GetResNode(node.ref().bbref_nodeid).GetMtxID(); math::MTX34Mult(&pCurVArray[i], &pBbMtxArray[bbMtxID], &pModelMtxArray[baseMtx + i]); } } ut::LC::StoreBlocks(&pViewPosArray[baseMtx], pCurVArray, numBlocks); if (pViewNrmArray != NULL) { for (u32 i = 0; i < remain; i++) { math::MTX34 &rVMtx = pCurVArray[i]; math::MTX33 &rNMtx = pCurNArray[i]; u32 attr = pModelMtxAttribArray[baseMtx + i]; if (detail::WorldMtxAttr::IsAllScaleUniform(attr)) { if (pViewTexMtxArray != NULL) { math::MTX34Copy(&pCurTArray[i], &rVMtx); pCurTArray[i]._03 = pCurTArray[i]._13 = pCurTArray[i]._23 = 0.0f; } math::MTX34ToMTX33(&rNMtx, &rVMtx); } else { if (pViewTexMtxArray != NULL) { detail::CalcViewTexMtx(&pCurTArray[i], &rVMtx); math::MTX34ToMTX33(&rNMtx, &pCurTArray[i]); } else { detail::CalcViewNrmMtx(&rNMtx, &rVMtx); } } } } if (pViewNrmArray != NULL) { ut::LC::StoreBlocks(&pViewNrmArray[baseMtx], pCurNArray, numBlocksNrm); if (pViewTexMtxArray != NULL) { ut::LC::StoreBlocks(&pViewTexMtxArray[baseMtx], pCurTArray, numBlocks); } } std::swap(pCurMArray, pPrevMArray); std::swap(pCurVArray, pPrevVArray); std::swap(pCurNArray, pPrevNArray); std::swap(pCurTArray, pPrevTArray); } } } // namespace g3d } // namespace nw4r