diff --git a/Runtime/Character/CAnimData.cpp b/Runtime/Character/CAnimData.cpp index 56992b443..38ed0507c 100644 --- a/Runtime/Character/CAnimData.cpp +++ b/Runtime/Character/CAnimData.cpp @@ -23,6 +23,7 @@ #include "Runtime/Character/CTransitionManager.hpp" #include "Runtime/Character/IAnimReader.hpp" #include "Runtime/Graphics/CSkinnedModel.hpp" +#include "Runtime/Graphics/CGX.hpp" #include @@ -559,7 +560,7 @@ void CAnimData::SetupRender(CSkinnedModel& model, CVertexMorphEffect* morphEffec } void CAnimData::DrawSkinnedModel(CSkinnedModel& model, const CModelFlags& flags) { - aurora::gfx::set_chan_mat_src(GX::COLOR0A0, GX::SRC_REG); + CGX::SetChanCtrl(CGX::EChannelId::Channel0, CGraphics::g_LightActive); model.Draw(flags); } diff --git a/Runtime/Character/CModelData.cpp b/Runtime/Character/CModelData.cpp index 310bbcb89..6e8ccaf45 100644 --- a/Runtime/Character/CModelData.cpp +++ b/Runtime/Character/CModelData.cpp @@ -422,12 +422,12 @@ void CModelData::MultiPassDraw(EWhichModel which, const zeus::CTransform& xf, co } } -void CModelData::DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, const CTexture& tex, +void CModelData::DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor, float t) { DisintegrateDraw(GetRenderingModel(mgr), xf, tex, addColor, t); } -void CModelData::DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, const CTexture& tex, +void CModelData::DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor, float t) { zeus::CTransform scaledXf = xf * zeus::CTransform::Scale(x0_scale); CGraphics::SetModelMatrix(scaledXf); @@ -435,27 +435,13 @@ void CModelData::DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, const auto aabb = GetBounds(scaledXf); if (x10_animData) { auto& model = PickAnimatedModel(which); - // x10_animData->SetupRender(model, CModelFlags{}, {}, ?) - model.DoDrawCallback([](auto positions, auto normals) { - // TODO + x10_animData->SetupRender(model, nullptr, nullptr); + model.DoDrawCallback([&](auto positions, auto normals) { + g_Renderer->DrawModelDisintegrate(*model.GetModel(), tex, addColor, positions, normals, t); }); } else { - g_Renderer->DrawModelDisintegrate(*PickStaticModel(which), tex, addColor, {}, {}); + g_Renderer->DrawModelDisintegrate(*PickStaticModel(which), tex, addColor, nullptr, nullptr, t); } - - // CBooModel::SetDisintegrateTexture(tex.GetTexture()); - // CModelFlags flags(5, 0, 3, zeus::skWhite); - // flags.m_extendedShader = EExtendedShader::Disintegrate; - // flags.addColor = addColor; - // flags.addColor.a() = t; // Stash T value in here (shader does not care) - // - // if (x10_animData) { - // CSkinnedModel& sModel = PickAnimatedModel(which); - // x10_animData->Render(sModel, flags, std::nullopt, nullptr); - // } else { - // CBooModel& model = *PickStaticModel(which); - // model.Draw(flags, nullptr, nullptr); - // } } void CModelData::ThermalDraw(const zeus::CColor& mulColor, const zeus::CColor& addColor, const CModelFlags& flags) {} diff --git a/Runtime/Character/CModelData.hpp b/Runtime/Character/CModelData.hpp index d8622b236..bb56ab2d8 100644 --- a/Runtime/Character/CModelData.hpp +++ b/Runtime/Character/CModelData.hpp @@ -126,10 +126,10 @@ public: const zeus::CColor& alphaColor, const zeus::CColor& additiveColor); void MultiPassDraw(EWhichModel which, const zeus::CTransform& xf, const CActorLights* lights, const CModelFlags* flags, u32 count); - void DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, const CTexture& tex, - const zeus::CColor& addColor, float t); - void DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, const CTexture& tex, + void DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor, float t); + void DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor, + float t); void ThermalDraw(const zeus::CColor& mulColor, const zeus::CColor& addColor, const CModelFlags& flags); CAnimData* GetAnimationData() { return x10_animData.get(); } diff --git a/Runtime/Graphics/CCubeMaterial.cpp b/Runtime/Graphics/CCubeMaterial.cpp index 27d7ede8e..c2ba601c1 100644 --- a/Runtime/Graphics/CCubeMaterial.cpp +++ b/Runtime/Graphics/CCubeMaterial.cpp @@ -4,10 +4,9 @@ #include "Graphics/CCubeModel.hpp" #include "Graphics/CCubeRenderer.hpp" #include "Graphics/CCubeSurface.hpp" +#include "Graphics/CGX.hpp" #include "Graphics/CModel.hpp" -#include - namespace metaforce { static u32 sReflectionType = 0; static u32 sLastMaterialUnique = UINT32_MAX; @@ -68,7 +67,7 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur sLastMaterialUnique = groupIdx; u32 vatFlags = SBig(*reinterpret_cast(materialDataCur)); - aurora::gfx::model::set_vtx_desc_compressed(vatFlags); + CGX::SetVtxDescv_Compressed(vatFlags); materialDataCur += 8; bool packedLightMaps = matFlags.IsSet(CCubeMaterialFlagBits::fLightmapUvArray); @@ -84,14 +83,14 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur for (u32 i = 0; i < konstCount; ++i) { u32 kColor = SBig(*reinterpret_cast(materialDataCur)); materialDataCur += 4; - aurora::gfx::set_tev_k_color(static_cast(i), kColor); + CGX::SetTevKColor(static_cast(i), kColor); } } u32 blendFactors = SBig(*reinterpret_cast(materialDataCur)); materialDataCur += 4; if (g_Renderer->IsInAreaDraw()) { - // TODO blackout fog, additive blend + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ONE, GX::LO_CLEAR); } else { SetupBlendMode(blendFactors, flags, matFlags.IsSet(CCubeMaterialFlagBits::fAlphaTest)); } @@ -135,7 +134,7 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur materialDataCur += 20; texMapTexCoordFlags += 1; finalCCFlags = SBig(*reinterpret_cast(materialDataCur + 8)); - aurora::gfx::set_tev_reg_color(GX::TEVREG0, 0xc0c0c0c0); + GXSetTevColor(GX::TEVREG0, 0xc0c0c0c0); } finalACFlags = SBig(*reinterpret_cast(materialDataCur + 12)); HandleTev(firstTev, reinterpret_cast(materialDataCur), texMapTexCoordFlags, @@ -219,10 +218,10 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur tcgCount += 1; } - // SetNumIndStages(numIndStages); - aurora::gfx::disable_tev_stage(static_cast(finalTevCount)); - // SetNumTexGens(tcgCount); - // SetNumColorChans(finalNumColorChans); + CGX::SetNumIndStages(numIndStages); + CGX::SetNumTevStages(finalTevCount); + CGX::SetNumTexGens(tcgCount); + CGX::SetNumChans(finalNumColorChans); } void CCubeMaterial::SetCurrentBlack() { @@ -230,50 +229,47 @@ void CCubeMaterial::SetCurrentBlack() { 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); + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ZERO, GX::BL_ONE, GX::LO_CLEAR); } else { - // set fog mode 5 - aurora::gfx::set_blend_mode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::Zero, ERglLogicOp::Clear); + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ZERO, GX::LO_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); + 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; + CGX::SetAlphaCompare(GX::GEQUAL, 64, GX::AOP_OR, GX::NEVER, 0); + newSrcFactor = GX::BL_ONE; + newDstFactor = GX::BL_ZERO; } else { - aurora::gfx::set_alpha_discard(false); + CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_OR, GX::ALWAYS, 0); } - if (flags.x0_blendMode > 4 && newSrcFactor == ERglBlendFactor::One) { - newSrcFactor = ERglBlendFactor::SrcAlpha; - if (newDstFactor == ERglBlendFactor::Zero) { - newDstFactor = flags.x0_blendMode > 6 ? ERglBlendFactor::One : ERglBlendFactor::InvSrcAlpha; + if (flags.x0_blendMode > 4 && newSrcFactor == GX::BL_ONE) { + newSrcFactor = GX::BL_SRCALPHA; + if (newDstFactor == GX::BL_ZERO) { + newDstFactor = flags.x0_blendMode > 6 ? GX::BL_ONE : GX::BL_INVSRCALPHA; } } - // TODO set fog color zero if dst blend zero - aurora::gfx::set_blend_mode(ERglBlendMode::Blend, newSrcFactor, newDstFactor, ERglLogicOp::Clear); + CGX::SetBlendMode(GX::BM_BLEND, newSrcFactor, newDstFactor, GX::LO_CLEAR); } void CCubeMaterial::HandleDepth(CModelFlagsFlags modelFlags, CCubeMaterialFlags matFlags) { - ERglEnum func = ERglEnum::Never; + GX::Compare func = GX::NEVER; if (!(modelFlags & CModelFlagBits::DepthTest)) { - func = ERglEnum::Always; + func = GX::ALWAYS; } else if (modelFlags & CModelFlagBits::DepthGreater) { - func = modelFlags & CModelFlagBits::DepthNonInclusive ? ERglEnum::Greater : ERglEnum::GEqual; + func = modelFlags & CModelFlagBits::DepthNonInclusive ? GX::GREATER : GX::GEQUAL; } else { - func = modelFlags & CModelFlagBits::DepthNonInclusive ? ERglEnum::Less : ERglEnum::LEqual; + func = modelFlags & CModelFlagBits::DepthNonInclusive ? GX::LESS : GX::LEQUAL; } bool depthWrite = modelFlags & CModelFlagBits::DepthUpdate && matFlags & CCubeMaterialFlagBits::fDepthWrite; - aurora::gfx::set_depth_mode(true, func, depthWrite); + CGX::SetZMode(true, func, depthWrite); } void CCubeMaterial::ResetCachedMaterials() { @@ -305,39 +301,40 @@ void CCubeMaterial::EnsureViewDepStateCached(const CCubeSurface* surface) { u32 CCubeMaterial::HandleColorChannels(u32 chanCount, u32 firstChan) { if (CCubeModel::sRenderModelShadow) { if (chanCount != 0) { - aurora::gfx::set_chan_amb_color(GX::COLOR1A1, zeus::skBlack); - aurora::gfx::set_chan_mat_color(GX::COLOR1A1, zeus::skWhite); + CGX::SetChanAmbColor(CGX::EChannelId::Channel1, zeus::skBlack); + CGX::SetChanMatColor(CGX::EChannelId::Channel1, zeus::skWhite); - // TODO chan / lights - - aurora::gfx::set_chan_mat_color(GX::COLOR0A0, zeus::skWhite); + auto chan0Lights = CGraphics::g_LightActive & ~CCubeModel::sChannel0DisableLightMask; + CGX::SetChanCtrl(CGX::EChannelId::Channel0, chan0Lights); // TODO use firstChan flags + CGX::SetChanCtrl(CGX::EChannelId::Channel1, CCubeModel::sChannel1EnableLightMask); + if (chan0Lights.any()) { + CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite); + } else { + CGX::SetChanMatColor(CGX::EChannelId::Channel0, CGX::GetChanAmbColor(CGX::EChannelId::Channel0)); + } } return 2; } if (chanCount == 2) { - aurora::gfx::set_chan_amb_color(GX::COLOR1A1, zeus::skBlack); - aurora::gfx::set_chan_mat_color(GX::COLOR1A1, zeus::skWhite); + CGX::SetChanAmbColor(CGX::EChannelId::Channel1, zeus::skBlack); + CGX::SetChanMatColor(CGX::EChannelId::Channel1, zeus::skWhite); } else { - // TODO chan ctrls + CGX::SetChanCtrl(CGX::EChannelId::Channel1, {}); } if (chanCount == 0) { - // TODO more chan ctrls + CGX::SetChanCtrl(CGX::EChannelId::Channel0, {}); } else { - auto uVar3 = firstChan & 0xfffffffe; - // TODO enabled lights - // TODO chan ctrl - // if (sEnabledLights == 0) { - // aurora::gfx::set_chan_mat_color(GX::COLOR0A0, amb_clr); - // } else { - aurora::gfx::set_chan_mat_color(GX::COLOR0A0, zeus::skWhite); - // } + // TODO use firstChan flags + CGX::SetChanCtrl(CGX::EChannelId::Channel0, CGraphics::g_LightActive); + if (CGraphics::g_LightActive.any()) { + CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite); + } else { + CGX::SetChanMatColor(CGX::EChannelId::Channel0, CGX::GetChanAmbColor(CGX::EChannelId::Channel0)); + } } - // TODO - aurora::gfx::set_chan_mat_src(GX::COLOR0A0, GX::SRC_REG); - aurora::gfx::set_chan_mat_src(GX::COLOR1A1, GX::SRC_REG); return chanCount; } @@ -348,27 +345,15 @@ void CCubeMaterial::HandleTev(u32 tevCur, const u32* materialDataCur, const u32* const u32 colorOps = SBig(materialDataCur[2]); const u32 alphaOps = SBig(materialDataCur[3]); - // GXSetTevDirect(tevCur); - const CTevCombiners::ColorPass colPass{colorArgs}; - const CTevCombiners::AlphaPass alphaPass{alphaArgs}; - const CTevCombiners::CTevOp colorOp{colorOps}; - const CTevCombiners::CTevOp alphaOp{alphaOps}; - // TODO does this actually change anything? - // if (colorOps == alphaOps && ((colorOps & 0x1FF) == 0x100)) { - // colorOp = {true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, colorOp.x10_regId}; - // alphaOp = {true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, colorOp.x10_regId}; - // } - aurora::gfx::update_tev_stage(static_cast(tevCur), colPass, alphaPass, colorOp, alphaOp); + const auto stage = static_cast(tevCur); + CGX::SetStandardDirectTev_Compressed(stage, colorArgs, alphaArgs, colorOps, alphaOps); u32 tmtcFlags = SBig(*texMapTexCoordFlags); u32 matFlags = SBig(materialDataCur[4]); - aurora::gfx::set_tev_order(static_cast(tevCur), static_cast(tmtcFlags & 0xFF), - static_cast(tmtcFlags >> 8 & 0xFF), - static_cast(matFlags & 0xFF)); - aurora::gfx::set_tev_k_color_sel(static_cast(tevCur), - static_cast(matFlags >> 0x8 & 0xFF)); - aurora::gfx::set_tev_k_alpha_sel(static_cast(tevCur), - static_cast(matFlags >> 0x10 & 0xFF)); + CGX::SetTevOrder(stage, static_cast(tmtcFlags & 0xFF), + static_cast(tmtcFlags >> 8 & 0xFF), static_cast(matFlags & 0xFF)); + CGX::SetTevKColorSel(stage, static_cast(matFlags >> 0x8 & 0xFF)); + CGX::SetTevKAlphaSel(stage, static_cast(matFlags >> 0x10 & 0xFF)); } u32 CCubeMaterial::HandleAnimatedUV(const u32* uvAnim, u32 texMtx, u32 pttTexMtx) { @@ -405,76 +390,56 @@ void CCubeMaterial::HandleTransparency(u32& finalTevCount, u32& finalKColorCount u32 blendFactors, u32& finalCCFlags, u32& finalACFlags) { if (modelFlags.x0_blendMode == 2) { u16 dstFactor = blendFactors >> 16 & 0xffff; - if (dstFactor == 1) + if (dstFactor == 1) { return; + } } if (modelFlags.x0_blendMode == 3) { // Stage outputting splatted KAlpha as color to reg0 - aurora::gfx::update_tev_stage(static_cast(finalTevCount), - CTevCombiners::ColorPass{GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_KONST}, - CTevCombiners::AlphaPass{GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV}, - CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVREG0}, - CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVPREV}); - // 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 - aurora::gfx::set_tev_k_color_sel(static_cast(finalTevCount), - static_cast(finalKColorCount + GX::TEV_KCSEL_K0_A)); - // GXSetTevKColorSel(finalTevCount, finalKColorCount+28); - // GXSetTevAlphaOp(finalTevCount, 0, 0, 0, 1, 0); // AlphaRegPrev - // GXSetTevOrder(finalTevCount, 255, 255, 255); - // GXSetTevDirect(finalTevCount); + auto stage = static_cast(finalTevCount); + CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_KONST); + CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV); + CGX::SetTevColorOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVREG0); + CGX::SetTevKColorSel(stage, static_cast(finalKColorCount + GX::TEV_KCSEL_K0_A)); + CGX::SetTevAlphaOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV); + CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL); + CGX::SetTevDirect(stage); + // Stage interpolating from splatted KAlpha using KColor - aurora::gfx::update_tev_stage(static_cast(finalTevCount + 1), - CTevCombiners::ColorPass{GX::CC_CPREV, GX::CC_C0, GX::CC_KONST, GX::CC_ZERO}, - CTevCombiners::AlphaPass{GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV}, - CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVPREV}, - CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVPREV}); - // GXSetTevColorIn(finalTevCount + 1, TEVCOLORARG_CPREV, TEVCOLORARG_C0, TEVCOLORARG_KONST, TEVCOLORARG_ZERO); - // GXSetTevAlphaIn(finalTevCount + 1, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_APREV); - aurora::gfx::set_tev_k_color_sel(static_cast(finalTevCount + 1), - static_cast(finalKColorCount + GX::TEV_KCSEL_K0)); - // GXSetTevKColorSel(finalTevCount, finalKColorCount+12); - // SetStandardTevColorAlphaOp(finalTevCount + 1); - // GXSetTevDirect(finalTevCount + 1); - // GXSetTevOrder(finalTevCount + 1, 255, 255, 255); - aurora::gfx::set_tev_k_color(static_cast(finalKColorCount), modelFlags.x4_color); - // GXSetTevKColor(finalKColorCount, modelFlags.x4_color); + stage = static_cast(stage + 1); + CGX::SetTevColorIn(stage, GX::CC_CPREV, GX::CC_C0, GX::CC_KONST, GX::CC_ZERO); + CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV); + CGX::SetTevKColorSel(stage, static_cast(finalKColorCount + GX::TEV_KCSEL_K0)); + CGX::SetStandardTevColorAlphaOp(stage); + CGX::SetTevDirect(stage); + CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL); + CGX::SetTevKColor(static_cast(finalKColorCount), modelFlags.x4_color); + finalKColorCount += 1; finalTevCount += 2; } else { - // Mul KAlpha - CTevCombiners::AlphaPass alphaPass{GX::CA_ZERO, GX::CA_KONST, GX::CA_APREV, GX::CA_ZERO}; - u32 tevAlpha = 0x000380C7; // TEVALPHAARG_ZERO, TEVALPHAARG_KONST, TEVALPHAARG_APREV, TEVALPHAARG_ZERO + auto stage = static_cast(finalTevCount); if (modelFlags.x0_blendMode == 8) { - // Set KAlpha - alphaPass = {GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_KONST}; - tevAlpha = 0x00031CE7; // TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_KONST + CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_KONST); // Set KAlpha + } else { + CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_KONST, GX::CA_APREV, GX::CA_ZERO); // Mul KAlpha } - // Mul KColor - CTevCombiners::ColorPass colorPass{GX::CC_ZERO, GX::CC_KONST, GX::CC_CPREV, GX::CC_ZERO}; - u32 tevColor = 0x000781CF; // TEVCOLORARG_ZERO, TEVCOLORARG_KONST, TEVCOLORARG_CPREV, TEVCOLORARG_ZERO if (modelFlags.x0_blendMode == 2) { - // Add KColor - colorPass = {GX::CC_ZERO, GX::CC_ONE, GX::CC_CPREV, GX::CC_KONST}; - tevColor = 0x0007018F; // TEVCOLORARG_ZERO, TEVCOLORARG_ONE, TEVCOLORARG_CPREV, TEVCOLORARG_KONST + CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_ONE, GX::CC_CPREV, GX::CC_KONST); // Add KColor + } else { + CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_KONST, GX::CC_CPREV, GX::CC_ZERO); // Mul KColor } - aurora::gfx::update_tev_stage(static_cast(finalTevCount), colorPass, alphaPass, {}, {}); - // GXSetTevColorIn(finalTevCount) - // GXSetTevAlphaIn(finalTevCount) - // SetStandardTevColorAlphaOp(finalTevCount); + CGX::SetStandardTevColorAlphaOp(stage); + finalCCFlags = 0x100; // Just clamp, output prev reg finalACFlags = 0x100; - // GXSetTevDirect(finalTevCount); - // GXSetTevOrder(finalTevCount, 255, 255, 255); - aurora::gfx::set_tev_k_color(static_cast(finalKColorCount), modelFlags.x4_color); - // GXSetTevKColor(finalKColorCount, modelFlags.x4_color); - aurora::gfx::set_tev_k_color_sel(static_cast(finalTevCount), - static_cast(finalKColorCount + GX::TEV_KCSEL_K0)); - // GXSetTevKColorSel(finalTevCount, finalKColorCount+12); - aurora::gfx::set_tev_k_alpha_sel(static_cast(finalTevCount), - static_cast(finalKColorCount + GX::TEV_KASEL_K0_A)); - // GXSetTevKAlphaSel(finalTevCount, finalKColorCount+28); + + CGX::SetTevDirect(stage); + CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL); + CGX::SetTevKColor(static_cast(finalKColorCount), modelFlags.x4_color); + CGX::SetTevKColorSel(stage, static_cast(finalKColorCount + GX::TEV_KCSEL_K0)); + CGX::SetTevKAlphaSel(stage, static_cast(finalKColorCount + GX::TEV_KASEL_K0_A)); + finalTevCount += 1; finalKColorCount += 1; } @@ -483,16 +448,20 @@ void CCubeMaterial::HandleTransparency(u32& finalTevCount, u32& finalKColorCount u32 CCubeMaterial::HandleReflection(bool usesTevReg2, u32 indTexSlot, u32 r5, u32 finalTevCount, u32 texCount, u32 tcgCount, u32 finalKColorCount, u32& finalCCFlags, u32& finalACFlags) { u32 out = 0; + GX::TevColorArg colorArg = GX::CC_KONST; if (usesTevReg2) { - // GX_CC_C2 + colorArg = GX::CC_C2; + const auto stage = static_cast(finalTevCount); + CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_C2, GX::CC_KONST, GX::CC_ZERO); + CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_A2); + CGX::SetTevColorOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVREG2); + CGX::SetTevAlphaOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVREG2); + CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_ZERO); out = 1; - } else { - // GX_CC_KONST } - aurora::gfx::set_tev_k_color(static_cast(finalKColorCount), - zeus::CColor{sReflectionAlpha, sReflectionAlpha}); - aurora::gfx::set_tev_k_color_sel(static_cast(finalTevCount), - static_cast(GX::TEV_KCSEL_K0 + finalKColorCount)); + CGX::SetTevKColor(static_cast(finalKColorCount), zeus::CColor{sReflectionAlpha, sReflectionAlpha}); + CGX::SetTevKColorSel(static_cast(finalTevCount), + static_cast(GX::TEV_KCSEL_K0 + finalKColorCount)); const auto stage = static_cast(finalTevCount + out); // tex = g_Renderer->GetRealReflection @@ -505,11 +474,16 @@ u32 CCubeMaterial::HandleReflection(bool usesTevReg2, u32 indTexSlot, u32 r5, u3 // aurora::gfx::set_tev_order(stage, ...) - return out + 1; + return out; //+ 1; } void CCubeMaterial::DoPassthru(u32 finalTevCount) { - aurora::gfx::disable_tev_stage(static_cast(finalTevCount)); + const auto stage = static_cast(finalTevCount); + CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_CPREV); + CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV); + CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL); + CGX::SetTevDirect(stage); + CGX::SetStandardTevColorAlphaOp(stage); } void CCubeMaterial::DoModelShadow(u32 texCount, u32 tcgCount) { @@ -523,8 +497,8 @@ void CCubeMaterial::EnsureTevsDirect() { return; } - // CGX::SetNumIndStages(0); - // CGX::SetTevDirect(sCurrentTevStage); + CGX::SetNumIndStages(0); + CGX::SetTevDirect(sCurrentTevStage); sCurrentTevStage = GX::NULL_STAGE; } } // namespace metaforce diff --git a/Runtime/Graphics/CCubeModel.cpp b/Runtime/Graphics/CCubeModel.cpp index e0271c10d..9bb93f4a0 100644 --- a/Runtime/Graphics/CCubeModel.cpp +++ b/Runtime/Graphics/CCubeModel.cpp @@ -5,22 +5,20 @@ #include "Graphics/CCubeSurface.hpp" #include "Graphics/CGraphics.hpp" #include "Graphics/CModel.hpp" - -#include +#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::CTransform sTextureProjectionTransform; -static u8 sChannel0DisableLightMask = 0; -static u8 sChannel1EnableLightMask = 0; - static zeus::CVector3f sPlayerPosition; CCubeModel::CCubeModel(std::vector* surfaces, std::vector>* textures, @@ -159,8 +157,8 @@ void CCubeModel::DrawFlat(TConstVectorRef positions, TConstVectorRef normals, ES const auto* surface = x38_firstUnsortedSurf; while (surface != nullptr) { const auto mat = GetMaterialByIndex(surface->GetMaterialIndex()); - aurora::gfx::model::set_vtx_desc_compressed(mat.GetVertexDesc()); - aurora::gfx::model::queue_surface(surface->GetDisplayList(), surface->GetDisplayListSize()); + CGX::SetVtxDescv_Compressed(mat.GetVertexDesc()); + CGX::CallDisplayList(surface->GetDisplayList(), surface->GetDisplayListSize()); surface = surface->GetNextSurface(); } } @@ -168,19 +166,23 @@ void CCubeModel::DrawFlat(TConstVectorRef positions, TConstVectorRef normals, ES const auto* surface = x3c_firstSortedSurf; while (surface != nullptr) { const auto mat = GetMaterialByIndex(surface->GetMaterialIndex()); - aurora::gfx::model::set_vtx_desc_compressed(mat.GetVertexDesc()); - aurora::gfx::model::queue_surface(surface->GetDisplayList(), surface->GetDisplayListSize()); + CGX::SetVtxDescv_Compressed(mat.GetVertexDesc()); + CGX::CallDisplayList(surface->GetDisplayList(), surface->GetDisplayListSize()); surface = surface->GetNextSurface(); } } } void CCubeModel::DrawNormal(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces) { - CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); - CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassZero); - CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); - // TODO update fog - CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::Zero, ERglBlendFactor::One, ERglLogicOp::Clear); + 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); } @@ -210,7 +212,7 @@ void CCubeModel::DrawSurface(const CCubeSurface& surface, const CModelFlags& fla auto mat = GetMaterialByIndex(surface.GetMaterialIndex()); if (!mat.GetFlags().IsSet(CCubeMaterialFlagBits::fShadowOccluderMesh) || sDrawingOccluders) { mat.SetCurrent(flags, surface, *this); - aurora::gfx::model::queue_surface(surface.GetDisplayList(), surface.GetDisplayListSize()); + CGX::CallDisplayList(surface.GetDisplayList(), surface.GetDisplayListSize()); } } @@ -245,8 +247,8 @@ void CCubeModel::DrawSurfaceWireframe(const CCubeSurface& surface) { // TODO convert vertices to line strips and draw } -void CCubeModel::EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, u8 chan0DisableMask, - u8 chan1EnableLightMask) { +void CCubeModel::EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, + GX::LightMask chan0DisableMask, GX::LightMask chan1EnableLightMask) { sRenderModelShadow = true; sShadowTexture = &shadowTex; sTextureProjectionTransform = textureProjXf; @@ -257,8 +259,8 @@ void CCubeModel::EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransf void CCubeModel::DisableShadowMaps() { sRenderModelShadow = false; } void CCubeModel::SetArraysCurrent() { - aurora::gfx::model::set_vertex_buffer(x0_modelInstance.GetVertexPointer()); - aurora::gfx::model::set_normal_buffer(x0_modelInstance.GetNormalPointer()); + CGX::SetArray(GX::VA_POS, x0_modelInstance.GetVertexPointer()); + CGX::SetArray(GX::VA_NRM, x0_modelInstance.GetNormalPointer()); SetStaticArraysCurrent(); } @@ -278,8 +280,8 @@ void CCubeModel::SetRenderModelBlack(bool v) { } void CCubeModel::SetSkinningArraysCurrent(TConstVectorRef positions, TConstVectorRef normals) { - aurora::gfx::model::set_vertex_buffer(positions); - aurora::gfx::model::set_normal_buffer(normals); + CGX::SetArray(GX::VA_POS, positions); + CGX::SetArray(GX::VA_NRM, normals); // colors unused SetStaticArraysCurrent(); } @@ -292,20 +294,21 @@ void CCubeModel::SetStaticArraysCurrent() { sUsingPackedLightmaps = false; } if (sUsingPackedLightmaps) { - aurora::gfx::model::set_tex0_tc_buffer(packedTexCoords); + CGX::SetArray(GX::VA_TEX0, packedTexCoords); } else { - aurora::gfx::model::set_tex0_tc_buffer(texCoords); + CGX::SetArray(GX::VA_TEX0, texCoords); } - aurora::gfx::model::set_tc_buffer(texCoords); + // TexCoord1 is currently used for all remaining + CGX::SetArray(GX::VA_TEX1, texCoords); CCubeMaterial::KillCachedViewDepState(); } void CCubeModel::SetUsingPackedLightmaps(bool v) { sUsingPackedLightmaps = v; if (v) { - aurora::gfx::model::set_tex0_tc_buffer(x0_modelInstance.GetPackedTCPointer()); + CGX::SetArray(GX::VA_TEX0, x0_modelInstance.GetPackedTCPointer()); } else { - aurora::gfx::model::set_tex0_tc_buffer(x0_modelInstance.GetTCPointer()); + CGX::SetArray(GX::VA_TEX0, x0_modelInstance.GetTCPointer()); } } diff --git a/Runtime/Graphics/CCubeModel.hpp b/Runtime/Graphics/CCubeModel.hpp index 9089e6107..334a7c045 100644 --- a/Runtime/Graphics/CCubeModel.hpp +++ b/Runtime/Graphics/CCubeModel.hpp @@ -26,6 +26,7 @@ using TConstVectorRef = const std::vector*; class CCubeModel { friend class CModel; + friend class CCubeMaterial; private: class ModelInstance { @@ -110,8 +111,8 @@ public: [[nodiscard]] TConstVectorRef GetNormals() const { return x0_modelInstance.GetNormalPointer(); } [[nodiscard]] TCachedToken& GetTexture(u32 idx) const { return x1c_textures->at(idx); } - static void EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, u8 chan0DisableMask, - u8 chan1EnableLightMask); + static void EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, + GX::LightMask chan0DisableMask, GX::LightMask chan1EnableLightMask); static void DisableShadowMaps(); static void MakeTexturesFromMats(const u8* ptr, std::vector>& texture, IObjectStore* store, bool b1); @@ -120,11 +121,6 @@ public: 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(TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags); void DrawAlphaSurfaces(const CModelFlags& flags); @@ -132,5 +128,13 @@ private: void DrawSurfaces(const CModelFlags& flags); void SetSkinningArraysCurrent(TConstVectorRef positions, TConstVectorRef normals); void SetStaticArraysCurrent(); + + static bool sRenderModelBlack; + static bool sUsingPackedLightmaps; + static bool sRenderModelShadow; + static const CTexture* sShadowTexture; + static zeus::CTransform sTextureProjectionTransform; + static GX::LightMask sChannel0DisableLightMask; + static GX::LightMask sChannel1EnableLightMask; }; } // namespace metaforce diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index 179460bb0..48e87fd5b 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -1,15 +1,16 @@ #include "Runtime/Graphics/CCubeRenderer.hpp" #include "Runtime/GameGlobalObjects.hpp" -#include "Runtime/Graphics/CDrawable.hpp" -#include "Runtime/Graphics/CMetroidModelInstance.hpp" -#include "Runtime/Graphics/CDrawablePlaneObject.hpp" -#include "Runtime/Graphics/CLight.hpp" -#include "Runtime/Graphics/CModel.hpp" -#include "Runtime/Particle/CParticleGen.hpp" +#include "Runtime/Graphics/CCubeMaterial.hpp" #include "Runtime/Graphics/CCubeModel.hpp" #include "Runtime/Graphics/CCubeSurface.hpp" -#include "Runtime/Graphics/CCubeMaterial.hpp" +#include "Runtime/Graphics/CDrawable.hpp" +#include "Runtime/Graphics/CDrawablePlaneObject.hpp" +#include "Runtime/Graphics/CGX.hpp" +#include "Runtime/Graphics/CLight.hpp" +#include "Runtime/Graphics/CMetroidModelInstance.hpp" +#include "Runtime/Graphics/CModel.hpp" +#include "Runtime/Particle/CParticleGen.hpp" namespace metaforce { static logvisor::Module Log("CCubeRenderer"); @@ -197,15 +198,35 @@ CCubeRenderer::CCubeRenderer(IObjectStore& store, IFactory& resFac) : x8_factory CCubeRenderer::~CCubeRenderer() { g_Renderer = nullptr; } -void CCubeRenderer::GenerateReflectionTex() {} -void CCubeRenderer::GenerateFogVolumeRampTex() {} -void CCubeRenderer::GenerateSphereRampTex() {} -void CCubeRenderer::LoadThermoPalette() {} -void CCubeRenderer::ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, const CTexture& maskTex, - const CTexture& indTex, const zeus::CColor& modColor, - float scale, float offX, float offY) {} -void CCubeRenderer::ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, const CTexture& maskTex) {} -void CCubeRenderer::DoPhazonSuitIndirectAlphaBlur(float blurRadius, float f2, const TLockedToken& indTex) {} +void CCubeRenderer::GenerateReflectionTex() { + // TODO +} + +void CCubeRenderer::GenerateFogVolumeRampTex() { + // TODO +} + +void CCubeRenderer::GenerateSphereRampTex() { + // TODO +} + +void CCubeRenderer::LoadThermoPalette() { + // TODO +} + +void CCubeRenderer::ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, CTexture& maskTex, + CTexture& indTex, const zeus::CColor& modColor, float scale, + float offX, float offY) { + // TODO +} + +void CCubeRenderer::ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, CTexture& maskTex) { + // TODO +} + +void CCubeRenderer::DoPhazonSuitIndirectAlphaBlur(float blurRadius, float f2, const TLockedToken& indTex) { + // TODO +} void CCubeRenderer::AddWorldSurfaces(CCubeModel& model) { for (auto* it = model.GetFirstSortedSurface(); it != nullptr; it = it->GetNextSurface()) { @@ -216,6 +237,7 @@ void CCubeRenderer::AddWorldSurfaces(CCubeModel& model) { Buckets::Insert(pos, bounds, EDrawableType::WorldSurface, it, xb0_viewPlane, static_cast(blend == 0x50004)); } } + void CCubeRenderer::AddStaticGeometry(const std::vector* geometry, const CAreaRenderOctTree* octTree, s32 areaIdx) { auto search = FindStaticGeometry(geometry); @@ -448,7 +470,11 @@ void CCubeRenderer::RenderBucketItems(const CAreaListItem* item) { } } } -void CCubeRenderer::PostRenderFogs() {} + +void CCubeRenderer::PostRenderFogs() { + // TODO +} + void CCubeRenderer::SetModelMatrix(const zeus::CTransform& xf) { CGraphics::SetModelMatrix(xf); } void CCubeRenderer::HandleUnsortedModel(CAreaListItem* areaItem, CCubeModel& model, const CModelFlags& flags) { @@ -473,7 +499,10 @@ void CCubeRenderer::HandleUnsortedModelWireframe(CAreaListItem* areaItem, CCubeM } } -void CCubeRenderer::ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model) {} +void CCubeRenderer::ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model) { + // TODO +} + void CCubeRenderer::AddParticleGen(CParticleGen& gen) { auto bounds = gen.GetBounds(); @@ -575,8 +604,8 @@ void CCubeRenderer::BeginScene() { } // GXSetPixelFmt(x318_26_requestRGBA6, GX_ZC_LINEAR); - aurora::gfx::set_alpha_update(true); - aurora::gfx::set_dst_alpha(true, 0.f); + GXSetAlphaUpdate(true); + GXSetDstAlpha(true, 0.f); CGraphics::BeginScene(); } @@ -607,64 +636,164 @@ void CCubeRenderer::BeginPrimitive(IRenderer::EPrimitiveType type, s32 nverts) { x18_primVertCount = nverts; CGraphics::StreamBegin(GX::Primitive(type)); } + void CCubeRenderer::BeginLines(s32 nverts) { BeginPrimitive(EPrimitiveType::Lines, nverts); } + void CCubeRenderer::BeginLineStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::LineStrip, nverts); } + void CCubeRenderer::BeginTriangles(s32 nverts) { BeginPrimitive(EPrimitiveType::Triangles, nverts); } + void CCubeRenderer::BeginTriangleStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleStrip, nverts); } + void CCubeRenderer::BeginTriangleFan(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleFan, nverts); } + void CCubeRenderer::PrimVertex(const zeus::CVector3f& vertex) { --x18_primVertCount; CGraphics::StreamColor(x2e0_primColor); CGraphics::StreamNormal(x2e4_primNormal); CGraphics::StreamVertex(vertex); } + void CCubeRenderer::PrimNormal(const zeus::CVector3f& normal) { x2e4_primNormal = normal; } + void CCubeRenderer::PrimColor(float r, float g, float b, float a) { PrimColor({r, g, b, a}); } + void CCubeRenderer::PrimColor(const zeus::CColor& color) { x2e0_primColor = color; } + void CCubeRenderer::EndPrimitive() { while (x18_primVertCount > 0) { PrimVertex(zeus::skZero3f); } CGraphics::StreamEnd(); } + void CCubeRenderer::SetAmbientColor(const zeus::CColor& color) { CGraphics::SetAmbientColor(color); } + void CCubeRenderer::DrawString(const char* string, s32 x, s32 y) { x10_font.DrawString(string, x, y, zeus::skWhite); } u32 CCubeRenderer::GetFPS() { return CGraphics::GetFPS(); } -void CCubeRenderer::CacheReflection(IRenderer::TReflectionCallback cb, void* ctx, bool clearAfter) {} -void CCubeRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) {} -void CCubeRenderer::DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, - TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {} -void CCubeRenderer::DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color, - TConstVectorRef positions, TConstVectorRef normals) {} -void CCubeRenderer::DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) {} -void CCubeRenderer::SetWireframeFlags(s32 flags) {} -void CCubeRenderer::SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) {} -void CCubeRenderer::RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, - const TLockedToken* model, const CSkinnedModel* sModel) {} -void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& color) {} -void CCubeRenderer::SetThermalColdScale(float scale) {} -void CCubeRenderer::DoThermalBlendCold() {} -void CCubeRenderer::DoThermalBlendHot() {} -u32 CCubeRenderer::GetStaticWorldDataSize() { return 0; } -void CCubeRenderer::SetGXRegister1Color(const zeus::CColor& color) { - aurora::gfx::set_tev_reg_color(GX::TevRegID::TEVREG1, color); +void CCubeRenderer::CacheReflection(IRenderer::TReflectionCallback cb, void* ctx, bool clearAfter) { + // TODO } +void CCubeRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) { + // TODO +} + +void CCubeRenderer::DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, + TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) { + model.UpdateLastFrame(); + // TODO + // DoThermalModelDraw(model.GetInstance(), multCol, addCol, positions, normals, flags); +} + +void CCubeRenderer::DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color, + TConstVectorRef positions, TConstVectorRef normals, float t) { + tex.Load(GX::TEXMAP0, EClampMode::Clamp); + CGX::SetNumIndStages(0); + CGX::SetNumTevStages(2); + CGX::SetNumTexGens(2); + CGX::SetNumChans(0); + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_SRCALPHA, GX::BL_INVSRCALPHA, GX::LO_CLEAR); + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0); + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE1); + CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_TEXC); + CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_TEXA); + CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_TEXC, GX::CC_CPREV, GX::CC_KONST); + CGX::SetTevAlphaIn(GX::TEVSTAGE1, GX::CA_ZERO, GX::CA_TEXA, GX::CA_APREV, GX::CA_ZERO); + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL); + CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP0, GX::COLOR_NULL); + CGX::SetTevKColorSel(GX::TEVSTAGE1, GX::TEV_KCSEL_K0); + CGX::SetTevKColor(GX::KCOLOR0, color); + // TODO +} + +void CCubeRenderer::DrawModelFlat(CModel& model, const CModelFlags& flags, bool unsortedOnly, TConstVectorRef positions, + TConstVectorRef normals) { + if (flags.x0_blendMode >= 7) { + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_SRCALPHA, GX::BL_ONE, GX::LO_CLEAR); + } else if (flags.x0_blendMode >= 5) { + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_SRCALPHA, GX::BL_INVSRCALPHA, GX::LO_CLEAR); + } else { + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR); + } + CGX::SetZMode(true, flags.x2_flags & CModelFlagBits::DepthTest ? GX::LEQUAL : GX::ALWAYS, + flags.x2_flags.IsSet(CModelFlagBits::DepthUpdate)); + CGX::SetNumTevStages(1); + CGX::SetNumTexGens(1); + CGX::SetNumChans(0); + CGX::SetNumIndStages(0); + CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0); + CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_KONST); + CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_KONST); + CGX::SetTevKColor(GX::KCOLOR0, flags.x4_color); + CGX::SetTevKColorSel(GX::TEVSTAGE0, GX::TEV_KCSEL_K0); + CGX::SetTevKAlphaSel(GX::TEVSTAGE0, GX::TEV_KASEL_K0_A); + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL); + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0); + CGX::SetTevDirect(GX::TEVSTAGE0); + CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_POS, GX::IDENTITY, false, GX::PTIDENTITY); + model.UpdateLastFrame(); + model.GetInstance().DrawFlat(positions, normals, unsortedOnly ? ESurfaceSelection::Unsorted : ESurfaceSelection::All); +} + +void CCubeRenderer::SetWireframeFlags(s32 flags) { + // TODO +} + +void CCubeRenderer::SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) { + // TODO +} + +void CCubeRenderer::RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, + const TLockedToken* model, const CSkinnedModel* sModel) { + // TODO +} + +void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& color) { + // TODO +} + +void CCubeRenderer::SetThermalColdScale(float scale) { + // TODO +} + +void CCubeRenderer::DoThermalBlendCold() { + // TODO +} + +void CCubeRenderer::DoThermalBlendHot() { + // TODO +} + +u32 CCubeRenderer::GetStaticWorldDataSize() { + // TODO + return 0; +} + +void CCubeRenderer::SetGXRegister1Color(const zeus::CColor& color) { GXSetTevColor(GX::TevRegID::TEVREG1, color); } + void CCubeRenderer::SetWorldLightFadeLevel(float level) { x2fc_tevReg1Color = zeus::CColor(level, level, level, 1.f); } -void CCubeRenderer::PrepareDynamicLights(const std::vector& lights) {} -void CCubeRenderer::AllocatePhazonSuitMaskTexture() {} +void CCubeRenderer::PrepareDynamicLights(const std::vector& lights) { + // TODO +} + +void CCubeRenderer::AllocatePhazonSuitMaskTexture() { + // TODO +} void CCubeRenderer::DrawPhazonSuitIndirectEffect(const zeus::CColor& nonIndirectMod, const TLockedToken& indTex, const zeus::CColor& indirectMod, float blurRadius, float scale, float offX, float offY) { // TODO - aurora::gfx::set_dst_alpha(false, 0.f); + GXSetDstAlpha(false, 0.f); } -void CCubeRenderer::DrawXRayOutline(const zeus::CAABox& aabb) {} +void CCubeRenderer::DrawXRayOutline(const zeus::CAABox& aabb) { + // TODO +} std::list::iterator CCubeRenderer::FindStaticGeometry(const std::vector* geometry) { @@ -687,9 +816,10 @@ void CCubeRenderer::SetupCGraphicsState() { CGraphics::SetModelMatrix({}); CTevCombiners::ResetStates(); CGraphics::SetAmbientColor({0.4f}); - // CGX::SetChanMatColor(EChannelId::Channel0, GX::Color{0xFFFFFFFF}); + CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite); CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); - // CGX::SetChanCtrl(EChannelId::Channel1, false, GX::SRC_REG, GX::LIGHT_NULL, GX::DF_NONE, GX::AF_NONE); + CGX::SetChanCtrl(CGX::EChannelId::Channel1, false, GX::SRC_REG, GX::SRC_REG, GX::LIGHT_NULL, GX::DF_NONE, + GX::AF_NONE); CCubeMaterial::EnsureTevsDirect(); } @@ -699,6 +829,6 @@ void CCubeRenderer::SetupRendererStates(bool depthWrite) { CGraphics::SetAmbientColor(zeus::skBlack); CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, depthWrite); CCubeMaterial::ResetCachedMaterials(); - aurora::gfx::set_tev_reg_color(GX::TEVREG1, x2fc_tevReg1Color); + GXSetTevColor(GX::TEVREG1, x2fc_tevReg1Color); } } // namespace metaforce diff --git a/Runtime/Graphics/CCubeRenderer.hpp b/Runtime/Graphics/CCubeRenderer.hpp index 07d8aec5b..3df7f266f 100644 --- a/Runtime/Graphics/CCubeRenderer.hpp +++ b/Runtime/Graphics/CCubeRenderer.hpp @@ -97,10 +97,9 @@ private: void GenerateSphereRampTex(); void LoadThermoPalette(); - void ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, const CTexture& maskTex, - const CTexture& indTex, const zeus::CColor& modColor, float scale, float offX, - float offY); - void ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, const CTexture& maskTex); + void ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, CTexture& maskTex, CTexture& indTex, + const zeus::CColor& modColor, float scale, float offX, float offY); + void ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, CTexture& maskTex); void DoPhazonSuitIndirectAlphaBlur(float blurRadius, float f2, const TLockedToken& indTex); public: @@ -179,11 +178,12 @@ public: u32 GetFPS() override; void CacheReflection(TReflectionCallback cb, void* ctx, bool clearAfter) override; void DrawSpaceWarp(const zeus::CVector3f& pt, float strength) override; - void DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, + void DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) override; - void DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color, - TConstVectorRef positions, TConstVectorRef normals) override; - void DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) override; + void DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color, TConstVectorRef positions, + TConstVectorRef normals, float t) override; + void DrawModelFlat(CModel& model, const CModelFlags& flags, bool unsortedOnly, TConstVectorRef positions, + TConstVectorRef normals) override; void SetWireframeFlags(s32 flags) override; void SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) override; void RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, const TLockedToken* model, @@ -217,6 +217,9 @@ public: void ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model); + void DoThermalModelDraw(CCubeModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, + TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags); + // Getters [[nodiscard]] bool IsInAreaDraw() const { return x318_30_inAreaDraw; } [[nodiscard]] bool IsReflectionDirty() const { return x318_24_refectionDirty; } diff --git a/Runtime/Graphics/CGX.cpp b/Runtime/Graphics/CGX.cpp new file mode 100644 index 000000000..d1a9b73e0 --- /dev/null +++ b/Runtime/Graphics/CGX.cpp @@ -0,0 +1,30 @@ +#include "CGX.hpp" + +#include "Graphics/CTexture.hpp" + +namespace metaforce::CGX { +SGXState sGXState; + +void ResetGXStates() noexcept { + sGXState.x48_descList = nullptr; + // GXClearVtxDesc(); + sGXState.x0_arrayPtrs.fill(nullptr); + for (GX::TexMapID id = GX::TEXMAP0; id < GX::MAX_TEXMAP; id = static_cast(id + 1)) { + CTexture::InvalidateTexMap(id); + } + for (GX::TevKColorID id = GX::KCOLOR0; const auto& item : sGXState.x58_kColors) { + GXSetTevKColor(id, item); + id = static_cast(id + 1); + } + // GXSetTevSwapModeTable + SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0); + // GXSetCurrentMtx(0); + SetNumIndStages(0); + // TODO GXSetIndTexCoordScale + for (GX::TevStageID id = GX::TEVSTAGE0; id < GX::MAX_TEVSTAGE; id = static_cast(id + 1)) { + SetTevDirect(id); + } + // GXSetTexCoordCylWrap + // GXSetZTexture +} +} // namespace metaforce::CGX diff --git a/Runtime/Graphics/CGX.hpp b/Runtime/Graphics/CGX.hpp new file mode 100644 index 000000000..5bbe94b33 --- /dev/null +++ b/Runtime/Graphics/CGX.hpp @@ -0,0 +1,387 @@ +#pragma once + +#include "Graphics/GX.hpp" +#include "RetroTypes.hpp" + +#include +#include + +namespace metaforce::CGX { +enum class EChannelId { + Channel0, // GX::COLOR0 + Channel1, // GX::COLOR1 +}; + +struct STevState { + u32 x0_colorInArgs = 0; + u32 x4_alphaInArgs = 0; + u32 x8_colorOps = 0; + u32 xc_alphaOps = 0; + u32 x10_indFlags = 0; + u32 x14_tevOrderFlags = 0; + GX::TevKColorSel x18_kColorSel = GX::TEV_KCSEL_1; + GX::TevKAlphaSel x19_kAlphaSel = GX::TEV_KASEL_1; +}; +struct STexState { + u32 x0_coordGen = 0; +}; +struct SGXState { + std::array x0_arrayPtrs{}; + std::array x30_prevChanCtrls{}; + std::array x34_chanCtrls{}; + std::array x38_chanAmbColors; + std::array x40_chanMatColors; + GX::VtxDescList* x48_descList = nullptr; + u8 x4c_dirtyChans = 0; + u8 x4d_prevNumChans = 0; + u8 x4e_numChans = 0; + u8 x4f_numTexGens = 0; + u8 x50_numTevStages = 0; + u8 x51_numIndStages = 0; + u8 x52_zmode = 0; + GX::FogType x53_fogType = GX::FOG_NONE; + u16 x54_lineWidthAndOffset = 0; + u16 x56_blendMode = 0; + std::array x58_kColors; + std::array x68_tevStates; + std::array x228_texStates; + u32 x248_alphaCompare = 0; + float x24c_fogStartZ = 0.f; + float x250_fogEndZ = 0.f; + float x254_fogNearZ = 0.f; + float x258_fogFarZ = 0.f; + GXColor x25c_fogColor; +}; +extern SGXState sGXState; + +static inline void update_fog(u32 value) noexcept { + if (sGXState.x53_fogType == GX::FOG_NONE || (sGXState.x56_blendMode & 0xE0) == (value & 0xE0)) { + return; + } + if ((value & 0xE0) == 0x20) { + // TODO + return; + } + // TODO +} + +static inline void FlushState() noexcept { + if ((sGXState.x4c_dirtyChans & 1) != 0) { + u8 numChans = sGXState.x4e_numChans; + GXSetNumChans(numChans); + sGXState.x4d_prevNumChans = numChans; + } + if ((sGXState.x4c_dirtyChans & 2) != 0) { + // TODO actually COLOR0 + auto flags = sGXState.x34_chanCtrls[0]; + GXSetChanCtrl(GX::COLOR0A0, GXBool(flags & 1), GX::ColorSrc(flags >> 1 & 1), GX::ColorSrc(flags >> 2 & 1), + flags >> 3 & 0xFF, GX::DiffuseFn(flags >> 11 & 3), GX::AttnFn(flags >> 13 & 3)); + sGXState.x30_prevChanCtrls[0] = flags; + } + if ((sGXState.x4c_dirtyChans & 4) != 0) { + // TODO actually COLOR1 + auto flags = sGXState.x34_chanCtrls[1]; + GXSetChanCtrl(GX::COLOR1A1, GXBool(flags & 1), GX::ColorSrc(flags >> 1 & 1), GX::ColorSrc(flags >> 2 & 1), + flags >> 3 & 0xFF, GX::DiffuseFn(flags >> 11 & 3), GX::AttnFn(flags >> 13 & 3)); + sGXState.x30_prevChanCtrls[1] = flags; + } + sGXState.x4c_dirtyChans = 0; +} + +static inline void Begin(GX::Primitive primitive, GX::VtxFmt fmt, u16 nverts) noexcept { + if (sGXState.x4c_dirtyChans != 0) { + FlushState(); + } + // TODO GXBegin(type, fmt, nverts); +} + +static inline void CallDisplayList(const void* data, u32 nbytes) noexcept { + if (sGXState.x4c_dirtyChans != 0) { + FlushState(); + } + GXCallDisplayList(data, nbytes); +} + +static inline void End() noexcept { + // no-op +} + +static inline const GXColor& GetChanAmbColor(EChannelId id) noexcept { + const auto idx = std::underlying_type_t(id); + return sGXState.x38_chanAmbColors[idx]; +} + +void ResetGXStates() noexcept; + +static inline void SetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, GX::Compare comp1, u8 ref1) noexcept { + u32 flags = ref1 << 17 | (comp1 & 7) << 14 | (op & 7) << 11 | ref0 << 3 | (comp0 & 7); + if (flags != sGXState.x248_alphaCompare) { + sGXState.x248_alphaCompare = flags; + GXSetAlphaCompare(comp0, ref0 / 255.f, op, comp1, ref1 / 255.f); + // GXSetZCompLoc(comp0 == GX::ALWAYS); + } +} + +template +static inline void SetArray(GX::Attr attr, const std::vector* data) noexcept { + if (data != nullptr && sGXState.x0_arrayPtrs[attr - GX::VA_POS] != data) { + GXSetArray(attr, data, sizeof(T)); + } +} + +static inline void SetBlendMode(GX::BlendMode mode, GX::BlendFactor srcFac, GX::BlendFactor dstFac, + GX::LogicOp op) noexcept { + const u16 flags = (op & 0xF) << 8 | (dstFac & 7) << 5 | (srcFac & 7) << 2 | (mode & 3); + if (flags != sGXState.x56_blendMode) { + update_fog(flags); + sGXState.x56_blendMode = flags; + GXSetBlendMode(mode, srcFac, dstFac, op); + } +} + +static inline void SetChanAmbColor(EChannelId id, const GXColor& color) noexcept { + const auto idx = std::underlying_type_t(id); + if (color != sGXState.x38_chanAmbColors[idx]) { + sGXState.x38_chanAmbColors[idx] = color; + GXSetChanAmbColor(GX::ChannelID(idx + GX::COLOR0A0), color); + } +} + +static inline void SetChanCtrl(EChannelId id, GXBool enable, GX::ColorSrc ambSrc, GX::ColorSrc matSrc, + GX::LightMask lights, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept { + const auto idx = std::underlying_type_t(id); + const u32 flags = (attnFn & 3) << 13 | (diffFn & 3) << 11 | (lights.to_ulong() & 0xFF) << 3 | (matSrc & 1) << 2 | + (ambSrc & 1) << 1 | (u8(enable) & 1); + sGXState.x34_chanCtrls[idx] = flags; + sGXState.x4c_dirtyChans = 7; // TODO +} + +// Helper function for common logic +static inline void SetChanCtrl(EChannelId id, GX::LightMask lights) noexcept { + const bool hasLights = lights.any(); + SetChanCtrl(id, hasLights, GX::SRC_REG, GX::SRC_REG, lights, hasLights ? GX::DF_CLAMP : GX::DF_NONE, + hasLights ? GX::AF_SPOT : GX::AF_NONE); +} + +static inline void SetChanMatColor(EChannelId id, const GXColor& color) noexcept { + const auto idx = std::underlying_type_t(id); + if (color != sGXState.x40_chanMatColors[idx]) { + sGXState.x40_chanMatColors[idx] = color; + GXSetChanMatColor(GX::ChannelID(idx + GX::COLOR0A0), color); + } +} + +static inline void SetFog(GX::FogType type, float startZ, float endZ, float nearZ, float farZ, + const GXColor& color) noexcept { + sGXState.x25c_fogColor = color; + sGXState.x53_fogType = type; + sGXState.x24c_fogStartZ = startZ; + sGXState.x250_fogEndZ = endZ; + sGXState.x254_fogNearZ = nearZ; + sGXState.x258_fogFarZ = farZ; + auto fogColor = color; + if ((sGXState.x56_blendMode & 0xE0) == 0x20) { + fogColor = zeus::skClear; + } + // TODO + // GXSetFog(type, startZ, endZ, nearZ, farZ, fogColor); +} + +void SetIndTexMtxSTPointFive(GX::IndTexMtxID id, s8 scaleExp) noexcept; + +void SetLineWidth(u8 width, GX::TexOffset offset) noexcept; + +static inline void SetNumChans(u8 num) noexcept { + sGXState.x4c_dirtyChans = 7; // TODO + sGXState.x4e_numChans = num; +} + +static inline void SetNumIndStages(u8 num) noexcept { + auto& state = sGXState.x51_numIndStages; + if (num != state) { + state = num; + GXSetNumIndStages(num); + } +} + +static inline void SetNumTevStages(u8 num) noexcept { + auto& state = sGXState.x50_numTevStages; + if (num != state) { + state = num; + GXSetNumTevStages(num); + } +} + +static inline void SetNumTexGens(u8 num) noexcept { + auto& state = sGXState.x4f_numTexGens; + if (num != state) { + state = num; + GXSetNumTexGens(num); + } +} + +static inline void SetStandardTevColorAlphaOp(GX::TevStageID stageId) noexcept { + auto& state = sGXState.x68_tevStates[stageId]; + if (state.x8_colorOps != 0x100 || state.xc_alphaOps != 0x100) { + state.x8_colorOps = 0x100; + state.xc_alphaOps = 0x100; + GXSetTevColorOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV); + GXSetTevAlphaOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV); + } +} + +static inline void SetTevAlphaIn(GX::TevStageID stageId, GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c, + GX::TevAlphaArg d) noexcept { + u32 flags = (d & 31) << 15 | (c & 31) << 10 | (b & 31) << 5 | (a & 31); + auto& state = sGXState.x68_tevStates[stageId].x4_alphaInArgs; + if (flags != state) { + state = flags; + GXSetTevAlphaIn(stageId, a, b, c, d); + } +} + +static inline void SetTevAlphaOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, + GXBool clamp, GX::TevRegID outReg) noexcept { + u32 flags = (outReg & 3) << 9 | (u8(clamp) & 1) << 8 | (scale & 3) << 6 | (bias & 3) << 4 | (op & 15); + auto& state = sGXState.x68_tevStates[stageId].xc_alphaOps; + if (flags != state) { + state = flags; + GXSetTevAlphaOp(stageId, op, bias, scale, clamp, outReg); + } +} + +static inline void SetTevAlphaOp_Compressed(GX::TevStageID stageId, u32 ops) noexcept { + auto& state = sGXState.x68_tevStates[stageId].xc_alphaOps; + if (ops != state) { + state = ops; + GXSetTevAlphaOp(stageId, GX::TevOp(ops & 31), GX::TevBias(ops >> 4 & 3), GX::TevScale(ops >> 6 & 3), + GXBool(ops >> 8 & 1), GX::TevRegID(ops >> 9 & 3)); + } +} + +static inline void SetTevColorIn(GX::TevStageID stageId, GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c, + GX::TevColorArg d) noexcept { + u32 flags = (d & 31) << 15 | (c & 31) << 10 | (b & 31) << 5 | (a & 31); + auto& state = sGXState.x68_tevStates[stageId].x0_colorInArgs; + if (flags != state) { + state = flags; + GXSetTevColorIn(stageId, a, b, c, d); + } +} + +static inline void SetTevColorOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, + GXBool clamp, GX::TevRegID outReg) noexcept { + u32 flags = (outReg & 3) << 9 | (u8(clamp) & 1) << 8 | (scale & 3) << 6 | (bias & 3) << 4 | (op & 15); + auto& state = sGXState.x68_tevStates[stageId].x8_colorOps; + if (flags != state) { + state = flags; + GXSetTevColorOp(stageId, op, bias, scale, clamp, outReg); + } +} + +static inline void SetTevColorOp_Compressed(GX::TevStageID stageId, u32 ops) noexcept { + auto& state = sGXState.x68_tevStates[stageId].x8_colorOps; + if (ops != state) { + state = ops; + GXSetTevColorOp(stageId, GX::TevOp(ops & 31), GX::TevBias(ops >> 4 & 3), GX::TevScale(ops >> 6 & 3), + GXBool(ops >> 8 & 1), GX::TevRegID(ops >> 9 & 3)); + } +} + +static inline void SetTevDirect(GX::TevStageID stageId) noexcept { + auto& state = sGXState.x68_tevStates[stageId].x10_indFlags; + if (state != 0) { + state = 0; + // TODO + // GXSetTevDirect(stageId); + } +} + +static inline void SetStandardDirectTev_Compressed(GX::TevStageID stageId, u32 colorArgs, u32 alphaArgs, u32 colorOps, + u32 alphaOps) noexcept { + auto& state = sGXState.x68_tevStates[stageId]; + SetTevDirect(stageId); + if (state.x0_colorInArgs != colorArgs) { + state.x0_colorInArgs = colorArgs; + GXSetTevColorIn(stageId, GX::TevColorArg(colorArgs & 31), GX::TevColorArg(colorArgs >> 5 & 31), + GX::TevColorArg(colorArgs >> 10 & 31), GX::TevColorArg(colorArgs >> 15 & 31)); + } + if (state.x4_alphaInArgs != alphaArgs) { + state.x4_alphaInArgs = alphaArgs; + GXSetTevAlphaIn(stageId, GX::TevAlphaArg(alphaArgs & 31), GX::TevAlphaArg(alphaArgs >> 5 & 31), + GX::TevAlphaArg(alphaArgs >> 10 & 31), GX::TevAlphaArg(alphaArgs >> 15 & 31)); + } + if (colorOps != alphaOps || (colorOps & 0x1FF) != 0x100) { + SetTevColorOp_Compressed(stageId, colorOps); + SetTevAlphaOp_Compressed(stageId, alphaOps); + } else if (colorOps != state.x8_colorOps || colorOps != state.xc_alphaOps) { + state.x8_colorOps = colorOps; + state.xc_alphaOps = colorOps; + const auto outReg = GX::TevRegID(colorOps >> 9 & 3); + GXSetTevColorOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, outReg); + GXSetTevAlphaOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, outReg); + } +} + +void SetTevIndirect(GX::TevStageID stageId, GX::IndTexStageID indStage, GX::IndTexFormat fmt, GX::IndTexBiasSel biasSel, + GX::IndTexMtxID mtxSel, GX::IndTexWrap wrapS, GX::IndTexWrap wrapT, GXBool addPrev, GXBool indLod, + GX::IndTexAlphaSel alphaSel) noexcept; + +void SetTevIndWarp(GX::TevStageID stageId, GX::IndTexStageID indStage, GXBool signedOffset, GXBool replaceMode, + GX::IndTexMtxID mtxSel) noexcept; + +static inline void SetTevKAlphaSel(GX::TevStageID stageId, GX::TevKAlphaSel sel) noexcept { + auto& state = sGXState.x68_tevStates[stageId].x19_kAlphaSel; + if (sel != state) { + state = sel; + GXSetTevKAlphaSel(stageId, sel); + } +} + +static inline void SetTevKColor(GX::TevKColorID id, const GXColor& color) noexcept { + auto& state = sGXState.x58_kColors[id]; + if (color != state) { + state = color; + GXSetTevKColor(id, color); + } +} + +static inline void SetTevKColorSel(GX::TevStageID stageId, GX::TevKColorSel sel) noexcept { + auto& state = sGXState.x68_tevStates[stageId].x18_kColorSel; + if (sel != state) { + state = sel; + GXSetTevKColorSel(stageId, sel); + } +} + +static inline void SetTevOrder(GX::TevStageID stageId, GX::TexCoordID texCoord, GX::TexMapID texMap, + GX::ChannelID color) noexcept { + u32 flags = (color & 0xFF) << 16 | (texMap & 0xFF) << 8 | (texCoord & 0xFF); + auto& state = sGXState.x68_tevStates[stageId].x14_tevOrderFlags; + if (flags != state) { + state = flags; + GXSetTevOrder(stageId, texCoord, texMap, color); + } +} + +static inline void SetTexCoordGen(GX::TexCoordID dstCoord, GX::TexGenType fn, GX::TexGenSrc src, u32 mtx, + GXBool normalize, u32 postMtx) noexcept { + // TODO +} + +void SetVtxDescv(GX::VtxDescList* descList) noexcept; + +static inline void SetVtxDescv_Compressed(u32 descList) noexcept { + // TODO convert to GX::VtxDescList + aurora::gfx::model::set_vtx_desc_compressed(descList); +} + +static inline void SetZMode(GXBool compareEnable, GX::Compare func, GXBool updateEnable) noexcept { + u32 flags = (func & 0xFF) << 2 | (u8(updateEnable) << 1) | (u8(compareEnable) & 1); + auto& state = sGXState.x52_zmode; + if (flags != state) { + state = flags; + GXSetZMode(compareEnable, func, updateEnable); + } +} +} // namespace metaforce::CGX diff --git a/Runtime/Graphics/CGraphics.cpp b/Runtime/Graphics/CGraphics.cpp index 156f31a77..fe9d0c4a7 100644 --- a/Runtime/Graphics/CGraphics.cpp +++ b/Runtime/Graphics/CGraphics.cpp @@ -6,18 +6,19 @@ #include "Runtime/Graphics/CTexture.hpp" #include "Runtime/Graphics/Shaders/CTextSupportShader.hpp" #include "Runtime/GuiSys/CGuiSys.hpp" +#include "Runtime/Graphics/CGX.hpp" #include namespace metaforce { CGraphics::CProjectionState CGraphics::g_Proj; -CFogState CGraphics::g_Fog; +// CFogState CGraphics::g_Fog; float CGraphics::g_ProjAspect = 1.f; u32 CGraphics::g_NumBreakpointsWaiting = 0; u32 CGraphics::g_FlippingState; bool CGraphics::g_LastFrameUsedAbove = false; bool CGraphics::g_InterruptLastFrameUsedAbove = false; -std::bitset CGraphics::g_LightActive{}; +GX::LightMask CGraphics::g_LightActive{}; zeus::CTransform CGraphics::g_GXModelView; zeus::CTransform CGraphics::g_GXModelViewInvXpose; zeus::CTransform CGraphics::g_GXModelMatrix = zeus::CTransform(); @@ -56,9 +57,15 @@ const std::array CGraphics::skCubeBasisMats{{ {-1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, -1.f}, }}; +// Stream API +static EStreamFlags sStreamFlags; +static zeus::CColor sQueuedColor; +static zeus::CVector2f sQueuedTexCoord; +static zeus::CVector3f sQueuedNormal; + void CGraphics::DisableAllLights() { g_LightActive.reset(); - aurora::gfx::set_light_state(g_LightActive); + CGX::SetChanCtrl(CGX::EChannelId::Channel0, {}); } void CGraphics::LoadLight(ERglLight light, const CLight& info) { @@ -89,50 +96,55 @@ void CGraphics::LoadLight(ERglLight light, const CLight& info) { } void CGraphics::EnableLight(ERglLight light) { + CGX::SetNumChans(1); if (!g_LightActive.test(light)) { g_LightActive.set(light); - aurora::gfx::set_light_state(g_LightActive); + CGX::SetChanCtrl(CGX::EChannelId::Channel0, g_LightActive); } } -void CGraphics::SetLightState(std::bitset lightState) { +void CGraphics::SetLightState(GX::LightMask lightState) { g_LightActive = lightState; - aurora::gfx::set_light_state(g_LightActive); + const bool hasLights = lightState.any(); + CGX::SetChanCtrl(CGX::EChannelId::Channel0, hasLights, GX::SRC_REG, + sStreamFlags & EStreamFlagBits::fHasColor ? GX::SRC_VTX : GX::SRC_REG, lightState, + hasLights ? GX::DF_CLAMP : GX::DF_NONE, hasLights ? GX::AF_SPOT : GX::AF_NONE); } void CGraphics::SetAmbientColor(const zeus::CColor& col) { - aurora::gfx::set_chan_amb_color(GX::COLOR0A0, col); - aurora::gfx::set_chan_amb_color(GX::COLOR1A1, col); + CGX::SetChanAmbColor(CGX::EChannelId::Channel0, col); + CGX::SetChanAmbColor(CGX::EChannelId::Channel1, col); } void CGraphics::SetFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) { - g_Fog.m_mode = mode > ERglFogMode::PerspRevExp2 ? ERglFogMode(int(mode) - 8) : mode; - g_Fog.m_color = color; - if (CGraphics::g_Proj.x18_far == CGraphics::g_Proj.x14_near || endz == startz) { - g_Fog.m_A = 0.f; - g_Fog.m_B = 0.5f; - g_Fog.m_C = 0.f; - } else { - float depthrange = CGraphics::g_Proj.x18_far - CGraphics::g_Proj.x14_near; - float fogrange = endz - startz; - g_Fog.m_A = (CGraphics::g_Proj.x18_far * CGraphics::g_Proj.x14_near) / (depthrange * fogrange); - g_Fog.m_B = CGraphics::g_Proj.x18_far / depthrange; - g_Fog.m_C = startz / fogrange; - } + // g_Fog.m_mode = mode > ERglFogMode::PerspRevExp2 ? ERglFogMode(int(mode) - 8) : mode; + // g_Fog.m_color = color; + // if (CGraphics::g_Proj.x18_far == CGraphics::g_Proj.x14_near || endz == startz) { + // g_Fog.m_A = 0.f; + // g_Fog.m_B = 0.5f; + // g_Fog.m_C = 0.f; + // } else { + // float depthrange = CGraphics::g_Proj.x18_far - CGraphics::g_Proj.x14_near; + // float fogrange = endz - startz; + // g_Fog.m_A = (CGraphics::g_Proj.x18_far * CGraphics::g_Proj.x14_near) / (depthrange * fogrange); + // g_Fog.m_B = CGraphics::g_Proj.x18_far / depthrange; + // g_Fog.m_C = startz / fogrange; + // } + CGX::SetFog(GX::FogType(mode), startz, endz, g_Proj.x14_near, g_Proj.x18_far, color); } void CGraphics::SetDepthWriteMode(bool compare_enable, ERglEnum comp, bool update_enable) { g_depthFunc = comp; - aurora::gfx::set_depth_mode(compare_enable, comp, update_enable); + CGX::SetZMode(compare_enable, GX::Compare(comp), update_enable); } void CGraphics::SetBlendMode(ERglBlendMode mode, ERglBlendFactor src, ERglBlendFactor dst, ERglLogicOp op) { - aurora::gfx::set_blend_mode(mode, src, dst, op); + CGX::SetBlendMode(GX::BlendMode(mode), GX::BlendFactor(src), GX::BlendFactor(dst), GX::LogicOp(op)); } void CGraphics::SetCullMode(ERglCullMode mode) { g_cullMode = mode; - aurora::gfx::set_cull_mode(mode); + GXSetCullMode(GX::CullMode(mode)); } void CGraphics::BeginScene() { @@ -140,7 +152,8 @@ void CGraphics::BeginScene() { } void CGraphics::EndScene() { - aurora::gfx::set_depth_mode(true, ERglEnum::LEqual, true); + CGX::SetZMode(true, GX::LEQUAL, true); + /* Spinwait until g_NumBreakpointsWaiting is 0 */ /* ++g_NumBreakpointsWaiting; */ /* GXCopyDisp to g_CurrenFrameBuf with clear enabled */ @@ -497,26 +510,18 @@ void CGraphics::SetUseVideoFilter(bool filter) { void CGraphics::SetClearColor(const zeus::CColor& color) { g_ClearColor = color; - aurora::gfx::set_clear_color(color); + GXSetCopyClear(color, g_ClearDepthValue); } void CGraphics::SetCopyClear(const zeus::CColor& color, float depth) { g_ClearColor = color; g_ClearDepthValue = depth; // 1.6777215E7 * depth; Metroid Prime needed this to convert float [0,1] depth into 24 bit // range, we no longer have this requirement - aurora::gfx::set_clear_color(color); - // TODO do we care about depth value? - // GXSetCopyClear(g_ClearColor, g_ClearDepthValue); + GXSetCopyClear(g_ClearColor, g_ClearDepthValue); } void CGraphics::SetIsBeginSceneClearFb(bool clear) { g_IsBeginSceneClearFb = clear; } -// Stream API -static EStreamFlags sStreamFlags; -static zeus::CColor sQueuedColor; -static zeus::CVector2f sQueuedTexCoord; -static zeus::CVector3f sQueuedNormal; - void CGraphics::SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass) { CTevCombiners::SetupPass(stage, pass); } @@ -583,13 +588,22 @@ void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* po void CGraphics::SetTevStates(EStreamFlags flags) noexcept { if (flags & EStreamFlagBits::fHasTexture) { - aurora::gfx::set_tev_order(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0); - aurora::gfx::set_tev_order(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0); - } else { - aurora::gfx::set_tev_order(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0); - aurora::gfx::set_tev_order(GX::TEVSTAGE1, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0); + CGX::SetNumChans(1); + CGX::SetNumTexGens(0); + CGX::SetNumTevStages(1); + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0); + CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0); + } else /* if (flags < 8) ? */ { + CGX::SetNumChans(1); + CGX::SetNumTexGens(2); // sTextureUsed & 3? + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0); + CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0); } + CGX::SetNumIndStages(0); // TODO load TCGs - aurora::gfx::set_chan_mat_src(GX::COLOR0A0, flags & EStreamFlagBits::fHasColor ? GX::SRC_VTX : GX::SRC_REG); + const bool hasLights = g_LightActive.any(); + CGX::SetChanCtrl(CGX::EChannelId::Channel0, hasLights, GX::SRC_REG, + flags & EStreamFlagBits::fHasColor ? GX::SRC_VTX : GX::SRC_REG, g_LightActive, + hasLights ? GX::DF_CLAMP : GX::DF_NONE, hasLights ? GX::AF_SPOT : GX::AF_NONE); } } // namespace metaforce diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index 93fa7c674..f8542080e 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -1,9 +1,9 @@ #pragma once -#include "Runtime/RetroTypes.hpp" -#include "Runtime/Graphics/GX.hpp" -#include "Runtime/Graphics/CTevCombiners.hpp" #include "Runtime/ConsoleVariables/CVar.hpp" +#include "Runtime/Graphics/CTevCombiners.hpp" +#include "Runtime/Graphics/GX.hpp" +#include "Runtime/RetroTypes.hpp" #include #include @@ -25,6 +25,83 @@ extern CVar* g_disableLighting; class CLight; class CTimeProvider; +enum class ERglCullMode : std::underlying_type_t { + None = GX::CULL_NONE, + Front = GX::CULL_FRONT, + Back = GX::CULL_BACK, + All = GX::CULL_ALL, +}; + +enum class ERglBlendMode : std::underlying_type_t { + None = GX::BM_NONE, + Blend = GX::BM_BLEND, + Logic = GX::BM_LOGIC, + Subtract = GX::BM_SUBTRACT, + Max = GX::MAX_BLENDMODE, +}; + +enum class ERglBlendFactor : std::underlying_type_t { + Zero = GX::BL_ZERO, + One = GX::BL_ONE, + SrcColor = GX::BL_SRCCLR, + InvSrcColor = GX::BL_INVSRCCLR, + SrcAlpha = GX::BL_SRCALPHA, + InvSrcAlpha = GX::BL_INVSRCALPHA, + DstAlpha = GX::BL_DSTALPHA, + InvDstAlpha = GX::BL_INVDSTALPHA, + DstColor = GX::BL_DSTCLR, + InvDstColor = GX::BL_INVDSTCLR, +}; + +enum class ERglLogicOp : std::underlying_type_t { + Clear = GX::LO_CLEAR, + And = GX::LO_AND, + RevAnd = GX::LO_REVAND, + Copy = GX::LO_COPY, + InvAnd = GX::LO_INVAND, + NoOp = GX::LO_NOOP, + Xor = GX::LO_XOR, + Or = GX::LO_OR, + Nor = GX::LO_NOR, + Equiv = GX::LO_EQUIV, + Inv = GX::LO_INV, + RevOr = GX::LO_REVOR, + InvCopy = GX::LO_INVCOPY, + InvOr = GX::LO_INVOR, + NAnd = GX::LO_NAND, + Set = GX::LO_SET, +}; + +enum class ERglAlphaFunc : std::underlying_type_t { + Never = GX::NEVER, + Less = GX::LESS, + Equal = GX::EQUAL, + LEqual = GX::LEQUAL, + Greater = GX::GREATER, + NEqual = GX::NEQUAL, + GEqual = GX::GEQUAL, + Always = GX::ALWAYS, +}; + +enum class ERglAlphaOp : std::underlying_type_t { + And = GX::AOP_AND, + Or = GX::AOP_OR, + Xor = GX::AOP_XOR, + XNor = GX::AOP_XNOR, + Max = GX::MAX_ALPHAOP, +}; + +enum class ERglEnum : std::underlying_type_t { + Never = GX::NEVER, + Less = GX::LESS, + Equal = GX::EQUAL, + LEqual = GX::LEQUAL, + Greater = GX::GREATER, + NEqual = GX::NEQUAL, + GEqual = GX::GEQUAL, + Always = GX::ALWAYS, +}; + using ERglLight = u8; struct SViewport { @@ -104,14 +181,14 @@ public: static CProjectionState g_Proj; static zeus::CVector2f g_CachedDepthRange; - static CFogState g_Fog; + // static CFogState g_Fog; static SViewport g_Viewport; static float g_ProjAspect; static u32 g_NumBreakpointsWaiting; static u32 g_FlippingState; static bool g_LastFrameUsedAbove; static bool g_InterruptLastFrameUsedAbove; - static std::bitset g_LightActive; + static GX::LightMask g_LightActive; static zeus::CTransform g_GXModelView; static zeus::CTransform g_GXModelViewInvXpose; static zeus::CTransform g_GXModelMatrix; @@ -131,7 +208,7 @@ public: static void DisableAllLights(); static void LoadLight(ERglLight light, const CLight& info); static void EnableLight(ERglLight light); - static void SetLightState(std::bitset lightState); + static void SetLightState(GX::LightMask lightState); static void SetAmbientColor(const zeus::CColor& col); static void SetFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color); static void SetDepthWriteMode(bool test, ERglEnum comp, bool write); diff --git a/Runtime/Graphics/CMakeLists.txt b/Runtime/Graphics/CMakeLists.txt index d764e5b19..51c49d431 100644 --- a/Runtime/Graphics/CMakeLists.txt +++ b/Runtime/Graphics/CMakeLists.txt @@ -17,6 +17,7 @@ set(GRAPHICS_SOURCES CVertexMorphEffect.hpp CVertexMorphEffect.cpp CMoviePlayer.hpp CMoviePlayer.cpp CGraphicsPalette.hpp CGraphicsPalette.cpp + CGX.hpp CGX.cpp CPVSVisSet.hpp CPVSVisSet.cpp CPVSVisOctree.hpp CPVSVisOctree.cpp CPVSAreaSet.hpp CPVSAreaSet.cpp diff --git a/Runtime/Graphics/CModel.hpp b/Runtime/Graphics/CModel.hpp index 7cd41281a..cce094025 100644 --- a/Runtime/Graphics/CModel.hpp +++ b/Runtime/Graphics/CModel.hpp @@ -105,13 +105,15 @@ public: void DrawUnsortedParts(CModelFlags flags); bool IsLoaded(u32 matIdx); - TVectorRef GetPositions(); - TConstVectorRef GetPositions() const; - TVectorRef GetNormals(); - TConstVectorRef GetNormals() const; - u32 GetNumMaterialSets() const { return x18_matSets.size(); } - bool IsOpaque() const { return x28_modelInst->x3c_firstSortedSurf == nullptr; } - const zeus::CAABox& GetAABB() const { return x28_modelInst->x20_worldAABB; } + [[nodiscard]] TVectorRef GetPositions(); + [[nodiscard]] TConstVectorRef GetPositions() const; + [[nodiscard]] TVectorRef GetNormals(); + [[nodiscard]] TConstVectorRef GetNormals() const; + [[nodiscard]] u32 GetNumMaterialSets() const { return x18_matSets.size(); } + [[nodiscard]] bool IsOpaque() const { return x28_modelInst->x3c_firstSortedSurf == nullptr; } + [[nodiscard]] const zeus::CAABox& GetAABB() const { return x28_modelInst->x20_worldAABB; } + [[nodiscard]] auto& GetInstance() { return *x28_modelInst; } + [[nodiscard]] const auto& GetInstance() const { return *x28_modelInst; } static void FrameDone(); static void EnableTextureTimeout(); diff --git a/Runtime/Graphics/CTevCombiners.cpp b/Runtime/Graphics/CTevCombiners.cpp index 3edeeb2ec..edd0c81c8 100644 --- a/Runtime/Graphics/CTevCombiners.cpp +++ b/Runtime/Graphics/CTevCombiners.cpp @@ -1,12 +1,20 @@ #include "Graphics/CTevCombiners.hpp" +#include "Graphics/CGX.hpp" + namespace metaforce::CTevCombiners { u32 CTevPass::sNextUniquePass = 0; void CTevPass::Execute(ERglTevStage stage) const { - aurora::gfx::update_tev_stage(stage, x4_colorPass, x14_alphaPass, x24_colorOp, x38_alphaOp); - aurora::gfx::set_tev_k_color_sel(static_cast(stage), GX::TevKColorSel::TEV_KCSEL_8_8); - aurora::gfx::set_tev_k_alpha_sel(static_cast(stage), GX::TevKAlphaSel::TEV_KASEL_8_8); + const auto stageId = GX::TevStageID(stage); + CGX::SetTevColorIn(stageId, x4_colorPass.x0_a, x4_colorPass.x4_b, x4_colorPass.x8_c, x4_colorPass.xc_d); + CGX::SetTevAlphaIn(stageId, x14_alphaPass.x0_a, x14_alphaPass.x4_b, x14_alphaPass.x8_c, x14_alphaPass.xc_d); + CGX::SetTevColorOp(stageId, x24_colorOp.x4_op, x24_colorOp.x8_bias, x24_colorOp.xc_scale, x24_colorOp.x0_clamp, + x24_colorOp.x10_regId); + CGX::SetTevAlphaOp(stageId, x38_alphaOp.x4_op, x38_alphaOp.x8_bias, x38_alphaOp.xc_scale, x38_alphaOp.x0_clamp, + x38_alphaOp.x10_regId); + CGX::SetTevKColorSel(stageId, GX::TevKColorSel::TEV_KCSEL_8_8); + CGX::SetTevKAlphaSel(stageId, GX::TevKAlphaSel::TEV_KASEL_8_8); } constexpr u32 maxTevPasses = 2; @@ -17,10 +25,6 @@ const CTevPass skPassThru{ {GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_RASC}, {GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA}, }; -const CTevPass skPassZero{ - {GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO}, - {GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO}, -}; const CTevPass sTevPass805a5698{ {GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_RASC, GX::TevColorArg::CC_C0, GX::TevColorArg::CC_ZERO}, {GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA, GX::TevAlphaArg::CA_A0, GX::TevAlphaArg::CA_ZERO}, @@ -96,16 +100,13 @@ bool SetPassCombiners(ERglTevStage stage, const CTevPass& pass) { void RecomputePasses() { sNumEnabledPasses = 1 - static_cast(sValidPasses[maxTevPasses - 1]); - for (u32 i = sNumEnabledPasses; i < maxTevPasses; ++i) { - aurora::gfx::disable_tev_stage(ERglTevStage(i)); - } - // CGX::SetNumTevStages(sNumEnabledPasses); + CGX::SetNumTevStages(sNumEnabledPasses); } void ResetStates() { sValidPasses.fill(false); skPassThru.Execute(ERglTevStage::Stage0); sNumEnabledPasses = 1; - // CGX::SetNumTevStages(1); + CGX::SetNumTevStages(1); } } // namespace metaforce::CTevCombiners diff --git a/Runtime/Graphics/CTevCombiners.hpp b/Runtime/Graphics/CTevCombiners.hpp index 2a04c01ee..c2922b419 100644 --- a/Runtime/Graphics/CTevCombiners.hpp +++ b/Runtime/Graphics/CTevCombiners.hpp @@ -3,9 +3,80 @@ #include "Graphics/GX.hpp" #include "RetroTypes.hpp" -#include +namespace metaforce { +enum class ERglTevStage : std::underlying_type_t { + Stage0 = GX::TEVSTAGE0, + Stage1 = GX::TEVSTAGE1, + Stage2 = GX::TEVSTAGE2, + Stage3 = GX::TEVSTAGE3, + Stage4 = GX::TEVSTAGE4, + Stage5 = GX::TEVSTAGE5, + Stage6 = GX::TEVSTAGE6, + Stage7 = GX::TEVSTAGE7, + Stage8 = GX::TEVSTAGE8, + Stage9 = GX::TEVSTAGE9, + Stage10 = GX::TEVSTAGE10, + Stage11 = GX::TEVSTAGE11, + Stage12 = GX::TEVSTAGE12, + Stage13 = GX::TEVSTAGE13, + Stage14 = GX::TEVSTAGE14, + Stage15 = GX::TEVSTAGE15, + Max = GX::MAX_TEVSTAGE, + None = GX::NULL_STAGE, +}; -namespace metaforce::CTevCombiners { +namespace CTevCombiners { +struct CTevOp { + bool x0_clamp = true; + GX::TevOp x4_op = GX::TevOp::TEV_ADD; + GX::TevBias x8_bias = GX::TevBias::TB_ZERO; + GX::TevScale xc_scale = GX::TevScale::CS_SCALE_1; + GX::TevRegID x10_regId = GX::TevRegID::TEVPREV; + + constexpr CTevOp() = default; + constexpr CTevOp(bool clamp, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GX::TevRegID regId) + : x0_clamp(clamp), x4_op(op), x8_bias(bias), xc_scale(scale), x10_regId(regId) {} + constexpr CTevOp(u32 compressedDesc) + : x0_clamp((compressedDesc >> 8 & 1) != 0) + , x4_op(static_cast(compressedDesc & 0xF)) + , x8_bias(static_cast(compressedDesc >> 4 & 3)) + , xc_scale(static_cast(compressedDesc >> 6 & 3)) + , x10_regId(static_cast(compressedDesc >> 9 & 3)) {} + + auto operator<=>(const CTevOp&) const = default; +}; +struct ColorPass { + GX::TevColorArg x0_a; + GX::TevColorArg x4_b; + GX::TevColorArg x8_c; + GX::TevColorArg xc_d; + + constexpr ColorPass(GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c, GX::TevColorArg d) + : x0_a(a), x4_b(b), x8_c(c), xc_d(d) {} + constexpr ColorPass(u32 compressedDesc) + : x0_a(static_cast(compressedDesc & 0x1F)) + , x4_b(static_cast(compressedDesc >> 5 & 0x1F)) + , x8_c(static_cast(compressedDesc >> 10 & 0x1F)) + , xc_d(static_cast(compressedDesc >> 15 & 0x1F)) {} + + auto operator<=>(const ColorPass&) const = default; +}; +struct AlphaPass { + GX::TevAlphaArg x0_a; + GX::TevAlphaArg x4_b; + GX::TevAlphaArg x8_c; + GX::TevAlphaArg xc_d; + + constexpr AlphaPass(GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c, GX::TevAlphaArg d) + : x0_a(a), x4_b(b), x8_c(c), xc_d(d) {} + constexpr AlphaPass(u32 compressedDesc) + : x0_a(static_cast(compressedDesc & 0x1F)) + , x4_b(static_cast(compressedDesc >> 5 & 0x1F)) + , x8_c(static_cast(compressedDesc >> 10 & 0x1F)) + , xc_d(static_cast(compressedDesc >> 15 & 0x1F)) {} + + auto operator<=>(const AlphaPass&) const = default; +}; class CTevPass { u32 x0_id; ColorPass x4_colorPass; @@ -29,7 +100,6 @@ public: }; extern const CTevPass skPassThru; -extern const CTevPass skPassZero; extern const CTevPass sTevPass805a5698; extern const CTevPass sTevPass805a5e70; extern const CTevPass sTevPass805a5ebc; @@ -47,4 +117,5 @@ void DeletePass(ERglTevStage stage); bool SetPassCombiners(ERglTevStage stage, const CTevPass& pass); void RecomputePasses(); void ResetStates(); -} // namespace metaforce::CTevCombiners +} // namespace CTevCombiners +} // namespace metaforce diff --git a/Runtime/Graphics/GX.hpp b/Runtime/Graphics/GX.hpp index 85ccdd284..4d52853b7 100644 --- a/Runtime/Graphics/GX.hpp +++ b/Runtime/Graphics/GX.hpp @@ -1,7 +1,11 @@ #pragma once -#include -#include +#include "../GCNTypes.hpp" + +#include +#include + +#include namespace GX { enum Attr { @@ -303,12 +307,14 @@ enum TevSwapSel { TEV_SWAP3 = 0x3, MAX_TEVSWAP = 0x4, }; + enum TevColorChan { CH_RED = 0x0, CH_GREEN = 0x1, CH_BLUE = 0x2, CH_ALPHA = 0x3, }; + enum TevRegID { TEVPREV = 0, TEVREG0 = 1, @@ -319,14 +325,14 @@ enum TevRegID { enum DiffuseFn { DF_NONE = 0, - DF_SIGN, - DF_CLAMP, + DF_SIGN = 1, + DF_CLAMP = 2, }; enum AttnFn { AF_SPEC = 0, AF_SPOT = 1, - AF_NONE, + AF_NONE = 2, }; enum Primitive { @@ -405,7 +411,7 @@ enum Compare { ALWAYS, }; -enum BlendFactor : uint16_t { +enum BlendFactor { BL_ZERO, BL_ONE, BL_SRCCLR, @@ -413,10 +419,19 @@ enum BlendFactor : uint16_t { BL_SRCALPHA, BL_INVSRCALPHA, BL_DSTALPHA, - BL_INVDSTALPHA + BL_INVDSTALPHA, + BL_DSTCLR, + BL_INVDSTCLR, }; -enum TextureFormat : uint32_t { +enum CullMode { + CULL_NONE, + CULL_FRONT, + CULL_BACK, + CULL_ALL, +}; + +enum TextureFormat { TF_I4 = 0x0, TF_I8 = 0x1, TF_IA4 = 0x2, @@ -520,6 +535,7 @@ enum IndTexAlphaSel { ITBA_U, MAX_ITBALPHA, }; + enum IndTexStageID { INDTEXSTAGE0, INDTEXSTAGE1, @@ -611,6 +627,8 @@ enum LightID { MAX_LIGHT = 0x100, LIGHT_NULL = 0x000, }; +constexpr u8 MaxLights = std::bit_width>(MAX_LIGHT) - 1; +using LightMask = std::bitset; enum FogType { FOG_NONE = 0x00, @@ -627,3 +645,43 @@ enum FogType { }; } // namespace GX + +using GXColor = zeus::CColor; +using GXBool = bool; + +void GXSetNumChans(u8 num) noexcept; +void GXSetNumIndStages(u8 num) noexcept; +void GXSetNumTevStages(u8 num) noexcept; +void GXSetNumTexGens(u8 num) noexcept; +void GXSetTevAlphaIn(GX::TevStageID stageId, GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c, + GX::TevAlphaArg d) noexcept; +void GXSetTevAlphaOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GXBool clamp, + GX::TevRegID outReg) noexcept; +void GXSetTevColorIn(GX::TevStageID stageId, GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c, + GX::TevColorArg d) noexcept; +void GXSetTevColorOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GXBool clamp, + GX::TevRegID outReg) noexcept; +void GXSetCullMode(GX::CullMode mode) noexcept; +void GXSetBlendMode(GX::BlendMode mode, GX::BlendFactor src, GX::BlendFactor dst, GX::LogicOp op) noexcept; +void GXSetZMode(GXBool compare_enable, GX::Compare func, GXBool update_enable) noexcept; +void GXSetTevColor(GX::TevRegID id, const GXColor& color) noexcept; +void GXSetTevKColor(GX::TevKColorID id, const GXColor& color) noexcept; +void GXSetAlphaUpdate(GXBool enabled) noexcept; +// Originally u8 instead of float +void GXSetDstAlpha(GXBool enabled, float value) noexcept; +void GXSetCopyClear(const GXColor& color, float depth) noexcept; +void GXSetTevOrder(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept; +void GXSetTevKColorSel(GX::TevStageID id, GX::TevKColorSel sel) noexcept; +void GXSetTevKAlphaSel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept; +void GXSetChanAmbColor(GX::ChannelID id, const GXColor& color) noexcept; +void GXSetChanMatColor(GX::ChannelID id, const GXColor& color) noexcept; +void GXSetChanCtrl(GX::ChannelID id, GXBool lightingEnabled, GX::ColorSrc ambSrc, GX::ColorSrc matSrc, + GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept; +// Originally u8 instead of floats +void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept; +void GXSetVtxDescv(GX::VtxDescList* list) noexcept; +void GXClearVtxDesc() noexcept; +void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept; +void GXSetTevDirect(GX::TevStageID stageId) noexcept; +void GXSetFog(GX::FogType type, float startZ, float endZ, float nearZ, float farZ, const GXColor& color) noexcept; +void GXCallDisplayList(const void* data, u32 nbytes) noexcept; diff --git a/Runtime/Graphics/IRenderer.hpp b/Runtime/Graphics/IRenderer.hpp index 27ab4f4f2..ff9a9344b 100644 --- a/Runtime/Graphics/IRenderer.hpp +++ b/Runtime/Graphics/IRenderer.hpp @@ -92,11 +92,12 @@ public: virtual u32 GetFPS() = 0; virtual void CacheReflection(TReflectionCallback cb, void* ctx, bool clearAfter) = 0; virtual void DrawSpaceWarp(const zeus::CVector3f& pt, float strength) = 0; - virtual void DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, + virtual void DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) = 0; - virtual void DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color, - TConstVectorRef positions, TConstVectorRef normals) = 0; - virtual void DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) = 0; + virtual void DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color, TConstVectorRef positions, + TConstVectorRef normals, float t) = 0; + virtual void DrawModelFlat(CModel& model, const CModelFlags& flags, bool unsortedOnly, TConstVectorRef positions, + TConstVectorRef normals) = 0; virtual void SetWireframeFlags(s32 flags) = 0; virtual void SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) = 0; virtual void RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, const TLockedToken* model, diff --git a/Runtime/MP1/CSamusDoll.cpp b/Runtime/MP1/CSamusDoll.cpp index 998030f6c..0b20c34a3 100644 --- a/Runtime/MP1/CSamusDoll.cpp +++ b/Runtime/MP1/CSamusDoll.cpp @@ -332,7 +332,7 @@ void CSamusDoll::Draw(const CStateManager& mgr, float alpha) { bool phazonSuit = x44_suit == CPlayerState::EPlayerSuit::Phazon; if (phazonSuit) { - aurora::gfx::set_dst_alpha(true, 1.f); + GXSetDstAlpha(true, 1.f); } for (size_t i = 0; i <= x118_suitModel1and2.size(); ++i) { diff --git a/Runtime/Particle/CElementGen.hpp b/Runtime/Particle/CElementGen.hpp index 3a15d9a3c..e815c663a 100644 --- a/Runtime/Particle/CElementGen.hpp +++ b/Runtime/Particle/CElementGen.hpp @@ -100,7 +100,7 @@ private: bool x26d_27_enableOPTS : 1; bool x26d_28_enableADV : 1 = false; int x270_MBSP = 0; - std::bitset x274_backupLightActive{}; + GX::LightMask x274_backupLightActive{}; std::array x278_hasVMD{}; CRandom16 x27c_randState; std::array x280_VELSources{}; diff --git a/Runtime/World/CActorModelParticles.cpp b/Runtime/World/CActorModelParticles.cpp index 6365530be..ad1179dd4 100644 --- a/Runtime/World/CActorModelParticles.cpp +++ b/Runtime/World/CActorModelParticles.cpp @@ -616,7 +616,7 @@ void CActorModelParticles::LightDudeOnFire(CActor& act) { iter->x70_onFire = true; } -const CTexture* CActorModelParticles::GetAshyTexture(const CActor& act) { +CTexture* CActorModelParticles::GetAshyTexture(const CActor& act) { auto iter = FindSystem(act.GetUniqueId()); if (iter != x0_items.cend() && iter->xdc_ashy && iter->xdc_ashy.IsLoaded()) { // iter->xdc_ashy->GetBooTexture()->setClampMode(boo::TextureClampMode::ClampToEdge); diff --git a/Runtime/World/CActorModelParticles.hpp b/Runtime/World/CActorModelParticles.hpp index 8e4329af9..2206156e3 100644 --- a/Runtime/World/CActorModelParticles.hpp +++ b/Runtime/World/CActorModelParticles.hpp @@ -169,6 +169,6 @@ public: void EnsureFirePopLoaded(CActor& act); void EnsureIceBreakLoaded(CActor& act); void LightDudeOnFire(CActor& act); - const CTexture* GetAshyTexture(const CActor& act); + CTexture* GetAshyTexture(const CActor& act); }; } // namespace metaforce diff --git a/Runtime/World/CPatterned.cpp b/Runtime/World/CPatterned.cpp index f4cb4b48a..26832deb4 100644 --- a/Runtime/World/CPatterned.cpp +++ b/Runtime/World/CPatterned.cpp @@ -1713,7 +1713,7 @@ void CPatterned::Render(CStateManager& mgr) { (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot && x402_31_thawed) || mgr.GetThermalDrawFlag() == EThermalDrawFlag::Bypass) { if (x401_28_burning) { - const CTexture* ashy = mgr.GetActorModelParticles()->GetAshyTexture(*this); + CTexture* ashy = mgr.GetActorModelParticles()->GetAshyTexture(*this); u8 alpha = GetModelAlphau8(mgr); if (ashy != nullptr && ((!x401_29_laggedBurnDeath && alpha <= 255) || alpha <= 127)) { if (xe5_31_pointGeneratorParticles) { diff --git a/Runtime/World/CScriptPlayerActor.cpp b/Runtime/World/CScriptPlayerActor.cpp index e9c413d06..7b7ed565d 100644 --- a/Runtime/World/CScriptPlayerActor.cpp +++ b/Runtime/World/CScriptPlayerActor.cpp @@ -400,7 +400,7 @@ void CScriptPlayerActor::AddToRenderer(const zeus::CFrustum& frustum, CStateMana void CScriptPlayerActor::Render(CStateManager& mgr) { const bool phazonSuit = x2e8_suitRes.GetCharacterNodeId() == 3; if (phazonSuit) { - aurora::gfx::set_dst_alpha(true, 1.f); + GXSetDstAlpha(true, 1.f); } CPhysicsActor::Render(mgr); diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index 5d3f77aa5..3106a1b38 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -5,6 +5,7 @@ // TODO make this shared? #include "../../../Runtime/Graphics/GX.hpp" +#include #include #include @@ -33,77 +34,6 @@ enum class ERglFogMode : uint32_t { OrthoRevExp2 = 0x0F }; -enum class ERglCullMode { None = 0, Front = 1, Back = 2, All = 3 }; - -enum class ERglBlendMode { None = 0, Blend = 1, Logic = 2, Subtract = 3 }; - -enum class ERglBlendFactor { - Zero = 0, - One = 1, - SrcColor = 2, - InvSrcColor = 3, - SrcAlpha = 4, - InvSrcAlpha = 5, - DstAlpha = 6, - InvDstAlpha = 7, - DstColor = 8, - InvDstColor = 9, -}; - -enum class ERglLogicOp { - Clear = 0, - And = 1, - RevAnd = 2, - Copy = 3, - InvAnd = 4, - NoOp = 5, - Xor = 6, - Or = 7, - Nor = 8, - Equiv = 9, - Inv = 10, - RevOr = 11, - InvCopy = 12, - InvOr = 13, - NAnd = 14, - Set = 15 -}; - -enum class ERglAlphaFunc { - Never = 0, - Less = 1, - Equal = 2, - LEqual = 3, - Greater = 4, - NEqual = 5, - GEqual = 6, - Always = 7 -}; - -enum class ERglAlphaOp { And = 0, Or = 1, Xor = 2, XNor = 3 }; - -enum class ERglEnum { Never = 0, Less = 1, Equal = 2, LEqual = 3, Greater = 4, NEqual = 5, GEqual = 6, Always = 7 }; - -enum class ERglTevStage : u32 { - Stage0, - Stage1, - Stage2, - Stage3, - Stage4, - Stage5, - Stage6, - Stage7, - Stage8, - Stage9, - Stage10, - Stage11, - Stage12, - Stage13, - Stage14, - Stage15, - MAX -}; - enum class ETexelFormat { Invalid = -1, I4 = 0, @@ -142,60 +72,6 @@ enum class EStreamFlagBits : u8 { fHasTexture = 0x4, }; using EStreamFlags = Flags; - -namespace CTevCombiners { -struct CTevOp { - bool x0_clamp = true; - GX::TevOp x4_op = GX::TevOp::TEV_ADD; - GX::TevBias x8_bias = GX::TevBias::TB_ZERO; - GX::TevScale xc_scale = GX::TevScale::CS_SCALE_1; - GX::TevRegID x10_regId = GX::TevRegID::TEVPREV; - - constexpr CTevOp() = default; - constexpr CTevOp(bool clamp, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GX::TevRegID regId) - : x0_clamp(clamp), x4_op(op), x8_bias(bias), xc_scale(scale), x10_regId(regId) {} - constexpr CTevOp(u32 compressedDesc) - : x0_clamp((compressedDesc >> 8 & 1) != 0) - , x4_op(static_cast(compressedDesc & 0xF)) - , x8_bias(static_cast(compressedDesc >> 4 & 3)) - , xc_scale(static_cast(compressedDesc >> 6 & 3)) - , x10_regId(static_cast(compressedDesc >> 9 & 3)) {} - - auto operator<=>(const CTevOp&) const = default; -}; -struct ColorPass { - GX::TevColorArg x0_a; - GX::TevColorArg x4_b; - GX::TevColorArg x8_c; - GX::TevColorArg xc_d; - - constexpr ColorPass(GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c, GX::TevColorArg d) - : x0_a(a), x4_b(b), x8_c(c), xc_d(d) {} - constexpr ColorPass(u32 compressedDesc) - : x0_a(static_cast(compressedDesc & 0x1F)) - , x4_b(static_cast(compressedDesc >> 5 & 0x1F)) - , x8_c(static_cast(compressedDesc >> 10 & 0x1F)) - , xc_d(static_cast(compressedDesc >> 15 & 0x1F)) {} - - auto operator<=>(const ColorPass&) const = default; -}; -struct AlphaPass { - GX::TevAlphaArg x0_a; - GX::TevAlphaArg x4_b; - GX::TevAlphaArg x8_c; - GX::TevAlphaArg xc_d; - - constexpr AlphaPass(GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c, GX::TevAlphaArg d) - : x0_a(a), x4_b(b), x8_c(c), xc_d(d) {} - constexpr AlphaPass(u32 compressedDesc) - : x0_a(static_cast(compressedDesc & 0x1F)) - , x4_b(static_cast(compressedDesc >> 5 & 0x1F)) - , x8_c(static_cast(compressedDesc >> 10 & 0x1F)) - , xc_d(static_cast(compressedDesc >> 15 & 0x1F)) {} - - auto operator<=>(const AlphaPass&) const = default; -}; -} // namespace CTevCombiners } // namespace metaforce namespace aurora::gfx { @@ -246,7 +122,6 @@ enum class ZComp : uint8_t { Always, }; -constexpr u32 MaxLights = 8; struct Light { zeus::CVector3f pos{0.f, 0.f, 0.f}; zeus::CVector3f dir{0.f, 0.f, -1.f}; @@ -265,36 +140,13 @@ void stream_end() noexcept; // GX state void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept; void unbind_texture(GX::TexMapID id) noexcept; -void disable_tev_stage(metaforce::ERglTevStage stage) noexcept; -void update_tev_stage(metaforce::ERglTevStage stage, const metaforce::CTevCombiners::ColorPass& colPass, - const metaforce::CTevCombiners::AlphaPass& alphaPass, - const metaforce::CTevCombiners::CTevOp& colorOp, - const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept; -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 compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept; -void set_tev_reg_color(GX::TevRegID id, const zeus::CColor& color) noexcept; -void set_tev_k_color(GX::TevKColorID id, const zeus::CColor& color) noexcept; -void set_alpha_update(bool enabled) noexcept; -void set_dst_alpha(bool enabled, float value) noexcept; -void set_clear_color(const zeus::CColor& color) noexcept; -void set_tev_order(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept; -void set_tev_k_color_sel(GX::TevStageID id, GX::TevKColorSel sel) noexcept; -void set_tev_k_alpha_sel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept; -void set_chan_amb_color(GX::ChannelID id, const zeus::CColor& color) noexcept; -void set_chan_mat_color(GX::ChannelID id, const zeus::CColor& color) noexcept; -void set_chan_mat_src(GX::ChannelID id, GX::ColorSrc src) noexcept; - -// 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; void update_fog_state(const metaforce::CFogState& state) noexcept; void load_light(GX::LightID id, const Light& light) noexcept; void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept; -void set_light_state(std::bitset bits) noexcept; +void set_light_state(GX::LightMask bits) noexcept; void set_viewport(const zeus::CRectangle& rect, float znear, float zfar) noexcept; void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept; diff --git a/aurora/include/aurora/model.hpp b/aurora/include/aurora/model.hpp index e3533b9c1..152661cf0 100644 --- a/aurora/include/aurora/model.hpp +++ b/aurora/include/aurora/model.hpp @@ -3,11 +3,5 @@ #include "common.hpp" namespace aurora::gfx::model { -void set_vertex_buffer(const std::vector* data) noexcept; -void set_normal_buffer(const std::vector* norm) noexcept; -void set_tex0_tc_buffer(const std::vector>* tcs) noexcept; // Tex coords for TEX0 -void set_tc_buffer(const std::vector>* tcs) noexcept; // Tex coords for the TEX1-7 - void set_vtx_desc_compressed(u32 vtxDesc) noexcept; -void queue_surface(const u8* dlStart, u32 dlSize) noexcept; } // namespace aurora::gfx::model diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index b1380723f..97f3d3413 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -301,10 +301,10 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv) .storeOp = wgpu::StoreOp::Store, .clearColor = { - .r = gfx::gx::g_clearColor.r(), - .g = gfx::gx::g_clearColor.g(), - .b = gfx::gx::g_clearColor.b(), - .a = gfx::gx::g_clearColor.a(), + .r = gfx::gx::g_gxState.clearColor.r(), + .g = gfx::gx::g_gxState.clearColor.g(), + .b = gfx::gx::g_gxState.clearColor.b(), + .a = gfx::gx::g_gxState.clearColor.a(), }, }, }; diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 47c1014de..d9407c2e6 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -4,7 +4,119 @@ #include "common.hpp" #include -#include + +using aurora::gfx::gx::g_gxState; +static logvisor::Module Log("aurora::gx"); + +void GXSetNumChans(u8 num) noexcept { g_gxState.numChans = num; } +void GXSetNumIndStages(u8 num) noexcept { g_gxState.numIndStages = num; } +void GXSetNumTevStages(u8 num) noexcept { g_gxState.numTevStages = num; } +void GXSetNumTexGens(u8 num) noexcept { g_gxState.numTexGens = num; } +void GXSetTevAlphaIn(GX::TevStageID stageId, GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c, + GX::TevAlphaArg d) noexcept { + g_gxState.tevStages[stageId].alphaPass = {a, b, c, d}; +} +void GXSetTevAlphaOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, bool clamp, + GX::TevRegID outReg) noexcept { + g_gxState.tevStages[stageId].alphaOp = {op, bias, scale, outReg, clamp}; +} +void GXSetTevColorIn(GX::TevStageID stageId, GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c, + GX::TevColorArg d) noexcept { + g_gxState.tevStages[stageId].colorPass = {a, b, c, d}; +} +void GXSetTevColorOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, bool clamp, + GX::TevRegID outReg) noexcept { + g_gxState.tevStages[stageId].colorOp = {op, bias, scale, outReg, clamp}; +} +void GXSetCullMode(GX::CullMode mode) noexcept { g_gxState.cullMode = mode; } +void GXSetBlendMode(GX::BlendMode mode, GX::BlendFactor src, GX::BlendFactor dst, GX::LogicOp op) noexcept { + g_gxState.blendMode = mode; + g_gxState.blendFacSrc = src; + g_gxState.blendFacDst = dst; + g_gxState.blendOp = op; +} +void GXSetZMode(bool compare_enable, GX::Compare func, bool update_enable) noexcept { + g_gxState.depthCompare = compare_enable; + g_gxState.depthFunc = func; + g_gxState.depthUpdate = update_enable; +} +void GXSetTevColor(GX::TevRegID id, const zeus::CColor& color) noexcept { + if (id < GX::TEVREG0 || id > GX::TEVREG2) { + Log.report(logvisor::Fatal, FMT_STRING("bad tevreg {}"), id); + unreachable(); + } + g_gxState.colorRegs[id - 1] = color; +} +void GXSetTevKColor(GX::TevKColorID id, const zeus::CColor& color) noexcept { + if (id >= GX::MAX_KCOLOR) { + Log.report(logvisor::Fatal, FMT_STRING("bad kcolor {}"), id); + unreachable(); + } + g_gxState.kcolors[id] = color; +} +void GXSetAlphaUpdate(bool enabled) noexcept { g_gxState.alphaUpdate = enabled; } +void GXSetDstAlpha(bool enabled, float value) noexcept { + if (enabled) { + g_gxState.dstAlpha = value; + } else { + g_gxState.dstAlpha.reset(); + } +} +void GXSetCopyClear(const zeus::CColor& color, float depth) noexcept { g_gxState.clearColor = color; } +void GXSetTevOrder(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept { + auto& stage = g_gxState.tevStages[id]; + stage.texCoordId = tcid; + stage.texMapId = tmid; + stage.channelId = cid; +} +void GXSetTevKColorSel(GX::TevStageID id, GX::TevKColorSel sel) noexcept { g_gxState.tevStages[id].kcSel = sel; } +void GXSetTevKAlphaSel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept { g_gxState.tevStages[id].kaSel = sel; } +void GXSetChanAmbColor(GX::ChannelID id, const zeus::CColor& color) noexcept { + if (id < GX::COLOR0A0 || id > GX::COLOR1A1) { + Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id); + unreachable(); + } + g_gxState.colorChannelState[id - GX::COLOR0A0].ambColor = color; +} +void GXSetChanMatColor(GX::ChannelID id, const zeus::CColor& color) noexcept { + if (id < GX::COLOR0A0 || id > GX::COLOR1A1) { + Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id); + unreachable(); + } + g_gxState.colorChannelState[id - GX::COLOR0A0].matColor = color; +} +void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc, GX::ColorSrc matSrc, + GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept { + if (id < GX::COLOR0A0 || id > GX::COLOR1A1) { + Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id); + unreachable(); + } + if (diffFn != GX::DF_NONE && diffFn != GX::DF_CLAMP) { + Log.report(logvisor::Fatal, FMT_STRING("unhandled diffuse fn {}"), diffFn); + unreachable(); + } + if (attnFn != GX::AF_NONE && attnFn != GX::AF_SPOT) { + Log.report(logvisor::Fatal, FMT_STRING("unhandled attn fn {}"), attnFn); + unreachable(); + } + u32 idx = id - GX::COLOR0A0; + auto& chan = g_gxState.colorChannelConfig[idx]; + chan.lightingEnabled = lightingEnabled; + chan.ambSrc = ambSrc; + chan.matSrc = matSrc; + g_gxState.colorChannelState[idx].lightState = lightState; +} +void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept { + if (comp0 == GX::ALWAYS && comp1 == GX::ALWAYS) { + g_gxState.alphaDiscard.reset(); + } else if (comp0 == GX::GEQUAL && comp1 == GX::NEVER) { + g_gxState.alphaDiscard = ref0; + } else { + Log.report(logvisor::Fatal, FMT_STRING("GXSetAlphaCompare: unknown operands")); + unreachable(); + } +} +void GXSetVtxDescv(GX::VtxDescList* list) noexcept; namespace aurora::gfx { static logvisor::Module Log("aurora::gfx::gx"); @@ -14,51 +126,13 @@ extern std::mutex g_pipelineMutex; // GX state void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept { - gx::g_textures[static_cast(id)] = {tex, clamp, lod}; + gx::g_gxState.textures[static_cast(id)] = {tex, clamp, lod}; } -void unbind_texture(GX::TexMapID id) noexcept { gx::g_textures[static_cast(id)].reset(); } - -void set_cull_mode(metaforce::ERglCullMode mode) noexcept { gx::g_cullMode = mode; } -void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst, - metaforce::ERglLogicOp op) noexcept { - gx::g_blendMode = mode; - gx::g_blendFacSrc = src; - gx::g_blendFacDst = dst; - gx::g_blendOp = op; -} -void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept { - gx::g_depthCompare = compare_enable; - gx::g_depthFunc = func; - gx::g_depthUpdate = update_enable; -} -void set_tev_reg_color(GX::TevRegID id, const zeus::CColor& color) noexcept { - if (id < GX::TEVREG0 || id > GX::TEVREG2) { - Log.report(logvisor::Fatal, FMT_STRING("set_tev_reg_color: bad reg {}"), id); - unreachable(); - } - gx::g_colorRegs[id - 1] = color; -} -void set_tev_k_color(GX::TevKColorID id, const zeus::CColor& color) noexcept { - if (id >= GX::MAX_KCOLOR) { - Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_color: bad reg {}"), id); - unreachable(); - } - gx::g_kcolors[id] = color; -} -void set_alpha_update(bool enabled) noexcept { gx::g_alphaUpdate = enabled; } -void set_dst_alpha(bool enabled, float value) noexcept { - if (enabled) { - gx::g_dstAlpha = value; - } else { - gx::g_dstAlpha.reset(); - } -} -void set_clear_color(const zeus::CColor& color) noexcept { gx::g_clearColor = color; } -void set_alpha_discard(bool v) { gx::g_alphaDiscard = v; } +void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast(id)].reset(); } void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept { - gx::g_mv = mv; - gx::g_mvInv = mv_inv; + gx::g_gxState.mv = mv; + gx::g_gxState.mvInv = mv_inv; } constexpr zeus::CMatrix4f DepthCorrect{ // clang-format off @@ -68,133 +142,44 @@ constexpr zeus::CMatrix4f DepthCorrect{ 0.f, 0.f, 0.f, 1.f, // clang-format on }; -void update_projection(const zeus::CMatrix4f& proj) noexcept { gx::g_proj = DepthCorrect * proj; } -void update_fog_state(const metaforce::CFogState& state) noexcept { gx::g_fogState = state; } +void update_projection(const zeus::CMatrix4f& proj) noexcept { gx::g_gxState.proj = DepthCorrect * proj; } +void update_fog_state(const metaforce::CFogState& state) noexcept { gx::g_gxState.fogState = state; } -void disable_tev_stage(metaforce::ERglTevStage stage) noexcept { gx::g_tevStages[static_cast(stage)].reset(); } -void update_tev_stage(metaforce::ERglTevStage stage, const metaforce::CTevCombiners::ColorPass& colPass, - const metaforce::CTevCombiners::AlphaPass& alphaPass, - const metaforce::CTevCombiners::CTevOp& colorOp, - const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept { - gx::g_tevStages[static_cast(stage)] = {colPass, alphaPass, colorOp, alphaOp}; +void load_light(GX::LightID id, const Light& light) noexcept { gx::g_gxState.lights[std::log2(id)] = light; } +void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept { + gx::g_gxState.lights[std::log2(id)] = ambient; } - -void set_tev_order(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept { - auto& stage = gx::g_tevStages[id]; - if (!stage) { - // Log.report(logvisor::Fatal, FMT_STRING("set_tev_order: disabled stage {}"), id); - // unreachable(); - return; - } - stage->texCoordId = tcid; - stage->texMapId = tmid; - stage->channelId = cid; -} -void set_tev_k_color_sel(GX::TevStageID id, GX::TevKColorSel sel) noexcept { - auto& stage = gx::g_tevStages[id]; - if (!stage) { - Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_color_sel: disabled stage {}"), id); - unreachable(); - } - stage->kcSel = sel; -} -void set_tev_k_alpha_sel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept { - auto& stage = gx::g_tevStages[id]; - if (!stage) { - Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_alpha_sel: disabled stage {}"), id); - unreachable(); - } - stage->kaSel = sel; -} - -void set_chan_amb_color(GX::ChannelID id, const zeus::CColor& color) noexcept { - if (id < GX::COLOR0A0 || id > GX::COLOR1A1) { - Log.report(logvisor::Fatal, FMT_STRING("set_chan_amb_color: invalid channel {}"), id); - unreachable(); - } - gx::g_colorChannels[id - GX::COLOR0A0].ambColor = color; -} -void set_chan_mat_color(GX::ChannelID id, const zeus::CColor& color) noexcept { - if (id < GX::COLOR0A0 || id > GX::COLOR1A1) { - Log.report(logvisor::Fatal, FMT_STRING("set_chan_mat_color: invalid channel {}"), id); - unreachable(); - } - gx::g_colorChannels[id - GX::COLOR0A0].matColor = color; -} -void set_chan_mat_src(GX::ChannelID id, GX::ColorSrc src) noexcept { - if (id < GX::COLOR0A0 || id > GX::COLOR1A1) { - Log.report(logvisor::Fatal, FMT_STRING("set_chan_mat_src: invalid channel {}"), id); - unreachable(); - } - gx::g_colorChannels[id - GX::COLOR0A0].matSrc = src; -} - -static inline u8 light_idx(GX::LightID id) { -#ifdef _MSC_VER - unsigned long r = 0; - _BitScanForward(&r, id); - return r; -#else - return __builtin_ctz(id); -#endif -} -void load_light(GX::LightID id, const Light& light) noexcept { gx::g_lights[light_idx(id)] = light; } -void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept { gx::g_lights[light_idx(id)] = ambient; } -void set_light_state(std::bitset bits) noexcept { gx::g_lightState = bits; } +void set_light_state(GX::LightMask bits) noexcept { gx::g_gxState.lightState = bits; } namespace gx { using gpu::g_device; using gpu::g_graphicsConfig; -zeus::CMatrix4f g_mv; -zeus::CMatrix4f g_mvInv; -zeus::CMatrix4f g_proj; -metaforce::CFogState g_fogState; -metaforce::ERglCullMode g_cullMode; -metaforce::ERglBlendMode g_blendMode; -metaforce::ERglBlendFactor g_blendFacSrc; -metaforce::ERglBlendFactor g_blendFacDst; -metaforce::ERglLogicOp g_blendOp; -bool g_depthCompare; -bool g_depthUpdate; -metaforce::ERglEnum g_depthFunc; -std::array g_colorRegs; -std::array g_kcolors; -bool g_alphaUpdate; -std::optional g_dstAlpha; -zeus::CColor g_clearColor = zeus::skClear; -bool g_alphaDiscard; +GXState g_gxState; -std::array g_colorChannels; -std::array g_lights; -std::bitset g_lightState; +const TextureBind& get_texture(GX::TexMapID id) noexcept { return g_gxState.textures[static_cast(id)]; } -std::array, maxTevStages> g_tevStages; -std::array g_textures; - -const gx::TextureBind& get_texture(GX::TexMapID id) noexcept { return gx::g_textures[static_cast(id)]; } - -static inline wgpu::BlendFactor to_blend_factor(metaforce::ERglBlendFactor fac) { +static inline wgpu::BlendFactor to_blend_factor(GX::BlendFactor fac) { switch (fac) { - case metaforce::ERglBlendFactor::Zero: + case GX::BL_ZERO: return wgpu::BlendFactor::Zero; - case metaforce::ERglBlendFactor::One: + case GX::BL_ONE: return wgpu::BlendFactor::One; - case metaforce::ERglBlendFactor::SrcColor: + case GX::BL_SRCCLR: return wgpu::BlendFactor::Src; - case metaforce::ERglBlendFactor::InvSrcColor: + case GX::BL_INVSRCCLR: return wgpu::BlendFactor::OneMinusSrc; - case metaforce::ERglBlendFactor::SrcAlpha: + case GX::BL_SRCALPHA: return wgpu::BlendFactor::SrcAlpha; - case metaforce::ERglBlendFactor::InvSrcAlpha: + case GX::BL_INVSRCALPHA: return wgpu::BlendFactor::OneMinusSrcAlpha; - case metaforce::ERglBlendFactor::DstAlpha: + case GX::BL_DSTALPHA: return wgpu::BlendFactor::DstAlpha; - case metaforce::ERglBlendFactor::InvDstAlpha: + case GX::BL_INVDSTALPHA: return wgpu::BlendFactor::OneMinusDstAlpha; - case metaforce::ERglBlendFactor::DstColor: + case GX::BL_DSTCLR: return wgpu::BlendFactor::Dst; - case metaforce::ERglBlendFactor::InvDstColor: + case GX::BL_INVDSTCLR: return wgpu::BlendFactor::OneMinusDst; default: Log.report(logvisor::Fatal, FMT_STRING("invalid blend factor {}"), fac); @@ -202,23 +187,23 @@ static inline wgpu::BlendFactor to_blend_factor(metaforce::ERglBlendFactor fac) } } -static inline wgpu::CompareFunction to_compare_function(metaforce::ERglEnum func) { +static inline wgpu::CompareFunction to_compare_function(GX::Compare func) { switch (func) { - case metaforce::ERglEnum::Never: + case GX::NEVER: return wgpu::CompareFunction::Never; - case metaforce::ERglEnum::Less: + case GX::LESS: return wgpu::CompareFunction::Less; - case metaforce::ERglEnum::Equal: + case GX::EQUAL: return wgpu::CompareFunction::Equal; - case metaforce::ERglEnum::LEqual: + case GX::LEQUAL: return wgpu::CompareFunction::LessEqual; - case metaforce::ERglEnum::Greater: + case GX::GREATER: return wgpu::CompareFunction::Greater; - case metaforce::ERglEnum::NEqual: + case GX::NEQUAL: return wgpu::CompareFunction::NotEqual; - case metaforce::ERglEnum::GEqual: + case GX::GEQUAL: return wgpu::CompareFunction::GreaterEqual; - case metaforce::ERglEnum::Always: + case GX::ALWAYS: return wgpu::CompareFunction::Always; default: Log.report(logvisor::Fatal, FMT_STRING("invalid depth fn {}"), func); @@ -226,10 +211,10 @@ static inline wgpu::CompareFunction to_compare_function(metaforce::ERglEnum func } } -static inline wgpu::BlendState to_blend_state(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor srcFac, - metaforce::ERglBlendFactor dstFac, std::optional dstAlpha) { - if (mode != metaforce::ERglBlendMode::Blend) { - Log.report(logvisor::Fatal, FMT_STRING("How to {}?"), magic_enum::enum_name(mode)); +static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFactor srcFac, GX::BlendFactor dstFac, + std::optional dstAlpha) { + if (mode != GX::BM_BLEND) { + Log.report(logvisor::Fatal, FMT_STRING("How to {}?"), mode); } const auto colorBlendComponent = wgpu::BlendComponent{ .operation = wgpu::BlendOperation::Add, @@ -258,7 +243,7 @@ static inline wgpu::ColorWriteMask to_write_mask(bool alphaUpdate) { return writeMask; } -static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, metaforce::ERglCullMode e_cullMode) { +static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, GX::CullMode gx_cullMode) { wgpu::PrimitiveTopology primitive = wgpu::PrimitiveTopology::TriangleList; switch (gx_prim) { case GX::TRIANGLES: @@ -272,14 +257,17 @@ static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, met } wgpu::FrontFace frontFace = wgpu::FrontFace::CCW; wgpu::CullMode cullMode = wgpu::CullMode::None; - switch (e_cullMode) { - case metaforce::ERglCullMode::Front: + switch (gx_cullMode) { + case GX::CULL_FRONT: frontFace = wgpu::FrontFace::CW; cullMode = wgpu::CullMode::Front; break; - case metaforce::ERglCullMode::Back: + case GX::CULL_BACK: cullMode = wgpu::CullMode::Back; break; + case GX::CULL_ALL: + Log.report(logvisor::Fatal, FMT_STRING("Unsupported cull mode {}"), gx_cullMode); + unreachable(); default: break; } @@ -345,29 +333,24 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive, const BindGroupRanges& ranges) noexcept { - for (size_t idx = 0; const auto& item : g_tevStages) { - // Copy until disabled TEV stage (indicating end) - if (!item) { - break; - } - config.shaderConfig.tevStages[idx++] = item; + for (size_t i = 0; i < g_gxState.numTevStages; ++i) { + config.shaderConfig.tevStages[i] = g_gxState.tevStages[i]; } - config.shaderConfig.channelMatSrcs[0] = g_colorChannels[0].matSrc; - config.shaderConfig.channelMatSrcs[1] = g_colorChannels[1].matSrc; - config.shaderConfig.alphaDiscard = g_alphaDiscard; + config.shaderConfig.colorChannels = g_gxState.colorChannelConfig; + config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard; config = { .shaderConfig = config.shaderConfig, .primitive = primitive, - .depthFunc = g_depthFunc, - .cullMode = g_cullMode, - .blendMode = g_blendMode, - .blendFacSrc = g_blendFacSrc, - .blendFacDst = g_blendFacDst, - .blendOp = g_blendOp, - .dstAlpha = g_dstAlpha, - .depthCompare = g_depthCompare, - .depthUpdate = g_depthUpdate, - .alphaUpdate = g_alphaUpdate, + .depthFunc = g_gxState.depthFunc, + .cullMode = g_gxState.cullMode, + .blendMode = g_gxState.blendMode, + .blendFacSrc = g_gxState.blendFacSrc, + .blendFacDst = g_gxState.blendFacDst, + .blendOp = g_gxState.blendOp, + .dstAlpha = g_gxState.dstAlpha, + .depthCompare = g_gxState.depthCompare, + .depthUpdate = g_gxState.depthUpdate, + .alphaUpdate = g_gxState.alphaUpdate, }; // TODO separate shader info from build_shader for async { @@ -381,51 +364,51 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit Range build_uniform(const ShaderInfo& info) noexcept { auto [buf, range] = map_uniform(info.uniformSize); { - buf.append(&g_mv, 64); - buf.append(&g_mvInv, 64); - buf.append(&g_proj, 64); + buf.append(&g_gxState.mv, 64); + buf.append(&g_gxState.mvInv, 64); + buf.append(&g_gxState.proj, 64); } for (int i = 0; i < info.usesTevReg.size(); ++i) { if (!info.usesTevReg.test(i)) { continue; } - buf.append(&g_colorRegs[i], 16); - } - if (info.sampledColorChannels.any()) { - zeus::CColor ambient = zeus::skClear; - int addedLights = 0; - for (int i = 0; i < g_lightState.size(); ++i) { - if (!g_lightState.test(i)) { - continue; - } - const auto& variant = g_lights[i]; - if (std::holds_alternative(variant)) { - ambient += std::get(variant); - } else if (std::holds_alternative(variant)) { - static_assert(sizeof(Light) == 80); - buf.append(&std::get(variant), sizeof(Light)); - ++addedLights; - } - } - constexpr Light emptyLight{}; - for (int i = addedLights; i < MaxLights; ++i) { - buf.append(&emptyLight, sizeof(Light)); - } - buf.append(&ambient, 16); -// fmt::print(FMT_STRING("Added lights: {}, ambient: {},{},{},{}\n"), addedLights, ambient.r(), ambient.g(), ambient.b(), ambient.a()); + buf.append(&g_gxState.colorRegs[i], 16); } for (int i = 0; i < info.sampledColorChannels.size(); ++i) { if (!info.sampledColorChannels.test(i)) { continue; } - buf.append(&g_colorChannels[i].ambColor, 16); - buf.append(&g_colorChannels[i].matColor, 16); + buf.append(&g_gxState.colorChannelState[i].ambColor, 16); + buf.append(&g_gxState.colorChannelState[i].matColor, 16); + + if (g_gxState.colorChannelConfig[i].lightingEnabled) { + zeus::CColor ambient = zeus::skClear; + int addedLights = 0; + for (int li = 0; li < g_gxState.lightState.size(); ++li) { + if (!g_gxState.lightState.test(li)) { + continue; + } + const auto& variant = g_gxState.lights[li]; + if (std::holds_alternative(variant)) { + ambient += std::get(variant); + } else if (std::holds_alternative(variant)) { + static_assert(sizeof(Light) == 80); + buf.append(&std::get(variant), sizeof(Light)); + ++addedLights; + } + } + constexpr Light emptyLight{}; + for (int li = addedLights; li < GX::MaxLights; ++li) { + buf.append(&emptyLight, sizeof(Light)); + } + buf.append(&ambient, 16); + } } - for (int i = 0; i < info.sampledKcolors.size(); ++i) { - if (!info.sampledKcolors.test(i)) { + for (int i = 0; i < info.sampledKColors.size(); ++i) { + if (!info.sampledKColors.test(i)) { continue; } - buf.append(&g_kcolors[i], 16); + buf.append(&g_gxState.kcolors[i], 16); } for (int i = 0; i < info.sampledTextures.size(); ++i) { if (!info.sampledTextures.test(i)) { @@ -480,13 +463,13 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi .size = ranges.packedTcDataRange.second - ranges.packedTcDataRange.first, }, }; - std::array samplerEntries; - std::array textureEntries; + std::array samplerEntries; + std::array textureEntries; for (u32 texIdx = 0, i = 0; texIdx < info.sampledTextures.size(); ++texIdx) { if (!info.sampledTextures.test(texIdx)) { continue; } - const auto& tex = g_textures[texIdx]; + const auto& tex = g_gxState.textures[texIdx]; if (!tex) { Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), texIdx); unreachable(); @@ -592,8 +575,8 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader out.samplerLayout = sl; out.textureLayout = tl; } else { - std::array samplerEntries; - std::array textureEntries; + std::array samplerEntries; + std::array textureEntries; for (u32 i = 0; i < textureCount; ++i) { samplerEntries[i] = { .binding = i, @@ -637,7 +620,7 @@ void shutdown() noexcept { // TODO we should probably store this all in g_state.gx instead sUniformBindGroupLayouts.clear(); sTextureBindGroupLayouts.clear(); - g_textures.fill({}); + g_gxState.textures.fill({}); g_gxCachedShaders.clear(); } diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index 3279a8db0..d9971f83d 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -5,51 +5,36 @@ #include namespace aurora::gfx::gx { -extern zeus::CMatrix4f g_mv; -extern zeus::CMatrix4f g_mvInv; -extern zeus::CMatrix4f g_proj; -extern metaforce::CFogState g_fogState; -extern metaforce::ERglCullMode g_cullMode; -extern metaforce::ERglBlendMode g_blendMode; -extern metaforce::ERglBlendFactor g_blendFacSrc; -extern metaforce::ERglBlendFactor g_blendFacDst; -extern metaforce::ERglLogicOp g_blendOp; -extern bool g_depthCompare; -extern bool g_depthUpdate; -extern metaforce::ERglEnum g_depthFunc; -extern std::array g_colorRegs; -extern std::array g_kcolors; -extern bool g_alphaUpdate; -extern std::optional g_dstAlpha; -extern zeus::CColor g_clearColor; -extern bool g_alphaDiscard; +constexpr u32 MaxTextures = GX::MAX_TEXMAP; +constexpr u32 MaxTevStages = GX::MAX_TEVSTAGE; +constexpr u32 MaxColorChannels = 2; // COLOR0A0, COLOR1A1 +constexpr u32 MaxTevRegs = 3; // TEVREG0-2 +constexpr u32 MaxKColors = GX::MAX_KCOLOR; -struct SChannelState { - zeus::CColor matColor; - zeus::CColor ambColor; - GX::ColorSrc matSrc; +template +struct TevPass { + Arg a = Default; + Arg b = Default; + Arg c = Default; + Arg d = Default; }; -extern std::array g_colorChannels; -using LightVariant = std::variant; -extern std::array g_lights; -extern std::bitset g_lightState; - -struct STevStage { - metaforce::CTevCombiners::ColorPass colorPass; - metaforce::CTevCombiners::AlphaPass alphaPass; - metaforce::CTevCombiners::CTevOp colorOp; - metaforce::CTevCombiners::CTevOp alphaOp; +struct TevOp { + GX::TevOp op = GX::TevOp::TEV_ADD; + GX::TevBias bias = GX::TevBias::TB_ZERO; + GX::TevScale scale = GX::TevScale::CS_SCALE_1; + GX::TevRegID outReg = GX::TevRegID::TEVPREV; + bool clamp = true; +}; +struct TevStage { + TevPass colorPass; + TevPass alphaPass; + TevOp colorOp; + TevOp alphaOp; GX::TevKColorSel kcSel = GX::TEV_KCSEL_1; GX::TevKAlphaSel kaSel = GX::TEV_KASEL_1; GX::TexCoordID texCoordId = GX::TEXCOORD_NULL; GX::TexMapID texMapId = GX::TEXMAP_NULL; GX::ChannelID channelId = GX::COLOR_NULL; - - constexpr STevStage(const metaforce::CTevCombiners::ColorPass& colPass, - const metaforce::CTevCombiners::AlphaPass& alphaPass, - const metaforce::CTevCombiners::CTevOp& colorOp, - const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept - : colorPass(colPass), alphaPass(alphaPass), colorOp(colorOp), alphaOp(alphaOp) {} }; struct TextureBind { aurora::gfx::TextureHandle handle; @@ -63,32 +48,72 @@ struct TextureBind { [[nodiscard]] wgpu::SamplerDescriptor get_descriptor() const noexcept; operator bool() const noexcept { return handle; } }; +// For shader generation +struct ColorChannelConfig { + GX::ColorSrc matSrc = GX::SRC_REG; + GX::ColorSrc ambSrc = GX::SRC_REG; + bool lightingEnabled = false; +}; +// For uniform generation +struct ColorChannelState { + zeus::CColor matColor = zeus::skClear; + zeus::CColor ambColor = zeus::skClear; + GX::LightMask lightState; +}; +using LightVariant = std::variant; -constexpr u32 maxTevStages = GX::MAX_TEVSTAGE; -extern std::array, maxTevStages> g_tevStages; -constexpr u32 maxTextures = 8; -extern std::array g_textures; +struct GXState { + zeus::CMatrix4f mv; + zeus::CMatrix4f mvInv; + zeus::CMatrix4f proj; + metaforce::CFogState fogState; + GX::CullMode cullMode = GX::CULL_BACK; + GX::BlendMode blendMode = GX::BM_NONE; + GX::BlendFactor blendFacSrc = GX::BL_SRCALPHA; + GX::BlendFactor blendFacDst = GX::BL_INVSRCALPHA; + GX::LogicOp blendOp = GX::LO_CLEAR; + GX::Compare depthFunc = GX::LEQUAL; + zeus::CColor clearColor = zeus::skBlack; + std::optional dstAlpha; + std::optional alphaDiscard; + std::array colorRegs; + std::array kcolors; + std::array colorChannelConfig; + std::array colorChannelState; + std::array lights; + std::array tevStages; + std::array textures; + GX::LightMask lightState; + bool depthCompare = true; + bool depthUpdate = true; + bool alphaUpdate = true; + u8 numChans = 0; + u8 numIndStages = 0; + u8 numTevStages = 0; + u8 numTexGens = 0; +}; +extern GXState g_gxState; -static inline Mat4x4 get_combined_matrix() noexcept { return g_proj * g_mv; } +static inline Mat4x4 get_combined_matrix() noexcept { return g_gxState.proj * g_gxState.mv; } void shutdown() noexcept; const TextureBind& get_texture(GX::TexMapID id) noexcept; struct ShaderConfig { - std::array, maxTevStages> tevStages; - std::array channelMatSrcs; - bool alphaDiscard = false; + std::array, MaxTevStages> tevStages; + std::array colorChannels; + std::optional alphaDiscard; bool denormalizedVertexAttributes = false; bool denormalizedHasNrm = false; // TODO this is a hack }; struct PipelineConfig { ShaderConfig shaderConfig; GX::Primitive primitive; - metaforce::ERglEnum depthFunc; - metaforce::ERglCullMode cullMode; - metaforce::ERglBlendMode blendMode; - metaforce::ERglBlendFactor blendFacSrc, blendFacDst; - metaforce::ERglLogicOp blendOp; + GX::Compare depthFunc; + GX::CullMode cullMode; + GX::BlendMode blendMode; + GX::BlendFactor blendFacSrc, blendFacDst; + GX::LogicOp blendOp; std::optional dstAlpha; bool depthCompare, depthUpdate, alphaUpdate; }; @@ -105,10 +130,10 @@ struct GXBindGroups { // Output info from shader generation struct ShaderInfo { GXBindGroups bindGroups; - std::bitset sampledTextures; - std::bitset<4> sampledKcolors; - std::bitset<2> sampledColorChannels; - std::bitset<3> usesTevReg; + std::bitset sampledTextures; + std::bitset sampledKColors; + std::bitset sampledColorChannels; + std::bitset usesTevReg; u32 uniformSize = 0; bool usesVtxColor : 1 = false; bool usesNormal : 1 = false; @@ -143,25 +168,41 @@ struct DlVert { } // namespace aurora::gfx::gx namespace aurora { -template <> -inline void xxh3_update(XXH3_state_t& state, const metaforce::CTevCombiners::CTevOp& input) { - XXH3_64bits_update(&state, &input.x0_clamp, sizeof(bool)); - XXH3_64bits_update(&state, &input.x4_op, sizeof(metaforce::CTevCombiners::CTevOp::x4_op)); - XXH3_64bits_update(&state, &input.x8_bias, sizeof(metaforce::CTevCombiners::CTevOp::x8_bias)); - XXH3_64bits_update(&state, &input.xc_scale, sizeof(metaforce::CTevCombiners::CTevOp::xc_scale)); - XXH3_64bits_update(&state, &input.x10_regId, sizeof(metaforce::CTevCombiners::CTevOp::x10_regId)); +template +inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevPass& input) { + XXH3_64bits_update(&state, &input.a, sizeof(Arg)); + XXH3_64bits_update(&state, &input.b, sizeof(Arg)); + XXH3_64bits_update(&state, &input.c, sizeof(Arg)); + XXH3_64bits_update(&state, &input.d, sizeof(Arg)); } template <> -inline void xxh3_update(XXH3_state_t& state, const gfx::gx::STevStage& input) { - XXH3_64bits_update(&state, &input.colorPass, sizeof(gfx::gx::STevStage::colorPass)); - XXH3_64bits_update(&state, &input.alphaPass, sizeof(gfx::gx::STevStage::alphaPass)); +inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevOp& input) { + XXH3_64bits_update(&state, &input.op, sizeof(gfx::gx::TevOp::op)); + XXH3_64bits_update(&state, &input.bias, sizeof(gfx::gx::TevOp::bias)); + XXH3_64bits_update(&state, &input.scale, sizeof(gfx::gx::TevOp::scale)); + XXH3_64bits_update(&state, &input.outReg, sizeof(gfx::gx::TevOp::outReg)); + XXH3_64bits_update(&state, &input.clamp, sizeof(bool)); +} +template <> +inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevStage& input) { + xxh3_update(state, input.colorPass); + xxh3_update(state, input.alphaPass); xxh3_update(state, input.colorOp); xxh3_update(state, input.alphaOp); - XXH3_64bits_update(&state, &input.kcSel, sizeof(gfx::gx::STevStage::kcSel)); - XXH3_64bits_update(&state, &input.kaSel, sizeof(gfx::gx::STevStage::kaSel)); - XXH3_64bits_update(&state, &input.texCoordId, sizeof(gfx::gx::STevStage::texCoordId)); - XXH3_64bits_update(&state, &input.texMapId, sizeof(gfx::gx::STevStage::texMapId)); - XXH3_64bits_update(&state, &input.channelId, sizeof(gfx::gx::STevStage::channelId)); + XXH3_64bits_update(&state, &input.kcSel, sizeof(gfx::gx::TevStage::kcSel)); + XXH3_64bits_update(&state, &input.kaSel, sizeof(gfx::gx::TevStage::kaSel)); + XXH3_64bits_update(&state, &input.texCoordId, sizeof(gfx::gx::TevStage::texCoordId)); + XXH3_64bits_update(&state, &input.texMapId, sizeof(gfx::gx::TevStage::texMapId)); + XXH3_64bits_update(&state, &input.channelId, sizeof(gfx::gx::TevStage::channelId)); +} +template <> +inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ColorChannelConfig& input) { + XXH3_64bits_update(&state, &input.lightingEnabled, sizeof(gfx::gx::ColorChannelConfig::lightingEnabled)); + XXH3_64bits_update(&state, &input.matSrc, sizeof(gfx::gx::ColorChannelConfig::matSrc)); + if (input.lightingEnabled) { + // Unused when lighting is disabled + XXH3_64bits_update(&state, &input.ambSrc, sizeof(gfx::gx::ColorChannelConfig::ambSrc)); + } } template <> inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) { @@ -171,10 +212,12 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) } xxh3_update(state, *item); } - for (const auto& item : input.channelMatSrcs) { - XXH3_64bits_update(&state, &item, sizeof(GX::ColorSrc)); + for (const auto& item : input.colorChannels) { + xxh3_update(state, item); + } + if (input.alphaDiscard) { + XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float)); } - XXH3_64bits_update(&state, &input.alphaDiscard, sizeof(bool)); XXH3_64bits_update(&state, &input.denormalizedVertexAttributes, sizeof(bool)); XXH3_64bits_update(&state, &input.denormalizedHasNrm, sizeof(bool)); } diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index 8ff927ea2..7ec787e02 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -12,7 +12,7 @@ static logvisor::Module Log("aurora::gfx::gx"); std::unordered_map> g_gxCachedShaders; -static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STevStage& stage, ShaderInfo& info) { +static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) { switch (arg) { case GX::CC_CPREV: return "prev.rgb"; @@ -105,64 +105,64 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STe case GX::TEV_KCSEL_1_8: return "(1.0/8.0)"; case GX::TEV_KCSEL_K0: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.rgb"; case GX::TEV_KCSEL_K1: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.rgb"; case GX::TEV_KCSEL_K2: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.rgb"; case GX::TEV_KCSEL_K3: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.rgb"; case GX::TEV_KCSEL_K0_R: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.r"; case GX::TEV_KCSEL_K1_R: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.r"; case GX::TEV_KCSEL_K2_R: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.r"; case GX::TEV_KCSEL_K3_R: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.r"; case GX::TEV_KCSEL_K0_G: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.g"; case GX::TEV_KCSEL_K1_G: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.g"; case GX::TEV_KCSEL_K2_G: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.g"; case GX::TEV_KCSEL_K3_G: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.g"; case GX::TEV_KCSEL_K0_B: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.b"; case GX::TEV_KCSEL_K1_B: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.b"; case GX::TEV_KCSEL_K2_B: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.b"; case GX::TEV_KCSEL_K3_B: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.b"; case GX::TEV_KCSEL_K0_A: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.a"; case GX::TEV_KCSEL_K1_A: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.a"; case GX::TEV_KCSEL_K2_A: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.a"; case GX::TEV_KCSEL_K3_A: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.a"; default: Log.report(logvisor::Fatal, FMT_STRING("invalid kcSel {}"), stage.kcSel); @@ -177,7 +177,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STe } } -static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const STevStage& stage, ShaderInfo& info) { +static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) { switch (arg) { case GX::CA_APREV: return "prev.a"; @@ -232,52 +232,52 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const STe case GX::TEV_KASEL_1_8: return "(1.0/8.0)"; case GX::TEV_KASEL_K0_R: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.r"; case GX::TEV_KASEL_K1_R: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.r"; case GX::TEV_KASEL_K2_R: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.r"; case GX::TEV_KASEL_K3_R: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.r"; case GX::TEV_KASEL_K0_G: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.g"; case GX::TEV_KASEL_K1_G: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.g"; case GX::TEV_KASEL_K2_G: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.g"; case GX::TEV_KASEL_K3_G: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.g"; case GX::TEV_KASEL_K0_B: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.b"; case GX::TEV_KASEL_K1_B: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.b"; case GX::TEV_KASEL_K2_B: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.b"; case GX::TEV_KASEL_K3_B: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.b"; case GX::TEV_KASEL_K0_A: - info.sampledKcolors.set(0); + info.sampledKColors.set(0); return "ubuf.kcolor0.a"; case GX::TEV_KASEL_K1_A: - info.sampledKcolors.set(1); + info.sampledKColors.set(1); return "ubuf.kcolor1.a"; case GX::TEV_KASEL_K2_A: - info.sampledKcolors.set(2); + info.sampledKColors.set(2); return "ubuf.kcolor2.a"; case GX::TEV_KASEL_K3_A: - info.sampledKcolors.set(3); + info.sampledKColors.set(3); return "ubuf.kcolor3.a"; default: Log.report(logvisor::Fatal, FMT_STRING("invalid kaSel {}"), stage.kaSel); @@ -352,34 +352,34 @@ std::pair build_shader(const ShaderConfig& confi break; } Log.report(logvisor::Info, FMT_STRING(" tevStages[{}]:"), i); - Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage->colorPass.x0_a); - Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage->colorPass.x4_b); - Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage->colorPass.x8_c); - Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage->colorPass.xc_d); - Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage->alphaPass.x0_a); - Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage->alphaPass.x4_b); - Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage->alphaPass.x8_c); - Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage->alphaPass.xc_d); - Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage->colorOp.x0_clamp); - Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage->colorOp.x4_op); - Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage->colorOp.x8_bias); - Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage->colorOp.xc_scale); - Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage->colorOp.x10_regId); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage->alphaOp.x0_clamp); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage->alphaOp.x4_op); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage->alphaOp.x8_bias); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage->alphaOp.xc_scale); - Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage->alphaOp.x10_regId); + Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage->colorPass.a); + Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage->colorPass.b); + Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage->colorPass.c); + Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage->colorPass.d); + Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage->alphaPass.a); + Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage->alphaPass.b); + Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage->alphaPass.c); + Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage->alphaPass.d); + Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage->colorOp.clamp); + Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage->colorOp.op); + Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage->colorOp.bias); + Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage->colorOp.scale); + Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage->colorOp.outReg); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage->alphaOp.clamp); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage->alphaOp.op); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage->alphaOp.bias); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage->alphaOp.scale); + Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage->alphaOp.outReg); Log.report(logvisor::Info, FMT_STRING(" kc_sel: {}"), stage->kcSel); Log.report(logvisor::Info, FMT_STRING(" ka_sel: {}"), stage->kaSel); Log.report(logvisor::Info, FMT_STRING(" texCoordId: {}"), stage->texCoordId); Log.report(logvisor::Info, FMT_STRING(" texMapId: {}"), stage->texMapId); Log.report(logvisor::Info, FMT_STRING(" channelId: {}"), stage->channelId); } - for (int i = 0; i < config.channelMatSrcs.size(); ++i) { - Log.report(logvisor::Info, FMT_STRING(" channelMatSrcs[{}]: {}"), i, config.channelMatSrcs[i]); - } - Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard); + // for (int i = 0; i < config.channelMatSrcs.size(); ++i) { + // Log.report(logvisor::Info, FMT_STRING(" channelMatSrcs[{}]: {}"), i, config.channelMatSrcs[i]); + // } + // Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard); Log.report(logvisor::Info, FMT_STRING(" denormalizedVertexAttributes: {}"), config.denormalizedVertexAttributes); } @@ -396,14 +396,16 @@ std::pair build_shader(const ShaderConfig& confi if (config.denormalizedVertexAttributes) { vtxInAttrs += "\n @location(0) in_pos: vec3"; vtxOutAttrs += "\n @builtin(position) pos: vec4;"; - vtxXfrAttrsPre += "\n var obj_pos = vec4(in_pos, 1.0);" + vtxXfrAttrsPre += + "\n var obj_pos = vec4(in_pos, 1.0);" "\n var mv_pos = ubuf.mv * obj_pos;" "\n out.pos = ubuf.proj * mv_pos;"; if (config.denormalizedHasNrm) { vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3;"), locIdx); vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_nrm: vec3"), ++locIdx); vtxXfrAttrs += fmt::format(FMT_STRING("\n out.nrm = in_nrm;")); - vtxXfrAttrsPre += "\n var obj_norm = vec4(in_nrm, 0.0);" + vtxXfrAttrsPre += + "\n var obj_norm = vec4(in_nrm, 0.0);" "\n var mv_norm = ubuf.mv_inv * obj_norm;"; info.usesNormal = true; } @@ -429,7 +431,8 @@ var v_packed_uvs: Vec2Block; "\n , @location(1) in_uv_0_4_idx: vec4" "\n , @location(2) in_uv_5_7_idx: vec4"; vtxOutAttrs += "\n @builtin(position) pos: vec4;"; - vtxXfrAttrsPre += "\n var obj_pos = vec4(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);" + vtxXfrAttrsPre += + "\n var obj_pos = vec4(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);" "\n var obj_norm = vec4(v_verts.data[in_pos_nrm_idx[1]].xyz, 0.0);" "\n var mv_pos = ubuf.mv * obj_pos;" "\n var mv_norm = ubuf.mv_inv * obj_norm;" @@ -444,7 +447,7 @@ var v_packed_uvs: Vec2Block; } { std::string outReg; - switch (stage->colorOp.x10_regId) { + switch (stage->colorOp.outReg) { case GX::TevRegID::TEVPREV: outReg = "prev"; break; @@ -461,23 +464,21 @@ var v_packed_uvs: Vec2Block; info.usesTevReg.set(2); break; default: - Log.report(logvisor::Fatal, FMT_STRING("TODO: colorOp outReg {}"), stage->colorOp.x10_regId); + Log.report(logvisor::Fatal, FMT_STRING("TODO: colorOp outReg {}"), stage->colorOp.outReg); } - std::string op = - fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), - color_arg_reg(stage->colorPass.x0_a, idx, *stage, info), - color_arg_reg(stage->colorPass.x4_b, idx, *stage, info), - color_arg_reg(stage->colorPass.x8_c, idx, *stage, info), - color_arg_reg(stage->colorPass.xc_d, idx, *stage, info), tev_op(stage->colorOp.x4_op), - tev_bias(stage->colorOp.x8_bias), tev_scale(stage->colorOp.xc_scale)); - if (stage->colorOp.x0_clamp) { + std::string op = fmt::format( + FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), + color_arg_reg(stage->colorPass.a, idx, *stage, info), color_arg_reg(stage->colorPass.b, idx, *stage, info), + color_arg_reg(stage->colorPass.c, idx, *stage, info), color_arg_reg(stage->colorPass.d, idx, *stage, info), + tev_op(stage->colorOp.op), tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale)); + if (stage->colorOp.clamp) { op = fmt::format(FMT_STRING("clamp(vec3({}), vec3(0.0), vec3(1.0))"), op); } fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4({1}, {0}.a);"), outReg, op); } { std::string outReg; - switch (stage->alphaOp.x10_regId) { + switch (stage->alphaOp.outReg) { case GX::TevRegID::TEVPREV: outReg = "prev.a"; break; @@ -494,16 +495,14 @@ var v_packed_uvs: Vec2Block; info.usesTevReg.set(2); break; default: - Log.report(logvisor::Fatal, FMT_STRING("TODO: alphaOp outReg {}"), stage->alphaOp.x10_regId); + Log.report(logvisor::Fatal, FMT_STRING("TODO: alphaOp outReg {}"), stage->alphaOp.outReg); } - std::string op = - fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), - alpha_arg_reg(stage->alphaPass.x0_a, idx, *stage, info), - alpha_arg_reg(stage->alphaPass.x4_b, idx, *stage, info), - alpha_arg_reg(stage->alphaPass.x8_c, idx, *stage, info), - alpha_arg_reg(stage->alphaPass.xc_d, idx, *stage, info), tev_op(stage->alphaOp.x4_op), - tev_bias(stage->alphaOp.x8_bias), tev_scale(stage->alphaOp.xc_scale)); - if (stage->alphaOp.x0_clamp) { + std::string op = fmt::format( + FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), + alpha_arg_reg(stage->alphaPass.a, idx, *stage, info), alpha_arg_reg(stage->alphaPass.b, idx, *stage, info), + alpha_arg_reg(stage->alphaPass.c, idx, *stage, info), alpha_arg_reg(stage->alphaPass.d, idx, *stage, info), + tev_op(stage->alphaOp.op), tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale)); + if (stage->alphaOp.clamp) { op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op); } fragmentFn += fmt::format(FMT_STRING("\n {0} = {1};"), outReg, op); @@ -518,19 +517,7 @@ var v_packed_uvs: Vec2Block; fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i); info.uniformSize += 16; } - if (info.sampledColorChannels.any()) { - uniformPre += "\n" - "struct Light {\n" - " pos: vec3;\n" - " dir: vec3;\n" - " color: vec4;\n" - " lin_att: vec3;\n" - " ang_att: vec3;\n" - "};"; - uniBufAttrs += fmt::format(FMT_STRING("\n lights: array;"), MaxLights); - uniBufAttrs += "\n lighting_ambient: vec4;"; - info.uniformSize += (80 * MaxLights) + 16; - } + bool addedLightStruct = false; for (int i = 0; i < info.sampledColorChannels.size(); ++i) { if (!info.sampledColorChannels.test(i)) { continue; @@ -540,26 +527,30 @@ var v_packed_uvs: Vec2Block; uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4;"), i); info.uniformSize += 32; - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), locIdx++, i); - - if (config.channelMatSrcs[i] == GX::SRC_VTX) { - if (config.denormalizedVertexAttributes) { - if (!info.usesVtxColor) { - vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4"), locIdx); - vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i); - } - fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); - } else { - Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes")); + if (config.colorChannels[i].lightingEnabled) { + if (!addedLightStruct) { + uniformPre += + "\n" + "struct Light {\n" + " pos: vec3;\n" + " dir: vec3;\n" + " color: vec4;\n" + " lin_att: vec3;\n" + " ang_att: vec3;\n" + "};"; + addedLightStruct = true; } - info.usesVtxColor = true; - } else { - // TODO only perform lighting on CC0 when enabled + + uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array;"), i, GX::MaxLights); + uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4;"), i); + info.uniformSize += (80 * GX::MaxLights) + 16; + + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), locIdx++, i); vtxXfrAttrs += fmt::format(FMT_STRING(R"""( {{ - var lighting = ubuf.lighting_ambient + ubuf.cc{0}_amb; + var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb; for (var i = 0; i < {1}; i = i + 1) {{ - var light = ubuf.lights[i]; + var light = ubuf.lights{0}[i]; var delta = mv_pos.xyz - light.pos; var dist = length(delta); var delta_norm = delta / dist; @@ -575,12 +566,27 @@ var v_packed_uvs: Vec2Block; lighting = lighting + vec4(this_color, 0.0); }} out.cc{0} = clamp(lighting, vec4(0.0), vec4(1.0)); - }})"""), i, MaxLights); + }})"""), + i, GX::MaxLights); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); + } else if (config.colorChannels[i].matSrc == GX::SRC_VTX) { + if (config.denormalizedVertexAttributes) { + if (!info.usesVtxColor) { + vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4"), locIdx); + } + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), locIdx++, i); + vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i); + fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); + } else { + Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes")); + } + info.usesVtxColor = true; + } else { + fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i); } } - for (int i = 0; i < info.sampledKcolors.size(); ++i) { - if (!info.sampledKcolors.test(i)) { + for (int i = 0; i < info.sampledKColors.size(); ++i) { + if (!info.sampledKColors.test(i)) { continue; } uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4;"), i); @@ -622,6 +628,9 @@ var v_packed_uvs: Vec2Block; FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i); locIdx++; } + if (config.alphaDiscard) { + fragmentFn += fmt::format(FMT_STRING("\n if (prev.a < {}f) {{ discard; }}"), *config.alphaDiscard); + } const auto shaderSource = fmt::format(FMT_STRING(R"""({uniformPre} diff --git a/aurora/lib/gfx/model/shader.cpp b/aurora/lib/gfx/model/shader.cpp index 815a408ea..3559abea5 100644 --- a/aurora/lib/gfx/model/shader.cpp +++ b/aurora/lib/gfx/model/shader.cpp @@ -54,10 +54,10 @@ static const std::vector* nrmData; static const std::vector>* tex0TcData; static const std::vector>* tcData; -void set_vertex_buffer(const std::vector* data) noexcept { vtxData = data; } -void set_normal_buffer(const std::vector* norm) noexcept { nrmData = norm; } -void set_tex0_tc_buffer(const std::vector>* tcs) noexcept { tex0TcData = tcs; } -void set_tc_buffer(const std::vector>* tcs) noexcept { tcData = tcs; } +// void set_vertex_buffer(const std::vector* data) noexcept { vtxData = data; } +// void set_normal_buffer(const std::vector* norm) noexcept { nrmData = norm; } +// void set_tex0_tc_buffer(const std::vector>* tcs) noexcept { tex0TcData = tcs; } +// void set_tc_buffer(const std::vector>* tcs) noexcept { tcData = tcs; } enum class VertexFormat : u8 { F32F32, @@ -233,3 +233,27 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco pass.DrawIndexed(data.indexCount); } } // namespace aurora::gfx::model + +void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept { + switch (attr) { + case GX::VA_POS: + aurora::gfx::model::vtxData = static_cast*>(data); + break; + case GX::VA_NRM: + aurora::gfx::model::nrmData = static_cast*>(data); + break; + case GX::VA_TEX0: + aurora::gfx::model::tex0TcData = static_cast>*>(data); + break; + case GX::VA_TEX1: + aurora::gfx::model::tcData = static_cast>*>(data); + break; + default: + aurora::gfx::model::Log.report(logvisor::Fatal, FMT_STRING("GXSetArray: invalid attr {}"), attr); + unreachable(); + } +} + +void GXCallDisplayList(const void* data, u32 nbytes) noexcept { + aurora::gfx::model::queue_surface(static_cast(data), nbytes); +}