From cd86dbd6ee46df785458e324ad8c4a5763adbd61 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 6 Mar 2022 02:46:42 -0500 Subject: [PATCH] More CCubeMaterial, more CGraphics, more aurora::gx --- Runtime/Character/CActorLights.cpp | 7 +- Runtime/Graphics/CCubeMaterial.cpp | 68 ++++++++--- Runtime/Graphics/CCubeMaterial.hpp | 2 +- Runtime/Graphics/CCubeRenderer.cpp | 14 ++- Runtime/Graphics/CCubeRenderer.hpp | 3 +- Runtime/Graphics/CGraphics.cpp | 103 ++++++++++++---- Runtime/Graphics/CGraphics.hpp | 24 +--- Runtime/Graphics/CModel.cpp | 2 +- Runtime/Graphics/CMoviePlayer.cpp | 38 ++---- Runtime/Graphics/CMoviePlayer.hpp | 3 - Runtime/Graphics/GX.hpp | 2 + Runtime/Graphics/IRenderer.hpp | 2 +- Runtime/GuiSys/CGuiFrame.cpp | 15 +-- Runtime/GuiSys/CGuiFrame.hpp | 3 +- Runtime/MP1/CFrontEndUI.cpp | 33 +++--- Runtime/Particle/CElementGen.hpp | 2 +- aurora/CMakeLists.txt | 1 + aurora/include/aurora/gfx.hpp | 63 ++++++++-- aurora/include/aurora/model.hpp | 5 + aurora/lib/aurora.cpp | 9 +- aurora/lib/gfx/colored_quad/shader.cpp | 1 + aurora/lib/gfx/common.cpp | 65 +--------- aurora/lib/gfx/common.hpp | 20 ---- aurora/lib/gfx/gx.cpp | 150 ++++++++++++++++++++++++ aurora/lib/gfx/gx.hpp | 60 ++++++++++ aurora/lib/gfx/movie_player/shader.cpp | 51 ++------ aurora/lib/gfx/movie_player/shader.hpp | 7 +- aurora/lib/gfx/stream.cpp | 29 +---- aurora/lib/gfx/textured_quad/shader.cpp | 1 + 29 files changed, 484 insertions(+), 299 deletions(-) create mode 100644 aurora/include/aurora/model.hpp create mode 100644 aurora/lib/gfx/gx.cpp create mode 100644 aurora/lib/gfx/gx.hpp diff --git a/Runtime/Character/CActorLights.cpp b/Runtime/Character/CActorLights.cpp index a1e0355c3..114d0d5c7 100644 --- a/Runtime/Character/CActorLights.cpp +++ b/Runtime/Character/CActorLights.cpp @@ -472,13 +472,12 @@ void CActorLights::ActivateLights() const { if (lights.empty()) { CGraphics::DisableAllLights(); } else { - for (int idx = 0; const auto& item : lights) { - CGraphics::LoadLight(static_cast(idx), item); + for (ERglLight idx = 0; const auto& item : lights) { + CGraphics::LoadLight(idx, item); idx++; } // Sets n LSB to 1 - auto bits = static_cast((1 << lights.size()) + 255); - CGraphics::SetLightState(static_cast(bits)); + CGraphics::SetLightState(static_cast((1 << lights.size()) + 255)); } if (x298_31_disableWorldLights) { diff --git a/Runtime/Graphics/CCubeMaterial.cpp b/Runtime/Graphics/CCubeMaterial.cpp index 13f6f1cc1..1d9ad72b1 100644 --- a/Runtime/Graphics/CCubeMaterial.cpp +++ b/Runtime/Graphics/CCubeMaterial.cpp @@ -76,17 +76,17 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur u32 finalKColorCount = 0; if (matFlags & CCubeMaterialFlagBits::fKonstValues) { - u32 konstCount = *reinterpret_cast(materialDataCur); + u32 konstCount = SBig(*reinterpret_cast(materialDataCur)); finalKColorCount = konstCount; materialDataCur += 4; for (u32 i = 0; i < konstCount; ++i) { - u32 kColor = *reinterpret_cast(materialDataCur); + u32 kColor = SBig(*reinterpret_cast(materialDataCur)); materialDataCur += 4; - // TODO set KColor + aurora::gfx::set_tev_k_color(static_cast(i), kColor); } } - u32 blendFactors = *reinterpret_cast(materialDataCur); + u32 blendFactors = SBig(*reinterpret_cast(materialDataCur)); materialDataCur += 4; if (g_Renderer->IsInAreaDraw()) { // TODO blackout fog, additive blend @@ -128,25 +128,27 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur finalTevCount = firstTev + 1; u32 ccFlags = SBig(*reinterpret_cast(materialDataCur + 8)); finalCCFlags = ccFlags; - u32 outputReg = ccFlags >> 9 & 0x3; - if (outputReg == 1) { // TevReg0 + auto outputReg = static_cast(ccFlags >> 9 & 0x3); + if (outputReg == GX::TEVREG0) { materialDataCur += 20; texMapTexCoordFlags += 1; finalCCFlags = SBig(*reinterpret_cast(materialDataCur + 8)); - // Set TevReg0 = 0xc0c0c0c0 + aurora::gfx::set_tev_reg_color(GX::TEVREG0, 0xc0c0c0c0); } finalACFlags = SBig(*reinterpret_cast(materialDataCur + 12)); - HandleTev(firstTev, materialDataCur, texMapTexCoordFlags, CCubeModel::sRenderModelShadow); + HandleTev(firstTev, reinterpret_cast(materialDataCur), texMapTexCoordFlags, + CCubeModel::sRenderModelShadow); usesTevReg2 = false; } else { finalTevCount = firstTev + matTevCount; for (u32 i = firstTev; i < finalTevCount; ++i) { - HandleTev(i, materialDataCur, texMapTexCoordFlags, CCubeModel::sRenderModelShadow && i == firstTev); + HandleTev(i, reinterpret_cast(materialDataCur), texMapTexCoordFlags, + CCubeModel::sRenderModelShadow && i == firstTev); u32 ccFlags = SBig(*reinterpret_cast(materialDataCur + 8)); finalCCFlags = ccFlags; finalACFlags = SBig(*reinterpret_cast(materialDataCur + 12)); - u32 outputReg = ccFlags >> 9 & 0x3; - if (outputReg == 3) { // TevReg2 + auto outputReg = static_cast(ccFlags >> 9 & 0x3); + if (outputReg == GX::TEVREG2) { usesTevReg2 = true; } materialDataCur += 20; @@ -310,10 +312,34 @@ u32 CCubeMaterial::HandleColorChannels(u32 chanCount, u32 firstChan) { return chanCount; } -void CCubeMaterial::HandleTev(u32 tevCur, const u8* materialDataCur, const u32* texMapTexCoordFlags, +void CCubeMaterial::HandleTev(u32 tevCur, const u32* materialDataCur, const u32* texMapTexCoordFlags, bool shadowMapsEnabled) { - u32 colorArgs = shadowMapsEnabled ? 0x7a04f : SBig(*materialDataCur); - // CGX::SetStandardDirectTev_Compressed + const u32 colorArgs = shadowMapsEnabled ? 0x7a04f : SBig(materialDataCur[0]); + const u32 alphaArgs = SBig(materialDataCur[1]); + 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); + + 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)); } u32 CCubeMaterial::HandleAnimatedUV(const u32* uvAnim, u32 texMtx, u32 pttTexMtx) { @@ -409,17 +435,27 @@ u32 CCubeMaterial::HandleReflection(bool usesTevReg2, u32 indTexSlot, u32 r5, u3 } else { // GX_CC_KONST } - // set reflection kcolor + 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)); + + const auto stage = static_cast(finalTevCount + out); // tex = g_Renderer->GetRealReflection // tex.Load(texCount, 0) + // TODO + finalACFlags = 0; finalCCFlags = 0; + + // aurora::gfx::set_tev_order(stage, ...) + return out + 1; } void CCubeMaterial::DoPassthru(u32 finalTevCount) { - // TODO + aurora::gfx::disable_tev_stage(static_cast(finalTevCount)); } void CCubeMaterial::DoModelShadow(u32 texCount, u32 tcgCount) { diff --git a/Runtime/Graphics/CCubeMaterial.hpp b/Runtime/Graphics/CCubeMaterial.hpp index c55b29baf..3b25a0ef0 100644 --- a/Runtime/Graphics/CCubeMaterial.hpp +++ b/Runtime/Graphics/CCubeMaterial.hpp @@ -96,7 +96,7 @@ private: static void SetupBlendMode(u32 blendFactors, const CModelFlags& flags, bool alphaTest); static void HandleDepth(CModelFlagsFlags modelFlags, CCubeMaterialFlags matFlags); static u32 HandleColorChannels(u32 chanCount, u32 firstChan); - static void HandleTev(u32 tevCur, const u8* materialDataCur, const u32* texMapTexCoordFlags, bool shadowMapsEnabled); + static void HandleTev(u32 tevCur, const u32* materialDataCur, const u32* texMapTexCoordFlags, bool shadowMapsEnabled); static u32 HandleAnimatedUV(const u32* uvAnim, u32 texMtx, u32 pttTexMtx); static void HandleTransparency(u32& finalTevCount, u32& finalKColorCount, const CModelFlags& modelFlags, u32 blendFactors, u32& finalCCFlags, u32& finalACFlags); diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index f5c827f8f..8a260cd02 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -472,14 +472,11 @@ void CCubeRenderer::DoThermalBlendHot() {} u32 CCubeRenderer::GetStaticWorldDataSize() { return 0; } void CCubeRenderer::SetGXRegister1Color(const zeus::CColor& color) { - CGraphics::g_ColorRegs[1] = color; - aurora::gfx::set_gx_reg1_color(color); + aurora::gfx::set_tev_reg_color(GX::TevRegID::TEVREG1, color); } void CCubeRenderer::SetWorldLightFadeLevel(float level) { x2fc_tevReg1Color = zeus::CColor(level, level, level, 1.f); } -void CCubeRenderer::SetWorldLightMultiplyColor(const zeus::CColor& color) { CGraphics::g_ColorRegs[2] = color; } - void CCubeRenderer::PrepareDynamicLights(const std::vector& lights) {} void CCubeRenderer::AllocatePhazonSuitMaskTexture() {} void CCubeRenderer::DrawPhazonSuitIndirectEffect(const zeus::CColor& nonIndirectMod, @@ -511,4 +508,13 @@ void CCubeRenderer::SetupCGraphicsState() { // CGX::SetChanCtrl(EChannelId::Channel1, false, GX::SRC_REG, GX::LIGHT_NULL, GX::DF_NONE, GX::AF_NONE); CCubeMaterial::EnsureTevsDirect(); } + +void CCubeRenderer::SetupRendererStates(bool depthWrite) { + CGraphics::DisableAllLights(); + CGraphics::SetModelMatrix({}); + CGraphics::SetAmbientColor(zeus::skBlack); + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, depthWrite); + CCubeMaterial::ResetCachedMaterials(); + aurora::gfx::set_tev_reg_color(GX::TEVREG1, x2fc_tevReg1Color); +} } // namespace metaforce diff --git a/Runtime/Graphics/CCubeRenderer.hpp b/Runtime/Graphics/CCubeRenderer.hpp index fd741d68f..0aeff33a6 100644 --- a/Runtime/Graphics/CCubeRenderer.hpp +++ b/Runtime/Graphics/CCubeRenderer.hpp @@ -195,10 +195,10 @@ public: u32 GetStaticWorldDataSize() override; void SetGXRegister1Color(const zeus::CColor& color) override; void SetWorldLightFadeLevel(float level) override; - void SetWorldLightMultiplyColor(const zeus::CColor& color) override; void PrepareDynamicLights(const std::vector& lights) override; // Non-virtual functions + void SetupRendererStates(bool depthWrite); void AllocatePhazonSuitMaskTexture(); void DrawPhazonSuitIndirectEffect(const zeus::CColor& nonIndirectMod, const TLockedToken& indTex, const zeus::CColor& indirectMod, float blurRadius, float scale, float offX, @@ -212,7 +212,6 @@ public: void RenderBucketItems(const CAreaListItem* lights); void DrawRenderBucketsDebug() {} - void SetupRendererStates(bool b) {} // Getters [[nodiscard]] bool IsInAreaDraw() const { return x318_30_inAreaDraw; } [[nodiscard]] bool IsReflectionDirty() const { return x318_24_refectionDirty; } diff --git a/Runtime/Graphics/CGraphics.cpp b/Runtime/Graphics/CGraphics.cpp index 860d5b137..fd8f0eadf 100644 --- a/Runtime/Graphics/CGraphics.cpp +++ b/Runtime/Graphics/CGraphics.cpp @@ -12,15 +12,12 @@ namespace metaforce { CGraphics::CProjectionState CGraphics::g_Proj; CFogState CGraphics::g_Fog; -std::array CGraphics::g_ColorRegs{}; float CGraphics::g_ProjAspect = 1.f; -u32 CGraphics::g_NumLightsActive = 0; u32 CGraphics::g_NumBreakpointsWaiting = 0; u32 CGraphics::g_FlippingState; bool CGraphics::g_LastFrameUsedAbove = false; bool CGraphics::g_InterruptLastFrameUsedAbove = false; -ERglLightBits CGraphics::g_LightActive = ERglLightBits::None; -ERglLightBits CGraphics::g_LightsWereOn = ERglLightBits::None; +std::bitset CGraphics::g_LightActive{}; zeus::CTransform CGraphics::g_GXModelView; zeus::CTransform CGraphics::g_GXModelViewInvXpose; zeus::CTransform CGraphics::g_GXModelMatrix = zeus::CTransform(); @@ -60,33 +57,52 @@ const std::array CGraphics::skCubeBasisMats{{ }}; void CGraphics::DisableAllLights() { - g_NumLightsActive = 0; - g_LightActive = ERglLightBits::None; - // TODO: turn lights off for real + g_LightActive.reset(); + aurora::gfx::set_light_state(g_LightActive); } void CGraphics::LoadLight(ERglLight light, const CLight& info) { - // TODO: load light for real + const auto lightId = static_cast(1 << light); + switch (info.GetType()) { + case ELightType::LocalAmbient: + aurora::gfx::load_light_ambient(lightId, info.GetColor()); + break; + case ELightType::Point: + case ELightType::Spot: + case ELightType::Custom: + case ELightType::Directional: { + aurora::gfx::Light lightOut{ + .pos = CGraphics::g_CameraMatrix * info.GetPosition(), + .dir = (CGraphics::g_CameraMatrix.basis * info.GetDirection()).normalized(), + .color = info.GetColor(), + .linAtt = {info.GetAttenuationConstant(), info.GetAttenuationLinear(), info.GetAttenuationQuadratic()}, + .angAtt = {info.GetAngleAttenuationConstant(), info.GetAngleAttenuationLinear(), + info.GetAngleAttenuationQuadratic()}, + }; + if (info.GetType() == ELightType::Directional) { + lightOut.pos = (-lightOut.dir) * 1048576.f; + } + aurora::gfx::load_light(lightId, lightOut); + break; + } + } } void CGraphics::EnableLight(ERglLight light) { - ERglLightBits lightBit = ERglLightBits(1 << int(light)); - if ((lightBit & g_LightActive) == ERglLightBits::None) { - g_LightActive |= lightBit; - ++g_NumLightsActive; - // TODO: turn light on for real + if (!g_LightActive.test(light)) { + g_LightActive.set(light); + aurora::gfx::set_light_state(g_LightActive); } - g_LightsWereOn = g_LightActive; } -void CGraphics::SetLightState(ERglLightBits lightState) { - // TODO: set state for real +void CGraphics::SetLightState(std::bitset lightState) { g_LightActive = lightState; - g_NumLightsActive = zeus::PopCount(lightState); + aurora::gfx::set_light_state(g_LightActive); } void CGraphics::SetAmbientColor(const zeus::CColor& col) { - // TODO: set for real + aurora::gfx::set_chan_amb_color(GX::COLOR0A0, col); + aurora::gfx::set_chan_amb_color(GX::COLOR1A1, col); } void CGraphics::SetFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) { @@ -150,13 +166,53 @@ void CGraphics::EndScene() { UpdateFPSCounter(); } -void CGraphics::Render2D(const CTexture& tex, u32 x, u32 y, u32 w, u32 h, const zeus::CColor& col) { +void CGraphics::Render2D(CTexture& tex, u32 x, u32 y, u32 w, u32 h, const zeus::CColor& col) { const auto oldProj = g_Proj; - CGraphics::SetOrtho(-g_Viewport.x8_width / 2, g_Viewport.x8_width / 2, g_Viewport.xc_height / 2, - -g_Viewport.xc_height / 2, -1.f, -10.f); - // TODO + const auto oldCull = g_cullMode; + const auto oldLights = g_LightActive; + SetOrtho(-g_Viewport.x10_halfWidth, g_Viewport.x10_halfWidth, g_Viewport.x14_halfHeight, -g_Viewport.x14_halfHeight, + -1.f, -10.f); + // disable Y/Z swap TODO do we need to do this elsewhere? + aurora::gfx::update_model_view(zeus::CMatrix4f{}, zeus::CMatrix4f{}); + DisableAllLights(); + SetCullMode(ERglCullMode::None); + tex.Load(GX::TEXMAP0, EClampMode::Repeat); + +// float hPad, vPad; +// if (CGraphics::GetViewportAspect() >= 1.78f) { +// hPad = 1.78f / CGraphics::GetViewportAspect(); +// vPad = 1.78f / 1.33f; +// } else { +// hPad = 1.f; +// vPad = CGraphics::GetViewportAspect() / 1.33f; +// } + // TODO make this right + float scaledX = static_cast(x) / 640.f * static_cast(g_Viewport.x8_width); + float scaledY = static_cast(y) / 448.f * static_cast(g_Viewport.xc_height); + float scaledW = static_cast(w) / 640.f * static_cast(g_Viewport.x8_width); + float scaledH = static_cast(h) / 448.f * static_cast(g_Viewport.xc_height); + + float x1 = scaledX - g_Viewport.x10_halfWidth; + float y1 = scaledY - g_Viewport.x14_halfHeight; + float x2 = x1 + scaledW; + float y2 = y1 + scaledH; + StreamBegin(GX::TRIANGLESTRIP); + StreamColor(col); + StreamTexcoord(0.f, 0.f); + StreamVertex(x1, y1, 1.f); + StreamTexcoord(1.f, 0.f); + StreamVertex(x2, y1, 1.f); + StreamTexcoord(0.f, 1.f); + StreamVertex(x1, y2, 1.f); + StreamTexcoord(1.f, 1.f); + StreamVertex(x2, y2, 1.f); + StreamEnd(); + + SetLightState(g_LightActive); g_Proj = oldProj; FlushProjection(); + SetModelMatrix({}); + SetCullMode(oldCull); } bool CGraphics::BeginRender2D(const CTexture& tex) { return false; } @@ -249,13 +305,12 @@ zeus::CMatrix4f CGraphics::GetPerspectiveProjectionMatrix() { float rpl = g_Proj.x8_right + g_Proj.x4_left; float tmb = g_Proj.xc_top - g_Proj.x10_bottom; float tpb = g_Proj.xc_top + g_Proj.x10_bottom; - float fpn = g_Proj.x18_far + g_Proj.x14_near; float fmn = g_Proj.x18_far - g_Proj.x14_near; // clang-format off return { 2.f / rml, 0.f, 0.f, -rpl / rml, 0.f, 2.f / tmb, 0.f, -tpb / tmb, - 0.f, 0.f, -2.f / fmn, -fpn / fmn, + 0.f, 0.f, -1.f / fmn, -g_Proj.x14_near / fmn, 0.f, 0.f, 0.f, 1.f }; // clang-format on diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index bb37c355c..16662d666 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -25,20 +25,7 @@ extern CVar* g_disableLighting; class CLight; class CTimeProvider; -enum class ERglLight : u8 { Zero = 0, One, Two, Three, Four, Five, Six, Seven }; - -enum class ERglLightBits : u8 { - None = 0, - Zero = 1, - One = 1 << 1, - Two = 1 << 2, - Three = 1 << 3, - Four = 1 << 4, - Five = 1 << 5, - Six = 1 << 6, - Seven = 1 << 7 -}; -ENABLE_BITWISE_ENUM(ERglLightBits) +using ERglLight = u8; struct SViewport { u32 x0_left; @@ -119,15 +106,12 @@ public: static zeus::CVector2f g_CachedDepthRange; static CFogState g_Fog; static SViewport g_Viewport; - static std::array g_ColorRegs; static float g_ProjAspect; - static u32 g_NumLightsActive; static u32 g_NumBreakpointsWaiting; static u32 g_FlippingState; static bool g_LastFrameUsedAbove; static bool g_InterruptLastFrameUsedAbove; - static ERglLightBits g_LightActive; - static ERglLightBits g_LightsWereOn; + static std::bitset g_LightActive; static zeus::CTransform g_GXModelView; static zeus::CTransform g_GXModelViewInvXpose; static zeus::CTransform g_GXModelMatrix; @@ -147,7 +131,7 @@ public: static void DisableAllLights(); static void LoadLight(ERglLight light, const CLight& info); static void EnableLight(ERglLight light); - static void SetLightState(ERglLightBits lightState); + static void SetLightState(std::bitset 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); @@ -155,7 +139,7 @@ public: static void SetCullMode(ERglCullMode); static void BeginScene(); static void EndScene(); - static void Render2D(const CTexture& tex, u32 x, u32 y, u32 w, u32 h, const zeus::CColor& col); + static void Render2D(CTexture& tex, u32 x, u32 y, u32 w, u32 h, const zeus::CColor& col); static bool BeginRender2D(const CTexture& tex); static void DoRender2D(const CTexture& tex, s32 x, s32 y, s32 w1, s32 w2, s32 w3, s32 w4, s32 w5, const zeus::CColor& col); diff --git a/Runtime/Graphics/CModel.cpp b/Runtime/Graphics/CModel.cpp index b53aa5e36..10e675b1c 100644 --- a/Runtime/Graphics/CModel.cpp +++ b/Runtime/Graphics/CModel.cpp @@ -227,7 +227,7 @@ bool CModel::IsLoaded(u32 matIdx) { VerifyCurrentShader(matIdx); const auto& textures = *x28_modelInst->x1c_textures; if (textures.empty()) { - return false; + return true; } for (const auto& token : textures) { if (token.IsNull() && !token.IsLoaded()) { diff --git a/Runtime/Graphics/CMoviePlayer.cpp b/Runtime/Graphics/CMoviePlayer.cpp index 18df6210b..b2b1798ea 100644 --- a/Runtime/Graphics/CMoviePlayer.cpp +++ b/Runtime/Graphics/CMoviePlayer.cpp @@ -366,36 +366,24 @@ void CMoviePlayer::Rewind() { } void CMoviePlayer::Draw() { - if (GetIsFullyCached()) { - g_Renderer->SetDepthReadWrite(false, false); - g_Renderer->SetViewportOrtho(false, -4096.f, 4096.f); - const auto vpHeight = CGraphics::GetViewportHeight(); - const auto vpWidth = CGraphics::GetViewportWidth(); - const auto vpTop = CGraphics::GetViewportTop(); - const auto vpLeft = CGraphics::GetViewportLeft(); - const auto [width, height] = GetVideoDimensions(); - const auto centerX = (width - vpWidth) / 2; - const auto centerY = (height - vpHeight) / 2; - DrawFrame(vpLeft - centerX, vpLeft + vpWidth + centerX, vpTop - centerY, vpTop + vpHeight + centerY); - } -} - -void CMoviePlayer::DrawFrame(u32 left, u32 right, u32 top, u32 bottom) { - DrawFrame({static_cast(left), 0.f, static_cast(bottom)}, - {static_cast(right), 0.f, static_cast(bottom)}, - {static_cast(left), 0.f, static_cast(top)}, - {static_cast(right), 0.f, static_cast(top)}); -} - -void CMoviePlayer::DrawFrame(const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3, - const zeus::CVector3f& v4) { - if (xd0_drawTexSlot == UINT32_MAX) + if (xd0_drawTexSlot == UINT32_MAX || !GetIsFullyCached()) { return; + } SCOPED_GRAPHICS_DEBUG_GROUP("CMoviePlayer::DrawFrame", zeus::skYellow); + /* Correct movie aspect ratio */ + float hPad, vPad; + if (CGraphics::GetViewportAspect() >= 1.78f) { + hPad = 1.78f / CGraphics::GetViewportAspect(); + vPad = 1.78f / 1.33f; + } else { + hPad = 1.f; + vPad = CGraphics::GetViewportAspect() / 1.33f; + } + /* draw appropriate field */ CTHPTextureSet& tex = x80_textures[xd0_drawTexSlot]; - aurora::gfx::queue_movie_player(tex.Y[m_deinterlace ? (xfc_fieldIndex != 0) : 0], tex.U, tex.V, v1, v2, v3, v4); + aurora::gfx::queue_movie_player(tex.Y[m_deinterlace ? (xfc_fieldIndex != 0) : 0], tex.U, tex.V, hPad, vPad); /* ensure second field is being displayed by VI to signal advance * (faked in metaforce with continuous xor) */ diff --git a/Runtime/Graphics/CMoviePlayer.hpp b/Runtime/Graphics/CMoviePlayer.hpp index 7020ca011..7a371f906 100644 --- a/Runtime/Graphics/CMoviePlayer.hpp +++ b/Runtime/Graphics/CMoviePlayer.hpp @@ -110,9 +110,6 @@ private: float m_vpad; void DecodeFromRead(const void* data); - void DrawFrame(u32 left, u32 right, u32 top, u32 bottom); - void DrawFrame(const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3, - const zeus::CVector3f& v4); void PostDVDReadRequestIfNeeded(); void ReadCompleted(); diff --git a/Runtime/Graphics/GX.hpp b/Runtime/Graphics/GX.hpp index 33f71f242..85ccdd284 100644 --- a/Runtime/Graphics/GX.hpp +++ b/Runtime/Graphics/GX.hpp @@ -457,6 +457,8 @@ enum TexMapID { TEXMAP6, TEXMAP7, MAX_TEXMAP, + TEXMAP_NULL = 0xFF, + TEX_DISABLE = 0x100, }; enum TevStageID { diff --git a/Runtime/Graphics/IRenderer.hpp b/Runtime/Graphics/IRenderer.hpp index 761a9b520..512e0c6e0 100644 --- a/Runtime/Graphics/IRenderer.hpp +++ b/Runtime/Graphics/IRenderer.hpp @@ -108,7 +108,7 @@ public: virtual u32 GetStaticWorldDataSize() = 0; virtual void SetGXRegister1Color(const zeus::CColor& color) = 0; virtual void SetWorldLightFadeLevel(float level) = 0; - virtual void SetWorldLightMultiplyColor(const zeus::CColor& color) = 0; + // Something virtual void PrepareDynamicLights(const std::vector& lights) = 0; }; diff --git a/Runtime/GuiSys/CGuiFrame.cpp b/Runtime/GuiSys/CGuiFrame.cpp index 98e3a2231..2898ae5a6 100644 --- a/Runtime/GuiSys/CGuiFrame.cpp +++ b/Runtime/GuiSys/CGuiFrame.cpp @@ -44,21 +44,19 @@ void CGuiFrame::SortDrawOrder() { }); } -void CGuiFrame::EnableLights(u32 lights) const { +void CGuiFrame::EnableLights(ERglLight lights) const { CGraphics::DisableAllLights(); zeus::CColor ambColor(zeus::skBlack); - ERglLight lightId = ERglLight::Zero; - int idx = 0; + ERglLight lightId = 0; int enabledLights = 0; for (CGuiLight* light : m_indexedLights) { if (light == nullptr || !light->GetIsVisible()) { - ++reinterpret_cast&>(lightId); - ++idx; + ++lightId; continue; } - if ((lights & (1 << idx)) != 0) { - const zeus::CColor& geomCol = light->GetGeometryColor(); + if ((lights & (1 << lightId)) != 0) { + const auto& geomCol = light->GetGeometryColor(); if (geomCol.r() != 0.f || geomCol.g() != 0.f || geomCol.b() != 0.f) { CGraphics::LoadLight(lightId, light->BuildLight()); CGraphics::EnableLight(lightId); @@ -67,8 +65,7 @@ void CGuiFrame::EnableLights(u32 lights) const { ambColor += light->GetAmbientLightColor(); ++enabledLights; } - ++reinterpret_cast&>(lightId); - ++idx; + ++lightId; } if (enabledLights == 0) { CGraphics::SetAmbientColor(zeus::skWhite); diff --git a/Runtime/GuiSys/CGuiFrame.hpp b/Runtime/GuiSys/CGuiFrame.hpp index 036b79ed7..2482a440c 100644 --- a/Runtime/GuiSys/CGuiFrame.hpp +++ b/Runtime/GuiSys/CGuiFrame.hpp @@ -9,6 +9,7 @@ #include "Runtime/GuiSys/CGuiHeadWidget.hpp" #include "Runtime/GuiSys/CGuiWidgetIdDB.hpp" #include "Runtime/GuiSys/CGuiWidget.hpp" +#include "Runtime/Graphics/CGraphics.hpp" namespace metaforce { class CGuiCamera; @@ -69,7 +70,7 @@ public: void SetHeadWidget(std::shared_ptr&& hwig) { xc_headWidget = std::move(hwig); } CGuiHeadWidget* GetHeadWidget() const { return xc_headWidget.get(); } void SortDrawOrder(); - void EnableLights(u32 lights) const; + void EnableLights(ERglLight lights) const; void DisableLights() const; void RemoveLight(CGuiLight* light); void AddLight(CGuiLight* light); diff --git a/Runtime/MP1/CFrontEndUI.cpp b/Runtime/MP1/CFrontEndUI.cpp index 740e949f3..f6b3ecd2d 100644 --- a/Runtime/MP1/CFrontEndUI.cpp +++ b/Runtime/MP1/CFrontEndUI.cpp @@ -113,8 +113,7 @@ void CFrontEndUI::PlayAdvanceSfx() { CSfxManager::SfxStart(SFXfnt_advance_R, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId); } -CFrontEndUI::SNewFileSelectFrame::SNewFileSelectFrame(CSaveGameScreen* sui, u32 rnd) -: x0_rnd(rnd), x4_saveUI(sui) { +CFrontEndUI::SNewFileSelectFrame::SNewFileSelectFrame(CSaveGameScreen* sui, u32 rnd) : x0_rnd(rnd), x4_saveUI(sui) { x10_frme = g_SimplePool->GetObj("FRME_NewFileSelect"); } @@ -218,8 +217,7 @@ void CFrontEndUI::SNewFileSelectFrame::Update(float dt) { x1c_loadedFrame->Update(dt); } -CFrontEndUI::SNewFileSelectFrame::EAction -CFrontEndUI::SNewFileSelectFrame::ProcessUserInput(const CFinalInput& input) { +CFrontEndUI::SNewFileSelectFrame::EAction CFrontEndUI::SNewFileSelectFrame::ProcessUserInput(const CFinalInput& input) { xc_action = EAction::None; if (x8_subMenu != ESubMenu::EraseGamePopup) @@ -962,8 +960,8 @@ void CFrontEndUI::SFusionBonusFrame::Update(float dt, CSaveGameScreen* saveUI) { x30_textpane_instructions.SetPairText(instructionStr); } -CFrontEndUI::SFusionBonusFrame::EAction -CFrontEndUI::SFusionBonusFrame::ProcessUserInput(const CFinalInput& input, CSaveGameScreen* sui) { +CFrontEndUI::SFusionBonusFrame::EAction CFrontEndUI::SFusionBonusFrame::ProcessUserInput(const CFinalInput& input, + CSaveGameScreen* sui) { x8_action = EAction::None; if (sui) @@ -1149,8 +1147,7 @@ void CFrontEndUI::SFrontEndFrame::Update(float dt) { x14_loadedFrme->Update(dt); } -CFrontEndUI::SFrontEndFrame::EAction -CFrontEndUI::SFrontEndFrame::ProcessUserInput(const CFinalInput& input) { +CFrontEndUI::SFrontEndFrame::EAction CFrontEndUI::SFrontEndFrame::ProcessUserInput(const CFinalInput& input) { x4_action = EAction::None; x14_loadedFrme->ProcessUserInput(input); return x4_action; @@ -1193,8 +1190,7 @@ void CFrontEndUI::SFrontEndFrame::DoAdvance(CGuiTableGroup* caller) { } } -CFrontEndUI::SFrontEndFrame::SFrontEndFrame(u32 rnd) -: x0_rnd(rnd) { +CFrontEndUI::SFrontEndFrame::SFrontEndFrame(u32 rnd) : x0_rnd(rnd) { x8_frme = g_SimplePool->GetObj("FRME_FrontEndPL"); } @@ -1827,15 +1823,14 @@ void CFrontEndUI::Draw() { if (x64_pressStartAlpha > 0.f && x38_pressStart.IsLoaded()) { /* Render "Press Start" */ - // TODO fixme -// const zeus::CRectangle rect(0.5f - x38_pressStart->GetWidth() / 2.f / 640.f * hPad, -// 0.5f + (x38_pressStart->GetHeight() / 2.f - 240.f + 72.f) / 480.f * vPad, -// x38_pressStart->GetWidth() / 640.f * hPad, -// x38_pressStart->GetHeight() / 480.f * vPad); -// zeus::CColor color = zeus::skWhite; -// color.a() = x64_pressStartAlpha; -// aurora::gfx::queue_textured_quad(aurora::gfx::CameraFilterType::Add, x38_pressStart->GetTexture(), -// aurora::gfx::ZComp::Always, false, color, 1.f, rect, 0.f); + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); + g_Renderer->SetBlendMode_AdditiveAlpha(); + g_Renderer->SetDepthReadWrite(false, false); + const auto width = x38_pressStart->GetWidth(); + const auto height = x38_pressStart->GetHeight(); + CGraphics::Render2D(*x38_pressStart, 320 - width / 2, 72 - height / 2, width, height, + zeus::CColor{1.f, x64_pressStartAlpha}); } if (xc0_attractCount > 0) { diff --git a/Runtime/Particle/CElementGen.hpp b/Runtime/Particle/CElementGen.hpp index 12c008f52..3a15d9a3c 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; - ERglLightBits x274_backupLightActive = ERglLightBits::None; + std::bitset x274_backupLightActive{}; std::array x278_hasVMD{}; CRandom16 x27c_randState; std::array x280_VELSources{}; diff --git a/aurora/CMakeLists.txt b/aurora/CMakeLists.txt index 28cf6e80f..c155e08ca 100644 --- a/aurora/CMakeLists.txt +++ b/aurora/CMakeLists.txt @@ -25,6 +25,7 @@ add_library(aurora STATIC lib/gfx/common.cpp lib/gfx/texture.cpp lib/gfx/stream.cpp + lib/gfx/gx.cpp lib/gfx/texture_convert.cpp lib/gfx/movie_player/shader.cpp lib/gfx/textured_quad/shader.cpp diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index fc2b887b2..7e4f5aa44 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -151,6 +151,16 @@ struct CTevOp { 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)) {} + bool operator<=>(const CTevOp&) const = default; }; struct ColorPass { @@ -159,6 +169,14 @@ struct ColorPass { 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)) {} + bool operator<=>(const ColorPass&) const = default; }; struct AlphaPass { @@ -167,6 +185,14 @@ struct AlphaPass { 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)) {} + bool operator<=>(const AlphaPass&) const = default; }; } // namespace CTevCombiners @@ -220,8 +246,23 @@ enum class ZComp : uint8_t { Always, }; +constexpr u32 MaxLights = 8; +struct Light { + zeus::CVector3f pos; + zeus::CVector3f dir; + zeus::CColor color; + zeus::CVector3f linAtt{1.f, 0.f, 0.f}; + zeus::CVector3f angAtt{1.f, 0.f, 0.f}; +}; + [[nodiscard]] bool get_dxt_compression_supported() noexcept; +void stream_begin(GX::Primitive primitive) noexcept; +void stream_vertex(metaforce::EStreamFlags flags, const zeus::CVector3f& pos, const zeus::CVector3f& nrm, + const zeus::CColor& color, const zeus::CVector2f& uv) noexcept; +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; @@ -229,20 +270,20 @@ void update_tev_stage(metaforce::ERglTevStage stage, const metaforce::CTevCombin const metaforce::CTevCombiners::AlphaPass& alphaPass, const metaforce::CTevCombiners::CTevOp& colorOp, const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept; -void stream_begin(GX::Primitive primitive) noexcept; -void stream_vertex(metaforce::EStreamFlags flags, const zeus::CVector3f& pos, const zeus::CVector3f& nrm, - const zeus::CColor& color, const zeus::CVector2f& uv) noexcept; -void stream_end() noexcept; - -// GX state 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_gx_reg1_color(const zeus::CColor& color) 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; // Model state void set_alpha_discard(bool v); @@ -250,6 +291,9 @@ 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_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; @@ -272,9 +316,8 @@ void queue_colored_quad_verts(CameraFilterType filter_type, ZComp z_comparison, const ArrayRef& pos) noexcept; void queue_colored_quad(CameraFilterType filter_type, ZComp z_comparison, bool z_test, const zeus::CColor& color, const zeus::CRectangle& rect, float z) noexcept; -void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, - const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3, - const zeus::CVector3f& v4) noexcept; +void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad, + float v_pad) noexcept; TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mips, metaforce::ETexelFormat format, ArrayRef data, zstring_view label) noexcept; diff --git a/aurora/include/aurora/model.hpp b/aurora/include/aurora/model.hpp new file mode 100644 index 000000000..0e4e06364 --- /dev/null +++ b/aurora/include/aurora/model.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace aurora::gfx::model { + +} diff --git a/aurora/lib/aurora.cpp b/aurora/lib/aurora.cpp index 3cb7d45b0..b4e096f47 100644 --- a/aurora/lib/aurora.cpp +++ b/aurora/lib/aurora.cpp @@ -1,5 +1,6 @@ #include #include "gfx/common.hpp" +#include "gfx/gx.hpp" #include "gpu.hpp" #include "input.hpp" #include "imgui.hpp" @@ -298,7 +299,13 @@ void app_run(std::unique_ptr app, Icon icon, int argc, char** argv) // .resolveTarget = g_frameBufferResolved.view, .loadOp = wgpu::LoadOp::Clear, .storeOp = wgpu::StoreOp::Store, - .clearColor = {0.f, 0.f, 0.f, 0.f}, + .clearColor = + { + .r = gfx::g_clearColor.r(), + .g = gfx::g_clearColor.g(), + .b = gfx::g_clearColor.b(), + .a = gfx::g_clearColor.a(), + }, }, }; const auto depthStencilAttachment = wgpu::RenderPassDepthStencilAttachment{ diff --git a/aurora/lib/gfx/colored_quad/shader.cpp b/aurora/lib/gfx/colored_quad/shader.cpp index 571a36140..58b8358b0 100644 --- a/aurora/lib/gfx/colored_quad/shader.cpp +++ b/aurora/lib/gfx/colored_quad/shader.cpp @@ -1,6 +1,7 @@ #include "shader.hpp" #include "../../gpu.hpp" +#include "../gx.hpp" #include #include diff --git a/aurora/lib/gfx/common.cpp b/aurora/lib/gfx/common.cpp index a1483c890..cea547e58 100644 --- a/aurora/lib/gfx/common.cpp +++ b/aurora/lib/gfx/common.cpp @@ -65,24 +65,6 @@ struct Command { } data; }; -zeus::CMatrix4f g_mv; -zeus::CMatrix4f g_mvInv; -zeus::CMatrix4f g_proj; -metaforce::CFogState g_fogState; -// GX state -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; -bool g_alphaUpdate; -std::optional g_dstAlpha; -zeus::CColor g_clearColor; - using NewPipelineCallback = std::function; static std::mutex g_pipelineMutex; static std::thread g_pipelineThread; @@ -135,48 +117,6 @@ static void push_draw_command(ShaderDrawCommand data) { g_commands.push_back({Co bool get_dxt_compression_supported() noexcept { return g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC); } -// GX state -void set_cull_mode(metaforce::ERglCullMode mode) noexcept { g_cullMode = mode; } -void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst, - metaforce::ERglLogicOp op) noexcept { - g_blendMode = mode; - g_blendFacSrc = src; - g_blendFacDst = dst; - g_blendOp = op; -} -void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept { - g_depthCompare = compare_enable; - g_depthFunc = func; - g_depthUpdate = update_enable; -} -void set_gx_reg1_color(const zeus::CColor& color) noexcept { g_colorRegs[1] = color; } -void set_alpha_update(bool enabled) noexcept { g_alphaUpdate = enabled; } -void set_dst_alpha(bool enabled, float value) noexcept { - if (enabled) { - g_dstAlpha = value; - } else { - g_dstAlpha.reset(); - } -} -void set_clear_color(const zeus::CColor& color) noexcept { g_clearColor = color; } - -// Model state -void set_alpha_discard(bool v) {} - -void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept { - g_mv = mv; - g_mvInv = mv_inv; -} -constexpr zeus::CMatrix4f DepthCorrect{ - // clang-format off - 1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f, - // clang-format on -}; -void update_projection(const zeus::CMatrix4f& proj) noexcept { g_proj = DepthCorrect * proj; } -void update_fog_state(const metaforce::CFogState& state) noexcept { g_fogState = state; } void set_viewport(const zeus::CRectangle& rect, float znear, float zfar) noexcept { g_commands.push_back({CommandType::SetViewport, {.setViewport = {rect, znear, zfar}}}); } @@ -243,9 +183,8 @@ PipelineRef pipeline_ref(colored_quad::PipelineConfig config) { } void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, - const zeus::CVector3f& v1, const zeus::CVector3f& v2, const zeus::CVector3f& v3, - const zeus::CVector3f& v4) noexcept { - auto data = movie_player::make_draw_data(g_state.moviePlayer, tex_y, tex_u, tex_v, v1, v2, v3, v4); + float h_pad, float v_pad) noexcept { + auto data = movie_player::make_draw_data(g_state.moviePlayer, tex_y, tex_u, tex_v, h_pad, v_pad); push_draw_command({.type = ShaderType::MoviePlayer, .moviePlayer = data}); } template <> diff --git a/aurora/lib/gfx/common.hpp b/aurora/lib/gfx/common.hpp index 280a9e824..0a2317298 100644 --- a/aurora/lib/gfx/common.hpp +++ b/aurora/lib/gfx/common.hpp @@ -142,24 +142,6 @@ constexpr Mat4x4 Mat4x4_Identity{ } // namespace aurora namespace aurora::gfx { -extern zeus::CMatrix4f g_mv; -extern zeus::CMatrix4f g_mvInv; -extern zeus::CMatrix4f g_proj; -extern metaforce::CFogState g_fogState; -// GX state -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 bool g_alphaUpdate; -extern std::optional g_dstAlpha; -extern zeus::CColor g_clearColor; - extern wgpu::Buffer g_vertexBuffer; extern wgpu::Buffer g_uniformBuffer; extern wgpu::Buffer g_indexBuffer; @@ -232,6 +214,4 @@ const wgpu::BindGroup& find_bind_group(BindGroupRef id); const wgpu::Sampler& sampler_ref(const wgpu::SamplerDescriptor& descriptor); uint32_t align_uniform(uint32_t value); - -static inline Mat4x4 get_combined_matrix() { return g_proj * g_mv; } } // namespace aurora::gfx diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp new file mode 100644 index 000000000..81f207f5d --- /dev/null +++ b/aurora/lib/gfx/gx.cpp @@ -0,0 +1,150 @@ +#include "gx.hpp" + +#include "common.hpp" +#include "../gpu.hpp" + +#include + +namespace aurora::gfx { +static logvisor::Module Log("aurora::gfx::gx"); + +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; + +std::array g_colorChannels; +std::array g_lights; +std::bitset g_lightState; + +std::array, maxTevStages> g_tevStages; + +// GX state +void set_cull_mode(metaforce::ERglCullMode mode) noexcept { g_cullMode = mode; } +void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst, + metaforce::ERglLogicOp op) noexcept { + g_blendMode = mode; + g_blendFacSrc = src; + g_blendFacDst = dst; + g_blendOp = op; +} +void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept { + g_depthCompare = compare_enable; + g_depthFunc = func; + 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(); + } + 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(); + } + g_kcolors[id] = color; +} +void set_alpha_update(bool enabled) noexcept { g_alphaUpdate = enabled; } +void set_dst_alpha(bool enabled, float value) noexcept { + if (enabled) { + g_dstAlpha = value; + } else { + g_dstAlpha.reset(); + } +} +void set_clear_color(const zeus::CColor& color) noexcept { g_clearColor = color; } +void set_alpha_discard(bool v) { + // TODO +} + +void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept { + g_mv = mv; + g_mvInv = mv_inv; +} +constexpr zeus::CMatrix4f DepthCorrect{ + // clang-format off + 1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 0.5f, 0.5f, + 0.f, 0.f, 0.f, 1.f, + // clang-format on +}; +void update_projection(const zeus::CMatrix4f& proj) noexcept { g_proj = DepthCorrect * proj; } +void update_fog_state(const metaforce::CFogState& state) noexcept { g_fogState = state; } + +void disable_tev_stage(metaforce::ERglTevStage stage) noexcept { 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 { + g_tevStages[static_cast(stage)] = {colPass, alphaPass, colorOp, alphaOp}; +} + +void set_tev_order(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept { + auto& stage = g_tevStages[id]; + if (!stage) { + Log.report(logvisor::Fatal, FMT_STRING("set_tev_order: disabled stage {}"), id); + unreachable(); + } + stage->texCoordId = tcid; + stage->texMapId = tmid; + stage->channelId = cid; +} +void set_tev_k_color_sel(GX::TevStageID id, GX::TevKColorSel sel) noexcept { + auto& stage = 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 = 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(); + } + 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(); + } + g_colorChannels[id - GX::COLOR0A0].matColor = color; +} + +void load_light(GX::LightID id, const Light& light) noexcept { + g_lights[id] = light; +} +void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept { + g_lights[id] = ambient; +} +void set_light_state(std::bitset bits) noexcept { + g_lightState = bits; +} +} // namespace aurora::gfx diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp new file mode 100644 index 000000000..f0d58057c --- /dev/null +++ b/aurora/lib/gfx/gx.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "common.hpp" + +#include + +namespace aurora::gfx { +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; + +struct SChannelState { + zeus::CColor matColor; + zeus::CColor ambColor; +}; +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; + 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; + + STevStage(const metaforce::CTevCombiners::ColorPass& colPass, const metaforce::CTevCombiners::AlphaPass& alphaPass, + const metaforce::CTevCombiners::CTevOp& colorOp, const metaforce::CTevCombiners::CTevOp& alphaOp) + : colorPass(colPass), alphaPass(alphaPass), colorOp(colorOp), alphaOp(alphaOp) {} +}; + +constexpr u32 maxTevStages = GX::MAX_TEVSTAGE; +extern std::array, maxTevStages> g_tevStages; + +static inline XXH64_hash_t hash_tev_stages(XXH64_hash_t seed = 0) { + const auto end = std::find_if(g_tevStages.cbegin(), g_tevStages.cend(), [](const auto& a) { return !a; }); + return xxh3_hash(g_tevStages.data(), (end - g_tevStages.begin()) * sizeof(STevStage), seed); +} + +static inline Mat4x4 get_combined_matrix() { return g_proj * g_mv; } +} // namespace aurora::gfx diff --git a/aurora/lib/gfx/movie_player/shader.cpp b/aurora/lib/gfx/movie_player/shader.cpp index ec241ac4c..4ed948f71 100644 --- a/aurora/lib/gfx/movie_player/shader.cpp +++ b/aurora/lib/gfx/movie_player/shader.cpp @@ -12,13 +12,7 @@ using gpu::utils::make_vertex_state; State construct_state() { wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{}; wgslDescriptor.source = R"""( -struct Uniform { - xf: mat4x4; - color: vec4; -}; @group(0) @binding(0) -var ubuf: Uniform; -@group(0) @binding(1) var tex_sampler: sampler; @group(1) @binding(0) var tex_y: texture_2d; @@ -35,7 +29,7 @@ struct VertexOutput { @stage(vertex) fn vs_main(@location(0) in_pos: vec3, @location(1) in_uv: vec2) -> VertexOutput { var out: VertexOutput; - out.pos = ubuf.xf * vec4(in_pos, 1.0); + out.pos = vec4(in_pos, 1.0); out.uv = in_uv; return out; } @@ -47,7 +41,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { textureSample(tex_u, tex_sampler, in.uv).x - 0.5, textureSample(tex_v, tex_sampler, in.uv).x - 0.5 ); - return ubuf.color * vec4( + return vec4( yuv.x + 1.5958 * yuv.z, yuv.x - 0.39173 * yuv.y - 0.8129 * yuv.z, yuv.x + 2.017 * yuv.y, @@ -61,24 +55,9 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { }; auto shader = g_device.CreateShaderModule(&shaderDescriptor); - wgpu::SupportedLimits limits; - g_device.GetLimits(&limits); - const auto uniform_alignment = limits.limits.minUniformBufferOffsetAlignment; - const auto uniform_size = ALIGN(sizeof(Uniform), uniform_alignment); - const std::array uniformLayoutEntries{ wgpu::BindGroupLayoutEntry{ .binding = 0, - .visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Uniform, - .hasDynamicOffset = true, - .minBindingSize = uniform_size, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 1, .visibility = wgpu::ShaderStage::Fragment, .sampler = wgpu::SamplerBindingLayout{ @@ -107,11 +86,6 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { const std::array uniformBindGroupEntries{ wgpu::BindGroupEntry{ .binding = 0, - .buffer = g_uniformBuffer, - .size = uniform_size, - }, - wgpu::BindGroupEntry{ - .binding = 1, .sampler = sampler, }, }; @@ -219,24 +193,17 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli } DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const TextureHandle& tex_u, - const TextureHandle& tex_v, const zeus::CVector3f& v1, const zeus::CVector3f& v2, - const zeus::CVector3f& v3, const zeus::CVector3f& v4) { + const TextureHandle& tex_v, float h_pad, float v_pad) { auto pipeline = pipeline_ref(PipelineConfig{}); const std::array verts{ - Vert{{v1.x(), v1.z(), v1.y()}, {0.0, 0.0}}, - Vert{{v2.x(), v2.z(), v2.y()}, {0.0, 1.0}}, - Vert{{v3.x(), v3.z(), v3.y()}, {1.0, 0.0}}, - Vert{{v4.x(), v4.z(), v4.y()}, {1.0, 1.0}}, + Vert{{-h_pad, v_pad, 0.f}, {0.0, 0.0}}, + Vert{{-h_pad, -v_pad, 0.f}, {0.0, 1.0}}, + Vert{{h_pad, v_pad, 0.f}, {1.0, 0.0}}, + Vert{{h_pad, -v_pad, 0.f}, {1.0, 1.0}}, }; const auto vertRange = push_verts(ArrayRef{verts}); - const auto uniform = Uniform{ - .xf = Mat4x4_Identity, - .color = zeus::skWhite, - }; - const auto uniformRange = push_uniform(uniform); - const std::array entries{ wgpu::BindGroupEntry{ .binding = 0, @@ -261,7 +228,6 @@ DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const Te return { .pipeline = pipeline, .vertRange = vertRange, - .uniformRange = uniformRange, .textureBindGroup = textureBindGroup, }; } @@ -271,8 +237,7 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco return; } - const std::array offsets{data.uniformRange.first}; - pass.SetBindGroup(0, state.uniformBindGroup, offsets.size(), offsets.data()); + pass.SetBindGroup(0, state.uniformBindGroup); pass.SetBindGroup(1, find_bind_group(data.textureBindGroup)); pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.first, data.vertRange.second); pass.Draw(4); diff --git a/aurora/lib/gfx/movie_player/shader.hpp b/aurora/lib/gfx/movie_player/shader.hpp index 5b9ec1193..2b57b895b 100644 --- a/aurora/lib/gfx/movie_player/shader.hpp +++ b/aurora/lib/gfx/movie_player/shader.hpp @@ -30,15 +30,10 @@ struct alignas(4) Vert { Vec3 pos; Vec2 uv; }; -struct alignas(4) Uniform { - Mat4x4 xf; - Vec4 color; -}; State construct_state(); wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] PipelineConfig config); DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const TextureHandle& tex_u, - const TextureHandle& tex_v, const zeus::CVector3f& v1, const zeus::CVector3f& v2, - const zeus::CVector3f& v3, const zeus::CVector3f& v4); + const TextureHandle& tex_v, float h_pad, float v_pad); void render(const State& state, const DrawData& data, const wgpu::RenderPassEncoder& pass); } // namespace aurora::gfx::movie_player diff --git a/aurora/lib/gfx/stream.cpp b/aurora/lib/gfx/stream.cpp index 06cbfcd0a..78b8a7e68 100644 --- a/aurora/lib/gfx/stream.cpp +++ b/aurora/lib/gfx/stream.cpp @@ -2,6 +2,7 @@ #include "../gpu.hpp" #include "common.hpp" +#include "gx.hpp" #include @@ -12,28 +13,6 @@ using namespace fmt::literals; static logvisor::Module Log("aurora::gfx::stream"); -struct STevStage { - metaforce::CTevCombiners::ColorPass colorPass; - metaforce::CTevCombiners::AlphaPass alphaPass; - metaforce::CTevCombiners::CTevOp colorOp; - metaforce::CTevCombiners::CTevOp alphaOp; - - STevStage(const metaforce::CTevCombiners::ColorPass& colPass, const metaforce::CTevCombiners::AlphaPass& alphaPass, - const metaforce::CTevCombiners::CTevOp& colorOp, const metaforce::CTevCombiners::CTevOp& alphaOp) - : colorPass(colPass), alphaPass(alphaPass), colorOp(colorOp), alphaOp(alphaOp) {} -}; -constexpr u32 maxTevStages = 2; -static std::array, maxTevStages> sTevStages; - -void disable_tev_stage(metaforce::ERglTevStage stage) noexcept { sTevStages[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 { - sTevStages[static_cast(stage)] = {colPass, alphaPass, colorOp, alphaOp}; -} - struct SStreamState { GX::Primitive primitive; metaforce::EStreamFlags flags; @@ -218,7 +197,7 @@ std::unordered_map g_streamCachedShaders; static ShaderRef generate_shader() { auto flags = sStreamState->flags; - const auto hash = xxh3_hash(sTevStages, static_cast(flags)); + const auto hash = hash_tev_stages(static_cast(flags)); if (g_streamCachedShaders.contains(hash)) { return hash; } @@ -264,7 +243,7 @@ static ShaderRef generate_shader() { } std::string fragmentFn; bool hasRast = false; - for (size_t idx = 0; const auto& stage : sTevStages) { + for (size_t idx = 0; const auto& stage : g_tevStages) { if (!stage) { idx++; continue; @@ -288,7 +267,7 @@ static ShaderRef generate_shader() { } idx++; } - for (size_t idx = 0; const auto& stage : sTevStages) { + for (size_t idx = 0; const auto& stage : g_tevStages) { if (!stage) { idx++; continue; diff --git a/aurora/lib/gfx/textured_quad/shader.cpp b/aurora/lib/gfx/textured_quad/shader.cpp index 9fc29ea11..42732ad8f 100644 --- a/aurora/lib/gfx/textured_quad/shader.cpp +++ b/aurora/lib/gfx/textured_quad/shader.cpp @@ -1,5 +1,6 @@ #include "shader.hpp" +#include "../gx.hpp" #include "../../gpu.hpp" #include