#include "nw4r/g3d.h" // IWYU pragma: export #include namespace nw4r { namespace g3d { /****************************************************************************** * * GetParent * ******************************************************************************/ ResMdl ResMat::GetParent() { return ofs_to_obj(ref().toResMdlData); } const ResMdl ResMat::GetParent() const { return ofs_to_obj(ref().toResMdlData); } /****************************************************************************** * * DCStore * ******************************************************************************/ void ResMatPix::DCStore(bool sync) { ResPixDL &r = ref(); if (sync) { DC::StoreRange(&r, sizeof(ResPixDL)); } else { DC::StoreRangeNoSync(&r, sizeof(ResPixDL)); } } void ResMatTevColor::DCStore(bool sync) { ResTevColorDL &r = ref(); if (sync) { DC::StoreRange(&r, sizeof(ResTevColorDL)); } else { DC::StoreRangeNoSync(&r, sizeof(ResTevColorDL)); } } void ResMatIndMtxAndScale::DCStore(bool sync) { ResIndMtxAndScaleDL &r = ref(); if (sync) { DC::StoreRange(&r, sizeof(ResIndMtxAndScaleDL)); } else { DC::StoreRangeNoSync(&r, sizeof(ResIndMtxAndScaleDL)); } } void ResMatTexCoordGen::DCStore(bool sync) { ResTexCoordGenDL &r = ref(); if (sync) { DC::StoreRange(&r, sizeof(ResTexCoordGenDL)); } else { DC::StoreRangeNoSync(&r, sizeof(ResTexCoordGenDL)); } } /****************************************************************************** * * CallDisplayList * ******************************************************************************/ void ResMatPix::CallDisplayList(bool sync) const { const ResPixDL &r = ref(); if (sync) { GXCallDisplayList(const_cast(&r), sizeof(ResPixDL)); } else { GXFastCallDisplayList(const_cast(&r), sizeof(ResPixDL)); } } void ResMatTevColor::CallDisplayList(bool sync) const { const ResTevColorDL &r = ref(); if (sync) { GXCallDisplayList(const_cast(&r), sizeof(ResTevColorDL)); } else { GXFastCallDisplayList(const_cast(&r), sizeof(ResTevColorDL)); } } /****************************************************************************** * * CopyTo * ******************************************************************************/ ResMatPix ResMatPix::CopyTo(void *pDst) const { detail::Copy32ByteBlocks(pDst, ptr(), sizeof(ResPixDL)); return ResMatPix(pDst); } ResMatTevColor ResMatTevColor::CopyTo(void *pDst) const { detail::Copy32ByteBlocks(pDst, ptr(), sizeof(ResTevColorDL)); return ResMatTevColor(pDst); } ResMatIndMtxAndScale ResMatIndMtxAndScale::CopyTo(void *pDst) const { detail::Copy32ByteBlocks(pDst, ptr(), sizeof(ResIndMtxAndScaleDL)); return ResMatIndMtxAndScale(pDst); } ResMatTexCoordGen ResMatTexCoordGen::CopyTo(void *pDst) const { detail::Copy32ByteBlocks(pDst, ptr(), sizeof(ResTexCoordGenDL)); return ResMatTexCoordGen(pDst); } /****************************************************************************** * * ResTexObj * ******************************************************************************/ const GXTexObj *ResTexObj::GetTexObj(GXTexMapID id) const { if (IsValid() && id >= GX_TEXMAP0 && id <= GX_TEXMAP7) { return &ptr()->texObj[id]; } return NULL; } GXTexObj *ResTexObj::GetTexObj(GXTexMapID id) { if (IsValid() && id >= GX_TEXMAP0 && id <= GX_TEXMAP7) { return &ptr()->texObj[id]; } return NULL; } bool ResTexObj::IsValidTexObj(GXTexMapID id) const { if (IsValid() && id >= GX_TEXMAP0 && id <= GX_TEXMAP7) { return ptr()->flagUsedTexMapID & (1 << id); } return false; } void ResTexObj::Validate(GXTexMapID id) { if (IsValid() && id >= GX_TEXMAP0 && id <= GX_TEXMAP7) { ptr()->flagUsedTexMapID |= (1 << id); } } void ResTexObj::Invalidate(GXTexMapID id) { if (IsValid() && id >= GX_TEXMAP0 && id <= GX_TEXMAP7) { ptr()->flagUsedTexMapID &= ~(1 << id); } } ResTexObj ResTexObj::CopyTo(void *pDst) const { ResTexObjData *pData = static_cast(pDst); const ResTexObjData &rSrc = ref(); u32 i = 0; u32 flag = rSrc.flagUsedTexMapID; pData->flagUsedTexMapID = flag; for (; flag != 0; flag >>= 1, i++) { if (!(flag & 1)) { continue; } detail::Copy32ByteBlocks(&pData->texObj[i], &rSrc.texObj[i], sizeof(GXTexObj)); } return ResTexObj(pData); } /****************************************************************************** * * ResTlutObj * ******************************************************************************/ const GXTlutObj *ResTlutObj::GetTlut(GXTlut tlut) const { if (IsValid() && tlut >= GX_TLUT0 && tlut <= GX_TLUT7) { return &ptr()->tlutObj[tlut]; } return NULL; } GXTlutObj *ResTlutObj::GetTlut(GXTlut tlut) { if (IsValid() && tlut >= GX_TLUT0 && tlut <= GX_TLUT7) { return &ptr()->tlutObj[tlut]; } return NULL; } bool ResTlutObj::IsValidTlut(GXTlut tlut) const { if (IsValid() && tlut >= GX_TLUT0 && tlut <= GX_TLUT7) { return ptr()->flagUsedTlutID & (1 << tlut); } return false; } void ResTlutObj::Validate(GXTlut tlut) { if (IsValid() && tlut >= GX_TLUT0 && tlut <= GX_TLUT7) { ptr()->flagUsedTlutID |= (1 << tlut); } } void ResTlutObj::Invalidate(GXTlut tlut) { if (IsValid() && tlut >= GX_TLUT0 && tlut <= GX_TLUT7) { ptr()->flagUsedTlutID &= ~(1 << tlut); } } ResTlutObj ResTlutObj::CopyTo(void *pDst) const { ResTlutObjData *pData = static_cast(pDst); const ResTlutObjData &rSrc = ref(); u32 flag = rSrc.flagUsedTlutID; pData->flagUsedTlutID = flag; if (flag != 0) { if (!(flag & static_cast(~(1 << GX_TLUT0 | 1 << GX_TLUT1)))) { // At most two tlut objects can fit into 64 bytes detail::Copy32ByteBlocks(&pData->tlutObj, &rSrc.tlutObj, 32); } else if (!(flag & static_cast(~(1 << GX_TLUT0 | 1 << GX_TLUT1 | 1 << GX_TLUT2 | 1 << GX_TLUT3 | 1 << GX_TLUT4)) )) { // At most five tlut objects can fit into 64 bytes detail::Copy32ByteBlocks(&pData->tlutObj, &rSrc.tlutObj, 64); } else { // Full copy is divisible by 32 detail::Copy32ByteBlocks(&pData->tlutObj, &rSrc.tlutObj, sizeof(GXTlutObj) * (GX_TLUT7 + 1)); } } return ResTlutObj(pData); } /****************************************************************************** * * ResTexSrt * ******************************************************************************/ ResTexSrt ResTexSrt::CopyTo(void *pDst) const { ResTexSrtData *pData = static_cast(pDst); const ResTexSrtData &r = ref(); u32 flag = r.flag; pData->flag = flag; pData->texMtxMode = r.texMtxMode; for (u32 i = 0; flag != 0; flag >>= TexSrt::NUM_OF_FLAGS, i++) { if (!(flag & TexSrt::FLAGSET_IDENTITY)) { continue; } const TexSrt &rFrom = r.texSrt[i]; const TexMtxEffect &rFromEffect = r.effect[i]; TexSrt &rTo = pData->texSrt[i]; TexMtxEffect &rToEffect = pData->effect[i]; rTo.Su = rFrom.Su; rTo.Sv = rFrom.Sv; rTo.R = rFrom.R; rTo.Tu = rFrom.Tu; rTo.Tv = rFrom.Tv; rToEffect.ref_camera = rFromEffect.ref_camera; rToEffect.ref_light = rFromEffect.ref_light; rToEffect.map_mode = rFromEffect.map_mode; rToEffect.misc_flag = rFromEffect.misc_flag; math::MTX34Copy( static_cast(&rToEffect.effectMtx), static_cast(&rFromEffect.effectMtx) ); } return ResTexSrt(pData); } bool ResTexSrt::SetEffectMtx(u32 id, const math::MTX34 *pMtx) { if (id < ResTexSrtData::NUM_OF_TEXTURE) { TexMtxEffect &rEffect = ref().effect[id]; if (pMtx != NULL) { math::MTX34Copy(static_cast(&rEffect.effectMtx), pMtx); rEffect.misc_flag &= ~TexMtxEffect::FLAG_IDENT; } else { math::MTX34Identity(static_cast(&rEffect.effectMtx)); rEffect.misc_flag |= TexMtxEffect::FLAG_IDENT; } return true; } return false; } bool ResTexSrt::GetEffectMtx(u32 id, math::MTX34 *pMtx) const { if (pMtx != NULL && id < ResTexSrtData::NUM_OF_TEXTURE) { const TexMtxEffect &rEffect = ref().effect[id]; math::MTX34Copy(pMtx, static_cast(&rEffect.effectMtx)); return true; } return false; } bool ResTexSrt::SetMapMode(u32 id, u32 mode, int camRef, int lightRef) { if (id < ResTexSrtData::NUM_OF_TEXTURE && mode < G3DState::NUM_SCNDEPENDENT_TEXMTX_FUNCTYPE) { ResTexSrtData &r = ref(); TexMtxEffect &rEffect = r.effect[id]; rEffect.map_mode = mode; rEffect.ref_camera = camRef >= 0 && camRef < G3DState::NUM_CAMERA ? static_cast(camRef) : -1; rEffect.ref_light = lightRef >= 0 && lightRef < G3DState::NUM_LIGHT ? static_cast(lightRef) : -1; return true; } return false; } bool ResTexSrt::GetMapMode(u32 id, u32 *pMode, int *pCamRef, int *pLightRef) const { if (id < ResTexSrtData::NUM_OF_TEXTURE) { const ResTexSrtData &r = ref(); const TexMtxEffect &rEffect = r.effect[id]; if (pMode != NULL) { *pMode = rEffect.map_mode; } if (pCamRef != NULL) { *pCamRef = rEffect.ref_camera; } if (pLightRef != NULL) { *pLightRef = rEffect.ref_light; } return true; } return false; } /****************************************************************************** * * ResGenMode * ******************************************************************************/ void ResGenMode::GXSetNumTexGens(u8 num) { if (IsValid()) { ref().nTexGens = num; } } void ResGenMode::GXSetNumChans(u8 num) { if (IsValid()) { ref().nChans = num; } } void ResGenMode::GXSetNumTevStages(u8 num) { if (IsValid()) { ref().nTevs = num; } } void ResGenMode::GXSetNumIndStages(u8 num) { if (IsValid()) { ref().nInds = num; } } void ResGenMode::GXSetCullMode(GXCullMode mode) { if (IsValid()) { ref().cullMode = mode; } } ResGenMode ResGenMode::CopyTo(void *pDst) const { ResGenModeData *pData = static_cast(pDst); const ResGenModeData &r = ref(); *pData = r; return ResGenMode(pData); } /****************************************************************************** * * ResMatMisc * ******************************************************************************/ GXBool ResMatMisc::GXGetZCompLoc() const { if (IsValid()) { return ptr()->zCompLoc; } return FALSE; } void ResMatMisc::SetLightSetIdx(int idx) { if (IsValid()) { if (idx > (u32)0x7F) { ptr()->light_set_idx = -1; } else { ptr()->light_set_idx = idx; } } } int ResMatMisc::GetLightSetIdx() const { if (IsValid()) { return ptr()->light_set_idx; } return -1; } void ResMatMisc::SetFogIdx(int idx) { if (IsValid()) { ptr()->fog_idx = idx; } } int ResMatMisc::GetFogIdx() const { if (IsValid()) { return ptr()->fog_idx; } return -1; } void ResMatMisc::GetIndirectTexMtxCalcMethod(GXIndTexMtxID id, ResMatMiscData::IndirectMethod *pMethod, s8 *pLightRef) { if (IsValid() && id >= GX_ITM_0 && id <= GX_ITM_2) { ResMatMiscData &r = *ptr(); if (pMethod != NULL) { *pMethod = static_cast(r.indirect_method[id - GX_ITM_0]); } if (pLightRef != NULL) { *pLightRef = r.normal_map_ref_light[id - GX_ITM_0]; } } } ResMatMisc ResMatMisc::CopyTo(void *pDst) const { ResMatMiscData *pData = static_cast(pDst); const ResMatMiscData &r = ref(); *pData = r; return ResMatMisc(pData); } /****************************************************************************** * * ResMatFur * ******************************************************************************/ f32 ResMatFur::GetLyrRate(u32 idx) const { 0.f; // For Float Ordering 1.f; // For Float Ordering if (IsValid()) { u32 layerSize = ref().lyrSize; switch (ref().lyrInterval) { case ResMatFurData::UNIFORM: { return f32(idx + 1) / layerSize; } break; case ResMatFurData::TIP: { return pow(f32(idx + 1) / layerSize, 0.6f); } break; default: { return 0.f; } break; } } return 0.f; } /****************************************************************************** * * ResMatPix * ******************************************************************************/ bool ResMatPix::GXGetAlphaCompare(GXCompare *pComp0, u8 *pRef0, GXAlphaOp *pLogic, GXCompare *pComp1, u8 *pRef1) const { const u8 *pCmd = ref().dl.alphaCompare; if (pCmd[0] == 0) { return false; } u32 reg; detail::ResReadBPCmd(pCmd, ®); if (pRef0 != NULL) { *pRef0 = reg >> GX_BP_ALPHACOMPARE_REF0_SHIFT & GX_BP_ALPHACOMPARE_REF0_LMASK; } if (pRef1 != NULL) { *pRef1 = reg >> GX_BP_ALPHACOMPARE_REF1_SHIFT & GX_BP_ALPHACOMPARE_REF1_LMASK; } if (pComp0 != NULL) { *pComp0 = static_cast(reg >> GX_BP_ALPHACOMPARE_COMP0_SHIFT & GX_BP_ALPHACOMPARE_COMP0_LMASK); } if (pComp1 != NULL) { *pComp1 = static_cast(reg >> GX_BP_ALPHACOMPARE_COMP1_SHIFT & GX_BP_ALPHACOMPARE_COMP1_LMASK); } if (pLogic != NULL) { *pLogic = static_cast(reg >> GX_BP_ALPHACOMPARE_LOGIC_SHIFT & GX_BP_ALPHACOMPARE_LOGIC_LMASK); } return true; } void ResMatPix::GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp logic, GXCompare comp1, u8 ref1) { u8 *pCmd = ref().dl.alphaCompare; u32 reg = ref0 << GX_BP_ALPHACOMPARE_REF0_SHIFT | ref1 << GX_BP_ALPHACOMPARE_REF1_SHIFT | comp0 << GX_BP_ALPHACOMPARE_COMP0_SHIFT | comp1 << GX_BP_ALPHACOMPARE_COMP1_SHIFT | logic << GX_BP_ALPHACOMPARE_LOGIC_SHIFT | GX_BP_REG_ALPHACOMPARE << GX_BP_OPCODE_SHIFT; detail::ResWriteBPCmd(pCmd, reg); } bool ResMatPix::GXGetZMode(GXBool *pTest, GXCompare *pCompare, GXBool *pUpdate) const { const u8 *pCmd = ref().dl.zMode; if (pCmd[0] == 0) { return false; } u32 reg; detail::ResReadBPCmd(pCmd, ®); if (pTest != NULL) { *pTest = reg >> GX_BP_ZMODE_TEST_ENABLE_SHIFT & GX_BP_ZMODE_TEST_ENABLE_LMASK; } if (pCompare != NULL) { *pCompare = static_cast(reg >> GX_BP_ZMODE_COMPARE_SHIFT & GX_BP_ZMODE_COMPARE_LMASK); } if (pUpdate != NULL) { // @note Update enable is only one bit *pUpdate = reg >> GX_BP_ZMODE_UPDATE_ENABLE_SHIFT & 0xFF; } return true; } void ResMatPix::GXSetZMode(GXBool test, GXCompare compare, GXBool update) { u8 *pCmd = ref().dl.zMode; u32 reg = test << GX_BP_ZMODE_TEST_ENABLE_SHIFT | compare << GX_BP_ZMODE_COMPARE_SHIFT | update << GX_BP_ZMODE_UPDATE_ENABLE_SHIFT | GX_BP_REG_ZMODE << GX_BP_OPCODE_SHIFT; detail::ResWriteBPCmd(pCmd, reg); } bool ResMatPix::GXGetBlendMode( GXBlendMode *pMode, GXBlendFactor *pSrcFactor, GXBlendFactor *pDstFactor, GXLogicOp *pLogic ) const { const u8 *pCmd = ref().dl.blendMode; if (pCmd[0] == 0) { return false; } u32 reg; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 1], ®); GXBlendMode mode; if (reg >> GX_BP_BLENDMODE_LOGIC_OP_ENABLE_SHIFT & GX_BP_BLENDMODE_LOGIC_OP_ENABLE_LMASK) { mode = GX_BM_LOGIC; } else if (reg >> GX_BP_BLENDMODE_SUBTRACT_SHIFT & GX_BP_BLENDMODE_SUBTRACT_LMASK) { mode = GX_BM_SUBTRACT; } else if (reg >> GX_BP_BLENDMODE_BLEND_ENABLE_SHIFT & GX_BP_BLENDMODE_BLEND_ENABLE_LMASK) { mode = GX_BM_BLEND; } else { mode = GX_BM_NONE; } if (pMode != NULL) { *pMode = mode; } if (pSrcFactor != NULL) { *pSrcFactor = static_cast(reg >> GX_BP_BLENDMODE_SRC_FACTOR_SHIFT & GX_BP_BLENDMODE_SRC_FACTOR_LMASK); } if (pDstFactor != NULL) { *pDstFactor = static_cast(reg >> GX_BP_BLENDMODE_DST_FACTOR_SHIFT & GX_BP_BLENDMODE_DST_FACTOR_LMASK); } if (pLogic != NULL) { *pLogic = static_cast( // @note Logic mode is only four bits reg >> GX_BP_BLENDMODE_LOGIC_MODE_SHIFT & 0xFFF ); } return true; } void ResMatPix::GXSetBlendMode(GXBlendMode mode, GXBlendFactor srcFactor, GXBlendFactor dstFactor, GXLogicOp logic) { u8 *pCmd = ref().dl.blendMode; // clang-format off detail::ResWriteSSMask(&pCmd[GX_BP_CMD_SZ * 0], GX_BP_BLENDMODE_BLEND_ENABLE_MASK | GX_BP_BLENDMODE_LOGIC_OP_ENABLE_MASK | GX_BP_BLENDMODE_DST_FACTOR_MASK | GX_BP_BLENDMODE_SRC_FACTOR_MASK | GX_BP_BLENDMODE_SUBTRACT_MASK | GX_BP_BLENDMODE_LOGIC_MODE_MASK); u32 reg = static_cast(mode == GX_BM_BLEND || mode == GX_BM_SUBTRACT) << GX_BP_BLENDMODE_BLEND_ENABLE_SHIFT | static_cast(mode == GX_BM_LOGIC) << GX_BP_BLENDMODE_LOGIC_OP_ENABLE_SHIFT | static_cast(dstFactor) << GX_BP_BLENDMODE_DST_FACTOR_SHIFT | static_cast(srcFactor) << GX_BP_BLENDMODE_SRC_FACTOR_SHIFT | static_cast(mode == GX_BM_SUBTRACT) << GX_BP_BLENDMODE_SUBTRACT_SHIFT | static_cast(logic) << GX_BP_BLENDMODE_LOGIC_MODE_SHIFT | static_cast(GX_BP_REG_BLENDMODE) << GX_BP_OPCODE_SHIFT; // clang-format on detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 1], reg); } bool ResMatPix::GXGetDstAlpha(GXBool *pEnable, u8 *pAlpha) const { const u8 *pCmd = ref().dl.setDstAlpha; if (pCmd[0] == 0) { return false; } u32 reg; detail::ResReadBPCmd(pCmd, ®); if (pEnable != NULL) { if (reg & GX_BP_DSTALPHA_ENABLE_MASK) { *pEnable = TRUE; } else { *pEnable = FALSE; } } if (pAlpha != NULL) { *pAlpha = reg >> GX_BP_DSTALPHA_ALPHA_SHIFT & GX_BP_DSTALPHA_ALPHA_LMASK; } return true; } void ResMatPix::GXSetDstAlpha(GXBool enable, u8 alpha) { u8 *pCmd = ref().dl.setDstAlpha; u32 reg = alpha << GX_BP_DSTALPHA_ALPHA_SHIFT | enable << GX_BP_DSTALPHA_ENABLE_SHIFT | GX_BP_REG_DSTALPHA << GX_BP_OPCODE_SHIFT; detail::ResWriteBPCmd(pCmd, reg); } /****************************************************************************** * * ResMatTevColor * ******************************************************************************/ bool ResMatTevColor::GXGetTevColor(GXTevRegID id, GXColor *pColor) const { const u8 *pCmd = ref().dl.tevColor[id - 1]; if (pCmd[0] == 0) { return false; } u32 regRA; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 0], ®RA); u32 regBG; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 1], ®BG); *pColor = detail::GetRGBA( regRA >> GX_BP_TEVREGLO_RED_SHIFT & GX_BP_TEVREGLO_RED_LMASK, regBG >> GX_BP_TEVREGLO_ALPHA_SHIFT & GX_BP_TEVREGLO_ALPHA_LMASK, regBG >> GX_BP_TEVREGHI_BLUE_SHIFT & GX_BP_TEVREGHI_BLUE_LMASK, regRA >> GX_BP_TEVREGHI_GREEN_SHIFT & GX_BP_TEVREGHI_GREEN_LMASK ); return true; } void ResMatTevColor::GXSetTevColor(GXTevRegID id, GXColor color) { u8 *pCmd = ref().dl.tevColor[id - 1]; u32 regRA = color.r << GX_BP_TEVREGLO_RED_SHIFT | color.a << GX_BP_TEVREGLO_ALPHA_SHIFT | GX_TEVREG_COLOR << GX_BP_TEVREGLO_TYPE_SHIFT | (id * 2 + GX_BP_REG_TEVREG0LO) << GX_BP_OPCODE_SHIFT; u32 regBG = color.b << GX_BP_TEVREGHI_BLUE_SHIFT | color.g << GX_BP_TEVREGHI_GREEN_SHIFT | GX_TEVREG_COLOR << GX_BP_TEVREGHI_TYPE_SHIFT | (id * 2 + GX_BP_REG_TEVREG0HI) << GX_BP_OPCODE_SHIFT; detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 0], regRA); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 1], regBG); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 2], regBG); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 3], regBG); } bool ResMatTevColor::GXGetTevColorS10(GXTevRegID id, GXColorS10 *pColor) const { const u8 *pCmd = ref().dl.tevColor[id - 1]; if (pCmd[0] == 0) { return false; } u32 regRA; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 0], ®RA); u32 regBG; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 1], ®BG); s16 r = regRA >> GX_BP_TEVREGLO_RED_SHIFT & GX_BP_TEVREGLO_RED_LMASK; s16 g = regBG >> GX_BP_TEVREGHI_GREEN_SHIFT & GX_BP_TEVREGHI_GREEN_LMASK; s16 b = regBG >> GX_BP_TEVREGHI_BLUE_SHIFT & GX_BP_TEVREGHI_BLUE_LMASK; s16 a = regRA >> GX_BP_TEVREGLO_ALPHA_SHIFT & GX_BP_TEVREGLO_ALPHA_LMASK; // clang-format off *pColor = detail::GetRGBAS10( (r << (32 - GX_BP_TEVREGLO_RED_SZ)) >> (32 - GX_BP_TEVREGLO_RED_SZ), (g << (32 - GX_BP_TEVREGHI_GREEN_SZ)) >> (32 - GX_BP_TEVREGHI_GREEN_SZ), (b << (32 - GX_BP_TEVREGHI_BLUE_SZ)) >> (32 - GX_BP_TEVREGHI_BLUE_SZ), (a << (32 - GX_BP_TEVREGLO_ALPHA_SZ)) >> (32 - GX_BP_TEVREGLO_ALPHA_SZ)); // clang-format on return true; } void ResMatTevColor::GXSetTevColorS10(GXTevRegID id, GXColorS10 color) { u8 *pCmd = ref().dl.tevColor[id - 1]; u32 mask = GX_BP_TEVREGLO_RED_LMASK; u32 regRA = (color.r & mask) << GX_BP_TEVREGLO_RED_SHIFT | (color.a & mask) << GX_BP_TEVREGLO_ALPHA_SHIFT | (id * 2 + GX_BP_REG_TEVREG0LO) << GX_BP_OPCODE_SHIFT | GX_TEVREG_COLOR << GX_BP_TEVREGLO_TYPE_SHIFT; u32 regBG = (color.b & mask) << GX_BP_TEVREGHI_BLUE_SHIFT | (color.g & mask) << GX_BP_TEVREGHI_GREEN_SHIFT | (id * 2 + GX_BP_REG_TEVREG0HI) << GX_BP_OPCODE_SHIFT | GX_TEVREG_COLOR << GX_BP_TEVREGHI_TYPE_SHIFT; detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 0], regRA); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 1], regBG); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 2], regBG); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 3], regBG); } bool ResMatTevColor::GXGetTevKColor(GXTevKColorID id, GXColor *pColor) const { const u8 *pCmd = ref().dl.tevKColor[id]; if (pCmd[0] == 0) { return false; } u32 regRA; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 0], ®RA); u32 regBG; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 1], ®BG); *pColor = detail::GetRGBA( regRA >> GX_BP_TEVREGLO_RED_SHIFT & GX_BP_TEVREGLO_RED_LMASK, regBG >> GX_BP_TEVREGLO_ALPHA_SHIFT & GX_BP_TEVREGLO_ALPHA_LMASK, regBG >> GX_BP_TEVREGHI_BLUE_SHIFT & GX_BP_TEVREGHI_BLUE_LMASK, regRA >> GX_BP_TEVREGHI_GREEN_SHIFT & GX_BP_TEVREGHI_GREEN_LMASK ); return true; } void ResMatTevColor::GXSetTevKColor(GXTevKColorID id, GXColor color) { u8 *pCmd = ref().dl.tevKColor[id]; u32 regRA = color.r << GX_BP_TEVREGLO_RED_SHIFT | color.a << GX_BP_TEVREGLO_ALPHA_SHIFT | GX_TEVREG_KONST << GX_BP_TEVREGLO_TYPE_SHIFT | (id * 2 + GX_BP_REG_TEVREG0LO) << GX_BP_OPCODE_SHIFT; u32 regBG = color.b << GX_BP_TEVREGHI_BLUE_SHIFT | color.g << GX_BP_TEVREGHI_GREEN_SHIFT | GX_TEVREG_KONST << GX_BP_TEVREGHI_TYPE_SHIFT | (id * 2 + GX_BP_REG_TEVREG0HI) << GX_BP_OPCODE_SHIFT; detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 0], regRA); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 1], regBG); } /****************************************************************************** * * ResMatIndMtxAndScale * ******************************************************************************/ void ResMatIndMtxAndScale::CallDisplayList(u8 indNum, bool sync) const { if (indNum == 0) { return; } const ResIndMtxAndScaleDL &r = ref(); if (sync) { GXCallDisplayList(const_cast(&r), sizeof(ResIndMtxAndScaleDL)); } else { GXFastCallDisplayList(const_cast(&r), sizeof(ResIndMtxAndScaleDL)); } } bool ResMatIndMtxAndScale::GXGetIndTexMtx(GXIndTexMtxID id, math::MTX34 *pMtx) const { s8 scaleExp; const u8 *pCmd; const ResIndMtxAndScaleDL &r = ref(); switch (id) { case GX_ITM_0: { pCmd = r.dl.indTexMtx0; } break; case GX_ITM_1: { pCmd = r.dl.indTexMtx1; } break; case GX_ITM_2: { pCmd = r.dl.indTexMtx2; } break; default: { return false; } } if (pCmd[0] == 0) { return false; } u32 regA; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 0], ®A); u32 regB; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 1], ®B); u32 regC; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 2], ®C); u32 scaleExpReg = (regA >> GX_BP_INDMTXA_EXP_SHIFT & GX_BP_INDMTXA_EXP_LMASK) << 0 | (regB >> GX_BP_INDMTXB_EXP_SHIFT & GX_BP_INDMTXB_EXP_LMASK) << 2 | (regC >> GX_BP_INDMTXC_EXP_SHIFT & GX_BP_INDMTXC_EXP_LMASK) << 4; // Hardware stores as -17 scaleExp = static_cast(scaleExpReg - 17); // Exponent to value f32 scale = 1.0f; if (scaleExp > 0) { while (scaleExp != 0) { scaleExp--; scale *= 2.0f; } } else if (scaleExp < 0) { while (scaleExp != 0) { scaleExp++; scale /= 2.0f; } } if (pMtx != NULL) { // clang-format off pMtx->_00 = scale * static_cast(static_cast((regA >> GX_BP_INDMTXA_M00_SHIFT & GX_BP_INDMTXA_M00_LMASK) << (32 - GX_BP_INDMTXA_M00_SZ)) >> (32 - GX_BP_INDMTXA_M00_SZ)) * (1.0f / 1024.0f); pMtx->_01 = scale * static_cast(static_cast((regB >> GX_BP_INDMTXB_M01_SHIFT & GX_BP_INDMTXB_M01_LMASK) << (32 - GX_BP_INDMTXB_M01_SZ)) >> (32 - GX_BP_INDMTXB_M01_SZ)) * (1.0f / 1024.0f); pMtx->_02 = scale * static_cast(static_cast((regC >> GX_BP_INDMTXC_M02_SHIFT & GX_BP_INDMTXC_M02_LMASK) << (32 - GX_BP_INDMTXC_M02_SZ)) >> (32 - GX_BP_INDMTXC_M02_SZ)) * (1.0f / 1024.0f); pMtx->_03 = 0.0f; pMtx->_10 = scale * static_cast(static_cast((regA >> GX_BP_INDMTXA_M10_SHIFT & GX_BP_INDMTXA_M10_LMASK) << (32 - GX_BP_INDMTXA_M10_SZ)) >> (32 - GX_BP_INDMTXA_M00_SZ)) * (1.0f / 1024.0f); pMtx->_11 = scale * static_cast(static_cast((regB >> GX_BP_INDMTXB_M11_SHIFT & GX_BP_INDMTXB_M11_LMASK) << (32 - GX_BP_INDMTXB_M11_SZ)) >> (32 - GX_BP_INDMTXB_M11_SZ)) * (1.0f / 1024.0f); pMtx->_12 = scale * static_cast(static_cast((regC >> GX_BP_INDMTXC_M12_SHIFT & GX_BP_INDMTXC_M12_LMASK) << (32 - GX_BP_INDMTXC_M12_SZ)) >> (32 - GX_BP_INDMTXC_M12_SZ)) * (1.0f / 1024.0f); pMtx->_13 = 0.0f; pMtx->_20 = 0.0f; pMtx->_21 = 0.0f; pMtx->_22 = 1.0f; pMtx->_23 = 0.0f; // clang-format on } return true; } bool ResMatIndMtxAndScale::GXGetIndTexMtx(GXIndTexMtxID id, math::MTX34 *pMtx, s8 *pScaleExp) const { s8 scaleExp; const u8 *pCmd; const ResIndMtxAndScaleDL &r = ref(); switch (id) { case GX_ITM_0: { pCmd = r.dl.indTexMtx0; } break; case GX_ITM_1: { pCmd = r.dl.indTexMtx1; } break; case GX_ITM_2: { pCmd = r.dl.indTexMtx2; } break; default: { return false; } } if (pCmd[0] == 0) { return false; } u32 regA; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 0], ®A); u32 regB; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 1], ®B); u32 regC; detail::ResReadBPCmd(&pCmd[GX_BP_CMD_SZ * 2], ®C); u32 scaleExpReg = (regA >> GX_BP_INDMTXA_EXP_SHIFT & GX_BP_INDMTXA_EXP_LMASK) << 0 | (regB >> GX_BP_INDMTXB_EXP_SHIFT & GX_BP_INDMTXB_EXP_LMASK) << 2 | (regC >> GX_BP_INDMTXC_EXP_SHIFT & GX_BP_INDMTXC_EXP_LMASK) << 4; // Hardware stores as -17 if (pScaleExp) { *pScaleExp = static_cast(scaleExpReg - 17); } if (pMtx != NULL) { // clang-format off pMtx->_00 = static_cast(static_cast((regA >> GX_BP_INDMTXA_M00_SHIFT & GX_BP_INDMTXA_M00_LMASK) << (32 - GX_BP_INDMTXA_M00_SZ)) >> (32 - GX_BP_INDMTXA_M00_SZ)) * (1.0f / 1024.0f); pMtx->_01 = static_cast(static_cast((regB >> GX_BP_INDMTXB_M01_SHIFT & GX_BP_INDMTXB_M01_LMASK) << (32 - GX_BP_INDMTXB_M01_SZ)) >> (32 - GX_BP_INDMTXB_M01_SZ)) * (1.0f / 1024.0f); pMtx->_02 = static_cast(static_cast((regC >> GX_BP_INDMTXC_M02_SHIFT & GX_BP_INDMTXC_M02_LMASK) << (32 - GX_BP_INDMTXC_M02_SZ)) >> (32 - GX_BP_INDMTXC_M02_SZ)) * (1.0f / 1024.0f); pMtx->_03 = 0.0f; pMtx->_10 = static_cast(static_cast((regA >> GX_BP_INDMTXA_M10_SHIFT & GX_BP_INDMTXA_M10_LMASK) << (32 - GX_BP_INDMTXA_M10_SZ)) >> (32 - GX_BP_INDMTXA_M00_SZ)) * (1.0f / 1024.0f); pMtx->_11 = static_cast(static_cast((regB >> GX_BP_INDMTXB_M11_SHIFT & GX_BP_INDMTXB_M11_LMASK) << (32 - GX_BP_INDMTXB_M11_SZ)) >> (32 - GX_BP_INDMTXB_M11_SZ)) * (1.0f / 1024.0f); pMtx->_12 = static_cast(static_cast((regC >> GX_BP_INDMTXC_M12_SHIFT & GX_BP_INDMTXC_M12_LMASK) << (32 - GX_BP_INDMTXC_M12_SZ)) >> (32 - GX_BP_INDMTXC_M12_SZ)) * (1.0f / 1024.0f); pMtx->_13 = 0.0f; pMtx->_20 = 0.0f; pMtx->_21 = 0.0f; pMtx->_22 = 1.0f; pMtx->_23 = 0.0f; // clang-format on } return true; } void ResMatIndMtxAndScale::GXSetIndTexMtx(GXIndTexMtxID id, const math::MTX34 &rMtx, s8 scaleExp) { u32 offset; u8 *pCmd; ResIndMtxAndScaleDL &r = ref(); switch (id) { case GX_ITM_0: { pCmd = r.dl.indTexMtx0; offset = GX_BP_REG_INDMTX0A - GX_BP_REG_INDMTX0A; break; } case GX_ITM_1: { pCmd = r.dl.indTexMtx1; offset = GX_BP_REG_INDMTX1A - GX_BP_REG_INDMTX0A; break; } case GX_ITM_2: { pCmd = r.dl.indTexMtx2; offset = GX_BP_REG_INDMTX2A - GX_BP_REG_INDMTX0A; break; } default: { return; } } // Hardware stores as -17 scaleExp += static_cast(17); // clang-format off detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 0], static_cast((static_cast(1024.0f * rMtx._00) & GX_BP_INDMTXA_M00_LMASK) << GX_BP_INDMTXA_M00_SHIFT) | static_cast((static_cast(1024.0f * rMtx._10) & GX_BP_INDMTXA_M10_LMASK) << GX_BP_INDMTXA_M10_SHIFT) | static_cast((scaleExp >> 0 & GX_BP_INDMTXA_EXP_LMASK) << GX_BP_INDMTXA_EXP_SHIFT) | static_cast(offset + GX_BP_REG_INDMTX0A << GX_BP_OPCODE_SHIFT)); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 1], static_cast((static_cast(1024.0f * rMtx._01) & GX_BP_INDMTXB_M01_LMASK) << GX_BP_INDMTXB_M01_SHIFT) | static_cast((static_cast(1024.0f * rMtx._11) & GX_BP_INDMTXB_M11_LMASK) << GX_BP_INDMTXB_M11_SHIFT) | static_cast((scaleExp >> 2 & GX_BP_INDMTXB_EXP_LMASK) << GX_BP_INDMTXB_EXP_SHIFT) | static_cast((offset + GX_BP_REG_INDMTX0B << GX_BP_OPCODE_SHIFT))); detail::ResWriteBPCmd(&pCmd[GX_BP_CMD_SZ * 2], static_cast((static_cast(1024.0f * rMtx._02) & GX_BP_INDMTXC_M02_LMASK) << GX_BP_INDMTXC_M02_SHIFT) | static_cast((static_cast(1024.0f * rMtx._12) & GX_BP_INDMTXC_M12_LMASK) << GX_BP_INDMTXC_M12_SHIFT) | static_cast((scaleExp >> 4 & GX_BP_INDMTXC_EXP_LMASK) << GX_BP_INDMTXC_EXP_SHIFT) | static_cast(offset + GX_BP_REG_INDMTX0C << GX_BP_OPCODE_SHIFT)); // clang-format on } /****************************************************************************** * * ResMatChan * ******************************************************************************/ void ResMatChan::GXSetChanMatColor(GXChannelID id, GXColor color) { GXColor &rMatColor = ref().chan[id & 1].matColor; if ((id & 2) == 0) { rMatColor.r = color.r; rMatColor.g = color.g; rMatColor.b = color.b; if (id == GX_COLOR0A0 || id == GX_COLOR1A1) { rMatColor.a = color.a; } } else { rMatColor.a = color.a; } } void ResMatChan::GXSetChanAmbColor(GXChannelID id, GXColor color) { GXColor &rAmbColor = ref().chan[id & 1].ambColor; if ((id & 2) == 0) { rAmbColor.r = color.r; rAmbColor.g = color.g; rAmbColor.b = color.b; if (id == GX_COLOR0A0 || id == GX_COLOR1A1) { rAmbColor.a = color.a; } } else { rAmbColor.a = color.a; } } void ResMatChan::GXSetChanCtrl( GXChannelID id, GXBool enable, GXColorSrc ambSrc, GXColorSrc matSrc, GXLightID lightMask, GXDiffuseFn diffuseFn, GXAttnFn attnFn ) { Chan &rChan = ref().chan[id & 1]; u32 *pCtrl; if ((id & 2) == 0) { pCtrl = &rChan.paramChanCtrlC; } else { pCtrl = &rChan.paramChanCtrlA; } // clang-format off u32 mask = (matSrc) << GX_XF_COLOR0CNTRL_MATSRC_SHIFT | (enable) << GX_XF_COLOR0CNTRL_LIGHT_SHIFT | (lightMask & 0b1111) << GX_XF_COLOR0CNTRL_LMASKLO_SHIFT | (ambSrc) << GX_XF_COLOR0CNTRL_AMBSRC_SHIFT | (attnFn == GX_AF_SPEC ? GX_DF_NONE : diffuseFn) << GX_XF_COLOR0CNTRL_DIFFUSEATTN_SHIFT | (attnFn != GX_AF_NONE) << GX_XF_COLOR0CNTRL_ATTNENABLE_SHIFT | (attnFn != GX_AF_SPEC) << GX_XF_COLOR0CNTRL_ATTNSELECT_SHIFT | ((lightMask >> 4) & 0b1111) << GX_XF_COLOR0CNTRL_LMASKHI_SHIFT; // clang-format on *pCtrl = mask; if (id == GX_COLOR0A0 || id == GX_COLOR1A1) { rChan.paramChanCtrlA = mask; } } bool ResMatChan::GXGetChanMatColor(GXChannelID id, GXColor *pColor) const { *pColor = ref().chan[id & 1].matColor; return true; } bool ResMatChan::GXGetChanAmbColor(GXChannelID id, GXColor *pColor) const { *pColor = ref().chan[id & 1].ambColor; return true; } bool ResMatChan::GXGetChanCtrl( GXChannelID id, GXBool *pEnable, GXColorSrc *pAmbSrc, GXColorSrc *pMatSrc, GXLightID *pLightMask, GXDiffuseFn *pDiffuseFn, GXAttnFn *pAttnFn ) const { const Chan &rChan = ref().chan[id & 1]; u32 ctrl; if ((id & 2) == 0) { ctrl = rChan.paramChanCtrlC; } else { ctrl = rChan.paramChanCtrlA; } if (pEnable != NULL) { *pEnable = ctrl >> GX_XF_COLOR0CNTRL_LIGHT_SHIFT & GX_XF_COLOR0CNTRL_LIGHT_LMASK; } if (pAmbSrc != NULL) { *pAmbSrc = static_cast(ctrl >> GX_XF_COLOR0CNTRL_AMBSRC_SHIFT & GX_XF_COLOR0CNTRL_AMBSRC_LMASK); } if (pMatSrc != NULL) { *pMatSrc = static_cast(ctrl >> GX_XF_COLOR0CNTRL_MATSRC_SHIFT & GX_XF_COLOR0CNTRL_MATSRC_LMASK); } u32 lightMaskLo = ctrl >> GX_XF_COLOR0CNTRL_LMASKLO_SHIFT & GX_XF_COLOR0CNTRL_LMASKLO_LMASK; u32 lightMaskHi = ctrl >> GX_XF_COLOR0CNTRL_LMASKHI_SHIFT & GX_XF_COLOR0CNTRL_LMASKHI_LMASK; if (pLightMask != NULL) { *pLightMask = static_cast(lightMaskLo | lightMaskHi << 4); } GXDiffuseFn diff; GXAttnFn attn; if (!(ctrl >> GX_XF_COLOR0CNTRL_ATTNSELECT_SHIFT & GX_XF_COLOR0CNTRL_ATTNSELECT_LMASK)) { attn = GX_AF_SPEC; diff = GX_DF_NONE; } else if (!(ctrl >> GX_XF_COLOR0CNTRL_ATTNENABLE_SHIFT & GX_XF_COLOR0CNTRL_ATTNENABLE_LMASK)) { attn = GX_AF_NONE; diff = static_cast(ctrl >> GX_XF_COLOR0CNTRL_DIFFUSEATTN_SHIFT & GX_XF_COLOR0CNTRL_DIFFUSEATTN_LMASK); } else { attn = GX_AF_SPOT; diff = static_cast(ctrl >> GX_XF_COLOR0CNTRL_DIFFUSEATTN_SHIFT & GX_XF_COLOR0CNTRL_DIFFUSEATTN_LMASK); } if (pDiffuseFn != NULL) { *pDiffuseFn = diff; } if (pAttnFn != NULL) { *pAttnFn = attn; } return true; } ResMatChan ResMatChan::CopyTo(void *pDst) const { ResChanData *pData = static_cast(pDst); const ResChanData &r = ref(); *pData = r; return ResMatChan(pData); } /****************************************************************************** * * ResMatTexCoordGen * ******************************************************************************/ void ResMatTexCoordGen::CallDisplayList(u8 numGens, bool sync) const { if (numGens == 0) { return; } const ResTexCoordGenDL &r = ref(); if (sync) { if (numGens < 2) { GXCallDisplayList(const_cast(&r), 32); } else if (numGens < 4) { GXCallDisplayList(const_cast(&r), 64); } else if (numGens < 8) { GXCallDisplayList(const_cast(&r), 128); } else { GXCallDisplayList(const_cast(&r), sizeof(ResTexCoordGenDL)); } } else { if (numGens < 2) { GXFastCallDisplayList(const_cast(&r), 32); } else if (numGens < 4) { GXFastCallDisplayList(const_cast(&r), 64); } else if (numGens < 8) { GXFastCallDisplayList(const_cast(&r), 128); } else { GXFastCallDisplayList(const_cast(&r), sizeof(ResTexCoordGenDL)); } } } bool ResMatTexCoordGen::GXGetTexCoordGen2( GXTexCoordID id, GXTexGenType *pFunc, GXTexGenSrc *pParam, GXBool *pNormalize, u32 *pPostMtx ) const { const u8 *pCmd = ref().dl.texCoordGen[id]; if (pCmd[0] == 0) { return false; } u32 regTex; detail::ResReadXFCmd(&pCmd[GX_XF_CMD_SZ * 0], ®Tex); u32 regDualTex; detail::ResReadXFCmd(&pCmd[GX_XF_CMD_SZ * 1], ®DualTex); if (pNormalize != NULL) { *pNormalize = regDualTex >> GX_XF_DUALTEX_NORMALIZE_SHIFT & GX_XF_DUALTEX_NORMALIZE_LMASK; } if (pPostMtx != NULL) { // @note BASEROW is actually only six bits *pPostMtx = (regDualTex >> GX_XF_DUALTEX_BASEROW_SHIFT & 0xFF) + GX_DUALMTX0; } u32 row; u32 tgType; tgType = regTex >> GX_XF_TEX_TEXGENTYPE_SHIFT & GX_XF_TEX_TEXGENTYPE_LMASK; row = regTex >> GX_XF_TEX_SRCROW_SHIFT & GX_XF_TEX_SRCROW_LMASK; if (tgType == GX_XF_TG_REGULAR) { // clang-format off GXTexGenType type = static_cast( (regTex >> GX_XF_TEX_PROJTYPE_SHIFT & GX_XF_TEX_PROJTYPE_LMASK) ^ 1); // clang-format on GXTexGenSrc param; switch (row) { case 0: { param = GX_TG_POS; break; } case 1: { param = GX_TG_NRM; break; } case 3: { param = GX_TG_BINRM; break; } case 4: { param = GX_TG_TANGENT; break; } case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: { param = static_cast(row - 1); break; } case 2: default: { return false; } } if (pFunc != NULL) { *pFunc = type; } if (pParam != NULL) { *pParam = param; } return true; } else if (row == 2) { if (pFunc != NULL) { *pFunc = GX_TG_SRTG; } if (pParam != NULL) { *pParam = tgType == GX_XF_TG_CLR0 ? GX_TG_COLOR0 : GX_TG_COLOR1; } return true; } else if (tgType == GX_XF_TG_BUMP) { if (pFunc != NULL) { // @note Assumes BUMPSRCLIGHT is the leftmost field *pFunc = static_cast((regTex >> GX_XF_TEX_BUMPSRCLIGHT_SHIFT) + GX_TG_BUMP0); } if (pParam != NULL) { *pParam = static_cast( (regTex >> GX_XF_TEX_BUMPSRCTEX_SHIFT & GX_XF_TEX_BUMPSRCTEX_LMASK) + GX_TG_TEXCOORD0 ); } return true; } else { return false; } return false; } void ResMatTexCoordGen::GXSetTexCoordGen2( GXTexCoordID id, GXTexGenType func, GXTexGenSrc param, GXBool normalize, u32 postMtx ) { u8 *pCmd = ref().dl.texCoordGen[id]; u32 form = GX_XF_TEX_FORM_AB11; u32 tgType; u32 proj = GX_XF_TEX_PROJ_ST; u32 row = 5; u32 embossRow = 5; u32 embossLit = 0; switch (param) { case GX_TG_POS: { row = 0; form = GX_XF_TEX_FORM_ABC1; break; } case GX_TG_NRM: { row = 1; form = GX_XF_TEX_FORM_ABC1; break; } case GX_TG_BINRM: { row = 3; form = GX_XF_TEX_FORM_ABC1; break; } case GX_TG_TANGENT: { row = 4; form = GX_XF_TEX_FORM_ABC1; break; } case GX_TG_COLOR0: { row = 2; break; } case GX_TG_COLOR1: { row = 2; break; } case GX_TG_TEX0: { row = 5; break; } case GX_TG_TEX1: { row = 6; break; } case GX_TG_TEX2: { row = 7; break; } case GX_TG_TEX3: { row = 8; break; } case GX_TG_TEX4: { row = 9; break; } case GX_TG_TEX5: { row = 10; break; } case GX_TG_TEX6: { row = 11; break; } case GX_TG_TEX7: { row = 12; break; } case GX_TG_TEXCOORD0: { embossRow = 0; break; } case GX_TG_TEXCOORD1: { embossRow = 1; break; } case GX_TG_TEXCOORD2: { embossRow = 2; break; } case GX_TG_TEXCOORD3: { embossRow = 3; break; } case GX_TG_TEXCOORD4: { embossRow = 4; break; } case GX_TG_TEXCOORD5: { embossRow = 5; break; } case GX_TG_TEXCOORD6: { embossRow = 6; break; } default: { break; } } switch (func) { case GX_TG_MTX2x4: { tgType = GX_XF_TG_REGULAR; break; } case GX_TG_MTX3x4: { tgType = GX_XF_TG_REGULAR; proj = GX_XF_TEX_PROJ_STQ; break; } case GX_TG_BUMP0: case GX_TG_BUMP1: case GX_TG_BUMP2: case GX_TG_BUMP3: case GX_TG_BUMP4: case GX_TG_BUMP5: case GX_TG_BUMP6: case GX_TG_BUMP7: { tgType = GX_XF_TG_BUMP; embossLit = func - GX_TG_BUMP0; break; } case GX_TG_SRTG: { if (param == GX_TG_COLOR0) { tgType = GX_XF_TG_CLR0; } else /* GX_TG_COLOR1 */ { tgType = GX_XF_TG_CLR1; } break; } default: { return; } } // clang-format off detail::ResWriteXFCmd(&pCmd[GX_XF_CMD_SZ * 0], id + GX_XF_REG_TEX0, proj << GX_XF_TEX_PROJTYPE_SHIFT | form << GX_XF_TEX_INPUTFORM_SHIFT | tgType << GX_XF_TEX_TEXGENTYPE_SHIFT | row << GX_XF_TEX_SRCROW_SHIFT | embossRow << GX_XF_TEX_BUMPSRCTEX_SHIFT | embossLit << GX_XF_TEX_BUMPSRCLIGHT_SHIFT); detail::ResWriteXFCmd(&pCmd[GX_XF_CMD_SZ * 1], id + GX_XF_REG_DUALTEX0, postMtx - GX_DUALMTX0 << GX_XF_DUALTEX_BASEROW_SHIFT | normalize << GX_XF_DUALTEX_NORMALIZE_SHIFT); // clang-format on } void ResMatTexCoordGen::Disable(GXTexCoordID coord) { std::memset(ref().dl.texCoordGen[coord], 0, GX_XF_CMD_SZ * 2); } /****************************************************************************** * * ResMat * ******************************************************************************/ bool ResMat::Bind(const ResFile file) { u32 i; u32 bindNum = 0; u32 texPlttInfoNum = GetNumResTexPlttInfo(); for (i = 0; i < texPlttInfoNum; i++) { if (GetResTexPlttInfo(i).Bind(file, GetResTexObj(), GetResTlutObj())) { bindNum++; } } return bindNum == texPlttInfoNum; } void ResMat::Release() { u32 i; u32 texPlttInfoNum = GetNumResTexPlttInfo(); for (i = 0; i < texPlttInfoNum; i++) { GetResTexPlttInfo(i).Release(GetResTexObj(), GetResTlutObj()); } } void ResMat::Init() { DC::StoreRangeNoSync(GetResMatDLData(), sizeof(ResMatDLData)); } bool ResMat::IsOpaque() const { return GetParent().IsOpaque(GetID()); } ResTev ResMat::GetResTev() { return ofs_to_obj(ref().toResTevData); } ResTev ResMat::GetResTev() const { return ofs_to_obj(ref().toResTevData); } ResMatFur ResMat::GetResMatFur() { return ofs_to_obj(ref().toResMatFurData); } ResUserData ResMat::GetResUserData() { return ofs_to_obj(ref().toResUserData); } /****************************************************************************** * * ResTexPlttInfo * ******************************************************************************/ void ResTexPlttInfo::BindTex_(const ResTex tex, ResTexObj texObj) { ResTexPlttInfoData &r = ref(); r.pTexData = const_cast(&tex.ref()); void *pTexData; u16 width, height; f32 minLod, maxLod; GXBool mipmap; GXTexObj *pGXObj = texObj.GetTexObj(r.mapID); if (IsCIFmt()) { GXCITexFmt fmtCi; tex.GetTexObjCIParam(&pTexData, &width, &height, &fmtCi, &minLod, &maxLod, &mipmap); GXInitTexObjCI(pGXObj, pTexData, width, height, fmtCi, r.wrap_s, r.wrap_t, mipmap, r.tlutID); } else { GXTexFmt fmt; tex.GetTexObjParam(&pTexData, &width, &height, &fmt, &minLod, &maxLod, &mipmap); GXInitTexObj(pGXObj, pTexData, width, height, fmt, r.wrap_s, r.wrap_t, mipmap); } GXInitTexObjLOD( pGXObj, r.min_filt, r.mag_filt, minLod, maxLod, r.lod_bias, r.bias_clamp, r.do_edge_lod, r.max_aniso ); texObj.Validate(r.mapID); } void ResTexPlttInfo::BindPltt_(const ResPltt pltt, ResTlutObj tlutObj) { ResTexPlttInfoData &r = ref(); r.pPlttData = const_cast(&pltt.ref()); // @bug Shouldn't this be the TLUT id? GXTlutObj *pGXObj = tlutObj.GetTlut(static_cast(r.mapID)); GXInitTlutObj(pGXObj, const_cast(pltt.GetPlttData()), pltt.GetFmt(), pltt.GetNumEntries()); // @bug Shouldn't this be the TLUT id? tlutObj.Validate(static_cast(r.mapID)); } bool ResTexPlttInfo::Bind(const ResFile file, ResTexObj texObj, ResTlutObj tlutObj) { bool success = true; ResName texName = GetTexResName(); if (ref().pTexData == NULL) { ResTex tex = file.GetResTex(texName); if (tex.IsValid() && (!IsCIFmt() || tex.IsCIFmt())) { BindTex_(tex, texObj); } else { success = false; } } if (ref().pPlttData == NULL) { ResName plttName = GetPlttResName(); if (plttName.IsValid()) { ResPltt pltt = file.GetResPltt(plttName); if (pltt.IsValid()) { BindPltt_(pltt, tlutObj); } else { success = false; } } } return success; } void ResTexPlttInfo::Release(ResTexObj texObj, ResTlutObj tlutObj) { ResTexPlttInfoData &r = ref(); r.pTexData = NULL; r.pPlttData = NULL; texObj.Invalidate(r.mapID); // @bug Shouldn't this be the TLUT id? tlutObj.Invalidate(static_cast(r.mapID)); } } // namespace g3d } // namespace nw4r