From 586268c66f3e2e4a6d702b6985cbcb8dd9edba46 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 26 Feb 2022 02:05:59 -0500 Subject: [PATCH] More CCubeModel/CCubeMaterial --- Runtime/Graphics/CCubeMaterial.cpp | 429 +++++++++++++++++++++ Runtime/Graphics/CCubeMaterial.hpp | 163 ++++++-- Runtime/Graphics/CCubeModel.cpp | 209 +++++++++- Runtime/Graphics/CCubeModel.hpp | 34 +- Runtime/Graphics/CCubeRenderer.hpp | 6 + Runtime/Graphics/CCubeSurface.hpp | 5 + Runtime/Graphics/CMetroidModelInstance.hpp | 2 +- Runtime/Graphics/CModel.hpp | 2 +- aurora/include/aurora/gfx.hpp | 5 +- 9 files changed, 813 insertions(+), 42 deletions(-) diff --git a/Runtime/Graphics/CCubeMaterial.cpp b/Runtime/Graphics/CCubeMaterial.cpp index e69de29bb..baf348f1f 100644 --- a/Runtime/Graphics/CCubeMaterial.cpp +++ b/Runtime/Graphics/CCubeMaterial.cpp @@ -0,0 +1,429 @@ +#include "Graphics/CCubeMaterial.hpp" + +#include "GameGlobalObjects.hpp" +#include "Graphics/CCubeModel.hpp" +#include "Graphics/CCubeRenderer.hpp" +#include "Graphics/CCubeSurface.hpp" +#include "Graphics/CModel.hpp" + +namespace metaforce { +static u32 sReflectionType = 0; +static u32 sLastMaterialUnique = UINT32_MAX; +static const u8* sLastMaterialCached = nullptr; +static const CCubeModel* sLastModelCached = nullptr; +static const CCubeModel* sRenderingModel = nullptr; +static float sReflectionAlpha = 0.f; + +void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& surface, CCubeModel& model) { + if (sLastMaterialCached == x0_data) { + if (sReflectionType == 1) { + if (sLastModelCached == sRenderingModel) { + return; + } + } else if (sReflectionType != 2) { + return; + } + } + + if (CCubeModel::sRenderModelBlack) { + SetCurrentBlack(); + return; + } + + sRenderingModel = &model; + sLastMaterialCached = x0_data; + + u32 numIndStages = 0; + const auto matFlags = GetFlags(); + const u8* materialDataCur = x0_data; + + const bool reflection = bool( + matFlags & (Flags(CCubeMaterialFlagBits::fSamusReflection) | CCubeMaterialFlagBits::fSamusReflectionSurfaceEye)); + if (reflection) { + if (!(matFlags & CCubeMaterialFlagBits::fSamusReflectionSurfaceEye)) { + EnsureViewDepStateCached(nullptr); + } else { + EnsureViewDepStateCached(&surface); + } + } + + u32 texCount = SBig(*reinterpret_cast(materialDataCur + 4)); + if ((flags.x2_flags & 4) != 0) { // render without texture lock + materialDataCur += (2 + texCount) * 4; + } else { + materialDataCur += 8; + for (u32 i = 0; i < texCount; ++i) { + u32 texIdx = SBig(*reinterpret_cast(materialDataCur)); + sRenderingModel->GetTexture(texIdx)->Load(i, CTexture::EClampMode::One); + materialDataCur += 4; + } + } + + auto groupIdx = SBig(*reinterpret_cast(materialDataCur + 4)); + if (sLastMaterialUnique != UINT32_MAX && sLastMaterialUnique == groupIdx && sReflectionType == 0) { + return; + } + sLastMaterialUnique = groupIdx; + + CCubeMaterialVatFlags vatFlags = SBig(*reinterpret_cast(materialDataCur)); + // SetVtxDescv_Compressed(vatFlags); + materialDataCur += 8; + + bool packedLightMaps = matFlags.IsSet(CCubeMaterialFlagBits::fLightmapUvArray); + if (packedLightMaps != CCubeModel::sUsingPackedLightmaps) { + model.SetUsingPackedLightmaps(packedLightMaps); + } + + u32 finalKColorCount = 0; + if (matFlags & CCubeMaterialFlagBits::fKonstValues) { + u32 konstCount = *reinterpret_cast(materialDataCur); + finalKColorCount = konstCount; + materialDataCur += 4; + for (u32 i = 0; i < konstCount; ++i) { + u32 kColor = *reinterpret_cast(materialDataCur); + materialDataCur += 4; + // TODO set KColor + } + } + + u32 blendFactors = *reinterpret_cast(materialDataCur); + materialDataCur += 4; + if (g_Renderer->IsInAreaDraw()) { + // TODO blackout fog, additive blend + } else { + SetupBlendMode(blendFactors, flags, matFlags.IsSet(CCubeMaterialFlagBits::fAlphaTest)); + } + + bool indTex = matFlags.IsSet(CCubeMaterialFlagBits::fSamusReflectionIndirectTexture); + u32 indTexSlot = 0; + if (indTex) { + indTexSlot = SBig(*reinterpret_cast(materialDataCur)); + materialDataCur += 4; + } + + HandleDepth(flags.x2_flags, matFlags); + + u32 chanCount = SBig(*reinterpret_cast(materialDataCur)); + materialDataCur += 4; + u32 firstChan = SBig(*reinterpret_cast(materialDataCur)); + materialDataCur += 4 * chanCount; + u32 finalNumColorChans = HandleColorChannels(chanCount, firstChan); + + u32 firstTev = 0; + if (CCubeModel::sRenderModelShadow) + firstTev = 2; + + u32 matTevCount = SBig(*reinterpret_cast(materialDataCur)); + materialDataCur += 4; + u32 finalTevCount = matTevCount; + + const u32* texMapTexCoordFlags = reinterpret_cast(materialDataCur + matTevCount * 20); + const u32* tcgs = reinterpret_cast(texMapTexCoordFlags + matTevCount); + bool usesTevReg2 = false; + + u32 finalCCFlags = 0; + u32 finalACFlags = 0; + + if (g_Renderer->IsThermalVisorActive()) { + finalTevCount = firstTev + 1; + u32 ccFlags = SBig(*reinterpret_cast(materialDataCur + 8)); + finalCCFlags = ccFlags; + u32 outputReg = ccFlags >> 9 & 0x3; + if (outputReg == 1) { // TevReg0 + materialDataCur += 20; + texMapTexCoordFlags += 1; + finalCCFlags = SBig(*reinterpret_cast(materialDataCur + 8)); + // Set TevReg0 = 0xc0c0c0c0 + } + finalACFlags = SBig(*reinterpret_cast(materialDataCur + 12)); + HandleTev(firstTev, materialDataCur, texMapTexCoordFlags, CCubeModel::sRenderModelShadow); + usesTevReg2 = false; + } else { + finalTevCount = firstTev + matTevCount; + for (u32 i = firstTev; i < finalTevCount; ++i) { + HandleTev(i, materialDataCur, texMapTexCoordFlags, CCubeModel::sRenderModelShadow && i == firstTev); + u32 ccFlags = SBig(*reinterpret_cast(materialDataCur + 8)); + finalCCFlags = ccFlags; + finalACFlags = SBig(*reinterpret_cast(materialDataCur + 12)); + u32 outputReg = ccFlags >> 9 & 0x3; + if (outputReg == 3) { // TevReg2 + usesTevReg2 = true; + } + materialDataCur += 20; + texMapTexCoordFlags += 1; + } + } + + u32 tcgCount = 0; + if (g_Renderer->IsThermalVisorActive()) { + u32 fullTcgCount = SBig(*tcgs); + tcgCount = std::min(fullTcgCount, 2u); + for (u32 i = 0; i < tcgCount; ++i) { + // TODO set TCG + } + tcgs += fullTcgCount + 1; + } else { + tcgCount = SBig(*tcgs); + for (u32 i = 0; i < tcgCount; ++i) { + // TODO set TCG + } + tcgs += tcgCount + 1; + } + + const u32* uvAnim = tcgs; + u32 animCount = uvAnim[1]; + uvAnim += 2; + u32 texMtx = 30; + u32 pttTexMtx = 64; + for (u32 i = 0; i < animCount; ++i) { + u32 size = HandleAnimatedUV(uvAnim, texMtx, pttTexMtx); + if (size == 0) + break; + uvAnim += size; + texMtx += 3; + pttTexMtx += 3; + } + + if (flags.x0_blendMode != 0) { + HandleTransparency(finalTevCount, finalKColorCount, flags, blendFactors, finalCCFlags, finalACFlags); + } + + if (reflection) { + if (sReflectionAlpha > 0.f) { + u32 additionalTevs = 0; + if (indTex) { + additionalTevs = HandleReflection(usesTevReg2, indTexSlot, 0, finalTevCount, texCount, tcgCount, + finalKColorCount, finalCCFlags, finalACFlags); + numIndStages = 1; + tcgCount += 2; + } else { + additionalTevs = HandleReflection(usesTevReg2, 255, 0, finalTevCount, texCount, tcgCount, finalKColorCount, + finalCCFlags, finalACFlags); + tcgCount += 1; + } + texCount += 1; + finalTevCount += additionalTevs; + finalKColorCount += 1; + } else if (((finalCCFlags >> 9) & 0x3) != 0) { + DoPassthru(finalTevCount); + finalTevCount += 1; + } + } + + if (CCubeModel::sRenderModelShadow) { + DoModelShadow(texCount, tcgCount); + tcgCount += 1; + } + + // SetNumIndStages(numIndStages); + // SetNumTevStages(finalTevCount); + // SetNumTexGens(tcgCount); + // SetNumColorChans(finalNumColorChans); +} + +void CCubeMaterial::SetCurrentBlack() { + auto flags = GetFlags(); + auto vatFlags = GetVatFlags(); + + if (flags.IsSet(CCubeMaterialFlagBits::fDepthSorting) || flags.IsSet(CCubeMaterialFlagBits::fAlphaTest)) { + // set fog mode 0x21 + aurora::gfx::set_blend_mode(ERglBlendMode::Blend, ERglBlendFactor::Zero, ERglBlendFactor::One, ERglLogicOp::Clear); + } else { + // set fog mode 5 + aurora::gfx::set_blend_mode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::Zero, ERglLogicOp::Clear); + } + // set vtx desc flags + // TODO +} + +void CCubeMaterial::SetupBlendMode(u32 blendFactors, const CModelFlags& flags, bool alphaTest) { + auto newSrcFactor = static_cast(blendFactors & 0xffff); + auto newDstFactor = static_cast(blendFactors >> 16 & 0xffff); + if (alphaTest) { + // discard fragments with alpha < 0.25 + aurora::gfx::set_alpha_discard(true); + newSrcFactor = ERglBlendFactor::One; + newDstFactor = ERglBlendFactor::Zero; + } else { + aurora::gfx::set_alpha_discard(false); + } + + if (flags.x0_blendMode > 4 && newSrcFactor == ERglBlendFactor::One) { + newSrcFactor = ERglBlendFactor::SrcAlpha; + if (newDstFactor == ERglBlendFactor::Zero) { + newDstFactor = flags.x0_blendMode > 6 ? ERglBlendFactor::One : ERglBlendFactor::InvSrcAlpha; + } + } + + // TODO set fog color zero if dst blend zero + aurora::gfx::set_blend_mode(ERglBlendMode::Blend, newSrcFactor, newDstFactor, ERglLogicOp::Clear); +} + +void CCubeMaterial::HandleDepth(u16 modelFlags, CCubeMaterialFlags matFlags) { + ERglEnum func = ERglEnum::Never; + if ((modelFlags & 0x1) == 0) { + func = ERglEnum::Always; + } else if ((modelFlags & 0x8) != 0) { + func = (modelFlags & 0x10) != 0 ? ERglEnum::Greater : ERglEnum::GEqual; + } else { + func = (modelFlags & 0x10) != 0 ? ERglEnum::Less : ERglEnum::LEqual; + } + bool depthWrite = (modelFlags & 0x2) != 0 && matFlags & CCubeMaterialFlagBits::fDepthWrite; + aurora::gfx::set_depth_mode(func, depthWrite); +} + +void CCubeMaterial::ResetCachedMaterials() { + KillCachedViewDepState(); + sLastMaterialUnique = UINT32_MAX; + sRenderingModel = nullptr; + sLastMaterialCached = nullptr; +} + +void CCubeMaterial::KillCachedViewDepState() { sLastModelCached = nullptr; } + +void CCubeMaterial::EnsureViewDepStateCached(const CCubeSurface* surface) { + // TODO + if ((surface != nullptr || sLastModelCached != sRenderingModel) && sRenderingModel != nullptr) { + sLastModelCached = sRenderingModel; + if (surface == nullptr) { + sReflectionType = 1; + } else { + sReflectionType = 2; + } + if (g_Renderer->IsReflectionDirty()) { + + } else { + g_Renderer->SetReflectionDirty(true); + } + } +} + +u32 CCubeMaterial::HandleColorChannels(u32 chanCount, u32 firstChan) { + if (CCubeModel::sRenderModelShadow) { + if (chanCount != 0) { + // TODO + } + return 2; + } + + // TODO + return chanCount; +} + +void CCubeMaterial::HandleTev(u32 tevCur, const u8* materialDataCur, const u32* texMapTexCoordFlags, + bool shadowMapsEnabled) { + u32 colorArgs = shadowMapsEnabled ? 0x7a04f : SBig(*materialDataCur); + // CGX::SetStandardDirectTev_Compressed +} + +u32 CCubeMaterial::HandleAnimatedUV(const u32* uvAnim, u32 texMtx, u32 pttTexMtx) { + u32 type = SBig(*uvAnim); + switch (type) { + case 0: + // TODO + return 1; + case 1: + // TODO + return 1; + case 2: + // TODO + return 5; + case 3: + // TODO + return 3; + case 4: + case 5: + // TODO + return 5; + case 6: + // TODO + return 1; + case 7: + // TODO + return 2; + default: + return 0; + } +} + +void CCubeMaterial::HandleTransparency(u32& finalTevCount, u32& finalKColorCount, const CModelFlags& modelFlags, + u32 blendFactors, u32& finalCCFlags, u32& finalACFlags) { + if (modelFlags.x0_blendMode == 2) { + u16 dstFactor = blendFactors >> 16 & 0xffff; + if (dstFactor == 1) + return; + } + if (modelFlags.x0_blendMode == 3) { + // Stage outputting splatted KAlpha as color to reg0 + // GXSetTevColorIn(finalTevCount, TEVCOLORARG_ZERO, TEVCOLORARG_ZERO, TEVCOLORARG_ZERO, TEVCOLORARG_KONST); + // GXSetTevAlphaIn(finalTevCount, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_APREV); + // GXSetTevColorOp(finalTevCount, 0, 0, 0, 1, 1); // ColorReg0 + // GXSetTevKColorSel(finalTevCount, finalKColorCount+28); + // GXSetTevAlphaOp(finalTevCount, 0, 0, 0, 1, 0); // AlphaRegPrev + // GXSetTevOrder(finalTevCount, 255, 255, 255); + // GXSetTevDirect(finalTevCount); + // Stage interpolating from splatted KAlpha using KColor + // GXSetTevColorIn(finalTevCount + 1, TEVCOLORARG_CPREV, TEVCOLORARG_C0, TEVCOLORARG_KONST, TEVCOLORARG_ZERO); + // GXSetTevAlphaIn(finalTevCount + 1, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_APREV); + // GXSetTevKColorSel(finalTevCount, finalKColorCount+12); + // SetStandardTevColorAlphaOp(finalTevCount + 1); + // GXSetTevDirect(finalTevCount + 1); + // GXSetTevOrder(finalTevCount + 1, 255, 255, 255); + // GXSetTevKColor(finalKColorCount, modelFlags.x4_color); + finalKColorCount += 1; + finalTevCount += 2; + } else { + // Mul KAlpha + u32 tevAlpha = 0x000380C7; // TEVALPHAARG_ZERO, TEVALPHAARG_KONST, TEVALPHAARG_APREV, TEVALPHAARG_ZERO + if (modelFlags.x0_blendMode == 8) { + // Set KAlpha + tevAlpha = 0x00031CE7; // TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_KONST + } + // Mul KColor + u32 tevColor = 0x000781CF; // TEVCOLORARG_ZERO, TEVCOLORARG_KONST, TEVCOLORARG_CPREV, TEVCOLORARG_ZERO + if (modelFlags.x0_blendMode == 2) { + // Add KColor + tevColor = 0x0007018F; // TEVCOLORARG_ZERO, TEVCOLORARG_ONE, TEVCOLORARG_CPREV, TEVCOLORARG_KONST + } + // GXSetTevColorIn(finalTevCount) + // GXSetTevAlphaIn(finalTevCount) + // SetStandardTevColorAlphaOp(finalTevCount); + finalCCFlags = 0x100; // Just clamp, output prev reg + finalACFlags = 0x100; + // GXSetTevDirect(finalTevCount); + // GXSetTevOrder(finalTevCount, 255, 255, 255); + // GXSetTevKColor(finalKColorCount, modelFlags.x4_color); + // GXSetTevKColorSel(finalTevCount, finalKColorCount+12); + // GXSetTevKAlphaSel(finalTevCount, finalKColorCount+28); + finalTevCount += 1; + finalKColorCount += 1; + } +} + +u32 CCubeMaterial::HandleReflection(bool usesTevReg2, u32 indTexSlot, u32 r5, u32 finalTevCount, u32 texCount, + u32 tcgCount, u32 finalKColorCount, u32& finalCCFlags, u32& finalACFlags) { + u32 out = 0; + if (usesTevReg2) { + // GX_CC_C2 + out = 1; + } else { + // GX_CC_KONST + } + // set reflection kcolor + // tex = g_Renderer->GetRealReflection + // tex.Load(texCount, 0) + + finalACFlags = 0; + finalCCFlags = 0; + return out + 1; +} + +void CCubeMaterial::DoPassthru(u32 finalTevCount) { + // TODO +} + +void CCubeMaterial::DoModelShadow(u32 texCount, u32 tcgCount) { + // CCubeModel::sShadowTexture->Load(texCount, CTexture::EClampMode::One); + // TODO +} +} // namespace metaforce diff --git a/Runtime/Graphics/CCubeMaterial.hpp b/Runtime/Graphics/CCubeMaterial.hpp index 7fc5c1694..97d75b6d9 100644 --- a/Runtime/Graphics/CCubeMaterial.hpp +++ b/Runtime/Graphics/CCubeMaterial.hpp @@ -9,23 +9,118 @@ #include "IObjectStore.hpp" namespace metaforce { -enum class EStateFlags { - Unused1 = 1 << 0, - Unused2 = 1 << 1, - Unused3 = 1 << 2, - KonstEnabled = 1 << 3, - DepthSorting = 1 << 4, - AlphaTest = 1 << 5, - Reflection = 1 << 6, - DepthWrite = 1 << 7, - ReflectionSurfaceEye = 1 << 8, - OccluderMesh = 1 << 9, - ReflectionIndirectTexture = 1 << 10, - LightMap = 1 << 11, - Unused4 = 1 << 12, - LightmapUVArray = 1 << 13, +class CCubeModel; +class CCubeSurface; +struct CModelFlags; + +template +class Flags { +public: + using MaskType = typename std::underlying_type::type; + + // constructors + constexpr Flags() noexcept : m_mask(0) {} + + constexpr Flags(BitType bit) noexcept : m_mask(static_cast(bit)) {} + + constexpr Flags(Flags const& rhs) noexcept : m_mask(rhs.m_mask) {} + + constexpr explicit Flags(MaskType flags) noexcept : m_mask(flags) {} + + [[nodiscard]] constexpr bool IsSet(Flags const bit) const noexcept { return bool(*this & bit); } + + // relational operators + auto operator<=>(Flags const&) const noexcept = default; + + // logical operator + constexpr bool operator!() const noexcept { return !m_mask; } + + // bitwise operators + constexpr Flags operator&(Flags const& rhs) const noexcept { + return Flags(m_mask & rhs.m_mask); + } + + constexpr Flags operator|(Flags const& rhs) const noexcept { + return Flags(m_mask | rhs.m_mask); + } + + constexpr Flags operator^(Flags const& rhs) const noexcept { + return Flags(m_mask ^ rhs.m_mask); + } + + // assignment operators + constexpr Flags& operator=(Flags const& rhs) noexcept { + m_mask = rhs.m_mask; + return *this; + } + + constexpr Flags& operator|=(Flags const& rhs) noexcept { + m_mask |= rhs.m_mask; + return *this; + } + + constexpr Flags& operator&=(Flags const& rhs) noexcept { + m_mask &= rhs.m_mask; + return *this; + } + + constexpr Flags& operator^=(Flags const& rhs) noexcept { + m_mask ^= rhs.m_mask; + return *this; + } + + // cast operators + explicit constexpr operator bool() const noexcept { return m_mask != 0; } + + explicit constexpr operator MaskType() const noexcept { return m_mask; } + +private: + MaskType m_mask; +}; + +enum class CCubeMaterialFlagBits : u32 { + fKonstValues = 0x8, + fDepthSorting = 0x10, + fAlphaTest = 0x20, + fSamusReflection = 0x40, + fDepthWrite = 0x80, + fSamusReflectionSurfaceEye = 0x100, + fShadowOccluderMesh = 0x200, + fSamusReflectionIndirectTexture = 0x400, + fLightmap = 0x800, + fLightmapUvArray = 0x2000, + fTextureSlotMask = 0xffff0000 +}; +using CCubeMaterialFlags = Flags; + +enum class CCubeMaterialVatAttribute : u32 { + Position = 0, + Normal = 2, + Color0 = 4, + Color1 = 8, + Tex0 = 10, + Tex1 = 12, + Tex2 = 14, + Tex3 = 16, + Tex4 = 18, + Tex5 = 20, + Tex6 = 22, +}; +enum class CCubeMaterialVatAttributeType : u32 { None = 0, Direct = 1, Index8 = 2, Index16 = 3 }; +class CCubeMaterialVatFlags { + u32 m_flags = 0; + +public: + constexpr CCubeMaterialVatFlags() noexcept = default; + constexpr CCubeMaterialVatFlags(u32 flags) noexcept : m_flags(flags){}; + [[nodiscard]] CCubeMaterialVatAttributeType GetAttributeType(CCubeMaterialVatAttribute attribute) const noexcept { + return CCubeMaterialVatAttributeType((m_flags >> u32(attribute)) & 0x3); + } + void SetAttributeType(CCubeMaterialVatAttribute attribute, CCubeMaterialVatAttributeType type) noexcept { + m_flags &= ~(u32(0x3) << u32(attribute)); + m_flags |= u32(type) << u32(attribute); + } }; -ENABLE_BITWISE_ENUM(EStateFlags); class CCubeMaterial { const u8* x0_data; @@ -33,24 +128,44 @@ class CCubeMaterial { public: explicit CCubeMaterial(const u8* data) : x0_data(data) {} - void SetCurrent(CModelFlags flags, const CCubeSurface& surface, const CCubeModel& model); + void SetCurrent(const CModelFlags& flags, const CCubeSurface& surface, CCubeModel& model); [[nodiscard]] u32 GetCompressedBlend() { - const u32* ptr = reinterpret_cast(x0_data[(GetTextureCount() * 4) + 16]); - if (IsFlagSet(EStateFlags::KonstEnabled)) { + const u32* ptr = reinterpret_cast(x0_data + (GetTextureCount() * 4) + 16); + if (GetFlags() & CCubeMaterialFlagBits::fKonstValues) { ptr += SBig(*ptr) + 1; } - return SBig(*ptr); } - [[nodiscard]] EStateFlags GetFlags() const { return EStateFlags(SBig(*reinterpret_cast(x0_data))); } - [[nodiscard]] bool IsFlagSet(EStateFlags flag) const { return True(GetFlags() & flag); } + [[nodiscard]] CCubeMaterialFlags GetFlags() const { + return CCubeMaterialFlags(SBig(*reinterpret_cast(x0_data))); + } + [[nodiscard]] CCubeMaterialVatFlags GetVatFlags() const { + return SBig(*reinterpret_cast(x0_data + 8 + (GetTextureCount() * 4))); + } [[nodiscard]] u32 GetUsedTextureSlots() const { return static_cast(GetFlags()) >> 16; } - [[nodiscard]] u32 GetTextureCount() const { return SBig(*reinterpret_cast(&x0_data[4])); } + [[nodiscard]] u32 GetTextureCount() const { return SBig(*reinterpret_cast(x0_data + 4)); } [[nodiscard]] u32 GetVertexDesc() const { - return SBig(*reinterpret_cast(&x0_data[(GetTextureCount() * 4) + 8])); + return SBig(*reinterpret_cast(&x0_data + (GetTextureCount() * 4) + 8)); } static void ResetCachedMaterials(); + static void EnsureViewDepStateCached(const CCubeSurface* surface); + static void KillCachedViewDepState(); + +private: + void SetCurrentBlack(); + + static void SetupBlendMode(u32 blendFactors, const CModelFlags& flags, bool alphaTest); + static void HandleDepth(u16 modelFlags, CCubeMaterialFlags matFlags); + static u32 HandleColorChannels(u32 chanCount, u32 firstChan); + static void HandleTev(u32 tevCur, const u8* materialDataCur, const u32* texMapTexCoordFlags, bool shadowMapsEnabled); + static u32 HandleAnimatedUV(const u32* uvAnim, u32 texMtx, u32 pttTexMtx); + static void HandleTransparency(u32& finalTevCount, u32& finalKColorCount, const CModelFlags& modelFlags, + u32 blendFactors, u32& finalCCFlags, u32& finalACFlags); + static u32 HandleReflection(bool usesTevReg2, u32 indTexSlot, u32 r5, u32 finalTevCount, u32 texCount, u32 tcgCount, + u32 finalKColorCount, u32& finalCCFlags, u32& finalACFlags); + static void DoPassthru(u32 finalTevCount); + static void DoModelShadow(u32 texCount, u32 tcgCount); }; } // namespace metaforce diff --git a/Runtime/Graphics/CCubeModel.cpp b/Runtime/Graphics/CCubeModel.cpp index 4fd7a1364..8409895f4 100644 --- a/Runtime/Graphics/CCubeModel.cpp +++ b/Runtime/Graphics/CCubeModel.cpp @@ -4,8 +4,22 @@ #include "Graphics/CCubeMaterial.hpp" #include "Graphics/CCubeSurface.hpp" #include "Graphics/CGraphics.hpp" +#include "Graphics/CModel.hpp" namespace metaforce { +bool CCubeModel::sRenderModelBlack = false; +bool CCubeModel::sRenderModelShadow = false; +bool CCubeModel::sUsingPackedLightmaps = false; +const CTexture* CCubeModel::sShadowTexture = nullptr; + +static bool sDrawingOccluders = false; +static bool sDrawingWireframe = false; + +static zeus::CTransform sTextureProjectionTransform; +static u8 sChannel0DisableLightMask = 0; +static u8 sChannel1EnableLightMask = 0; + +static zeus::CVector3f sPlayerPosition; CCubeModel::CCubeModel(std::vector* surfaces, std::vector>* textures, u8* materialData, std::vector* positions, std::vector* colors, @@ -24,7 +38,8 @@ CCubeModel::CCubeModel(std::vector* surfaces, std::vectorsize(); i > 0; --i) { auto& surf = (*x0_modelInstance.Surfaces())[i - 1]; - if (!GetMaterialByIndex(surf.GetMaterialIndex()).IsFlagSet(EStateFlags::DepthSorting)) { + const auto matFlags = GetMaterialByIndex(surf.GetMaterialIndex()).GetFlags(); + if (!matFlags.IsSet(CCubeMaterialFlagBits::fDepthSorting)) { surf.SetNextSurface(x38_firstUnsortedSurf); x38_firstUnsortedSurf = &surf; } else { @@ -97,4 +112,196 @@ void CCubeModel::MakeTexturesFromMats(const u8* ptr, std::vectorGetNextSurface(); + } + } else if (TryLockTextures()) { + const auto* surface = x3c_firstSortedSurf; + while (surface != nullptr) { + DrawSurface(*surface, flags); + surface = surface->GetNextSurface(); + } + } +} + +void CCubeModel::DrawFlat(TVectorRef positions, TVectorRef 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()); + // TODO draw + } + } + if (surfaces != ESurfaceSelection::Unsorted) { + const auto* surface = x3c_firstSortedSurf; + while (surface != nullptr) { + const auto mat = GetMaterialByIndex(surface->GetMaterialIndex()); + // TODO draw + } + } +} + +void CCubeModel::DrawNormal(TVectorRef positions, TVectorRef normals, ESurfaceSelection surfaces) { + // TODO bunch of CGX stuff, what is it doing? + 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); + // TODO draw + } +} + +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, u8 chan0DisableMask, + u8 chan1EnableLightMask) { + sRenderModelShadow = true; + sShadowTexture = &shadowTex; + sTextureProjectionTransform = textureProjXf; + sChannel0DisableLightMask = chan0DisableMask; + sChannel1EnableLightMask = chan1EnableLightMask; +} + +void CCubeModel::DisableShadowMaps() { sRenderModelShadow = false; } + +void CCubeModel::SetArraysCurrent() { + if (x0_modelInstance.GetVertexPointer() != nullptr) { + // TODO set vertices active + } + if (x0_modelInstance.GetNormalPointer() != nullptr) { + // TODO set normals active + } + 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(TVectorRef positions, TVectorRef normals) { + // TODO activate vertices, normals & colors + SetStaticArraysCurrent(); +} + +void CCubeModel::SetStaticArraysCurrent() { + // TODO activate colors + const auto* packedTexCoords = x0_modelInstance.GetPackedTCPointer(); + const auto* texCoords = x0_modelInstance.GetTCPointer(); + if (packedTexCoords == nullptr) { + sUsingPackedLightmaps = false; + } + if (sUsingPackedLightmaps) { + // TODO activate packed TCs for texture 0 + } else if (texCoords != nullptr) { + // TODO activate TCs for texture 0 + } + if (texCoords != nullptr) { + for (int i = 1; i < 8; ++i) { + // TODO activate TCs for textures 1-7 + } + } + CCubeMaterial::KillCachedViewDepState(); +} + +void CCubeModel::SetUsingPackedLightmaps(bool v) { + sUsingPackedLightmaps = v; + if (v) { + // TODO activate packed TCs for texture 0 + } else { + // TODO activate TCs for texture 0 + } +} + } // namespace metaforce diff --git a/Runtime/Graphics/CCubeModel.hpp b/Runtime/Graphics/CCubeModel.hpp index c898153a0..8415dfc23 100644 --- a/Runtime/Graphics/CCubeModel.hpp +++ b/Runtime/Graphics/CCubeModel.hpp @@ -17,6 +17,7 @@ struct CModelFlags; enum class ESurfaceSelection { Unsorted, Sorted, + All, }; // These parameters were originally float* @@ -81,36 +82,41 @@ public: bool TryLockTextures(); void UnlockTextures(); void RemapMaterialData(u8* data, std::vector>& textures); - void Draw(CModelFlags flags); - void DrawAlpha(CModelFlags flags); + void Draw(const CModelFlags& flags); + void DrawAlpha(const CModelFlags& flags); void DrawFlat(TVectorRef positions, TVectorRef normals, ESurfaceSelection surfaces); void DrawNormal(TVectorRef positions, TVectorRef normals, ESurfaceSelection surfaces); - void DrawNormal(CModelFlags flags); - void DrawSurface(const CCubeSurface& surface, CModelFlags flags); + void DrawNormal(const CModelFlags& flags); + void DrawSurface(const CCubeSurface& surface, const CModelFlags& flags); void DrawSurfaceWireframe(const CCubeSurface& surface); void SetArraysCurrent(); + void SetUsingPackedLightmaps(bool v); - TVectorRef GetPositions() const { return x0_modelInstance.GetVertexPointer(); } - TVectorRef GetNormals() const { return x0_modelInstance.GetNormalPointer(); } + [[nodiscard]] TVectorRef GetPositions() const { return x0_modelInstance.GetVertexPointer(); } + [[nodiscard]] TVectorRef GetNormals() const { return x0_modelInstance.GetNormalPointer(); } + [[nodiscard]] TCachedToken& GetTexture(u32 idx) const { return x1c_textures->at(idx); } - static void EnableShadowMaps(CTexture shadowTex, zeus::CTransform textureProjXf, u8 chan0DisableMask, + static void EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, u8 chan0DisableMask, u8 chan1EnableLightMask); static void DisableShadowMaps(); static void MakeTexturesFromMats(const u8* ptr, std::vector>& texture, IObjectStore* store, bool b1); - static void KillCachedViewDepState(); static void SetDrawingOccluders(bool v); - static void SetModelWireframe(); + static void SetModelWireframe(bool v); static void SetNewPlayerPositionAndTime(const zeus::CVector3f& pos, const CStopwatch& time); static void SetRenderModelBlack(bool v); + static bool sRenderModelBlack; + static bool sUsingPackedLightmaps; + static bool sRenderModelShadow; + static const CTexture* sShadowTexture; + private: - void Draw(TVectorRef positions, TVectorRef normals, CModelFlags flags); - void DrawAlphaSurfaces(CModelFlags flags); - void DrawNormalSurfaces(CModelFlags flags); - void DrawSurfaces(CModelFlags flags); + void Draw(TVectorRef positions, TVectorRef normals, const CModelFlags& flags); + void DrawAlphaSurfaces(const CModelFlags& flags); + void DrawNormalSurfaces(const CModelFlags& flags); + void DrawSurfaces(const CModelFlags& flags); void SetSkinningArraysCurrent(TVectorRef positions, TVectorRef normals); void SetStaticArraysCurrent(); - void SetUsingPackedLightmaps(bool v); }; } // namespace metaforce diff --git a/Runtime/Graphics/CCubeRenderer.hpp b/Runtime/Graphics/CCubeRenderer.hpp index ed4920e96..df91fb7ff 100644 --- a/Runtime/Graphics/CCubeRenderer.hpp +++ b/Runtime/Graphics/CCubeRenderer.hpp @@ -206,5 +206,11 @@ public: int DrawOverlappingWorldModelIDs(int alphaVal, const std::vector& modelBits, const zeus::CAABox& aabb); void DrawOverlappingWorldModelShadows(int alphaVal, const std::vector& modelBits, const zeus::CAABox& aabb, float alpha); + + // Getters + [[nodiscard]] bool IsInAreaDraw() const { return x318_30_inAreaDraw; } + [[nodiscard]] bool IsReflectionDirty() const { return x318_24_refectionDirty; } + void SetReflectionDirty(bool v) { x318_24_refectionDirty = v; } + [[nodiscard]] bool IsThermalVisorActive() const { return x318_29_thermalVisor; } }; } // namespace metaforce diff --git a/Runtime/Graphics/CCubeSurface.hpp b/Runtime/Graphics/CCubeSurface.hpp index 849144c6e..fa1197afd 100644 --- a/Runtime/Graphics/CCubeSurface.hpp +++ b/Runtime/Graphics/CCubeSurface.hpp @@ -27,8 +27,13 @@ class CCubeSurface { public: explicit CCubeSurface(const u8* ptr, u32 len); // Metaforce addition for extracting surface data + // bool IsValid() const; + [[nodiscard]] CCubeModel* GetParent() { return x14_parent; } + [[nodiscard]] const CCubeModel* GetParent() const { return x14_parent; } void SetParent(CCubeModel* parent) { x14_parent = parent; } + [[nodiscard]] CCubeSurface* GetNextSurface() { return x18_nextSurface; } + [[nodiscard]] const CCubeSurface* GetNextSurface() const { return x18_nextSurface; } void SetNextSurface(CCubeSurface* next) { x18_nextSurface = next; } [[nodiscard]] u32 GetMaterialIndex() const { return xc_materialIndex; } [[nodiscard]] u32 GetDisplayListSize() const { return x10_displayListSize & 0x7fffffff; } diff --git a/Runtime/Graphics/CMetroidModelInstance.hpp b/Runtime/Graphics/CMetroidModelInstance.hpp index 9021e1a03..8131cc3c6 100644 --- a/Runtime/Graphics/CMetroidModelInstance.hpp +++ b/Runtime/Graphics/CMetroidModelInstance.hpp @@ -4,8 +4,8 @@ #include #include -#include "Runtime/RetroTypes.hpp" #include "Graphics/CCubeModel.hpp" +#include "Runtime/RetroTypes.hpp" #include #include diff --git a/Runtime/Graphics/CModel.hpp b/Runtime/Graphics/CModel.hpp index f9681c4f9..ec221112e 100644 --- a/Runtime/Graphics/CModel.hpp +++ b/Runtime/Graphics/CModel.hpp @@ -5,9 +5,9 @@ #include "CToken.hpp" #include "GCNTypes.hpp" +#include "Graphics/CCubeModel.hpp" #include "Graphics/CTexture.hpp" #include "IObjectStore.hpp" -#include "Graphics/CCubeModel.hpp" namespace metaforce { class CCubeSurface; diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index 39c969e5e..686a9d8c4 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -142,7 +142,10 @@ enum class ZComp : uint8_t { void set_cull_mode(metaforce::ERglCullMode mode) noexcept; void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst, metaforce::ERglLogicOp op) noexcept; -void set_depth_mode(bool test, metaforce::ERglEnum func, bool update); +void set_depth_mode(metaforce::ERglEnum func, bool update); + +// Model state +void set_alpha_discard(bool v); void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept; void update_projection(const zeus::CMatrix4f& proj) noexcept;