From 22dfd3b3f7bdae84298d620069c91dbda3a4626e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 13 May 2022 19:40:19 -0400 Subject: [PATCH] aurora: Rework texture binding API - Texture binding is now handled by GX calls - More CCubeMaterial / CCubeRenderer impl - Semi-working thermal visor rendering - More CGraphicsPalette impl - Some CWorldShadow impl - Start work on indirect texturing - Stub out CTextRenderBuffer --- Runtime/CDvdFile.cpp | 2 + Runtime/CDvdFile.hpp | 2 + Runtime/CMemoryCardSys.cpp | 4 +- Runtime/Graphics/CCubeMaterial.cpp | 20 +- Runtime/Graphics/CCubeMaterial.hpp | 31 +- Runtime/Graphics/CCubeRenderer.cpp | 261 ++++++++++- Runtime/Graphics/CCubeRenderer.hpp | 4 +- Runtime/Graphics/CGX.hpp | 20 +- Runtime/Graphics/CGraphics.hpp | 15 +- Runtime/Graphics/CGraphicsPalette.cpp | 20 +- Runtime/Graphics/CGraphicsPalette.hpp | 16 +- Runtime/Graphics/CMoviePlayer.cpp | 42 +- Runtime/Graphics/CTexture.cpp | 137 ++---- Runtime/Graphics/CTexture.hpp | 16 +- Runtime/Graphics/GX.hpp | 181 ++++++-- .../Graphics/Shaders/CCameraBlurFilter.cpp | 2 +- .../Graphics/Shaders/CPhazonSuitFilter.cpp | 4 +- Runtime/Graphics/Shaders/CSpaceWarpFilter.cpp | 4 +- .../Graphics/Shaders/CThermalColdFilter.cpp | 2 +- .../Graphics/Shaders/CThermalHotFilter.cpp | 2 +- Runtime/Graphics/Shaders/CXRayBlurFilter.cpp | 2 +- Runtime/GuiSys/CGuiTextSupport.cpp | 117 ++--- Runtime/GuiSys/CTextRenderBuffer.cpp | 300 +++++++------ Runtime/GuiSys/CTextRenderBuffer.hpp | 86 ++-- Runtime/MP1/CInGameGuiManager.cpp | 2 +- Runtime/MP1/CPlayerVisor.cpp | 4 +- Runtime/Particle/CElementGen.cpp | 2 +- Runtime/Weapon/CPhazonBeam.cpp | 2 +- Runtime/Weapon/CPlayerGun.cpp | 2 +- Runtime/World/CFluidPlaneManager.cpp | 2 +- Runtime/World/CWorldShadow.cpp | 73 +-- Runtime/World/CWorldShadow.hpp | 8 +- Runtime/World/CWorldTransManager.cpp | 4 +- aurora/include/aurora/common.hpp | 21 + aurora/include/aurora/gfx.hpp | 31 +- aurora/lib/gfx/common.cpp | 12 +- aurora/lib/gfx/common.hpp | 9 +- aurora/lib/gfx/gx.cpp | 415 ++++++++++++------ aurora/lib/gfx/gx.hpp | 58 ++- aurora/lib/gfx/gx_shader.cpp | 358 +++++++++------ aurora/lib/gfx/model/shader.cpp | 14 +- aurora/lib/gfx/movie_player/shader.cpp | 6 +- aurora/lib/gfx/texture.cpp | 25 +- aurora/lib/gfx/texture_convert.cpp | 31 +- aurora/lib/gfx/texture_convert.hpp | 10 +- 45 files changed, 1511 insertions(+), 868 deletions(-) diff --git a/Runtime/CDvdFile.cpp b/Runtime/CDvdFile.cpp index b9fd777fa..eff4d5449 100644 --- a/Runtime/CDvdFile.cpp +++ b/Runtime/CDvdFile.cpp @@ -95,6 +95,7 @@ std::mutex CDvdFile::m_WaitMutex; std::atomic_bool CDvdFile::m_WorkerRun = {false}; std::vector> CDvdFile::m_RequestQueue; std::string CDvdFile::m_rootDirectory; +std::unique_ptr CDvdFile::m_dolBuf; CDvdFile::CDvdFile(std::string_view path) : x18_path(path) { auto* node = ResolvePath(path); @@ -211,6 +212,7 @@ bool CDvdFile::Initialize(const std::string_view& path) { if (!m_DvdRoot) { return false; } + m_dolBuf = m_DvdRoot->getDataPartition()->getDOLBuf(); m_WorkerRun.store(true); m_WorkerThread = std::thread(WorkerProc); return true; diff --git a/Runtime/CDvdFile.hpp b/Runtime/CDvdFile.hpp index 831137dd1..d220fd765 100644 --- a/Runtime/CDvdFile.hpp +++ b/Runtime/CDvdFile.hpp @@ -40,6 +40,7 @@ class CDvdFile { static std::atomic_bool m_WorkerRun; static std::vector> m_RequestQueue; static std::string m_rootDirectory; + static std::unique_ptr m_dolBuf; static void WorkerProc(); std::string x18_path; @@ -55,6 +56,7 @@ public: static SDiscInfo DiscInfo(); static void SetRootDirectory(const std::string_view& rootDir); static void Shutdown(); + static u8* GetDolBuf() { return m_dolBuf.get(); } CDvdFile(std::string_view path); operator bool() const { return m_reader.operator bool(); } diff --git a/Runtime/CMemoryCardSys.cpp b/Runtime/CMemoryCardSys.cpp index 5fb68ed55..a72ecfa62 100644 --- a/Runtime/CMemoryCardSys.cpp +++ b/Runtime/CMemoryCardSys.cpp @@ -244,7 +244,7 @@ void CMemoryCardSys::CCardFileInfo::WriteBannerData(COutputStream& out) const { out.Put(texels, 3072); } if (format == ETexelFormat::C8) { - out.Put(tex->GetPalette()->GetEntries(), 512); + out.Put(tex->GetPalette()->GetPaletteData(), 512); } } } @@ -260,7 +260,7 @@ void CMemoryCardSys::CCardFileInfo::WriteIconData(COutputStream& out) const { out.Put(texels, 1024); } if (format == ETexelFormat::C8) { - palette = icon.x8_tex->GetPalette()->GetEntries(); + palette = icon.x8_tex->GetPalette()->GetPaletteData(); } } if (palette != nullptr) { diff --git a/Runtime/Graphics/CCubeMaterial.cpp b/Runtime/Graphics/CCubeMaterial.cpp index 3fede3618..7c5d72a5a 100644 --- a/Runtime/Graphics/CCubeMaterial.cpp +++ b/Runtime/Graphics/CCubeMaterial.cpp @@ -55,7 +55,7 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur materialDataCur += 8; for (u32 i = 0; i < texCount; ++i) { u32 texIdx = SBig(*reinterpret_cast(materialDataCur)); - sRenderingModel->GetTexture(texIdx)->Load(static_cast(i), EClampMode::Repeat); + model.GetTexture(texIdx)->Load(static_cast(i), EClampMode::Repeat); materialDataCur += 4; } } @@ -225,16 +225,24 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur } void CCubeMaterial::SetCurrentBlack() { - auto flags = GetFlags(); - auto vatFlags = GetVatFlags(); - + const auto flags = GetFlags(); + const auto vatFlags = GetVatFlags(); if (flags.IsSet(CCubeMaterialFlagBits::fDepthSorting) || flags.IsSet(CCubeMaterialFlagBits::fAlphaTest)) { CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ZERO, GX::BL_ONE, GX::LO_CLEAR); } else { CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR); } - // set vtx desc flags - // TODO +// CGX::SetVtxDescv_Compressed(vatFlags); +// CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO /* ? CC_ONE */); +// CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO /* ? CA_KONST */); +// CGX::SetTevKAlphaSel(GX::TEVSTAGE0, GX::TEV_KASEL_1); +// CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_POS, GX::IDENTITY, false, GX::PTIDENTITY); +// CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0); +// CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL); +// CGX::SetNumTevStages(1); +// CGX::SetNumChans(0); +// CGX::SetNumTexGens(1); +// CGX::SetNumIndStages(0); } void CCubeMaterial::SetupBlendMode(u32 blendFactors, const CModelFlags& flags, bool alphaTest) { diff --git a/Runtime/Graphics/CCubeMaterial.hpp b/Runtime/Graphics/CCubeMaterial.hpp index 870f63dba..be1a51f2a 100644 --- a/Runtime/Graphics/CCubeMaterial.hpp +++ b/Runtime/Graphics/CCubeMaterial.hpp @@ -25,35 +25,6 @@ enum class CCubeMaterialFlagBits : u32 { }; using CCubeMaterialFlags = Flags; -enum class CCubeMaterialVatAttribute : u32 { - Position = 0, - Normal = 2, - Color0 = 4, - Color1 = 8, - Tex0 = 10, - Tex1 = 12, - Tex2 = 14, - Tex3 = 16, - Tex4 = 18, - Tex5 = 20, - Tex6 = 22, -}; -enum class CCubeMaterialVatAttributeType : u32 { None = 0, Direct = 1, Index8 = 2, Index16 = 3 }; -class CCubeMaterialVatFlags { - u32 m_flags = 0; - -public: - constexpr CCubeMaterialVatFlags() noexcept = default; - constexpr CCubeMaterialVatFlags(u32 flags) noexcept : m_flags(flags){}; - [[nodiscard]] CCubeMaterialVatAttributeType GetAttributeType(CCubeMaterialVatAttribute attribute) const noexcept { - return CCubeMaterialVatAttributeType((m_flags >> u32(attribute)) & 0x3); - } - void SetAttributeType(CCubeMaterialVatAttribute attribute, CCubeMaterialVatAttributeType type) noexcept { - m_flags &= ~(u32(0x3) << u32(attribute)); - m_flags |= u32(type) << u32(attribute); - } -}; - class CCubeMaterial { const u8* x0_data; @@ -72,7 +43,7 @@ public: [[nodiscard]] CCubeMaterialFlags GetFlags() const { return CCubeMaterialFlags(SBig(*reinterpret_cast(x0_data))); } - [[nodiscard]] CCubeMaterialVatFlags GetVatFlags() const { + [[nodiscard]] u32 GetVatFlags() const { return SBig(*reinterpret_cast(x0_data + 8 + (GetTextureCount() * 4))); } [[nodiscard]] u32 GetUsedTextureSlots() const { return static_cast(GetFlags()) >> 16; } diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index 837fa972c..258e97110 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -12,6 +12,9 @@ #include "Runtime/Graphics/CModel.hpp" #include "Runtime/World/CGameArea.hpp" #include "Runtime/Particle/CParticleGen.hpp" +#include "Runtime/Particle/CDecal.hpp" +#include "Runtime/Particle/CElementGen.hpp" +#include "Runtime/CDvdFile.hpp" namespace metaforce { static logvisor::Module Log("CCubeRenderer"); @@ -208,11 +211,35 @@ void CCubeRenderer::GenerateFogVolumeRampTex() { } void CCubeRenderer::GenerateSphereRampTex() { - // TODO + u8* data = x220_sphereRamp.Lock(); + u32 offset = 0; + for (u32 y = 0; y < 32; ++y) { + s32 iVar3 = y >> 0x1f; + u8* row = data + offset; + for (u32 x = 0; x < 32; ++x) { + // TODO actually figure out what this is doing + const u32 vx = + ((static_cast(y) >> 2) + static_cast(y < 0 && (y & 3) != 0)) * 4 + (static_cast(x) >> 3); + const u32 vy = ((iVar3 * 4 | (y * 0x40000000 + iVar3) >> 0x1e) - iVar3) * 8 + (x & 7); + const zeus::CVector2f vec{ + static_cast(vx) / 15.5f - 1.f, + static_cast(vy) / 15.5f - 1.f, + }; + const auto mag = vec.magnitude(); + *row = static_cast(255.f * std::clamp(-(mag * mag - 1.f), 0.f, 1.f)); + ++row; + } + offset += 32; + } + x220_sphereRamp.UnLock(); } void CCubeRenderer::LoadThermoPalette() { - // TODO + x288_thermoPalette.Lock(); + TToken token = xc_store.GetObj("TXTR_ThermoPalette"); + u8* data = token.GetObj()->GetPalette()->GetPaletteData(); + memcpy(x288_thermoPalette.GetPaletteData(), data, 32); + x288_thermoPalette.UnLock(); } void CCubeRenderer::ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, CTexture& maskTex, @@ -443,8 +470,8 @@ void CCubeRenderer::DrawAreaGeometry(s32 areaIdx, s32 mask, s32 targetMask) { } void CCubeRenderer::RenderBucketItems(const CAreaListItem* item) { - SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CCubeRenderer::RenderBucketItems areaIdx={}"), item->x18_areaIdx).c_str(), - zeus::skBlue); + SCOPED_GRAPHICS_DEBUG_GROUP( + fmt::format(FMT_STRING("CCubeRenderer::RenderBucketItems areaIdx={}"), item->x18_areaIdx).c_str(), zeus::skBlue); CCubeModel* lastModel = nullptr; EDrawableType lastDrawableType = EDrawableType::Invalid; @@ -780,8 +807,7 @@ void CCubeRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) { 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); + DoThermalModelDraw(model.GetInstance(), multCol, addCol, positions, normals, flags); } void CCubeRenderer::DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color, @@ -848,17 +874,201 @@ void CCubeRenderer::RenderFogVolume(const zeus::CColor& color, const zeus::CAABo } void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& color) { - // TODO + x318_29_thermalVisor = thermal; + x2f0_thermalVisorLevel = level; + x2f4_thermColor = color; + CDecal::SetMoveRedToAlphaBuffer(false); + CElementGen::SetMoveRedToAlphaBuffer(false); } void CCubeRenderer::SetThermalColdScale(float scale) { x2f8_thermColdScale = zeus::clamp(0.f, scale, 1.f); } void CCubeRenderer::DoThermalBlendCold() { - // TODO + // Capture EFB + x318_26_requestRGBA6 = true; + GXSetAlphaUpdate(true); + GXSetDstAlpha(false, 0); + const auto height = CGraphics::GetViewportHeight(); + const auto width = CGraphics::GetViewportWidth(); + const auto top = CGraphics::GetViewportTop(); + const auto left = CGraphics::GetViewportLeft(); + CGX::SetZMode(true, GX::LEQUAL, false); + // GXSetTexCopySrc(left, top, width, height); + // GXSetTexCopyDst(width, height, GX::TF_I4, false); + // GXCopyTex(sSpareTextureData, true); + CGraphics::ResolveSpareTexture(aurora::gfx::ClipRect{ + .x = static_cast(left), + .y = static_cast(top), + .width = static_cast(width), + .height = static_cast(height), + }, 0, GX::TF_I4); + // CGraphics::LoadDolphinSpareTexture(width, height, GX::TF_I4, nullptr, GX::TEXMAP7); + CGraphics::LoadDolphinSpareTexture(0, GX::TF_I4, GX::TEXMAP7); + + // Upload random static texture (game reads from .text) + const u8* buf = CDvdFile::GetDolBuf() + 0x4f60; + u8* out = m_thermalRandomStatic.Lock(); + memcpy(out, buf + ROUND_UP_32(x2a8_thermalRand.Next()), m_thermalRandomStatic.GetMemoryAllocated()); + m_thermalRandomStatic.UnLock(); + m_thermalRandomStatic.Load(GX::TEXMAP0, EClampMode::Clamp); + m_thermalRandomStatic.Load(GX::TEXMAP1, EClampMode::Clamp); + + // Configure indirect texturing + const float level = std::clamp(x2f0_thermalVisorLevel * 0.5f, 0.f, 0.5f); + const aurora::Mat3x2 mtx{ + aurora::Vec2{(1.f - level) * 0.1f, 0.f}, + aurora::Vec2{0.f, 0.f}, + aurora::Vec2{0.f, level}, + }; + GXSetIndTexMtx(GX::ITM_0, &mtx, -2); + CGX::SetTevIndirect(GX::TEVSTAGE0, GX::INDTEXSTAGE0, GX::ITF_8, GX::ITB_STU, GX::ITM_0, GX::ITW_OFF, GX::ITW_OFF, + false, false, GX::ITBA_OFF); + GXSetIndTexOrder(GX::INDTEXSTAGE0, GX::TEXCOORD0, GX::TEXMAP0); + + // Configure register colors + const auto color0 = zeus::CColor::lerp(x2f4_thermColor, zeus::skWhite, x2f8_thermColdScale); + const float bAlpha = x2f8_thermColdScale < 0.5f ? x2f8_thermColdScale * 2.f : 1.f; + const float bFac = (1.f - bAlpha) / 8.f; + const zeus::CColor color1{bFac, bAlpha}; + float cFac; + if (x2f8_thermColdScale < 0.25f) { + cFac = 0.f; + } else if (x2f8_thermColdScale >= 1.f) { + cFac = 1.f; + } else { + cFac = (x2f8_thermColdScale - 0.25f) * 4.f / 3.f; + } + const zeus::CColor color2{cFac, cFac}; + GXSetTevColor(GX::TEVREG0, color0); + GXSetTevColor(GX::TEVREG1, color1); + GXSetTevColor(GX::TEVREG2, color2); + + // Configure TEV stage 0 + GXSetTevSwapMode(GX::TEVSTAGE0, GX::TEV_SWAP0, GX::TEV_SWAP1); + CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXC, GX::CC_C0, GX::CC_C2); + CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_TEXA, GX::CA_A1, GX::CA_A2); + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0); + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP7, GX::COLOR_NULL); + + // Configure TEV stage 1 + GXSetTevSwapMode(GX::TEVSTAGE1, GX::TEV_SWAP0, GX::TEV_SWAP1); + CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_TEXC, GX::CC_C1, GX::CC_CPREV); + CGX::SetTevColorOp(GX::TEVSTAGE1, GX::TEV_SUB, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV); + CGX::SetTevAlphaIn(GX::TEVSTAGE1, GX::CA_ZERO, GX::CA_A1, GX::CA_TEXA, GX::CA_APREV); + CGX::SetTevAlphaOp(GX::TEVSTAGE1, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_4, true, GX::TEVPREV); + CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD0, GX::TEXMAP1, GX::COLOR_NULL); + + // Configure everything else + CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX3x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY); + CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0); + CGX::SetNumTevStages(2); + CGX::SetNumTexGens(1); + CGX::SetNumChans(0); + CGX::SetNumIndStages(1); + CGX::SetZMode(false, GX::ALWAYS, false); + constexpr std::array vtxDescList{ + GX::VtxDescList{GX::VA_POS, GX::DIRECT}, + GX::VtxDescList{GX::VA_TEX0, GX::DIRECT}, + GX::VtxDescList{}, + }; + CGX::SetVtxDescv(vtxDescList.data()); + CGX::SetBlendMode(GX::BM_NONE, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR); + + // Backup & set viewport/projection + const auto backupViewMatrix = CGraphics::g_ViewMatrix; + const auto backupProjectionState = CGraphics::GetProjectionState(); + CGraphics::SetOrtho(0.f, static_cast(width), 0.f, static_cast(height), -4096.f, 4096.f); + CGraphics::SetViewPointMatrix({}); + CGraphics::SetModelMatrix({}); + GXPixModeSync(); + + // Draw + CGX::Begin(GX::TRIANGLEFAN, GX::VTXFMT0, 4); + GXPosition3f32(0.f, 0.5f, 0.f); + GXTexCoord2f32(0.f, 0.f); + GXPosition3f32(0.f, 0.5f, static_cast(height)); + GXTexCoord2f32(0.f, 1.f); + GXPosition3f32(static_cast(width), 0.5f, static_cast(height)); + GXTexCoord2f32(1.f, 1.f); + GXPosition3f32(static_cast(width), 0.5f, 0.f); + GXTexCoord2f32(1.f, 0.f); + CGX::End(); + + // Cleanup + GXSetTevSwapMode(GX::TEVSTAGE0, GX::TEV_SWAP0, GX::TEV_SWAP0); + GXSetTevSwapMode(GX::TEVSTAGE1, GX::TEV_SWAP0, GX::TEV_SWAP0); + CGX::SetNumIndStages(0); + CGX::SetTevDirect(GX::TEVSTAGE0); + GXSetDstAlpha(false, 255); + CGraphics::SetProjectionState(backupProjectionState); + CGraphics::SetViewPointMatrix(backupViewMatrix); + CDecal::SetMoveRedToAlphaBuffer(true); + CElementGen::SetMoveRedToAlphaBuffer(true); } void CCubeRenderer::DoThermalBlendHot() { - // TODO + CGX::SetNumIndStages(0); + CGX::SetTevDirect(GX::TEVSTAGE0); + GXSetAlphaUpdate(true); + // CGraphics::SetProjectionState(backupProjectionState); + // CGraphics::SetViewPointMatrix(backupViewMatrix); + CDecal::SetMoveRedToAlphaBuffer(false); + CElementGen::SetMoveRedToAlphaBuffer(false); + return; // TODO + + GXSetAlphaUpdate(false); + GXSetDstAlpha(true, 0); + const auto height = CGraphics::GetViewportHeight(); + const auto width = CGraphics::GetViewportWidth(); + const auto top = CGraphics::GetViewportTop(); + const auto left = CGraphics::GetViewportLeft(); + CGX::SetZMode(true, GX::LEQUAL, true); + // GXSetTexCopySrc(left, top, width, height); + // GXSetTexCopyDst(width, height, GX::TF_I4, false); + // GXCopyTex(sSpareTextureData, false); + CGraphics::ResolveSpareTexture(CGraphics::g_Viewport, 0, GX::TF_I4); + x288_thermoPalette.Load(); + // CGraphics::LoadDolphinSpareTexture(width, height, GX::TF_C4, GX::TLUT0, nullptr, GX::TEXMAP7); + CGraphics::LoadDolphinSpareTexture(0, GX::TF_C4, GX::TEXMAP7); + CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXA, GX::CC_TEXC, GX::CC_ZERO); + CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_TEXA); + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0); + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP7, GX::COLOR_NULL); + CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX3x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY); + CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0); + CGX::SetNumTevStages(1); + CGX::SetNumTexGens(1); + CGX::SetNumChans(0); + CGX::SetZMode(false, GX::LEQUAL, false); + constexpr std::array vtxDescList{ + GX::VtxDescList{GX::VA_POS, GX::DIRECT}, + GX::VtxDescList{GX::VA_TEX0, GX::DIRECT}, + GX::VtxDescList{}, + }; + CGX::SetVtxDescv(vtxDescList.data()); + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_DSTALPHA, GX::BL_INVDSTALPHA, GX::LO_CLEAR); + + // Backup & set viewport/projection + const auto backupViewMatrix = CGraphics::g_ViewMatrix; + const auto backupProjectionState = CGraphics::GetProjectionState(); + CGraphics::SetOrtho(0.f, static_cast(width), 0.f, static_cast(height), -4096.f, 4096.f); + CGraphics::SetViewPointMatrix({}); + CGraphics::SetModelMatrix({}); + GXPixModeSync(); + + // Draw + CGX::Begin(GX::TRIANGLEFAN, GX::VTXFMT0, 4); + GXPosition3f32(0.f, 0.5f, 0.f); + GXTexCoord2f32(0.f, 0.f); + GXPosition3f32(0.f, 0.5f, static_cast(height)); + GXTexCoord2f32(0.f, 1.f); + GXPosition3f32(static_cast(width), 0.5f, static_cast(height)); + GXTexCoord2f32(1.f, 1.f); + GXPosition3f32(static_cast(width), 0.5f, 0.f); + GXTexCoord2f32(1.f, 0.f); + CGX::End(); + + // move prologue here } u32 CCubeRenderer::GetStaticWorldDataSize() { @@ -941,4 +1151,37 @@ void CCubeRenderer::SetupRendererStates(bool depthWrite) { CCubeMaterial::ResetCachedMaterials(); GXSetTevColor(GX::TEVREG1, x2fc_tevReg1Color); } + +constexpr zeus::CTransform MvPostXf{ + {zeus::CVector3f{0.5f, 0.f, 0.f}, {0.f, 0.f, 0.f}, {0.f, 0.5f, 0.f}}, + {0.5f, 0.5f, 1.f}, +}; + +void CCubeRenderer::DoThermalModelDraw(CCubeModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol, + TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) { + SCOPED_GRAPHICS_DEBUG_GROUP("CCubeRenderer::DoThermalModelDraw", zeus::skBlue); + CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX3x4, GX::TG_NRM, GX::TEXMTX0, true, GX::PTTEXMTX0); + CGX::SetNumTexGens(1); + CGX::SetNumChans(0); + x220_sphereRamp.Load(GX::TEXMAP0, EClampMode::Clamp); + zeus::CTransform xf = CGraphics::g_ViewMatrix.inverse().multiplyIgnoreTranslation(CGraphics::g_GXModelMatrix); + xf.origin.zeroOut(); + GXLoadTexMtxImm(&xf, GX::TEXMTX0, GX::MTX3x4); + GXLoadTexMtxImm(&MvPostXf, GX::PTTEXMTX0, GX::MTX3x4); + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0); + CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_C0, GX::CC_TEXC, GX::CC_KONST); + CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_TEXA, GX::CA_A0, GX::CA_KONST); + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL); + CGX::SetNumTevStages(1); + CGX::SetTevKColor(GX::KCOLOR0, addCol); + CGX::SetTevKColorSel(GX::TEVSTAGE0, GX::TEV_KCSEL_K0); + CGX::SetTevKAlphaSel(GX::TEVSTAGE0, GX::TEV_KASEL_K0_A); + GXSetTevColor(GX::TEVREG0, multCol); + CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_OR, GX::ALWAYS, 0); + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ONE, GX::LO_CLEAR); + CGX::SetZMode(flags.x2_flags.IsSet(CModelFlagBits::DepthTest), GX::LEQUAL, + flags.x2_flags.IsSet(CModelFlagBits::DepthUpdate)); + model.DrawFlat(positions, normals, + flags.x2_flags.IsSet(CModelFlagBits::Unknown1) ? ESurfaceSelection::Unsorted : ESurfaceSelection::All); +} } // namespace metaforce diff --git a/Runtime/Graphics/CCubeRenderer.hpp b/Runtime/Graphics/CCubeRenderer.hpp index 7836658c4..3e6880c89 100644 --- a/Runtime/Graphics/CCubeRenderer.hpp +++ b/Runtime/Graphics/CCubeRenderer.hpp @@ -69,7 +69,7 @@ private: CTexture x150_reflectionTex{ETexelFormat::IA8, 32, 32, 1, "Reflection Texture"}; CTexture x1b8_fogVolumeRamp{ETexelFormat::I8, 256, 256, 1, "Fog Volume Ramp Texture"}; CTexture x220_sphereRamp{ETexelFormat::I8, 32, 32, 1, "Sphere Ramp Texture"}; - // CGraphicsPalette x288_thermoPalette{1, 16}; + CGraphicsPalette x288_thermoPalette{EPaletteFormat::RGB565, 16}; CRandom16 x2a8_thermalRand{20}; std::list x2ac_fogVolumes; std::list> x2c4_spaceWarps; @@ -92,6 +92,8 @@ private: bool x318_30_inAreaDraw : 1 = false; bool x318_31_persistRGBA6 : 1 = false; + CTexture m_thermalRandomStatic{ETexelFormat::IA4, 640, 448, 1, "Thermal Random Static"}; + void GenerateReflectionTex(); void GenerateFogVolumeRampTex(); void GenerateSphereRampTex(); diff --git a/Runtime/Graphics/CGX.hpp b/Runtime/Graphics/CGX.hpp index 69fc6d0fa..bc5e3bfe8 100644 --- a/Runtime/Graphics/CGX.hpp +++ b/Runtime/Graphics/CGX.hpp @@ -300,8 +300,7 @@ static inline void SetTevDirect(GX::TevStageID stageId) noexcept { auto& state = sGXState.x68_tevStates[stageId].x10_indFlags; if (state != 0) { state = 0; - // TODO - // GXSetTevDirect(stageId); + GXSetTevDirect(stageId); } } @@ -331,12 +330,19 @@ static inline void SetStandardDirectTev_Compressed(GX::TevStageID stageId, u32 c } } -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; +static inline 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 { + // TODO + GXSetTevIndirect(stageId, indStage, fmt, biasSel, mtxSel, wrapS, wrapT, addPrev, indLod, alphaSel); +} -void SetTevIndWarp(GX::TevStageID stageId, GX::IndTexStageID indStage, GXBool signedOffset, GXBool replaceMode, - GX::IndTexMtxID mtxSel) noexcept; +static inline void SetTevIndWarp(GX::TevStageID stageId, GX::IndTexStageID indStage, GXBool signedOffset, GXBool replaceMode, + GX::IndTexMtxID mtxSel) noexcept { + // TODO + GXSetTevIndWarp(stageId, indStage, signedOffset, replaceMode, mtxSel); +} static inline void SetTevKAlphaSel(GX::TevStageID stageId, GX::TevKAlphaSel sel) noexcept { auto& state = sGXState.x68_tevStates[stageId].x19_kAlphaSel; diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index a23fb06af..c71a50950 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -309,14 +309,19 @@ public: static const std::array skCubeBasisMats; - static void ResolveSpareTexture(const SClipScreenRect& rect, int bindIdx = 0, bool clearDepth = false) { - aurora::gfx::resolve_color({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx, clearDepth); + static void ResolveSpareTexture(const SClipScreenRect& rect, int bindIdx, GX::TextureFormat format, + bool clearDepth = false) { + aurora::gfx::resolve_color({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx, format, + clearDepth); } - static void LoadDolphinSpareTexture(int bindIdx, GX::TexMapID id) { - aurora::gfx::bind_color(bindIdx, id); + static void LoadDolphinSpareTexture(int bindIdx, GX::TextureFormat format, GX::TexMapID id) { + GXTexObj obj; + GXInitTexObjResolved(&obj, bindIdx, format, GX_CLAMP, GX_CLAMP); + GXInitTexObjLOD(&obj, GX_NEAR, GX_NEAR, 0.f, 0.f, 0.f, false, false, GX_ANISO_1); + GXLoadTexObj(&obj, id); } static void ResolveSpareDepth(const SClipScreenRect& rect, int bindIdx = 0) { - aurora::gfx::resolve_depth({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx); + // aurora::gfx::resolve_depth({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx); } static void SetTevStates(EStreamFlags flags) noexcept; diff --git a/Runtime/Graphics/CGraphicsPalette.cpp b/Runtime/Graphics/CGraphicsPalette.cpp index 1a388d8e4..1a3d4e318 100644 --- a/Runtime/Graphics/CGraphicsPalette.cpp +++ b/Runtime/Graphics/CGraphicsPalette.cpp @@ -6,7 +6,7 @@ u32 CGraphicsPalette::sCurrentFrameCount = 0; CGraphicsPalette::CGraphicsPalette(EPaletteFormat fmt, int count) : x0_fmt(fmt), x8_entryCount(count), xc_entries(new u8[count * 2]) { - //GXInitTlutObj(&x10_tlutObj, xc_entries.get(), x8_entryCount); + GXInitTlutObj(&x10_tlutObj, xc_entries.get(), static_cast(x0_fmt), x8_entryCount); } CGraphicsPalette::CGraphicsPalette(CInputStream& in) : x0_fmt(EPaletteFormat(in.ReadLong())) { @@ -15,13 +15,21 @@ CGraphicsPalette::CGraphicsPalette(CInputStream& in) : x0_fmt(EPaletteFormat(in. x8_entryCount = w * h; xc_entries.reset(new u8[x8_entryCount * 2]); in.Get(xc_entries.get(), x8_entryCount * 2); - //GXInitTlutObj(&x10_tlutObj, xc_entries.get(), x8_entryCount); - //DCFlushRange(xc_entries.get(), x8_entryCount * 2); + GXInitTlutObj(&x10_tlutObj, xc_entries.get(), static_cast(x0_fmt), x8_entryCount); + // DCFlushRange(xc_entries.get(), x8_entryCount * 2); } - void CGraphicsPalette::Load() { - //GXLoadTlut(x10_tlutObj, 0); + GXLoadTlut(&x10_tlutObj, GX_TLUT0); x4_frameLoaded = sCurrentFrameCount; } -} // namespace metaforce \ No newline at end of file + +void CGraphicsPalette::Lock() { x1c_locked = true; } + +void CGraphicsPalette::UnLock() { + // DCStoreRange(xc_lut, x8_numEntries << 1); + GXInitTlutObj(&x10_tlutObj, xc_entries.get(), static_cast(x0_fmt), x8_entryCount); + // DCFlushRange(xc_lut, x8_numEntries << 1); + x1c_locked = false; +} +} // namespace metaforce diff --git a/Runtime/Graphics/CGraphicsPalette.hpp b/Runtime/Graphics/CGraphicsPalette.hpp index 04280cee7..e7703f73d 100644 --- a/Runtime/Graphics/CGraphicsPalette.hpp +++ b/Runtime/Graphics/CGraphicsPalette.hpp @@ -1,16 +1,17 @@ #pragma once #include "RetroTypes.hpp" +#include "GX.hpp" #include namespace metaforce { class CInputStream; -enum class EPaletteFormat { - IA8 = 0x0, - RGB565 = 0x1, - RGB5A3 = 0x2, +enum class EPaletteFormat : std::underlying_type_t { + IA8 = GX_TL_IA8, + RGB565 = GX_TL_RGB565, + RGB5A3 = GX_TL_RGB5A3, }; class CGraphicsPalette { @@ -20,7 +21,7 @@ class CGraphicsPalette { u32 x4_frameLoaded{}; u32 x8_entryCount; std::unique_ptr xc_entries; - /* GXTlutObj x10_; */ + GXTlutObj x10_tlutObj; bool x1c_locked = false; public: @@ -28,8 +29,11 @@ public: explicit CGraphicsPalette(CInputStream& in); void Load(); + void Lock(); + void UnLock(); - [[nodiscard]] const u8* GetEntries() const { return xc_entries.get(); } + [[nodiscard]] u8* GetPaletteData() { return xc_entries.get(); } + [[nodiscard]] const u8* GetPaletteData() const { return xc_entries.get(); } static void SetCurrentFrameCount(u32 frameCount) { sCurrentFrameCount = frameCount; } }; diff --git a/Runtime/Graphics/CMoviePlayer.cpp b/Runtime/Graphics/CMoviePlayer.cpp index b2b1798ea..285f168c8 100644 --- a/Runtime/Graphics/CMoviePlayer.cpp +++ b/Runtime/Graphics/CMoviePlayer.cpp @@ -192,28 +192,22 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo CTHPTextureSet& set = x80_textures.emplace_back(); if (deinterlace) { /* metaforce addition: this way interlaced THPs don't look horrible */ - set.Y[0] = - aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1, ETexelFormat::R8PC, - fmt::format(FMT_STRING("Movie {} Texture Set {} Y[0]"), path, i)); - set.Y[1] = - aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1, ETexelFormat::R8PC, - fmt::format(FMT_STRING("Movie {} Texture Set {} Y[1]"), path, i)); - set.U = - aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, ETexelFormat::R8PC, - fmt::format(FMT_STRING("Movie {} Texture Set {} U"), path, i)); - set.V = - aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, ETexelFormat::R8PC, - fmt::format(FMT_STRING("Movie {} Texture Set {} V"), path, i)); + set.Y[0] = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1, GX::TF_I8, + fmt::format(FMT_STRING("Movie {} Texture Set {} Y[0]"), path, i)); + set.Y[1] = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1, GX::TF_I8, + fmt::format(FMT_STRING("Movie {} Texture Set {} Y[1]"), path, i)); + set.U = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, GX::TF_I8, + fmt::format(FMT_STRING("Movie {} Texture Set {} U"), path, i)); + set.V = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, GX::TF_I8, + fmt::format(FMT_STRING("Movie {} Texture Set {} V"), path, i)); } else { /* normal progressive presentation */ - set.Y[0] = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height, 1, ETexelFormat::R8PC, + set.Y[0] = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height, 1, GX::TF_I8, fmt::format(FMT_STRING("Movie {} Texture Set {} Y"), path, i)); - set.U = - aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, ETexelFormat::R8PC, - fmt::format(FMT_STRING("Movie {} Texture Set {} U"), path, i)); - set.V = - aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, ETexelFormat::R8PC, - fmt::format(FMT_STRING("Movie {} Texture Set {} V"), path, i)); + set.U = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, GX::TF_I8, + fmt::format(FMT_STRING("Movie {} Texture Set {} U"), path, i)); + set.V = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, GX::TF_I8, + fmt::format(FMT_STRING("Movie {} Texture Set {} V"), path, i)); } if (xf4_25_hasAudio) set.audioBuf.reset(new s16[x28_thpHead.maxAudioSamples * 2]); @@ -504,18 +498,18 @@ void CMoviePlayer::DecodeFromRead(const void* data) { memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2), x6c_videoInfo.width); } - aurora::gfx::write_texture(tex.Y[0], {buffer.get(), planeSizeHalf}); + aurora::gfx::write_texture(*tex.Y[0], {buffer.get(), planeSizeHalf}); for (unsigned y = 0; y < x6c_videoInfo.height / 2; ++y) { memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1), x6c_videoInfo.width); } - aurora::gfx::write_texture(tex.Y[1], {buffer.get(), planeSizeHalf}); + aurora::gfx::write_texture(*tex.Y[1], {buffer.get(), planeSizeHalf}); } else { /* Direct planar load */ - aurora::gfx::write_texture(tex.Y[0], {m_yuvBuf.get(), planeSize}); + aurora::gfx::write_texture(*tex.Y[0], {m_yuvBuf.get(), planeSize}); } - aurora::gfx::write_texture(tex.U, {m_yuvBuf.get() + planeSize, planeSizeQuarter}); - aurora::gfx::write_texture(tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter}); + aurora::gfx::write_texture(*tex.U, {m_yuvBuf.get() + planeSize, planeSizeQuarter}); + aurora::gfx::write_texture(*tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter}); break; } diff --git a/Runtime/Graphics/CTexture.cpp b/Runtime/Graphics/CTexture.cpp index 62959dec1..d4d2accbe 100644 --- a/Runtime/Graphics/CTexture.cpp +++ b/Runtime/Graphics/CTexture.cpp @@ -5,74 +5,6 @@ #include #include -u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, bool mipmap, u8 max_lod) { - s32 shiftX = 0; - s32 shiftY = 0; - switch (format) { - case GX::TF_I4: - case GX::TF_C4: - case GX::TF_CMPR: - case GX::CTF_R4: - case GX::CTF_Z4: - shiftX = 3; - shiftY = 3; - break; - case GX::TF_I8: - case GX::TF_IA4: - case GX::TF_C8: - case GX::TF_Z8: - case GX::CTF_RA4: - case GX::CTF_A8: - case GX::CTF_R8: - case GX::CTF_G8: - case GX::CTF_B8: - case GX::CTF_Z8M: - case GX::CTF_Z8L: - shiftX = 3; - shiftY = 2; - break; - case GX::TF_IA8: - case GX::TF_RGB565: - case GX::TF_RGB5A3: - case GX::TF_RGBA8: - case GX::TF_C14X2: - case GX::TF_Z16: - case GX::TF_Z24X8: - case GX::CTF_RA8: - case GX::CTF_RG8: - case GX::CTF_GB8: - case GX::CTF_Z16L: - shiftX = 2; - shiftY = 2; - break; - default: - break; - } - u32 bitSize = format == GX::TF_RGBA8 || format == GX::TF_Z24X8 ? 64 : 32; - u32 bufLen = 0; - if (mipmap) { - while (max_lod != 0) { - const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); - const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); - bufLen += bitSize * tileX * tileY; - - if (width == 1 && height == 1) { - return bufLen; - } - - width = (width < 2) ? 1 : width / 2; - height = (height < 2) ? 1 : height / 2; - --max_lod; - }; - } else { - const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); - const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); - bufLen = bitSize * tileX * tileY; - } - - return bufLen; -} - namespace metaforce { static std::array sLoadedTextures{}; @@ -85,7 +17,7 @@ CTexture::CTexture(ETexelFormat fmt, u16 w, u16 h, s32 mips, std::string_view la , x64_frameAllocated(sCurrentFrameCount) , m_label(fmt::format(FMT_STRING("{} ({})"), label, magic_enum::enum_name(fmt))) { InitBitmapBuffers(fmt, w, h, mips); - InitTextureObjs(false); + InitTextureObjs(); } CTexture::CTexture(CInputStream& in, std::string_view label, EAutoMipmap automip, EBlackKey blackKey) @@ -129,7 +61,7 @@ CTexture::CTexture(CInputStream& in, std::string_view label, EAutoMipmap automip } } - InitTextureObjs(true); + InitTextureObjs(); } u8* CTexture::Lock() { @@ -141,11 +73,14 @@ void CTexture::UnLock() { xa_24_locked = false; CountMemory(); // DCFlushRange(x44_aramToken.GetMRAMSafe(), ROUND_UP_32(xc_memoryAllocated)); + + // Aurora change: track when texture data needs to be invalidated + m_needsTexObjDataLoad = true; } void CTexture::Load(GX::TexMapID id, EClampMode clamp) { if (sLoadedTextures[id] != this || xa_29_canLoadObj) { - // auto* image_ptr = /*x44_aramToken.GetMRAMSafe() */ x44_aramToken_x4_buff.get(); + auto* data = /*x44_aramToken.GetMRAMSafe() */ x44_aramToken_x4_buff.get(); CountMemory(); if (HasPalette()) { x10_graphicsPalette->Load(); @@ -154,12 +89,16 @@ void CTexture::Load(GX::TexMapID id, EClampMode clamp) { xa_29_canLoadObj = false; if (x40_clampMode != clamp) { x40_clampMode = !xa_26_isPowerOfTwo ? EClampMode::Clamp : clamp; - // GXInitTexObjWrapMode(x20_texObj, static_cast(x40_clampMode), static_cast(x40_clampMode)); + GXInitTexObjWrapMode(&x20_texObj, static_cast(x40_clampMode), + static_cast(x40_clampMode)); } - // GXInitObjectData(x20_texObj, image_ptr); - // GXLoadObj(x20_texObj, id); - aurora::gfx::bind_texture(id, clamp, x20_texObj, 0.f); + // Aurora change: track when texture data needs to be invalidated + if (m_needsTexObjDataLoad) { + GXInitTexObjData(&x20_texObj, data); + m_needsTexObjDataLoad = false; + } + GXLoadTexObj(&x20_texObj, id); sLoadedTextures[id] = this; x64_frameAllocated = sCurrentFrameCount; } @@ -179,15 +118,15 @@ void CTexture::LoadMipLevel(float lod, GX::TexMapID id, EClampMode clamp) { // } // } + // TODO // GXTexObj texObj; // GXInitTexObj(&texObj, image_ptr + offset, width, height, x18_gxFormat); - // GXInitTexObjLod(&texObj, GX_LINEAR, GX_LINEAR, 0.f, 1.f, 0.f, false, false, GX_ANISO_1); - if (HasPalette()) { - x10_graphicsPalette->Load(); - xa_25_canLoadPalette = false; - } - // GXLoadTexObj(&texObj, mapId); - aurora::gfx::bind_texture(id, clamp, x20_texObj, lod); + // GXInitTexObjLOD(&texObj, GX_LINEAR, GX_LINEAR, 0.f, 1.f, 0.f, false, false, GX_ANISO_1); + // if (HasPalette()) { + // x10_graphicsPalette->Load(); + // xa_25_canLoadPalette = false; + // } + // GXLoadTexObj(&x20_texObj, id); x64_frameAllocated = sCurrentFrameCount; sLoadedTextures[id] = nullptr; } @@ -227,13 +166,13 @@ void CTexture::InitBitmapBuffers(ETexelFormat fmt, u16 width, u16 height, s32 mi x18_gxFormat = GX::TF_IA8; break; case ETexelFormat::C4: - x1c_gxCIFormat = GX::TF_C4; + x1c_gxCIFormat = GX_TF_C4; break; case ETexelFormat::C8: - x1c_gxCIFormat = GX::TF_C8; + x1c_gxCIFormat = GX_TF_C8; break; case ETexelFormat::C14X2: - x1c_gxCIFormat = GX::TF_C14X2; + x1c_gxCIFormat = GX_TF_C14X2; break; case ETexelFormat::RGB565: x18_gxFormat = GX::TF_RGB565; @@ -252,16 +191,15 @@ void CTexture::InitBitmapBuffers(ETexelFormat fmt, u16 width, u16 height, s32 mi } u32 format = (x0_fmt == ETexelFormat::C4 || x0_fmt == ETexelFormat::C8 || x0_fmt == ETexelFormat::C14X2) - ? x1c_gxCIFormat - : x18_gxFormat; - + ? u32(x1c_gxCIFormat) + : u32(x18_gxFormat); xc_memoryAllocated = GXGetTexBufferSize(width, height, format, mips > 1, mips > 1 ? 11 : 0); x44_aramToken_x4_buff = std::make_unique(xc_memoryAllocated); /*x44_aramToken.PostConstruct(buf, xc_memoryAllocated, 1);*/ CountMemory(); } -void CTexture::InitTextureObjs(bool write) { +void CTexture::InitTextureObjs() { xa_26_isPowerOfTwo = zeus::floorPowerOfTwo(x4_w) == x4_w && zeus::floorPowerOfTwo(x6_h) == x6_h; if (!xa_26_isPowerOfTwo) { @@ -270,19 +208,14 @@ void CTexture::InitTextureObjs(bool write) { CountMemory(); if (IsCITexture()) { - // GXInitTexObjCI(x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x1c_gxCIFormat, u32(x40_clampMode), - // u32(x40_clampMode), x8_mips > 1, 0); - // TODO + GXInitTexObjCI(&x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x1c_gxCIFormat, + static_cast(x40_clampMode), static_cast(x40_clampMode), x8_mips > 1, + 0); } else { - // GXInitTexObj(x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x1c_gxCIFormat, u32(x40_clampMode), - // u32(x40_clampMode), x8_mips > 1); - // GXInitTexObjLOD(x20_texObj, x8_mips > 1 ? GX_LIN_MIP_LIN : GX_LINEAR, 0.f, static_cast(x8_mips) - 1.f, - // 0.f, - // false, false, x8_mips > 1 ? GX_ANISO_4 : GX_ANISO_1); - x20_texObj = aurora::gfx::new_dynamic_texture_2d(x4_w, x6_h, x8_mips, x0_fmt, m_label); - if (write) { - aurora::gfx::write_texture(x20_texObj, {x44_aramToken_x4_buff.get(), xc_memoryAllocated}); - } + GXInitTexObj(&x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x18_gxFormat, + static_cast(x40_clampMode), static_cast(x40_clampMode), x8_mips > 1); + GXInitTexObjLOD(&x20_texObj, x8_mips > 1 ? GX_LIN_MIP_LIN : GX_LINEAR, GX_LINEAR, 0.f, + static_cast(x8_mips) - 1.f, 0.f, false, false, x8_mips > 1 ? GX_ANISO_4 : GX_ANISO_1); } xa_29_canLoadObj = true; } @@ -336,7 +269,7 @@ u32 CTexture::sCurrentFrameCount = 0; u32 CTexture::sTotalAllocatedMemory = 0; void CTexture::InvalidateTexMap(GX::TexMapID id) { - aurora::gfx::unbind_texture(id); + // TODO: can we unbind in GX? sLoadedTextures[id] = nullptr; } diff --git a/Runtime/Graphics/CTexture.hpp b/Runtime/Graphics/CTexture.hpp index a9aaf6adf..972844bfd 100644 --- a/Runtime/Graphics/CTexture.hpp +++ b/Runtime/Graphics/CTexture.hpp @@ -6,8 +6,15 @@ #include "Runtime/Graphics/GX.hpp" #include "Runtime/IObj.hpp" #include "Runtime/Streams/CInputStream.hpp" +#include "GX.hpp" namespace metaforce { +enum class EClampMode : std::underlying_type_t { + Clamp = GX_CLAMP, + Repeat = GX_REPEAT, + Mirror = GX_MIRROR, +}; + class CTexture { class CDumpedBitmapDataReloader { int x0_; @@ -56,18 +63,19 @@ private: u32 xc_memoryAllocated = 0; std::unique_ptr x10_graphicsPalette; std::unique_ptr x14_bitmapReloader; - u32 x18_gxFormat = GX::TF_RGB565; - u32 x1c_gxCIFormat = GX::TF_C8; - aurora::gfx::TextureHandle x20_texObj; // was GXTexObj + GX::TextureFormat x18_gxFormat = GX::TF_RGB565; + GXCITexFmt x1c_gxCIFormat = GX_TF_C8; + GXTexObj x20_texObj; EClampMode x40_clampMode = EClampMode::Repeat; std::unique_ptr x44_aramToken_x4_buff; // was CARAMToken u32 x64_frameAllocated{}; // Metaforce additions std::string m_label; + bool m_needsTexObjDataLoad = true; void InitBitmapBuffers(ETexelFormat fmt, u16 width, u16 height, s32 mips); - void InitTextureObjs(bool write); // write param is added + void InitTextureObjs(); void CountMemory(); void UncountMemory(); void MangleMipmap(u32 mip); diff --git a/Runtime/Graphics/GX.hpp b/Runtime/Graphics/GX.hpp index 749a4d48d..f855b49ce 100644 --- a/Runtime/Graphics/GX.hpp +++ b/Runtime/Graphics/GX.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -740,6 +741,96 @@ enum DistAttnFn { using GXColor = zeus::CColor; using GXBool = bool; +enum GXTlutFmt { + GX_TL_IA8 = 0x0, + GX_TL_RGB565 = 0x1, + GX_TL_RGB5A3 = 0x2, + GX_MAX_TLUTFMT = 0x3, +}; + +struct GXTlutObj { + u32 format; + u32 addr; + u16 entries; +}; + +enum GXTlut { + GX_TLUT0 = 0, + GX_TLUT1 = 1, + GX_TLUT2 = 2, + GX_TLUT3 = 3, + GX_TLUT4 = 4, + GX_TLUT5 = 5, + GX_TLUT6 = 6, + GX_TLUT7 = 7, + GX_TLUT8 = 8, + GX_TLUT9 = 9, + GX_TLUT10 = 10, + GX_TLUT11 = 11, + GX_TLUT12 = 12, + GX_TLUT13 = 13, + GX_TLUT14 = 14, + GX_TLUT15 = 15, + GX_BIGTLUT0 = 16, + GX_BIGTLUT1 = 17, + GX_BIGTLUT2 = 18, + GX_BIGTLUT3 = 19, +}; + +enum GXTexWrapMode { + GX_CLAMP = 0, + GX_REPEAT = 1, + GX_MIRROR = 2, + GX_MAX_TEXWRAPMODE = 3, +}; + +enum GXTexFilter { + GX_NEAR, + GX_LINEAR, + GX_NEAR_MIP_NEAR, + GX_LIN_MIP_NEAR, + GX_NEAR_MIP_LIN, + GX_LIN_MIP_LIN, +}; + +enum GXAnisotropy { + GX_ANISO_1, + GX_ANISO_2, + GX_ANISO_4, + GX_MAX_ANISOTROPY, +}; + +enum GXCITexFmt { + GX_TF_C4 = GX::TF_C4, + GX_TF_C8 = GX::TF_C8, + GX_TF_C14X2 = GX::TF_C14X2, +}; + +namespace aurora::gfx { +struct TextureRef; +} // namespace aurora::gfx +struct GXTexObj { + std::shared_ptr ref; + void* data; + u32 dataSize; + u16 width; + u16 height; + GX::TextureFormat fmt; + GXTexWrapMode wrapS; + GXTexWrapMode wrapT; + GXBool hasMips; + GXTexFilter minFilter; + GXTexFilter magFilter; + float minLod; + float maxLod; + float lodBias; + GXBool biasClamp; + GXBool doEdgeLod; + GXAnisotropy maxAniso; + GXTlut tlut; + bool dataInvalidated; +}; + void GXSetNumChans(u8 num) noexcept; void GXSetNumIndStages(u8 num) noexcept; void GXSetNumTevStages(u8 num) noexcept; @@ -772,7 +863,6 @@ void GXSetVtxDesc(GX::Attr attr, GX::AttrType type) 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 GXSetFogColor(const GXColor& color) noexcept; void GXCallDisplayList(const void* data, u32 nbytes) noexcept; @@ -785,7 +875,8 @@ void GXSetProjection(const zeus::CMatrix4f& mtx, GX::ProjectionType type) noexce void GXSetViewport(float left, float top, float width, float height, float nearZ, float farZ) noexcept; void GXSetScissor(u32 left, u32 top, u32 width, u32 height) noexcept; // Unneeded, all attributes are expected to be full floats -// void GXSetVtxAttrFmt(GX::VtxFmt vtxfmt, GX::Attr attr, GX::CompCnt cnt, GX::CompType type, u8 frac) noexcept; +static inline void GXSetVtxAttrFmt(GX::VtxFmt vtxfmt, GX::Attr attr, GX::CompCnt cnt, GX::CompType type, + u8 frac) noexcept {} // Streaming void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept; void GXMatrixIndex1u8(u8 idx) noexcept; @@ -802,38 +893,78 @@ void GXEnd() noexcept; void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColorChan green, GX::TevColorChan blue, GX::TevColorChan alpha) noexcept; void GXSetTevSwapMode(GX::TevStageID stage, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) noexcept; +void GXSetLineWidth(u8 width, GX::TexOffset texOffset) noexcept; +void GXInitTlutObj(GXTlutObj* obj, void* data, GXTlutFmt format, u16 entries) noexcept; +void GXLoadTlut(const GXTlutObj* obj, GXTlut idx) noexcept; +void GXInitTexObj(GXTexObj* obj, void* data, u16 width, u16 height, GX::TextureFormat format, GXTexWrapMode wrapS, + GXTexWrapMode wrapT, GXBool mipmap) noexcept; +// Addition for binding render textures +void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format, GXTexWrapMode wrapS, GXTexWrapMode wrapT); +void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilt, GXTexFilter magFilt, float minLod, float maxLod, float lodBias, + GXBool biasClamp, GXBool doEdgeLod, GXAnisotropy maxAniso) noexcept; +void GXInitTexObjCI(GXTexObj* obj, void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS, + GXTexWrapMode wrapT, GXBool mipmap, u32 tlut) noexcept; +void GXInitTexObjData(GXTexObj* obj, void* data) noexcept; +void GXInitTexObjWrapMode(GXTexObj* obj, GXTexWrapMode wrapS, GXTexWrapMode wrapT) noexcept; +void GXInitTexObjTlut(GXTexObj* obj, u32 tlut) noexcept; +void GXLoadTexObj(GXTexObj* obj, GX::TexMapID id) noexcept; +void GXSetTexCopySrc(u16 x, u16 y, u16 w, u16 h) noexcept; +void GXSetTexCopyDst(u16 wd, u16 ht, GX::TextureFormat fmt, GXBool mipmap) noexcept; +u32 GXGetTexBufferSize(u16 width, u16 height, u32 fmt, GXBool mips, u8 maxLod) noexcept; +void GXCopyTex(void* dest, GXBool clear) noexcept; +static inline void GXPixModeSync() noexcept {} // no-op +void GXSetIndTexMtx(GX::IndTexMtxID id, const void* mtx /* Mat4x2 */, s8 scaleExp) noexcept; +void GXSetTevIndirect(GX::TevStageID tevStage, GX::IndTexStageID indStage, GX::IndTexFormat fmt, + GX::IndTexBiasSel biasSel, GX::IndTexMtxID matrixSel, GX::IndTexWrap wrapS, GX::IndTexWrap wrapT, + GXBool addPrev, GXBool indLod, GX::IndTexAlphaSel alphaSel) noexcept; +static inline void GXSetTevDirect(GX::TevStageID stageId) noexcept { + GXSetTevIndirect(stageId, GX::INDTEXSTAGE0, GX::ITF_8, GX::ITB_NONE, GX::ITM_OFF, GX::ITW_OFF, GX::ITW_OFF, false, + false, GX::ITBA_OFF); +} +static inline void GXSetTevIndWarp(GX::TevStageID tevStage, GX::IndTexStageID indStage, GXBool signedOffsets, + GXBool replaceMode, GX::IndTexMtxID matrixSel) noexcept { + const auto wrap = replaceMode ? GX::ITW_0 : GX::ITW_OFF; + const auto biasSel = signedOffsets ? GX::ITB_STU : GX::ITB_NONE; + GXSetTevIndirect(tevStage, indStage, GX::ITF_8, biasSel, matrixSel, wrap, wrap, false, false, GX::ITBA_OFF); +} +void GXSetIndTexOrder(GX::IndTexStageID indStage, GX::TexCoordID texCoord, GX::TexMapID texMap) noexcept; +void GXSetIndTexCoordScale(GX::IndTexStageID indStage, GX::IndTexScale scaleS, GX::IndTexScale scaleT) noexcept; // Lighting -void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0, float k1, float k2); -void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2); -void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2); -void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn); -void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBrightness, GX::DistAttnFn distFunc); -static inline void GXInitLightShininess(GX::LightObj* light, float shininess) { +void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0, float k1, float k2) noexcept; +void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2) noexcept; +void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2) noexcept; +void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn) noexcept; +void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBrightness, GX::DistAttnFn distFunc) noexcept; +static inline void GXInitLightShininess(GX::LightObj* light, float shininess) noexcept { GXInitLightAttn(light, 0.f, 0.f, 1.f, (shininess) / 2.f, 0.f, 1.f - (shininess) / 2.f); } -void GXInitLightPos(GX::LightObj* light, float x, float y, float z); -static inline void GXInitLightPosv(GX::LightObj* light, float vec[3]) { GXInitLightPos(light, vec[0], vec[1], vec[2]); } -void GXInitLightDir(GX::LightObj* light, float nx, float ny, float nz); -static inline void GXInitLightDirv(GX::LightObj* light, float vec[3]) { GXInitLightDir(light, vec[0], vec[1], vec[2]); } -void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz); -void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, float hx, float hy, float hz); -static inline void GXInitLightSpecularDirHAv(GX::LightObj* light, float vecn[3], float vech[3]) { +void GXInitLightPos(GX::LightObj* light, float x, float y, float z) noexcept; +static inline void GXInitLightPosv(GX::LightObj* light, float vec[3]) noexcept { + GXInitLightPos(light, vec[0], vec[1], vec[2]); +} +void GXInitLightDir(GX::LightObj* light, float nx, float ny, float nz) noexcept; +static inline void GXInitLightDirv(GX::LightObj* light, float vec[3]) noexcept { + GXInitLightDir(light, vec[0], vec[1], vec[2]); +} +void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz) noexcept; +void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, float hx, float hy, float hz) noexcept; +static inline void GXInitLightSpecularDirHAv(GX::LightObj* light, float vecn[3], float vech[3]) noexcept { GXInitSpecularDirHA(light, vecn[0], vecn[1], vecn[2], vech[0], vech[1], vech[2]); } -void GXInitLightColor(GX::LightObj* light, GX::Color col); -void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id); -void GXLoadLightObjIndx(u32 index, GX::LightID); +void GXInitLightColor(GX::LightObj* light, GX::Color col) noexcept; +void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) noexcept; +void GXLoadLightObjIndx(u32 index, GX::LightID) noexcept; -void GXGetLightAttnA(const GX::LightObj* light, float* a0, float* a1, float* a2); -void GXGetLightAttnK(const GX::LightObj* light, float* k0, float* k1, float* k2); -void GXGetLightPos(const GX::LightObj* light, float* x, float* y, float* z); -static inline void GXGetLightPosv(const GX::LightObj* light, float* vec[3]) { +void GXGetLightAttnA(const GX::LightObj* light, float* a0, float* a1, float* a2) noexcept; +void GXGetLightAttnK(const GX::LightObj* light, float* k0, float* k1, float* k2) noexcept; +void GXGetLightPos(const GX::LightObj* light, float* x, float* y, float* z) noexcept; +static inline void GXGetLightPosv(const GX::LightObj* light, float* vec[3]) noexcept { GXGetLightPos(light, vec[0], vec[1], vec[2]); } -void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz); -static inline void GXGetLightDirv(const GX::LightObj* light, float* vec[3]) { +void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz) noexcept; +static inline void GXGetLightDirv(const GX::LightObj* light, float* vec[3]) noexcept { GXGetLightDir(light, vec[0], vec[1], vec[2]); } -void GXGetLightColor(const GX::LightObj* light, GX::Color* col); +void GXGetLightColor(const GX::LightObj* light, GX::Color* col) noexcept; diff --git a/Runtime/Graphics/Shaders/CCameraBlurFilter.cpp b/Runtime/Graphics/Shaders/CCameraBlurFilter.cpp index 8172ccc4f..82bd316c7 100644 --- a/Runtime/Graphics/Shaders/CCameraBlurFilter.cpp +++ b/Runtime/Graphics/Shaders/CCameraBlurFilter.cpp @@ -48,7 +48,7 @@ void CCameraBlurFilter::draw(float amount, bool clearDepth) { SCOPED_GRAPHICS_DEBUG_GROUP("CCameraBlurFilter::draw", zeus::skMagenta); const SClipScreenRect clipRect(CGraphics::g_Viewport); - CGraphics::ResolveSpareTexture(clipRect, 0, clearDepth); +// CGraphics::ResolveSpareTexture(clipRect, 0, clearDepth); const float aspect = float(CGraphics::g_CroppedViewport.xc_width) / float(CGraphics::g_CroppedViewport.x10_height); const float xFac = float(CGraphics::GetCroppedViewportWidth()) / float(CGraphics::GetViewportWidth()); diff --git a/Runtime/Graphics/Shaders/CPhazonSuitFilter.cpp b/Runtime/Graphics/Shaders/CPhazonSuitFilter.cpp index 0163354ae..fdabdcb07 100644 --- a/Runtime/Graphics/Shaders/CPhazonSuitFilter.cpp +++ b/Runtime/Graphics/Shaders/CPhazonSuitFilter.cpp @@ -128,7 +128,7 @@ void CPhazonSuitFilter::drawBlurPasses(float radius, const CTexture* indTex) { // CGraphics::SetShaderDataBinding(m_dataBindBlurX); // CGraphics::DrawArray(0, 4); - CGraphics::ResolveSpareTexture(rect, 2); +// CGraphics::ResolveSpareTexture(rect, 2); /* Y Pass */ blurDir = zeus::CVector4f{0.f, radius * blurScale, 0.f, 0.f}; @@ -136,7 +136,7 @@ void CPhazonSuitFilter::drawBlurPasses(float radius, const CTexture* indTex) { // CGraphics::SetShaderDataBinding(m_dataBindBlurY); // CGraphics::DrawArray(0, 4); - CGraphics::ResolveSpareTexture(rect, 2); +// CGraphics::ResolveSpareTexture(rect, 2); } void CPhazonSuitFilter::draw(const zeus::CColor& color, float indScale, float indOffX, float indOffY) { diff --git a/Runtime/Graphics/Shaders/CSpaceWarpFilter.cpp b/Runtime/Graphics/Shaders/CSpaceWarpFilter.cpp index e79beed36..eb68db077 100644 --- a/Runtime/Graphics/Shaders/CSpaceWarpFilter.cpp +++ b/Runtime/Graphics/Shaders/CSpaceWarpFilter.cpp @@ -36,7 +36,7 @@ void CSpaceWarpFilter::GenerateWarpRampTex() { } } m_warpTex = aurora::gfx::new_static_texture_2d( - WARP_RAMP_RES + 1, WARP_RAMP_RES + 1, 1, ETexelFormat::RGBA8PC, + WARP_RAMP_RES + 1, WARP_RAMP_RES + 1, 1, GX::TF_RGBA8, {reinterpret_cast(data.data()), (WARP_RAMP_RES + 1) * (WARP_RAMP_RES + 1) * 4}, "Warp Ramp"); } @@ -158,7 +158,7 @@ void CSpaceWarpFilter::draw(const zeus::CVector3f& pt) { clipRect.x4_left += CGraphics::g_CroppedViewport.x4_left; clipRect.x8_top += CGraphics::g_CroppedViewport.x8_top; clipRect.x8_top = CGraphics::GetViewportHeight() - clipRect.x10_height - clipRect.x8_top; - CGraphics::ResolveSpareTexture(clipRect); +// CGraphics::ResolveSpareTexture(clipRect); m_uniform.m_strength.x() = m_uniform.m_matrix[0][0] * m_strength * 0.5f * (clipRect.x10_height / float(clipRect.xc_width)); diff --git a/Runtime/Graphics/Shaders/CThermalColdFilter.cpp b/Runtime/Graphics/Shaders/CThermalColdFilter.cpp index 4d05bffbb..221f6be1c 100644 --- a/Runtime/Graphics/Shaders/CThermalColdFilter.cpp +++ b/Runtime/Graphics/Shaders/CThermalColdFilter.cpp @@ -53,7 +53,7 @@ CThermalColdFilter::CThermalColdFilter() { void CThermalColdFilter::draw() { SCOPED_GRAPHICS_DEBUG_GROUP("CThermalColdFilter::draw", zeus::skMagenta); - CGraphics::ResolveSpareTexture(CGraphics::g_CroppedViewport); +// CGraphics::ResolveSpareTexture(CGraphics::g_CroppedViewport); // m_uniBuf->load(&m_uniform, sizeof(m_uniform)); // CGraphics::SetShaderDataBinding(m_dataBind); // CGraphics::DrawArray(0, 4); diff --git a/Runtime/Graphics/Shaders/CThermalHotFilter.cpp b/Runtime/Graphics/Shaders/CThermalHotFilter.cpp index 4e844511e..05eec49ce 100644 --- a/Runtime/Graphics/Shaders/CThermalHotFilter.cpp +++ b/Runtime/Graphics/Shaders/CThermalHotFilter.cpp @@ -49,7 +49,7 @@ CThermalHotFilter::CThermalHotFilter() { void CThermalHotFilter::draw() { SCOPED_GRAPHICS_DEBUG_GROUP("CThermalHotFilter::draw", zeus::skMagenta); - CGraphics::ResolveSpareTexture(CGraphics::g_CroppedViewport); +// CGraphics::ResolveSpareTexture(CGraphics::g_CroppedViewport); // m_uniBuf->load(&m_uniform, sizeof(m_uniform)); diff --git a/Runtime/Graphics/Shaders/CXRayBlurFilter.cpp b/Runtime/Graphics/Shaders/CXRayBlurFilter.cpp index 14a67b8ce..f34967fee 100644 --- a/Runtime/Graphics/Shaders/CXRayBlurFilter.cpp +++ b/Runtime/Graphics/Shaders/CXRayBlurFilter.cpp @@ -49,7 +49,7 @@ CXRayBlurFilter::CXRayBlurFilter(TLockedToken& tex) : m_paletteTex(tex void CXRayBlurFilter::draw(float amount) { SCOPED_GRAPHICS_DEBUG_GROUP("CXRayBlurFilter::draw", zeus::skMagenta); - CGraphics::ResolveSpareTexture(CGraphics::g_CroppedViewport); +// CGraphics::ResolveSpareTexture(CGraphics::g_CroppedViewport); const float blurL = amount * g_tweakGui->GetXrayBlurScaleLinear() * 0.25f; const float blurQ = amount * g_tweakGui->GetXrayBlurScaleQuadratic() * 0.25f; diff --git a/Runtime/GuiSys/CGuiTextSupport.cpp b/Runtime/GuiSys/CGuiTextSupport.cpp index 7013e1b94..71de6db27 100644 --- a/Runtime/GuiSys/CGuiTextSupport.cpp +++ b/Runtime/GuiSys/CGuiTextSupport.cpp @@ -68,44 +68,48 @@ const CTextRenderBuffer* CGuiTextSupport::GetCurrentPageRenderBuffer() const { float CGuiTextSupport::GetCurrentAnimationOverAge() const { float ret = 0.f; - if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { - if (x50_typeEnable) { - if (x40_primStartTimes.size()) { - const auto& lastTime = x40_primStartTimes.back(); - ret = std::max(ret, (buf->GetPrimitiveCount() - lastTime.second) / x58_chRate + lastTime.first); - } else { - ret = std::max(ret, buf->GetPrimitiveCount() / x58_chRate); - } - } - } + // TODO +// if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { +// if (x50_typeEnable) { +// if (x40_primStartTimes.size()) { +// const auto& lastTime = x40_primStartTimes.back(); +// ret = std::max(ret, (buf->GetPrimitiveCount() - lastTime.second) / x58_chRate + lastTime.first); +// } else { +// ret = std::max(ret, buf->GetPrimitiveCount() / x58_chRate); +// } +// } +// } return ret; } float CGuiTextSupport::GetNumCharsTotal() const { - if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { - if (x50_typeEnable) { - return buf->GetPrimitiveCount(); - } - } + // TODO +// if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { +// if (x50_typeEnable) { +// return buf->GetPrimitiveCount(); +// } +// } return 0.f; } float CGuiTextSupport::GetNumCharsPrinted() const { - if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { - if (x50_typeEnable) { - const float charsPrinted = x3c_curTime * x58_chRate; - return std::min(charsPrinted, float(buf->GetPrimitiveCount())); - } - } + // TODO +// if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { +// if (x50_typeEnable) { +// const float charsPrinted = x3c_curTime * x58_chRate; +// return std::min(charsPrinted, float(buf->GetPrimitiveCount())); +// } +// } return 0.f; } float CGuiTextSupport::GetTotalAnimationTime() const { - if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { - if (x50_typeEnable) { - return buf->GetPrimitiveCount() / x58_chRate; - } - } + // TODO +// if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { +// if (x50_typeEnable) { +// return buf->GetPrimitiveCount() / x58_chRate; +// } +// } return 0.f; } @@ -117,20 +121,21 @@ void CGuiTextSupport::SetTypeWriteEffectOptions(bool enable, float chFadeTime, f x58_chRate = std::max(chRate, 1.f); if (enable) { if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { - float chStartTime = 0.f; - for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) { - for (const std::pair& p : x40_primStartTimes) { - if (p.second < i) - continue; - if (p.second != i) - break; - chStartTime = p.first; - break; - } - - buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f)); - chStartTime += 1.f / x58_chRate; - } + // TODO +// float chStartTime = 0.f; +// for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) { +// for (const std::pair& p : x40_primStartTimes) { +// if (p.second < i) +// continue; +// if (p.second != i) +// break; +// chStartTime = p.first; +// break; +// } +// +// buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f)); +// chStartTime += 1.f / x58_chRate; +// } } } } @@ -138,20 +143,21 @@ void CGuiTextSupport::SetTypeWriteEffectOptions(bool enable, float chFadeTime, f void CGuiTextSupport::Update(float dt) { if (x50_typeEnable) { if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { - float chStartTime = 0.f; - for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) { - for (const std::pair& p : x40_primStartTimes) { - if (p.second < i) - continue; - if (p.second != i) - break; - chStartTime = p.first; - break; - } - - buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f)); - chStartTime += 1.f / x58_chRate; - } + // TODO +// float chStartTime = 0.f; +// for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) { +// for (const std::pair& p : x40_primStartTimes) { +// if (p.second < i) +// continue; +// if (p.second != i) +// break; +// chStartTime = p.first; +// break; +// } +// +// buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f)); +// chStartTime += 1.f / x58_chRate; +// } } x3c_curTime += dt; } @@ -253,7 +259,8 @@ void CGuiTextSupport::SetFontColor(const zeus::CColor& col) { void CGuiTextSupport::AddText(std::u16string_view str) { if (x60_renderBuf) { const float t = GetCurrentAnimationOverAge(); - x40_primStartTimes.emplace_back(std::max(t, x3c_curTime), x60_renderBuf->GetPrimitiveCount()); + // TODO +// x40_primStartTimes.emplace_back(std::max(t, x3c_curTime), x60_renderBuf->GetPrimitiveCount()); } x0_string += str; ClearRenderBuffer(); diff --git a/Runtime/GuiSys/CTextRenderBuffer.cpp b/Runtime/GuiSys/CTextRenderBuffer.cpp index 3afe4bc24..966784137 100644 --- a/Runtime/GuiSys/CTextRenderBuffer.cpp +++ b/Runtime/GuiSys/CTextRenderBuffer.cpp @@ -12,74 +12,74 @@ namespace metaforce { -struct CTextRenderBuffer::BooFontCharacters { - TLockedToken m_font; +//struct CTextRenderBuffer::BooFontCharacters { +// TLockedToken m_font; // hecl::VertexBufferPool::Token m_instBuf; // boo::ObjToken m_dataBinding; // boo::ObjToken m_dataBinding2; - std::vector m_charData; - u32 m_charCount = 0; - bool m_dirty = true; - - BooFontCharacters(const CToken& token) : m_font(token) {} -}; - -struct CTextRenderBuffer::BooImage { - CFontImageDef m_imageDef; +// std::vector m_charData; +// u32 m_charCount = 0; +// bool m_dirty = true; +// +// BooFontCharacters(const CToken& token) : m_font(token) {} +//}; +// +//struct CTextRenderBuffer::BooImage { +// CFontImageDef m_imageDef; // hecl::VertexBufferPool::Token m_instBuf; // std::vector> m_dataBinding; // std::vector> m_dataBinding2; - CTextSupportShader::ImageInstance m_imageData; - bool m_dirty = true; - - BooImage(const CFontImageDef& imgDef, const zeus::CVector2i& offset) : m_imageDef(imgDef) { - m_imageData.SetMetrics(imgDef, offset); - } -}; - -struct CTextRenderBuffer::BooPrimitiveMark { - Command m_cmd; - u32 m_bindIdx; - u32 m_instIdx; - - void SetOpacity(CTextRenderBuffer& rb, float opacity) { - switch (m_cmd) { - case Command::CharacterRender: { - BooFontCharacters& fc = rb.m_fontCharacters[m_bindIdx]; - CTextSupportShader::CharacterInstance& inst = fc.m_charData[m_instIdx]; - inst.m_mulColor.a() = opacity; - fc.m_dirty = true; - break; - } - case Command::ImageRender: { - BooImage& img = rb.m_images[m_bindIdx]; - img.m_imageData.m_color.a() = opacity; - img.m_dirty = true; - break; - } - default: - break; - } - } -}; +// CTextSupportShader::ImageInstance m_imageData; +// bool m_dirty = true; +// +// BooImage(const CFontImageDef& imgDef, const zeus::CVector2i& offset) : m_imageDef(imgDef) { +// m_imageData.SetMetrics(imgDef, offset); +// } +//}; +// +//struct CTextRenderBuffer::BooPrimitiveMark { +// Command m_cmd; +// u32 m_bindIdx; +// u32 m_instIdx; +// +// void SetOpacity(CTextRenderBuffer& rb, float opacity) { +// switch (m_cmd) { +// case Command::CharacterRender: { +// BooFontCharacters& fc = rb.m_fontCharacters[m_bindIdx]; +// CTextSupportShader::CharacterInstance& inst = fc.m_charData[m_instIdx]; +// inst.m_mulColor.a() = opacity; +// fc.m_dirty = true; +// break; +// } +// case Command::ImageRender: { +// BooImage& img = rb.m_images[m_bindIdx]; +// img.m_imageData.m_color.a() = opacity; +// img.m_dirty = true; +// break; +// } +// default: +// break; +// } +// } +//}; CTextRenderBuffer::CTextRenderBuffer(CTextRenderBuffer&&) noexcept = default; -CTextRenderBuffer::CTextRenderBuffer(EMode mode, CGuiWidget::EGuiModelDrawFlags df) : x0_mode(mode), m_drawFlags(df) {} +CTextRenderBuffer::CTextRenderBuffer(EMode mode, CGuiWidget::EGuiModelDrawFlags df) : x0_mode(mode)/*, m_drawFlags(df)*/ {} CTextRenderBuffer::~CTextRenderBuffer() = default; CTextRenderBuffer& CTextRenderBuffer::operator=(CTextRenderBuffer&&) noexcept = default; -void CTextRenderBuffer::CommitResources() { - if (m_committed) - return; - m_committed = true; - - /* Ensure font textures are ready outside transaction */ - for (BooFontCharacters& chs : m_fontCharacters) - chs.m_font->GetTexture(); - +//void CTextRenderBuffer::CommitResources() { +// if (m_committed) +// return; +// m_committed = true; +// +// /* Ensure font textures are ready outside transaction */ +// for (BooFontCharacters& chs : m_fontCharacters) +// chs.m_font->GetTexture(); +// // CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { // m_uniBuf = CTextSupportShader::s_Uniforms.allocateBlock(CGraphics::g_BooFactory); // auto uBufInfo = m_uniBuf.getBufferInfo(); @@ -142,109 +142,103 @@ void CTextRenderBuffer::CommitResources() { // } // return true; // } BooTrace); -} +//} void CTextRenderBuffer::SetMode(EMode mode) { - if (mode == EMode::BufferFill) { - m_images.reserve(m_imagesCount); - for (BooFontCharacters& fc : m_fontCharacters) - fc.m_charData.reserve(fc.m_charCount); - } - m_activeFontCh = -1; x0_mode = mode; } -void CTextRenderBuffer::SetPrimitiveOpacity(int idx, float opacity) { - m_primitiveMarks[idx].SetOpacity(*this, opacity); -} - -u32 CTextRenderBuffer::GetPrimitiveCount() const { return m_primitiveMarks.size(); } +//void CTextRenderBuffer::SetPrimitiveOpacity(int idx, float opacity) { +// m_primitiveMarks[idx].SetOpacity(*this, opacity); +//} +// +//u32 CTextRenderBuffer::GetPrimitiveCount() const { return m_primitiveMarks.size(); } void CTextRenderBuffer::Render(const zeus::CColor& col, float time) { - CommitResources(); +// CommitResources(); // const zeus::CMatrix4f mv = CGraphics::g_GXModelView.toMatrix4f(); // const zeus::CMatrix4f proj = CGraphics::GetPerspectiveProjectionMatrix(true); // const zeus::CMatrix4f mat = proj * mv; // m_uniBuf.access() = CTextSupportShader::Uniform{mat, col}; - if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { - zeus::CColor colPremul = col * col.a(); - colPremul.a() = col.a(); +// if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { +// zeus::CColor colPremul = col * col.a(); +// colPremul.a() = col.a(); // m_uniBuf2.access() = CTextSupportShader::Uniform{mat, colPremul}; - } +// } - for (BooFontCharacters& chs : m_fontCharacters) { - if (chs.m_charData.size()) { - if (chs.m_dirty) { +// for (BooFontCharacters& chs : m_fontCharacters) { +// if (chs.m_charData.size()) { +// if (chs.m_dirty) { // std::memmove(chs.m_instBuf.access(), chs.m_charData.data(), // sizeof(CTextSupportShader::CharacterInstance) * chs.m_charData.size()); - chs.m_dirty = false; - } +// chs.m_dirty = false; +// } // CGraphics::SetShaderDataBinding(chs.m_dataBinding); // CGraphics::DrawInstances(0, 4, chs.m_charData.size()); - if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { +// if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { // CGraphics::SetShaderDataBinding(chs.m_dataBinding2); // CGraphics::DrawInstances(0, 4, chs.m_charData.size()); - } - } - } +// } +// } +// } - for (BooImage& img : m_images) { - if (img.m_dirty) { +// for (BooImage& img : m_images) { +// if (img.m_dirty) { // *img.m_instBuf.access() = img.m_imageData; - img.m_dirty = false; - } +// img.m_dirty = false; +// } // const int idx = int(img.m_imageDef.x0_fps * time) % img.m_dataBinding.size(); // CGraphics::SetShaderDataBinding(img.m_dataBinding[idx]); // CGraphics::DrawInstances(0, 4, 1); - if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { +// if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { // CGraphics::SetShaderDataBinding(img.m_dataBinding2[idx]); // CGraphics::DrawInstances(0, 4, 1); - } - } +// } +// } } void CTextRenderBuffer::AddImage(const zeus::CVector2i& offset, const CFontImageDef& image) { - if (x0_mode == EMode::AllocTally) - m_primitiveMarks.push_back({Command::ImageRender, m_imagesCount++, 0}); - else - m_images.emplace_back(image, offset); +// if (x0_mode == EMode::AllocTally) +// m_primitiveMarks.push_back({Command::ImageRender, m_imagesCount++, 0}); +// else +// m_images.emplace_back(image, offset); } void CTextRenderBuffer::AddCharacter(const zeus::CVector2i& offset, char16_t ch, const zeus::CColor& color) { - if (m_activeFontCh == UINT32_MAX) - return; - BooFontCharacters& chs = m_fontCharacters[m_activeFontCh]; - if (x0_mode == EMode::AllocTally) - m_primitiveMarks.push_back({Command::CharacterRender, m_activeFontCh, chs.m_charCount++}); - else { - const CGlyph* glyph = chs.m_font.GetObj()->GetGlyph(ch); - - CTextSupportShader::CharacterInstance& inst = chs.m_charData.emplace_back(); - inst.SetMetrics(*glyph, offset); - inst.m_fontColor = m_main * color; - inst.m_outlineColor = m_outline * color; - inst.m_mulColor = zeus::skWhite; - } +// if (m_activeFontCh == UINT32_MAX) +// return; +// BooFontCharacters& chs = m_fontCharacters[m_activeFontCh]; +// if (x0_mode == EMode::AllocTally) +// m_primitiveMarks.push_back({Command::CharacterRender, m_activeFontCh, chs.m_charCount++}); +// else { +// const CGlyph* glyph = chs.m_font.GetObj()->GetGlyph(ch); +// +// CTextSupportShader::CharacterInstance& inst = chs.m_charData.emplace_back(); +// inst.SetMetrics(*glyph, offset); +// inst.m_fontColor = m_main * color; +// inst.m_outlineColor = m_outline * color; +// inst.m_mulColor = zeus::skWhite; +// } } void CTextRenderBuffer::AddPaletteChange(const zeus::CColor& main, const zeus::CColor& outline) { - m_main = main; - m_outline = outline; +// m_main = main; +// m_outline = outline; } void CTextRenderBuffer::AddFontChange(const TToken& font) { - for (size_t i = 0; i < m_fontCharacters.size(); ++i) { - BooFontCharacters& chs = m_fontCharacters[i]; - if (*chs.m_font.GetObjectTag() == *font.GetObjectTag()) { - m_activeFontCh = i; - return; - } - } - - m_activeFontCh = m_fontCharacters.size(); - m_fontCharacters.emplace_back(font); +// for (size_t i = 0; i < m_fontCharacters.size(); ++i) { +// BooFontCharacters& chs = m_fontCharacters[i]; +// if (*chs.m_font.GetObjectTag() == *font.GetObjectTag()) { +// m_activeFontCh = i; +// return; +// } +// } +// +// m_activeFontCh = m_fontCharacters.size(); +// m_fontCharacters.emplace_back(font); } bool CTextRenderBuffer::HasSpaceAvailable(const zeus::CVector2i& origin, const zeus::CVector2i& extent) const { @@ -263,23 +257,65 @@ std::pair CTextRenderBuffer::AccumulateTextBou std::pair ret = std::make_pair(zeus::CVector2i{INT_MAX, INT_MAX}, zeus::CVector2i{INT_MIN, INT_MIN}); - for (const BooFontCharacters& chars : m_fontCharacters) { - for (const CTextSupportShader::CharacterInstance& charInst : chars.m_charData) { - ret.first.x = std::min(ret.first.x, int(charInst.m_pos[0].x())); - ret.first.y = std::min(ret.first.y, int(charInst.m_pos[0].z())); - ret.second.x = std::max(ret.second.x, int(charInst.m_pos[3].x())); - ret.second.y = std::max(ret.second.y, int(charInst.m_pos[3].z())); - } - } - - for (const BooImage& imgs : m_images) { - ret.first.x = std::min(ret.first.x, int(imgs.m_imageData.m_pos[0].x())); - ret.first.y = std::min(ret.first.y, int(imgs.m_imageData.m_pos[0].z())); - ret.second.x = std::max(ret.second.x, int(imgs.m_imageData.m_pos[3].x())); - ret.second.y = std::max(ret.second.y, int(imgs.m_imageData.m_pos[3].z())); - } +// for (const BooFontCharacters& chars : m_fontCharacters) { +// for (const CTextSupportShader::CharacterInstance& charInst : chars.m_charData) { +// ret.first.x = std::min(ret.first.x, int(charInst.m_pos[0].x())); +// ret.first.y = std::min(ret.first.y, int(charInst.m_pos[0].z())); +// ret.second.x = std::max(ret.second.x, int(charInst.m_pos[3].x())); +// ret.second.y = std::max(ret.second.y, int(charInst.m_pos[3].z())); +// } +// } +// +// for (const BooImage& imgs : m_images) { +// ret.first.x = std::min(ret.first.x, int(imgs.m_imageData.m_pos[0].x())); +// ret.first.y = std::min(ret.first.y, int(imgs.m_imageData.m_pos[0].z())); +// ret.second.x = std::max(ret.second.x, int(imgs.m_imageData.m_pos[3].x())); +// ret.second.y = std::max(ret.second.y, int(imgs.m_imageData.m_pos[3].z())); +// } return ret; } +void CTextRenderBuffer::SetPrimitive(const Primitive& prim, s32 idx) { + CMemoryStreamOut out(reinterpret_cast(x34_bytecode.data() + x24_primOffsets[idx]), + x44_blobSize - x24_primOffsets[idx]); + if (prim.x4_command == Command::ImageRender) { + out.WriteUint8(1); + out.Put(prim.x8_xPos); + out.Put(prim.xa_zPos); + out.Put(prim.xe_imageIndex); +// out.Put(prim.x0_color1.toRGBA()); + } else if (prim.x4_command == Command::CharacterRender) { + out.WriteUint8(0); + out.Put(prim.x8_xPos); + out.Put(prim.xa_zPos); + out.Put(u16(prim.xc_glyph)); +// out.Put(prim.x0_color1.toRGBA()); + } +} + +CTextRenderBuffer::Primitive CTextRenderBuffer::GetPrimitive(s32 idx) const { + CMemoryInStream in(reinterpret_cast(x34_bytecode.data() + x24_primOffsets[idx]), + x44_blobSize - x24_primOffsets[idx]); + auto cmd = Command(in.ReadChar()); + if (cmd == Command::ImageRender) { + u16 xPos = in.ReadShort(); + u16 zPos = in.ReadShort(); + u8 imageIndex = in.ReadChar(); + CTextColor color(in.ReadUint32()); + return {color, Command::ImageRender, xPos, zPos, u'\0', imageIndex }; + } + + if (cmd == Command::CharacterRender) { + u16 xPos = in.ReadShort(); + u16 zPos = in.ReadShort(); + char16_t glyph = in.ReadUint16(); + CTextColor color(in.ReadUint32()); + + return {color, Command::CharacterRender, xPos, zPos, glyph, 0}; + } + + return {CTextColor(zeus::Comp32(0)), Command::Invalid, 0, 0, u'\0', 0 }; +} + } // namespace metaforce diff --git a/Runtime/GuiSys/CTextRenderBuffer.hpp b/Runtime/GuiSys/CTextRenderBuffer.hpp index d624a6536..b94f646de 100644 --- a/Runtime/GuiSys/CTextRenderBuffer.hpp +++ b/Runtime/GuiSys/CTextRenderBuffer.hpp @@ -27,58 +27,29 @@ class CTextRenderBuffer { friend class CTextSupportShader; public: - enum class Command { CharacterRender, ImageRender, FontChange, PaletteChange }; -#if 0 - struct Primitive - { - CTextColor x0_color1; - Command x4_command; - u16 x8_xPos; - u16 xa_zPos; - char16_t xc_glyph; - u8 xe_imageIndex; - }; -#endif + enum class Command { CharacterRender, ImageRender, FontChange, PaletteChange, Invalid }; + struct Primitive { + CTextColor x0_color1; + Command x4_command; + u16 x8_xPos; + u16 xa_zPos; + char16_t xc_glyph; + u8 xe_imageIndex; + }; enum class EMode { AllocTally, BufferFill }; private: EMode x0_mode; -#if 0 - std::vector> x4_fonts; - std::vector x14_images; - std::vector x24_primOffsets; - std::vector x34_bytecode; - u32 x44_blobSize = 0; - u32 x48_curBytecodeOffset = 0; - u8 x4c_activeFont; - u32 x50_paletteCount = 0; - std::array, 64> x54_palettes; - u32 x254_nextPalette = 0; - -#else - /* Boo-specific text-rendering functionality */ -// hecl::UniformBufferPool::Token m_uniBuf; -// hecl::UniformBufferPool::Token m_uniBuf2; - - struct BooFontCharacters; - std::vector m_fontCharacters; - - struct BooImage; - std::vector m_images; - - struct BooPrimitiveMark; - std::vector m_primitiveMarks; - u32 m_imagesCount = 0; - u32 m_activeFontCh = UINT32_MAX; - - zeus::CColor m_main; - zeus::CColor m_outline = zeus::skBlack; - - CGuiWidget::EGuiModelDrawFlags m_drawFlags; - - bool m_committed = false; - void CommitResources(); -#endif + std::vector> x4_fonts; + std::vector x14_images; + std::vector x24_primOffsets; + std::vector x34_bytecode; + u32 x44_blobSize = 0; + u32 x48_curBytecodeOffset = 0; + u8 x4c_activeFont; + u32 x50_paletteCount = 0; + std::array, 64> x54_palettes; + u32 x254_nextPalette = 0; public: CTextRenderBuffer(CTextRenderBuffer&& other) noexcept; @@ -87,18 +58,13 @@ public: CTextRenderBuffer& operator=(CTextRenderBuffer&& other) noexcept; -#if 0 - void SetPrimitive(const Primitive&, int); - Primitive GetPrimitive(int) const; - void GetOutStream(); - void VerifyBuffer(); - int GetMatchingPaletteIndex(const CGraphicsPalette& palette); - CGraphicsPalette* GetNextAvailablePalette(); - void AddPaletteChange(const CGraphicsPalette& palette); -#else - void SetPrimitiveOpacity(int idx, float opacity); - u32 GetPrimitiveCount() const; -#endif + void SetPrimitive(const Primitive&, int); + [[nodiscard]] Primitive GetPrimitive(int) const; + void GetOutStream(); + void VerifyBuffer(); + int GetMatchingPaletteIndex(const CGraphicsPalette& palette); + CGraphicsPalette* GetNextAvailablePalette(); + void AddPaletteChange(const CGraphicsPalette& palette); void SetMode(EMode mode); void Render(const zeus::CColor& col, float time); void AddImage(const zeus::CVector2i& offset, const CFontImageDef& image); diff --git a/Runtime/MP1/CInGameGuiManager.cpp b/Runtime/MP1/CInGameGuiManager.cpp index b58eb9901..b2278294d 100644 --- a/Runtime/MP1/CInGameGuiManager.cpp +++ b/Runtime/MP1/CInGameGuiManager.cpp @@ -596,7 +596,7 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) { float xT = 1.f - zeus::clamp(0.f, (stateMgr.GetPlayer().GetDeathTime() - xStart) / 0.5f, 1.f); float colT = 1.f - zeus::clamp(0.f, (stateMgr.GetPlayer().GetDeathTime() - colStart) / 0.5f, 1.f); SClipScreenRect rect(CGraphics::g_Viewport); - CGraphics::ResolveSpareTexture(rect); + CGraphics::ResolveSpareTexture(rect, 0, GX::TF_RGB565); CCameraFilterPass::DrawFilter(EFilterType::Blend, EFilterShape::Fullscreen, zeus::skBlack, nullptr, 1.f); float z = 0.5f * (zT * zT * zT * zT * zT * (CGraphics::GetViewportHeight() - 12.f) + 12.f); float x = 0.5f * (xT * (CGraphics::GetViewportWidth() - 12.f) + 12.f); diff --git a/Runtime/MP1/CPlayerVisor.cpp b/Runtime/MP1/CPlayerVisor.cpp index cad374539..70d8289d2 100644 --- a/Runtime/MP1/CPlayerVisor.cpp +++ b/Runtime/MP1/CPlayerVisor.cpp @@ -353,7 +353,7 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t rect.x8_top = int((CGraphics::GetViewportHeight() - vpH) / 2.f); rect.xc_width = int(vpW); rect.x10_height = int(vpH); - CGraphics::ResolveSpareTexture(rect); + CGraphics::ResolveSpareTexture(rect, 0, GX::TF_RGB565); // TODO hack; figure out why needed CGraphics::SetCullMode(ERglCullMode::None); @@ -369,7 +369,7 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t const zeus::CTransform seventeenScale = zeus::CTransform::Scale(17.f * vpScale, 1.f, 17.f * vpScale); const zeus::CTransform mm = seventeenScale * windowScale; g_Renderer->SetModelMatrix(mm); - CGraphics::LoadDolphinSpareTexture(0, GX::TEXMAP0); + CGraphics::LoadDolphinSpareTexture(0, GX::TF_RGB565, GX::TEXMAP0); if (x108_newScanPane) { SCOPED_GRAPHICS_DEBUG_GROUP("x108_newScanPane Draw", zeus::skMagenta); diff --git a/Runtime/Particle/CElementGen.cpp b/Runtime/Particle/CElementGen.cpp index 4b9f0ce8b..ea3b2ce22 100644 --- a/Runtime/Particle/CElementGen.cpp +++ b/Runtime/Particle/CElementGen.cpp @@ -1751,7 +1751,7 @@ void CElementGen::RenderParticlesIndirectTexture() { if (!clipRect.x0_valid) continue; - CGraphics::ResolveSpareTexture(clipRect); +// CGraphics::ResolveSpareTexture(clipRect); // SParticleInstanceIndTex& inst = g_instIndTexData.emplace_back(); // inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f}; diff --git a/Runtime/Weapon/CPhazonBeam.cpp b/Runtime/Weapon/CPhazonBeam.cpp index ec0a2fd14..0c78af813 100644 --- a/Runtime/Weapon/CPhazonBeam.cpp +++ b/Runtime/Weapon/CPhazonBeam.cpp @@ -184,7 +184,7 @@ void CPhazonBeam::Draw(bool drawSuitArm, const CStateManager& mgr, const zeus::C bool drawIndirect = visor == CPlayerState::EPlayerVisor::Combat || visor == CPlayerState::EPlayerVisor::Scan; if (drawIndirect) { - CGraphics::ResolveSpareTexture(CGraphics::g_Viewport); + // TODO CGraphics::ResolveSpareTexture(CGraphics::g_Viewport); CModelFlags tmpFlags = flags; // TODO tmpFlags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; CGunWeapon::Draw(drawSuitArm, mgr, xf, tmpFlags, lights); diff --git a/Runtime/Weapon/CPlayerGun.cpp b/Runtime/Weapon/CPlayerGun.cpp index 28a38ded3..9909541b7 100644 --- a/Runtime/Weapon/CPlayerGun.cpp +++ b/Runtime/Weapon/CPlayerGun.cpp @@ -2133,7 +2133,7 @@ zeus::CVector3f CPlayerGun::ConvertToScreenSpace(const zeus::CVector3f& pos, con void CPlayerGun::CopyScreenTex() { // Copy lower right quadrant to gpCopyTexBuf as RGBA8 - CGraphics::ResolveSpareTexture(CGraphics::g_Viewport); + // TODO CGraphics::ResolveSpareTexture(CGraphics::g_Viewport); } void CPlayerGun::DrawScreenTex(float z) { diff --git a/Runtime/World/CFluidPlaneManager.cpp b/Runtime/World/CFluidPlaneManager.cpp index 59a80c069..6eb3eb516 100644 --- a/Runtime/World/CFluidPlaneManager.cpp +++ b/Runtime/World/CFluidPlaneManager.cpp @@ -135,7 +135,7 @@ void CFluidPlaneManager::SetupRippleMap() { curX += (1.f / 63.f); } - RippleMapTex = aurora::gfx::new_static_texture_2d(64, 64, 1, ETexelFormat::R8PC, + RippleMapTex = aurora::gfx::new_static_texture_2d(64, 64, 1, GX::TF_I8, {reinterpret_cast(RippleValues.data()), 64 * 64}, "Ripple Map"); } diff --git a/Runtime/World/CWorldShadow.cpp b/Runtime/World/CWorldShadow.cpp index 91b97f472..55c372bab 100644 --- a/Runtime/World/CWorldShadow.cpp +++ b/Runtime/World/CWorldShadow.cpp @@ -6,7 +6,9 @@ namespace metaforce { -CWorldShadow::CWorldShadow(u32 w, u32 h, bool rgba8) : m_shader(w, h) {} +CWorldShadow::CWorldShadow(u32 w, u32 h, bool rgba8) +: x0_texture( + std::make_unique(rgba8 ? ETexelFormat::RGBA8 : ETexelFormat::RGB565, w, h, 1, "World Shadow"sv)) {} void CWorldShadow::EnableModelProjectedShadow(const zeus::CTransform& pos, s32 lightIdx, float f1) { zeus::CTransform texTransform = zeus::lookAt(zeus::skZero3f, x74_lightPos - x68_objPos); @@ -15,15 +17,9 @@ void CWorldShadow::EnableModelProjectedShadow(const zeus::CTransform& pos, s32 l texTransform = posXf.inverse() * texTransform; texTransform = (texTransform * zeus::CTransform::Scale(float(M_SQRT2) * x64_objHalfExtent * f1)).inverse(); texTransform = zeus::CTransform::Translate(0.5f, 0.f, 0.5f) * texTransform; - // TODO CCubeModel::EnableShadowMaps(m_shader.GetTexture(), texTransform); - -#if CWORLDSHADOW_FEEDBACK - if (!m_feedback) - m_feedback.emplace(EFilterType::Blend, m_shader.GetTexture().get()); - - zeus::CRectangle rect(0.4f, 0.4f, 0.2f, 0.2f); - m_feedback->draw(zeus::skWhite, 1.f, rect); -#endif + GX::LightMask lightMask; + lightMask.set(lightIdx); + // CCubeModel::EnableShadowMaps(*x0_texture, texTransform, lightMask, lightMask); } void CWorldShadow::DisableModelProjectedShadow() { CCubeModel::DisableShadowMaps(); } @@ -63,45 +59,72 @@ void CWorldShadow::BuildLightShadowTexture(const CStateManager& mgr, TAreaId aid zeus::CFrustum frustum; frustum.updatePlanes(x4_view, zeus::SProjPersp(zeus::degToRad(fov), 1.f, 0.1f, distance + x64_objHalfExtent)); g_Renderer->SetClippingPlanes(frustum); - g_Renderer->SetPerspective(fov, m_shader.GetWidth(), m_shader.GetHeight(), 0.1f, 1000.f); + g_Renderer->SetPerspective(fov, x0_texture->GetWidth(), x0_texture->GetHeight(), 0.1f, 1000.f); SViewport backupVp = CGraphics::g_Viewport; zeus::CVector2f backupDepthRange = CGraphics::g_CachedDepthRange; - m_shader.bindRenderTarget(); - g_Renderer->SetViewport(0, 0, m_shader.GetWidth(), m_shader.GetHeight()); + g_Renderer->SetViewport(0, 0, x0_texture->GetWidth(), x0_texture->GetHeight()); CGraphics::SetDepthRange(DEPTH_NEAR, DEPTH_FAR); x34_model = zeus::lookAt(centerPoint - zeus::CVector3f(0.f, 0.f, 0.1f), light.GetPosition()); CGraphics::SetModelMatrix(x34_model); float extent = float(M_SQRT2) * x64_objHalfExtent; - /* Depth test and write */ - /* Color white 100% alpha */ - m_shader.drawBase(extent); + g_Renderer->PrimColor(zeus::skWhite); + CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); + CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, + ERglLogicOp::Clear); + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassThru); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); + g_Renderer->BeginTriangleStrip(4); + g_Renderer->PrimVertex({-extent, 0.f, extent}); + g_Renderer->PrimVertex({extent, 0.f, extent}); + g_Renderer->PrimVertex({-extent, 0.f, -extent}); + g_Renderer->PrimVertex({extent, 0.f, -extent}); + g_Renderer->EndPrimitive(); CGraphics::SetModelMatrix(zeus::CTransform()); + CCubeModel::SetRenderModelBlack(true); CCubeModel::SetDrawingOccluders(true); g_Renderer->PrepareDynamicLights({}); - // g_Renderer->UpdateAreaUniforms(aid, EWorldShadowMode::WorldOnActorShadow); g_Renderer->DrawUnsortedGeometry(aid, 0, 0); + CCubeModel::SetRenderModelBlack(false); CCubeModel::SetDrawingOccluders(false); if (lighten) { CGraphics::SetModelMatrix(x34_model); - /* No depth test or write */ - /* Color white 25% alpha */ - m_shader.lightenShadow(); + CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); + CGraphics::SetDepthWriteMode(false, ERglEnum::LEqual, false); + CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, + ERglLogicOp::Clear); + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassThru); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); + CGraphics::StreamBegin(GX::TRIANGLESTRIP); + CGraphics::StreamColor(1.f, 1.f, 1.f, 0.25f); + CGraphics::StreamVertex(-extent, 0.f, extent); + CGraphics::StreamVertex(extent, 0.f, extent); + CGraphics::StreamVertex(-extent, 0.f, -extent); + CGraphics::StreamVertex(extent, 0.f, -extent); + CGraphics::StreamEnd(); + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); } if (motionBlur && !x88_blurReset) { - /* No depth test or write */ - /* Color white 85% alpha */ - /* Draw in shadow texture */ - m_shader.blendPreviousShadow(); + CGraphics::SetDepthWriteMode(false, ERglEnum::LEqual, false); + CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, + ERglLogicOp::Clear); + CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); + CGraphics::Render2D(*x0_texture, 0, x0_texture->GetWidth() * 2, x0_texture->GetHeight() * 2, + x0_texture->GetWidth() * -2, zeus::CColor{1.f, 0.85f}); + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); } x88_blurReset = false; - m_shader.resolveTexture(); + // TODO + // m_shader.resolveTexture(); // CBooRenderer::BindMainDrawTarget(); g_Renderer->SetViewport(backupVp.x0_left, backupVp.x4_top, backupVp.x8_width, backupVp.xc_height); diff --git a/Runtime/World/CWorldShadow.hpp b/Runtime/World/CWorldShadow.hpp index 6c0e91ed4..4613ae814 100644 --- a/Runtime/World/CWorldShadow.hpp +++ b/Runtime/World/CWorldShadow.hpp @@ -7,13 +7,11 @@ #include #include -#define CWORLDSHADOW_FEEDBACK 0 - namespace metaforce { class CStateManager; class CWorldShadow { - CWorldShadowShader m_shader; + std::unique_ptr x0_texture; zeus::CTransform x4_view; zeus::CTransform x34_model; float x64_objHalfExtent = 1.f; @@ -22,9 +20,7 @@ class CWorldShadow { TAreaId x80_aid = kInvalidAreaId; s32 x84_lightIdx = -1; bool x88_blurReset = true; -#if CWORLDSHADOW_FEEDBACK - std::optional m_feedback; -#endif + public: CWorldShadow(u32 w, u32 h, bool rgba8); void EnableModelProjectedShadow(const zeus::CTransform& pos, s32 lightIdx, float f1); diff --git a/Runtime/World/CWorldTransManager.cpp b/Runtime/World/CWorldTransManager.cpp index 96144eb4e..b99f1bc7c 100644 --- a/Runtime/World/CWorldTransManager.cpp +++ b/Runtime/World/CWorldTransManager.cpp @@ -290,9 +290,9 @@ void CWorldTransManager::DrawEnabled() { float t = zeus::clamp(0.f, (x0_curTime - x4_modelData->x1d0_dissolveStartTime) / 2.f, 1.f); DrawFirstPass(&lights); SClipScreenRect rect(CGraphics::g_Viewport); - CGraphics::ResolveSpareTexture(rect); +// CGraphics::ResolveSpareTexture(rect); // CGraphics::g_BooMainCommandQueue->clearTarget(true, true); - DrawSecondPass(&lights); +// DrawSecondPass(&lights); // m_dissolve.drawCropped(zeus::CColor{1.f, 1.f, 1.f, 1.f - t}, 1.f); } diff --git a/aurora/include/aurora/common.hpp b/aurora/include/aurora/common.hpp index fb4a34002..9d597ac95 100644 --- a/aurora/include/aurora/common.hpp +++ b/aurora/include/aurora/common.hpp @@ -18,6 +18,8 @@ struct Vec2 { constexpr Vec2() = default; constexpr Vec2(T x, T y) : x(x), y(y) {} constexpr Vec2(const zeus::CVector2f& vec) : x(vec.x()), y(vec.y()) {} + + bool operator==(const Vec2&) const = default; }; template struct Vec3 { @@ -28,6 +30,8 @@ struct Vec3 { constexpr Vec3() = default; constexpr Vec3(T x, T y, T z) : x(x), y(y), z(z) {} constexpr Vec3(const zeus::CVector3f& vec) : x(vec.x()), y(vec.y()), z(vec.z()) {} + + bool operator==(const Vec3&) const = default; }; template struct Vec4 { @@ -40,6 +44,19 @@ struct Vec4 { constexpr Vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {} constexpr Vec4(const zeus::CVector4f& vec) : x(vec.x()), y(vec.y()), z(vec.z()), w(vec.w()) {} constexpr Vec4(const zeus::CColor& color) : x(color.r()), y(color.g()), z(color.b()), w(color.a()) {} + + bool operator==(const Vec4&) const = default; +}; +template +struct Mat3x2 { + Vec2 m0{}; + Vec2 m1{}; + Vec2 m2{}; + + constexpr Mat3x2() = default; + constexpr Mat3x2(const Vec2& m0, const Vec2& m1, const Vec2& m2) : m0(m0), m1(m1), m2(m2) {} + + bool operator==(const Mat3x2&) const = default; }; template struct Mat4x2 { @@ -51,6 +68,8 @@ struct Mat4x2 { constexpr Mat4x2() = default; constexpr Mat4x2(const Vec2& m0, const Vec2& m1, const Vec2& m2, const Vec2& m3) : m0(m0), m1(m1), m2(m2), m3(m3) {} + + bool operator==(const Mat4x2&) const = default; }; template struct Mat4x4 { @@ -64,6 +83,8 @@ struct Mat4x4 { : m0(m0), m1(m1), m2(m2), m3(m3) {} constexpr Mat4x4(const zeus::CMatrix4f& m) : m0(m[0]), m1(m[1]), m2(m[2]), m3(m[3]) {} constexpr Mat4x4(const zeus::CTransform& m) : Mat4x4(m.toMatrix4f()) {} + + bool operator==(const Mat4x4&) const = default; }; constexpr Mat4x4 Mat4x4_Identity{ Vec4{1.f, 0.f, 0.f, 0.f}, diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index 2126998aa..efbbba7d0 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -36,12 +36,6 @@ enum class ETexelFormat { R8PC = 12, }; -enum class EClampMode { - Clamp, - Repeat, - Mirror, -}; - enum class EStreamFlagBits : u8 { fHasNormal = 0x1, fHasColor = 0x2, @@ -52,13 +46,7 @@ using EStreamFlags = Flags; namespace aurora::gfx { struct TextureRef; -struct TextureHandle { - std::shared_ptr ref; - TextureHandle() = default; - TextureHandle(std::shared_ptr&& ref) : ref(std::move(ref)) {} - operator bool() const { return ref.operator bool(); } - void reset() { ref.reset(); } -}; +using TextureHandle = std::shared_ptr; struct ClipRect { int32_t x; @@ -85,24 +73,19 @@ struct ScopedDebugGroup { inline ~ScopedDebugGroup() noexcept { pop_debug_group(); } }; -// 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 set_viewport(float left, float top, float width, float height, float znear, float zfar) noexcept; void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept; -void resolve_color(const ClipRect& rect, uint32_t bind, bool clear_depth) noexcept; -void resolve_depth(const ClipRect& rect, uint32_t bind) noexcept; -void bind_color(u32 bindIdx, GX::TexMapID id) noexcept; +void resolve_color(const ClipRect& rect, uint32_t bindIdx, GX::TextureFormat fmt, bool clear_depth) noexcept; +void resolve_depth(const ClipRect& rect, uint32_t bindIdx, GX::TextureFormat fmt) 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, +TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mips, GX::TextureFormat format, ArrayRef data, zstring_view label) noexcept; -TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, metaforce::ETexelFormat format, +TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, GX::TextureFormat format, zstring_view label) noexcept; -TextureHandle new_render_texture(uint32_t width, uint32_t height, zstring_view label) noexcept; -void write_texture(const TextureHandle& handle, ArrayRef data) noexcept; +TextureHandle new_render_texture(uint32_t width, uint32_t height, GX::TextureFormat fmt, zstring_view label) noexcept; +void write_texture(const TextureRef& handle, ArrayRef data) noexcept; } // namespace aurora::gfx diff --git a/aurora/lib/gfx/common.cpp b/aurora/lib/gfx/common.cpp index 55d6b6b47..bb8fc46c0 100644 --- a/aurora/lib/gfx/common.cpp +++ b/aurora/lib/gfx/common.cpp @@ -218,7 +218,7 @@ bool operator==(const wgpu::Extent3D& lhs, const wgpu::Extent3D& rhs) { return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depthOrArrayLayers == rhs.depthOrArrayLayers; } -void resolve_color(const ClipRect& rect, uint32_t bind, bool clear_depth) noexcept { +void resolve_color(const ClipRect& rect, uint32_t bind, GX::TextureFormat fmt, bool clear_depth) noexcept { if (g_resolvedTextures.size() < bind + 1) { g_resolvedTextures.resize(bind + 1); } @@ -226,8 +226,8 @@ void resolve_color(const ClipRect& rect, uint32_t bind, bool clear_depth) noexce .width = static_cast(rect.width), .height = static_cast(rect.height), }; - if (!g_resolvedTextures[bind] || g_resolvedTextures[bind].ref->size != size) { - g_resolvedTextures[bind] = new_render_texture(rect.width, rect.height, "Resolved Texture"); + if (!g_resolvedTextures[bind] || g_resolvedTextures[bind]->size != size) { + g_resolvedTextures[bind] = new_render_texture(rect.width, rect.height, fmt, "Resolved Texture"); } auto& currentPass = g_renderPasses[g_currentRenderPass]; currentPass.resolveTarget = bind; @@ -237,12 +237,10 @@ void resolve_color(const ClipRect& rect, uint32_t bind, bool clear_depth) noexce newPass.clear = false; // TODO ++g_currentRenderPass; } -void resolve_depth(const ClipRect& rect, uint32_t bind) noexcept { +void resolve_depth(const ClipRect& rect, uint32_t bind, GX::TextureFormat fmt) noexcept { // TODO } -void bind_color(u32 bindIdx, GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast(id)] = {bindIdx}; } - void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, 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); @@ -552,7 +550,7 @@ void render(wgpu::CommandEncoder& cmd) { } auto& target = g_resolvedTextures[passInfo.resolveTarget]; const wgpu::ImageCopyTexture dst{ - .texture = target.ref->texture, + .texture = target->texture, }; const wgpu::Extent3D size{ .width = static_cast(passInfo.resolveRect.width), diff --git a/aurora/lib/gfx/common.hpp b/aurora/lib/gfx/common.hpp index cd6a5a216..d7046c907 100644 --- a/aurora/lib/gfx/common.hpp +++ b/aurora/lib/gfx/common.hpp @@ -128,22 +128,25 @@ extern size_t g_staticStorageLastSize; // TODO this is a bad place for this... extern std::vector g_resolvedTextures; +constexpr GX::TextureFormat InvalidTextureFormat = static_cast(-1); struct TextureRef { wgpu::Texture texture; wgpu::TextureView view; wgpu::Extent3D size; wgpu::TextureFormat format; uint32_t mipCount; - metaforce::ETexelFormat gameFormat; + GX::TextureFormat gxFormat; + bool isRenderTexture; // :shrug: for now TextureRef(wgpu::Texture&& texture, wgpu::TextureView&& view, wgpu::Extent3D size, wgpu::TextureFormat format, - uint32_t mipCount, metaforce::ETexelFormat gameFormat = metaforce::ETexelFormat::Invalid) + uint32_t mipCount, GX::TextureFormat gxFormat, bool isRenderTexture) : texture(std::move(texture)) , view(std::move(view)) , size(size) , format(format) , mipCount(mipCount) - , gameFormat(gameFormat) {} + , gxFormat(gxFormat) + , isRenderTexture(isRenderTexture) {} }; using BindGroupRef = uint64_t; diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 05c2bcabd..2ea676372 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -42,11 +42,11 @@ void GXSetZMode(bool compare_enable, GX::Compare func, bool update_enable) noexc g_gxState.depthUpdate = update_enable; } void GXSetTevColor(GX::TevRegID id, const zeus::CColor& color) noexcept { - if (id < GX::TEVREG0 || id > GX::TEVREG2) { + if (id < GX::TEVPREV || id > GX::TEVREG2) { Log.report(logvisor::Fatal, FMT_STRING("bad tevreg {}"), id); unreachable(); } - g_gxState.colorRegs[id - 1] = color; + g_gxState.colorRegs[id] = color; } void GXSetTevKColor(GX::TevKColorID id, const zeus::CColor& color) noexcept { if (id >= GX::MAX_KCOLOR) { @@ -201,8 +201,76 @@ void GXSetLineWidth(u8 width, GX::TexOffset offs) noexcept { // TODO } +u32 GXGetTexBufferSize(u16 width, u16 height, u32 fmt, GXBool mips, u8 maxLod) noexcept { + s32 shiftX = 0; + s32 shiftY = 0; + switch (fmt) { + case GX::TF_I4: + case GX::TF_C4: + case GX::TF_CMPR: + case GX::CTF_R4: + case GX::CTF_Z4: + shiftX = 3; + shiftY = 3; + break; + case GX::TF_I8: + case GX::TF_IA4: + case GX::TF_C8: + case GX::TF_Z8: + case GX::CTF_RA4: + case GX::CTF_A8: + case GX::CTF_R8: + case GX::CTF_G8: + case GX::CTF_B8: + case GX::CTF_Z8M: + case GX::CTF_Z8L: + shiftX = 3; + shiftY = 2; + break; + case GX::TF_IA8: + case GX::TF_RGB565: + case GX::TF_RGB5A3: + case GX::TF_RGBA8: + case GX::TF_C14X2: + case GX::TF_Z16: + case GX::TF_Z24X8: + case GX::CTF_RA8: + case GX::CTF_RG8: + case GX::CTF_GB8: + case GX::CTF_Z16L: + shiftX = 2; + shiftY = 2; + break; + default: + break; + } + u32 bitSize = fmt == GX::TF_RGBA8 || fmt == GX::TF_Z24X8 ? 64 : 32; + u32 bufLen = 0; + if (mips) { + while (maxLod != 0) { + const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); + const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); + bufLen += bitSize * tileX * tileY; + + if (width == 1 && height == 1) { + return bufLen; + } + + width = (width < 2) ? 1 : width / 2; + height = (height < 2) ? 1 : height / 2; + --maxLod; + }; + } else { + const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); + const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); + bufLen = bitSize * tileX * tileY; + } + + return bufLen; +} + // Lighting -void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0, float k1, float k2) { +void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0, float k1, float k2) noexcept { light->a0 = a0; light->a1 = a1; light->a2 = a2; @@ -211,19 +279,19 @@ void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0 light->k2 = k2; } -void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2) { +void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2) noexcept { light->a0 = a0; light->a1 = a1; light->a2 = a2; } -void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2) { +void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2) noexcept { light->k0 = k0; light->k1 = k1; light->k2 = k2; } -void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn) { +void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn) noexcept { if (cutoff <= 0.f || cutoff > 90.f) { spotFn = GX::SP_OFF; } @@ -278,7 +346,8 @@ void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn) { light->a2 = a2; } -void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBrightness, GX::DistAttnFn distFunc) { +void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBrightness, + GX::DistAttnFn distFunc) noexcept { if (refDistance < 0.f || refBrightness < 0.f || refBrightness >= 1.f) { distFunc = GX::DA_OFF; } @@ -313,19 +382,19 @@ void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBright light->k2 = k2; } -void GXInitLightPos(GX::LightObj* light, float x, float y, float z) { +void GXInitLightPos(GX::LightObj* light, float x, float y, float z) noexcept { light->px = x; light->py = y; light->pz = z; } -void GXInitLightDir(GX::LightObj* light, float nx, float ny, float nz) { +void GXInitLightDir(GX::LightObj* light, float nx, float ny, float nz) noexcept { light->nx = -nx; light->ny = -ny; light->nz = -nz; } -void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz) { +void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz) noexcept { float hx = -nx; float hy = -ny; float hz = (-nz + 1.0f); @@ -341,7 +410,7 @@ void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz) { light->nz = hz * mag; } -void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, float hx, float hy, float hz) { +void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, float hx, float hy, float hz) noexcept { light->px = (nx * GX::LARGE_NUMBER); light->py = (ny * GX::LARGE_NUMBER); light->pz = (nz * GX::LARGE_NUMBER); @@ -350,9 +419,9 @@ void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, floa light->nz = hz; } -void GXInitLightColor(GX::LightObj* light, GX::Color col) { light->color = col; } +void GXInitLightColor(GX::LightObj* light, GX::Color col) noexcept { light->color = col; } -void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) { +void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) noexcept { u32 idx = std::log2(id); aurora::gfx::Light realLight; realLight.pos.assign(light->px, light->py, light->pz); @@ -364,33 +433,152 @@ void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) { } /* TODO Figure out a way to implement this, requires GXSetArray */ -void GXLoadLightObjIndx(u32 index, GX::LightID) {} +void GXLoadLightObjIndx(u32 index, GX::LightID) noexcept {} -void GXGetLightAttnA(const GX::LightObj* light, float* a0, float* a1, float* a2) { +void GXGetLightAttnA(const GX::LightObj* light, float* a0, float* a1, float* a2) noexcept { *a0 = light->a0; *a1 = light->a1; *a2 = light->a2; } -void GXGetLightAttnK(const GX::LightObj* light, float* k0, float* k1, float* k2) { +void GXGetLightAttnK(const GX::LightObj* light, float* k0, float* k1, float* k2) noexcept { *k0 = light->k0; *k1 = light->k1; *k2 = light->k2; } -void GXGetLightPos(const GX::LightObj* light, float* x, float* y, float* z) { +void GXGetLightPos(const GX::LightObj* light, float* x, float* y, float* z) noexcept { *x = light->px; *z = light->py; *z = light->pz; } -void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz) { - *nx = light->nx; - *ny = light->ny; - *nz = light->nz; +void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz) noexcept { + *nx = -light->nx; + *ny = -light->ny; + *nz = -light->nz; } -void GXGetLightColor(const GX::LightObj* light, GX::Color* col) { *col = light->color; } +void GXGetLightColor(const GX::LightObj* light, GX::Color* col) noexcept { *col = light->color; } + +// Indirect Texturing +void GXSetTevIndirect(GX::TevStageID tevStage, GX::IndTexStageID indStage, GX::IndTexFormat fmt, + GX::IndTexBiasSel biasSel, GX::IndTexMtxID matrixSel, GX::IndTexWrap wrapS, GX::IndTexWrap wrapT, + GXBool addPrev, GXBool indLod, GX::IndTexAlphaSel alphaSel) noexcept { + auto& stage = g_gxState.tevStages[tevStage]; + stage.indTexStage = indStage; + stage.indTexFormat = fmt; + stage.indTexBiasSel = biasSel; + stage.indTexAlphaSel = alphaSel; + stage.indTexMtxId = matrixSel; + stage.indTexWrapS = wrapS; + stage.indTexWrapT = wrapT; + stage.indTexAddPrev = addPrev; + stage.indTexUseOrigLOD = indLod; +} +void GXSetIndTexOrder(GX::IndTexStageID indStage, GX::TexCoordID texCoord, GX::TexMapID texMap) noexcept { + auto& stage = g_gxState.indStages[indStage]; + stage.texCoordId = texCoord; + stage.texMapId = texMap; +} +void GXSetIndTexCoordScale(GX::IndTexStageID indStage, GX::IndTexScale scaleS, GX::IndTexScale scaleT) noexcept { + auto& stage = g_gxState.indStages[indStage]; + stage.scaleS = scaleS; + stage.scaleT = scaleT; +} +void GXSetIndTexMtx(GX::IndTexMtxID id, const void* mtx, s8 scaleExp) noexcept { + if (id < GX::ITM_0 || id > GX::ITM_2) { + Log.report(logvisor::Fatal, FMT_STRING("invalid ind tex mtx ID {}"), id); + } + g_gxState.indTexMtxs[id - 1] = {*static_cast*>(mtx), scaleExp}; +} + +void GXInitTexObj(GXTexObj* obj, void* data, u16 width, u16 height, GX::TextureFormat format, GXTexWrapMode wrapS, + GXTexWrapMode wrapT, GXBool mipmap) noexcept { + obj->data = data; + obj->width = width; + obj->height = height; + obj->fmt = format; + obj->wrapS = wrapS; + obj->wrapT = wrapT; + obj->hasMips = mipmap; + // TODO default values? + obj->minFilter = GX_LINEAR; + obj->magFilter = GX_LINEAR; + obj->minLod = 0.f; + obj->maxLod = 0.f; + obj->lodBias = 0.f; + obj->biasClamp = false; + obj->doEdgeLod = false; + obj->maxAniso = GX_ANISO_4; + obj->tlut = GX_TLUT0; + obj->dataInvalidated = true; +} +void GXInitTexObjResolved(GXTexObj* obj, u32 bindIdx, GX::TextureFormat format, GXTexWrapMode wrapS, + GXTexWrapMode wrapT) { + const auto& ref = aurora::gfx::g_resolvedTextures[bindIdx]; + obj->ref = ref; + obj->data = nullptr; + obj->dataSize = 0; + obj->width = ref->size.width; + obj->height = ref->size.height; + obj->fmt = format; + obj->wrapS = wrapS; + obj->wrapT = wrapT; + obj->hasMips = false; // TODO + // TODO default values? + obj->minFilter = GX_LINEAR; + obj->magFilter = GX_LINEAR; + obj->minLod = 0.f; + obj->maxLod = 0.f; + obj->lodBias = 0.f; + obj->biasClamp = false; + obj->doEdgeLod = false; + obj->maxAniso = GX_ANISO_4; + obj->tlut = GX_TLUT0; + obj->dataInvalidated = false; +} +void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter minFilt, GXTexFilter magFilt, float minLod, float maxLod, float lodBias, + GXBool biasClamp, GXBool doEdgeLod, GXAnisotropy maxAniso) noexcept { + obj->minFilter = minFilt; + obj->magFilter = magFilt; + obj->minLod = minLod; + obj->maxLod = maxLod; + obj->lodBias = lodBias; + obj->doEdgeLod = doEdgeLod; + obj->maxAniso = maxAniso; +} +void GXInitTexObjCI(GXTexObj* obj, void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS, + GXTexWrapMode wrapT, GXBool mipmap, u32 tlut) noexcept { + // TODO +} +void GXInitTexObjData(GXTexObj* obj, void* data) noexcept { + obj->data = data; + obj->dataInvalidated = true; +} +void GXInitTexObjWrapMode(GXTexObj* obj, GXTexWrapMode wrapS, GXTexWrapMode wrapT) noexcept { + obj->wrapS = wrapS; + obj->wrapT = wrapT; +} +void GXInitTexObjTlut(GXTexObj* obj, u32 tlut) noexcept { obj->tlut = static_cast(tlut); } +void GXLoadTexObj(GXTexObj* obj, GX::TexMapID id) noexcept { + if (!obj->ref) { + obj->ref = + aurora::gfx::new_dynamic_texture_2d(obj->width, obj->height, u32(obj->minLod) + 1, obj->fmt, "GXLoadTexObj"); + } + if (obj->dataInvalidated) { + aurora::gfx::write_texture(*obj->ref, {static_cast(obj->data), UINT32_MAX /* TODO */}); + obj->dataInvalidated = false; + } + g_gxState.textures[id] = {*obj}; +} + +void GXInitTlutObj(GXTlutObj* obj, void* data, GXTlutFmt format, u16 entries) noexcept { + // TODO +} +void GXLoadTlut(const GXTlutObj* obj, GXTlut idx) noexcept { + // TODO +} namespace aurora::gfx { static logvisor::Module Log("aurora::gfx::gx"); @@ -398,12 +586,6 @@ static logvisor::Module Log("aurora::gfx::gx"); // TODO remove this hack for build_shader extern std::mutex g_pipelineMutex; -// GX state -void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept { - gx::g_gxState.textures[static_cast(id)] = {tex, clamp, lod}; -} -void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast(id)].reset(); } - namespace gx { using gpu::g_device; using gpu::g_graphicsConfig; @@ -677,77 +859,22 @@ void populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive) n [](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; }); for (u8 i = 0; i < MaxTextures; ++i) { const auto& bind = g_gxState.textures[i]; - bool hasAlpha = false; - // TODO check resolved fmt - if (bind.handle) { - wgpu::TextureFormat format = bind.handle.ref->format; - switch (format) { - case wgpu::TextureFormat::R8Unorm: - case wgpu::TextureFormat::R8Snorm: - case wgpu::TextureFormat::R8Uint: - case wgpu::TextureFormat::R8Sint: - case wgpu::TextureFormat::R16Uint: - case wgpu::TextureFormat::R16Sint: - case wgpu::TextureFormat::R16Float: - case wgpu::TextureFormat::RG8Unorm: - case wgpu::TextureFormat::RG8Snorm: - case wgpu::TextureFormat::RG8Uint: - case wgpu::TextureFormat::RG8Sint: - case wgpu::TextureFormat::R32Float: - case wgpu::TextureFormat::R32Uint: - case wgpu::TextureFormat::R32Sint: - case wgpu::TextureFormat::RG16Uint: - case wgpu::TextureFormat::RG16Sint: - case wgpu::TextureFormat::RG16Float: - case wgpu::TextureFormat::RG11B10Ufloat: - case wgpu::TextureFormat::RGB9E5Ufloat: - case wgpu::TextureFormat::RG32Float: - case wgpu::TextureFormat::RG32Uint: - case wgpu::TextureFormat::RG32Sint: - case wgpu::TextureFormat::BC4RUnorm: - case wgpu::TextureFormat::BC4RSnorm: - case wgpu::TextureFormat::BC5RGUnorm: - case wgpu::TextureFormat::BC5RGSnorm: - case wgpu::TextureFormat::BC6HRGBUfloat: - case wgpu::TextureFormat::BC6HRGBFloat: - case wgpu::TextureFormat::ETC2RGB8Unorm: - case wgpu::TextureFormat::ETC2RGB8UnormSrgb: - hasAlpha = false; - break; - case wgpu::TextureFormat::RGBA8Unorm: - case wgpu::TextureFormat::RGBA8UnormSrgb: - case wgpu::TextureFormat::RGBA8Snorm: - case wgpu::TextureFormat::RGBA8Uint: - case wgpu::TextureFormat::RGBA8Sint: - case wgpu::TextureFormat::BGRA8Unorm: - case wgpu::TextureFormat::BGRA8UnormSrgb: - case wgpu::TextureFormat::RGB10A2Unorm: - case wgpu::TextureFormat::RGBA16Uint: - case wgpu::TextureFormat::RGBA16Sint: - case wgpu::TextureFormat::RGBA16Float: - case wgpu::TextureFormat::RGBA32Float: - case wgpu::TextureFormat::RGBA32Uint: - case wgpu::TextureFormat::RGBA32Sint: - case wgpu::TextureFormat::BC1RGBAUnorm: - case wgpu::TextureFormat::BC1RGBAUnormSrgb: - case wgpu::TextureFormat::BC2RGBAUnorm: - case wgpu::TextureFormat::BC2RGBAUnormSrgb: - case wgpu::TextureFormat::BC3RGBAUnorm: - case wgpu::TextureFormat::BC3RGBAUnormSrgb: - case wgpu::TextureFormat::BC7RGBAUnorm: - case wgpu::TextureFormat::BC7RGBAUnormSrgb: - case wgpu::TextureFormat::ETC2RGB8A1Unorm: - case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb: - case wgpu::TextureFormat::ETC2RGBA8Unorm: - case wgpu::TextureFormat::ETC2RGBA8UnormSrgb: - hasAlpha = true; - break; - default: - Log.report(logvisor::Fatal, FMT_STRING("Unknown texture format {}"), format); - unreachable(); - } + GX::TextureFormat copyFmt, bindFmt; + bool flipUV = false; + if (!bind.texObj.ref) { + config.shaderConfig.textureConfig[i] = {}; + continue; + } else if (bind.texObj.ref->isRenderTexture) { + // EFB copy + copyFmt = bind.texObj.ref->gxFormat; + bindFmt = bind.texObj.fmt; + flipUV = true; + } else { + // Loaded texture object, no conversion necessary + copyFmt = InvalidTextureFormat; + bindFmt = InvalidTextureFormat; } - config.shaderConfig.texHasAlpha[i] = hasAlpha; + config.shaderConfig.textureConfig[i] = {copyFmt, bindFmt, flipUV}; } config = { .shaderConfig = config.shaderConfig, @@ -870,7 +997,7 @@ Range build_uniform(const ShaderInfo& info) noexcept { Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), i); unreachable(); } - buf.append(&tex.lod, 4); + buf.append(&tex.texObj.lodBias, 4); } return range; } @@ -929,17 +1056,10 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi .binding = i, .sampler = sampler_ref(tex.get_descriptor()), }; - if (tex.handle) { - textureEntries[i] = { - .binding = i, - .textureView = tex.handle.ref->view, - }; - } else if (tex.resolvedBindIdx != UINT32_MAX) { - textureEntries[i] = { - .binding = i, - .textureView = g_resolvedTextures[tex.resolvedBindIdx].ref->view, - }; - } + textureEntries[i] = { + .binding = i, + .textureView = tex.texObj.ref->view, + }; i++; } return { @@ -1084,29 +1204,64 @@ void shutdown() noexcept { g_gxCachedShaders.clear(); } -wgpu::SamplerDescriptor TextureBind::get_descriptor() const noexcept { - wgpu::AddressMode mode; - switch (clampMode) { - case metaforce::EClampMode::Clamp: - mode = wgpu::AddressMode::ClampToEdge; - break; - case metaforce::EClampMode::Repeat: - mode = wgpu::AddressMode::Repeat; - break; - case metaforce::EClampMode::Mirror: - mode = wgpu::AddressMode::MirrorRepeat; - break; +static wgpu::AddressMode wgpu_address_mode(GXTexWrapMode mode) { + switch (mode) { + case GX_CLAMP: + return wgpu::AddressMode::ClampToEdge; + case GX_REPEAT: + return wgpu::AddressMode::Repeat; + case GX_MIRROR: + return wgpu::AddressMode::MirrorRepeat; + default: + Log.report(logvisor::Fatal, FMT_STRING("invalid wrap mode {}"), mode); + unreachable(); } +} +static std::pair wgpu_filter_mode(GXTexFilter filter) { + switch (filter) { + case GX_NEAR: + return {wgpu::FilterMode::Nearest, wgpu::FilterMode::Linear}; + case GX_LINEAR: + return {wgpu::FilterMode::Linear, wgpu::FilterMode::Linear}; + case GX_NEAR_MIP_NEAR: + return {wgpu::FilterMode::Nearest, wgpu::FilterMode::Nearest}; + case GX_LIN_MIP_NEAR: + return {wgpu::FilterMode::Linear, wgpu::FilterMode::Nearest}; + case GX_NEAR_MIP_LIN: + return {wgpu::FilterMode::Nearest, wgpu::FilterMode::Linear}; + case GX_LIN_MIP_LIN: + return {wgpu::FilterMode::Linear, wgpu::FilterMode::Linear}; + default: + Log.report(logvisor::Fatal, FMT_STRING("invalid filter mode {}"), filter); + unreachable(); + } +} +static u16 wgpu_aniso(GXAnisotropy aniso) { + // TODO use config values? + switch (aniso) { + case GX_ANISO_1: + return 1; + case GX_ANISO_2: + return 2; + case GX_ANISO_4: + return 4; + default: + Log.report(logvisor::Fatal, FMT_STRING("invalid aniso mode {}"), aniso); + unreachable(); + } +} +wgpu::SamplerDescriptor TextureBind::get_descriptor() const noexcept { + const auto [minFilter, mipFilter] = wgpu_filter_mode(texObj.minFilter); + const auto [magFilter, _] = wgpu_filter_mode(texObj.magFilter); return { .label = "Generated Sampler", - .addressModeU = mode, - .addressModeV = mode, - .addressModeW = mode, - // TODO logic from CTexture? - .magFilter = wgpu::FilterMode::Linear, - .minFilter = wgpu::FilterMode::Linear, - .mipmapFilter = wgpu::FilterMode::Linear, - .maxAnisotropy = g_graphicsConfig.textureAnistropy, + .addressModeU = wgpu_address_mode(texObj.wrapS), + .addressModeV = wgpu_address_mode(texObj.wrapT), + .addressModeW = wgpu::AddressMode::Repeat, + .magFilter = magFilter, + .minFilter = minFilter, + .mipmapFilter = mipFilter, + .maxAnisotropy = wgpu_aniso(texObj.maxAniso), }; } } // namespace gx diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index face98395..439ed1a68 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -3,19 +3,22 @@ #include "common.hpp" #include +#include #include namespace aurora::gfx::gx { 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 MaxTevRegs = 4; // TEVPREV, TEVREG0-2 constexpr u32 MaxKColors = GX::MAX_KCOLOR; constexpr u32 MaxTexMtx = 10; constexpr u32 MaxPTTexMtx = 20; constexpr u32 MaxTexCoord = GX::MAX_TEXCOORD; constexpr u32 MaxVtxAttr = GX::VA_MAX_ATTR; constexpr u32 MaxTevSwap = GX::MAX_TEVSWAP; +constexpr u32 MaxIndStages = GX::MAX_INDTEXSTAGE; +constexpr u32 MaxIndTexMtxs = 3; template struct TevPass { @@ -51,25 +54,37 @@ struct TevStage { GX::ChannelID channelId = GX::COLOR_NULL; GX::TevSwapSel tevSwapRas = GX::TEV_SWAP0; GX::TevSwapSel tevSwapTex = GX::TEV_SWAP0; + GX::IndTexStageID indTexStage = GX::INDTEXSTAGE0; + GX::IndTexFormat indTexFormat = GX::ITF_8; + GX::IndTexBiasSel indTexBiasSel = GX::ITB_NONE; + GX::IndTexAlphaSel indTexAlphaSel = GX::ITBA_OFF; + GX::IndTexMtxID indTexMtxId = GX::ITM_OFF; + GX::IndTexWrap indTexWrapS = GX::ITW_OFF; + GX::IndTexWrap indTexWrapT = GX::ITW_OFF; + bool indTexUseOrigLOD = false; + bool indTexAddPrev = false; + u8 _p1 = 0; + u8 _p2 = 0; bool operator==(const TevStage&) const = default; }; static_assert(std::has_unique_object_representations_v); +struct IndStage { + GX::TexCoordID texCoordId; + GX::TexMapID texMapId; + GX::IndTexScale scaleS; + GX::IndTexScale scaleT; +}; +static_assert(std::has_unique_object_representations_v); struct TextureBind { - aurora::gfx::TextureHandle handle; - metaforce::EClampMode clampMode = metaforce::EClampMode::Repeat; - float lod = 0.f; - u32 resolvedBindIdx = UINT32_MAX; + GXTexObj texObj; TextureBind() noexcept = default; - TextureBind(u32 resolvedBindIdx) noexcept : resolvedBindIdx(resolvedBindIdx) {} - TextureBind(aurora::gfx::TextureHandle handle, metaforce::EClampMode clampMode, float lod) noexcept - : handle(std::move(handle)), clampMode(clampMode), lod(lod) {} + TextureBind(GXTexObj obj) noexcept : texObj(std::move(obj)) {} void reset() noexcept { - handle.reset(); - resolvedBindIdx = UINT32_MAX; + texObj.ref.reset(); }; [[nodiscard]] wgpu::SamplerDescriptor get_descriptor() const noexcept; - operator bool() const noexcept { return handle || resolvedBindIdx != UINT32_MAX; } + operator bool() const noexcept { return texObj.ref.operator bool(); } }; // For shader generation struct ColorChannelConfig { @@ -132,6 +147,10 @@ struct AlphaCompare { operator bool() const { return *this != AlphaCompare{}; } }; static_assert(std::has_unique_object_representations_v); +struct IndTexMtxInfo { + aurora::Mat3x2 mtx; + s8 scaleExp; +}; struct GXState { zeus::CMatrix4f mv; @@ -164,6 +183,8 @@ struct GXState { TevSwap{GX::CH_GREEN, GX::CH_GREEN, GX::CH_GREEN, GX::CH_ALPHA}, TevSwap{GX::CH_BLUE, GX::CH_BLUE, GX::CH_BLUE, GX::CH_ALPHA}, }; + std::array indStages; + std::array indTexMtxs; bool depthCompare = true; bool depthUpdate = true; bool alphaUpdate = true; @@ -179,6 +200,15 @@ static inline Mat4x4 get_combined_matrix() noexcept { return g_gxState.pr void shutdown() noexcept; const TextureBind& get_texture(GX::TexMapID id) noexcept; +struct TextureConfig { + GX::TextureFormat copyFmt = InvalidTextureFormat; // GXSetTexCopyDst + GX::TextureFormat loadFmt = InvalidTextureFormat; // GXTexObj format + bool flipUV = false; // For render textures + u8 _p1 = 0; + u8 _p2 = 0; + u8 _p3 = 0; + bool operator==(const TextureConfig&) const = default; +}; struct ShaderConfig { GX::FogType fogType; std::array vtxAttrs; @@ -189,12 +219,12 @@ struct ShaderConfig { std::array tcgs; AlphaCompare alphaCompare; u32 indexedAttributeCount = 0; - std::array texHasAlpha; + std::array textureConfig; bool operator==(const ShaderConfig&) const = default; }; static_assert(std::has_unique_object_representations_v); -constexpr u32 GXPipelineConfigVersion = 2; +constexpr u32 GXPipelineConfigVersion = 3; struct PipelineConfig { u32 version = GXPipelineConfigVersion; ShaderConfig shaderConfig; @@ -222,10 +252,12 @@ struct GXBindGroups { }; // Output info from shader generation struct ShaderInfo { + std::bitset sampledTexCoords; std::bitset sampledTextures; std::bitset sampledKColors; std::bitset sampledColorChannels; std::bitset usesTevReg; + std::bitset writesTevReg; std::bitset usesTexMtx; std::bitset usesPTTexMtx; std::array texMtxTypes; diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index cde2dce08..071167afc 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -33,25 +33,46 @@ static inline std::string_view chan_comp(GX::TevColorChan chan) noexcept { static void color_arg_reg_info(GX::TevColorArg arg, const TevStage& stage, ShaderInfo& info) { switch (arg) { + case GX::CC_CPREV: + case GX::CC_APREV: + if (!info.writesTevReg.test(GX::TEVPREV)) { + info.usesTevReg.set(GX::TEVPREV); + } + break; case GX::CC_C0: case GX::CC_A0: - info.usesTevReg.set(0); + if (!info.writesTevReg.test(GX::TEVREG0)) { + info.usesTevReg.set(GX::TEVREG0); + } break; case GX::CC_C1: case GX::CC_A1: - info.usesTevReg.set(1); + if (!info.writesTevReg.test(GX::TEVREG1)) { + info.usesTevReg.set(GX::TEVREG1); + } break; case GX::CC_C2: case GX::CC_A2: - info.usesTevReg.set(2); + if (!info.writesTevReg.test(GX::TEVREG2)) { + info.usesTevReg.set(GX::TEVREG2); + } break; case GX::CC_TEXC: case GX::CC_TEXA: + if (stage.texCoordId == GX::TEXCOORD_NULL) { + Log.report(logvisor::Fatal, FMT_STRING("texCoord not bound")); + } + if (stage.texMapId == GX::TEXMAP_NULL) { + Log.report(logvisor::Fatal, FMT_STRING("texMap not bound")); + } + info.sampledTexCoords.set(stage.texCoordId); info.sampledTextures.set(stage.texMapId); break; case GX::CC_RASC: case GX::CC_RASA: - info.sampledColorChannels.set(stage.channelId - GX::COLOR0A0); + if (stage.channelId >= GX::COLOR0A0 && stage.channelId <= GX::COLOR1A1) { + info.sampledColorChannels.set(stage.channelId - GX::COLOR0A0); + } break; case GX::CC_KONST: switch (stage.kcSel) { @@ -92,25 +113,60 @@ static void color_arg_reg_info(GX::TevColorArg arg, const TevStage& stage, Shade } } +static bool formatHasAlpha(GX::TextureFormat format) { + switch (format) { + case GX::TF_I4: + case GX::TF_I8: + case GX::TF_RGB565: + case GX::TF_C4: + case GX::TF_C8: + case GX::TF_C14X2: + case GX::TF_Z8: + case GX::TF_Z16: + case GX::TF_Z24X8: + case GX::CTF_R4: + case GX::CTF_R8: + case GX::CTF_G8: + case GX::CTF_B8: + case GX::CTF_RG8: + case GX::CTF_GB8: + case GX::CTF_Z4: + case GX::CTF_Z8M: + case GX::CTF_Z8L: + case GX::CTF_Z16L: + return false; + case GX::TF_IA4: + case GX::TF_IA8: + case GX::TF_RGB5A3: + case GX::TF_RGBA8: + case GX::TF_CMPR: + case GX::CTF_RA4: + case GX::CTF_RA8: + case GX::CTF_YUVA8: + case GX::CTF_A8: + return true; + } +} + static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const ShaderConfig& config, const TevStage& stage) { switch (arg) { case GX::CC_CPREV: return "prev.rgb"; case GX::CC_APREV: - return "prev.a"; + return "vec3(prev.a)"; case GX::CC_C0: return "tevreg0.rgb"; case GX::CC_A0: - return "tevreg0.a"; + return "vec3(tevreg0.a)"; case GX::CC_C1: return "tevreg1.rgb"; case GX::CC_A1: - return "tevreg1.a"; + return "vec3(tevreg1.a)"; case GX::CC_C2: return "tevreg2.rgb"; case GX::CC_A2: - return "tevreg2.a"; + return "vec3(tevreg2.a)"; case GX::CC_TEXC: { if (stage.texMapId == GX::TEXMAP_NULL) { Log.report(logvisor::Fatal, FMT_STRING("unmapped texture for stage {}"), stageIdx); @@ -121,7 +177,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha } const auto swap = config.tevSwapTable[stage.tevSwapTex]; // TODO check for CH_ALPHA + config.texHasAlpha - return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stage.texMapId, chan_comp(swap.red), chan_comp(swap.green), + return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stageIdx, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue)); } case GX::CC_TEXA: { @@ -133,15 +189,14 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha unreachable(); } const auto swap = config.tevSwapTable[stage.tevSwapTex]; - if (swap.alpha == GX::CH_ALPHA && !config.texHasAlpha[stage.texMapId]) { - return "1.0"; - } - return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha)); + return fmt::format(FMT_STRING("vec3(sampled{}.{})"), stageIdx, chan_comp(swap.alpha)); } case GX::CC_RASC: { if (stage.channelId == GX::COLOR_NULL) { Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx); unreachable(); + } else if (stage.channelId == GX::COLOR_ZERO) { + return "vec3(0.0)"; } else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) { Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx); unreachable(); @@ -155,36 +210,38 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha if (stage.channelId == GX::COLOR_NULL) { Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx); unreachable(); + } else if (stage.channelId == GX::COLOR_ZERO) { + return "vec3(0.0)"; } else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) { Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx); unreachable(); } u32 idx = stage.channelId - GX::COLOR0A0; const auto swap = config.tevSwapTable[stage.tevSwapRas]; - return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha)); + return fmt::format(FMT_STRING("vec3(rast{}.{})"), idx, chan_comp(swap.alpha)); } case GX::CC_ONE: - return "1.0"; + return "vec3(1.0)"; case GX::CC_HALF: - return "0.5"; + return "vec3(0.5)"; case GX::CC_KONST: { switch (stage.kcSel) { case GX::TEV_KCSEL_8_8: - return "1.0"; + return "vec3(1.0)"; case GX::TEV_KCSEL_7_8: - return "(7.0/8.0)"; + return "vec3(7.0/8.0)"; case GX::TEV_KCSEL_6_8: - return "(6.0/8.0)"; + return "vec3(6.0/8.0)"; case GX::TEV_KCSEL_5_8: - return "(5.0/8.0)"; + return "vec3(5.0/8.0)"; case GX::TEV_KCSEL_4_8: - return "(4.0/8.0)"; + return "vec3(4.0/8.0)"; case GX::TEV_KCSEL_3_8: - return "(3.0/8.0)"; + return "vec3(3.0/8.0)"; case GX::TEV_KCSEL_2_8: - return "(2.0/8.0)"; + return "vec3(2.0/8.0)"; case GX::TEV_KCSEL_1_8: - return "(1.0/8.0)"; + return "vec3(1.0/8.0)"; case GX::TEV_KCSEL_K0: return "ubuf.kcolor0.rgb"; case GX::TEV_KCSEL_K1: @@ -194,44 +251,44 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha case GX::TEV_KCSEL_K3: return "ubuf.kcolor3.rgb"; case GX::TEV_KCSEL_K0_R: - return "ubuf.kcolor0.r"; + return "vec3(ubuf.kcolor0.r)"; case GX::TEV_KCSEL_K1_R: - return "ubuf.kcolor1.r"; + return "vec3(ubuf.kcolor1.r)"; case GX::TEV_KCSEL_K2_R: - return "ubuf.kcolor2.r"; + return "vec3(ubuf.kcolor2.r)"; case GX::TEV_KCSEL_K3_R: - return "ubuf.kcolor3.r"; + return "vec3(ubuf.kcolor3.r)"; case GX::TEV_KCSEL_K0_G: - return "ubuf.kcolor0.g"; + return "vec3(ubuf.kcolor0.g)"; case GX::TEV_KCSEL_K1_G: - return "ubuf.kcolor1.g"; + return "vec3(ubuf.kcolor1.g)"; case GX::TEV_KCSEL_K2_G: - return "ubuf.kcolor2.g"; + return "vec3(ubuf.kcolor2.g)"; case GX::TEV_KCSEL_K3_G: - return "ubuf.kcolor3.g"; + return "vec3(ubuf.kcolor3.g)"; case GX::TEV_KCSEL_K0_B: - return "ubuf.kcolor0.b"; + return "vec3(ubuf.kcolor0.b)"; case GX::TEV_KCSEL_K1_B: - return "ubuf.kcolor1.b"; + return "vec3(ubuf.kcolor1.b)"; case GX::TEV_KCSEL_K2_B: - return "ubuf.kcolor2.b"; + return "vec3(ubuf.kcolor2.b)"; case GX::TEV_KCSEL_K3_B: - return "ubuf.kcolor3.b"; + return "vec3(ubuf.kcolor3.b)"; case GX::TEV_KCSEL_K0_A: - return "ubuf.kcolor0.a"; + return "vec3(ubuf.kcolor0.a)"; case GX::TEV_KCSEL_K1_A: - return "ubuf.kcolor1.a"; + return "vec3(ubuf.kcolor1.a)"; case GX::TEV_KCSEL_K2_A: - return "ubuf.kcolor2.a"; + return "vec3(ubuf.kcolor2.a)"; case GX::TEV_KCSEL_K3_A: - return "ubuf.kcolor3.a"; + return "vec3(ubuf.kcolor3.a)"; default: Log.report(logvisor::Fatal, FMT_STRING("invalid kcSel {}"), stage.kcSel); unreachable(); } } case GX::CC_ZERO: - return "0.0"; + return "vec3(0.0)"; default: Log.report(logvisor::Fatal, FMT_STRING("invalid color arg {}"), arg); unreachable(); @@ -240,20 +297,40 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha static void alpha_arg_reg_info(GX::TevAlphaArg arg, const TevStage& stage, ShaderInfo& info) { switch (arg) { + case GX::CA_APREV: + if (!info.writesTevReg.test(GX::TEVPREV)) { + info.usesTevReg.set(GX::TEVPREV); + } + break; case GX::CA_A0: - info.usesTevReg.set(0); + if (!info.writesTevReg.test(GX::TEVREG0)) { + info.usesTevReg.set(GX::TEVREG0); + } break; case GX::CA_A1: - info.usesTevReg.set(1); + if (!info.writesTevReg.test(GX::TEVREG1)) { + info.usesTevReg.set(GX::TEVREG1); + } break; case GX::CA_A2: - info.usesTevReg.set(2); + if (!info.writesTevReg.test(GX::TEVREG2)) { + info.usesTevReg.set(GX::TEVREG2); + } break; case GX::CA_TEXA: + if (stage.texCoordId == GX::TEXCOORD_NULL) { + Log.report(logvisor::Fatal, FMT_STRING("texCoord not bound")); + } + if (stage.texMapId == GX::TEXMAP_NULL) { + Log.report(logvisor::Fatal, FMT_STRING("texMap not bound")); + } + info.sampledTexCoords.set(stage.texCoordId); info.sampledTextures.set(stage.texMapId); break; case GX::CA_RASA: - info.sampledColorChannels.set(stage.channelId - GX::COLOR0A0); + if (stage.channelId >= GX::COLOR0A0 && stage.channelId <= GX::COLOR1A1) { + info.sampledColorChannels.set(stage.channelId - GX::COLOR0A0); + } break; case GX::CA_KONST: switch (stage.kaSel) { @@ -310,15 +387,14 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha unreachable(); } const auto swap = config.tevSwapTable[stage.tevSwapTex]; - if (swap.alpha == GX::CH_ALPHA && !config.texHasAlpha[stage.texMapId]) { - return "1.0"; - } - return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha)); + return fmt::format(FMT_STRING("sampled{}.{}"), stageIdx, chan_comp(swap.alpha)); } case GX::CA_RASA: { if (stage.channelId == GX::COLOR_NULL) { Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx); unreachable(); + } else if (stage.channelId == GX::COLOR_ZERO) { + return "0.0"; } else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) { Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx); unreachable(); @@ -393,9 +469,9 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha static std::string_view tev_op(GX::TevOp op) { switch (op) { case GX::TEV_ADD: - return "+"; + return ""sv; case GX::TEV_SUB: - return "-"; + return "-"sv; default: Log.report(logvisor::Fatal, FMT_STRING("TODO {}"), op); unreachable(); @@ -405,11 +481,11 @@ static std::string_view tev_op(GX::TevOp op) { static std::string_view tev_bias(GX::TevBias bias) { switch (bias) { case GX::TB_ZERO: - return " + 0.0"; + return ""sv; case GX::TB_ADDHALF: - return " + 0.5"; + return " + 0.5"sv; case GX::TB_SUBHALF: - return " - 0.5"; + return " - 0.5"sv; default: Log.report(logvisor::Fatal, FMT_STRING("invalid bias {}"), bias); unreachable(); @@ -420,7 +496,7 @@ static std::string alpha_compare(GX::Compare comp, u8 ref, bool& valid) { const float fref = ref / 255.f; switch (comp) { case GX::NEVER: - return "false"; + return "false"s; case GX::LESS: return fmt::format(FMT_STRING("(prev.a < {}f)"), fref); case GX::LEQUAL: @@ -435,7 +511,7 @@ static std::string alpha_compare(GX::Compare comp, u8 ref, bool& valid) { return fmt::format(FMT_STRING("(prev.a > {}f)"), fref); case GX::ALWAYS: valid = false; - return "true"; + return "true"s; default: Log.report(logvisor::Fatal, FMT_STRING("invalid compare {}"), comp); unreachable(); @@ -445,13 +521,13 @@ static std::string alpha_compare(GX::Compare comp, u8 ref, bool& valid) { static std::string_view tev_scale(GX::TevScale scale) { switch (scale) { case GX::CS_SCALE_1: - return " * 1.0"; + return ""sv; case GX::CS_SCALE_2: - return " * 2.0"; + return " * 2.0"sv; case GX::CS_SCALE_4: - return " * 4.0"; + return " * 4.0"sv; case GX::CS_DIVIDE_2: - return " / 2.0"; + return " / 2.0"sv; default: Log.report(logvisor::Fatal, FMT_STRING("invalid scale {}"), scale); unreachable(); @@ -463,16 +539,16 @@ static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) { if (type == GX::NONE) { if (attr == GX::VA_NRM) { // Default normal - return "vec3(1.0, 0.0, 0.0)"; + return "vec3(1.0, 0.0, 0.0)"s; } Log.report(logvisor::Fatal, FMT_STRING("unmapped attr {}"), attr); unreachable(); } if (attr == GX::VA_POS) { - return "in_pos"; + return "in_pos"s; } if (attr == GX::VA_NRM) { - return "in_nrm"; + return "in_nrm"s; } if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) { const auto idx = attr - GX::VA_CLR0; @@ -486,6 +562,36 @@ static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) { unreachable(); } +static inline std::string texture_conversion(const TextureConfig& tex, u32 stageIdx) { + std::string out; + switch (tex.copyFmt) { + default: + break; + case GX::TF_RGB565: + // Set alpha channel to 1.0 + out += fmt::format(FMT_STRING("\n sampled{0}.a = 1.0;"), stageIdx); + break; + case GX::TF_I4: + // Perform intensity conversion + out += fmt::format( + FMT_STRING("\n {{" + "\n var intensity = dot(sampled{0}.rgb, vec3(0.257, 0.504, 0.098)) + 16.0 / 255.0;" + "\n sampled{0} = vec4(intensity);" + "\n }}"), + stageIdx); + break; + } + return out; +} + +constexpr std::array TevColorArgNames{ + "CPREV"sv, "APREV"sv, "C0"sv, "A0"sv, "C1"sv, "A1"sv, "C2"sv, "A2"sv, + "TEXC"sv, "TEXA"sv, "RASC"sv, "RASA"sv, "ONE"sv, "HALF"sv, "KONST"sv, "ZERO"sv, +}; +constexpr std::array TevAlphaArgNames{ + "APREV"sv, "A0"sv, "A1"sv, "A2"sv, "TEXA"sv, "RASA"sv, "KONST"sv, "ZERO"sv, +}; + constexpr std::array VtxAttributeNames{ "pn_mtx", "tex0_mtx", "tex1_mtx", "tex2_mtx", "tex3_mtx", "tex4_mtx", "tex5_mtx", "tex6_mtx", "tex7_mtx", "pos", "nrm", "clr0", "clr1", "tex0_uv", @@ -506,42 +612,23 @@ ShaderInfo build_shader_info(const ShaderConfig& config) noexcept { for (int i = 0; i < config.tevStageCount; ++i) { const auto& stage = config.tevStages[i]; // Color pass - switch (stage.colorOp.outReg) { - case GX::TEVREG0: - info.usesTevReg.set(0); - break; - case GX::TEVREG1: - info.usesTevReg.set(1); - break; - case GX::TEVREG2: - info.usesTevReg.set(2); - break; - default: - break; - } color_arg_reg_info(stage.colorPass.a, stage, info); color_arg_reg_info(stage.colorPass.b, stage, info); color_arg_reg_info(stage.colorPass.c, stage, info); color_arg_reg_info(stage.colorPass.d, stage, info); + info.writesTevReg.set(stage.colorOp.outReg); // Alpha pass - switch (stage.alphaOp.outReg) { - case GX::TEVREG0: - info.usesTevReg.set(0); - break; - case GX::TEVREG1: - info.usesTevReg.set(1); - break; - case GX::TEVREG2: - info.usesTevReg.set(2); - break; - default: - break; - } alpha_arg_reg_info(stage.alphaPass.a, stage, info); alpha_arg_reg_info(stage.alphaPass.b, stage, info); alpha_arg_reg_info(stage.alphaPass.c, stage, info); alpha_arg_reg_info(stage.alphaPass.d, stage, info); + if (!info.writesTevReg.test(stage.alphaOp.outReg)) { + // If we're writing alpha to a register that's not been + // written to in the shader, load from uniform buffer + info.usesTevReg.set(stage.alphaOp.outReg); + info.writesTevReg.set(stage.alphaOp.outReg); + } } info.uniformSize += info.usesTevReg.count() * 16; for (int i = 0; i < info.sampledColorChannels.size(); ++i) { @@ -611,14 +698,14 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in for (int i = 0; i < config.tevStageCount; ++i) { const auto& stage = config.tevStages[i]; Log.report(logvisor::Info, FMT_STRING(" tevStages[{}]:"), i); - 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_a: {}"), TevColorArgNames[stage.colorPass.a]); + Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), TevColorArgNames[stage.colorPass.b]); + Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), TevColorArgNames[stage.colorPass.c]); + Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), TevColorArgNames[stage.colorPass.d]); + Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), TevAlphaArgNames[stage.alphaPass.a]); + Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), TevAlphaArgNames[stage.alphaPass.b]); + Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), TevAlphaArgNames[stage.alphaPass.c]); + Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), TevAlphaArgNames[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); @@ -652,12 +739,6 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in config.alphaCompare.ref1); Log.report(logvisor::Info, FMT_STRING(" indexedAttributeCount: {}"), config.indexedAttributeCount); Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType); - std::string hasAlphaArr; - for (int i = 0; i < config.texHasAlpha.size(); ++i) { - if (i != 0) hasAlphaArr += ", "; - hasAlphaArr += config.texHasAlpha[i] ? "Y" : "N"; - } - Log.report(logvisor::Info, FMT_STRING(" texHasAlpha: [{}]"), hasAlphaArr); } } @@ -785,12 +866,12 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in Log.report(logvisor::Fatal, FMT_STRING("invalid 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.a, idx, config, stage), color_arg_reg(stage.colorPass.b, idx, config, stage), - color_arg_reg(stage.colorPass.c, idx, config, stage), color_arg_reg(stage.colorPass.d, idx, config, stage), - tev_op(stage.colorOp.op), tev_bias(stage.colorOp.bias), tev_scale(stage.colorOp.scale)); + FMT_STRING("(({4}mix({0}, {1}, {2}) + {3}){5}){6}"), color_arg_reg(stage.colorPass.a, idx, config, stage), + color_arg_reg(stage.colorPass.b, idx, config, stage), color_arg_reg(stage.colorPass.c, idx, config, stage), + color_arg_reg(stage.colorPass.d, idx, config, stage), 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); + op = fmt::format(FMT_STRING("clamp({}, vec3(0.0), vec3(1.0))"), op); } fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4({1}, {0}.a);"), outReg, op); } @@ -813,20 +894,28 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in Log.report(logvisor::Fatal, FMT_STRING("invalid 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.a, idx, config, stage), alpha_arg_reg(stage.alphaPass.b, idx, config, stage), - alpha_arg_reg(stage.alphaPass.c, idx, config, stage), alpha_arg_reg(stage.alphaPass.d, idx, config, stage), - tev_op(stage.alphaOp.op), tev_bias(stage.alphaOp.bias), tev_scale(stage.alphaOp.scale)); + FMT_STRING("(({4}mix({0}, {1}, {2}) + {3}){5}){6}"), alpha_arg_reg(stage.alphaPass.a, idx, config, stage), + alpha_arg_reg(stage.alphaPass.b, idx, config, stage), alpha_arg_reg(stage.alphaPass.c, idx, config, stage), + alpha_arg_reg(stage.alphaPass.d, idx, config, stage), 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); } } - for (int i = 0; i < info.usesTevReg.size(); ++i) { + if (info.usesTevReg.test(0)) { + uniBufAttrs += "\n tevprev: vec4,"; + fragmentFnPre += "\n var prev = ubuf.tevprev;"; + } else { + fragmentFnPre += "\n var prev: vec4;"; + } + for (int i = 1 /* Skip TEVPREV */; i < info.usesTevReg.size(); ++i) { if (info.usesTevReg.test(i)) { - uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4,"), i); - fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i); + uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4,"), i - 1); + fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i - 1); + } else if (info.writesTevReg.test(i)) { + fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0}: vec4;"), i - 1); } } bool addedLightStruct = false; @@ -917,9 +1006,8 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4,"), i); } } - size_t texBindIdx = 0; - for (int i = 0; i < info.sampledTextures.size(); ++i) { - if (!info.sampledTextures.test(i)) { + for (int i = 0; i < info.sampledTexCoords.size(); ++i) { + if (!info.sampledTexCoords.test(i)) { continue; } const auto& tcg = config.tcgs[i]; @@ -932,7 +1020,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in } else if (tcg.src == GX::TG_NRM) { vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4(in_nrm, 1.0);"), i); } else { - Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {}"), tcg.src); + Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {} for "), tcg.src); unreachable(); } // TODO this all assumes MTX3x4 currently @@ -953,15 +1041,27 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in i, postMtxIdx); } vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i); - std::string uvIn; - // FIXME terrible hack to flip Y for render textures - if (config.texHasAlpha[i]) { - uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), i); - } else { - uvIn = fmt::format(FMT_STRING("vec2(in.tex{0}_uv.x, -in.tex{0}_uv.y)"), i); + } + for (int i = 0; i < config.tevStages.size(); ++i) { + const auto& stage = config.tevStages[i]; + if (stage.texMapId == GX::TEXMAP_NULL || + stage.texCoordId == GX::TEXCOORD_NULL + // TODO should check this per-stage probably + || !info.sampledTextures.test(stage.texMapId)) { + continue; } - fragmentFnPre += fmt::format( - FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, {1}, ubuf.tex{0}_lod);"), i, uvIn); + std::string uvIn; + const auto& texConfig = config.textureConfig[stage.texMapId]; + // TODO + // if (texConfig.flipUV) { + // uvIn = fmt::format(FMT_STRING("vec2(in.tex{0}_uv.x, -in.tex{0}_uv.y)"), stage.texCoordId); + // } else { + uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), stage.texCoordId); + // } + fragmentFnPre += + fmt::format(FMT_STRING("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_lod);"), + i, stage.texMapId, uvIn); + fragmentFnPre += texture_conversion(texConfig, i); } for (int i = 0; i < info.usesTexMtx.size(); ++i) { if (info.usesTexMtx.test(i)) { @@ -1025,6 +1125,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in } fragmentFn += "\n prev = vec4(mix(prev.rgb, ubuf.fog.color.rgb, clamp(fogZ, 0.0, 1.0)), prev.a);"; } + size_t texBindIdx = 0; for (int i = 0; i < info.sampledTextures.size(); ++i) { if (!info.sampledTextures.test(i)) { continue; @@ -1091,8 +1192,7 @@ fn vs_main({vtxInAttrs} }} @stage(fragment) -fn fs_main(in: VertexOutput) -> @location(0) vec4 {{ - var prev: vec4;{fragmentFnPre}{fragmentFn} +fn fs_main(in: VertexOutput) -> @location(0) vec4 {{{fragmentFnPre}{fragmentFn} return prev; }} )"""), diff --git a/aurora/lib/gfx/model/shader.cpp b/aurora/lib/gfx/model/shader.cpp index 9a190f9aa..3e300b520 100644 --- a/aurora/lib/gfx/model/shader.cpp +++ b/aurora/lib/gfx/model/shader.cpp @@ -40,6 +40,14 @@ static inline void read_vert(ByteBuffer& out, const u8* data) noexcept { static absl::flat_hash_map> sCachedDisplayLists; void queue_surface(const u8* dlStart, u32 dlSize) noexcept { + // TODO CElementGen needs fixing + for (const auto& type : gx::g_gxState.vtxDesc) { + if (type == GX::DIRECT) { + Log.report(logvisor::Warning, FMT_STRING("Direct attributes in surface config!")); + return; + } + } + const auto hash = xxh3_hash_s(dlStart, dlSize, 0); Range vertRange, idxRange; u32 numIndices = 0; @@ -55,7 +63,11 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept { u8 inVtxSize = 0; u8 outVtxSize = 0; for (const auto& type : gx::g_gxState.vtxDesc) { - if (type == GX::NONE || type == GX::DIRECT) { + if (type == GX::DIRECT) { + Log.report(logvisor::Fatal, FMT_STRING("Direct attributes in surface config!")); + unreachable(); + } + if (type == GX::NONE) { continue; } if (type == GX::INDEX8) { diff --git a/aurora/lib/gfx/movie_player/shader.cpp b/aurora/lib/gfx/movie_player/shader.cpp index 2cf6c8a0e..9d6d2843b 100644 --- a/aurora/lib/gfx/movie_player/shader.cpp +++ b/aurora/lib/gfx/movie_player/shader.cpp @@ -207,15 +207,15 @@ DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const Te const std::array entries{ wgpu::BindGroupEntry{ .binding = 0, - .textureView = tex_y.ref->view, + .textureView = tex_y->view, }, wgpu::BindGroupEntry{ .binding = 1, - .textureView = tex_u.ref->view, + .textureView = tex_u->view, }, wgpu::BindGroupEntry{ .binding = 2, - .textureView = tex_v.ref->view, + .textureView = tex_v->view, }, }; const auto textureBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{ diff --git a/aurora/lib/gfx/texture.cpp b/aurora/lib/gfx/texture.cpp index 65d701e42..d4a98f3e6 100644 --- a/aurora/lib/gfx/texture.cpp +++ b/aurora/lib/gfx/texture.cpp @@ -38,14 +38,14 @@ static wgpu::Extent3D physical_size(wgpu::Extent3D size, TextureFormatInfo info) return {width, height, size.depthOrArrayLayers}; } -TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mips, metaforce::ETexelFormat format, +TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mips, GX::TextureFormat format, ArrayRef data, zstring_view label) noexcept { auto handle = new_dynamic_texture_2d(width, height, mips, format, label); - const TextureRef& ref = *handle.ref; + const auto& ref = *handle; ByteBuffer buffer; - if (ref.gameFormat != metaforce::ETexelFormat::Invalid) { - buffer = convert_texture(ref.gameFormat, ref.size.width, ref.size.height, ref.mipCount, data); + if (ref.gxFormat != InvalidTextureFormat) { + buffer = convert_texture(ref.gxFormat, ref.size.width, ref.size.height, ref.mipCount, data); if (!buffer.empty()) { data = {buffer.data(), buffer.size()}; } @@ -87,7 +87,7 @@ TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mi return handle; } -TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, metaforce::ETexelFormat format, +TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, GX::TextureFormat format, zstring_view label) noexcept { const auto wgpuFormat = to_wgpu(format); const auto size = wgpu::Extent3D{ @@ -110,10 +110,10 @@ TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t m }; auto texture = g_device.CreateTexture(&textureDescriptor); auto textureView = texture.CreateView(&textureViewDescriptor); - return {std::make_shared(std::move(texture), std::move(textureView), size, wgpuFormat, mips, format)}; + return std::make_shared(std::move(texture), std::move(textureView), size, wgpuFormat, mips, format, false); } -TextureHandle new_render_texture(uint32_t width, uint32_t height, zstring_view label) noexcept { +TextureHandle new_render_texture(uint32_t width, uint32_t height, GX::TextureFormat fmt, zstring_view label) noexcept { const auto wgpuFormat = gpu::g_graphicsConfig.colorFormat; const auto size = wgpu::Extent3D{ .width = width, @@ -135,17 +135,14 @@ TextureHandle new_render_texture(uint32_t width, uint32_t height, zstring_view l }; auto texture = g_device.CreateTexture(&textureDescriptor); auto textureView = texture.CreateView(&textureViewDescriptor); - return {std::make_shared(std::move(texture), std::move(textureView), size, wgpuFormat, 1, - metaforce::ETexelFormat::Invalid)}; + return std::make_shared(std::move(texture), std::move(textureView), size, wgpuFormat, 1, fmt, true); } // TODO accept mip/layer parameters -void write_texture(const TextureHandle& handle, ArrayRef data) noexcept { - const TextureRef& ref = *handle.ref; - +void write_texture(const TextureRef& ref, ArrayRef data) noexcept { ByteBuffer buffer; - if (ref.gameFormat != metaforce::ETexelFormat::Invalid) { - buffer = convert_texture(ref.gameFormat, ref.size.width, ref.size.height, ref.mipCount, data); + if (ref.gxFormat != InvalidTextureFormat) { + buffer = convert_texture(ref.gxFormat, ref.size.width, ref.size.height, ref.mipCount, data); if (!buffer.empty()) { data = {buffer.data(), buffer.size()}; } diff --git a/aurora/lib/gfx/texture_convert.cpp b/aurora/lib/gfx/texture_convert.cpp index 8273a4ff8..ad9d4fbbc 100644 --- a/aurora/lib/gfx/texture_convert.cpp +++ b/aurora/lib/gfx/texture_convert.cpp @@ -491,41 +491,38 @@ ByteBuffer BuildDXT1FromGCN(uint32_t width, uint32_t height, uint32_t mips, Arra return buf; } -ByteBuffer convert_texture(metaforce::ETexelFormat format, uint32_t width, uint32_t height, uint32_t mips, +ByteBuffer convert_texture(GX::TextureFormat format, uint32_t width, uint32_t height, uint32_t mips, ArrayRef data) { switch (format) { - case metaforce::ETexelFormat::RGBA8PC: - case metaforce::ETexelFormat::R8PC: - return {}; - case metaforce::ETexelFormat::Invalid: - Log.report(logvisor::Fatal, FMT_STRING("convert_texture: invalid format supplied")); + default: + Log.report(logvisor::Fatal, FMT_STRING("convert_texture: unknown format supplied {}"), format); unreachable(); - case metaforce::ETexelFormat::I4: + case GX::TF_I4: return BuildI4FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::I8: + case GX::TF_I8: return BuildI8FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::IA4: + case GX::TF_IA4: return BuildIA4FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::IA8: + case GX::TF_IA8: return BuildIA8FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::C4: + case GX::TF_C4: Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C4 unimplemented")); unreachable(); // return BuildC4FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::C8: + case GX::TF_C8: Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C8 unimplemented")); unreachable(); // return BuildC8FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::C14X2: + case GX::TF_C14X2: Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C14X2 unimplemented")); unreachable(); - case metaforce::ETexelFormat::RGB565: + case GX::TF_RGB565: return BuildRGB565FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::RGB5A3: + case GX::TF_RGB5A3: return BuildRGB5A3FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::RGBA8: + case GX::TF_RGBA8: return BuildRGBA8FromGCN(width, height, mips, data); - case metaforce::ETexelFormat::CMPR: + case GX::TF_CMPR: if (gpu::g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC)) { return BuildDXT1FromGCN(width, height, mips, data); } else { diff --git a/aurora/lib/gfx/texture_convert.hpp b/aurora/lib/gfx/texture_convert.hpp index 1341e7534..64dc78549 100644 --- a/aurora/lib/gfx/texture_convert.hpp +++ b/aurora/lib/gfx/texture_convert.hpp @@ -5,12 +5,12 @@ #include "../gpu.hpp" namespace aurora::gfx { -static wgpu::TextureFormat to_wgpu(metaforce::ETexelFormat format) { +static wgpu::TextureFormat to_wgpu(GX::TextureFormat format) { switch (format) { - case metaforce::ETexelFormat::C8: - case metaforce::ETexelFormat::R8PC: + case GX::TF_C8: + case GX::TF_I8: return wgpu::TextureFormat::R8Unorm; - case metaforce::ETexelFormat::CMPR: + case GX::TF_CMPR: if (gpu::g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC)) { return wgpu::TextureFormat::BC1RGBAUnorm; } @@ -20,6 +20,6 @@ static wgpu::TextureFormat to_wgpu(metaforce::ETexelFormat format) { } } -ByteBuffer convert_texture(metaforce::ETexelFormat format, uint32_t width, uint32_t height, uint32_t mips, +ByteBuffer convert_texture(GX::TextureFormat format, uint32_t width, uint32_t height, uint32_t mips, ArrayRef data); } // namespace aurora::gfx