#include "common.h" #include "nw4r/g3d.h" // IWYU pragma: export #include #include namespace nw4r { namespace g3d { namespace detail { namespace ScnDependentMtxFunc { /****************************************************************************** * * ScnDependentMtxFunc * ******************************************************************************/ void EnvironmentMapping(math::MTX34 *pMtx, s8 camRef, s8 lightRef) { if (pMtx == NULL) { return; } if (camRef >= 0 && camRef < G3DState::NUM_CAMERA) { math::MTX34Mult(pMtx, G3DState::GetCameraMtxPtr(camRef), G3DState::GetInvCameraMtxPtr()); pMtx->_03 = pMtx->_13 = pMtx->_23 = 0.0f; math::MTX34Mult(pMtx, G3DState::GetEnvironmentTexMtxPtr(), pMtx); return; } if (lightRef >= 0 && lightRef < G3DState::NUM_LIGHT && G3DState::GetLightObj(lightRef)->IsEnable()) { math::VEC3 look, camUp, right, up; const LightObj *pLight = G3DState::GetLightObj(lightRef); pLight->GetLightDir(&look); const math::MTX34 *pInvCamMtx = G3DState::GetInvCameraMtxPtr(); if (pLight->IsDiffuseLight() || (look.x == 0.0f && look.y == 0.0f && look.z == 0.0f)) { pLight->GetLightPos(&look); math::VEC3TransformNormal(&look, pInvCamMtx, &look); look = -look; if (look.x == 0.0f && look.y == 0.0f && look.z == 0.0f) { look.y = -1.0f; } } else { math::VEC3TransformNormal(&look, pInvCamMtx, &look); } math::VEC3Normalize(&look, &look); if (math::FAbs(look.x) < 0.000001f && math::FAbs(look.z) < 0.000001f) { camUp.x = camUp.y = 0.0f; if (look.y <= 0.0f) { camUp.z = -1.0f; } else { camUp.z = 1.0f; } } else { camUp.x = camUp.z = 0.0f; camUp.y = 1.0f; } math::VEC3Cross(&right, &look, &camUp); math::VEC3Normalize(&right, &right); math::VEC3Cross(&up, &right, &look); pMtx->_00 = right.x; pMtx->_01 = right.y; pMtx->_02 = right.z; pMtx->_10 = up.x; pMtx->_11 = up.y; pMtx->_12 = up.z; pMtx->_20 = -look.x; pMtx->_21 = -look.y; pMtx->_22 = -look.z; math::MTX34Mult(pMtx, pMtx, pInvCamMtx); pMtx->_03 = pMtx->_13 = pMtx->_23 = 0.0f; static const math::_MTX34 envMtx = { // clang-format off 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // clang-format on }; math::MTX34Mult(pMtx, static_cast(&envMtx), pMtx); return; } math::MTX34Copy(pMtx, G3DState::GetEnvironmentTexMtxPtr()); } void ProjectionMapping(math::MTX34 *pMtx, s8 camRef, s8 lightRef) { #pragma unused(lightRef) if (pMtx == NULL) { return; } if (camRef >= 0 && camRef < G3DState::NUM_CAMERA) { math::MTX34Mult(pMtx, G3DState::GetCameraMtxPtr(camRef), G3DState::GetInvCameraMtxPtr()); math::MTX34Mult(pMtx, G3DState::GetProjectionTexMtxPtr(camRef), pMtx); } else { math::MTX34Copy(pMtx, G3DState::GetProjectionTexMtxPtr()); } } void EnvironmentSpecularMapping(math::MTX34 *pMtx, s8 camRef, s8 lightRef) { if (pMtx == NULL) { return; } math::VEC3 look, camUp, camLook; const math::MTX34 *pCamMtx = G3DState::GetCameraMtxPtr(); camLook.x = -pCamMtx->_20; camLook.y = -pCamMtx->_21; camLook.z = -pCamMtx->_22; const math::MTX34 *pInvCamMtx = G3DState::GetInvCameraMtxPtr(); if (lightRef >= 0 && lightRef < G3DState::NUM_LIGHT && G3DState::GetLightObj(lightRef)->IsEnable()) { math::VEC3 lightLook; const LightObj *pLight = G3DState::GetLightObj(lightRef); pLight->GetLightDir(&lightLook); if (pLight->IsDiffuseLight() || (lightLook.x == 0.0f && lightLook.y == 0.0f && lightLook.z == 0.0f)) { pLight->GetLightPos(&lightLook); math::VEC3TransformNormal(&lightLook, pInvCamMtx, &lightLook); lightLook = -lightLook; if (lightLook.x == 0.0f && lightLook.y == 0.0f && lightLook.z == 0.0f) { lightLook.y = -1.0f; } } else { math::VEC3TransformNormal(&lightLook, pInvCamMtx, &lightLook); } if (!pLight->IsSpecularLight()) { C_VECHalfAngle(camLook, lightLook, look); } else { look = -lightLook; } if (math::FAbs(look.x) < 0.000001f && math::FAbs(look.z) < 0.000001f) { camUp.x = camUp.y = 0.0f; if (look.y <= 0.0f) { camUp.z = -1.0f; } else { camUp.z = 1.0f; } } else { camUp.x = camUp.z = 0.0f; camUp.y = 1.0f; } } else if (camRef >= 0 && camRef < G3DState::NUM_CAMERA) { const math::MTX34 *pLightCamMtx = G3DState::GetCameraMtxPtr(camRef); camUp.x = pLightCamMtx->_10; camUp.y = pLightCamMtx->_11; camUp.z = pLightCamMtx->_12; math::VEC3 lightLook(-pLightCamMtx->_20, -pLightCamMtx->_21, -pLightCamMtx->_22); C_VECHalfAngle(camLook, lightLook, look); } else { math::MTX34Copy(pMtx, G3DState::GetEnvironmentTexMtxPtr()); return; } math::VEC3Normalize(&look, &look); math::VEC3 right, up; math::VEC3Cross(&right, &camUp, &look); math::VEC3Normalize(&right, &right); math::VEC3Cross(&up, &look, &right); pMtx->_00 = right.x; pMtx->_01 = right.y; pMtx->_02 = right.z; pMtx->_10 = up.x; pMtx->_11 = up.y; pMtx->_12 = up.z; pMtx->_20 = look.x; pMtx->_21 = look.y; pMtx->_22 = look.z; math::MTX34Mult(pMtx, pMtx, pInvCamMtx); pMtx->_03 = pMtx->_13 = pMtx->_23 = 0.0f; math::MTX34Mult(pMtx, G3DState::GetEnvironmentTexMtxPtr(), pMtx); } void DefaultMapping(math::MTX34 *pMtx, s8 camRef, s8 lightRef) { #pragma unused(camRef) #pragma unused(lightRef) if (pMtx == NULL) { return; } math::MTX34Identity(pMtx); } } // namespace ScnDependentMtxFunc } // namespace detail namespace G3DState { namespace { /****************************************************************************** * * Utility functions * ******************************************************************************/ inline bool IsEqualTexObj(const GXTexObj &rLhs, const GXTexObj &rRhs) { return rLhs.dummy[0] == rRhs.dummy[0] && rLhs.dummy[1] == rRhs.dummy[1] && rLhs.dummy[2] == rRhs.dummy[2] && rLhs.dummy[3] == rRhs.dummy[3] && rLhs.dummy[4] == rRhs.dummy[4] && rLhs.dummy[5] == rRhs.dummy[5] && rLhs.dummy[6] == rRhs.dummy[6] && rLhs.dummy[7] == rRhs.dummy[7]; } inline bool IsEqualTlutObj(const GXTlutObj &rLhs, const GXTlutObj &rRhs) { return rLhs.dummy[0] == rRhs.dummy[0] && rLhs.dummy[1] == rRhs.dummy[1] && rLhs.dummy[2] == rRhs.dummy[2]; } } // namespace /****************************************************************************** * * IndMtxTexInfo * ******************************************************************************/ IndTexMtxInfo::IndTexMtxInfo(const ResMatIndMtxAndScale ind) : flag(0) { if (ind.GXGetIndTexMtx(GX_ITM_0, &offset_mtx[GX_ITM_0 - 1])) { flag |= 1 << GX_ITM_0 - 1; } if (ind.GXGetIndTexMtx(GX_ITM_1, &offset_mtx[GX_ITM_1 - 1])) { flag |= 1 << GX_ITM_1 - 1; } if (ind.GXGetIndTexMtx(GX_ITM_2, &offset_mtx[GX_ITM_2 - 1])) { flag |= 1 << GX_ITM_2 - 1; } } void IndTexMtxInfo::FifoSend() const { if (flag & (1 << GX_ITM_0 - 1)) { fifo::GDSetIndTexMtx(GX_PNMTX0, offset_mtx[GX_ITM_0 - 1]); } if (flag & (1 << GX_ITM_1 - 1)) { fifo::GDSetIndTexMtx(GX_PNMTX1, offset_mtx[GX_ITM_1 - 1]); } if (flag & (1 << GX_ITM_2 - 1)) { fifo::GDSetIndTexMtx(GX_PNMTX2, offset_mtx[GX_ITM_2 - 1]); } } void IndTexMtxInfo::SetMtx(GXIndTexMtxID id, const math::MTX34 &rMtx) { if (id == GX_ITM_0) { offset_mtx[GX_ITM_0 - 1] = rMtx; flag |= 1 << GX_ITM_0 - 1; } else if (id == GX_ITM_1) { offset_mtx[GX_ITM_1 - 1] = rMtx; flag |= 1 << GX_ITM_1 - 1; } else if (id == GX_ITM_2) { offset_mtx[GX_ITM_2 - 1] = rMtx; flag |= 1 << GX_ITM_2 - 1; } } namespace { /****************************************************************************** * * SyncGX * ******************************************************************************/ class SyncGX { public: SyncGX() : bNeedSync(true) {} void Set(); void Unset() { bNeedSync = false; } bool Get() { bool result = bNeedSync; Unset(); return result; } void Invalidate() { bNeedSync = true; } private: bool bNeedSync; // at 0x0 }; SyncGX sSyncGX; void SyncGX::Set() { bNeedSync = true; } /****************************************************************************** * * GenMode2 * ******************************************************************************/ class GenMode2 { public: GenMode2() : mNumTexGens(1), mNumChans(0), mNumTevs(1), mNumInds(0), mCullMode(GX_CULL_BACK), flag(0) {} void Invalidate() { mNumTexGens = 1; mNumChans = 0; mNumTevs = 1; mNumInds = 0; mCullMode = GX_CULL_BACK; flag = 0; } void LoadBP() { if ((flag & FLAG_FIRST_SET) && (flag & FLAG_ALL_LOADED) == FLAG_XF_LOADED) { fifo::GDSetGenMode2Ex_BP(mNumTexGens, mNumChans, mNumTevs, mNumInds, mCullMode); flag |= FLAG_BP_LOADED; } } void LoadXF() { if ((flag & FLAG_FIRST_SET) && (flag & FLAG_ALL_LOADED) != FLAG_ALL_LOADED) { fifo::GDSetGenMode2(mNumTexGens, mNumChans, mNumTevs, mNumInds, mCullMode); flag |= FLAG_BP_LOADED | FLAG_XF_LOADED; } } void SetResGenMode(const ResGenMode res) { if (mNumTexGens != res.GXGetNumTexGens()) { mNumTexGens = res.GXGetNumTexGens(); flag &= ~FLAG_ALL_LOADED; } if (mNumChans != res.GXGetNumChans()) { mNumChans = res.GXGetNumChans(); flag &= ~FLAG_ALL_LOADED; } if (mNumTevs != res.GXGetNumTevStages()) { mNumTevs = res.GXGetNumTevStages(); flag &= ~FLAG_BP_LOADED; } if (mNumInds != res.GXGetNumIndStages()) { mNumInds = res.GXGetNumIndStages(); flag &= ~FLAG_BP_LOADED; } if (mCullMode != res.GXGetCullMode()) { mCullMode = res.GXGetCullMode(); flag &= ~FLAG_BP_LOADED; } if (!(flag & FLAG_FIRST_SET)) { flag &= ~FLAG_ALL_LOADED; flag |= FLAG_FIRST_SET; } } u8 GXGetNumTexGens() const { return mNumTexGens; } u8 GXGetNumChans() const { return mNumChans; } u8 GXGetNumIndStages() const { return mNumInds; } private: enum Flag { FLAG_BP_LOADED = (1 << 0), FLAG_XF_LOADED = (1 << 1), FLAG_FIRST_SET = (1 << 2), FLAG_ALL_LOADED = FLAG_BP_LOADED | FLAG_XF_LOADED }; private: u8 mNumTexGens; // at 0x0 u8 mNumChans; // at 0x1 u8 mNumTevs; // at 0x2 u8 mNumInds; // at 0x3 GXCullMode mCullMode; // at 0x4 u32 flag; // at 0x8 }; GenMode2 sGenMode2; /****************************************************************************** * * TexCoordScaleState * ******************************************************************************/ struct TexMapSize { u16 width; // at 0x0 u16 height; // at 0x2 }; struct TexCoordScale { u16 width; // at 0x0 u16 height; // at 0x2 u32 opt; // at 0x4 }; class TexCoordScaleState { public: TexCoordScaleState() { std::memset(this, 0, sizeof(TexCoordScaleState)); } void Invalidate() { mUpToDate = 0; } void UpdateTexMapSize(GXTexMapID map, u16 width, u16 height) { wh[map].width = width; wh[map].height = height; mUpToDate |= FLAG_TEXMAP; mUpToDate &= ~FLAG_TEXCOORD; } void UpdateTable(const ResTev tev) { const u32 *pTable = reinterpret_cast(tev.ref().texCoordToTexMapID); if (!(mUpToDate & FLAG_TEXMAP) || pTable[0] != table_data[0] || pTable[1] != table_data[1]) { table_data[0] = pTable[0]; table_data[1] = pTable[1]; mUpToDate |= FLAG_TEXMAP; mUpToDate &= ~FLAG_TEXCOORD; } } void LoadTexCoordScale(u8 texGens) { if ((mUpToDate & FLAG_TEXMAP) && !(mUpToDate & FLAG_TEXCOORD) && texGens != 0) { LoadTexCoordScale_(texGens); } } private: enum UpToDateFlag { FLAG_TEXCOORD = (1 << 0), FLAG_TEXMAP = (1 << 1), }; private: void LoadTexCoordScale_(u8 texGens); private: u32 mUpToDate; // at 0x0 TexMapSize wh[GX_MAX_TEXMAP]; // at 0x4 TexCoordScale scale[GX_MAX_TEXCOORD]; // at 0x24 union { u8 table[GX_MAX_TEXCOORD]; u32 table_data[GX_MAX_TEXCOORD / sizeof(u32)]; }; // at 0x64 }; TexCoordScaleState sTexCoordScale; void TexCoordScaleState::LoadTexCoordScale_(u8 texGens) { for (u8 i = 0; i < texGens; i++) { if (table[i] == GX_TEXMAP_NULL) { continue; } scale[i].width = wh[table[i]].width; scale[i].height = wh[table[i]].height; fifo::GDSetTexCoordScale2( static_cast(i), scale[i].width, false, false, scale[i].height, false, false ); } mUpToDate |= FLAG_TEXCOORD; } /****************************************************************************** * * TexState * ******************************************************************************/ class TexState { public: TexState() : mValidFlag(0) {} void Invalidate() { mValidFlag = 0; } void Invalidate(GXTexMapID map) { mValidFlag &= ~(1 << map); } void LoadResTexObj(const ResTexObj texObj) { for (u32 i = 0; i < GX_MAX_TEXMAP; i++) { if (!texObj.IsValidTexObj(static_cast(i))) { continue; } GXTexMapID id = static_cast(i); const GXTexObj *pGXObj = texObj.GetTexObj(id); u8 mask = 1 << id; if (!(mValidFlag & mask) || !IsEqualTexObj(*pGXObj, mTexObj[id])) { mValidFlag |= mask; mTexObj[id] = *pGXObj; GXLoadTexObj(pGXObj, id); sTexCoordScale.UpdateTexMapSize(id, GXGetTexObjWidth(pGXObj), GXGetTexObjHeight(pGXObj)); } } } private: GXTexObj mTexObj[GX_MAX_TEXMAP]; // at 0x0 u8 mValidFlag; // at 0x100 u8 PADDING_0x101; // at 0x101 u8 PADDING_0x102; // at 0x102 u8 PADDING_0x103; // at 0x103 }; TexState sTex ALIGN_DECL(32); /****************************************************************************** * * TlutState * ******************************************************************************/ class TlutState { public: TlutState() : mFlag(0) {} void Invalidate() { mFlag = 0; } void LoadResTlutObj(const ResTlutObj tlutObj) { for (u32 i = 0; i < GX_TLUT8; i++) { if (!tlutObj.IsValidTlut(static_cast(i))) { continue; } GXTlut id = static_cast(i); const GXTlutObj *pGXObj = tlutObj.GetTlut(id); u16 mask = 1 << id; if (!(mFlag & mask) || !IsEqualTlutObj(*pGXObj, mTlutObj[id])) { mFlag |= mask; mTlutObj[id] = *pGXObj; GXLoadTlut(const_cast(pGXObj), id); sTex.Invalidate(static_cast(id)); } } } private: GXTlutObj mTlutObj[GX_TLUT7 - GX_TLUT0 + 1]; // at 0x0 u16 mFlag; // at 0x60 u16 PADDING_0x62; // at 0x62 }; TlutState sTlut ALIGN_DECL(32); /****************************************************************************** * * ShpState * ******************************************************************************/ class ShpState { public: ShpState() { mCache.Clear(); } void Invalidate() { mCache.Clear(); } bool IsCacheEqual(const ResCacheVtxDescv &rOther) { if (rOther == mCache) { return true; } mCache = rOther; return false; } private: ResCacheVtxDescv mCache; // at 0x0 }; ShpState sShp; /****************************************************************************** * * CurrMtxState * ******************************************************************************/ class CurrMtxState { public: CurrMtxState() : mIsUpToDate(false) {} void Invalidate() { mIsUpToDate = false; } void SetCurrMtx() { if (mIsUpToDate) { return; } fifo::GDResetCurrentMtx(); mIsUpToDate = true; } private: bool mIsUpToDate; // at 0x0 }; CurrMtxState sCurrMtx; /****************************************************************************** * * PostTexMtxState * ******************************************************************************/ class PostTexMtxState { public: PostTexMtxState() : mFlagIdentity(0) {} void Invalidate() { mFlagIdentity = 0; } bool IsIdentity(u32 id) const { return mFlagIdentity & (1 << id); } void SetIdentity(u32 id) { mFlagIdentity |= (1 << id); } void ResetIdentity(u32 id) { mFlagIdentity &= ~(1 << id); } private: u32 mFlagIdentity; // at 0x0 }; PostTexMtxState sPostTexMtx; /****************************************************************************** * * PreTexMtxState * ******************************************************************************/ class PreTexMtxState { public: PreTexMtxState() { Invalidate(); } void Invalidate() { mType[0] = mType[1] = mType[2] = mType[3] = mType[4] = mType[5] = mType[6] = mType[7] = SCNDEPENDENT_TEXMTX_FUNCTYPE_TEXMTX_NOT_EXIST; } void SetFuncType(u32 id, ScnDependentTexMtxFuncType type) { mType[id] = type; } void SetCurrentMtx(int id) const { bool allIdent = true; u32 idArray[NUM_TEX_MTX]; if (id < 0) { return; } for (u32 i = 0; i < NUM_TEX_MTX; i++) { if (mType[i] == SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_NRM) { idArray[i] = i * 3 + GX_TEXMTX0; fifo::GDLoadTexMtxImm3x3(*GetViewNrmMtxPtr(static_cast(id)), idArray[i]); allIdent = false; } else if (mType[i] == SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_POS) { idArray[i] = GX_PNMTX0; allIdent = false; } else { idArray[i] = GX_IDENTITY; } } if (allIdent) { sCurrMtx.SetCurrMtx(); } else { fifo::GDSetCurrentMtx(idArray); sCurrMtx.Invalidate(); } } private: static const int NUM_TEX_MTX = (GX_TEXMTX8 - GX_TEXMTX0) / 3; private: ScnDependentTexMtxFuncType mType[NUM_TEX_MTX]; // at 0x0 }; PreTexMtxState sPreTexMtxState; /****************************************************************************** * * TevState * ******************************************************************************/ class TevState { public: TevState() : mpTevData(NULL) {} void Invalidate() { mpTevData = NULL; } bool IsTevEqual(const ResTev tev) { if (tev.ptr() == mpTevData) { return true; } mpTevData = tev.ptr(); return false; } private: const ResTevData *mpTevData; // at 0x0 }; TevState sTev; /****************************************************************************** * * PosNrmMtxArrayState * ******************************************************************************/ class PosNrmMtxArrayState { public: PosNrmMtxArrayState() : mpViewPosMtxArray(NULL), mpViewNrmMtxArray(NULL), mpViewEnvTexMtxArray(NULL) {} void Invalidate() { mpViewPosMtxArray = NULL; mpViewNrmMtxArray = NULL; mpViewEnvTexMtxArray = NULL; } bool IsValid() const { return mpViewPosMtxArray != NULL; } void SetViewPosNrmMtxArray( const math::MTX34 *pViewPosMtxArray, const math::MTX33 *pViewNrmMtxArray, const math::MTX34 *pViewEnvTexMtxArray ) { mpViewPosMtxArray = pViewPosMtxArray; mpViewNrmMtxArray = pViewNrmMtxArray; mpViewEnvTexMtxArray = pViewEnvTexMtxArray; if (mpViewPosMtxArray != NULL) { GXSetArray(GX_POS_MTX_ARRAY, mpViewPosMtxArray, sizeof(math::MTX34)); } if (mpViewNrmMtxArray != NULL) { GXSetArray(GX_NRM_MTX_ARRAY, mpViewNrmMtxArray, sizeof(math::MTX33)); } if (mpViewEnvTexMtxArray != NULL) { GXSetArray(GX_TEX_MTX_ARRAY, mpViewEnvTexMtxArray, sizeof(math::MTX34)); } } const math::MTX34 *GetViewPosMtxPtr(u32 id) const { if (mpViewPosMtxArray != NULL) { return &mpViewPosMtxArray[id]; } return NULL; } const math::MTX33 *GetViewNrmMtxPtr(u32 id) const { if (mpViewNrmMtxArray != NULL) { return &mpViewNrmMtxArray[id]; } static math::MTX33 m; detail::CalcViewNrmMtx(&m, GetViewPosMtxPtr(id)); return &m; } private: const math::MTX34 *mpViewPosMtxArray; // at 0x0 const math::MTX33 *mpViewNrmMtxArray; // at 0x4 const math::MTX34 *mpViewEnvTexMtxArray; // at 0x8 }; PosNrmMtxArrayState sPosNrmArrayState; /****************************************************************************** * * ScnDependentTexMtxFuncTable * ******************************************************************************/ class ScnDependentTexMtxFuncTable { public: ScnDependentTexMtxFuncTable() { mTable[0].func = detail::ScnDependentMtxFunc::DefaultMapping; mTable[0].type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_TEXCOORD; mTable[1].func = detail::ScnDependentMtxFunc::EnvironmentMapping; mTable[1].type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_NRM; mTable[2].func = detail::ScnDependentMtxFunc::ProjectionMapping; mTable[2].type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_POS; mTable[3].func = detail::ScnDependentMtxFunc::EnvironmentMapping; mTable[3].type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_NRM; mTable[4].func = detail::ScnDependentMtxFunc::EnvironmentSpecularMapping; mTable[4].type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_NRM; for (u32 i = 5; i < NUM_SCNDEPENDENT_TEXMTX_FUNCTYPE; i++) { mTable[i].func = detail::ScnDependentMtxFunc::DefaultMapping; mTable[i].type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_TEXCOORD; } } void SetFunc(u32 id, ScnDependentTexMtxFuncPtr func, ScnDependentTexMtxFuncType type) { if (id <= 4 || id >= NUM_SCNDEPENDENT_TEXMTX_FUNCTYPE) { return; } if (func != NULL) { if (type >= MAX_SCNDEPENDENT_TEXMTX_FUNCTYPE) { type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_TEXCOORD; } mTable[id].func = func; mTable[id].type = type; } else { mTable[id].func = detail::ScnDependentMtxFunc::DefaultMapping; mTable[id].type = SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_TEXCOORD; } } bool GetFunc(u32 id, ScnDependentTexMtxFuncPtr *pFunc, ScnDependentTexMtxFuncType *pType) { if (id < NUM_SCNDEPENDENT_TEXMTX_FUNCTYPE) { if (pFunc != NULL) { *pFunc = mTable[id].func; } if (pType != NULL) { *pType = mTable[id].type; } return true; } return false; } ScnDependentTexMtxFuncType GetFuncType(u32 id) { if (id >= NUM_SCNDEPENDENT_TEXMTX_FUNCTYPE) { id = 0; } return mTable[id].type; } void Calc(u32 id, math::MTX34 *pMtx, s8 camRef, s8 lightRef) { if (id >= NUM_SCNDEPENDENT_TEXMTX_FUNCTYPE) { id = 0; } if (camRef >= NUM_CAMERA) { camRef = -1; } if (lightRef >= NUM_LIGHT) { lightRef = -1; } mTable[id].func(pMtx, camRef, lightRef); } private: struct { ScnDependentTexMtxFuncPtr func; // at 0x0 ScnDependentTexMtxFuncType type; // at 0x4 } mTable[NUM_SCNDEPENDENT_TEXMTX_FUNCTYPE]; // at 0x0 }; ScnDependentTexMtxFuncTable sScnDependentTexMtxFuncTable; /****************************************************************************** * * FogState * ******************************************************************************/ class FogState { public: FogState() : mFlag(0), mCurrentFogIdx(-1) { for (u32 i = 0; i < NUM_FOG; i++) { Fog(&mFogData[i]).Init(); } } void Invalidate() { mFlag = 0; } void SetFog(const Fog fog, int id) { if (id < 0 || id >= NUM_FOG || !fog.IsValid()) { return; } if (mCurrentFogIdx == id) { if (std::memcmp(&fog.ref(), &mFogData[id], sizeof(FogData)) == 0) { return; } Invalidate(); } fog.CopyTo(&mFogData[id]); } void LoadFog(int id) { if (!(mFlag & FLAG_0) || !(mFlag & FLAG_1) || id != mCurrentFogIdx) { if (id < 0 || id >= NUM_FOG) { GXColor color = {0, 0, 0, 0}; GXSetFog(GX_FOG_NONE, color, 0.0f, 0.0f, 0.0f, 0.0f); } else { Fog(&mFogData[id]).SetGP(); } mFlag |= FLAG_0 | FLAG_1; mCurrentFogIdx = id; } } private: enum Flag { FLAG_0 = (1 << 0), FLAG_1 = (1 << 1), }; private: u32 mFlag; // at 0x0 int mCurrentFogIdx; // at 0x4 FogData mFogData[NUM_FOG]; // at 0x8 }; FogState sFogState; /****************************************************************************** * * LightState * ******************************************************************************/ class LightState { public: LightState(); void Invalidate(); void SetLightSetting(const LightSetting &rSetting); const LightObj *GetLightObj(int id) const; void LoadLightSet( int id, u32 *pDiffColorMask, u32 *pDiffAlphaMask, u32 *pSpecColorMask, u32 *pSpecAlphaMask, AmbLightObj *pAmb ); private: LightSetting mLightSetting; // at 0x0 int mCurrentLightSetIdx; // at 0x10 u32 mCurrentMaskDiffColor; // at 0x14 u32 mCurrentMaskDiffAlpha; // at 0x18 u32 mCurrentMaskSpecColor; // at 0x1C u32 mCurrentMaskSpecAlpha; // at 0x20 s8 mLoadedLightIdx[NUM_LIGHT_IN_LIGHT_SET]; // at 0x24 LightObj mLightObj[NUM_LIGHT]; // at 0x2C AmbLightObj mAmbLightObj[NUM_LIGHT]; // at 0x222C LightSetData mLightSetData[NUM_LIGHT_SET]; // at 0x242C }; LightState sLightState; LightState::LightState() : mLightSetting(mLightObj, mAmbLightObj, NUM_LIGHT, mLightSetData, NUM_LIGHT_SET) { Invalidate(); } void LightState::Invalidate() { mCurrentLightSetIdx = -1; mCurrentMaskDiffColor = 0; mCurrentMaskDiffAlpha = 0; mCurrentMaskSpecColor = 0; mCurrentMaskSpecAlpha = 0; mLoadedLightIdx[0] = mLoadedLightIdx[1] = mLoadedLightIdx[2] = mLoadedLightIdx[3] = mLoadedLightIdx[4] = mLoadedLightIdx[5] = mLoadedLightIdx[6] = mLoadedLightIdx[7] = -1; } void LightState::SetLightSetting(const LightSetting &rSetting) { mLightSetting.Import(rSetting); const math::MTX34 *pCamMtx = GetCameraMtxPtr(); mLightSetting.ApplyViewMtx(*pCamMtx, rSetting.GetNumLightObj()); Invalidate(); u32 lightNum = mLightSetting.GetNumLightObj(); u32 i = 0; u32 idx = 0; for (; i < G3DState::NUM_LIGHT_IN_LIGHT_SET && idx < lightNum; idx++) { const LightObj &rLight = mLightSetting.GetLightObjArray()[idx]; if (!rLight.IsEnable()) { continue; } mLoadedLightIdx[i] = idx; GXLightID id = static_cast(1 << i); GXLoadLightObjImm(rLight, id); i++; } } const LightObj *LightState::GetLightObj(int id) const { if (id >= 0 && id < NUM_LIGHT) { return &mLightObj[id]; } return NULL; } void LightState::LoadLightSet( int id, u32 *pDiffColorMask, u32 *pDiffAlphaMask, u32 *pSpecColorMask, u32 *pSpecAlphaMask, AmbLightObj *pAmb ) { if (id < 0 || id >= NUM_LIGHT_SET) { if (pDiffColorMask != NULL) { *pDiffColorMask = 0; } if (pDiffAlphaMask != NULL) { *pDiffAlphaMask = 0; } if (pSpecColorMask != NULL) { *pSpecColorMask = 0; } if (pSpecAlphaMask != NULL) { *pSpecAlphaMask = 0; } if (pAmb != NULL) { pAmb->r = pAmb->g = pAmb->b = pAmb->a = 255; } return; } if (pAmb != NULL) { int ambId = mLightSetData[id].idxAmbLight; if (ambId < 0) { pAmb->r = pAmb->g = pAmb->b = pAmb->a = 255; } else { *pAmb = mAmbLightObj[ambId]; } } if (mCurrentLightSetIdx == id) { if (pDiffColorMask != NULL) { *pDiffColorMask = mCurrentMaskDiffColor; } if (pDiffAlphaMask != NULL) { *pDiffAlphaMask = mCurrentMaskDiffAlpha; } if (pSpecColorMask != NULL) { *pSpecColorMask = mCurrentMaskSpecColor; } if (pSpecAlphaMask != NULL) { *pSpecAlphaMask = mCurrentMaskSpecAlpha; } return; } LightSetData &rData = mLightSetData[id]; mCurrentMaskDiffColor = 0; mCurrentMaskDiffAlpha = 0; mCurrentMaskSpecColor = 0; mCurrentMaskSpecAlpha = 0; mCurrentLightSetIdx = id; for (u32 i = 0; i < NUM_LIGHT_IN_LIGHT_SET; i++) { s8 lightId = rData.idxLight[i]; if (lightId < 0) { continue; } if (!mLightObj[lightId].IsEnable()) { continue; } s8 *pLoaded = std::find(mLoadedLightIdx, mLoadedLightIdx + NUM_LIGHT_IN_LIGHT_SET, lightId); GXLightID idFlag; if (pLoaded == mLoadedLightIdx + NUM_LIGHT_IN_LIGHT_SET) { pLoaded = std::find(mLoadedLightIdx, mLoadedLightIdx + NUM_LIGHT_IN_LIGHT_SET, -1); if (pLoaded != mLoadedLightIdx + NUM_LIGHT_IN_LIGHT_SET) { idFlag = static_cast(1 << std::distance(mLoadedLightIdx, pLoaded)); GXLoadLightObjImm(mLightObj[lightId], idFlag); *pLoaded = lightId; } else { u32 j; for (j = 0; j < NUM_LIGHT_IN_LIGHT_SET; j++) { s8 *pResult = std::find(rData.idxLight, rData.idxLight + NUM_LIGHT_IN_LIGHT_SET, mLoadedLightIdx[j]); if (pResult == rData.idxLight + NUM_LIGHT_IN_LIGHT_SET) { break; } } idFlag = static_cast(1 << j); GXLoadLightObjImm(mLightObj[lightId], idFlag); mLoadedLightIdx[j] = lightId; } } else { idFlag = static_cast(1 << std::distance(mLoadedLightIdx, pLoaded)); } if (mLightObj[lightId].IsSpecularLight()) { if (mLightObj[lightId].IsColorEnable()) { mCurrentMaskSpecColor |= idFlag; } if (mLightObj[lightId].IsAlphaEnable()) { mCurrentMaskSpecAlpha |= idFlag; } } else { if (mLightObj[lightId].IsColorEnable()) { mCurrentMaskDiffColor |= idFlag; } if (mLightObj[lightId].IsAlphaEnable()) { mCurrentMaskDiffAlpha |= idFlag; } } } if (pDiffColorMask != NULL) { *pDiffColorMask = mCurrentMaskDiffColor; } if (pDiffAlphaMask != NULL) { *pDiffAlphaMask = mCurrentMaskDiffAlpha; } if (pSpecColorMask != NULL) { *pSpecColorMask = mCurrentMaskSpecColor; } if (pSpecAlphaMask != NULL) { *pSpecAlphaMask = mCurrentMaskSpecAlpha; } } /****************************************************************************** * * CameraMtxState * ******************************************************************************/ class CameraMtxState { public: CameraMtxState(); void SetCameraProjMtx(const Camera &rCam, int id, bool view); const math::MTX34 *GetInvCameraMtxPtr() const { if (!(mFlag & FLAG_INV_MTX_READY)) { math::MTX34Inv(&mInvCurrentCameraMtx, GetCameraMtxPtr()); mFlag |= FLAG_INV_MTX_READY; } return &mInvCurrentCameraMtx; } const math::MTX34 *GetCameraMtxPtr() const { return &mCameraMtx[mViewIdx]; } const math::MTX34 *GetCameraMtxPtr(int id) const { if (id < NUM_CAMERA && id >= 0) { return &mCameraMtx[id]; } return NULL; } const math::MTX44 *GetProjectionMtxPtr() const { return &mProjMtx[mViewIdx]; } const math::MTX44 *GetProjectionMtxPtr(int id) const { if (id < NUM_CAMERA && id >= 0) { return &mProjMtx[id]; } return NULL; } const math::MTX34 *GetProjectionTexMtxPtr() const { return &mProjTexMtx[mViewIdx]; } const math::MTX34 *GetProjectionTexMtxPtr(int id) const { if (id < NUM_CAMERA && id >= 0) { return &mProjTexMtx[id]; } return NULL; } const math::MTX34 *GetEnvironmentTexMtxPtr() const { return &mEnvTexMtx[mViewIdx]; } private: enum Flag { FLAG_INV_MTX_READY = (1 << 0), }; private: mutable u16 mFlag; // at 0x0 u16 mViewIdx; // at 0x2 mutable math::MTX34 mInvCurrentCameraMtx; // at 0x4 math::MTX34 mCameraMtx[NUM_CAMERA]; // at 0x34 math::MTX44 mProjMtx[NUM_CAMERA]; // at 0x634 math::MTX34 mProjTexMtx[NUM_CAMERA]; // at 0xE34 math::MTX34 mEnvTexMtx[NUM_CAMERA]; // at 0x1434 }; CameraMtxState sCameraMtxState; CameraMtxState::CameraMtxState() : mFlag(0), mViewIdx(0) { math::MTX34Identity(&mInvCurrentCameraMtx); for (u32 i = 0; i < NUM_CAMERA; i++) { math::MTX34Identity(&mCameraMtx[i]); math::MTX44Identity(&mProjMtx[i]); math::MTX34Identity(&mProjTexMtx[i]); math::MTX34Identity(&mEnvTexMtx[i]); } } void CameraMtxState::SetCameraProjMtx(const Camera &rCam, int id, bool view) { if (id >= NUM_CAMERA || id < 0) { return; } rCam.GetCameraMtx(&mCameraMtx[id]); rCam.GetProjectionMtx(&mProjMtx[id]); rCam.GetProjectionTexMtx(&mProjTexMtx[id]); rCam.GetEnvironmentTexMtx(&mEnvTexMtx[id]); if (view) { mViewIdx = static_cast(id); mFlag &= ~FLAG_INV_MTX_READY; } } /****************************************************************************** * * Render mode * ******************************************************************************/ GXRenderModeObj sRenderMode; /****************************************************************************** * * Misc * ******************************************************************************/ class Misc { public: Misc() : mValidFlag(0), mbZCompLoc(FALSE) {} void Invalidate() { InvalidateZCompLoc(); } void InvalidateZCompLoc() { mValidFlag &= ~FLAG_ZCOMPLOC; } void GXSetZCompLoc(GXBool beforeTex) { if (!(mValidFlag & FLAG_ZCOMPLOC) || mbZCompLoc != beforeTex) { mValidFlag |= FLAG_ZCOMPLOC; mbZCompLoc = beforeTex; ::GXSetZCompLoc(beforeTex); sSyncGX.Set(); } } private: enum ValidFlag { FLAG_ZCOMPLOC = (1 << 0), }; private: u32 mValidFlag; // at 0x0 GXBool mbZCompLoc; // at 0x4 }; Misc sMisc; } // namespace /****************************************************************************** * * G3DState * ******************************************************************************/ void LoadResMatMisc(const ResMatMisc misc) { if (!misc.IsValid()) { return; } sMisc.GXSetZCompLoc(misc.GXGetZCompLoc()); } void LoadResTexObj(const ResTexObj texObj) { if (!texObj.IsValid()) { return; } sTex.LoadResTexObj(texObj); sSyncGX.Set(); } void LoadResTlutObj(const ResTlutObj tlutObj) { if (!tlutObj.IsValid()) { return; } sTlut.LoadResTlutObj(tlutObj); sSyncGX.Set(); } void LoadResGenMode(const ResGenMode mode) { if (!mode.IsValid()) { return; } sGenMode2.SetResGenMode(mode); } void LoadResTev(const ResTev tev) { if (!tev.IsValid()) { return; } if (sTev.IsTevEqual(tev)) { return; } sGenMode2.LoadBP(); tev.CallDisplayList(sSyncGX.Get()); sTexCoordScale.UpdateTable(tev); sTexCoordScale.LoadTexCoordScale(sGenMode2.GXGetNumTexGens()); } void LoadResMatPix(const ResMatPix pix) { if (!pix.IsValid()) { return; } sGenMode2.LoadBP(); pix.CallDisplayList(sSyncGX.Get()); } void LoadResMatTevColor(const ResMatTevColor color) { if (!color.IsValid()) { return; } sGenMode2.LoadBP(); color.CallDisplayList(sSyncGX.Get()); } void LoadResMatIndMtxAndScale(const ResMatIndMtxAndScale ind) { if (!ind.IsValid()) { return; } sGenMode2.LoadBP(); ind.CallDisplayList(sGenMode2.GXGetNumIndStages(), sSyncGX.Get()); } void LoadResMatIndMtxAndScale(const ResMatIndMtxAndScale ind, IndMtxOp &rOp) { if (!ind.IsValid()) { return; } LoadResMatIndMtxAndScale(ind); IndTexMtxInfo info(ind); rOp(&info); info.FifoSend(); } void LoadResMatChan( const ResMatChan chan, u32 maskDiffColor, u32 maskDiffAlpha, u32 maskSpecColor, u32 maskSpecAlpha, GXColor amb, bool lightOff ) { if (!chan.IsValid()) { return; } { const Chan &r = chan.ref().chan[0]; if (r.flag & Chan::FLAG_MAT_COLOR_ENABLE) { if (r.flag & Chan::FLAG_MAT_ALPHA_ENABLE) { // @bug Color+Alpha channel is GX_COLOR0A0 fifo::GDSetChanMatColor(GX_COLOR0, r.matColor); } else { fifo::GDSetChanMatColor(GX_COLOR0, r.matColor); } } else if (r.flag & Chan::FLAG_MAT_ALPHA_ENABLE) { // @bug Alpha channel is GX_ALPHA0 fifo::GDSetChanMatColor(GX_COLOR0, r.matColor); } GXColor ambColor; ambColor.r = 0.5f + (amb.r * r.ambColor.r) * (1.0f / 255.0f); ambColor.g = 0.5f + (amb.g * r.ambColor.g) * (1.0f / 255.0f); ambColor.b = 0.5f + (amb.b * r.ambColor.b) * (1.0f / 255.0f); ambColor.a = 0.5f + (amb.a * r.ambColor.a) * (1.0f / 255.0f); if (r.flag & Chan::FLAG_AMB_COLOR_ENABLE) { if (r.flag & Chan::FLAG_AMB_ALPHA_ENABLE) { // @bug Color+Alpha channel is GX_COLOR0A0 fifo::GDSetChanAmbColor(GX_COLOR0, ambColor); } else { fifo::GDSetChanAmbColor(GX_COLOR0, ambColor); } } else if (r.flag & Chan::FLAG_AMB_ALPHA_ENABLE) { // @bug Alpha channel is GX_ALPHA0 fifo::GDSetChanAmbColor(GX_COLOR0, ambColor); } if (lightOff) { if (r.flag & Chan::FLAG_CTRL_COLOR_ENABLE) { fifo::GDSetChanCtrlLightOff(GX_COLOR0, r.paramChanCtrlC, maskDiffColor); } if (r.flag & Chan::FLAG_CTRL_ALPHA_ENABLE) { fifo::GDSetChanCtrlLightOff(GX_ALPHA0, r.paramChanCtrlA, maskDiffAlpha); } } else { if (r.flag & Chan::FLAG_CTRL_COLOR_ENABLE) { fifo::GDSetChanCtrl(GX_COLOR0, r.paramChanCtrlC, maskDiffColor); } if (r.flag & Chan::FLAG_CTRL_ALPHA_ENABLE) { fifo::GDSetChanCtrl(GX_ALPHA0, r.paramChanCtrlA, maskDiffAlpha); } } } { if (sGenMode2.GXGetNumChans() == 2) { const Chan &r = chan.ref().chan[1]; if (r.flag & Chan::FLAG_MAT_COLOR_ENABLE) { if (r.flag & Chan::FLAG_MAT_ALPHA_ENABLE) { // @bug Color+Alpha channel is GX_COLOR1A1 fifo::GDSetChanMatColor(GX_COLOR1, r.matColor); } else { fifo::GDSetChanMatColor(GX_COLOR1, r.matColor); } } else if (r.flag & Chan::FLAG_MAT_ALPHA_ENABLE) { // @bug Alpha channel is GX_ALPHA1 fifo::GDSetChanMatColor(GX_COLOR1, r.matColor); } if (r.flag & Chan::FLAG_AMB_COLOR_ENABLE) { if (r.flag & Chan::FLAG_AMB_ALPHA_ENABLE) { // @bug Color+Alpha channel is GX_COLOR1A1 fifo::GDSetChanAmbColor(GX_COLOR1, r.ambColor); } else { fifo::GDSetChanAmbColor(GX_COLOR1, r.ambColor); } } else if (r.flag & Chan::FLAG_AMB_ALPHA_ENABLE) { // @bug Alpha channel is GX_ALPHA1 fifo::GDSetChanAmbColor(GX_COLOR1, r.ambColor); } if (lightOff) { if (r.flag & Chan::FLAG_CTRL_COLOR_ENABLE) { fifo::GDSetChanCtrlLightOff(GX_COLOR1, r.paramChanCtrlC, maskSpecColor); } if (r.flag & Chan::FLAG_CTRL_ALPHA_ENABLE) { fifo::GDSetChanCtrlLightOff(GX_ALPHA1, r.paramChanCtrlA, maskSpecAlpha); } } else { if (r.flag & Chan::FLAG_CTRL_COLOR_ENABLE) { fifo::GDSetChanCtrl(GX_COLOR1, r.paramChanCtrlC, maskSpecColor); } if (r.flag & Chan::FLAG_CTRL_ALPHA_ENABLE) { fifo::GDSetChanCtrl(GX_ALPHA1, r.paramChanCtrlA, maskSpecAlpha); } } } else { fifo::GDSetChanCtrl(GX_COLOR1, 0, 0); fifo::GDSetChanCtrl(GX_ALPHA1, 0, 0); } } sGenMode2.LoadXF(); } void LoadResMatTexCoordGen(const ResMatTexCoordGen gen) { if (!gen.IsValid()) { return; } gen.CallDisplayList(sGenMode2.GXGetNumTexGens(), sSyncGX.Get()); sGenMode2.LoadXF(); } void LoadResTexSrt(const ResTexSrt srt) { math::MTX34 mtx; for (u32 i = 0; i < ResTexSrtData::NUM_OF_TEXTURE; i++) { if (srt.IsExist(i)) { bool ident = true; const TexMtxEffect &rEffect = srt.ref().effect[i]; math::MTX34Identity(&mtx); if (rEffect.map_mode != 0) { sScnDependentTexMtxFuncTable.Calc(rEffect.map_mode, &mtx, rEffect.ref_camera, rEffect.ref_light); sPreTexMtxState.SetFuncType(i, sScnDependentTexMtxFuncTable.GetFuncType(rEffect.map_mode)); ident = false; } else { sPreTexMtxState.SetFuncType(i, SCNDEPENDENT_TEXMTX_FUNCTYPE_TEXMTX_NOT_EXIST); } if (!srt.IsIdentity(i)) { if (ident) { if (!(rEffect.misc_flag & TexMtxEffect::FLAG_IDENT)) { ident = false; math::MTX34Copy(&mtx, static_cast(&rEffect.effectMtx)); } } else { math::MTX34Mult(&mtx, static_cast(&rEffect.effectMtx), &mtx); } if (rEffect.map_mode == 0) { CalcTexMtx(&mtx, ident, srt.ref().texSrt[i], srt.GetTexSrtFlag(i), srt.GetTexMtxMode()); } else { math::MTX34 srtMtx; CalcTexMtx(&srtMtx, true, srt.ref().texSrt[i], srt.GetTexSrtFlag(i), srt.GetTexMtxMode()); std::swap(srtMtx._02, srtMtx._03); std::swap(srtMtx._12, srtMtx._13); math::MTX34Mult(&mtx, &srtMtx, &mtx); } ident = false; } if (ident) { if (!sPostTexMtx.IsIdentity(i)) { math::MTX34 identMtx; sPostTexMtx.SetIdentity(i); math::MTX34Identity(&identMtx); GXLoadTexMtxImm(identMtx, i * 3 + GX_DUALMTX0, GX_MTX3x4); } } else { sPostTexMtx.ResetIdentity(i); GXLoadTexMtxImm(mtx, i * 3 + GX_DUALMTX0, GX_MTX3x4); } } else { sPreTexMtxState.SetFuncType(i, SCNDEPENDENT_TEXMTX_FUNCTYPE_TEXMTX_NOT_EXIST); } } } void LoadResShpPrePrimitive(const ResShp shp) { if (!shp.IsValid()) { return; } sTexCoordScale.LoadTexCoordScale(sGenMode2.GXGetNumTexGens()); sGenMode2.LoadXF(); shp.CallPrePrimitiveDisplayList(sSyncGX.Get(), sShp.IsCacheEqual(shp.ref().cache)); } void LoadResShpPrimitive(const ResShp shp, const math::MTX34 *pViewPos, const math::MTX34 *pViewNrm) { if (!shp.IsValid()) { return; } sTexCoordScale.LoadTexCoordScale(sGenMode2.GXGetNumTexGens()); int id = shp.ref().curMtxIdx; bool envelope = (id & ResShpData::ID_FLAG_ENVELOPE) != 0; if (!envelope) { if (pViewPos != NULL) { GXLoadPosMtxImm(*pViewPos, GX_PNMTX0); if (shp.ExistVtxDesc(GX_VA_NRM)) { if (pViewNrm != NULL) { GXLoadNrmMtxImm(*pViewNrm, GX_PNMTX0); } else { GXLoadNrmMtxImm(*pViewPos, GX_PNMTX0); } } } else { GXLoadPosMtxIndx(id, GX_PNMTX0); if (shp.ExistVtxDesc(GX_VA_NRM)) { GXLoadNrmMtxIndx3x3(id, GX_PNMTX0); } } sPreTexMtxState.SetCurrentMtx(id); } else { sCurrMtx.SetCurrMtx(); } sGenMode2.LoadXF(); shp.CallPrimitiveDisplayList(sSyncGX.Get()); if (envelope) { sCurrMtx.Invalidate(); } } void SetViewPosNrmMtxArray( const math::MTX34 *pViewPosMtxArray, const math::MTX33 *pViewNrmMtxArray, const math::MTX34 *pViewEnvTexMtxArray ) { sPosNrmArrayState.SetViewPosNrmMtxArray(pViewPosMtxArray, pViewNrmMtxArray, pViewEnvTexMtxArray); } const math::MTX33 *GetViewNrmMtxPtr(u32 id) { return sPosNrmArrayState.GetViewNrmMtxPtr(id); } void SetScnDependentTexMtxFunc(u32 id, ScnDependentTexMtxFuncPtr func, ScnDependentTexMtxFuncType type) { sScnDependentTexMtxFuncTable.SetFunc(id, func, type); } bool GetScnDependentTexMtxFunc(u32 id, ScnDependentTexMtxFuncPtr *pFunc, ScnDependentTexMtxFuncType *pType) { return sScnDependentTexMtxFuncTable.GetFunc(id, pFunc, pType); } namespace { IndMtxOpStd IndMtxOpDefault; IndMtxOp *pG3DStateIndMtxOp = &IndMtxOpDefault; } // namespace IndMtxOp *GetIndMtxOp() { return pG3DStateIndMtxOp; } void SetFog(const Fog fog, int id) { sFogState.SetFog(fog, id); } void LoadFog(int id) { sFogState.LoadFog(id); } void SetLightSetting(const LightSetting &rSetting) { sLightState.SetLightSetting(rSetting); } const LightObj *GetLightObj(int id) { return sLightState.GetLightObj(id); } void LoadLightSet( int id, u32 *pDiffColorMask, u32 *pDiffAlphaMask, u32 *pSpecColorMask, u32 *pSpecAlphaMask, AmbLightObj *pAmb ) { sLightState.LoadLightSet(id, pDiffColorMask, pDiffAlphaMask, pSpecColorMask, pSpecAlphaMask, pAmb); } void LoadLightSet(int id, u32 *pDiffMask, u32 *pSpecMask, AmbLightObj *pAmb) { u32 diffAlphaMask, specAlphaMask; sLightState.LoadLightSet(id, pDiffMask, &diffAlphaMask, pSpecMask, &specAlphaMask, pAmb); if (pDiffMask != NULL) { *pDiffMask |= diffAlphaMask; } if (pSpecMask != NULL) { *pSpecMask |= specAlphaMask; } } void SetCameraProjMtx(const Camera &rCam, int id, bool view) { sCameraMtxState.SetCameraProjMtx(rCam, id, view); } const math::MTX34 *GetCameraMtxPtr() { return sCameraMtxState.GetCameraMtxPtr(); } const math::MTX34 *GetInvCameraMtxPtr() { return sCameraMtxState.GetInvCameraMtxPtr(); } const math::MTX34 *GetCameraMtxPtr(int id) { return sCameraMtxState.GetCameraMtxPtr(id); } const math::MTX34 *GetProjectionTexMtxPtr() { return sCameraMtxState.GetProjectionTexMtxPtr(); } const math::MTX34 *GetProjectionTexMtxPtr(int id) { return sCameraMtxState.GetProjectionTexMtxPtr(id); } const math::MTX34 *GetEnvironmentTexMtxPtr() { return sCameraMtxState.GetEnvironmentTexMtxPtr(); } void SetRenderModeObj(const GXRenderModeObj &rObj) { sRenderMode = rObj; } const GXRenderModeObj *GetRenderModeObj() { return &sRenderMode; } void Invalidate(u32 flag) { if (flag & INVALIDATE_TEX) { sTex.Invalidate(); sTexCoordScale.Invalidate(); } if (flag & INVALIDATE_TLUT) { sTlut.Invalidate(); } if (flag & INVALIDATE_TEV) { sTexCoordScale.Invalidate(); sTev.Invalidate(); } if (flag & INVALIDATE_GENMODE) { sGenMode2.Invalidate(); } if (flag & INVALIDATE_SHP) { sShp.Invalidate(); } if (flag & INVALIDATE_CURRMTX) { sCurrMtx.Invalidate(); } if (flag & INVALIDATE_TEXMTX) { sPreTexMtxState.Invalidate(); sPostTexMtx.Invalidate(); } if (flag & INVALIDATE_MISC) { sMisc.Invalidate(); } if (flag & INVALIDATE_FOG) { sFogState.Invalidate(); } if (flag & INVALIDATE_LIGHT) { sLightState.Invalidate(); } if (flag & INVALIDATE_POSMTX) { sPosNrmArrayState.Invalidate(); } sSyncGX.Invalidate(); } /****************************************************************************** * * IndMtxOpStd * ******************************************************************************/ IndMtxOpStd::IndMtxOpStd() { math::MTX34Identity(&mIndMtx[GX_ITM_0 - 1]); math::MTX34Identity(&mIndMtx[GX_ITM_1 - 1]); math::MTX34Identity(&mIndMtx[GX_ITM_2 - 1]); mIsValidMtx[GX_ITM_0 - 1] = mIsValidMtx[GX_ITM_1 - 1] = mIsValidMtx[GX_ITM_2 - 1] = false; PADDING_0x7 = 0; } void IndMtxOpStd::SetNrmMapMtx( GXIndTexMtxID id, const math::VEC3 *pLightVec, const math::MTX34 *pNrmMtx, ResMatMiscData::IndirectMethod method ) { if (id >= GX_ITM_0 && id <= GX_ITM_2 && method != ResMatMiscData::WARP && method != ResMatMiscData::FUR) { u32 i = id - GX_ITM_0; mIsValidMtx[i] = true; if (pLightVec != NULL) { mIndMtx[i]._00 = 0.5f * -pLightVec->x; mIndMtx[i]._01 = 0.5f * -pLightVec->y; mIndMtx[i]._02 = 0.5f * -pLightVec->z; if (method == ResMatMiscData::NORMAL_MAP_SPECULAR) { math::VEC3 H(pLightVec->x, pLightVec->y, pLightVec->z - 1.0f); math::VEC3Normalize(&H, &H); mIndMtx[i]._10 = 0.5f * -H.x; mIndMtx[i]._11 = 0.5f * -H.y; mIndMtx[i]._12 = 0.5f * -H.z; } else { mIndMtx[i]._10 = mIndMtx[i]._11 = mIndMtx[i]._12 = 0.0f; } math::MTX34Mult(&mIndMtx[i], &mIndMtx[i], pNrmMtx); } else { math::MTX34Zero(&mIndMtx[i]); } } } void IndMtxOpStd::Reset() { math::MTX34Identity(&mIndMtx[GX_ITM_0 - 1]); math::MTX34Identity(&mIndMtx[GX_ITM_1 - 1]); math::MTX34Identity(&mIndMtx[GX_ITM_2 - 1]); mIsValidMtx[GX_ITM_0 - 1] = mIsValidMtx[GX_ITM_1 - 1] = mIsValidMtx[GX_ITM_2 - 1] = false; } void IndMtxOpStd::operator()(IndTexMtxInfo *pInfo) { if (mIsValidMtx[GX_ITM_0 - 1]) { pInfo->SetMtx(GX_ITM_0, mIndMtx[GX_ITM_0 - 1]); } if (mIsValidMtx[GX_ITM_1 - 1]) { pInfo->SetMtx(GX_ITM_1, mIndMtx[GX_ITM_1 - 1]); } if (mIsValidMtx[GX_ITM_2 - 1]) { pInfo->SetMtx(GX_ITM_2, mIndMtx[GX_ITM_2 - 1]); } } } // namespace G3DState } // namespace g3d } // namespace nw4r