#include "CCubeModel.hpp" #include "CSimplePool.hpp" #include "Graphics/CCubeMaterial.hpp" #include "Graphics/CCubeSurface.hpp" #include "Graphics/CGraphics.hpp" #include "Graphics/CModel.hpp" #include "Graphics/CGX.hpp" namespace metaforce { bool CCubeModel::sRenderModelBlack = false; bool CCubeModel::sRenderModelShadow = false; bool CCubeModel::sUsingPackedLightmaps = false; const CTexture* CCubeModel::sShadowTexture = nullptr; zeus::CTransform CCubeModel::sTextureProjectionTransform; GX::LightMask CCubeModel::sChannel0DisableLightMask; GX::LightMask CCubeModel::sChannel1EnableLightMask; static bool sDrawingOccluders = false; static bool sDrawingWireframe = false; static zeus::CVector3f sPlayerPosition; CCubeModel::CCubeModel(std::vector* surfaces, std::vector>* textures, u8* materialData, std::vector* positions, std::vector* colors, std::vector* normals, std::vector>* texCoords, std::vector>* packedTexCoords, const zeus::CAABox& aabb, u8 flags, bool b1, u32 idx) : x0_modelInstance(surfaces, materialData, positions, colors, normals, texCoords, packedTexCoords) , x1c_textures(textures) , x20_worldAABB(aabb) , x40_24_texturesLoaded(!b1) , x41_visorFlags(flags) , x44_idx(idx) { for (auto& surf : *x0_modelInstance.Surfaces()) { surf.SetParent(this); } for (u32 i = x0_modelInstance.Surfaces()->size(); i > 0; --i) { auto& surf = (*x0_modelInstance.Surfaces())[i - 1]; const auto matFlags = GetMaterialByIndex(surf.GetMaterialIndex()).GetFlags(); if (!matFlags.IsSet(CCubeMaterialFlagBits::fDepthSorting)) { surf.SetNextSurface(x38_firstUnsortedSurf); x38_firstUnsortedSurf = &surf; } else { surf.SetNextSurface(x3c_firstSortedSurf); x3c_firstSortedSurf = &surf; } } } CCubeMaterial CCubeModel::GetMaterialByIndex(u32 idx) { u32 materialOffset = 0; const u8* matData = x0_modelInstance.GetMaterialPointer(); matData += (x1c_textures->size() + 1) * 4; if (idx != 0) { materialOffset = SBig(*reinterpret_cast(matData + (idx * 4))); } u32 materialCount = SBig(*reinterpret_cast(matData)); return CCubeMaterial(matData + materialOffset + (materialCount * 4) + 4); } bool CCubeModel::TryLockTextures() { if (!x40_24_texturesLoaded) { bool texturesLoading = false; for (auto& texture : *x1c_textures) { texture.Lock(); bool loadTexture = true; if (!texture.HasReference()) { if (!texture.IsLocked() || texture.IsNull()) { loadTexture = false; } else { texture.GetObj(); } } if (loadTexture) { // if (!texture->LoadToMRAM()) { // texturesLoading = true; // } } } if (!texturesLoading) { x40_24_texturesLoaded = true; } } return x40_24_texturesLoaded; } void CCubeModel::UnlockTextures() { for (auto& token : *x1c_textures) { token.Unlock(); } } void CCubeModel::RemapMaterialData(u8* data, std::vector>& textures) { x0_modelInstance.SetMaterialPointer(data); x1c_textures = &textures; x40_24_texturesLoaded = false; } void CCubeModel::MakeTexturesFromMats(const u8* ptr, std::vector>& textures, IObjectStore* store, bool b1) { const u32* curId = reinterpret_cast(ptr + 4); u32 textureCount = SBig(*reinterpret_cast(ptr)); textures.reserve(textureCount); for (u32 i = 0; i < textureCount; ++i) { textures.emplace_back(store->GetObj({FOURCC('TXTR'), SBig(curId[i])})); if (!b1 && textures.back().IsNull()) { textures.back().GetObj(); } } } void CCubeModel::Draw(const CModelFlags& flags) { CCubeMaterial::KillCachedViewDepState(); SetArraysCurrent(); DrawSurfaces(flags); } void CCubeModel::Draw(TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) { CCubeMaterial::KillCachedViewDepState(); SetSkinningArraysCurrent(positions, normals); DrawSurfaces(flags); } void CCubeModel::DrawAlpha(const CModelFlags& flags) { CCubeMaterial::KillCachedViewDepState(); SetArraysCurrent(); DrawAlphaSurfaces(flags); } void CCubeModel::DrawAlphaSurfaces(const CModelFlags& flags) { if (sDrawingWireframe) { const auto* surface = x3c_firstSortedSurf; while (surface != nullptr) { DrawSurfaceWireframe(*surface); surface = surface->GetNextSurface(); } } else if (TryLockTextures()) { const auto* surface = x3c_firstSortedSurf; while (surface != nullptr) { DrawSurface(*surface, flags); surface = surface->GetNextSurface(); } } } void CCubeModel::DrawFlat(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces) { if (positions == nullptr) { SetArraysCurrent(); } else { SetSkinningArraysCurrent(positions, normals); } if (surfaces != ESurfaceSelection::Sorted) { const auto* surface = x38_firstUnsortedSurf; while (surface != nullptr) { const auto mat = GetMaterialByIndex(surface->GetMaterialIndex()); CGX::SetVtxDescv_Compressed(mat.GetVertexDesc()); CGX::CallDisplayList(surface->GetDisplayList(), surface->GetDisplayListSize()); surface = surface->GetNextSurface(); } } if (surfaces != ESurfaceSelection::Unsorted) { const auto* surface = x3c_firstSortedSurf; while (surface != nullptr) { const auto mat = GetMaterialByIndex(surface->GetMaterialIndex()); CGX::SetVtxDescv_Compressed(mat.GetVertexDesc()); CGX::CallDisplayList(surface->GetDisplayList(), surface->GetDisplayListSize()); surface = surface->GetNextSurface(); } } } void CCubeModel::DrawNormal(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces) { CGX::SetNumIndStages(0); CGX::SetNumTevStages(1); CGX::SetNumTexGens(1); CGX::SetZMode(true, GX_LEQUAL, true); CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE0); CGX::SetBlendMode(GX_BM_BLEND, GX_BL_ZERO, GX_BL_ONE, GX_LO_CLEAR); DrawFlat(positions, normals, surfaces); } void CCubeModel::DrawNormal(const CModelFlags& flags) { CCubeMaterial::KillCachedViewDepState(); SetArraysCurrent(); DrawNormalSurfaces(flags); } void CCubeModel::DrawNormalSurfaces(const CModelFlags& flags) { if (sDrawingWireframe) { const auto* surface = x38_firstUnsortedSurf; while (surface != nullptr) { DrawSurfaceWireframe(*surface); surface = surface->GetNextSurface(); } } else if (TryLockTextures()) { const auto* surface = x38_firstUnsortedSurf; while (surface != nullptr) { DrawSurface(*surface, flags); surface = surface->GetNextSurface(); } } } void CCubeModel::DrawSurface(const CCubeSurface& surface, const CModelFlags& flags) { auto mat = GetMaterialByIndex(surface.GetMaterialIndex()); if (!mat.GetFlags().IsSet(CCubeMaterialFlagBits::fShadowOccluderMesh) || sDrawingOccluders) { mat.SetCurrent(flags, surface, *this); CGX::CallDisplayList(surface.GetDisplayList(), surface.GetDisplayListSize()); } } void CCubeModel::DrawSurfaces(const CModelFlags& flags) { if (sDrawingWireframe) { const auto* surface = x38_firstUnsortedSurf; while (surface != nullptr) { DrawSurfaceWireframe(*surface); surface = surface->GetNextSurface(); } surface = x3c_firstSortedSurf; while (surface != nullptr) { DrawSurfaceWireframe(*surface); surface = surface->GetNextSurface(); } } else if (TryLockTextures()) { const auto* surface = x38_firstUnsortedSurf; while (surface != nullptr) { DrawSurface(*surface, flags); surface = surface->GetNextSurface(); } surface = x3c_firstSortedSurf; while (surface != nullptr) { DrawSurface(*surface, flags); surface = surface->GetNextSurface(); } } } void CCubeModel::DrawSurfaceWireframe(const CCubeSurface& surface) { auto mat = GetMaterialByIndex(surface.GetMaterialIndex()); // TODO convert vertices to line strips and draw } void CCubeModel::EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, GX::LightMask chan0DisableMask, GX::LightMask chan1EnableLightMask) { sRenderModelShadow = true; sShadowTexture = &shadowTex; sTextureProjectionTransform = textureProjXf; sChannel0DisableLightMask = chan0DisableMask; sChannel1EnableLightMask = chan1EnableLightMask; } void CCubeModel::DisableShadowMaps() { sRenderModelShadow = false; } void CCubeModel::SetArraysCurrent() { CGX::SetArray(GX_VA_POS, x0_modelInstance.GetVertexPointer(), true); CGX::SetArray(GX_VA_NRM, x0_modelInstance.GetNormalPointer(), true); SetStaticArraysCurrent(); } void CCubeModel::SetDrawingOccluders(bool v) { sDrawingOccluders = v; } void CCubeModel::SetModelWireframe(bool v) { sDrawingWireframe = v; } void CCubeModel::SetNewPlayerPositionAndTime(const zeus::CVector3f& pos, const CStopwatch& time) { sPlayerPosition = pos; CCubeMaterial::KillCachedViewDepState(); // TODO time } void CCubeModel::SetRenderModelBlack(bool v) { sRenderModelBlack = v; // TODO another value is set here, but always 0? } void CCubeModel::SetSkinningArraysCurrent(TConstVectorRef positions, TConstVectorRef normals) { CGX::SetArray(GX_VA_POS, positions, false); CGX::SetArray(GX_VA_NRM, normals, false); // colors unused SetStaticArraysCurrent(); } void CCubeModel::SetStaticArraysCurrent() { // colors unused const auto* packedTexCoords = x0_modelInstance.GetPackedTCPointer(); const auto* texCoords = x0_modelInstance.GetTCPointer(); if (packedTexCoords == nullptr) { sUsingPackedLightmaps = false; } if (sUsingPackedLightmaps) { CGX::SetArray(GX_VA_TEX0, packedTexCoords, true); } else { CGX::SetArray(GX_VA_TEX0, texCoords, true); } for (int i = GX_VA_TEX1; i <= GX_VA_TEX7; ++i) { CGX::SetArray(static_cast(i), texCoords, true); } CCubeMaterial::KillCachedViewDepState(); } void CCubeModel::SetUsingPackedLightmaps(bool v) { sUsingPackedLightmaps = v; if (v) { CGX::SetArray(GX_VA_TEX0, x0_modelInstance.GetPackedTCPointer(), true); } else { CGX::SetArray(GX_VA_TEX0, x0_modelInstance.GetTCPointer(), true); } } template <> aurora::Vec2 cinput_stream_helper(CInputStream& in) { float x = in.ReadFloat(); float y = in.ReadFloat(); return {x, y}; } } // namespace metaforce