mirror of https://github.com/AxioDL/metaforce.git
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:
parent
22256228fb
commit
22dfd3b3f7
|
@ -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;
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
} // namespace metaforce
|
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}}
|
}}
|
||||||
)"""),
|
)"""),
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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{
|
||||||
|
|
|
@ -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()};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue