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
This commit is contained in:
Luke Street 2022-05-13 19:40:19 -04:00
parent 22256228fb
commit 22dfd3b3f7
45 changed files with 1511 additions and 868 deletions

View File

@ -95,6 +95,7 @@ std::mutex CDvdFile::m_WaitMutex;
std::atomic_bool CDvdFile::m_WorkerRun = {false}; std::atomic_bool CDvdFile::m_WorkerRun = {false};
std::vector<std::shared_ptr<IDvdRequest>> CDvdFile::m_RequestQueue; std::vector<std::shared_ptr<IDvdRequest>> CDvdFile::m_RequestQueue;
std::string CDvdFile::m_rootDirectory; std::string CDvdFile::m_rootDirectory;
std::unique_ptr<u8[]> CDvdFile::m_dolBuf;
CDvdFile::CDvdFile(std::string_view path) : x18_path(path) { CDvdFile::CDvdFile(std::string_view path) : x18_path(path) {
auto* node = ResolvePath(path); auto* node = ResolvePath(path);
@ -211,6 +212,7 @@ bool CDvdFile::Initialize(const std::string_view& path) {
if (!m_DvdRoot) { if (!m_DvdRoot) {
return false; return false;
} }
m_dolBuf = m_DvdRoot->getDataPartition()->getDOLBuf();
m_WorkerRun.store(true); m_WorkerRun.store(true);
m_WorkerThread = std::thread(WorkerProc); m_WorkerThread = std::thread(WorkerProc);
return true; return true;

View File

@ -40,6 +40,7 @@ class CDvdFile {
static std::atomic_bool m_WorkerRun; static std::atomic_bool m_WorkerRun;
static std::vector<std::shared_ptr<IDvdRequest>> m_RequestQueue; static std::vector<std::shared_ptr<IDvdRequest>> m_RequestQueue;
static std::string m_rootDirectory; static std::string m_rootDirectory;
static std::unique_ptr<u8[]> m_dolBuf;
static void WorkerProc(); static void WorkerProc();
std::string x18_path; std::string x18_path;
@ -55,6 +56,7 @@ public:
static SDiscInfo DiscInfo(); static SDiscInfo DiscInfo();
static void SetRootDirectory(const std::string_view& rootDir); static void SetRootDirectory(const std::string_view& rootDir);
static void Shutdown(); static void Shutdown();
static u8* GetDolBuf() { return m_dolBuf.get(); }
CDvdFile(std::string_view path); CDvdFile(std::string_view path);
operator bool() const { return m_reader.operator bool(); } operator bool() const { return m_reader.operator bool(); }

View File

@ -244,7 +244,7 @@ void CMemoryCardSys::CCardFileInfo::WriteBannerData(COutputStream& out) const {
out.Put(texels, 3072); out.Put(texels, 3072);
} }
if (format == ETexelFormat::C8) { 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); out.Put(texels, 1024);
} }
if (format == ETexelFormat::C8) { if (format == ETexelFormat::C8) {
palette = icon.x8_tex->GetPalette()->GetEntries(); palette = icon.x8_tex->GetPalette()->GetPaletteData();
} }
} }
if (palette != nullptr) { if (palette != nullptr) {

View File

@ -55,7 +55,7 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur
materialDataCur += 8; materialDataCur += 8;
for (u32 i = 0; i < texCount; ++i) { for (u32 i = 0; i < texCount; ++i) {
u32 texIdx = SBig(*reinterpret_cast<const u32*>(materialDataCur)); u32 texIdx = SBig(*reinterpret_cast<const u32*>(materialDataCur));
sRenderingModel->GetTexture(texIdx)->Load(static_cast<GX::TexMapID>(i), EClampMode::Repeat); model.GetTexture(texIdx)->Load(static_cast<GX::TexMapID>(i), EClampMode::Repeat);
materialDataCur += 4; materialDataCur += 4;
} }
} }
@ -225,16 +225,24 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur
} }
void CCubeMaterial::SetCurrentBlack() { void CCubeMaterial::SetCurrentBlack() {
auto flags = GetFlags(); const auto flags = GetFlags();
auto vatFlags = GetVatFlags(); const auto vatFlags = GetVatFlags();
if (flags.IsSet(CCubeMaterialFlagBits::fDepthSorting) || flags.IsSet(CCubeMaterialFlagBits::fAlphaTest)) { if (flags.IsSet(CCubeMaterialFlagBits::fDepthSorting) || flags.IsSet(CCubeMaterialFlagBits::fAlphaTest)) {
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ZERO, GX::BL_ONE, GX::LO_CLEAR); CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ZERO, GX::BL_ONE, GX::LO_CLEAR);
} else { } else {
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR); CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR);
} }
// set vtx desc flags // CGX::SetVtxDescv_Compressed(vatFlags);
// TODO // 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) { void CCubeMaterial::SetupBlendMode(u32 blendFactors, const CModelFlags& flags, bool alphaTest) {

View File

@ -25,35 +25,6 @@ enum class CCubeMaterialFlagBits : u32 {
}; };
using CCubeMaterialFlags = Flags<CCubeMaterialFlagBits>; using CCubeMaterialFlags = Flags<CCubeMaterialFlagBits>;
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 { class CCubeMaterial {
const u8* x0_data; const u8* x0_data;
@ -72,7 +43,7 @@ public:
[[nodiscard]] CCubeMaterialFlags GetFlags() const { [[nodiscard]] CCubeMaterialFlags GetFlags() const {
return CCubeMaterialFlags(SBig(*reinterpret_cast<const u32*>(x0_data))); return CCubeMaterialFlags(SBig(*reinterpret_cast<const u32*>(x0_data)));
} }
[[nodiscard]] CCubeMaterialVatFlags GetVatFlags() const { [[nodiscard]] u32 GetVatFlags() const {
return SBig(*reinterpret_cast<const u32*>(x0_data + 8 + (GetTextureCount() * 4))); return SBig(*reinterpret_cast<const u32*>(x0_data + 8 + (GetTextureCount() * 4)));
} }
[[nodiscard]] u32 GetUsedTextureSlots() const { return static_cast<u32>(GetFlags()) >> 16; } [[nodiscard]] u32 GetUsedTextureSlots() const { return static_cast<u32>(GetFlags()) >> 16; }

View File

@ -12,6 +12,9 @@
#include "Runtime/Graphics/CModel.hpp" #include "Runtime/Graphics/CModel.hpp"
#include "Runtime/World/CGameArea.hpp" #include "Runtime/World/CGameArea.hpp"
#include "Runtime/Particle/CParticleGen.hpp" #include "Runtime/Particle/CParticleGen.hpp"
#include "Runtime/Particle/CDecal.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/CDvdFile.hpp"
namespace metaforce { namespace metaforce {
static logvisor::Module Log("CCubeRenderer"); static logvisor::Module Log("CCubeRenderer");
@ -208,11 +211,35 @@ void CCubeRenderer::GenerateFogVolumeRampTex() {
} }
void CCubeRenderer::GenerateSphereRampTex() { 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<s32>(y) >> 2) + static_cast<u32>(y < 0 && (y & 3) != 0)) * 4 + (static_cast<s32>(x) >> 3);
const u32 vy = ((iVar3 * 4 | (y * 0x40000000 + iVar3) >> 0x1e) - iVar3) * 8 + (x & 7);
const zeus::CVector2f vec{
static_cast<float>(vx) / 15.5f - 1.f,
static_cast<float>(vy) / 15.5f - 1.f,
};
const auto mag = vec.magnitude();
*row = static_cast<u8>(255.f * std::clamp(-(mag * mag - 1.f), 0.f, 1.f));
++row;
}
offset += 32;
}
x220_sphereRamp.UnLock();
} }
void CCubeRenderer::LoadThermoPalette() { void CCubeRenderer::LoadThermoPalette() {
// TODO x288_thermoPalette.Lock();
TToken<CTexture> 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, 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) { void CCubeRenderer::RenderBucketItems(const CAreaListItem* item) {
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CCubeRenderer::RenderBucketItems areaIdx={}"), item->x18_areaIdx).c_str(), SCOPED_GRAPHICS_DEBUG_GROUP(
zeus::skBlue); fmt::format(FMT_STRING("CCubeRenderer::RenderBucketItems areaIdx={}"), item->x18_areaIdx).c_str(), zeus::skBlue);
CCubeModel* lastModel = nullptr; CCubeModel* lastModel = nullptr;
EDrawableType lastDrawableType = EDrawableType::Invalid; 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, void CCubeRenderer::DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) { TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {
model.UpdateLastFrame(); 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, 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) { 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::SetThermalColdScale(float scale) { x2f8_thermColdScale = zeus::clamp(0.f, scale, 1.f); }
void CCubeRenderer::DoThermalBlendCold() { 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<int32_t>(left),
.y = static_cast<int32_t>(top),
.width = static_cast<int32_t>(width),
.height = static_cast<int32_t>(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<float> 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<float>(width), 0.f, static_cast<float>(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<float>(height));
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(static_cast<float>(width), 0.5f, static_cast<float>(height));
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(static_cast<float>(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() { 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<float>(width), 0.f, static_cast<float>(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<float>(height));
GXTexCoord2f32(0.f, 1.f);
GXPosition3f32(static_cast<float>(width), 0.5f, static_cast<float>(height));
GXTexCoord2f32(1.f, 1.f);
GXPosition3f32(static_cast<float>(width), 0.5f, 0.f);
GXTexCoord2f32(1.f, 0.f);
CGX::End();
// move prologue here
} }
u32 CCubeRenderer::GetStaticWorldDataSize() { u32 CCubeRenderer::GetStaticWorldDataSize() {
@ -941,4 +1151,37 @@ void CCubeRenderer::SetupRendererStates(bool depthWrite) {
CCubeMaterial::ResetCachedMaterials(); CCubeMaterial::ResetCachedMaterials();
GXSetTevColor(GX::TEVREG1, x2fc_tevReg1Color); 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 } // namespace metaforce

View File

@ -69,7 +69,7 @@ private:
CTexture x150_reflectionTex{ETexelFormat::IA8, 32, 32, 1, "Reflection Texture"}; CTexture x150_reflectionTex{ETexelFormat::IA8, 32, 32, 1, "Reflection Texture"};
CTexture x1b8_fogVolumeRamp{ETexelFormat::I8, 256, 256, 1, "Fog Volume Ramp Texture"}; CTexture x1b8_fogVolumeRamp{ETexelFormat::I8, 256, 256, 1, "Fog Volume Ramp Texture"};
CTexture x220_sphereRamp{ETexelFormat::I8, 32, 32, 1, "Sphere 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}; CRandom16 x2a8_thermalRand{20};
std::list<CFogVolumeListItem> x2ac_fogVolumes; std::list<CFogVolumeListItem> x2ac_fogVolumes;
std::list<std::pair<zeus::CVector3f, float>> x2c4_spaceWarps; std::list<std::pair<zeus::CVector3f, float>> x2c4_spaceWarps;
@ -92,6 +92,8 @@ private:
bool x318_30_inAreaDraw : 1 = false; bool x318_30_inAreaDraw : 1 = false;
bool x318_31_persistRGBA6 : 1 = false; bool x318_31_persistRGBA6 : 1 = false;
CTexture m_thermalRandomStatic{ETexelFormat::IA4, 640, 448, 1, "Thermal Random Static"};
void GenerateReflectionTex(); void GenerateReflectionTex();
void GenerateFogVolumeRampTex(); void GenerateFogVolumeRampTex();
void GenerateSphereRampTex(); void GenerateSphereRampTex();

View File

@ -300,8 +300,7 @@ static inline void SetTevDirect(GX::TevStageID stageId) noexcept {
auto& state = sGXState.x68_tevStates[stageId].x10_indFlags; auto& state = sGXState.x68_tevStates[stageId].x10_indFlags;
if (state != 0) { if (state != 0) {
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, static inline void SetTevIndirect(GX::TevStageID stageId, GX::IndTexStageID indStage, GX::IndTexFormat fmt,
GX::IndTexMtxID mtxSel, GX::IndTexWrap wrapS, GX::IndTexWrap wrapT, GXBool addPrev, GXBool indLod, GX::IndTexBiasSel biasSel, GX::IndTexMtxID mtxSel, GX::IndTexWrap wrapS,
GX::IndTexAlphaSel alphaSel) noexcept; 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, static inline void SetTevIndWarp(GX::TevStageID stageId, GX::IndTexStageID indStage, GXBool signedOffset, GXBool replaceMode,
GX::IndTexMtxID mtxSel) noexcept; GX::IndTexMtxID mtxSel) noexcept {
// TODO
GXSetTevIndWarp(stageId, indStage, signedOffset, replaceMode, mtxSel);
}
static inline void SetTevKAlphaSel(GX::TevStageID stageId, GX::TevKAlphaSel sel) noexcept { static inline void SetTevKAlphaSel(GX::TevStageID stageId, GX::TevKAlphaSel sel) noexcept {
auto& state = sGXState.x68_tevStates[stageId].x19_kAlphaSel; auto& state = sGXState.x68_tevStates[stageId].x19_kAlphaSel;

View File

@ -309,14 +309,19 @@ public:
static const std::array<zeus::CMatrix3f, 6> skCubeBasisMats; static const std::array<zeus::CMatrix3f, 6> skCubeBasisMats;
static void ResolveSpareTexture(const SClipScreenRect& rect, int bindIdx = 0, bool clearDepth = false) { static void ResolveSpareTexture(const SClipScreenRect& rect, int bindIdx, GX::TextureFormat format,
aurora::gfx::resolve_color({rect.x4_left, rect.x8_top, rect.xc_width, rect.x10_height}, bindIdx, clearDepth); 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) { static void LoadDolphinSpareTexture(int bindIdx, GX::TextureFormat format, GX::TexMapID id) {
aurora::gfx::bind_color(bindIdx, 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) { 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; static void SetTevStates(EStreamFlags flags) noexcept;

View File

@ -6,7 +6,7 @@ u32 CGraphicsPalette::sCurrentFrameCount = 0;
CGraphicsPalette::CGraphicsPalette(EPaletteFormat fmt, int count) CGraphicsPalette::CGraphicsPalette(EPaletteFormat fmt, int count)
: x0_fmt(fmt), x8_entryCount(count), xc_entries(new u8[count * 2]) { : 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<GXTlutFmt>(x0_fmt), x8_entryCount);
} }
CGraphicsPalette::CGraphicsPalette(CInputStream& in) : x0_fmt(EPaletteFormat(in.ReadLong())) { 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; x8_entryCount = w * h;
xc_entries.reset(new u8[x8_entryCount * 2]); xc_entries.reset(new u8[x8_entryCount * 2]);
in.Get(xc_entries.get(), x8_entryCount * 2); in.Get(xc_entries.get(), x8_entryCount * 2);
//GXInitTlutObj(&x10_tlutObj, xc_entries.get(), x8_entryCount); GXInitTlutObj(&x10_tlutObj, xc_entries.get(), static_cast<GXTlutFmt>(x0_fmt), x8_entryCount);
//DCFlushRange(xc_entries.get(), x8_entryCount * 2); // DCFlushRange(xc_entries.get(), x8_entryCount * 2);
} }
void CGraphicsPalette::Load() { void CGraphicsPalette::Load() {
//GXLoadTlut(x10_tlutObj, 0); GXLoadTlut(&x10_tlutObj, GX_TLUT0);
x4_frameLoaded = sCurrentFrameCount; x4_frameLoaded = sCurrentFrameCount;
} }
} // namespace metaforce
void CGraphicsPalette::Lock() { x1c_locked = true; }
void CGraphicsPalette::UnLock() {
// DCStoreRange(xc_lut, x8_numEntries << 1);
GXInitTlutObj(&x10_tlutObj, xc_entries.get(), static_cast<GXTlutFmt>(x0_fmt), x8_entryCount);
// DCFlushRange(xc_lut, x8_numEntries << 1);
x1c_locked = false;
}
} // namespace metaforce

View File

@ -1,16 +1,17 @@
#pragma once #pragma once
#include "RetroTypes.hpp" #include "RetroTypes.hpp"
#include "GX.hpp"
#include <memory> #include <memory>
namespace metaforce { namespace metaforce {
class CInputStream; class CInputStream;
enum class EPaletteFormat { enum class EPaletteFormat : std::underlying_type_t<GXTlutFmt> {
IA8 = 0x0, IA8 = GX_TL_IA8,
RGB565 = 0x1, RGB565 = GX_TL_RGB565,
RGB5A3 = 0x2, RGB5A3 = GX_TL_RGB5A3,
}; };
class CGraphicsPalette { class CGraphicsPalette {
@ -20,7 +21,7 @@ class CGraphicsPalette {
u32 x4_frameLoaded{}; u32 x4_frameLoaded{};
u32 x8_entryCount; u32 x8_entryCount;
std::unique_ptr<u8[]> xc_entries; std::unique_ptr<u8[]> xc_entries;
/* GXTlutObj x10_; */ GXTlutObj x10_tlutObj;
bool x1c_locked = false; bool x1c_locked = false;
public: public:
@ -28,8 +29,11 @@ public:
explicit CGraphicsPalette(CInputStream& in); explicit CGraphicsPalette(CInputStream& in);
void Load(); 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; } static void SetCurrentFrameCount(u32 frameCount) { sCurrentFrameCount = frameCount; }
}; };

View File

@ -192,28 +192,22 @@ CMoviePlayer::CMoviePlayer(const char* path, float preLoadSeconds, bool loop, bo
CTHPTextureSet& set = x80_textures.emplace_back(); CTHPTextureSet& set = x80_textures.emplace_back();
if (deinterlace) { if (deinterlace) {
/* metaforce addition: this way interlaced THPs don't look horrible */ /* metaforce addition: this way interlaced THPs don't look horrible */
set.Y[0] = set.Y[0] = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1, GX::TF_I8,
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));
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,
set.Y[1] = fmt::format(FMT_STRING("Movie {} Texture Set {} Y[1]"), path, i));
aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width, x6c_videoInfo.height / 2, 1, ETexelFormat::R8PC, 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 {} Y[1]"), path, i)); fmt::format(FMT_STRING("Movie {} Texture Set {} U"), path, i));
set.U = set.V = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, GX::TF_I8,
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));
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));
} else { } else {
/* normal progressive presentation */ /* 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)); fmt::format(FMT_STRING("Movie {} Texture Set {} Y"), path, i));
set.U = set.U = aurora::gfx::new_dynamic_texture_2d(x6c_videoInfo.width / 2, x6c_videoInfo.height / 2, 1, GX::TF_I8,
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));
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,
set.V = fmt::format(FMT_STRING("Movie {} Texture Set {} V"), path, i));
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));
} }
if (xf4_25_hasAudio) if (xf4_25_hasAudio)
set.audioBuf.reset(new s16[x28_thpHead.maxAudioSamples * 2]); 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), memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2),
x6c_videoInfo.width); 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) { 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), memcpy(buffer.get() + x6c_videoInfo.width * y, m_yuvBuf.get() + x6c_videoInfo.width * (y * 2 + 1),
x6c_videoInfo.width); x6c_videoInfo.width);
} }
aurora::gfx::write_texture(tex.Y[1], {buffer.get(), planeSizeHalf}); aurora::gfx::write_texture(*tex.Y[1], {buffer.get(), planeSizeHalf});
} else { } else {
/* Direct planar load */ /* 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.U, {m_yuvBuf.get() + planeSize, planeSizeQuarter});
aurora::gfx::write_texture(tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter}); aurora::gfx::write_texture(*tex.V, {m_yuvBuf.get() + planeSize + planeSizeQuarter, planeSizeQuarter});
break; break;
} }

View File

@ -5,74 +5,6 @@
#include <zeus/Math.hpp> #include <zeus/Math.hpp>
#include <magic_enum.hpp> #include <magic_enum.hpp>
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 { namespace metaforce {
static std::array<CTexture*, GX::MAX_TEXMAP> sLoadedTextures{}; static std::array<CTexture*, GX::MAX_TEXMAP> sLoadedTextures{};
@ -85,7 +17,7 @@ CTexture::CTexture(ETexelFormat fmt, u16 w, u16 h, s32 mips, std::string_view la
, x64_frameAllocated(sCurrentFrameCount) , x64_frameAllocated(sCurrentFrameCount)
, m_label(fmt::format(FMT_STRING("{} ({})"), label, magic_enum::enum_name(fmt))) { , m_label(fmt::format(FMT_STRING("{} ({})"), label, magic_enum::enum_name(fmt))) {
InitBitmapBuffers(fmt, w, h, mips); InitBitmapBuffers(fmt, w, h, mips);
InitTextureObjs(false); InitTextureObjs();
} }
CTexture::CTexture(CInputStream& in, std::string_view label, EAutoMipmap automip, EBlackKey blackKey) 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() { u8* CTexture::Lock() {
@ -141,11 +73,14 @@ void CTexture::UnLock() {
xa_24_locked = false; xa_24_locked = false;
CountMemory(); CountMemory();
// DCFlushRange(x44_aramToken.GetMRAMSafe(), ROUND_UP_32(xc_memoryAllocated)); // 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) { void CTexture::Load(GX::TexMapID id, EClampMode clamp) {
if (sLoadedTextures[id] != this || xa_29_canLoadObj) { 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(); CountMemory();
if (HasPalette()) { if (HasPalette()) {
x10_graphicsPalette->Load(); x10_graphicsPalette->Load();
@ -154,12 +89,16 @@ void CTexture::Load(GX::TexMapID id, EClampMode clamp) {
xa_29_canLoadObj = false; xa_29_canLoadObj = false;
if (x40_clampMode != clamp) { if (x40_clampMode != clamp) {
x40_clampMode = !xa_26_isPowerOfTwo ? EClampMode::Clamp : clamp; x40_clampMode = !xa_26_isPowerOfTwo ? EClampMode::Clamp : clamp;
// GXInitTexObjWrapMode(x20_texObj, static_cast<u32>(x40_clampMode), static_cast<u32>(x40_clampMode)); GXInitTexObjWrapMode(&x20_texObj, static_cast<GXTexWrapMode>(x40_clampMode),
static_cast<GXTexWrapMode>(x40_clampMode));
} }
// GXInitObjectData(x20_texObj, image_ptr); // Aurora change: track when texture data needs to be invalidated
// GXLoadObj(x20_texObj, id); if (m_needsTexObjDataLoad) {
aurora::gfx::bind_texture(id, clamp, x20_texObj, 0.f); GXInitTexObjData(&x20_texObj, data);
m_needsTexObjDataLoad = false;
}
GXLoadTexObj(&x20_texObj, id);
sLoadedTextures[id] = this; sLoadedTextures[id] = this;
x64_frameAllocated = sCurrentFrameCount; x64_frameAllocated = sCurrentFrameCount;
} }
@ -179,15 +118,15 @@ void CTexture::LoadMipLevel(float lod, GX::TexMapID id, EClampMode clamp) {
// } // }
// } // }
// TODO
// GXTexObj texObj; // GXTexObj texObj;
// GXInitTexObj(&texObj, image_ptr + offset, width, height, x18_gxFormat); // 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); // GXInitTexObjLOD(&texObj, GX_LINEAR, GX_LINEAR, 0.f, 1.f, 0.f, false, false, GX_ANISO_1);
if (HasPalette()) { // if (HasPalette()) {
x10_graphicsPalette->Load(); // x10_graphicsPalette->Load();
xa_25_canLoadPalette = false; // xa_25_canLoadPalette = false;
} // }
// GXLoadTexObj(&texObj, mapId); // GXLoadTexObj(&x20_texObj, id);
aurora::gfx::bind_texture(id, clamp, x20_texObj, lod);
x64_frameAllocated = sCurrentFrameCount; x64_frameAllocated = sCurrentFrameCount;
sLoadedTextures[id] = nullptr; sLoadedTextures[id] = nullptr;
} }
@ -227,13 +166,13 @@ void CTexture::InitBitmapBuffers(ETexelFormat fmt, u16 width, u16 height, s32 mi
x18_gxFormat = GX::TF_IA8; x18_gxFormat = GX::TF_IA8;
break; break;
case ETexelFormat::C4: case ETexelFormat::C4:
x1c_gxCIFormat = GX::TF_C4; x1c_gxCIFormat = GX_TF_C4;
break; break;
case ETexelFormat::C8: case ETexelFormat::C8:
x1c_gxCIFormat = GX::TF_C8; x1c_gxCIFormat = GX_TF_C8;
break; break;
case ETexelFormat::C14X2: case ETexelFormat::C14X2:
x1c_gxCIFormat = GX::TF_C14X2; x1c_gxCIFormat = GX_TF_C14X2;
break; break;
case ETexelFormat::RGB565: case ETexelFormat::RGB565:
x18_gxFormat = GX::TF_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) u32 format = (x0_fmt == ETexelFormat::C4 || x0_fmt == ETexelFormat::C8 || x0_fmt == ETexelFormat::C14X2)
? x1c_gxCIFormat ? u32(x1c_gxCIFormat)
: x18_gxFormat; : u32(x18_gxFormat);
xc_memoryAllocated = GXGetTexBufferSize(width, height, format, mips > 1, mips > 1 ? 11 : 0); xc_memoryAllocated = GXGetTexBufferSize(width, height, format, mips > 1, mips > 1 ? 11 : 0);
x44_aramToken_x4_buff = std::make_unique<u8[]>(xc_memoryAllocated); x44_aramToken_x4_buff = std::make_unique<u8[]>(xc_memoryAllocated);
/*x44_aramToken.PostConstruct(buf, xc_memoryAllocated, 1);*/ /*x44_aramToken.PostConstruct(buf, xc_memoryAllocated, 1);*/
CountMemory(); CountMemory();
} }
void CTexture::InitTextureObjs(bool write) { void CTexture::InitTextureObjs() {
xa_26_isPowerOfTwo = zeus::floorPowerOfTwo(x4_w) == x4_w && zeus::floorPowerOfTwo(x6_h) == x6_h; xa_26_isPowerOfTwo = zeus::floorPowerOfTwo(x4_w) == x4_w && zeus::floorPowerOfTwo(x6_h) == x6_h;
if (!xa_26_isPowerOfTwo) { if (!xa_26_isPowerOfTwo) {
@ -270,19 +208,14 @@ void CTexture::InitTextureObjs(bool write) {
CountMemory(); CountMemory();
if (IsCITexture()) { if (IsCITexture()) {
// GXInitTexObjCI(x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x1c_gxCIFormat, u32(x40_clampMode), GXInitTexObjCI(&x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x1c_gxCIFormat,
// u32(x40_clampMode), x8_mips > 1, 0); static_cast<GXTexWrapMode>(x40_clampMode), static_cast<GXTexWrapMode>(x40_clampMode), x8_mips > 1,
// TODO 0);
} else { } else {
// GXInitTexObj(x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x1c_gxCIFormat, u32(x40_clampMode), GXInitTexObj(&x20_texObj, x44_aramToken_x4_buff.get(), x4_w, x6_h, x18_gxFormat,
// u32(x40_clampMode), x8_mips > 1); static_cast<GXTexWrapMode>(x40_clampMode), static_cast<GXTexWrapMode>(x40_clampMode), x8_mips > 1);
// GXInitTexObjLOD(x20_texObj, x8_mips > 1 ? GX_LIN_MIP_LIN : GX_LINEAR, 0.f, static_cast<float>(x8_mips) - 1.f, GXInitTexObjLOD(&x20_texObj, x8_mips > 1 ? GX_LIN_MIP_LIN : GX_LINEAR, GX_LINEAR, 0.f,
// 0.f, static_cast<float>(x8_mips) - 1.f, 0.f, false, false, x8_mips > 1 ? GX_ANISO_4 : GX_ANISO_1);
// 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});
}
} }
xa_29_canLoadObj = true; xa_29_canLoadObj = true;
} }
@ -336,7 +269,7 @@ u32 CTexture::sCurrentFrameCount = 0;
u32 CTexture::sTotalAllocatedMemory = 0; u32 CTexture::sTotalAllocatedMemory = 0;
void CTexture::InvalidateTexMap(GX::TexMapID id) { void CTexture::InvalidateTexMap(GX::TexMapID id) {
aurora::gfx::unbind_texture(id); // TODO: can we unbind in GX?
sLoadedTextures[id] = nullptr; sLoadedTextures[id] = nullptr;
} }

View File

@ -6,8 +6,15 @@
#include "Runtime/Graphics/GX.hpp" #include "Runtime/Graphics/GX.hpp"
#include "Runtime/IObj.hpp" #include "Runtime/IObj.hpp"
#include "Runtime/Streams/CInputStream.hpp" #include "Runtime/Streams/CInputStream.hpp"
#include "GX.hpp"
namespace metaforce { namespace metaforce {
enum class EClampMode : std::underlying_type_t<GXTexWrapMode> {
Clamp = GX_CLAMP,
Repeat = GX_REPEAT,
Mirror = GX_MIRROR,
};
class CTexture { class CTexture {
class CDumpedBitmapDataReloader { class CDumpedBitmapDataReloader {
int x0_; int x0_;
@ -56,18 +63,19 @@ private:
u32 xc_memoryAllocated = 0; u32 xc_memoryAllocated = 0;
std::unique_ptr<CGraphicsPalette> x10_graphicsPalette; std::unique_ptr<CGraphicsPalette> x10_graphicsPalette;
std::unique_ptr<CDumpedBitmapDataReloader> x14_bitmapReloader; std::unique_ptr<CDumpedBitmapDataReloader> x14_bitmapReloader;
u32 x18_gxFormat = GX::TF_RGB565; GX::TextureFormat x18_gxFormat = GX::TF_RGB565;
u32 x1c_gxCIFormat = GX::TF_C8; GXCITexFmt x1c_gxCIFormat = GX_TF_C8;
aurora::gfx::TextureHandle x20_texObj; // was GXTexObj GXTexObj x20_texObj;
EClampMode x40_clampMode = EClampMode::Repeat; EClampMode x40_clampMode = EClampMode::Repeat;
std::unique_ptr<u8[]> x44_aramToken_x4_buff; // was CARAMToken std::unique_ptr<u8[]> x44_aramToken_x4_buff; // was CARAMToken
u32 x64_frameAllocated{}; u32 x64_frameAllocated{};
// Metaforce additions // Metaforce additions
std::string m_label; std::string m_label;
bool m_needsTexObjDataLoad = true;
void InitBitmapBuffers(ETexelFormat fmt, u16 width, u16 height, s32 mips); void InitBitmapBuffers(ETexelFormat fmt, u16 width, u16 height, s32 mips);
void InitTextureObjs(bool write); // write param is added void InitTextureObjs();
void CountMemory(); void CountMemory();
void UncountMemory(); void UncountMemory();
void MangleMipmap(u32 mip); void MangleMipmap(u32 mip);

View File

@ -8,6 +8,7 @@
#include <bit> #include <bit>
#include <bitset> #include <bitset>
#include <memory>
#include <zeus/CColor.hpp> #include <zeus/CColor.hpp>
#include <zeus/CMatrix4f.hpp> #include <zeus/CMatrix4f.hpp>
@ -740,6 +741,96 @@ enum DistAttnFn {
using GXColor = zeus::CColor; using GXColor = zeus::CColor;
using GXBool = bool; 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<aurora::gfx::TextureRef> 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 GXSetNumChans(u8 num) noexcept;
void GXSetNumIndStages(u8 num) noexcept; void GXSetNumIndStages(u8 num) noexcept;
void GXSetNumTevStages(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 GXSetVtxDescv(GX::VtxDescList* list) noexcept;
void GXClearVtxDesc() noexcept; void GXClearVtxDesc() noexcept;
void GXSetArray(GX::Attr attr, const void* data, u8 stride) 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 GXSetFog(GX::FogType type, float startZ, float endZ, float nearZ, float farZ, const GXColor& color) noexcept;
void GXSetFogColor(const GXColor& color) noexcept; void GXSetFogColor(const GXColor& color) noexcept;
void GXCallDisplayList(const void* data, u32 nbytes) 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 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; void GXSetScissor(u32 left, u32 top, u32 width, u32 height) noexcept;
// Unneeded, all attributes are expected to be full floats // 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 // Streaming
void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept; void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept;
void GXMatrixIndex1u8(u8 idx) 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, void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColorChan green, GX::TevColorChan blue,
GX::TevColorChan alpha) noexcept; GX::TevColorChan alpha) noexcept;
void GXSetTevSwapMode(GX::TevStageID stage, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) 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<float> */, 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 // 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;
void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2); void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2) noexcept;
void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2); void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2) noexcept;
void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn); void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn) noexcept;
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;
static inline void GXInitLightShininess(GX::LightObj* light, float shininess) { 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); 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); void GXInitLightPos(GX::LightObj* light, float x, float y, float z) noexcept;
static inline void GXInitLightPosv(GX::LightObj* light, float vec[3]) { GXInitLightPos(light, vec[0], vec[1], vec[2]); } static inline void GXInitLightPosv(GX::LightObj* light, float vec[3]) noexcept {
void GXInitLightDir(GX::LightObj* light, float nx, float ny, float nz); GXInitLightPos(light, vec[0], vec[1], vec[2]);
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 GXInitLightDir(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); static inline void GXInitLightDirv(GX::LightObj* light, float vec[3]) noexcept {
static inline void GXInitLightSpecularDirHAv(GX::LightObj* light, float vecn[3], float vech[3]) { 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]); GXInitSpecularDirHA(light, vecn[0], vecn[1], vecn[2], vech[0], vech[1], vech[2]);
} }
void GXInitLightColor(GX::LightObj* light, GX::Color col); void GXInitLightColor(GX::LightObj* light, GX::Color col) noexcept;
void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id); void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) noexcept;
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;
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;
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;
static inline void GXGetLightPosv(const GX::LightObj* light, float* vec[3]) { static inline void GXGetLightPosv(const GX::LightObj* light, float* vec[3]) noexcept {
GXGetLightPos(light, vec[0], vec[1], vec[2]); GXGetLightPos(light, vec[0], vec[1], vec[2]);
} }
void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz); void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz) noexcept;
static inline void GXGetLightDirv(const GX::LightObj* light, float* vec[3]) { static inline void GXGetLightDirv(const GX::LightObj* light, float* vec[3]) noexcept {
GXGetLightDir(light, vec[0], vec[1], vec[2]); 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;

View File

@ -48,7 +48,7 @@ void CCameraBlurFilter::draw(float amount, bool clearDepth) {
SCOPED_GRAPHICS_DEBUG_GROUP("CCameraBlurFilter::draw", zeus::skMagenta); SCOPED_GRAPHICS_DEBUG_GROUP("CCameraBlurFilter::draw", zeus::skMagenta);
const SClipScreenRect clipRect(CGraphics::g_Viewport); 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 aspect = float(CGraphics::g_CroppedViewport.xc_width) / float(CGraphics::g_CroppedViewport.x10_height);
const float xFac = float(CGraphics::GetCroppedViewportWidth()) / float(CGraphics::GetViewportWidth()); const float xFac = float(CGraphics::GetCroppedViewportWidth()) / float(CGraphics::GetViewportWidth());

View File

@ -128,7 +128,7 @@ void CPhazonSuitFilter::drawBlurPasses(float radius, const CTexture* indTex) {
// CGraphics::SetShaderDataBinding(m_dataBindBlurX); // CGraphics::SetShaderDataBinding(m_dataBindBlurX);
// CGraphics::DrawArray(0, 4); // CGraphics::DrawArray(0, 4);
CGraphics::ResolveSpareTexture(rect, 2); // CGraphics::ResolveSpareTexture(rect, 2);
/* Y Pass */ /* Y Pass */
blurDir = zeus::CVector4f{0.f, radius * blurScale, 0.f, 0.f}; 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::SetShaderDataBinding(m_dataBindBlurY);
// CGraphics::DrawArray(0, 4); // 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) { void CPhazonSuitFilter::draw(const zeus::CColor& color, float indScale, float indOffX, float indOffY) {

View File

@ -36,7 +36,7 @@ void CSpaceWarpFilter::GenerateWarpRampTex() {
} }
} }
m_warpTex = aurora::gfx::new_static_texture_2d( 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<const uint8_t*>(data.data()), (WARP_RAMP_RES + 1) * (WARP_RAMP_RES + 1) * 4}, "Warp Ramp"); {reinterpret_cast<const uint8_t*>(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.x4_left += CGraphics::g_CroppedViewport.x4_left;
clipRect.x8_top += CGraphics::g_CroppedViewport.x8_top; clipRect.x8_top += CGraphics::g_CroppedViewport.x8_top;
clipRect.x8_top = CGraphics::GetViewportHeight() - clipRect.x10_height - clipRect.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_strength.x() =
m_uniform.m_matrix[0][0] * m_strength * 0.5f * (clipRect.x10_height / float(clipRect.xc_width)); m_uniform.m_matrix[0][0] * m_strength * 0.5f * (clipRect.x10_height / float(clipRect.xc_width));

View File

@ -53,7 +53,7 @@ CThermalColdFilter::CThermalColdFilter() {
void CThermalColdFilter::draw() { void CThermalColdFilter::draw() {
SCOPED_GRAPHICS_DEBUG_GROUP("CThermalColdFilter::draw", zeus::skMagenta); 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)); // m_uniBuf->load(&m_uniform, sizeof(m_uniform));
// CGraphics::SetShaderDataBinding(m_dataBind); // CGraphics::SetShaderDataBinding(m_dataBind);
// CGraphics::DrawArray(0, 4); // CGraphics::DrawArray(0, 4);

View File

@ -49,7 +49,7 @@ CThermalHotFilter::CThermalHotFilter() {
void CThermalHotFilter::draw() { void CThermalHotFilter::draw() {
SCOPED_GRAPHICS_DEBUG_GROUP("CThermalHotFilter::draw", zeus::skMagenta); 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)); // m_uniBuf->load(&m_uniform, sizeof(m_uniform));

View File

@ -49,7 +49,7 @@ CXRayBlurFilter::CXRayBlurFilter(TLockedToken<CTexture>& tex) : m_paletteTex(tex
void CXRayBlurFilter::draw(float amount) { void CXRayBlurFilter::draw(float amount) {
SCOPED_GRAPHICS_DEBUG_GROUP("CXRayBlurFilter::draw", zeus::skMagenta); 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 blurL = amount * g_tweakGui->GetXrayBlurScaleLinear() * 0.25f;
const float blurQ = amount * g_tweakGui->GetXrayBlurScaleQuadratic() * 0.25f; const float blurQ = amount * g_tweakGui->GetXrayBlurScaleQuadratic() * 0.25f;

View File

@ -68,44 +68,48 @@ const CTextRenderBuffer* CGuiTextSupport::GetCurrentPageRenderBuffer() const {
float CGuiTextSupport::GetCurrentAnimationOverAge() const { float CGuiTextSupport::GetCurrentAnimationOverAge() const {
float ret = 0.f; float ret = 0.f;
if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { // TODO
if (x50_typeEnable) { // if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
if (x40_primStartTimes.size()) { // if (x50_typeEnable) {
const auto& lastTime = x40_primStartTimes.back(); // if (x40_primStartTimes.size()) {
ret = std::max(ret, (buf->GetPrimitiveCount() - lastTime.second) / x58_chRate + lastTime.first); // const auto& lastTime = x40_primStartTimes.back();
} else { // ret = std::max(ret, (buf->GetPrimitiveCount() - lastTime.second) / x58_chRate + lastTime.first);
ret = std::max(ret, buf->GetPrimitiveCount() / x58_chRate); // } else {
} // ret = std::max(ret, buf->GetPrimitiveCount() / x58_chRate);
} // }
} // }
// }
return ret; return ret;
} }
float CGuiTextSupport::GetNumCharsTotal() const { float CGuiTextSupport::GetNumCharsTotal() const {
if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { // TODO
if (x50_typeEnable) { // if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
return buf->GetPrimitiveCount(); // if (x50_typeEnable) {
} // return buf->GetPrimitiveCount();
} // }
// }
return 0.f; return 0.f;
} }
float CGuiTextSupport::GetNumCharsPrinted() const { float CGuiTextSupport::GetNumCharsPrinted() const {
if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { // TODO
if (x50_typeEnable) { // if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
const float charsPrinted = x3c_curTime * x58_chRate; // if (x50_typeEnable) {
return std::min(charsPrinted, float(buf->GetPrimitiveCount())); // const float charsPrinted = x3c_curTime * x58_chRate;
} // return std::min(charsPrinted, float(buf->GetPrimitiveCount()));
} // }
// }
return 0.f; return 0.f;
} }
float CGuiTextSupport::GetTotalAnimationTime() const { float CGuiTextSupport::GetTotalAnimationTime() const {
if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { // TODO
if (x50_typeEnable) { // if (const CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
return buf->GetPrimitiveCount() / x58_chRate; // if (x50_typeEnable) {
} // return buf->GetPrimitiveCount() / x58_chRate;
} // }
// }
return 0.f; return 0.f;
} }
@ -117,20 +121,21 @@ void CGuiTextSupport::SetTypeWriteEffectOptions(bool enable, float chFadeTime, f
x58_chRate = std::max(chRate, 1.f); x58_chRate = std::max(chRate, 1.f);
if (enable) { if (enable) {
if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
float chStartTime = 0.f; // TODO
for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) { // float chStartTime = 0.f;
for (const std::pair<float, int>& p : x40_primStartTimes) { // for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) {
if (p.second < i) // for (const std::pair<float, int>& p : x40_primStartTimes) {
continue; // if (p.second < i)
if (p.second != i) // continue;
break; // if (p.second != i)
chStartTime = p.first; // break;
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; // 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) { void CGuiTextSupport::Update(float dt) {
if (x50_typeEnable) { if (x50_typeEnable) {
if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) { if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) {
float chStartTime = 0.f; // TODO
for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) { // float chStartTime = 0.f;
for (const std::pair<float, int>& p : x40_primStartTimes) { // for (u32 i = 0; i < buf->GetPrimitiveCount(); ++i) {
if (p.second < i) // for (const std::pair<float, int>& p : x40_primStartTimes) {
continue; // if (p.second < i)
if (p.second != i) // continue;
break; // if (p.second != i)
chStartTime = p.first; // break;
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; // buf->SetPrimitiveOpacity(i, std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f));
} // chStartTime += 1.f / x58_chRate;
// }
} }
x3c_curTime += dt; x3c_curTime += dt;
} }
@ -253,7 +259,8 @@ void CGuiTextSupport::SetFontColor(const zeus::CColor& col) {
void CGuiTextSupport::AddText(std::u16string_view str) { void CGuiTextSupport::AddText(std::u16string_view str) {
if (x60_renderBuf) { if (x60_renderBuf) {
const float t = GetCurrentAnimationOverAge(); 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; x0_string += str;
ClearRenderBuffer(); ClearRenderBuffer();

View File

@ -12,74 +12,74 @@
namespace metaforce { namespace metaforce {
struct CTextRenderBuffer::BooFontCharacters { //struct CTextRenderBuffer::BooFontCharacters {
TLockedToken<CRasterFont> m_font; // TLockedToken<CRasterFont> m_font;
// hecl::VertexBufferPool<CTextSupportShader::CharacterInstance>::Token m_instBuf; // hecl::VertexBufferPool<CTextSupportShader::CharacterInstance>::Token m_instBuf;
// boo::ObjToken<boo::IShaderDataBinding> m_dataBinding; // boo::ObjToken<boo::IShaderDataBinding> m_dataBinding;
// boo::ObjToken<boo::IShaderDataBinding> m_dataBinding2; // boo::ObjToken<boo::IShaderDataBinding> m_dataBinding2;
std::vector<CTextSupportShader::CharacterInstance> m_charData; // std::vector<CTextSupportShader::CharacterInstance> m_charData;
u32 m_charCount = 0; // u32 m_charCount = 0;
bool m_dirty = true; // bool m_dirty = true;
//
BooFontCharacters(const CToken& token) : m_font(token) {} // BooFontCharacters(const CToken& token) : m_font(token) {}
}; //};
//
struct CTextRenderBuffer::BooImage { //struct CTextRenderBuffer::BooImage {
CFontImageDef m_imageDef; // CFontImageDef m_imageDef;
// hecl::VertexBufferPool<CTextSupportShader::ImageInstance>::Token m_instBuf; // hecl::VertexBufferPool<CTextSupportShader::ImageInstance>::Token m_instBuf;
// std::vector<boo::ObjToken<boo::IShaderDataBinding>> m_dataBinding; // std::vector<boo::ObjToken<boo::IShaderDataBinding>> m_dataBinding;
// std::vector<boo::ObjToken<boo::IShaderDataBinding>> m_dataBinding2; // std::vector<boo::ObjToken<boo::IShaderDataBinding>> m_dataBinding2;
CTextSupportShader::ImageInstance m_imageData; // CTextSupportShader::ImageInstance m_imageData;
bool m_dirty = true; // bool m_dirty = true;
//
BooImage(const CFontImageDef& imgDef, const zeus::CVector2i& offset) : m_imageDef(imgDef) { // BooImage(const CFontImageDef& imgDef, const zeus::CVector2i& offset) : m_imageDef(imgDef) {
m_imageData.SetMetrics(imgDef, offset); // m_imageData.SetMetrics(imgDef, offset);
} // }
}; //};
//
struct CTextRenderBuffer::BooPrimitiveMark { //struct CTextRenderBuffer::BooPrimitiveMark {
Command m_cmd; // Command m_cmd;
u32 m_bindIdx; // u32 m_bindIdx;
u32 m_instIdx; // u32 m_instIdx;
//
void SetOpacity(CTextRenderBuffer& rb, float opacity) { // void SetOpacity(CTextRenderBuffer& rb, float opacity) {
switch (m_cmd) { // switch (m_cmd) {
case Command::CharacterRender: { // case Command::CharacterRender: {
BooFontCharacters& fc = rb.m_fontCharacters[m_bindIdx]; // BooFontCharacters& fc = rb.m_fontCharacters[m_bindIdx];
CTextSupportShader::CharacterInstance& inst = fc.m_charData[m_instIdx]; // CTextSupportShader::CharacterInstance& inst = fc.m_charData[m_instIdx];
inst.m_mulColor.a() = opacity; // inst.m_mulColor.a() = opacity;
fc.m_dirty = true; // fc.m_dirty = true;
break; // break;
} // }
case Command::ImageRender: { // case Command::ImageRender: {
BooImage& img = rb.m_images[m_bindIdx]; // BooImage& img = rb.m_images[m_bindIdx];
img.m_imageData.m_color.a() = opacity; // img.m_imageData.m_color.a() = opacity;
img.m_dirty = true; // img.m_dirty = true;
break; // break;
} // }
default: // default:
break; // break;
} // }
} // }
}; //};
CTextRenderBuffer::CTextRenderBuffer(CTextRenderBuffer&&) noexcept = default; 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() = default;
CTextRenderBuffer& CTextRenderBuffer::operator=(CTextRenderBuffer&&) noexcept = default; CTextRenderBuffer& CTextRenderBuffer::operator=(CTextRenderBuffer&&) noexcept = default;
void CTextRenderBuffer::CommitResources() { //void CTextRenderBuffer::CommitResources() {
if (m_committed) // if (m_committed)
return; // return;
m_committed = true; // m_committed = true;
//
/* Ensure font textures are ready outside transaction */ // /* Ensure font textures are ready outside transaction */
for (BooFontCharacters& chs : m_fontCharacters) // for (BooFontCharacters& chs : m_fontCharacters)
chs.m_font->GetTexture(); // chs.m_font->GetTexture();
//
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { // CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
// m_uniBuf = CTextSupportShader::s_Uniforms.allocateBlock(CGraphics::g_BooFactory); // m_uniBuf = CTextSupportShader::s_Uniforms.allocateBlock(CGraphics::g_BooFactory);
// auto uBufInfo = m_uniBuf.getBufferInfo(); // auto uBufInfo = m_uniBuf.getBufferInfo();
@ -142,109 +142,103 @@ void CTextRenderBuffer::CommitResources() {
// } // }
// return true; // return true;
// } BooTrace); // } BooTrace);
} //}
void CTextRenderBuffer::SetMode(EMode mode) { 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; x0_mode = mode;
} }
void CTextRenderBuffer::SetPrimitiveOpacity(int idx, float opacity) { //void CTextRenderBuffer::SetPrimitiveOpacity(int idx, float opacity) {
m_primitiveMarks[idx].SetOpacity(*this, opacity); // m_primitiveMarks[idx].SetOpacity(*this, opacity);
} //}
//
u32 CTextRenderBuffer::GetPrimitiveCount() const { return m_primitiveMarks.size(); } //u32 CTextRenderBuffer::GetPrimitiveCount() const { return m_primitiveMarks.size(); }
void CTextRenderBuffer::Render(const zeus::CColor& col, float time) { void CTextRenderBuffer::Render(const zeus::CColor& col, float time) {
CommitResources(); // CommitResources();
// const zeus::CMatrix4f mv = CGraphics::g_GXModelView.toMatrix4f(); // const zeus::CMatrix4f mv = CGraphics::g_GXModelView.toMatrix4f();
// const zeus::CMatrix4f proj = CGraphics::GetPerspectiveProjectionMatrix(true); // const zeus::CMatrix4f proj = CGraphics::GetPerspectiveProjectionMatrix(true);
// const zeus::CMatrix4f mat = proj * mv; // const zeus::CMatrix4f mat = proj * mv;
// m_uniBuf.access() = CTextSupportShader::Uniform{mat, col}; // m_uniBuf.access() = CTextSupportShader::Uniform{mat, col};
if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { // if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) {
zeus::CColor colPremul = col * col.a(); // zeus::CColor colPremul = col * col.a();
colPremul.a() = col.a(); // colPremul.a() = col.a();
// m_uniBuf2.access() = CTextSupportShader::Uniform{mat, colPremul}; // m_uniBuf2.access() = CTextSupportShader::Uniform{mat, colPremul};
} // }
for (BooFontCharacters& chs : m_fontCharacters) { // for (BooFontCharacters& chs : m_fontCharacters) {
if (chs.m_charData.size()) { // if (chs.m_charData.size()) {
if (chs.m_dirty) { // if (chs.m_dirty) {
// std::memmove(chs.m_instBuf.access(), chs.m_charData.data(), // std::memmove(chs.m_instBuf.access(), chs.m_charData.data(),
// sizeof(CTextSupportShader::CharacterInstance) * chs.m_charData.size()); // sizeof(CTextSupportShader::CharacterInstance) * chs.m_charData.size());
chs.m_dirty = false; // chs.m_dirty = false;
} // }
// CGraphics::SetShaderDataBinding(chs.m_dataBinding); // CGraphics::SetShaderDataBinding(chs.m_dataBinding);
// CGraphics::DrawInstances(0, 4, chs.m_charData.size()); // 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::SetShaderDataBinding(chs.m_dataBinding2);
// CGraphics::DrawInstances(0, 4, chs.m_charData.size()); // CGraphics::DrawInstances(0, 4, chs.m_charData.size());
} // }
} // }
} // }
for (BooImage& img : m_images) { // for (BooImage& img : m_images) {
if (img.m_dirty) { // if (img.m_dirty) {
// *img.m_instBuf.access() = img.m_imageData; // *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(); // const int idx = int(img.m_imageDef.x0_fps * time) % img.m_dataBinding.size();
// CGraphics::SetShaderDataBinding(img.m_dataBinding[idx]); // CGraphics::SetShaderDataBinding(img.m_dataBinding[idx]);
// CGraphics::DrawInstances(0, 4, 1); // CGraphics::DrawInstances(0, 4, 1);
if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) { // if (m_drawFlags == CGuiWidget::EGuiModelDrawFlags::AlphaAdditiveOverdraw) {
// CGraphics::SetShaderDataBinding(img.m_dataBinding2[idx]); // CGraphics::SetShaderDataBinding(img.m_dataBinding2[idx]);
// CGraphics::DrawInstances(0, 4, 1); // CGraphics::DrawInstances(0, 4, 1);
} // }
} // }
} }
void CTextRenderBuffer::AddImage(const zeus::CVector2i& offset, const CFontImageDef& image) { void CTextRenderBuffer::AddImage(const zeus::CVector2i& offset, const CFontImageDef& image) {
if (x0_mode == EMode::AllocTally) // if (x0_mode == EMode::AllocTally)
m_primitiveMarks.push_back({Command::ImageRender, m_imagesCount++, 0}); // m_primitiveMarks.push_back({Command::ImageRender, m_imagesCount++, 0});
else // else
m_images.emplace_back(image, offset); // m_images.emplace_back(image, offset);
} }
void CTextRenderBuffer::AddCharacter(const zeus::CVector2i& offset, char16_t ch, const zeus::CColor& color) { void CTextRenderBuffer::AddCharacter(const zeus::CVector2i& offset, char16_t ch, const zeus::CColor& color) {
if (m_activeFontCh == UINT32_MAX) // if (m_activeFontCh == UINT32_MAX)
return; // return;
BooFontCharacters& chs = m_fontCharacters[m_activeFontCh]; // BooFontCharacters& chs = m_fontCharacters[m_activeFontCh];
if (x0_mode == EMode::AllocTally) // if (x0_mode == EMode::AllocTally)
m_primitiveMarks.push_back({Command::CharacterRender, m_activeFontCh, chs.m_charCount++}); // m_primitiveMarks.push_back({Command::CharacterRender, m_activeFontCh, chs.m_charCount++});
else { // else {
const CGlyph* glyph = chs.m_font.GetObj()->GetGlyph(ch); // const CGlyph* glyph = chs.m_font.GetObj()->GetGlyph(ch);
//
CTextSupportShader::CharacterInstance& inst = chs.m_charData.emplace_back(); // CTextSupportShader::CharacterInstance& inst = chs.m_charData.emplace_back();
inst.SetMetrics(*glyph, offset); // inst.SetMetrics(*glyph, offset);
inst.m_fontColor = m_main * color; // inst.m_fontColor = m_main * color;
inst.m_outlineColor = m_outline * color; // inst.m_outlineColor = m_outline * color;
inst.m_mulColor = zeus::skWhite; // inst.m_mulColor = zeus::skWhite;
} // }
} }
void CTextRenderBuffer::AddPaletteChange(const zeus::CColor& main, const zeus::CColor& outline) { void CTextRenderBuffer::AddPaletteChange(const zeus::CColor& main, const zeus::CColor& outline) {
m_main = main; // m_main = main;
m_outline = outline; // m_outline = outline;
} }
void CTextRenderBuffer::AddFontChange(const TToken<CRasterFont>& font) { void CTextRenderBuffer::AddFontChange(const TToken<CRasterFont>& font) {
for (size_t i = 0; i < m_fontCharacters.size(); ++i) { // for (size_t i = 0; i < m_fontCharacters.size(); ++i) {
BooFontCharacters& chs = m_fontCharacters[i]; // BooFontCharacters& chs = m_fontCharacters[i];
if (*chs.m_font.GetObjectTag() == *font.GetObjectTag()) { // if (*chs.m_font.GetObjectTag() == *font.GetObjectTag()) {
m_activeFontCh = i; // m_activeFontCh = i;
return; // return;
} // }
} // }
//
m_activeFontCh = m_fontCharacters.size(); // m_activeFontCh = m_fontCharacters.size();
m_fontCharacters.emplace_back(font); // m_fontCharacters.emplace_back(font);
} }
bool CTextRenderBuffer::HasSpaceAvailable(const zeus::CVector2i& origin, const zeus::CVector2i& extent) const { bool CTextRenderBuffer::HasSpaceAvailable(const zeus::CVector2i& origin, const zeus::CVector2i& extent) const {
@ -263,23 +257,65 @@ std::pair<zeus::CVector2i, zeus::CVector2i> CTextRenderBuffer::AccumulateTextBou
std::pair<zeus::CVector2i, zeus::CVector2i> ret = std::pair<zeus::CVector2i, zeus::CVector2i> ret =
std::make_pair(zeus::CVector2i{INT_MAX, INT_MAX}, zeus::CVector2i{INT_MIN, INT_MIN}); std::make_pair(zeus::CVector2i{INT_MAX, INT_MAX}, zeus::CVector2i{INT_MIN, INT_MIN});
for (const BooFontCharacters& chars : m_fontCharacters) { // for (const BooFontCharacters& chars : m_fontCharacters) {
for (const CTextSupportShader::CharacterInstance& charInst : chars.m_charData) { // for (const CTextSupportShader::CharacterInstance& charInst : chars.m_charData) {
ret.first.x = std::min(ret.first.x, int(charInst.m_pos[0].x())); // 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.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.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())); // ret.second.y = std::max(ret.second.y, int(charInst.m_pos[3].z()));
} // }
} // }
//
for (const BooImage& imgs : m_images) { // for (const BooImage& imgs : m_images) {
ret.first.x = std::min(ret.first.x, int(imgs.m_imageData.m_pos[0].x())); // 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.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.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())); // ret.second.y = std::max(ret.second.y, int(imgs.m_imageData.m_pos[3].z()));
} // }
return ret; return ret;
} }
void CTextRenderBuffer::SetPrimitive(const Primitive& prim, s32 idx) {
CMemoryStreamOut out(reinterpret_cast<u8*>(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<const u8*>(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 } // namespace metaforce

View File

@ -27,58 +27,29 @@ class CTextRenderBuffer {
friend class CTextSupportShader; friend class CTextSupportShader;
public: public:
enum class Command { CharacterRender, ImageRender, FontChange, PaletteChange }; enum class Command { CharacterRender, ImageRender, FontChange, PaletteChange, Invalid };
#if 0 struct Primitive {
struct Primitive CTextColor x0_color1;
{ Command x4_command;
CTextColor x0_color1; u16 x8_xPos;
Command x4_command; u16 xa_zPos;
u16 x8_xPos; char16_t xc_glyph;
u16 xa_zPos; u8 xe_imageIndex;
char16_t xc_glyph; };
u8 xe_imageIndex;
};
#endif
enum class EMode { AllocTally, BufferFill }; enum class EMode { AllocTally, BufferFill };
private: private:
EMode x0_mode; EMode x0_mode;
#if 0 std::vector<TToken<CRasterFont>> x4_fonts;
std::vector<TToken<CRasterFont>> x4_fonts; std::vector<CFontImageDef> x14_images;
std::vector<CFontImageDef> x14_images; std::vector<int> x24_primOffsets;
std::vector<int> x24_primOffsets; std::vector<char> x34_bytecode;
std::vector<char> x34_bytecode; u32 x44_blobSize = 0;
u32 x44_blobSize = 0; u32 x48_curBytecodeOffset = 0;
u32 x48_curBytecodeOffset = 0; u8 x4c_activeFont;
u8 x4c_activeFont; u32 x50_paletteCount = 0;
u32 x50_paletteCount = 0; std::array<std::unique_ptr<CGraphicsPalette>, 64> x54_palettes;
std::array<std::unique_ptr<CGraphicsPalette>, 64> x54_palettes; u32 x254_nextPalette = 0;
u32 x254_nextPalette = 0;
#else
/* Boo-specific text-rendering functionality */
// hecl::UniformBufferPool<CTextSupportShader::Uniform>::Token m_uniBuf;
// hecl::UniformBufferPool<CTextSupportShader::Uniform>::Token m_uniBuf2;
struct BooFontCharacters;
std::vector<BooFontCharacters> m_fontCharacters;
struct BooImage;
std::vector<BooImage> m_images;
struct BooPrimitiveMark;
std::vector<BooPrimitiveMark> 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
public: public:
CTextRenderBuffer(CTextRenderBuffer&& other) noexcept; CTextRenderBuffer(CTextRenderBuffer&& other) noexcept;
@ -87,18 +58,13 @@ public:
CTextRenderBuffer& operator=(CTextRenderBuffer&& other) noexcept; CTextRenderBuffer& operator=(CTextRenderBuffer&& other) noexcept;
#if 0 void SetPrimitive(const Primitive&, int);
void SetPrimitive(const Primitive&, int); [[nodiscard]] Primitive GetPrimitive(int) const;
Primitive GetPrimitive(int) const; void GetOutStream();
void GetOutStream(); void VerifyBuffer();
void VerifyBuffer(); int GetMatchingPaletteIndex(const CGraphicsPalette& palette);
int GetMatchingPaletteIndex(const CGraphicsPalette& palette); CGraphicsPalette* GetNextAvailablePalette();
CGraphicsPalette* GetNextAvailablePalette(); void AddPaletteChange(const CGraphicsPalette& palette);
void AddPaletteChange(const CGraphicsPalette& palette);
#else
void SetPrimitiveOpacity(int idx, float opacity);
u32 GetPrimitiveCount() const;
#endif
void SetMode(EMode mode); void SetMode(EMode mode);
void Render(const zeus::CColor& col, float time); void Render(const zeus::CColor& col, float time);
void AddImage(const zeus::CVector2i& offset, const CFontImageDef& image); void AddImage(const zeus::CVector2i& offset, const CFontImageDef& image);

View File

@ -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 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); float colT = 1.f - zeus::clamp(0.f, (stateMgr.GetPlayer().GetDeathTime() - colStart) / 0.5f, 1.f);
SClipScreenRect rect(CGraphics::g_Viewport); 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); 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 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); float x = 0.5f * (xT * (CGraphics::GetViewportWidth() - 12.f) + 12.f);

View File

@ -353,7 +353,7 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t
rect.x8_top = int((CGraphics::GetViewportHeight() - vpH) / 2.f); rect.x8_top = int((CGraphics::GetViewportHeight() - vpH) / 2.f);
rect.xc_width = int(vpW); rect.xc_width = int(vpW);
rect.x10_height = int(vpH); rect.x10_height = int(vpH);
CGraphics::ResolveSpareTexture(rect); CGraphics::ResolveSpareTexture(rect, 0, GX::TF_RGB565);
// TODO hack; figure out why needed // TODO hack; figure out why needed
CGraphics::SetCullMode(ERglCullMode::None); 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 seventeenScale = zeus::CTransform::Scale(17.f * vpScale, 1.f, 17.f * vpScale);
const zeus::CTransform mm = seventeenScale * windowScale; const zeus::CTransform mm = seventeenScale * windowScale;
g_Renderer->SetModelMatrix(mm); g_Renderer->SetModelMatrix(mm);
CGraphics::LoadDolphinSpareTexture(0, GX::TEXMAP0); CGraphics::LoadDolphinSpareTexture(0, GX::TF_RGB565, GX::TEXMAP0);
if (x108_newScanPane) { if (x108_newScanPane) {
SCOPED_GRAPHICS_DEBUG_GROUP("x108_newScanPane Draw", zeus::skMagenta); SCOPED_GRAPHICS_DEBUG_GROUP("x108_newScanPane Draw", zeus::skMagenta);

View File

@ -1751,7 +1751,7 @@ void CElementGen::RenderParticlesIndirectTexture() {
if (!clipRect.x0_valid) if (!clipRect.x0_valid)
continue; continue;
CGraphics::ResolveSpareTexture(clipRect); // CGraphics::ResolveSpareTexture(clipRect);
// SParticleInstanceIndTex& inst = g_instIndTexData.emplace_back(); // SParticleInstanceIndTex& inst = g_instIndTexData.emplace_back();
// inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f}; // inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f};

View File

@ -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; bool drawIndirect = visor == CPlayerState::EPlayerVisor::Combat || visor == CPlayerState::EPlayerVisor::Scan;
if (drawIndirect) { if (drawIndirect) {
CGraphics::ResolveSpareTexture(CGraphics::g_Viewport); // TODO CGraphics::ResolveSpareTexture(CGraphics::g_Viewport);
CModelFlags tmpFlags = flags; CModelFlags tmpFlags = flags;
// TODO tmpFlags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly; // TODO tmpFlags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly;
CGunWeapon::Draw(drawSuitArm, mgr, xf, tmpFlags, lights); CGunWeapon::Draw(drawSuitArm, mgr, xf, tmpFlags, lights);

View File

@ -2133,7 +2133,7 @@ zeus::CVector3f CPlayerGun::ConvertToScreenSpace(const zeus::CVector3f& pos, con
void CPlayerGun::CopyScreenTex() { void CPlayerGun::CopyScreenTex() {
// Copy lower right quadrant to gpCopyTexBuf as RGBA8 // Copy lower right quadrant to gpCopyTexBuf as RGBA8
CGraphics::ResolveSpareTexture(CGraphics::g_Viewport); // TODO CGraphics::ResolveSpareTexture(CGraphics::g_Viewport);
} }
void CPlayerGun::DrawScreenTex(float z) { void CPlayerGun::DrawScreenTex(float z) {

View File

@ -135,7 +135,7 @@ void CFluidPlaneManager::SetupRippleMap() {
curX += (1.f / 63.f); 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<const uint8_t*>(RippleValues.data()), 64 * 64}, {reinterpret_cast<const uint8_t*>(RippleValues.data()), 64 * 64},
"Ripple Map"); "Ripple Map");
} }

View File

@ -6,7 +6,9 @@
namespace metaforce { 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<CTexture>(rgba8 ? ETexelFormat::RGBA8 : ETexelFormat::RGB565, w, h, 1, "World Shadow"sv)) {}
void CWorldShadow::EnableModelProjectedShadow(const zeus::CTransform& pos, s32 lightIdx, float f1) { void CWorldShadow::EnableModelProjectedShadow(const zeus::CTransform& pos, s32 lightIdx, float f1) {
zeus::CTransform texTransform = zeus::lookAt(zeus::skZero3f, x74_lightPos - x68_objPos); 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 = posXf.inverse() * texTransform;
texTransform = (texTransform * zeus::CTransform::Scale(float(M_SQRT2) * x64_objHalfExtent * f1)).inverse(); texTransform = (texTransform * zeus::CTransform::Scale(float(M_SQRT2) * x64_objHalfExtent * f1)).inverse();
texTransform = zeus::CTransform::Translate(0.5f, 0.f, 0.5f) * texTransform; texTransform = zeus::CTransform::Translate(0.5f, 0.f, 0.5f) * texTransform;
// TODO CCubeModel::EnableShadowMaps(m_shader.GetTexture(), texTransform); GX::LightMask lightMask;
lightMask.set(lightIdx);
#if CWORLDSHADOW_FEEDBACK // CCubeModel::EnableShadowMaps(*x0_texture, texTransform, lightMask, lightMask);
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
} }
void CWorldShadow::DisableModelProjectedShadow() { CCubeModel::DisableShadowMaps(); } void CWorldShadow::DisableModelProjectedShadow() { CCubeModel::DisableShadowMaps(); }
@ -63,45 +59,72 @@ void CWorldShadow::BuildLightShadowTexture(const CStateManager& mgr, TAreaId aid
zeus::CFrustum frustum; zeus::CFrustum frustum;
frustum.updatePlanes(x4_view, zeus::SProjPersp(zeus::degToRad(fov), 1.f, 0.1f, distance + x64_objHalfExtent)); frustum.updatePlanes(x4_view, zeus::SProjPersp(zeus::degToRad(fov), 1.f, 0.1f, distance + x64_objHalfExtent));
g_Renderer->SetClippingPlanes(frustum); 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; SViewport backupVp = CGraphics::g_Viewport;
zeus::CVector2f backupDepthRange = CGraphics::g_CachedDepthRange; zeus::CVector2f backupDepthRange = CGraphics::g_CachedDepthRange;
m_shader.bindRenderTarget(); g_Renderer->SetViewport(0, 0, x0_texture->GetWidth(), x0_texture->GetHeight());
g_Renderer->SetViewport(0, 0, m_shader.GetWidth(), m_shader.GetHeight());
CGraphics::SetDepthRange(DEPTH_NEAR, DEPTH_FAR); CGraphics::SetDepthRange(DEPTH_NEAR, DEPTH_FAR);
x34_model = zeus::lookAt(centerPoint - zeus::CVector3f(0.f, 0.f, 0.1f), light.GetPosition()); x34_model = zeus::lookAt(centerPoint - zeus::CVector3f(0.f, 0.f, 0.1f), light.GetPosition());
CGraphics::SetModelMatrix(x34_model); CGraphics::SetModelMatrix(x34_model);
float extent = float(M_SQRT2) * x64_objHalfExtent; float extent = float(M_SQRT2) * x64_objHalfExtent;
/* Depth test and write */ g_Renderer->PrimColor(zeus::skWhite);
/* Color white 100% alpha */ CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
m_shader.drawBase(extent); 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()); CGraphics::SetModelMatrix(zeus::CTransform());
CCubeModel::SetRenderModelBlack(true);
CCubeModel::SetDrawingOccluders(true); CCubeModel::SetDrawingOccluders(true);
g_Renderer->PrepareDynamicLights({}); g_Renderer->PrepareDynamicLights({});
// g_Renderer->UpdateAreaUniforms(aid, EWorldShadowMode::WorldOnActorShadow);
g_Renderer->DrawUnsortedGeometry(aid, 0, 0); g_Renderer->DrawUnsortedGeometry(aid, 0, 0);
CCubeModel::SetRenderModelBlack(false);
CCubeModel::SetDrawingOccluders(false); CCubeModel::SetDrawingOccluders(false);
if (lighten) { if (lighten) {
CGraphics::SetModelMatrix(x34_model); CGraphics::SetModelMatrix(x34_model);
/* No depth test or write */ CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
/* Color white 25% alpha */ CGraphics::SetDepthWriteMode(false, ERglEnum::LEqual, false);
m_shader.lightenShadow(); 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) { if (motionBlur && !x88_blurReset) {
/* No depth test or write */ CGraphics::SetDepthWriteMode(false, ERglEnum::LEqual, false);
/* Color white 85% alpha */ CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
/* Draw in shadow texture */ ERglLogicOp::Clear);
m_shader.blendPreviousShadow(); 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; x88_blurReset = false;
m_shader.resolveTexture(); // TODO
// m_shader.resolveTexture();
// CBooRenderer::BindMainDrawTarget(); // CBooRenderer::BindMainDrawTarget();
g_Renderer->SetViewport(backupVp.x0_left, backupVp.x4_top, backupVp.x8_width, backupVp.xc_height); g_Renderer->SetViewport(backupVp.x0_left, backupVp.x4_top, backupVp.x8_width, backupVp.xc_height);

View File

@ -7,13 +7,11 @@
#include <zeus/CTransform.hpp> #include <zeus/CTransform.hpp>
#include <zeus/CVector3f.hpp> #include <zeus/CVector3f.hpp>
#define CWORLDSHADOW_FEEDBACK 0
namespace metaforce { namespace metaforce {
class CStateManager; class CStateManager;
class CWorldShadow { class CWorldShadow {
CWorldShadowShader m_shader; std::unique_ptr<CTexture> x0_texture;
zeus::CTransform x4_view; zeus::CTransform x4_view;
zeus::CTransform x34_model; zeus::CTransform x34_model;
float x64_objHalfExtent = 1.f; float x64_objHalfExtent = 1.f;
@ -22,9 +20,7 @@ class CWorldShadow {
TAreaId x80_aid = kInvalidAreaId; TAreaId x80_aid = kInvalidAreaId;
s32 x84_lightIdx = -1; s32 x84_lightIdx = -1;
bool x88_blurReset = true; bool x88_blurReset = true;
#if CWORLDSHADOW_FEEDBACK
std::optional<CTexturedQuadFilter> m_feedback;
#endif
public: public:
CWorldShadow(u32 w, u32 h, bool rgba8); CWorldShadow(u32 w, u32 h, bool rgba8);
void EnableModelProjectedShadow(const zeus::CTransform& pos, s32 lightIdx, float f1); void EnableModelProjectedShadow(const zeus::CTransform& pos, s32 lightIdx, float f1);

View File

@ -290,9 +290,9 @@ void CWorldTransManager::DrawEnabled() {
float t = zeus::clamp(0.f, (x0_curTime - x4_modelData->x1d0_dissolveStartTime) / 2.f, 1.f); float t = zeus::clamp(0.f, (x0_curTime - x4_modelData->x1d0_dissolveStartTime) / 2.f, 1.f);
DrawFirstPass(&lights); DrawFirstPass(&lights);
SClipScreenRect rect(CGraphics::g_Viewport); SClipScreenRect rect(CGraphics::g_Viewport);
CGraphics::ResolveSpareTexture(rect); // CGraphics::ResolveSpareTexture(rect);
// CGraphics::g_BooMainCommandQueue->clearTarget(true, true); // 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); // m_dissolve.drawCropped(zeus::CColor{1.f, 1.f, 1.f, 1.f - t}, 1.f);
} }

View File

@ -18,6 +18,8 @@ struct Vec2 {
constexpr Vec2() = default; constexpr Vec2() = default;
constexpr Vec2(T x, T y) : x(x), y(y) {} constexpr Vec2(T x, T y) : x(x), y(y) {}
constexpr Vec2(const zeus::CVector2f& vec) : x(vec.x()), y(vec.y()) {} constexpr Vec2(const zeus::CVector2f& vec) : x(vec.x()), y(vec.y()) {}
bool operator==(const Vec2&) const = default;
}; };
template <typename T> template <typename T>
struct Vec3 { struct Vec3 {
@ -28,6 +30,8 @@ struct Vec3 {
constexpr Vec3() = default; constexpr Vec3() = default;
constexpr Vec3(T x, T y, T z) : x(x), y(y), z(z) {} 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()) {} constexpr Vec3(const zeus::CVector3f& vec) : x(vec.x()), y(vec.y()), z(vec.z()) {}
bool operator==(const Vec3&) const = default;
}; };
template <typename T> template <typename T>
struct Vec4 { 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(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::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()) {} 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 <typename T>
struct Mat3x2 {
Vec2<T> m0{};
Vec2<T> m1{};
Vec2<T> m2{};
constexpr Mat3x2() = default;
constexpr Mat3x2(const Vec2<T>& m0, const Vec2<T>& m1, const Vec2<T>& m2) : m0(m0), m1(m1), m2(m2) {}
bool operator==(const Mat3x2&) const = default;
}; };
template <typename T> template <typename T>
struct Mat4x2 { struct Mat4x2 {
@ -51,6 +68,8 @@ struct Mat4x2 {
constexpr Mat4x2() = default; constexpr Mat4x2() = default;
constexpr Mat4x2(const Vec2<T>& m0, const Vec2<T>& m1, const Vec2<T>& m2, const Vec2<T>& m3) constexpr Mat4x2(const Vec2<T>& m0, const Vec2<T>& m1, const Vec2<T>& m2, const Vec2<T>& m3)
: m0(m0), m1(m1), m2(m2), m3(m3) {} : m0(m0), m1(m1), m2(m2), m3(m3) {}
bool operator==(const Mat4x2&) const = default;
}; };
template <typename T> template <typename T>
struct Mat4x4 { struct Mat4x4 {
@ -64,6 +83,8 @@ struct Mat4x4 {
: m0(m0), m1(m1), m2(m2), m3(m3) {} : 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::CMatrix4f& m) : m0(m[0]), m1(m[1]), m2(m[2]), m3(m[3]) {}
constexpr Mat4x4(const zeus::CTransform& m) : Mat4x4(m.toMatrix4f()) {} constexpr Mat4x4(const zeus::CTransform& m) : Mat4x4(m.toMatrix4f()) {}
bool operator==(const Mat4x4&) const = default;
}; };
constexpr Mat4x4<float> Mat4x4_Identity{ constexpr Mat4x4<float> Mat4x4_Identity{
Vec4<float>{1.f, 0.f, 0.f, 0.f}, Vec4<float>{1.f, 0.f, 0.f, 0.f},

View File

@ -36,12 +36,6 @@ enum class ETexelFormat {
R8PC = 12, R8PC = 12,
}; };
enum class EClampMode {
Clamp,
Repeat,
Mirror,
};
enum class EStreamFlagBits : u8 { enum class EStreamFlagBits : u8 {
fHasNormal = 0x1, fHasNormal = 0x1,
fHasColor = 0x2, fHasColor = 0x2,
@ -52,13 +46,7 @@ using EStreamFlags = Flags<EStreamFlagBits>;
namespace aurora::gfx { namespace aurora::gfx {
struct TextureRef; struct TextureRef;
struct TextureHandle { using TextureHandle = std::shared_ptr<TextureRef>;
std::shared_ptr<TextureRef> ref;
TextureHandle() = default;
TextureHandle(std::shared_ptr<TextureRef>&& ref) : ref(std::move(ref)) {}
operator bool() const { return ref.operator bool(); }
void reset() { ref.reset(); }
};
struct ClipRect { struct ClipRect {
int32_t x; int32_t x;
@ -85,24 +73,19 @@ struct ScopedDebugGroup {
inline ~ScopedDebugGroup() noexcept { pop_debug_group(); } 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_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 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_color(const ClipRect& rect, uint32_t bindIdx, GX::TextureFormat fmt, bool clear_depth) noexcept;
void resolve_depth(const ClipRect& rect, uint32_t bind) noexcept; void resolve_depth(const ClipRect& rect, uint32_t bindIdx, GX::TextureFormat fmt) noexcept;
void bind_color(u32 bindIdx, GX::TexMapID id) noexcept;
void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad, void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad,
float v_pad) noexcept; 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<uint8_t> data, zstring_view label) noexcept; ArrayRef<uint8_t> 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; zstring_view label) noexcept;
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;
void write_texture(const TextureHandle& handle, ArrayRef<uint8_t> data) noexcept; void write_texture(const TextureRef& handle, ArrayRef<uint8_t> data) noexcept;
} // namespace aurora::gfx } // namespace aurora::gfx

View File

@ -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; 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) { if (g_resolvedTextures.size() < bind + 1) {
g_resolvedTextures.resize(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<uint32_t>(rect.width), .width = static_cast<uint32_t>(rect.width),
.height = static_cast<uint32_t>(rect.height), .height = static_cast<uint32_t>(rect.height),
}; };
if (!g_resolvedTextures[bind] || g_resolvedTextures[bind].ref->size != size) { if (!g_resolvedTextures[bind] || g_resolvedTextures[bind]->size != size) {
g_resolvedTextures[bind] = new_render_texture(rect.width, rect.height, "Resolved Texture"); g_resolvedTextures[bind] = new_render_texture(rect.width, rect.height, fmt, "Resolved Texture");
} }
auto& currentPass = g_renderPasses[g_currentRenderPass]; auto& currentPass = g_renderPasses[g_currentRenderPass];
currentPass.resolveTarget = bind; currentPass.resolveTarget = bind;
@ -237,12 +237,10 @@ void resolve_color(const ClipRect& rect, uint32_t bind, bool clear_depth) noexce
newPass.clear = false; // TODO newPass.clear = false; // TODO
++g_currentRenderPass; ++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 // TODO
} }
void bind_color(u32 bindIdx, GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast<size_t>(id)] = {bindIdx}; }
void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad, void queue_movie_player(const TextureHandle& tex_y, const TextureHandle& tex_u, const TextureHandle& tex_v, float h_pad,
float v_pad) noexcept { float v_pad) noexcept {
auto data = movie_player::make_draw_data(g_state.moviePlayer, tex_y, tex_u, tex_v, h_pad, v_pad); 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]; auto& target = g_resolvedTextures[passInfo.resolveTarget];
const wgpu::ImageCopyTexture dst{ const wgpu::ImageCopyTexture dst{
.texture = target.ref->texture, .texture = target->texture,
}; };
const wgpu::Extent3D size{ const wgpu::Extent3D size{
.width = static_cast<uint32_t>(passInfo.resolveRect.width), .width = static_cast<uint32_t>(passInfo.resolveRect.width),

View File

@ -128,22 +128,25 @@ extern size_t g_staticStorageLastSize;
// TODO this is a bad place for this... // TODO this is a bad place for this...
extern std::vector<TextureHandle> g_resolvedTextures; extern std::vector<TextureHandle> g_resolvedTextures;
constexpr GX::TextureFormat InvalidTextureFormat = static_cast<GX::TextureFormat>(-1);
struct TextureRef { struct TextureRef {
wgpu::Texture texture; wgpu::Texture texture;
wgpu::TextureView view; wgpu::TextureView view;
wgpu::Extent3D size; wgpu::Extent3D size;
wgpu::TextureFormat format; wgpu::TextureFormat format;
uint32_t mipCount; 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, 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)) : texture(std::move(texture))
, view(std::move(view)) , view(std::move(view))
, size(size) , size(size)
, format(format) , format(format)
, mipCount(mipCount) , mipCount(mipCount)
, gameFormat(gameFormat) {} , gxFormat(gxFormat)
, isRenderTexture(isRenderTexture) {}
}; };
using BindGroupRef = uint64_t; using BindGroupRef = uint64_t;

View File

@ -42,11 +42,11 @@ void GXSetZMode(bool compare_enable, GX::Compare func, bool update_enable) noexc
g_gxState.depthUpdate = update_enable; g_gxState.depthUpdate = update_enable;
} }
void GXSetTevColor(GX::TevRegID id, const zeus::CColor& color) noexcept { 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); Log.report(logvisor::Fatal, FMT_STRING("bad tevreg {}"), id);
unreachable(); unreachable();
} }
g_gxState.colorRegs[id - 1] = color; g_gxState.colorRegs[id] = color;
} }
void GXSetTevKColor(GX::TevKColorID id, const zeus::CColor& color) noexcept { void GXSetTevKColor(GX::TevKColorID id, const zeus::CColor& color) noexcept {
if (id >= GX::MAX_KCOLOR) { if (id >= GX::MAX_KCOLOR) {
@ -201,8 +201,76 @@ void GXSetLineWidth(u8 width, GX::TexOffset offs) noexcept {
// TODO // 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 // 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->a0 = a0;
light->a1 = a1; light->a1 = a1;
light->a2 = a2; light->a2 = a2;
@ -211,19 +279,19 @@ void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0
light->k2 = k2; 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->a0 = a0;
light->a1 = a1; light->a1 = a1;
light->a2 = a2; 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->k0 = k0;
light->k1 = k1; light->k1 = k1;
light->k2 = k2; 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) { if (cutoff <= 0.f || cutoff > 90.f) {
spotFn = GX::SP_OFF; spotFn = GX::SP_OFF;
} }
@ -278,7 +346,8 @@ void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn) {
light->a2 = a2; 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) { if (refDistance < 0.f || refBrightness < 0.f || refBrightness >= 1.f) {
distFunc = GX::DA_OFF; distFunc = GX::DA_OFF;
} }
@ -313,19 +382,19 @@ void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBright
light->k2 = k2; 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->px = x;
light->py = y; light->py = y;
light->pz = z; 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->nx = -nx;
light->ny = -ny; light->ny = -ny;
light->nz = -nz; 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 hx = -nx;
float hy = -ny; float hy = -ny;
float hz = (-nz + 1.0f); float hz = (-nz + 1.0f);
@ -341,7 +410,7 @@ void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz) {
light->nz = hz * mag; 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->px = (nx * GX::LARGE_NUMBER);
light->py = (ny * GX::LARGE_NUMBER); light->py = (ny * GX::LARGE_NUMBER);
light->pz = (nz * 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; 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<u32>(id); u32 idx = std::log2<u32>(id);
aurora::gfx::Light realLight; aurora::gfx::Light realLight;
realLight.pos.assign(light->px, light->py, light->pz); 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 */ /* 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; *a0 = light->a0;
*a1 = light->a1; *a1 = light->a1;
*a2 = light->a2; *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; *k0 = light->k0;
*k1 = light->k1; *k1 = light->k1;
*k2 = light->k2; *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; *x = light->px;
*z = light->py; *z = light->py;
*z = light->pz; *z = light->pz;
} }
void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz) { void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz) noexcept {
*nx = light->nx; *nx = -light->nx;
*ny = light->ny; *ny = -light->ny;
*nz = light->nz; *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<const aurora::Mat3x2<float>*>(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<GXTlut>(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<const u8*>(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 { namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx"); 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 // TODO remove this hack for build_shader
extern std::mutex g_pipelineMutex; 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<size_t>(id)] = {tex, clamp, lod};
}
void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast<size_t>(id)].reset(); }
namespace gx { namespace gx {
using gpu::g_device; using gpu::g_device;
using gpu::g_graphicsConfig; 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; }); [](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; });
for (u8 i = 0; i < MaxTextures; ++i) { for (u8 i = 0; i < MaxTextures; ++i) {
const auto& bind = g_gxState.textures[i]; const auto& bind = g_gxState.textures[i];
bool hasAlpha = false; GX::TextureFormat copyFmt, bindFmt;
// TODO check resolved fmt bool flipUV = false;
if (bind.handle) { if (!bind.texObj.ref) {
wgpu::TextureFormat format = bind.handle.ref->format; config.shaderConfig.textureConfig[i] = {};
switch (format) { continue;
case wgpu::TextureFormat::R8Unorm: } else if (bind.texObj.ref->isRenderTexture) {
case wgpu::TextureFormat::R8Snorm: // EFB copy
case wgpu::TextureFormat::R8Uint: copyFmt = bind.texObj.ref->gxFormat;
case wgpu::TextureFormat::R8Sint: bindFmt = bind.texObj.fmt;
case wgpu::TextureFormat::R16Uint: flipUV = true;
case wgpu::TextureFormat::R16Sint: } else {
case wgpu::TextureFormat::R16Float: // Loaded texture object, no conversion necessary
case wgpu::TextureFormat::RG8Unorm: copyFmt = InvalidTextureFormat;
case wgpu::TextureFormat::RG8Snorm: bindFmt = InvalidTextureFormat;
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();
}
} }
config.shaderConfig.texHasAlpha[i] = hasAlpha; config.shaderConfig.textureConfig[i] = {copyFmt, bindFmt, flipUV};
} }
config = { config = {
.shaderConfig = config.shaderConfig, .shaderConfig = config.shaderConfig,
@ -870,7 +997,7 @@ Range build_uniform(const ShaderInfo& info) noexcept {
Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), i); Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), i);
unreachable(); unreachable();
} }
buf.append(&tex.lod, 4); buf.append(&tex.texObj.lodBias, 4);
} }
return range; return range;
} }
@ -929,17 +1056,10 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
.binding = i, .binding = i,
.sampler = sampler_ref(tex.get_descriptor()), .sampler = sampler_ref(tex.get_descriptor()),
}; };
if (tex.handle) { textureEntries[i] = {
textureEntries[i] = { .binding = i,
.binding = i, .textureView = tex.texObj.ref->view,
.textureView = tex.handle.ref->view, };
};
} else if (tex.resolvedBindIdx != UINT32_MAX) {
textureEntries[i] = {
.binding = i,
.textureView = g_resolvedTextures[tex.resolvedBindIdx].ref->view,
};
}
i++; i++;
} }
return { return {
@ -1084,29 +1204,64 @@ void shutdown() noexcept {
g_gxCachedShaders.clear(); g_gxCachedShaders.clear();
} }
wgpu::SamplerDescriptor TextureBind::get_descriptor() const noexcept { static wgpu::AddressMode wgpu_address_mode(GXTexWrapMode mode) {
wgpu::AddressMode mode; switch (mode) {
switch (clampMode) { case GX_CLAMP:
case metaforce::EClampMode::Clamp: return wgpu::AddressMode::ClampToEdge;
mode = wgpu::AddressMode::ClampToEdge; case GX_REPEAT:
break; return wgpu::AddressMode::Repeat;
case metaforce::EClampMode::Repeat: case GX_MIRROR:
mode = wgpu::AddressMode::Repeat; return wgpu::AddressMode::MirrorRepeat;
break; default:
case metaforce::EClampMode::Mirror: Log.report(logvisor::Fatal, FMT_STRING("invalid wrap mode {}"), mode);
mode = wgpu::AddressMode::MirrorRepeat; unreachable();
break;
} }
}
static std::pair<wgpu::FilterMode, wgpu::FilterMode> 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 { return {
.label = "Generated Sampler", .label = "Generated Sampler",
.addressModeU = mode, .addressModeU = wgpu_address_mode(texObj.wrapS),
.addressModeV = mode, .addressModeV = wgpu_address_mode(texObj.wrapT),
.addressModeW = mode, .addressModeW = wgpu::AddressMode::Repeat,
// TODO logic from CTexture? .magFilter = magFilter,
.magFilter = wgpu::FilterMode::Linear, .minFilter = minFilter,
.minFilter = wgpu::FilterMode::Linear, .mipmapFilter = mipFilter,
.mipmapFilter = wgpu::FilterMode::Linear, .maxAnisotropy = wgpu_aniso(texObj.maxAniso),
.maxAnisotropy = g_graphicsConfig.textureAnistropy,
}; };
} }
} // namespace gx } // namespace gx

View File

@ -3,19 +3,22 @@
#include "common.hpp" #include "common.hpp"
#include <type_traits> #include <type_traits>
#include <utility>
#include <variant> #include <variant>
namespace aurora::gfx::gx { namespace aurora::gfx::gx {
constexpr u32 MaxTextures = GX::MAX_TEXMAP; constexpr u32 MaxTextures = GX::MAX_TEXMAP;
constexpr u32 MaxTevStages = GX::MAX_TEVSTAGE; constexpr u32 MaxTevStages = GX::MAX_TEVSTAGE;
constexpr u32 MaxColorChannels = 2; // COLOR0A0, COLOR1A1 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 MaxKColors = GX::MAX_KCOLOR;
constexpr u32 MaxTexMtx = 10; constexpr u32 MaxTexMtx = 10;
constexpr u32 MaxPTTexMtx = 20; constexpr u32 MaxPTTexMtx = 20;
constexpr u32 MaxTexCoord = GX::MAX_TEXCOORD; constexpr u32 MaxTexCoord = GX::MAX_TEXCOORD;
constexpr u32 MaxVtxAttr = GX::VA_MAX_ATTR; constexpr u32 MaxVtxAttr = GX::VA_MAX_ATTR;
constexpr u32 MaxTevSwap = GX::MAX_TEVSWAP; constexpr u32 MaxTevSwap = GX::MAX_TEVSWAP;
constexpr u32 MaxIndStages = GX::MAX_INDTEXSTAGE;
constexpr u32 MaxIndTexMtxs = 3;
template <typename Arg, Arg Default> template <typename Arg, Arg Default>
struct TevPass { struct TevPass {
@ -51,25 +54,37 @@ struct TevStage {
GX::ChannelID channelId = GX::COLOR_NULL; GX::ChannelID channelId = GX::COLOR_NULL;
GX::TevSwapSel tevSwapRas = GX::TEV_SWAP0; GX::TevSwapSel tevSwapRas = GX::TEV_SWAP0;
GX::TevSwapSel tevSwapTex = 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; bool operator==(const TevStage&) const = default;
}; };
static_assert(std::has_unique_object_representations_v<TevStage>); static_assert(std::has_unique_object_representations_v<TevStage>);
struct IndStage {
GX::TexCoordID texCoordId;
GX::TexMapID texMapId;
GX::IndTexScale scaleS;
GX::IndTexScale scaleT;
};
static_assert(std::has_unique_object_representations_v<IndStage>);
struct TextureBind { struct TextureBind {
aurora::gfx::TextureHandle handle; GXTexObj texObj;
metaforce::EClampMode clampMode = metaforce::EClampMode::Repeat;
float lod = 0.f;
u32 resolvedBindIdx = UINT32_MAX;
TextureBind() noexcept = default; TextureBind() noexcept = default;
TextureBind(u32 resolvedBindIdx) noexcept : resolvedBindIdx(resolvedBindIdx) {} TextureBind(GXTexObj obj) noexcept : texObj(std::move(obj)) {}
TextureBind(aurora::gfx::TextureHandle handle, metaforce::EClampMode clampMode, float lod) noexcept
: handle(std::move(handle)), clampMode(clampMode), lod(lod) {}
void reset() noexcept { void reset() noexcept {
handle.reset(); texObj.ref.reset();
resolvedBindIdx = UINT32_MAX;
}; };
[[nodiscard]] wgpu::SamplerDescriptor get_descriptor() const noexcept; [[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 // For shader generation
struct ColorChannelConfig { struct ColorChannelConfig {
@ -132,6 +147,10 @@ struct AlphaCompare {
operator bool() const { return *this != AlphaCompare{}; } operator bool() const { return *this != AlphaCompare{}; }
}; };
static_assert(std::has_unique_object_representations_v<AlphaCompare>); static_assert(std::has_unique_object_representations_v<AlphaCompare>);
struct IndTexMtxInfo {
aurora::Mat3x2<float> mtx;
s8 scaleExp;
};
struct GXState { struct GXState {
zeus::CMatrix4f mv; 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_GREEN, GX::CH_GREEN, GX::CH_GREEN, GX::CH_ALPHA},
TevSwap{GX::CH_BLUE, GX::CH_BLUE, GX::CH_BLUE, GX::CH_ALPHA}, TevSwap{GX::CH_BLUE, GX::CH_BLUE, GX::CH_BLUE, GX::CH_ALPHA},
}; };
std::array<IndStage, MaxIndStages> indStages;
std::array<IndTexMtxInfo, MaxIndTexMtxs> indTexMtxs;
bool depthCompare = true; bool depthCompare = true;
bool depthUpdate = true; bool depthUpdate = true;
bool alphaUpdate = true; bool alphaUpdate = true;
@ -179,6 +200,15 @@ static inline Mat4x4<float> get_combined_matrix() noexcept { return g_gxState.pr
void shutdown() noexcept; void shutdown() noexcept;
const TextureBind& get_texture(GX::TexMapID id) 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 { struct ShaderConfig {
GX::FogType fogType; GX::FogType fogType;
std::array<GX::AttrType, MaxVtxAttr> vtxAttrs; std::array<GX::AttrType, MaxVtxAttr> vtxAttrs;
@ -189,12 +219,12 @@ struct ShaderConfig {
std::array<TcgConfig, MaxTexCoord> tcgs; std::array<TcgConfig, MaxTexCoord> tcgs;
AlphaCompare alphaCompare; AlphaCompare alphaCompare;
u32 indexedAttributeCount = 0; u32 indexedAttributeCount = 0;
std::array<bool, MaxTextures> texHasAlpha; std::array<TextureConfig, MaxTextures> textureConfig;
bool operator==(const ShaderConfig&) const = default; bool operator==(const ShaderConfig&) const = default;
}; };
static_assert(std::has_unique_object_representations_v<ShaderConfig>); static_assert(std::has_unique_object_representations_v<ShaderConfig>);
constexpr u32 GXPipelineConfigVersion = 2; constexpr u32 GXPipelineConfigVersion = 3;
struct PipelineConfig { struct PipelineConfig {
u32 version = GXPipelineConfigVersion; u32 version = GXPipelineConfigVersion;
ShaderConfig shaderConfig; ShaderConfig shaderConfig;
@ -222,10 +252,12 @@ struct GXBindGroups {
}; };
// Output info from shader generation // Output info from shader generation
struct ShaderInfo { struct ShaderInfo {
std::bitset<MaxTexCoord> sampledTexCoords;
std::bitset<MaxTextures> sampledTextures; std::bitset<MaxTextures> sampledTextures;
std::bitset<MaxKColors> sampledKColors; std::bitset<MaxKColors> sampledKColors;
std::bitset<MaxColorChannels> sampledColorChannels; std::bitset<MaxColorChannels> sampledColorChannels;
std::bitset<MaxTevRegs> usesTevReg; std::bitset<MaxTevRegs> usesTevReg;
std::bitset<MaxTevRegs> writesTevReg;
std::bitset<MaxTexMtx> usesTexMtx; std::bitset<MaxTexMtx> usesTexMtx;
std::bitset<MaxPTTexMtx> usesPTTexMtx; std::bitset<MaxPTTexMtx> usesPTTexMtx;
std::array<GX::TexGenType, MaxTexMtx> texMtxTypes; std::array<GX::TexGenType, MaxTexMtx> texMtxTypes;

View File

@ -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) { static void color_arg_reg_info(GX::TevColorArg arg, const TevStage& stage, ShaderInfo& info) {
switch (arg) { 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_C0:
case GX::CC_A0: case GX::CC_A0:
info.usesTevReg.set(0); if (!info.writesTevReg.test(GX::TEVREG0)) {
info.usesTevReg.set(GX::TEVREG0);
}
break; break;
case GX::CC_C1: case GX::CC_C1:
case GX::CC_A1: case GX::CC_A1:
info.usesTevReg.set(1); if (!info.writesTevReg.test(GX::TEVREG1)) {
info.usesTevReg.set(GX::TEVREG1);
}
break; break;
case GX::CC_C2: case GX::CC_C2:
case GX::CC_A2: case GX::CC_A2:
info.usesTevReg.set(2); if (!info.writesTevReg.test(GX::TEVREG2)) {
info.usesTevReg.set(GX::TEVREG2);
}
break; break;
case GX::CC_TEXC: case GX::CC_TEXC:
case GX::CC_TEXA: 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); info.sampledTextures.set(stage.texMapId);
break; break;
case GX::CC_RASC: case GX::CC_RASC:
case GX::CC_RASA: 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; break;
case GX::CC_KONST: case GX::CC_KONST:
switch (stage.kcSel) { 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, static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const ShaderConfig& config,
const TevStage& stage) { const TevStage& stage) {
switch (arg) { switch (arg) {
case GX::CC_CPREV: case GX::CC_CPREV:
return "prev.rgb"; return "prev.rgb";
case GX::CC_APREV: case GX::CC_APREV:
return "prev.a"; return "vec3<f32>(prev.a)";
case GX::CC_C0: case GX::CC_C0:
return "tevreg0.rgb"; return "tevreg0.rgb";
case GX::CC_A0: case GX::CC_A0:
return "tevreg0.a"; return "vec3<f32>(tevreg0.a)";
case GX::CC_C1: case GX::CC_C1:
return "tevreg1.rgb"; return "tevreg1.rgb";
case GX::CC_A1: case GX::CC_A1:
return "tevreg1.a"; return "vec3<f32>(tevreg1.a)";
case GX::CC_C2: case GX::CC_C2:
return "tevreg2.rgb"; return "tevreg2.rgb";
case GX::CC_A2: case GX::CC_A2:
return "tevreg2.a"; return "vec3<f32>(tevreg2.a)";
case GX::CC_TEXC: { case GX::CC_TEXC: {
if (stage.texMapId == GX::TEXMAP_NULL) { if (stage.texMapId == GX::TEXMAP_NULL) {
Log.report(logvisor::Fatal, FMT_STRING("unmapped texture for stage {}"), stageIdx); 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]; const auto swap = config.tevSwapTable[stage.tevSwapTex];
// TODO check for CH_ALPHA + config.texHasAlpha // 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)); chan_comp(swap.blue));
} }
case GX::CC_TEXA: { case GX::CC_TEXA: {
@ -133,15 +189,14 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Sha
unreachable(); unreachable();
} }
const auto swap = config.tevSwapTable[stage.tevSwapTex]; const auto swap = config.tevSwapTable[stage.tevSwapTex];
if (swap.alpha == GX::CH_ALPHA && !config.texHasAlpha[stage.texMapId]) { return fmt::format(FMT_STRING("vec3<f32>(sampled{}.{})"), stageIdx, chan_comp(swap.alpha));
return "1.0";
}
return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha));
} }
case GX::CC_RASC: { case GX::CC_RASC: {
if (stage.channelId == GX::COLOR_NULL) { if (stage.channelId == GX::COLOR_NULL) {
Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx); Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx);
unreachable(); unreachable();
} else if (stage.channelId == GX::COLOR_ZERO) {
return "vec3<f32>(0.0)";
} else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) { } else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx); Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx);
unreachable(); 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) { if (stage.channelId == GX::COLOR_NULL) {
Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx); Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx);
unreachable(); unreachable();
} else if (stage.channelId == GX::COLOR_ZERO) {
return "vec3<f32>(0.0)";
} else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) { } else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx); Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx);
unreachable(); unreachable();
} }
u32 idx = stage.channelId - GX::COLOR0A0; u32 idx = stage.channelId - GX::COLOR0A0;
const auto swap = config.tevSwapTable[stage.tevSwapRas]; const auto swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha)); return fmt::format(FMT_STRING("vec3<f32>(rast{}.{})"), idx, chan_comp(swap.alpha));
} }
case GX::CC_ONE: case GX::CC_ONE:
return "1.0"; return "vec3<f32>(1.0)";
case GX::CC_HALF: case GX::CC_HALF:
return "0.5"; return "vec3<f32>(0.5)";
case GX::CC_KONST: { case GX::CC_KONST: {
switch (stage.kcSel) { switch (stage.kcSel) {
case GX::TEV_KCSEL_8_8: case GX::TEV_KCSEL_8_8:
return "1.0"; return "vec3<f32>(1.0)";
case GX::TEV_KCSEL_7_8: case GX::TEV_KCSEL_7_8:
return "(7.0/8.0)"; return "vec3<f32>(7.0/8.0)";
case GX::TEV_KCSEL_6_8: case GX::TEV_KCSEL_6_8:
return "(6.0/8.0)"; return "vec3<f32>(6.0/8.0)";
case GX::TEV_KCSEL_5_8: case GX::TEV_KCSEL_5_8:
return "(5.0/8.0)"; return "vec3<f32>(5.0/8.0)";
case GX::TEV_KCSEL_4_8: case GX::TEV_KCSEL_4_8:
return "(4.0/8.0)"; return "vec3<f32>(4.0/8.0)";
case GX::TEV_KCSEL_3_8: case GX::TEV_KCSEL_3_8:
return "(3.0/8.0)"; return "vec3<f32>(3.0/8.0)";
case GX::TEV_KCSEL_2_8: case GX::TEV_KCSEL_2_8:
return "(2.0/8.0)"; return "vec3<f32>(2.0/8.0)";
case GX::TEV_KCSEL_1_8: case GX::TEV_KCSEL_1_8:
return "(1.0/8.0)"; return "vec3<f32>(1.0/8.0)";
case GX::TEV_KCSEL_K0: case GX::TEV_KCSEL_K0:
return "ubuf.kcolor0.rgb"; return "ubuf.kcolor0.rgb";
case GX::TEV_KCSEL_K1: 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: case GX::TEV_KCSEL_K3:
return "ubuf.kcolor3.rgb"; return "ubuf.kcolor3.rgb";
case GX::TEV_KCSEL_K0_R: case GX::TEV_KCSEL_K0_R:
return "ubuf.kcolor0.r"; return "vec3<f32>(ubuf.kcolor0.r)";
case GX::TEV_KCSEL_K1_R: case GX::TEV_KCSEL_K1_R:
return "ubuf.kcolor1.r"; return "vec3<f32>(ubuf.kcolor1.r)";
case GX::TEV_KCSEL_K2_R: case GX::TEV_KCSEL_K2_R:
return "ubuf.kcolor2.r"; return "vec3<f32>(ubuf.kcolor2.r)";
case GX::TEV_KCSEL_K3_R: case GX::TEV_KCSEL_K3_R:
return "ubuf.kcolor3.r"; return "vec3<f32>(ubuf.kcolor3.r)";
case GX::TEV_KCSEL_K0_G: case GX::TEV_KCSEL_K0_G:
return "ubuf.kcolor0.g"; return "vec3<f32>(ubuf.kcolor0.g)";
case GX::TEV_KCSEL_K1_G: case GX::TEV_KCSEL_K1_G:
return "ubuf.kcolor1.g"; return "vec3<f32>(ubuf.kcolor1.g)";
case GX::TEV_KCSEL_K2_G: case GX::TEV_KCSEL_K2_G:
return "ubuf.kcolor2.g"; return "vec3<f32>(ubuf.kcolor2.g)";
case GX::TEV_KCSEL_K3_G: case GX::TEV_KCSEL_K3_G:
return "ubuf.kcolor3.g"; return "vec3<f32>(ubuf.kcolor3.g)";
case GX::TEV_KCSEL_K0_B: case GX::TEV_KCSEL_K0_B:
return "ubuf.kcolor0.b"; return "vec3<f32>(ubuf.kcolor0.b)";
case GX::TEV_KCSEL_K1_B: case GX::TEV_KCSEL_K1_B:
return "ubuf.kcolor1.b"; return "vec3<f32>(ubuf.kcolor1.b)";
case GX::TEV_KCSEL_K2_B: case GX::TEV_KCSEL_K2_B:
return "ubuf.kcolor2.b"; return "vec3<f32>(ubuf.kcolor2.b)";
case GX::TEV_KCSEL_K3_B: case GX::TEV_KCSEL_K3_B:
return "ubuf.kcolor3.b"; return "vec3<f32>(ubuf.kcolor3.b)";
case GX::TEV_KCSEL_K0_A: case GX::TEV_KCSEL_K0_A:
return "ubuf.kcolor0.a"; return "vec3<f32>(ubuf.kcolor0.a)";
case GX::TEV_KCSEL_K1_A: case GX::TEV_KCSEL_K1_A:
return "ubuf.kcolor1.a"; return "vec3<f32>(ubuf.kcolor1.a)";
case GX::TEV_KCSEL_K2_A: case GX::TEV_KCSEL_K2_A:
return "ubuf.kcolor2.a"; return "vec3<f32>(ubuf.kcolor2.a)";
case GX::TEV_KCSEL_K3_A: case GX::TEV_KCSEL_K3_A:
return "ubuf.kcolor3.a"; return "vec3<f32>(ubuf.kcolor3.a)";
default: default:
Log.report(logvisor::Fatal, FMT_STRING("invalid kcSel {}"), stage.kcSel); Log.report(logvisor::Fatal, FMT_STRING("invalid kcSel {}"), stage.kcSel);
unreachable(); unreachable();
} }
} }
case GX::CC_ZERO: case GX::CC_ZERO:
return "0.0"; return "vec3<f32>(0.0)";
default: default:
Log.report(logvisor::Fatal, FMT_STRING("invalid color arg {}"), arg); Log.report(logvisor::Fatal, FMT_STRING("invalid color arg {}"), arg);
unreachable(); 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) { static void alpha_arg_reg_info(GX::TevAlphaArg arg, const TevStage& stage, ShaderInfo& info) {
switch (arg) { switch (arg) {
case GX::CA_APREV:
if (!info.writesTevReg.test(GX::TEVPREV)) {
info.usesTevReg.set(GX::TEVPREV);
}
break;
case GX::CA_A0: case GX::CA_A0:
info.usesTevReg.set(0); if (!info.writesTevReg.test(GX::TEVREG0)) {
info.usesTevReg.set(GX::TEVREG0);
}
break; break;
case GX::CA_A1: case GX::CA_A1:
info.usesTevReg.set(1); if (!info.writesTevReg.test(GX::TEVREG1)) {
info.usesTevReg.set(GX::TEVREG1);
}
break; break;
case GX::CA_A2: case GX::CA_A2:
info.usesTevReg.set(2); if (!info.writesTevReg.test(GX::TEVREG2)) {
info.usesTevReg.set(GX::TEVREG2);
}
break; break;
case GX::CA_TEXA: 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); info.sampledTextures.set(stage.texMapId);
break; break;
case GX::CA_RASA: 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; break;
case GX::CA_KONST: case GX::CA_KONST:
switch (stage.kaSel) { switch (stage.kaSel) {
@ -310,15 +387,14 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Sha
unreachable(); unreachable();
} }
const auto swap = config.tevSwapTable[stage.tevSwapTex]; const auto swap = config.tevSwapTable[stage.tevSwapTex];
if (swap.alpha == GX::CH_ALPHA && !config.texHasAlpha[stage.texMapId]) { return fmt::format(FMT_STRING("sampled{}.{}"), stageIdx, chan_comp(swap.alpha));
return "1.0";
}
return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha));
} }
case GX::CA_RASA: { case GX::CA_RASA: {
if (stage.channelId == GX::COLOR_NULL) { if (stage.channelId == GX::COLOR_NULL) {
Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx); Log.report(logvisor::Fatal, FMT_STRING("unmapped color channel for stage {}"), stageIdx);
unreachable(); unreachable();
} else if (stage.channelId == GX::COLOR_ZERO) {
return "0.0";
} else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) { } else if (stage.channelId < GX::COLOR0A0 || stage.channelId > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx); Log.report(logvisor::Fatal, FMT_STRING("invalid color channel {} for stage {}"), stage.channelId, stageIdx);
unreachable(); 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) { static std::string_view tev_op(GX::TevOp op) {
switch (op) { switch (op) {
case GX::TEV_ADD: case GX::TEV_ADD:
return "+"; return ""sv;
case GX::TEV_SUB: case GX::TEV_SUB:
return "-"; return "-"sv;
default: default:
Log.report(logvisor::Fatal, FMT_STRING("TODO {}"), op); Log.report(logvisor::Fatal, FMT_STRING("TODO {}"), op);
unreachable(); unreachable();
@ -405,11 +481,11 @@ static std::string_view tev_op(GX::TevOp op) {
static std::string_view tev_bias(GX::TevBias bias) { static std::string_view tev_bias(GX::TevBias bias) {
switch (bias) { switch (bias) {
case GX::TB_ZERO: case GX::TB_ZERO:
return " + 0.0"; return ""sv;
case GX::TB_ADDHALF: case GX::TB_ADDHALF:
return " + 0.5"; return " + 0.5"sv;
case GX::TB_SUBHALF: case GX::TB_SUBHALF:
return " - 0.5"; return " - 0.5"sv;
default: default:
Log.report(logvisor::Fatal, FMT_STRING("invalid bias {}"), bias); Log.report(logvisor::Fatal, FMT_STRING("invalid bias {}"), bias);
unreachable(); unreachable();
@ -420,7 +496,7 @@ static std::string alpha_compare(GX::Compare comp, u8 ref, bool& valid) {
const float fref = ref / 255.f; const float fref = ref / 255.f;
switch (comp) { switch (comp) {
case GX::NEVER: case GX::NEVER:
return "false"; return "false"s;
case GX::LESS: case GX::LESS:
return fmt::format(FMT_STRING("(prev.a < {}f)"), fref); return fmt::format(FMT_STRING("(prev.a < {}f)"), fref);
case GX::LEQUAL: 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); return fmt::format(FMT_STRING("(prev.a > {}f)"), fref);
case GX::ALWAYS: case GX::ALWAYS:
valid = false; valid = false;
return "true"; return "true"s;
default: default:
Log.report(logvisor::Fatal, FMT_STRING("invalid compare {}"), comp); Log.report(logvisor::Fatal, FMT_STRING("invalid compare {}"), comp);
unreachable(); 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) { static std::string_view tev_scale(GX::TevScale scale) {
switch (scale) { switch (scale) {
case GX::CS_SCALE_1: case GX::CS_SCALE_1:
return " * 1.0"; return ""sv;
case GX::CS_SCALE_2: case GX::CS_SCALE_2:
return " * 2.0"; return " * 2.0"sv;
case GX::CS_SCALE_4: case GX::CS_SCALE_4:
return " * 4.0"; return " * 4.0"sv;
case GX::CS_DIVIDE_2: case GX::CS_DIVIDE_2:
return " / 2.0"; return " / 2.0"sv;
default: default:
Log.report(logvisor::Fatal, FMT_STRING("invalid scale {}"), scale); Log.report(logvisor::Fatal, FMT_STRING("invalid scale {}"), scale);
unreachable(); unreachable();
@ -463,16 +539,16 @@ static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) {
if (type == GX::NONE) { if (type == GX::NONE) {
if (attr == GX::VA_NRM) { if (attr == GX::VA_NRM) {
// Default normal // Default normal
return "vec3<f32>(1.0, 0.0, 0.0)"; return "vec3<f32>(1.0, 0.0, 0.0)"s;
} }
Log.report(logvisor::Fatal, FMT_STRING("unmapped attr {}"), attr); Log.report(logvisor::Fatal, FMT_STRING("unmapped attr {}"), attr);
unreachable(); unreachable();
} }
if (attr == GX::VA_POS) { if (attr == GX::VA_POS) {
return "in_pos"; return "in_pos"s;
} }
if (attr == GX::VA_NRM) { if (attr == GX::VA_NRM) {
return "in_nrm"; return "in_nrm"s;
} }
if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) { if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) {
const auto idx = attr - GX::VA_CLR0; const auto idx = attr - GX::VA_CLR0;
@ -486,6 +562,36 @@ static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) {
unreachable(); 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<f32>(intensity);"
"\n }}"),
stageIdx);
break;
}
return out;
}
constexpr std::array<std::string_view, GX::TevColorArg::CC_ZERO + 1> 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<std::string_view, GX::TevAlphaArg::CA_ZERO + 1> TevAlphaArgNames{
"APREV"sv, "A0"sv, "A1"sv, "A2"sv, "TEXA"sv, "RASA"sv, "KONST"sv, "ZERO"sv,
};
constexpr std::array<std::string_view, MaxVtxAttr> VtxAttributeNames{ constexpr std::array<std::string_view, MaxVtxAttr> VtxAttributeNames{
"pn_mtx", "tex0_mtx", "tex1_mtx", "tex2_mtx", "tex3_mtx", "tex4_mtx", "tex5_mtx", "pn_mtx", "tex0_mtx", "tex1_mtx", "tex2_mtx", "tex3_mtx", "tex4_mtx", "tex5_mtx",
"tex6_mtx", "tex7_mtx", "pos", "nrm", "clr0", "clr1", "tex0_uv", "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) { for (int i = 0; i < config.tevStageCount; ++i) {
const auto& stage = config.tevStages[i]; const auto& stage = config.tevStages[i];
// Color pass // 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.a, stage, info);
color_arg_reg_info(stage.colorPass.b, 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.c, stage, info);
color_arg_reg_info(stage.colorPass.d, stage, info); color_arg_reg_info(stage.colorPass.d, stage, info);
info.writesTevReg.set(stage.colorOp.outReg);
// Alpha pass // 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.a, stage, info);
alpha_arg_reg_info(stage.alphaPass.b, 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.c, stage, info);
alpha_arg_reg_info(stage.alphaPass.d, 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; info.uniformSize += info.usesTevReg.count() * 16;
for (int i = 0; i < info.sampledColorChannels.size(); ++i) { 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) { for (int i = 0; i < config.tevStageCount; ++i) {
const auto& stage = config.tevStages[i]; const auto& stage = config.tevStages[i];
Log.report(logvisor::Info, FMT_STRING(" 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_a: {}"), TevColorArgNames[stage.colorPass.a]);
Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage.colorPass.b); Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), TevColorArgNames[stage.colorPass.b]);
Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage.colorPass.c); Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), TevColorArgNames[stage.colorPass.c]);
Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage.colorPass.d); Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), TevColorArgNames[stage.colorPass.d]);
Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage.alphaPass.a); Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), TevAlphaArgNames[stage.alphaPass.a]);
Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage.alphaPass.b); Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), TevAlphaArgNames[stage.alphaPass.b]);
Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage.alphaPass.c); Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), TevAlphaArgNames[stage.alphaPass.c]);
Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage.alphaPass.d); 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_clamp: {}"), stage.colorOp.clamp);
Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage.colorOp.op); Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage.colorOp.op);
Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage.colorOp.bias); Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage.colorOp.bias);
@ -652,12 +739,6 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
config.alphaCompare.ref1); config.alphaCompare.ref1);
Log.report(logvisor::Info, FMT_STRING(" indexedAttributeCount: {}"), config.indexedAttributeCount); Log.report(logvisor::Info, FMT_STRING(" indexedAttributeCount: {}"), config.indexedAttributeCount);
Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType); 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); Log.report(logvisor::Fatal, FMT_STRING("invalid colorOp outReg {}"), stage.colorOp.outReg);
} }
std::string op = fmt::format( std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), FMT_STRING("(({4}mix({0}, {1}, {2}) + {3}){5}){6}"), color_arg_reg(stage.colorPass.a, idx, config, stage),
color_arg_reg(stage.colorPass.a, idx, config, stage), color_arg_reg(stage.colorPass.b, 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.c, idx, config, stage), color_arg_reg(stage.colorPass.d, idx, config, stage), color_arg_reg(stage.colorPass.d, idx, config, stage), tev_op(stage.colorOp.op), tev_bias(stage.colorOp.bias),
tev_op(stage.colorOp.op), tev_bias(stage.colorOp.bias), tev_scale(stage.colorOp.scale)); tev_scale(stage.colorOp.scale));
if (stage.colorOp.clamp) { if (stage.colorOp.clamp) {
op = fmt::format(FMT_STRING("clamp(vec3<f32>({}), vec3<f32>(0.0), vec3<f32>(1.0))"), op); op = fmt::format(FMT_STRING("clamp({}, vec3<f32>(0.0), vec3<f32>(1.0))"), op);
} }
fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4<f32>({1}, {0}.a);"), outReg, op); fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4<f32>({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); Log.report(logvisor::Fatal, FMT_STRING("invalid alphaOp outReg {}"), stage.alphaOp.outReg);
} }
std::string op = fmt::format( std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), FMT_STRING("(({4}mix({0}, {1}, {2}) + {3}){5}){6}"), alpha_arg_reg(stage.alphaPass.a, idx, config, stage),
alpha_arg_reg(stage.alphaPass.a, idx, config, stage), alpha_arg_reg(stage.alphaPass.b, 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.c, idx, config, stage), alpha_arg_reg(stage.alphaPass.d, idx, config, stage), alpha_arg_reg(stage.alphaPass.d, idx, config, stage), tev_op(stage.alphaOp.op), tev_bias(stage.alphaOp.bias),
tev_op(stage.alphaOp.op), tev_bias(stage.alphaOp.bias), tev_scale(stage.alphaOp.scale)); tev_scale(stage.alphaOp.scale));
if (stage.alphaOp.clamp) { if (stage.alphaOp.clamp) {
op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op); op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op);
} }
fragmentFn += fmt::format(FMT_STRING("\n {0} = {1};"), outReg, 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<f32>,";
fragmentFnPre += "\n var prev = ubuf.tevprev;";
} else {
fragmentFnPre += "\n var prev: vec4<f32>;";
}
for (int i = 1 /* Skip TEVPREV */; i < info.usesTevReg.size(); ++i) {
if (info.usesTevReg.test(i)) { if (info.usesTevReg.test(i)) {
uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4<f32>,"), i); uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4<f32>,"), i - 1);
fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i); 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<f32>;"), i - 1);
} }
} }
bool addedLightStruct = false; 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<f32>,"), i); uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4<f32>,"), i);
} }
} }
size_t texBindIdx = 0; for (int i = 0; i < info.sampledTexCoords.size(); ++i) {
for (int i = 0; i < info.sampledTextures.size(); ++i) { if (!info.sampledTexCoords.test(i)) {
if (!info.sampledTextures.test(i)) {
continue; continue;
} }
const auto& tcg = config.tcgs[i]; 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) { } else if (tcg.src == GX::TG_NRM) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(in_nrm, 1.0);"), i); vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(in_nrm, 1.0);"), i);
} else { } 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(); unreachable();
} }
// TODO this all assumes MTX3x4 currently // TODO this all assumes MTX3x4 currently
@ -953,15 +1041,27 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
i, postMtxIdx); i, postMtxIdx);
} }
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i); 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 for (int i = 0; i < config.tevStages.size(); ++i) {
if (config.texHasAlpha[i]) { const auto& stage = config.tevStages[i];
uvIn = fmt::format(FMT_STRING("in.tex{0}_uv"), i); if (stage.texMapId == GX::TEXMAP_NULL ||
} else { stage.texCoordId == GX::TEXCOORD_NULL
uvIn = fmt::format(FMT_STRING("vec2<f32>(in.tex{0}_uv.x, -in.tex{0}_uv.y)"), i); // TODO should check this per-stage probably
|| !info.sampledTextures.test(stage.texMapId)) {
continue;
} }
fragmentFnPre += fmt::format( std::string uvIn;
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, {1}, ubuf.tex{0}_lod);"), i, uvIn); const auto& texConfig = config.textureConfig[stage.texMapId];
// TODO
// if (texConfig.flipUV) {
// uvIn = fmt::format(FMT_STRING("vec2<f32>(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) { for (int i = 0; i < info.usesTexMtx.size(); ++i) {
if (info.usesTexMtx.test(i)) { if (info.usesTexMtx.test(i)) {
@ -1025,6 +1125,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
} }
fragmentFn += "\n prev = vec4<f32>(mix(prev.rgb, ubuf.fog.color.rgb, clamp(fogZ, 0.0, 1.0)), prev.a);"; fragmentFn += "\n prev = vec4<f32>(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) { for (int i = 0; i < info.sampledTextures.size(); ++i) {
if (!info.sampledTextures.test(i)) { if (!info.sampledTextures.test(i)) {
continue; continue;
@ -1091,8 +1192,7 @@ fn vs_main({vtxInAttrs}
}} }}
@stage(fragment) @stage(fragment)
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {{ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {{{fragmentFnPre}{fragmentFn}
var prev: vec4<f32>;{fragmentFnPre}{fragmentFn}
return prev; return prev;
}} }}
)"""), )"""),

View File

@ -40,6 +40,14 @@ static inline void read_vert(ByteBuffer& out, const u8* data) noexcept {
static absl::flat_hash_map<XXH64_hash_t, std::pair<ByteBuffer, ByteBuffer>> sCachedDisplayLists; static absl::flat_hash_map<XXH64_hash_t, std::pair<ByteBuffer, ByteBuffer>> sCachedDisplayLists;
void queue_surface(const u8* dlStart, u32 dlSize) noexcept { 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); const auto hash = xxh3_hash_s(dlStart, dlSize, 0);
Range vertRange, idxRange; Range vertRange, idxRange;
u32 numIndices = 0; u32 numIndices = 0;
@ -55,7 +63,11 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept {
u8 inVtxSize = 0; u8 inVtxSize = 0;
u8 outVtxSize = 0; u8 outVtxSize = 0;
for (const auto& type : gx::g_gxState.vtxDesc) { 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; continue;
} }
if (type == GX::INDEX8) { if (type == GX::INDEX8) {

View File

@ -207,15 +207,15 @@ DrawData make_draw_data(const State& state, const TextureHandle& tex_y, const Te
const std::array entries{ const std::array entries{
wgpu::BindGroupEntry{ wgpu::BindGroupEntry{
.binding = 0, .binding = 0,
.textureView = tex_y.ref->view, .textureView = tex_y->view,
}, },
wgpu::BindGroupEntry{ wgpu::BindGroupEntry{
.binding = 1, .binding = 1,
.textureView = tex_u.ref->view, .textureView = tex_u->view,
}, },
wgpu::BindGroupEntry{ wgpu::BindGroupEntry{
.binding = 2, .binding = 2,
.textureView = tex_v.ref->view, .textureView = tex_v->view,
}, },
}; };
const auto textureBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{ const auto textureBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{

View File

@ -38,14 +38,14 @@ static wgpu::Extent3D physical_size(wgpu::Extent3D size, TextureFormatInfo info)
return {width, height, size.depthOrArrayLayers}; 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<uint8_t> data, zstring_view label) noexcept { ArrayRef<uint8_t> data, zstring_view label) noexcept {
auto handle = new_dynamic_texture_2d(width, height, mips, format, label); auto handle = new_dynamic_texture_2d(width, height, mips, format, label);
const TextureRef& ref = *handle.ref; const auto& ref = *handle;
ByteBuffer buffer; ByteBuffer buffer;
if (ref.gameFormat != metaforce::ETexelFormat::Invalid) { if (ref.gxFormat != InvalidTextureFormat) {
buffer = convert_texture(ref.gameFormat, ref.size.width, ref.size.height, ref.mipCount, data); buffer = convert_texture(ref.gxFormat, ref.size.width, ref.size.height, ref.mipCount, data);
if (!buffer.empty()) { if (!buffer.empty()) {
data = {buffer.data(), buffer.size()}; 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; 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 { zstring_view label) noexcept {
const auto wgpuFormat = to_wgpu(format); const auto wgpuFormat = to_wgpu(format);
const auto size = wgpu::Extent3D{ 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 texture = g_device.CreateTexture(&textureDescriptor);
auto textureView = texture.CreateView(&textureViewDescriptor); auto textureView = texture.CreateView(&textureViewDescriptor);
return {std::make_shared<TextureRef>(std::move(texture), std::move(textureView), size, wgpuFormat, mips, format)}; return std::make_shared<TextureRef>(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 wgpuFormat = gpu::g_graphicsConfig.colorFormat;
const auto size = wgpu::Extent3D{ const auto size = wgpu::Extent3D{
.width = width, .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 texture = g_device.CreateTexture(&textureDescriptor);
auto textureView = texture.CreateView(&textureViewDescriptor); auto textureView = texture.CreateView(&textureViewDescriptor);
return {std::make_shared<TextureRef>(std::move(texture), std::move(textureView), size, wgpuFormat, 1, return std::make_shared<TextureRef>(std::move(texture), std::move(textureView), size, wgpuFormat, 1, fmt, true);
metaforce::ETexelFormat::Invalid)};
} }
// TODO accept mip/layer parameters // TODO accept mip/layer parameters
void write_texture(const TextureHandle& handle, ArrayRef<uint8_t> data) noexcept { void write_texture(const TextureRef& ref, ArrayRef<uint8_t> data) noexcept {
const TextureRef& ref = *handle.ref;
ByteBuffer buffer; ByteBuffer buffer;
if (ref.gameFormat != metaforce::ETexelFormat::Invalid) { if (ref.gxFormat != InvalidTextureFormat) {
buffer = convert_texture(ref.gameFormat, ref.size.width, ref.size.height, ref.mipCount, data); buffer = convert_texture(ref.gxFormat, ref.size.width, ref.size.height, ref.mipCount, data);
if (!buffer.empty()) { if (!buffer.empty()) {
data = {buffer.data(), buffer.size()}; data = {buffer.data(), buffer.size()};
} }

View File

@ -491,41 +491,38 @@ ByteBuffer BuildDXT1FromGCN(uint32_t width, uint32_t height, uint32_t mips, Arra
return buf; 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<uint8_t> data) { ArrayRef<uint8_t> data) {
switch (format) { switch (format) {
case metaforce::ETexelFormat::RGBA8PC: default:
case metaforce::ETexelFormat::R8PC: Log.report(logvisor::Fatal, FMT_STRING("convert_texture: unknown format supplied {}"), format);
return {};
case metaforce::ETexelFormat::Invalid:
Log.report(logvisor::Fatal, FMT_STRING("convert_texture: invalid format supplied"));
unreachable(); unreachable();
case metaforce::ETexelFormat::I4: case GX::TF_I4:
return BuildI4FromGCN(width, height, mips, data); return BuildI4FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::I8: case GX::TF_I8:
return BuildI8FromGCN(width, height, mips, data); return BuildI8FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::IA4: case GX::TF_IA4:
return BuildIA4FromGCN(width, height, mips, data); return BuildIA4FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::IA8: case GX::TF_IA8:
return BuildIA8FromGCN(width, height, mips, data); return BuildIA8FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::C4: case GX::TF_C4:
Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C4 unimplemented")); Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C4 unimplemented"));
unreachable(); unreachable();
// return BuildC4FromGCN(width, height, mips, data); // return BuildC4FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::C8: case GX::TF_C8:
Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C8 unimplemented")); Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C8 unimplemented"));
unreachable(); unreachable();
// return BuildC8FromGCN(width, height, mips, data); // return BuildC8FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::C14X2: case GX::TF_C14X2:
Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C14X2 unimplemented")); Log.report(logvisor::Fatal, FMT_STRING("convert_texture: C14X2 unimplemented"));
unreachable(); unreachable();
case metaforce::ETexelFormat::RGB565: case GX::TF_RGB565:
return BuildRGB565FromGCN(width, height, mips, data); return BuildRGB565FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::RGB5A3: case GX::TF_RGB5A3:
return BuildRGB5A3FromGCN(width, height, mips, data); return BuildRGB5A3FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::RGBA8: case GX::TF_RGBA8:
return BuildRGBA8FromGCN(width, height, mips, data); return BuildRGBA8FromGCN(width, height, mips, data);
case metaforce::ETexelFormat::CMPR: case GX::TF_CMPR:
if (gpu::g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC)) { if (gpu::g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {
return BuildDXT1FromGCN(width, height, mips, data); return BuildDXT1FromGCN(width, height, mips, data);
} else { } else {

View File

@ -5,12 +5,12 @@
#include "../gpu.hpp" #include "../gpu.hpp"
namespace aurora::gfx { namespace aurora::gfx {
static wgpu::TextureFormat to_wgpu(metaforce::ETexelFormat format) { static wgpu::TextureFormat to_wgpu(GX::TextureFormat format) {
switch (format) { switch (format) {
case metaforce::ETexelFormat::C8: case GX::TF_C8:
case metaforce::ETexelFormat::R8PC: case GX::TF_I8:
return wgpu::TextureFormat::R8Unorm; return wgpu::TextureFormat::R8Unorm;
case metaforce::ETexelFormat::CMPR: case GX::TF_CMPR:
if (gpu::g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC)) { if (gpu::g_device.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {
return wgpu::TextureFormat::BC1RGBAUnorm; 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<uint8_t> data); ArrayRef<uint8_t> data);
} // namespace aurora::gfx } // namespace aurora::gfx