#include "egg/gfx/eggG3DUtility.h" #include "common.h" #include "egg/core/eggHeap.h" #include "nw4r/g3d/g3d_light.h" #include "nw4r/g3d/g3d_state.h" #include "nw4r/g3d/res/g3d_resanmamblight.h" #include "nw4r/g3d/res/g3d_resanmlight.h" #include "nw4r/g3d/res/g3d_resanmscn.h" #include "nw4r/g3d/res/g3d_reslightset.h" #include "nw4r/g3d/res/g3d_resmat.h" #include "nw4r/g3d/res/g3d_resnode.h" #include "nw4r/g3d/res/g3d_restev.h" #include "nw4r/math/math_types.h" #include "rvl/GX/GXTexture.h" #include "rvl/GX/GXTypes.h" #include "rvl/MTX/mtx.h" #include namespace EGG { void G3DUtility::create(u32 size, Heap *pHeap) { if (pHeap == nullptr) { pHeap = Heap::getCurrentHeap(); } if (size != 0) { sBuf = operator new[](size, pHeap, 0x20); sSize = size; } else { sBuf = nullptr; sSize = 0; } sOffset = 0; nw4r::g3d::G3DState::ScnDependentTexMtxFuncPtr pFunc; u32 id = 5; while (true) { if (nw4r::g3d::G3DState::GetScnDependentTexMtxFunc(id, &pFunc, nullptr) && pFunc == defaultTexMtxFunc) { break; } id++; if (id >= 256) { id = 5; nw4r::g3d::G3DState::ScnDependentTexMtxFuncPtr pFunc2; while (true) { if (nw4r::g3d::G3DState::GetScnDependentTexMtxFunc(id, &pFunc2, nullptr) && pFunc2 == nw4r::g3d::detail::ScnDependentMtxFunc::DefaultMapping) { sId = id; nw4r::g3d::G3DState::SetScnDependentTexMtxFunc( id, defaultTexMtxFunc, nw4r::g3d::G3DState::SCNDEPENDENT_TEXMTX_FUNCTYPE_SRC_POS ); break; } id++; if (id >= 256) { break; } } return; } } } void G3DUtility::defaultTexMtxFunc(nw4r::math::MTX34 *pMtx, s8 camRef, s8 lightRef) { const nw4r::math::MTX34 *mtxPtr = nw4r::g3d::G3DState::GetInvCameraMtxPtr(); MTXCopy(mtxPtr->m, pMtx->m); } bool G3DUtility::setUpLightSet(nw4r::g3d::LightSetting &lightSet, nw4r::g3d::ResAnmScn scn, int refNumber) { if (!scn.IsValid()) { return false; } int end = scn.GetResLightSetMaxRefNumber() < lightSet.GetNumLightSet() ? scn.GetResLightSetMaxRefNumber() : lightSet.GetNumLightSet(); int start = 0; if (refNumber >= 0) { start = refNumber; end = refNumber + 1; } for (; start < end; start++) { nw4r::g3d::LightSet set = lightSet.GetLightSet(start); nw4r::g3d::ResLightSet resSet = scn.GetResLightSetByRefNumber(start); if (!set.IsValid()) { return false; } if (resSet.IsValid()) { u32 counter = 7; u32 j = 0; u32 numLight = resSet.GetNumLight(); if (numLight != 0) { for (; j < numLight; j++) { if (resSet.GetLightID(j) != 0xFFFF) { nw4r::g3d::ResAnmLight anmLight = scn.GetResAnmLight(resSet.GetLightID(j)); set.SelectLightObj(j, anmLight.GetRefNumber()); if (anmLight.HasSpecularLight()) { set.SelectLightObj(counter--, anmLight.GetSpecularLightIdx()); } } else { set.SelectLightObj(j, -1); } } } for (; numLight <= counter; numLight++) { set.SelectLightObj(numLight, -1); } if (resSet.HasAmbLight()) { nw4r::g3d::ResAnmAmbLight anmAmbLight = scn.GetResAnmAmbLight(resSet.GetAmbLightID()); set.SelectAmbLightObj(anmAmbLight.GetRefNumber()); } else { set.SelectAmbLightObj(-1); } } } return true; } inline bool searchInner( const char *name, const char *candidate, bool exactMatch, G3DUtility::SearchResult *pResults, int i, int resultIdx, int maxNumResults ) { if (name != nullptr) { bool found; if (exactMatch) { found = !std::strcmp(candidate, name); } else { found = std::strstr(candidate, name); } if (!found) { goto err; } } if (resultIdx < maxNumResults) { pResults[resultIdx].nodeIdx = i; pResults[resultIdx].name = candidate; } return true; err: return false; } int G3DUtility::searchStringResNode( nw4r::g3d::ResMdl mdl, const char *name, bool exactMatch, SearchResult *pResults, int maxNumResults ) { u16 resultIdx = 0; for (int i = 0; i < mdl.GetResNodeNumEntries(); i++) { nw4r::g3d::ResNode nd = mdl.GetResNode(i); const char *nodeName = nd.GetName(); if (searchInner(name, nodeName, exactMatch, pResults, i, resultIdx, maxNumResults)) { resultIdx++; } } return resultIdx; } int G3DUtility::searchStringResMat( nw4r::g3d::ResMdl mdl, const char *name, bool exactMatch, SearchResult *pResults, int maxNumResults ) { u16 resultIdx = 0; for (int i = 0; i < mdl.GetResMatNumEntries(); i++) { nw4r::g3d::ResMat mat = mdl.GetResMat(i); const char *nodeName = mat.GetName(); if (searchInner(name, nodeName, exactMatch, pResults, i, resultIdx, maxNumResults)) { resultIdx++; } } return resultIdx; } int G3DUtility::searchStringResTexPlttInfo( nw4r::g3d::ResMdl mdl, const char *name, bool exactMatch, SearchResult *pResults, int maxNumResults ) { u16 resultIdx = 0; for (u32 i = 0; i < mdl.GetResTexPlttInfoOffsetFromTexNameNumEntries(); i++) { nw4r::g3d::ResTexPlttInfoOffset info = mdl.GetResTexPlttInfoOffsetFromTexName(i); for (u16 j = 0; j < info.GetNumData(); j++) { const char *nodeName = info.GetPllt(j).GetTexName(); if (searchInner(name, nodeName, exactMatch, pResults, i, resultIdx, maxNumResults)) { resultIdx++; } } } return resultIdx; } u16 G3DUtility::SetTexture( nw4r::g3d::ResMat resMat, nw4r::g3d::ScnMdl::CopiedMatAccess *matAccess, const char *name, const GXTexObj *texObj, bool copy, SetTextureResult *pResult, int maxNumResults, int param_8 ) { if (!resMat.IsValid()) { return 0; } u16 resultIdx = 0; for (u16 i = 0; i < resMat.GetNumResTexPlttInfo(); i++) { nw4r::g3d::ResTexPlttInfo plltInfo = resMat.GetResTexPlttInfo(i); const char *plltName = plltInfo.GetTexName(); if (std::strcmp(name, plltName)) { continue; } for (int j = 0; j < 2; j++) { nw4r::g3d::ResTexObj resTexObj(nullptr); if (j == 0) { if ((matAccess == nullptr || param_8 == 1) || (param_8 == 0 && !matAccess->GetResTexObj(false).IsValid())) { resTexObj = resMat.GetResTexObj(); } } else if (matAccess != nullptr) { resTexObj = param_8 == 0 ? matAccess->GetResTexObjEx() : matAccess->GetResTexObj(param_8 == 3); } if (resTexObj.IsValid()) { GXTexObj *obj = resTexObj.GetTexObj(plltInfo.ref().mapID); if (copy) { void *pImage; u16 width; u16 height; GXTexFmt format; GXTexWrapMode wrapS; GXTexWrapMode wrapT; u8 mipmap; GXGetTexObjAll(obj, &pImage, &width, &height, &format, &wrapS, &wrapT, &mipmap); GXTexFilter minFilter; GXTexFilter magFilter; f32 minLOD; f32 maxLOD; f32 LODBias; u8 biasClampEnable; u8 edgeLODEnable; GXAnisotropy anisotropy; GXGetTexObjLODAll( obj, &minFilter, &magFilter, &minLOD, &maxLOD, &LODBias, &biasClampEnable, &edgeLODEnable, &anisotropy ); *obj = *texObj; GXInitTexObjFilter(obj, minFilter, magFilter); GXInitTexObjWrapMode(obj, wrapS, wrapT); } else { *obj = *texObj; } } } if (pResult != nullptr && resultIdx < maxNumResults) { pResult[resultIdx].texCoordId = -1; pResult[resultIdx].texMapId = -1; nw4r::g3d::ResTev resTev = resMat.GetResTev(); for (u8 stage = 0; stage < resTev.GetNumTevStages(); stage++) { GXTexCoordID coord; GXTexMapID map; if (resTev.GXGetTevOrder(static_cast(stage), &coord, &map, nullptr) && map == plltInfo.ref().mapID) { pResult[resultIdx].texMapId = map; pResult[resultIdx].texCoordId = coord; } } } resultIdx++; } return resultIdx; } int G3DUtility::ApplyLightMat(nw4r::g3d::ResMdl mdl, const char *prefix) { GXTexCoordID matchingLayerCoords[8]; int prefixLen = std::strlen(prefix); int result = 0; u32 i = 0; u32 numMats = mdl.GetResMatNumEntries(); if (numMats != 0) { for (; i < numMats; i++) { int numMatchingLayers = 0; nw4r::g3d::ResMat mat = mdl.GetResMat(i); if (mat.GetResGenMode().GXGetNumTexGens() >= mat.GetNumResTexPlttInfo()) { for (u32 j = 0; j < mat.GetNumResTexPlttInfo(); j++) { const char *texName = mat.GetResTexPlttInfo(j).GetTexName(); bool prefixMatch = true; int rem = prefixLen; for (int i = 0; i < prefixLen; i++) { if (prefix[i] != texName[i]) { prefixMatch = false; break; } } if (prefixMatch) { matchingLayerCoords[numMatchingLayers++] = static_cast(j); } } if (numMatchingLayers > 1) { nw4r::g3d::ResGenMode genMode = mat.GetResGenMode(); int numTexGens = genMode.GXGetNumTexGens(); nw4r::g3d::ResMatTexCoordGen resMatTexCoordGen = mat.GetResMatTexCoordGen(); nw4r::g3d::ResTexSrt resTexSrt = mat.GetResTexSrt(); nw4r::g3d::ResTev resTev = mat.GetResTev(); GXTexGenType texGenType; GXTexGenSrc param; GXBool normalize; u32 postMtx; resMatTexCoordGen.GXGetTexCoordGen2( matchingLayerCoords[0], &texGenType, ¶m, &normalize, &postMtx ); numMatchingLayers--; for (; numMatchingLayers > 0; numMatchingLayers--) { GXTexCoordID idx = matchingLayerCoords[numMatchingLayers]; if (idx == numTexGens - 1) { u32 numStages = resTev.GetNumTevStages(); for (u32 stage = 0; stage < numStages; stage++) { GXTexCoordID coord; GXTexMapID map; GXChannelID channel; if (resTev.GXGetTevOrder(static_cast(stage), &coord, &map, &channel) && coord == idx) { resTev.GXSetTevOrder( static_cast(stage), matchingLayerCoords[0], map, channel ); } } int stage = 0; int nInds = genMode.GXGetNumIndStages(); for (; stage < nInds; stage++) { GXTexCoordID coord; GXTexMapID map; if (resTev.GXGetIndTexOrder(static_cast(stage), &coord, &map) && coord == idx) { resTev.GXSetIndTexOrder( static_cast(stage), static_cast(matchingLayerCoords[0]), map ); } } resMatTexCoordGen.Disable(idx); result++; resTexSrt.Disable(idx); numTexGens--; } } resMatTexCoordGen.DCStore(false); resTev.DCStore(false); genMode.GXSetNumTexGens(numTexGens); } } } } return result; } void *G3DUtility::BumpAlloc(u32 size, u32 align) { u32 next = sOffset % align != 0 ? sOffset + (align - sOffset % align) : sOffset; sOffset = next + size; // REGSWAP return reinterpret_cast(sBuf) + next; } } // namespace EGG