Implement CGX & migrate usages to CGX/GX

This commit is contained in:
Luke Street 2022-03-12 10:47:20 -05:00
parent 929bb65417
commit a3d0da44e2
31 changed files with 1560 additions and 912 deletions

View File

@ -23,6 +23,7 @@
#include "Runtime/Character/CTransitionManager.hpp"
#include "Runtime/Character/IAnimReader.hpp"
#include "Runtime/Graphics/CSkinnedModel.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include <logvisor/logvisor.hpp>
@ -559,7 +560,7 @@ void CAnimData::SetupRender(CSkinnedModel& model, CVertexMorphEffect* morphEffec
}
void CAnimData::DrawSkinnedModel(CSkinnedModel& model, const CModelFlags& flags) {
aurora::gfx::set_chan_mat_src(GX::COLOR0A0, GX::SRC_REG);
CGX::SetChanCtrl(CGX::EChannelId::Channel0, CGraphics::g_LightActive);
model.Draw(flags);
}

View File

@ -422,12 +422,12 @@ void CModelData::MultiPassDraw(EWhichModel which, const zeus::CTransform& xf, co
}
}
void CModelData::DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, const CTexture& tex,
void CModelData::DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, CTexture& tex,
const zeus::CColor& addColor, float t) {
DisintegrateDraw(GetRenderingModel(mgr), xf, tex, addColor, t);
}
void CModelData::DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, const CTexture& tex,
void CModelData::DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, CTexture& tex,
const zeus::CColor& addColor, float t) {
zeus::CTransform scaledXf = xf * zeus::CTransform::Scale(x0_scale);
CGraphics::SetModelMatrix(scaledXf);
@ -435,27 +435,13 @@ void CModelData::DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf,
const auto aabb = GetBounds(scaledXf);
if (x10_animData) {
auto& model = PickAnimatedModel(which);
// x10_animData->SetupRender(model, CModelFlags{}, {}, ?)
model.DoDrawCallback([](auto positions, auto normals) {
// TODO
x10_animData->SetupRender(model, nullptr, nullptr);
model.DoDrawCallback([&](auto positions, auto normals) {
g_Renderer->DrawModelDisintegrate(*model.GetModel(), tex, addColor, positions, normals, t);
});
} else {
g_Renderer->DrawModelDisintegrate(*PickStaticModel(which), tex, addColor, {}, {});
g_Renderer->DrawModelDisintegrate(*PickStaticModel(which), tex, addColor, nullptr, nullptr, t);
}
// CBooModel::SetDisintegrateTexture(tex.GetTexture());
// CModelFlags flags(5, 0, 3, zeus::skWhite);
// flags.m_extendedShader = EExtendedShader::Disintegrate;
// flags.addColor = addColor;
// flags.addColor.a() = t; // Stash T value in here (shader does not care)
//
// if (x10_animData) {
// CSkinnedModel& sModel = PickAnimatedModel(which);
// x10_animData->Render(sModel, flags, std::nullopt, nullptr);
// } else {
// CBooModel& model = *PickStaticModel(which);
// model.Draw(flags, nullptr, nullptr);
// }
}
void CModelData::ThermalDraw(const zeus::CColor& mulColor, const zeus::CColor& addColor, const CModelFlags& flags) {}

View File

@ -126,10 +126,10 @@ public:
const zeus::CColor& alphaColor, const zeus::CColor& additiveColor);
void MultiPassDraw(EWhichModel which, const zeus::CTransform& xf, const CActorLights* lights,
const CModelFlags* flags, u32 count);
void DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, const CTexture& tex,
const zeus::CColor& addColor, float t);
void DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, const CTexture& tex,
void DisintegrateDraw(const CStateManager& mgr, const zeus::CTransform& xf, CTexture& tex,
const zeus::CColor& addColor, float t);
void DisintegrateDraw(EWhichModel which, const zeus::CTransform& xf, CTexture& tex, const zeus::CColor& addColor,
float t);
void ThermalDraw(const zeus::CColor& mulColor, const zeus::CColor& addColor, const CModelFlags& flags);
CAnimData* GetAnimationData() { return x10_animData.get(); }

View File

@ -4,10 +4,9 @@
#include "Graphics/CCubeModel.hpp"
#include "Graphics/CCubeRenderer.hpp"
#include "Graphics/CCubeSurface.hpp"
#include "Graphics/CGX.hpp"
#include "Graphics/CModel.hpp"
#include <aurora/model.hpp>
namespace metaforce {
static u32 sReflectionType = 0;
static u32 sLastMaterialUnique = UINT32_MAX;
@ -68,7 +67,7 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur
sLastMaterialUnique = groupIdx;
u32 vatFlags = SBig(*reinterpret_cast<const u32*>(materialDataCur));
aurora::gfx::model::set_vtx_desc_compressed(vatFlags);
CGX::SetVtxDescv_Compressed(vatFlags);
materialDataCur += 8;
bool packedLightMaps = matFlags.IsSet(CCubeMaterialFlagBits::fLightmapUvArray);
@ -84,14 +83,14 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur
for (u32 i = 0; i < konstCount; ++i) {
u32 kColor = SBig(*reinterpret_cast<const u32*>(materialDataCur));
materialDataCur += 4;
aurora::gfx::set_tev_k_color(static_cast<GX::TevKColorID>(i), kColor);
CGX::SetTevKColor(static_cast<GX::TevKColorID>(i), kColor);
}
}
u32 blendFactors = SBig(*reinterpret_cast<const u32*>(materialDataCur));
materialDataCur += 4;
if (g_Renderer->IsInAreaDraw()) {
// TODO blackout fog, additive blend
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ONE, GX::LO_CLEAR);
} else {
SetupBlendMode(blendFactors, flags, matFlags.IsSet(CCubeMaterialFlagBits::fAlphaTest));
}
@ -135,7 +134,7 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur
materialDataCur += 20;
texMapTexCoordFlags += 1;
finalCCFlags = SBig(*reinterpret_cast<const u32*>(materialDataCur + 8));
aurora::gfx::set_tev_reg_color(GX::TEVREG0, 0xc0c0c0c0);
GXSetTevColor(GX::TEVREG0, 0xc0c0c0c0);
}
finalACFlags = SBig(*reinterpret_cast<const u32*>(materialDataCur + 12));
HandleTev(firstTev, reinterpret_cast<const u32*>(materialDataCur), texMapTexCoordFlags,
@ -219,10 +218,10 @@ void CCubeMaterial::SetCurrent(const CModelFlags& flags, const CCubeSurface& sur
tcgCount += 1;
}
// SetNumIndStages(numIndStages);
aurora::gfx::disable_tev_stage(static_cast<ERglTevStage>(finalTevCount));
// SetNumTexGens(tcgCount);
// SetNumColorChans(finalNumColorChans);
CGX::SetNumIndStages(numIndStages);
CGX::SetNumTevStages(finalTevCount);
CGX::SetNumTexGens(tcgCount);
CGX::SetNumChans(finalNumColorChans);
}
void CCubeMaterial::SetCurrentBlack() {
@ -230,50 +229,47 @@ void CCubeMaterial::SetCurrentBlack() {
auto vatFlags = GetVatFlags();
if (flags.IsSet(CCubeMaterialFlagBits::fDepthSorting) || flags.IsSet(CCubeMaterialFlagBits::fAlphaTest)) {
// set fog mode 0x21
aurora::gfx::set_blend_mode(ERglBlendMode::Blend, ERglBlendFactor::Zero, ERglBlendFactor::One, ERglLogicOp::Clear);
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ZERO, GX::BL_ONE, GX::LO_CLEAR);
} else {
// set fog mode 5
aurora::gfx::set_blend_mode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::Zero, ERglLogicOp::Clear);
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR);
}
// set vtx desc flags
// TODO
}
void CCubeMaterial::SetupBlendMode(u32 blendFactors, const CModelFlags& flags, bool alphaTest) {
auto newSrcFactor = static_cast<ERglBlendFactor>(blendFactors & 0xffff);
auto newDstFactor = static_cast<ERglBlendFactor>(blendFactors >> 16 & 0xffff);
auto newSrcFactor = static_cast<GX::BlendFactor>(blendFactors & 0xffff);
auto newDstFactor = static_cast<GX::BlendFactor>(blendFactors >> 16 & 0xffff);
if (alphaTest) {
// discard fragments with alpha < 0.25
aurora::gfx::set_alpha_discard(true);
newSrcFactor = ERglBlendFactor::One;
newDstFactor = ERglBlendFactor::Zero;
CGX::SetAlphaCompare(GX::GEQUAL, 64, GX::AOP_OR, GX::NEVER, 0);
newSrcFactor = GX::BL_ONE;
newDstFactor = GX::BL_ZERO;
} else {
aurora::gfx::set_alpha_discard(false);
CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_OR, GX::ALWAYS, 0);
}
if (flags.x0_blendMode > 4 && newSrcFactor == ERglBlendFactor::One) {
newSrcFactor = ERglBlendFactor::SrcAlpha;
if (newDstFactor == ERglBlendFactor::Zero) {
newDstFactor = flags.x0_blendMode > 6 ? ERglBlendFactor::One : ERglBlendFactor::InvSrcAlpha;
if (flags.x0_blendMode > 4 && newSrcFactor == GX::BL_ONE) {
newSrcFactor = GX::BL_SRCALPHA;
if (newDstFactor == GX::BL_ZERO) {
newDstFactor = flags.x0_blendMode > 6 ? GX::BL_ONE : GX::BL_INVSRCALPHA;
}
}
// TODO set fog color zero if dst blend zero
aurora::gfx::set_blend_mode(ERglBlendMode::Blend, newSrcFactor, newDstFactor, ERglLogicOp::Clear);
CGX::SetBlendMode(GX::BM_BLEND, newSrcFactor, newDstFactor, GX::LO_CLEAR);
}
void CCubeMaterial::HandleDepth(CModelFlagsFlags modelFlags, CCubeMaterialFlags matFlags) {
ERglEnum func = ERglEnum::Never;
GX::Compare func = GX::NEVER;
if (!(modelFlags & CModelFlagBits::DepthTest)) {
func = ERglEnum::Always;
func = GX::ALWAYS;
} else if (modelFlags & CModelFlagBits::DepthGreater) {
func = modelFlags & CModelFlagBits::DepthNonInclusive ? ERglEnum::Greater : ERglEnum::GEqual;
func = modelFlags & CModelFlagBits::DepthNonInclusive ? GX::GREATER : GX::GEQUAL;
} else {
func = modelFlags & CModelFlagBits::DepthNonInclusive ? ERglEnum::Less : ERglEnum::LEqual;
func = modelFlags & CModelFlagBits::DepthNonInclusive ? GX::LESS : GX::LEQUAL;
}
bool depthWrite = modelFlags & CModelFlagBits::DepthUpdate && matFlags & CCubeMaterialFlagBits::fDepthWrite;
aurora::gfx::set_depth_mode(true, func, depthWrite);
CGX::SetZMode(true, func, depthWrite);
}
void CCubeMaterial::ResetCachedMaterials() {
@ -305,39 +301,40 @@ void CCubeMaterial::EnsureViewDepStateCached(const CCubeSurface* surface) {
u32 CCubeMaterial::HandleColorChannels(u32 chanCount, u32 firstChan) {
if (CCubeModel::sRenderModelShadow) {
if (chanCount != 0) {
aurora::gfx::set_chan_amb_color(GX::COLOR1A1, zeus::skBlack);
aurora::gfx::set_chan_mat_color(GX::COLOR1A1, zeus::skWhite);
CGX::SetChanAmbColor(CGX::EChannelId::Channel1, zeus::skBlack);
CGX::SetChanMatColor(CGX::EChannelId::Channel1, zeus::skWhite);
// TODO chan / lights
aurora::gfx::set_chan_mat_color(GX::COLOR0A0, zeus::skWhite);
auto chan0Lights = CGraphics::g_LightActive & ~CCubeModel::sChannel0DisableLightMask;
CGX::SetChanCtrl(CGX::EChannelId::Channel0, chan0Lights); // TODO use firstChan flags
CGX::SetChanCtrl(CGX::EChannelId::Channel1, CCubeModel::sChannel1EnableLightMask);
if (chan0Lights.any()) {
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
} else {
CGX::SetChanMatColor(CGX::EChannelId::Channel0, CGX::GetChanAmbColor(CGX::EChannelId::Channel0));
}
}
return 2;
}
if (chanCount == 2) {
aurora::gfx::set_chan_amb_color(GX::COLOR1A1, zeus::skBlack);
aurora::gfx::set_chan_mat_color(GX::COLOR1A1, zeus::skWhite);
CGX::SetChanAmbColor(CGX::EChannelId::Channel1, zeus::skBlack);
CGX::SetChanMatColor(CGX::EChannelId::Channel1, zeus::skWhite);
} else {
// TODO chan ctrls
CGX::SetChanCtrl(CGX::EChannelId::Channel1, {});
}
if (chanCount == 0) {
// TODO more chan ctrls
CGX::SetChanCtrl(CGX::EChannelId::Channel0, {});
} else {
auto uVar3 = firstChan & 0xfffffffe;
// TODO enabled lights
// TODO chan ctrl
// if (sEnabledLights == 0) {
// aurora::gfx::set_chan_mat_color(GX::COLOR0A0, amb_clr);
// } else {
aurora::gfx::set_chan_mat_color(GX::COLOR0A0, zeus::skWhite);
// }
// TODO use firstChan flags
CGX::SetChanCtrl(CGX::EChannelId::Channel0, CGraphics::g_LightActive);
if (CGraphics::g_LightActive.any()) {
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
} else {
CGX::SetChanMatColor(CGX::EChannelId::Channel0, CGX::GetChanAmbColor(CGX::EChannelId::Channel0));
}
}
// TODO
aurora::gfx::set_chan_mat_src(GX::COLOR0A0, GX::SRC_REG);
aurora::gfx::set_chan_mat_src(GX::COLOR1A1, GX::SRC_REG);
return chanCount;
}
@ -348,27 +345,15 @@ void CCubeMaterial::HandleTev(u32 tevCur, const u32* materialDataCur, const u32*
const u32 colorOps = SBig(materialDataCur[2]);
const u32 alphaOps = SBig(materialDataCur[3]);
// GXSetTevDirect(tevCur);
const CTevCombiners::ColorPass colPass{colorArgs};
const CTevCombiners::AlphaPass alphaPass{alphaArgs};
const CTevCombiners::CTevOp colorOp{colorOps};
const CTevCombiners::CTevOp alphaOp{alphaOps};
// TODO does this actually change anything?
// if (colorOps == alphaOps && ((colorOps & 0x1FF) == 0x100)) {
// colorOp = {true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, colorOp.x10_regId};
// alphaOp = {true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, colorOp.x10_regId};
// }
aurora::gfx::update_tev_stage(static_cast<ERglTevStage>(tevCur), colPass, alphaPass, colorOp, alphaOp);
const auto stage = static_cast<GX::TevStageID>(tevCur);
CGX::SetStandardDirectTev_Compressed(stage, colorArgs, alphaArgs, colorOps, alphaOps);
u32 tmtcFlags = SBig(*texMapTexCoordFlags);
u32 matFlags = SBig(materialDataCur[4]);
aurora::gfx::set_tev_order(static_cast<GX::TevStageID>(tevCur), static_cast<GX::TexCoordID>(tmtcFlags & 0xFF),
static_cast<GX::TexMapID>(tmtcFlags >> 8 & 0xFF),
static_cast<GX::ChannelID>(matFlags & 0xFF));
aurora::gfx::set_tev_k_color_sel(static_cast<GX::TevStageID>(tevCur),
static_cast<GX::TevKColorSel>(matFlags >> 0x8 & 0xFF));
aurora::gfx::set_tev_k_alpha_sel(static_cast<GX::TevStageID>(tevCur),
static_cast<GX::TevKAlphaSel>(matFlags >> 0x10 & 0xFF));
CGX::SetTevOrder(stage, static_cast<GX::TexCoordID>(tmtcFlags & 0xFF),
static_cast<GX::TexMapID>(tmtcFlags >> 8 & 0xFF), static_cast<GX::ChannelID>(matFlags & 0xFF));
CGX::SetTevKColorSel(stage, static_cast<GX::TevKColorSel>(matFlags >> 0x8 & 0xFF));
CGX::SetTevKAlphaSel(stage, static_cast<GX::TevKAlphaSel>(matFlags >> 0x10 & 0xFF));
}
u32 CCubeMaterial::HandleAnimatedUV(const u32* uvAnim, u32 texMtx, u32 pttTexMtx) {
@ -405,76 +390,56 @@ void CCubeMaterial::HandleTransparency(u32& finalTevCount, u32& finalKColorCount
u32 blendFactors, u32& finalCCFlags, u32& finalACFlags) {
if (modelFlags.x0_blendMode == 2) {
u16 dstFactor = blendFactors >> 16 & 0xffff;
if (dstFactor == 1)
if (dstFactor == 1) {
return;
}
}
if (modelFlags.x0_blendMode == 3) {
// Stage outputting splatted KAlpha as color to reg0
aurora::gfx::update_tev_stage(static_cast<ERglTevStage>(finalTevCount),
CTevCombiners::ColorPass{GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_KONST},
CTevCombiners::AlphaPass{GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV},
CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVREG0},
CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVPREV});
// GXSetTevColorIn(finalTevCount, TEVCOLORARG_ZERO, TEVCOLORARG_ZERO, TEVCOLORARG_ZERO, TEVCOLORARG_KONST);
// GXSetTevAlphaIn(finalTevCount, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_APREV);
// GXSetTevColorOp(finalTevCount, 0, 0, 0, 1, 1); // ColorReg0
aurora::gfx::set_tev_k_color_sel(static_cast<GX::TevStageID>(finalTevCount),
static_cast<GX::TevKColorSel>(finalKColorCount + GX::TEV_KCSEL_K0_A));
// GXSetTevKColorSel(finalTevCount, finalKColorCount+28);
// GXSetTevAlphaOp(finalTevCount, 0, 0, 0, 1, 0); // AlphaRegPrev
// GXSetTevOrder(finalTevCount, 255, 255, 255);
// GXSetTevDirect(finalTevCount);
auto stage = static_cast<GX::TevStageID>(finalTevCount);
CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_KONST);
CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV);
CGX::SetTevColorOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVREG0);
CGX::SetTevKColorSel(stage, static_cast<GX::TevKColorSel>(finalKColorCount + GX::TEV_KCSEL_K0_A));
CGX::SetTevAlphaOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetTevDirect(stage);
// Stage interpolating from splatted KAlpha using KColor
aurora::gfx::update_tev_stage(static_cast<ERglTevStage>(finalTevCount + 1),
CTevCombiners::ColorPass{GX::CC_CPREV, GX::CC_C0, GX::CC_KONST, GX::CC_ZERO},
CTevCombiners::AlphaPass{GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV},
CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVPREV},
CTevCombiners::CTevOp{true, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, GX::TEVPREV});
// GXSetTevColorIn(finalTevCount + 1, TEVCOLORARG_CPREV, TEVCOLORARG_C0, TEVCOLORARG_KONST, TEVCOLORARG_ZERO);
// GXSetTevAlphaIn(finalTevCount + 1, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_APREV);
aurora::gfx::set_tev_k_color_sel(static_cast<GX::TevStageID>(finalTevCount + 1),
static_cast<GX::TevKColorSel>(finalKColorCount + GX::TEV_KCSEL_K0));
// GXSetTevKColorSel(finalTevCount, finalKColorCount+12);
// SetStandardTevColorAlphaOp(finalTevCount + 1);
// GXSetTevDirect(finalTevCount + 1);
// GXSetTevOrder(finalTevCount + 1, 255, 255, 255);
aurora::gfx::set_tev_k_color(static_cast<GX::TevKColorID>(finalKColorCount), modelFlags.x4_color);
// GXSetTevKColor(finalKColorCount, modelFlags.x4_color);
stage = static_cast<GX::TevStageID>(stage + 1);
CGX::SetTevColorIn(stage, GX::CC_CPREV, GX::CC_C0, GX::CC_KONST, GX::CC_ZERO);
CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV);
CGX::SetTevKColorSel(stage, static_cast<GX::TevKColorSel>(finalKColorCount + GX::TEV_KCSEL_K0));
CGX::SetStandardTevColorAlphaOp(stage);
CGX::SetTevDirect(stage);
CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetTevKColor(static_cast<GX::TevKColorID>(finalKColorCount), modelFlags.x4_color);
finalKColorCount += 1;
finalTevCount += 2;
} else {
// Mul KAlpha
CTevCombiners::AlphaPass alphaPass{GX::CA_ZERO, GX::CA_KONST, GX::CA_APREV, GX::CA_ZERO};
u32 tevAlpha = 0x000380C7; // TEVALPHAARG_ZERO, TEVALPHAARG_KONST, TEVALPHAARG_APREV, TEVALPHAARG_ZERO
auto stage = static_cast<GX::TevStageID>(finalTevCount);
if (modelFlags.x0_blendMode == 8) {
// Set KAlpha
alphaPass = {GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_KONST};
tevAlpha = 0x00031CE7; // TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_ZERO, TEVALPHAARG_KONST
CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_KONST); // Set KAlpha
} else {
CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_KONST, GX::CA_APREV, GX::CA_ZERO); // Mul KAlpha
}
// Mul KColor
CTevCombiners::ColorPass colorPass{GX::CC_ZERO, GX::CC_KONST, GX::CC_CPREV, GX::CC_ZERO};
u32 tevColor = 0x000781CF; // TEVCOLORARG_ZERO, TEVCOLORARG_KONST, TEVCOLORARG_CPREV, TEVCOLORARG_ZERO
if (modelFlags.x0_blendMode == 2) {
// Add KColor
colorPass = {GX::CC_ZERO, GX::CC_ONE, GX::CC_CPREV, GX::CC_KONST};
tevColor = 0x0007018F; // TEVCOLORARG_ZERO, TEVCOLORARG_ONE, TEVCOLORARG_CPREV, TEVCOLORARG_KONST
CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_ONE, GX::CC_CPREV, GX::CC_KONST); // Add KColor
} else {
CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_KONST, GX::CC_CPREV, GX::CC_ZERO); // Mul KColor
}
aurora::gfx::update_tev_stage(static_cast<ERglTevStage>(finalTevCount), colorPass, alphaPass, {}, {});
// GXSetTevColorIn(finalTevCount)
// GXSetTevAlphaIn(finalTevCount)
// SetStandardTevColorAlphaOp(finalTevCount);
CGX::SetStandardTevColorAlphaOp(stage);
finalCCFlags = 0x100; // Just clamp, output prev reg
finalACFlags = 0x100;
// GXSetTevDirect(finalTevCount);
// GXSetTevOrder(finalTevCount, 255, 255, 255);
aurora::gfx::set_tev_k_color(static_cast<GX::TevKColorID>(finalKColorCount), modelFlags.x4_color);
// GXSetTevKColor(finalKColorCount, modelFlags.x4_color);
aurora::gfx::set_tev_k_color_sel(static_cast<GX::TevStageID>(finalTevCount),
static_cast<GX::TevKColorSel>(finalKColorCount + GX::TEV_KCSEL_K0));
// GXSetTevKColorSel(finalTevCount, finalKColorCount+12);
aurora::gfx::set_tev_k_alpha_sel(static_cast<GX::TevStageID>(finalTevCount),
static_cast<GX::TevKAlphaSel>(finalKColorCount + GX::TEV_KASEL_K0_A));
// GXSetTevKAlphaSel(finalTevCount, finalKColorCount+28);
CGX::SetTevDirect(stage);
CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetTevKColor(static_cast<GX::TevKColorID>(finalKColorCount), modelFlags.x4_color);
CGX::SetTevKColorSel(stage, static_cast<GX::TevKColorSel>(finalKColorCount + GX::TEV_KCSEL_K0));
CGX::SetTevKAlphaSel(stage, static_cast<GX::TevKAlphaSel>(finalKColorCount + GX::TEV_KASEL_K0_A));
finalTevCount += 1;
finalKColorCount += 1;
}
@ -483,16 +448,20 @@ void CCubeMaterial::HandleTransparency(u32& finalTevCount, u32& finalKColorCount
u32 CCubeMaterial::HandleReflection(bool usesTevReg2, u32 indTexSlot, u32 r5, u32 finalTevCount, u32 texCount,
u32 tcgCount, u32 finalKColorCount, u32& finalCCFlags, u32& finalACFlags) {
u32 out = 0;
GX::TevColorArg colorArg = GX::CC_KONST;
if (usesTevReg2) {
// GX_CC_C2
colorArg = GX::CC_C2;
const auto stage = static_cast<GX::TevStageID>(finalTevCount);
CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_C2, GX::CC_KONST, GX::CC_ZERO);
CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_A2);
CGX::SetTevColorOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVREG2);
CGX::SetTevAlphaOp(stage, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVREG2);
CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_ZERO);
out = 1;
} else {
// GX_CC_KONST
}
aurora::gfx::set_tev_k_color(static_cast<GX::TevKColorID>(finalKColorCount),
zeus::CColor{sReflectionAlpha, sReflectionAlpha});
aurora::gfx::set_tev_k_color_sel(static_cast<GX::TevStageID>(finalTevCount),
static_cast<GX::TevKColorSel>(GX::TEV_KCSEL_K0 + finalKColorCount));
CGX::SetTevKColor(static_cast<GX::TevKColorID>(finalKColorCount), zeus::CColor{sReflectionAlpha, sReflectionAlpha});
CGX::SetTevKColorSel(static_cast<GX::TevStageID>(finalTevCount),
static_cast<GX::TevKColorSel>(GX::TEV_KCSEL_K0 + finalKColorCount));
const auto stage = static_cast<GX::TevStageID>(finalTevCount + out);
// tex = g_Renderer->GetRealReflection
@ -505,11 +474,16 @@ u32 CCubeMaterial::HandleReflection(bool usesTevReg2, u32 indTexSlot, u32 r5, u3
// aurora::gfx::set_tev_order(stage, ...)
return out + 1;
return out; //+ 1;
}
void CCubeMaterial::DoPassthru(u32 finalTevCount) {
aurora::gfx::disable_tev_stage(static_cast<ERglTevStage>(finalTevCount));
const auto stage = static_cast<GX::TevStageID>(finalTevCount);
CGX::SetTevColorIn(stage, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_CPREV);
CGX::SetTevAlphaIn(stage, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_APREV);
CGX::SetTevOrder(stage, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetTevDirect(stage);
CGX::SetStandardTevColorAlphaOp(stage);
}
void CCubeMaterial::DoModelShadow(u32 texCount, u32 tcgCount) {
@ -523,8 +497,8 @@ void CCubeMaterial::EnsureTevsDirect() {
return;
}
// CGX::SetNumIndStages(0);
// CGX::SetTevDirect(sCurrentTevStage);
CGX::SetNumIndStages(0);
CGX::SetTevDirect(sCurrentTevStage);
sCurrentTevStage = GX::NULL_STAGE;
}
} // namespace metaforce

View File

@ -5,22 +5,20 @@
#include "Graphics/CCubeSurface.hpp"
#include "Graphics/CGraphics.hpp"
#include "Graphics/CModel.hpp"
#include <aurora/model.hpp>
#include "Graphics/CGX.hpp"
namespace metaforce {
bool CCubeModel::sRenderModelBlack = false;
bool CCubeModel::sRenderModelShadow = false;
bool CCubeModel::sUsingPackedLightmaps = false;
const CTexture* CCubeModel::sShadowTexture = nullptr;
zeus::CTransform CCubeModel::sTextureProjectionTransform;
GX::LightMask CCubeModel::sChannel0DisableLightMask;
GX::LightMask CCubeModel::sChannel1EnableLightMask;
static bool sDrawingOccluders = false;
static bool sDrawingWireframe = false;
static zeus::CTransform sTextureProjectionTransform;
static u8 sChannel0DisableLightMask = 0;
static u8 sChannel1EnableLightMask = 0;
static zeus::CVector3f sPlayerPosition;
CCubeModel::CCubeModel(std::vector<CCubeSurface>* surfaces, std::vector<TCachedToken<CTexture>>* textures,
@ -159,8 +157,8 @@ void CCubeModel::DrawFlat(TConstVectorRef positions, TConstVectorRef normals, ES
const auto* surface = x38_firstUnsortedSurf;
while (surface != nullptr) {
const auto mat = GetMaterialByIndex(surface->GetMaterialIndex());
aurora::gfx::model::set_vtx_desc_compressed(mat.GetVertexDesc());
aurora::gfx::model::queue_surface(surface->GetDisplayList(), surface->GetDisplayListSize());
CGX::SetVtxDescv_Compressed(mat.GetVertexDesc());
CGX::CallDisplayList(surface->GetDisplayList(), surface->GetDisplayListSize());
surface = surface->GetNextSurface();
}
}
@ -168,19 +166,23 @@ void CCubeModel::DrawFlat(TConstVectorRef positions, TConstVectorRef normals, ES
const auto* surface = x3c_firstSortedSurf;
while (surface != nullptr) {
const auto mat = GetMaterialByIndex(surface->GetMaterialIndex());
aurora::gfx::model::set_vtx_desc_compressed(mat.GetVertexDesc());
aurora::gfx::model::queue_surface(surface->GetDisplayList(), surface->GetDisplayListSize());
CGX::SetVtxDescv_Compressed(mat.GetVertexDesc());
CGX::CallDisplayList(surface->GetDisplayList(), surface->GetDisplayListSize());
surface = surface->GetNextSurface();
}
}
}
void CCubeModel::DrawNormal(TConstVectorRef positions, TConstVectorRef normals, ESurfaceSelection surfaces) {
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassZero);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
// TODO update fog
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::Zero, ERglBlendFactor::One, ERglLogicOp::Clear);
CGX::SetNumIndStages(0);
CGX::SetNumTevStages(1);
CGX::SetNumTexGens(1);
CGX::SetZMode(true, GX::LEQUAL, true);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO);
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0);
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ZERO, GX::BL_ONE, GX::LO_CLEAR);
DrawFlat(positions, normals, surfaces);
}
@ -210,7 +212,7 @@ void CCubeModel::DrawSurface(const CCubeSurface& surface, const CModelFlags& fla
auto mat = GetMaterialByIndex(surface.GetMaterialIndex());
if (!mat.GetFlags().IsSet(CCubeMaterialFlagBits::fShadowOccluderMesh) || sDrawingOccluders) {
mat.SetCurrent(flags, surface, *this);
aurora::gfx::model::queue_surface(surface.GetDisplayList(), surface.GetDisplayListSize());
CGX::CallDisplayList(surface.GetDisplayList(), surface.GetDisplayListSize());
}
}
@ -245,8 +247,8 @@ void CCubeModel::DrawSurfaceWireframe(const CCubeSurface& surface) {
// TODO convert vertices to line strips and draw
}
void CCubeModel::EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, u8 chan0DisableMask,
u8 chan1EnableLightMask) {
void CCubeModel::EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf,
GX::LightMask chan0DisableMask, GX::LightMask chan1EnableLightMask) {
sRenderModelShadow = true;
sShadowTexture = &shadowTex;
sTextureProjectionTransform = textureProjXf;
@ -257,8 +259,8 @@ void CCubeModel::EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransf
void CCubeModel::DisableShadowMaps() { sRenderModelShadow = false; }
void CCubeModel::SetArraysCurrent() {
aurora::gfx::model::set_vertex_buffer(x0_modelInstance.GetVertexPointer());
aurora::gfx::model::set_normal_buffer(x0_modelInstance.GetNormalPointer());
CGX::SetArray(GX::VA_POS, x0_modelInstance.GetVertexPointer());
CGX::SetArray(GX::VA_NRM, x0_modelInstance.GetNormalPointer());
SetStaticArraysCurrent();
}
@ -278,8 +280,8 @@ void CCubeModel::SetRenderModelBlack(bool v) {
}
void CCubeModel::SetSkinningArraysCurrent(TConstVectorRef positions, TConstVectorRef normals) {
aurora::gfx::model::set_vertex_buffer(positions);
aurora::gfx::model::set_normal_buffer(normals);
CGX::SetArray(GX::VA_POS, positions);
CGX::SetArray(GX::VA_NRM, normals);
// colors unused
SetStaticArraysCurrent();
}
@ -292,20 +294,21 @@ void CCubeModel::SetStaticArraysCurrent() {
sUsingPackedLightmaps = false;
}
if (sUsingPackedLightmaps) {
aurora::gfx::model::set_tex0_tc_buffer(packedTexCoords);
CGX::SetArray(GX::VA_TEX0, packedTexCoords);
} else {
aurora::gfx::model::set_tex0_tc_buffer(texCoords);
CGX::SetArray(GX::VA_TEX0, texCoords);
}
aurora::gfx::model::set_tc_buffer(texCoords);
// TexCoord1 is currently used for all remaining
CGX::SetArray(GX::VA_TEX1, texCoords);
CCubeMaterial::KillCachedViewDepState();
}
void CCubeModel::SetUsingPackedLightmaps(bool v) {
sUsingPackedLightmaps = v;
if (v) {
aurora::gfx::model::set_tex0_tc_buffer(x0_modelInstance.GetPackedTCPointer());
CGX::SetArray(GX::VA_TEX0, x0_modelInstance.GetPackedTCPointer());
} else {
aurora::gfx::model::set_tex0_tc_buffer(x0_modelInstance.GetTCPointer());
CGX::SetArray(GX::VA_TEX0, x0_modelInstance.GetTCPointer());
}
}

View File

@ -26,6 +26,7 @@ using TConstVectorRef = const std::vector<zeus::CVector3f>*;
class CCubeModel {
friend class CModel;
friend class CCubeMaterial;
private:
class ModelInstance {
@ -110,8 +111,8 @@ public:
[[nodiscard]] TConstVectorRef GetNormals() const { return x0_modelInstance.GetNormalPointer(); }
[[nodiscard]] TCachedToken<CTexture>& GetTexture(u32 idx) const { return x1c_textures->at(idx); }
static void EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf, u8 chan0DisableMask,
u8 chan1EnableLightMask);
static void EnableShadowMaps(const CTexture& shadowTex, const zeus::CTransform& textureProjXf,
GX::LightMask chan0DisableMask, GX::LightMask chan1EnableLightMask);
static void DisableShadowMaps();
static void MakeTexturesFromMats(const u8* ptr, std::vector<TCachedToken<CTexture>>& texture, IObjectStore* store,
bool b1);
@ -120,11 +121,6 @@ public:
static void SetNewPlayerPositionAndTime(const zeus::CVector3f& pos, const CStopwatch& time);
static void SetRenderModelBlack(bool v);
static bool sRenderModelBlack;
static bool sUsingPackedLightmaps;
static bool sRenderModelShadow;
static const CTexture* sShadowTexture;
private:
void Draw(TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags);
void DrawAlphaSurfaces(const CModelFlags& flags);
@ -132,5 +128,13 @@ private:
void DrawSurfaces(const CModelFlags& flags);
void SetSkinningArraysCurrent(TConstVectorRef positions, TConstVectorRef normals);
void SetStaticArraysCurrent();
static bool sRenderModelBlack;
static bool sUsingPackedLightmaps;
static bool sRenderModelShadow;
static const CTexture* sShadowTexture;
static zeus::CTransform sTextureProjectionTransform;
static GX::LightMask sChannel0DisableLightMask;
static GX::LightMask sChannel1EnableLightMask;
};
} // namespace metaforce

View File

@ -1,15 +1,16 @@
#include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CDrawable.hpp"
#include "Runtime/Graphics/CMetroidModelInstance.hpp"
#include "Runtime/Graphics/CDrawablePlaneObject.hpp"
#include "Runtime/Graphics/CLight.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Particle/CParticleGen.hpp"
#include "Runtime/Graphics/CCubeMaterial.hpp"
#include "Runtime/Graphics/CCubeModel.hpp"
#include "Runtime/Graphics/CCubeSurface.hpp"
#include "Runtime/Graphics/CCubeMaterial.hpp"
#include "Runtime/Graphics/CDrawable.hpp"
#include "Runtime/Graphics/CDrawablePlaneObject.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include "Runtime/Graphics/CLight.hpp"
#include "Runtime/Graphics/CMetroidModelInstance.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Particle/CParticleGen.hpp"
namespace metaforce {
static logvisor::Module Log("CCubeRenderer");
@ -197,15 +198,35 @@ CCubeRenderer::CCubeRenderer(IObjectStore& store, IFactory& resFac) : x8_factory
CCubeRenderer::~CCubeRenderer() { g_Renderer = nullptr; }
void CCubeRenderer::GenerateReflectionTex() {}
void CCubeRenderer::GenerateFogVolumeRampTex() {}
void CCubeRenderer::GenerateSphereRampTex() {}
void CCubeRenderer::LoadThermoPalette() {}
void CCubeRenderer::ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, const CTexture& maskTex,
const CTexture& indTex, const zeus::CColor& modColor,
float scale, float offX, float offY) {}
void CCubeRenderer::ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, const CTexture& maskTex) {}
void CCubeRenderer::DoPhazonSuitIndirectAlphaBlur(float blurRadius, float f2, const TLockedToken<CTexture>& indTex) {}
void CCubeRenderer::GenerateReflectionTex() {
// TODO
}
void CCubeRenderer::GenerateFogVolumeRampTex() {
// TODO
}
void CCubeRenderer::GenerateSphereRampTex() {
// TODO
}
void CCubeRenderer::LoadThermoPalette() {
// TODO
}
void CCubeRenderer::ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, CTexture& maskTex,
CTexture& indTex, const zeus::CColor& modColor, float scale,
float offX, float offY) {
// TODO
}
void CCubeRenderer::ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, CTexture& maskTex) {
// TODO
}
void CCubeRenderer::DoPhazonSuitIndirectAlphaBlur(float blurRadius, float f2, const TLockedToken<CTexture>& indTex) {
// TODO
}
void CCubeRenderer::AddWorldSurfaces(CCubeModel& model) {
for (auto* it = model.GetFirstSortedSurface(); it != nullptr; it = it->GetNextSurface()) {
@ -216,6 +237,7 @@ void CCubeRenderer::AddWorldSurfaces(CCubeModel& model) {
Buckets::Insert(pos, bounds, EDrawableType::WorldSurface, it, xb0_viewPlane, static_cast<u16>(blend == 0x50004));
}
}
void CCubeRenderer::AddStaticGeometry(const std::vector<CMetroidModelInstance>* geometry,
const CAreaRenderOctTree* octTree, s32 areaIdx) {
auto search = FindStaticGeometry(geometry);
@ -448,7 +470,11 @@ void CCubeRenderer::RenderBucketItems(const CAreaListItem* item) {
}
}
}
void CCubeRenderer::PostRenderFogs() {}
void CCubeRenderer::PostRenderFogs() {
// TODO
}
void CCubeRenderer::SetModelMatrix(const zeus::CTransform& xf) { CGraphics::SetModelMatrix(xf); }
void CCubeRenderer::HandleUnsortedModel(CAreaListItem* areaItem, CCubeModel& model, const CModelFlags& flags) {
@ -473,7 +499,10 @@ void CCubeRenderer::HandleUnsortedModelWireframe(CAreaListItem* areaItem, CCubeM
}
}
void CCubeRenderer::ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model) {}
void CCubeRenderer::ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model) {
// TODO
}
void CCubeRenderer::AddParticleGen(CParticleGen& gen) {
auto bounds = gen.GetBounds();
@ -575,8 +604,8 @@ void CCubeRenderer::BeginScene() {
}
// GXSetPixelFmt(x318_26_requestRGBA6, GX_ZC_LINEAR);
aurora::gfx::set_alpha_update(true);
aurora::gfx::set_dst_alpha(true, 0.f);
GXSetAlphaUpdate(true);
GXSetDstAlpha(true, 0.f);
CGraphics::BeginScene();
}
@ -607,64 +636,164 @@ void CCubeRenderer::BeginPrimitive(IRenderer::EPrimitiveType type, s32 nverts) {
x18_primVertCount = nverts;
CGraphics::StreamBegin(GX::Primitive(type));
}
void CCubeRenderer::BeginLines(s32 nverts) { BeginPrimitive(EPrimitiveType::Lines, nverts); }
void CCubeRenderer::BeginLineStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::LineStrip, nverts); }
void CCubeRenderer::BeginTriangles(s32 nverts) { BeginPrimitive(EPrimitiveType::Triangles, nverts); }
void CCubeRenderer::BeginTriangleStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleStrip, nverts); }
void CCubeRenderer::BeginTriangleFan(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleFan, nverts); }
void CCubeRenderer::PrimVertex(const zeus::CVector3f& vertex) {
--x18_primVertCount;
CGraphics::StreamColor(x2e0_primColor);
CGraphics::StreamNormal(x2e4_primNormal);
CGraphics::StreamVertex(vertex);
}
void CCubeRenderer::PrimNormal(const zeus::CVector3f& normal) { x2e4_primNormal = normal; }
void CCubeRenderer::PrimColor(float r, float g, float b, float a) { PrimColor({r, g, b, a}); }
void CCubeRenderer::PrimColor(const zeus::CColor& color) { x2e0_primColor = color; }
void CCubeRenderer::EndPrimitive() {
while (x18_primVertCount > 0) {
PrimVertex(zeus::skZero3f);
}
CGraphics::StreamEnd();
}
void CCubeRenderer::SetAmbientColor(const zeus::CColor& color) { CGraphics::SetAmbientColor(color); }
void CCubeRenderer::DrawString(const char* string, s32 x, s32 y) { x10_font.DrawString(string, x, y, zeus::skWhite); }
u32 CCubeRenderer::GetFPS() { return CGraphics::GetFPS(); }
void CCubeRenderer::CacheReflection(IRenderer::TReflectionCallback cb, void* ctx, bool clearAfter) {}
void CCubeRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) {}
void CCubeRenderer::DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {}
void CCubeRenderer::DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color,
TConstVectorRef positions, TConstVectorRef normals) {}
void CCubeRenderer::DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) {}
void CCubeRenderer::SetWireframeFlags(s32 flags) {}
void CCubeRenderer::SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) {}
void CCubeRenderer::RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb,
const TLockedToken<CModel>* model, const CSkinnedModel* sModel) {}
void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& color) {}
void CCubeRenderer::SetThermalColdScale(float scale) {}
void CCubeRenderer::DoThermalBlendCold() {}
void CCubeRenderer::DoThermalBlendHot() {}
u32 CCubeRenderer::GetStaticWorldDataSize() { return 0; }
void CCubeRenderer::SetGXRegister1Color(const zeus::CColor& color) {
aurora::gfx::set_tev_reg_color(GX::TevRegID::TEVREG1, color);
void CCubeRenderer::CacheReflection(IRenderer::TReflectionCallback cb, void* ctx, bool clearAfter) {
// TODO
}
void CCubeRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) {
// TODO
}
void CCubeRenderer::DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {
model.UpdateLastFrame();
// TODO
// DoThermalModelDraw(model.GetInstance(), multCol, addCol, positions, normals, flags);
}
void CCubeRenderer::DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color,
TConstVectorRef positions, TConstVectorRef normals, float t) {
tex.Load(GX::TEXMAP0, EClampMode::Clamp);
CGX::SetNumIndStages(0);
CGX::SetNumTevStages(2);
CGX::SetNumTexGens(2);
CGX::SetNumChans(0);
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_SRCALPHA, GX::BL_INVSRCALPHA, GX::LO_CLEAR);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE1);
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_TEXC);
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_TEXA);
CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_TEXC, GX::CC_CPREV, GX::CC_KONST);
CGX::SetTevAlphaIn(GX::TEVSTAGE1, GX::CA_ZERO, GX::CA_TEXA, GX::CA_APREV, GX::CA_ZERO);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP0, GX::COLOR_NULL);
CGX::SetTevKColorSel(GX::TEVSTAGE1, GX::TEV_KCSEL_K0);
CGX::SetTevKColor(GX::KCOLOR0, color);
// TODO
}
void CCubeRenderer::DrawModelFlat(CModel& model, const CModelFlags& flags, bool unsortedOnly, TConstVectorRef positions,
TConstVectorRef normals) {
if (flags.x0_blendMode >= 7) {
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_SRCALPHA, GX::BL_ONE, GX::LO_CLEAR);
} else if (flags.x0_blendMode >= 5) {
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_SRCALPHA, GX::BL_INVSRCALPHA, GX::LO_CLEAR);
} else {
CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ZERO, GX::LO_CLEAR);
}
CGX::SetZMode(true, flags.x2_flags & CModelFlagBits::DepthTest ? GX::LEQUAL : GX::ALWAYS,
flags.x2_flags.IsSet(CModelFlagBits::DepthUpdate));
CGX::SetNumTevStages(1);
CGX::SetNumTexGens(1);
CGX::SetNumChans(0);
CGX::SetNumIndStages(0);
CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0);
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_ZERO, GX::CC_ZERO, GX::CC_KONST);
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_ZERO, GX::CA_ZERO, GX::CA_KONST);
CGX::SetTevKColor(GX::KCOLOR0, flags.x4_color);
CGX::SetTevKColorSel(GX::TEVSTAGE0, GX::TEV_KCSEL_K0);
CGX::SetTevKAlphaSel(GX::TEVSTAGE0, GX::TEV_KASEL_K0_A);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR_NULL);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0);
CGX::SetTevDirect(GX::TEVSTAGE0);
CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_POS, GX::IDENTITY, false, GX::PTIDENTITY);
model.UpdateLastFrame();
model.GetInstance().DrawFlat(positions, normals, unsortedOnly ? ESurfaceSelection::Unsorted : ESurfaceSelection::All);
}
void CCubeRenderer::SetWireframeFlags(s32 flags) {
// TODO
}
void CCubeRenderer::SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) {
// TODO
}
void CCubeRenderer::RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb,
const TLockedToken<CModel>* model, const CSkinnedModel* sModel) {
// TODO
}
void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& color) {
// TODO
}
void CCubeRenderer::SetThermalColdScale(float scale) {
// TODO
}
void CCubeRenderer::DoThermalBlendCold() {
// TODO
}
void CCubeRenderer::DoThermalBlendHot() {
// TODO
}
u32 CCubeRenderer::GetStaticWorldDataSize() {
// TODO
return 0;
}
void CCubeRenderer::SetGXRegister1Color(const zeus::CColor& color) { GXSetTevColor(GX::TevRegID::TEVREG1, color); }
void CCubeRenderer::SetWorldLightFadeLevel(float level) { x2fc_tevReg1Color = zeus::CColor(level, level, level, 1.f); }
void CCubeRenderer::PrepareDynamicLights(const std::vector<CLight>& lights) {}
void CCubeRenderer::AllocatePhazonSuitMaskTexture() {}
void CCubeRenderer::PrepareDynamicLights(const std::vector<CLight>& lights) {
// TODO
}
void CCubeRenderer::AllocatePhazonSuitMaskTexture() {
// TODO
}
void CCubeRenderer::DrawPhazonSuitIndirectEffect(const zeus::CColor& nonIndirectMod,
const TLockedToken<CTexture>& indTex, const zeus::CColor& indirectMod,
float blurRadius, float scale, float offX, float offY) {
// TODO
aurora::gfx::set_dst_alpha(false, 0.f);
GXSetDstAlpha(false, 0.f);
}
void CCubeRenderer::DrawXRayOutline(const zeus::CAABox& aabb) {}
void CCubeRenderer::DrawXRayOutline(const zeus::CAABox& aabb) {
// TODO
}
std::list<CCubeRenderer::CAreaListItem>::iterator
CCubeRenderer::FindStaticGeometry(const std::vector<CMetroidModelInstance>* geometry) {
@ -687,9 +816,10 @@ void CCubeRenderer::SetupCGraphicsState() {
CGraphics::SetModelMatrix({});
CTevCombiners::ResetStates();
CGraphics::SetAmbientColor({0.4f});
// CGX::SetChanMatColor(EChannelId::Channel0, GX::Color{0xFFFFFFFF});
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
// CGX::SetChanCtrl(EChannelId::Channel1, false, GX::SRC_REG, GX::LIGHT_NULL, GX::DF_NONE, GX::AF_NONE);
CGX::SetChanCtrl(CGX::EChannelId::Channel1, false, GX::SRC_REG, GX::SRC_REG, GX::LIGHT_NULL, GX::DF_NONE,
GX::AF_NONE);
CCubeMaterial::EnsureTevsDirect();
}
@ -699,6 +829,6 @@ void CCubeRenderer::SetupRendererStates(bool depthWrite) {
CGraphics::SetAmbientColor(zeus::skBlack);
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, depthWrite);
CCubeMaterial::ResetCachedMaterials();
aurora::gfx::set_tev_reg_color(GX::TEVREG1, x2fc_tevReg1Color);
GXSetTevColor(GX::TEVREG1, x2fc_tevReg1Color);
}
} // namespace metaforce

View File

@ -97,10 +97,9 @@ private:
void GenerateSphereRampTex();
void LoadThermoPalette();
void ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, const CTexture& maskTex,
const CTexture& indTex, const zeus::CColor& modColor, float scale, float offX,
float offY);
void ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, const CTexture& maskTex);
void ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, CTexture& maskTex, CTexture& indTex,
const zeus::CColor& modColor, float scale, float offX, float offY);
void ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, CTexture& maskTex);
void DoPhazonSuitIndirectAlphaBlur(float blurRadius, float f2, const TLockedToken<CTexture>& indTex);
public:
@ -179,11 +178,12 @@ public:
u32 GetFPS() override;
void CacheReflection(TReflectionCallback cb, void* ctx, bool clearAfter) override;
void DrawSpaceWarp(const zeus::CVector3f& pt, float strength) override;
void DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
void DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) override;
void DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color,
TConstVectorRef positions, TConstVectorRef normals) override;
void DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) override;
void DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color, TConstVectorRef positions,
TConstVectorRef normals, float t) override;
void DrawModelFlat(CModel& model, const CModelFlags& flags, bool unsortedOnly, TConstVectorRef positions,
TConstVectorRef normals) override;
void SetWireframeFlags(s32 flags) override;
void SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) override;
void RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, const TLockedToken<CModel>* model,
@ -217,6 +217,9 @@ public:
void ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model);
void DoThermalModelDraw(CCubeModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags);
// Getters
[[nodiscard]] bool IsInAreaDraw() const { return x318_30_inAreaDraw; }
[[nodiscard]] bool IsReflectionDirty() const { return x318_24_refectionDirty; }

30
Runtime/Graphics/CGX.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "CGX.hpp"
#include "Graphics/CTexture.hpp"
namespace metaforce::CGX {
SGXState sGXState;
void ResetGXStates() noexcept {
sGXState.x48_descList = nullptr;
// GXClearVtxDesc();
sGXState.x0_arrayPtrs.fill(nullptr);
for (GX::TexMapID id = GX::TEXMAP0; id < GX::MAX_TEXMAP; id = static_cast<GX::TexMapID>(id + 1)) {
CTexture::InvalidateTexMap(id);
}
for (GX::TevKColorID id = GX::KCOLOR0; const auto& item : sGXState.x58_kColors) {
GXSetTevKColor(id, item);
id = static_cast<GX::TevKColorID>(id + 1);
}
// GXSetTevSwapModeTable
SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0);
// GXSetCurrentMtx(0);
SetNumIndStages(0);
// TODO GXSetIndTexCoordScale
for (GX::TevStageID id = GX::TEVSTAGE0; id < GX::MAX_TEVSTAGE; id = static_cast<GX::TevStageID>(id + 1)) {
SetTevDirect(id);
}
// GXSetTexCoordCylWrap
// GXSetZTexture
}
} // namespace metaforce::CGX

387
Runtime/Graphics/CGX.hpp Normal file
View File

@ -0,0 +1,387 @@
#pragma once
#include "Graphics/GX.hpp"
#include "RetroTypes.hpp"
#include <aurora/model.hpp>
#include <zeus/CColor.hpp>
namespace metaforce::CGX {
enum class EChannelId {
Channel0, // GX::COLOR0
Channel1, // GX::COLOR1
};
struct STevState {
u32 x0_colorInArgs = 0;
u32 x4_alphaInArgs = 0;
u32 x8_colorOps = 0;
u32 xc_alphaOps = 0;
u32 x10_indFlags = 0;
u32 x14_tevOrderFlags = 0;
GX::TevKColorSel x18_kColorSel = GX::TEV_KCSEL_1;
GX::TevKAlphaSel x19_kAlphaSel = GX::TEV_KASEL_1;
};
struct STexState {
u32 x0_coordGen = 0;
};
struct SGXState {
std::array<void*, 12> x0_arrayPtrs{};
std::array<u16, 2> x30_prevChanCtrls{};
std::array<u16, 2> x34_chanCtrls{};
std::array<GXColor, 2> x38_chanAmbColors;
std::array<GXColor, 2> x40_chanMatColors;
GX::VtxDescList* x48_descList = nullptr;
u8 x4c_dirtyChans = 0;
u8 x4d_prevNumChans = 0;
u8 x4e_numChans = 0;
u8 x4f_numTexGens = 0;
u8 x50_numTevStages = 0;
u8 x51_numIndStages = 0;
u8 x52_zmode = 0;
GX::FogType x53_fogType = GX::FOG_NONE;
u16 x54_lineWidthAndOffset = 0;
u16 x56_blendMode = 0;
std::array<GXColor, GX::MAX_KCOLOR> x58_kColors;
std::array<STevState, GX::MAX_TEVSTAGE> x68_tevStates;
std::array<STexState, GX::MAX_TEXMAP> x228_texStates;
u32 x248_alphaCompare = 0;
float x24c_fogStartZ = 0.f;
float x250_fogEndZ = 0.f;
float x254_fogNearZ = 0.f;
float x258_fogFarZ = 0.f;
GXColor x25c_fogColor;
};
extern SGXState sGXState;
static inline void update_fog(u32 value) noexcept {
if (sGXState.x53_fogType == GX::FOG_NONE || (sGXState.x56_blendMode & 0xE0) == (value & 0xE0)) {
return;
}
if ((value & 0xE0) == 0x20) {
// TODO
return;
}
// TODO
}
static inline void FlushState() noexcept {
if ((sGXState.x4c_dirtyChans & 1) != 0) {
u8 numChans = sGXState.x4e_numChans;
GXSetNumChans(numChans);
sGXState.x4d_prevNumChans = numChans;
}
if ((sGXState.x4c_dirtyChans & 2) != 0) {
// TODO actually COLOR0
auto flags = sGXState.x34_chanCtrls[0];
GXSetChanCtrl(GX::COLOR0A0, GXBool(flags & 1), GX::ColorSrc(flags >> 1 & 1), GX::ColorSrc(flags >> 2 & 1),
flags >> 3 & 0xFF, GX::DiffuseFn(flags >> 11 & 3), GX::AttnFn(flags >> 13 & 3));
sGXState.x30_prevChanCtrls[0] = flags;
}
if ((sGXState.x4c_dirtyChans & 4) != 0) {
// TODO actually COLOR1
auto flags = sGXState.x34_chanCtrls[1];
GXSetChanCtrl(GX::COLOR1A1, GXBool(flags & 1), GX::ColorSrc(flags >> 1 & 1), GX::ColorSrc(flags >> 2 & 1),
flags >> 3 & 0xFF, GX::DiffuseFn(flags >> 11 & 3), GX::AttnFn(flags >> 13 & 3));
sGXState.x30_prevChanCtrls[1] = flags;
}
sGXState.x4c_dirtyChans = 0;
}
static inline void Begin(GX::Primitive primitive, GX::VtxFmt fmt, u16 nverts) noexcept {
if (sGXState.x4c_dirtyChans != 0) {
FlushState();
}
// TODO GXBegin(type, fmt, nverts);
}
static inline void CallDisplayList(const void* data, u32 nbytes) noexcept {
if (sGXState.x4c_dirtyChans != 0) {
FlushState();
}
GXCallDisplayList(data, nbytes);
}
static inline void End() noexcept {
// no-op
}
static inline const GXColor& GetChanAmbColor(EChannelId id) noexcept {
const auto idx = std::underlying_type_t<EChannelId>(id);
return sGXState.x38_chanAmbColors[idx];
}
void ResetGXStates() noexcept;
static inline void SetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, GX::Compare comp1, u8 ref1) noexcept {
u32 flags = ref1 << 17 | (comp1 & 7) << 14 | (op & 7) << 11 | ref0 << 3 | (comp0 & 7);
if (flags != sGXState.x248_alphaCompare) {
sGXState.x248_alphaCompare = flags;
GXSetAlphaCompare(comp0, ref0 / 255.f, op, comp1, ref1 / 255.f);
// GXSetZCompLoc(comp0 == GX::ALWAYS);
}
}
template <typename T>
static inline void SetArray(GX::Attr attr, const std::vector<T>* data) noexcept {
if (data != nullptr && sGXState.x0_arrayPtrs[attr - GX::VA_POS] != data) {
GXSetArray(attr, data, sizeof(T));
}
}
static inline void SetBlendMode(GX::BlendMode mode, GX::BlendFactor srcFac, GX::BlendFactor dstFac,
GX::LogicOp op) noexcept {
const u16 flags = (op & 0xF) << 8 | (dstFac & 7) << 5 | (srcFac & 7) << 2 | (mode & 3);
if (flags != sGXState.x56_blendMode) {
update_fog(flags);
sGXState.x56_blendMode = flags;
GXSetBlendMode(mode, srcFac, dstFac, op);
}
}
static inline void SetChanAmbColor(EChannelId id, const GXColor& color) noexcept {
const auto idx = std::underlying_type_t<EChannelId>(id);
if (color != sGXState.x38_chanAmbColors[idx]) {
sGXState.x38_chanAmbColors[idx] = color;
GXSetChanAmbColor(GX::ChannelID(idx + GX::COLOR0A0), color);
}
}
static inline void SetChanCtrl(EChannelId id, GXBool enable, GX::ColorSrc ambSrc, GX::ColorSrc matSrc,
GX::LightMask lights, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept {
const auto idx = std::underlying_type_t<EChannelId>(id);
const u32 flags = (attnFn & 3) << 13 | (diffFn & 3) << 11 | (lights.to_ulong() & 0xFF) << 3 | (matSrc & 1) << 2 |
(ambSrc & 1) << 1 | (u8(enable) & 1);
sGXState.x34_chanCtrls[idx] = flags;
sGXState.x4c_dirtyChans = 7; // TODO
}
// Helper function for common logic
static inline void SetChanCtrl(EChannelId id, GX::LightMask lights) noexcept {
const bool hasLights = lights.any();
SetChanCtrl(id, hasLights, GX::SRC_REG, GX::SRC_REG, lights, hasLights ? GX::DF_CLAMP : GX::DF_NONE,
hasLights ? GX::AF_SPOT : GX::AF_NONE);
}
static inline void SetChanMatColor(EChannelId id, const GXColor& color) noexcept {
const auto idx = std::underlying_type_t<EChannelId>(id);
if (color != sGXState.x40_chanMatColors[idx]) {
sGXState.x40_chanMatColors[idx] = color;
GXSetChanMatColor(GX::ChannelID(idx + GX::COLOR0A0), color);
}
}
static inline void SetFog(GX::FogType type, float startZ, float endZ, float nearZ, float farZ,
const GXColor& color) noexcept {
sGXState.x25c_fogColor = color;
sGXState.x53_fogType = type;
sGXState.x24c_fogStartZ = startZ;
sGXState.x250_fogEndZ = endZ;
sGXState.x254_fogNearZ = nearZ;
sGXState.x258_fogFarZ = farZ;
auto fogColor = color;
if ((sGXState.x56_blendMode & 0xE0) == 0x20) {
fogColor = zeus::skClear;
}
// TODO
// GXSetFog(type, startZ, endZ, nearZ, farZ, fogColor);
}
void SetIndTexMtxSTPointFive(GX::IndTexMtxID id, s8 scaleExp) noexcept;
void SetLineWidth(u8 width, GX::TexOffset offset) noexcept;
static inline void SetNumChans(u8 num) noexcept {
sGXState.x4c_dirtyChans = 7; // TODO
sGXState.x4e_numChans = num;
}
static inline void SetNumIndStages(u8 num) noexcept {
auto& state = sGXState.x51_numIndStages;
if (num != state) {
state = num;
GXSetNumIndStages(num);
}
}
static inline void SetNumTevStages(u8 num) noexcept {
auto& state = sGXState.x50_numTevStages;
if (num != state) {
state = num;
GXSetNumTevStages(num);
}
}
static inline void SetNumTexGens(u8 num) noexcept {
auto& state = sGXState.x4f_numTexGens;
if (num != state) {
state = num;
GXSetNumTexGens(num);
}
}
static inline void SetStandardTevColorAlphaOp(GX::TevStageID stageId) noexcept {
auto& state = sGXState.x68_tevStates[stageId];
if (state.x8_colorOps != 0x100 || state.xc_alphaOps != 0x100) {
state.x8_colorOps = 0x100;
state.xc_alphaOps = 0x100;
GXSetTevColorOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
GXSetTevAlphaOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, GX::TEVPREV);
}
}
static inline void SetTevAlphaIn(GX::TevStageID stageId, GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c,
GX::TevAlphaArg d) noexcept {
u32 flags = (d & 31) << 15 | (c & 31) << 10 | (b & 31) << 5 | (a & 31);
auto& state = sGXState.x68_tevStates[stageId].x4_alphaInArgs;
if (flags != state) {
state = flags;
GXSetTevAlphaIn(stageId, a, b, c, d);
}
}
static inline void SetTevAlphaOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale,
GXBool clamp, GX::TevRegID outReg) noexcept {
u32 flags = (outReg & 3) << 9 | (u8(clamp) & 1) << 8 | (scale & 3) << 6 | (bias & 3) << 4 | (op & 15);
auto& state = sGXState.x68_tevStates[stageId].xc_alphaOps;
if (flags != state) {
state = flags;
GXSetTevAlphaOp(stageId, op, bias, scale, clamp, outReg);
}
}
static inline void SetTevAlphaOp_Compressed(GX::TevStageID stageId, u32 ops) noexcept {
auto& state = sGXState.x68_tevStates[stageId].xc_alphaOps;
if (ops != state) {
state = ops;
GXSetTevAlphaOp(stageId, GX::TevOp(ops & 31), GX::TevBias(ops >> 4 & 3), GX::TevScale(ops >> 6 & 3),
GXBool(ops >> 8 & 1), GX::TevRegID(ops >> 9 & 3));
}
}
static inline void SetTevColorIn(GX::TevStageID stageId, GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c,
GX::TevColorArg d) noexcept {
u32 flags = (d & 31) << 15 | (c & 31) << 10 | (b & 31) << 5 | (a & 31);
auto& state = sGXState.x68_tevStates[stageId].x0_colorInArgs;
if (flags != state) {
state = flags;
GXSetTevColorIn(stageId, a, b, c, d);
}
}
static inline void SetTevColorOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale,
GXBool clamp, GX::TevRegID outReg) noexcept {
u32 flags = (outReg & 3) << 9 | (u8(clamp) & 1) << 8 | (scale & 3) << 6 | (bias & 3) << 4 | (op & 15);
auto& state = sGXState.x68_tevStates[stageId].x8_colorOps;
if (flags != state) {
state = flags;
GXSetTevColorOp(stageId, op, bias, scale, clamp, outReg);
}
}
static inline void SetTevColorOp_Compressed(GX::TevStageID stageId, u32 ops) noexcept {
auto& state = sGXState.x68_tevStates[stageId].x8_colorOps;
if (ops != state) {
state = ops;
GXSetTevColorOp(stageId, GX::TevOp(ops & 31), GX::TevBias(ops >> 4 & 3), GX::TevScale(ops >> 6 & 3),
GXBool(ops >> 8 & 1), GX::TevRegID(ops >> 9 & 3));
}
}
static inline void SetTevDirect(GX::TevStageID stageId) noexcept {
auto& state = sGXState.x68_tevStates[stageId].x10_indFlags;
if (state != 0) {
state = 0;
// TODO
// GXSetTevDirect(stageId);
}
}
static inline void SetStandardDirectTev_Compressed(GX::TevStageID stageId, u32 colorArgs, u32 alphaArgs, u32 colorOps,
u32 alphaOps) noexcept {
auto& state = sGXState.x68_tevStates[stageId];
SetTevDirect(stageId);
if (state.x0_colorInArgs != colorArgs) {
state.x0_colorInArgs = colorArgs;
GXSetTevColorIn(stageId, GX::TevColorArg(colorArgs & 31), GX::TevColorArg(colorArgs >> 5 & 31),
GX::TevColorArg(colorArgs >> 10 & 31), GX::TevColorArg(colorArgs >> 15 & 31));
}
if (state.x4_alphaInArgs != alphaArgs) {
state.x4_alphaInArgs = alphaArgs;
GXSetTevAlphaIn(stageId, GX::TevAlphaArg(alphaArgs & 31), GX::TevAlphaArg(alphaArgs >> 5 & 31),
GX::TevAlphaArg(alphaArgs >> 10 & 31), GX::TevAlphaArg(alphaArgs >> 15 & 31));
}
if (colorOps != alphaOps || (colorOps & 0x1FF) != 0x100) {
SetTevColorOp_Compressed(stageId, colorOps);
SetTevAlphaOp_Compressed(stageId, alphaOps);
} else if (colorOps != state.x8_colorOps || colorOps != state.xc_alphaOps) {
state.x8_colorOps = colorOps;
state.xc_alphaOps = colorOps;
const auto outReg = GX::TevRegID(colorOps >> 9 & 3);
GXSetTevColorOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, outReg);
GXSetTevAlphaOp(stageId, GX::TEV_ADD, GX::TB_ZERO, GX::CS_SCALE_1, true, outReg);
}
}
void SetTevIndirect(GX::TevStageID stageId, GX::IndTexStageID indStage, GX::IndTexFormat fmt, GX::IndTexBiasSel biasSel,
GX::IndTexMtxID mtxSel, GX::IndTexWrap wrapS, GX::IndTexWrap wrapT, GXBool addPrev, GXBool indLod,
GX::IndTexAlphaSel alphaSel) noexcept;
void SetTevIndWarp(GX::TevStageID stageId, GX::IndTexStageID indStage, GXBool signedOffset, GXBool replaceMode,
GX::IndTexMtxID mtxSel) noexcept;
static inline void SetTevKAlphaSel(GX::TevStageID stageId, GX::TevKAlphaSel sel) noexcept {
auto& state = sGXState.x68_tevStates[stageId].x19_kAlphaSel;
if (sel != state) {
state = sel;
GXSetTevKAlphaSel(stageId, sel);
}
}
static inline void SetTevKColor(GX::TevKColorID id, const GXColor& color) noexcept {
auto& state = sGXState.x58_kColors[id];
if (color != state) {
state = color;
GXSetTevKColor(id, color);
}
}
static inline void SetTevKColorSel(GX::TevStageID stageId, GX::TevKColorSel sel) noexcept {
auto& state = sGXState.x68_tevStates[stageId].x18_kColorSel;
if (sel != state) {
state = sel;
GXSetTevKColorSel(stageId, sel);
}
}
static inline void SetTevOrder(GX::TevStageID stageId, GX::TexCoordID texCoord, GX::TexMapID texMap,
GX::ChannelID color) noexcept {
u32 flags = (color & 0xFF) << 16 | (texMap & 0xFF) << 8 | (texCoord & 0xFF);
auto& state = sGXState.x68_tevStates[stageId].x14_tevOrderFlags;
if (flags != state) {
state = flags;
GXSetTevOrder(stageId, texCoord, texMap, color);
}
}
static inline void SetTexCoordGen(GX::TexCoordID dstCoord, GX::TexGenType fn, GX::TexGenSrc src, u32 mtx,
GXBool normalize, u32 postMtx) noexcept {
// TODO
}
void SetVtxDescv(GX::VtxDescList* descList) noexcept;
static inline void SetVtxDescv_Compressed(u32 descList) noexcept {
// TODO convert to GX::VtxDescList
aurora::gfx::model::set_vtx_desc_compressed(descList);
}
static inline void SetZMode(GXBool compareEnable, GX::Compare func, GXBool updateEnable) noexcept {
u32 flags = (func & 0xFF) << 2 | (u8(updateEnable) << 1) | (u8(compareEnable) & 1);
auto& state = sGXState.x52_zmode;
if (flags != state) {
state = flags;
GXSetZMode(compareEnable, func, updateEnable);
}
}
} // namespace metaforce::CGX

View File

@ -6,18 +6,19 @@
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CTextSupportShader.hpp"
#include "Runtime/GuiSys/CGuiSys.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include <zeus/Math.hpp>
namespace metaforce {
CGraphics::CProjectionState CGraphics::g_Proj;
CFogState CGraphics::g_Fog;
// CFogState CGraphics::g_Fog;
float CGraphics::g_ProjAspect = 1.f;
u32 CGraphics::g_NumBreakpointsWaiting = 0;
u32 CGraphics::g_FlippingState;
bool CGraphics::g_LastFrameUsedAbove = false;
bool CGraphics::g_InterruptLastFrameUsedAbove = false;
std::bitset<aurora::gfx::MaxLights> CGraphics::g_LightActive{};
GX::LightMask CGraphics::g_LightActive{};
zeus::CTransform CGraphics::g_GXModelView;
zeus::CTransform CGraphics::g_GXModelViewInvXpose;
zeus::CTransform CGraphics::g_GXModelMatrix = zeus::CTransform();
@ -56,9 +57,15 @@ const std::array<zeus::CMatrix3f, 6> CGraphics::skCubeBasisMats{{
{-1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, -1.f},
}};
// Stream API
static EStreamFlags sStreamFlags;
static zeus::CColor sQueuedColor;
static zeus::CVector2f sQueuedTexCoord;
static zeus::CVector3f sQueuedNormal;
void CGraphics::DisableAllLights() {
g_LightActive.reset();
aurora::gfx::set_light_state(g_LightActive);
CGX::SetChanCtrl(CGX::EChannelId::Channel0, {});
}
void CGraphics::LoadLight(ERglLight light, const CLight& info) {
@ -89,50 +96,55 @@ void CGraphics::LoadLight(ERglLight light, const CLight& info) {
}
void CGraphics::EnableLight(ERglLight light) {
CGX::SetNumChans(1);
if (!g_LightActive.test(light)) {
g_LightActive.set(light);
aurora::gfx::set_light_state(g_LightActive);
CGX::SetChanCtrl(CGX::EChannelId::Channel0, g_LightActive);
}
}
void CGraphics::SetLightState(std::bitset<aurora::gfx::MaxLights> lightState) {
void CGraphics::SetLightState(GX::LightMask lightState) {
g_LightActive = lightState;
aurora::gfx::set_light_state(g_LightActive);
const bool hasLights = lightState.any();
CGX::SetChanCtrl(CGX::EChannelId::Channel0, hasLights, GX::SRC_REG,
sStreamFlags & EStreamFlagBits::fHasColor ? GX::SRC_VTX : GX::SRC_REG, lightState,
hasLights ? GX::DF_CLAMP : GX::DF_NONE, hasLights ? GX::AF_SPOT : GX::AF_NONE);
}
void CGraphics::SetAmbientColor(const zeus::CColor& col) {
aurora::gfx::set_chan_amb_color(GX::COLOR0A0, col);
aurora::gfx::set_chan_amb_color(GX::COLOR1A1, col);
CGX::SetChanAmbColor(CGX::EChannelId::Channel0, col);
CGX::SetChanAmbColor(CGX::EChannelId::Channel1, col);
}
void CGraphics::SetFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) {
g_Fog.m_mode = mode > ERglFogMode::PerspRevExp2 ? ERglFogMode(int(mode) - 8) : mode;
g_Fog.m_color = color;
if (CGraphics::g_Proj.x18_far == CGraphics::g_Proj.x14_near || endz == startz) {
g_Fog.m_A = 0.f;
g_Fog.m_B = 0.5f;
g_Fog.m_C = 0.f;
} else {
float depthrange = CGraphics::g_Proj.x18_far - CGraphics::g_Proj.x14_near;
float fogrange = endz - startz;
g_Fog.m_A = (CGraphics::g_Proj.x18_far * CGraphics::g_Proj.x14_near) / (depthrange * fogrange);
g_Fog.m_B = CGraphics::g_Proj.x18_far / depthrange;
g_Fog.m_C = startz / fogrange;
}
// g_Fog.m_mode = mode > ERglFogMode::PerspRevExp2 ? ERglFogMode(int(mode) - 8) : mode;
// g_Fog.m_color = color;
// if (CGraphics::g_Proj.x18_far == CGraphics::g_Proj.x14_near || endz == startz) {
// g_Fog.m_A = 0.f;
// g_Fog.m_B = 0.5f;
// g_Fog.m_C = 0.f;
// } else {
// float depthrange = CGraphics::g_Proj.x18_far - CGraphics::g_Proj.x14_near;
// float fogrange = endz - startz;
// g_Fog.m_A = (CGraphics::g_Proj.x18_far * CGraphics::g_Proj.x14_near) / (depthrange * fogrange);
// g_Fog.m_B = CGraphics::g_Proj.x18_far / depthrange;
// g_Fog.m_C = startz / fogrange;
// }
CGX::SetFog(GX::FogType(mode), startz, endz, g_Proj.x14_near, g_Proj.x18_far, color);
}
void CGraphics::SetDepthWriteMode(bool compare_enable, ERglEnum comp, bool update_enable) {
g_depthFunc = comp;
aurora::gfx::set_depth_mode(compare_enable, comp, update_enable);
CGX::SetZMode(compare_enable, GX::Compare(comp), update_enable);
}
void CGraphics::SetBlendMode(ERglBlendMode mode, ERglBlendFactor src, ERglBlendFactor dst, ERglLogicOp op) {
aurora::gfx::set_blend_mode(mode, src, dst, op);
CGX::SetBlendMode(GX::BlendMode(mode), GX::BlendFactor(src), GX::BlendFactor(dst), GX::LogicOp(op));
}
void CGraphics::SetCullMode(ERglCullMode mode) {
g_cullMode = mode;
aurora::gfx::set_cull_mode(mode);
GXSetCullMode(GX::CullMode(mode));
}
void CGraphics::BeginScene() {
@ -140,7 +152,8 @@ void CGraphics::BeginScene() {
}
void CGraphics::EndScene() {
aurora::gfx::set_depth_mode(true, ERglEnum::LEqual, true);
CGX::SetZMode(true, GX::LEQUAL, true);
/* Spinwait until g_NumBreakpointsWaiting is 0 */
/* ++g_NumBreakpointsWaiting; */
/* GXCopyDisp to g_CurrenFrameBuf with clear enabled */
@ -497,26 +510,18 @@ void CGraphics::SetUseVideoFilter(bool filter) {
void CGraphics::SetClearColor(const zeus::CColor& color) {
g_ClearColor = color;
aurora::gfx::set_clear_color(color);
GXSetCopyClear(color, g_ClearDepthValue);
}
void CGraphics::SetCopyClear(const zeus::CColor& color, float depth) {
g_ClearColor = color;
g_ClearDepthValue = depth; // 1.6777215E7 * depth; Metroid Prime needed this to convert float [0,1] depth into 24 bit
// range, we no longer have this requirement
aurora::gfx::set_clear_color(color);
// TODO do we care about depth value?
// GXSetCopyClear(g_ClearColor, g_ClearDepthValue);
GXSetCopyClear(g_ClearColor, g_ClearDepthValue);
}
void CGraphics::SetIsBeginSceneClearFb(bool clear) { g_IsBeginSceneClearFb = clear; }
// Stream API
static EStreamFlags sStreamFlags;
static zeus::CColor sQueuedColor;
static zeus::CVector2f sQueuedTexCoord;
static zeus::CVector3f sQueuedNormal;
void CGraphics::SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass) {
CTevCombiners::SetupPass(stage, pass);
}
@ -583,13 +588,22 @@ void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* po
void CGraphics::SetTevStates(EStreamFlags flags) noexcept {
if (flags & EStreamFlagBits::fHasTexture) {
aurora::gfx::set_tev_order(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0);
aurora::gfx::set_tev_order(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0);
} else {
aurora::gfx::set_tev_order(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0);
aurora::gfx::set_tev_order(GX::TEVSTAGE1, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0);
CGX::SetNumChans(1);
CGX::SetNumTexGens(0);
CGX::SetNumTevStages(1);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0);
} else /* if (flags < 8) ? */ {
CGX::SetNumChans(1);
CGX::SetNumTexGens(2); // sTextureUsed & 3?
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0);
}
CGX::SetNumIndStages(0);
// TODO load TCGs
aurora::gfx::set_chan_mat_src(GX::COLOR0A0, flags & EStreamFlagBits::fHasColor ? GX::SRC_VTX : GX::SRC_REG);
const bool hasLights = g_LightActive.any();
CGX::SetChanCtrl(CGX::EChannelId::Channel0, hasLights, GX::SRC_REG,
flags & EStreamFlagBits::fHasColor ? GX::SRC_VTX : GX::SRC_REG, g_LightActive,
hasLights ? GX::DF_CLAMP : GX::DF_NONE, hasLights ? GX::AF_SPOT : GX::AF_NONE);
}
} // namespace metaforce

View File

@ -1,9 +1,9 @@
#pragma once
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Graphics/GX.hpp"
#include "Runtime/Graphics/CTevCombiners.hpp"
#include "Runtime/ConsoleVariables/CVar.hpp"
#include "Runtime/Graphics/CTevCombiners.hpp"
#include "Runtime/Graphics/GX.hpp"
#include "Runtime/RetroTypes.hpp"
#include <array>
#include <chrono>
@ -25,6 +25,83 @@ extern CVar* g_disableLighting;
class CLight;
class CTimeProvider;
enum class ERglCullMode : std::underlying_type_t<GX::CullMode> {
None = GX::CULL_NONE,
Front = GX::CULL_FRONT,
Back = GX::CULL_BACK,
All = GX::CULL_ALL,
};
enum class ERglBlendMode : std::underlying_type_t<GX::BlendMode> {
None = GX::BM_NONE,
Blend = GX::BM_BLEND,
Logic = GX::BM_LOGIC,
Subtract = GX::BM_SUBTRACT,
Max = GX::MAX_BLENDMODE,
};
enum class ERglBlendFactor : std::underlying_type_t<GX::BlendFactor> {
Zero = GX::BL_ZERO,
One = GX::BL_ONE,
SrcColor = GX::BL_SRCCLR,
InvSrcColor = GX::BL_INVSRCCLR,
SrcAlpha = GX::BL_SRCALPHA,
InvSrcAlpha = GX::BL_INVSRCALPHA,
DstAlpha = GX::BL_DSTALPHA,
InvDstAlpha = GX::BL_INVDSTALPHA,
DstColor = GX::BL_DSTCLR,
InvDstColor = GX::BL_INVDSTCLR,
};
enum class ERglLogicOp : std::underlying_type_t<GX::LogicOp> {
Clear = GX::LO_CLEAR,
And = GX::LO_AND,
RevAnd = GX::LO_REVAND,
Copy = GX::LO_COPY,
InvAnd = GX::LO_INVAND,
NoOp = GX::LO_NOOP,
Xor = GX::LO_XOR,
Or = GX::LO_OR,
Nor = GX::LO_NOR,
Equiv = GX::LO_EQUIV,
Inv = GX::LO_INV,
RevOr = GX::LO_REVOR,
InvCopy = GX::LO_INVCOPY,
InvOr = GX::LO_INVOR,
NAnd = GX::LO_NAND,
Set = GX::LO_SET,
};
enum class ERglAlphaFunc : std::underlying_type_t<GX::Compare> {
Never = GX::NEVER,
Less = GX::LESS,
Equal = GX::EQUAL,
LEqual = GX::LEQUAL,
Greater = GX::GREATER,
NEqual = GX::NEQUAL,
GEqual = GX::GEQUAL,
Always = GX::ALWAYS,
};
enum class ERglAlphaOp : std::underlying_type_t<GX::AlphaOp> {
And = GX::AOP_AND,
Or = GX::AOP_OR,
Xor = GX::AOP_XOR,
XNor = GX::AOP_XNOR,
Max = GX::MAX_ALPHAOP,
};
enum class ERglEnum : std::underlying_type_t<GX::Compare> {
Never = GX::NEVER,
Less = GX::LESS,
Equal = GX::EQUAL,
LEqual = GX::LEQUAL,
Greater = GX::GREATER,
NEqual = GX::NEQUAL,
GEqual = GX::GEQUAL,
Always = GX::ALWAYS,
};
using ERglLight = u8;
struct SViewport {
@ -104,14 +181,14 @@ public:
static CProjectionState g_Proj;
static zeus::CVector2f g_CachedDepthRange;
static CFogState g_Fog;
// static CFogState g_Fog;
static SViewport g_Viewport;
static float g_ProjAspect;
static u32 g_NumBreakpointsWaiting;
static u32 g_FlippingState;
static bool g_LastFrameUsedAbove;
static bool g_InterruptLastFrameUsedAbove;
static std::bitset<aurora::gfx::MaxLights> g_LightActive;
static GX::LightMask g_LightActive;
static zeus::CTransform g_GXModelView;
static zeus::CTransform g_GXModelViewInvXpose;
static zeus::CTransform g_GXModelMatrix;
@ -131,7 +208,7 @@ public:
static void DisableAllLights();
static void LoadLight(ERglLight light, const CLight& info);
static void EnableLight(ERglLight light);
static void SetLightState(std::bitset<aurora::gfx::MaxLights> lightState);
static void SetLightState(GX::LightMask lightState);
static void SetAmbientColor(const zeus::CColor& col);
static void SetFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color);
static void SetDepthWriteMode(bool test, ERglEnum comp, bool write);

View File

@ -17,6 +17,7 @@ set(GRAPHICS_SOURCES
CVertexMorphEffect.hpp CVertexMorphEffect.cpp
CMoviePlayer.hpp CMoviePlayer.cpp
CGraphicsPalette.hpp CGraphicsPalette.cpp
CGX.hpp CGX.cpp
CPVSVisSet.hpp CPVSVisSet.cpp
CPVSVisOctree.hpp CPVSVisOctree.cpp
CPVSAreaSet.hpp CPVSAreaSet.cpp

View File

@ -105,13 +105,15 @@ public:
void DrawUnsortedParts(CModelFlags flags);
bool IsLoaded(u32 matIdx);
TVectorRef GetPositions();
TConstVectorRef GetPositions() const;
TVectorRef GetNormals();
TConstVectorRef GetNormals() const;
u32 GetNumMaterialSets() const { return x18_matSets.size(); }
bool IsOpaque() const { return x28_modelInst->x3c_firstSortedSurf == nullptr; }
const zeus::CAABox& GetAABB() const { return x28_modelInst->x20_worldAABB; }
[[nodiscard]] TVectorRef GetPositions();
[[nodiscard]] TConstVectorRef GetPositions() const;
[[nodiscard]] TVectorRef GetNormals();
[[nodiscard]] TConstVectorRef GetNormals() const;
[[nodiscard]] u32 GetNumMaterialSets() const { return x18_matSets.size(); }
[[nodiscard]] bool IsOpaque() const { return x28_modelInst->x3c_firstSortedSurf == nullptr; }
[[nodiscard]] const zeus::CAABox& GetAABB() const { return x28_modelInst->x20_worldAABB; }
[[nodiscard]] auto& GetInstance() { return *x28_modelInst; }
[[nodiscard]] const auto& GetInstance() const { return *x28_modelInst; }
static void FrameDone();
static void EnableTextureTimeout();

View File

@ -1,12 +1,20 @@
#include "Graphics/CTevCombiners.hpp"
#include "Graphics/CGX.hpp"
namespace metaforce::CTevCombiners {
u32 CTevPass::sNextUniquePass = 0;
void CTevPass::Execute(ERglTevStage stage) const {
aurora::gfx::update_tev_stage(stage, x4_colorPass, x14_alphaPass, x24_colorOp, x38_alphaOp);
aurora::gfx::set_tev_k_color_sel(static_cast<GX::TevStageID>(stage), GX::TevKColorSel::TEV_KCSEL_8_8);
aurora::gfx::set_tev_k_alpha_sel(static_cast<GX::TevStageID>(stage), GX::TevKAlphaSel::TEV_KASEL_8_8);
const auto stageId = GX::TevStageID(stage);
CGX::SetTevColorIn(stageId, x4_colorPass.x0_a, x4_colorPass.x4_b, x4_colorPass.x8_c, x4_colorPass.xc_d);
CGX::SetTevAlphaIn(stageId, x14_alphaPass.x0_a, x14_alphaPass.x4_b, x14_alphaPass.x8_c, x14_alphaPass.xc_d);
CGX::SetTevColorOp(stageId, x24_colorOp.x4_op, x24_colorOp.x8_bias, x24_colorOp.xc_scale, x24_colorOp.x0_clamp,
x24_colorOp.x10_regId);
CGX::SetTevAlphaOp(stageId, x38_alphaOp.x4_op, x38_alphaOp.x8_bias, x38_alphaOp.xc_scale, x38_alphaOp.x0_clamp,
x38_alphaOp.x10_regId);
CGX::SetTevKColorSel(stageId, GX::TevKColorSel::TEV_KCSEL_8_8);
CGX::SetTevKAlphaSel(stageId, GX::TevKAlphaSel::TEV_KASEL_8_8);
}
constexpr u32 maxTevPasses = 2;
@ -17,10 +25,6 @@ const CTevPass skPassThru{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_RASC},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA},
};
const CTevPass skPassZero{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_ZERO},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_ZERO},
};
const CTevPass sTevPass805a5698{
{GX::TevColorArg::CC_ZERO, GX::TevColorArg::CC_RASC, GX::TevColorArg::CC_C0, GX::TevColorArg::CC_ZERO},
{GX::TevAlphaArg::CA_ZERO, GX::TevAlphaArg::CA_RASA, GX::TevAlphaArg::CA_A0, GX::TevAlphaArg::CA_ZERO},
@ -96,16 +100,13 @@ bool SetPassCombiners(ERglTevStage stage, const CTevPass& pass) {
void RecomputePasses() {
sNumEnabledPasses = 1 - static_cast<int>(sValidPasses[maxTevPasses - 1]);
for (u32 i = sNumEnabledPasses; i < maxTevPasses; ++i) {
aurora::gfx::disable_tev_stage(ERglTevStage(i));
}
// CGX::SetNumTevStages(sNumEnabledPasses);
CGX::SetNumTevStages(sNumEnabledPasses);
}
void ResetStates() {
sValidPasses.fill(false);
skPassThru.Execute(ERglTevStage::Stage0);
sNumEnabledPasses = 1;
// CGX::SetNumTevStages(1);
CGX::SetNumTevStages(1);
}
} // namespace metaforce::CTevCombiners

View File

@ -3,9 +3,80 @@
#include "Graphics/GX.hpp"
#include "RetroTypes.hpp"
#include <aurora/gfx.hpp>
namespace metaforce {
enum class ERglTevStage : std::underlying_type_t<GX::TevStageID> {
Stage0 = GX::TEVSTAGE0,
Stage1 = GX::TEVSTAGE1,
Stage2 = GX::TEVSTAGE2,
Stage3 = GX::TEVSTAGE3,
Stage4 = GX::TEVSTAGE4,
Stage5 = GX::TEVSTAGE5,
Stage6 = GX::TEVSTAGE6,
Stage7 = GX::TEVSTAGE7,
Stage8 = GX::TEVSTAGE8,
Stage9 = GX::TEVSTAGE9,
Stage10 = GX::TEVSTAGE10,
Stage11 = GX::TEVSTAGE11,
Stage12 = GX::TEVSTAGE12,
Stage13 = GX::TEVSTAGE13,
Stage14 = GX::TEVSTAGE14,
Stage15 = GX::TEVSTAGE15,
Max = GX::MAX_TEVSTAGE,
None = GX::NULL_STAGE,
};
namespace metaforce::CTevCombiners {
namespace CTevCombiners {
struct CTevOp {
bool x0_clamp = true;
GX::TevOp x4_op = GX::TevOp::TEV_ADD;
GX::TevBias x8_bias = GX::TevBias::TB_ZERO;
GX::TevScale xc_scale = GX::TevScale::CS_SCALE_1;
GX::TevRegID x10_regId = GX::TevRegID::TEVPREV;
constexpr CTevOp() = default;
constexpr CTevOp(bool clamp, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GX::TevRegID regId)
: x0_clamp(clamp), x4_op(op), x8_bias(bias), xc_scale(scale), x10_regId(regId) {}
constexpr CTevOp(u32 compressedDesc)
: x0_clamp((compressedDesc >> 8 & 1) != 0)
, x4_op(static_cast<GX::TevOp>(compressedDesc & 0xF))
, x8_bias(static_cast<GX::TevBias>(compressedDesc >> 4 & 3))
, xc_scale(static_cast<GX::TevScale>(compressedDesc >> 6 & 3))
, x10_regId(static_cast<GX::TevRegID>(compressedDesc >> 9 & 3)) {}
auto operator<=>(const CTevOp&) const = default;
};
struct ColorPass {
GX::TevColorArg x0_a;
GX::TevColorArg x4_b;
GX::TevColorArg x8_c;
GX::TevColorArg xc_d;
constexpr ColorPass(GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c, GX::TevColorArg d)
: x0_a(a), x4_b(b), x8_c(c), xc_d(d) {}
constexpr ColorPass(u32 compressedDesc)
: x0_a(static_cast<GX::TevColorArg>(compressedDesc & 0x1F))
, x4_b(static_cast<GX::TevColorArg>(compressedDesc >> 5 & 0x1F))
, x8_c(static_cast<GX::TevColorArg>(compressedDesc >> 10 & 0x1F))
, xc_d(static_cast<GX::TevColorArg>(compressedDesc >> 15 & 0x1F)) {}
auto operator<=>(const ColorPass&) const = default;
};
struct AlphaPass {
GX::TevAlphaArg x0_a;
GX::TevAlphaArg x4_b;
GX::TevAlphaArg x8_c;
GX::TevAlphaArg xc_d;
constexpr AlphaPass(GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c, GX::TevAlphaArg d)
: x0_a(a), x4_b(b), x8_c(c), xc_d(d) {}
constexpr AlphaPass(u32 compressedDesc)
: x0_a(static_cast<GX::TevAlphaArg>(compressedDesc & 0x1F))
, x4_b(static_cast<GX::TevAlphaArg>(compressedDesc >> 5 & 0x1F))
, x8_c(static_cast<GX::TevAlphaArg>(compressedDesc >> 10 & 0x1F))
, xc_d(static_cast<GX::TevAlphaArg>(compressedDesc >> 15 & 0x1F)) {}
auto operator<=>(const AlphaPass&) const = default;
};
class CTevPass {
u32 x0_id;
ColorPass x4_colorPass;
@ -29,7 +100,6 @@ public:
};
extern const CTevPass skPassThru;
extern const CTevPass skPassZero;
extern const CTevPass sTevPass805a5698;
extern const CTevPass sTevPass805a5e70;
extern const CTevPass sTevPass805a5ebc;
@ -47,4 +117,5 @@ void DeletePass(ERglTevStage stage);
bool SetPassCombiners(ERglTevStage stage, const CTevPass& pass);
void RecomputePasses();
void ResetStates();
} // namespace metaforce::CTevCombiners
} // namespace CTevCombiners
} // namespace metaforce

View File

@ -1,7 +1,11 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include "../GCNTypes.hpp"
#include <bit>
#include <bitset>
#include <zeus/CColor.hpp>
namespace GX {
enum Attr {
@ -303,12 +307,14 @@ enum TevSwapSel {
TEV_SWAP3 = 0x3,
MAX_TEVSWAP = 0x4,
};
enum TevColorChan {
CH_RED = 0x0,
CH_GREEN = 0x1,
CH_BLUE = 0x2,
CH_ALPHA = 0x3,
};
enum TevRegID {
TEVPREV = 0,
TEVREG0 = 1,
@ -319,14 +325,14 @@ enum TevRegID {
enum DiffuseFn {
DF_NONE = 0,
DF_SIGN,
DF_CLAMP,
DF_SIGN = 1,
DF_CLAMP = 2,
};
enum AttnFn {
AF_SPEC = 0,
AF_SPOT = 1,
AF_NONE,
AF_NONE = 2,
};
enum Primitive {
@ -405,7 +411,7 @@ enum Compare {
ALWAYS,
};
enum BlendFactor : uint16_t {
enum BlendFactor {
BL_ZERO,
BL_ONE,
BL_SRCCLR,
@ -413,10 +419,19 @@ enum BlendFactor : uint16_t {
BL_SRCALPHA,
BL_INVSRCALPHA,
BL_DSTALPHA,
BL_INVDSTALPHA
BL_INVDSTALPHA,
BL_DSTCLR,
BL_INVDSTCLR,
};
enum TextureFormat : uint32_t {
enum CullMode {
CULL_NONE,
CULL_FRONT,
CULL_BACK,
CULL_ALL,
};
enum TextureFormat {
TF_I4 = 0x0,
TF_I8 = 0x1,
TF_IA4 = 0x2,
@ -520,6 +535,7 @@ enum IndTexAlphaSel {
ITBA_U,
MAX_ITBALPHA,
};
enum IndTexStageID {
INDTEXSTAGE0,
INDTEXSTAGE1,
@ -611,6 +627,8 @@ enum LightID {
MAX_LIGHT = 0x100,
LIGHT_NULL = 0x000,
};
constexpr u8 MaxLights = std::bit_width<std::underlying_type_t<LightID>>(MAX_LIGHT) - 1;
using LightMask = std::bitset<MaxLights>;
enum FogType {
FOG_NONE = 0x00,
@ -627,3 +645,43 @@ enum FogType {
};
} // namespace GX
using GXColor = zeus::CColor;
using GXBool = bool;
void GXSetNumChans(u8 num) noexcept;
void GXSetNumIndStages(u8 num) noexcept;
void GXSetNumTevStages(u8 num) noexcept;
void GXSetNumTexGens(u8 num) noexcept;
void GXSetTevAlphaIn(GX::TevStageID stageId, GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c,
GX::TevAlphaArg d) noexcept;
void GXSetTevAlphaOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GXBool clamp,
GX::TevRegID outReg) noexcept;
void GXSetTevColorIn(GX::TevStageID stageId, GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c,
GX::TevColorArg d) noexcept;
void GXSetTevColorOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GXBool clamp,
GX::TevRegID outReg) noexcept;
void GXSetCullMode(GX::CullMode mode) noexcept;
void GXSetBlendMode(GX::BlendMode mode, GX::BlendFactor src, GX::BlendFactor dst, GX::LogicOp op) noexcept;
void GXSetZMode(GXBool compare_enable, GX::Compare func, GXBool update_enable) noexcept;
void GXSetTevColor(GX::TevRegID id, const GXColor& color) noexcept;
void GXSetTevKColor(GX::TevKColorID id, const GXColor& color) noexcept;
void GXSetAlphaUpdate(GXBool enabled) noexcept;
// Originally u8 instead of float
void GXSetDstAlpha(GXBool enabled, float value) noexcept;
void GXSetCopyClear(const GXColor& color, float depth) noexcept;
void GXSetTevOrder(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept;
void GXSetTevKColorSel(GX::TevStageID id, GX::TevKColorSel sel) noexcept;
void GXSetTevKAlphaSel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept;
void GXSetChanAmbColor(GX::ChannelID id, const GXColor& color) noexcept;
void GXSetChanMatColor(GX::ChannelID id, const GXColor& color) noexcept;
void GXSetChanCtrl(GX::ChannelID id, GXBool lightingEnabled, GX::ColorSrc ambSrc, GX::ColorSrc matSrc,
GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept;
// Originally u8 instead of floats
void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept;
void GXSetVtxDescv(GX::VtxDescList* list) noexcept;
void GXClearVtxDesc() noexcept;
void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept;
void GXSetTevDirect(GX::TevStageID stageId) noexcept;
void GXSetFog(GX::FogType type, float startZ, float endZ, float nearZ, float farZ, const GXColor& color) noexcept;
void GXCallDisplayList(const void* data, u32 nbytes) noexcept;

View File

@ -92,11 +92,12 @@ public:
virtual u32 GetFPS() = 0;
virtual void CacheReflection(TReflectionCallback cb, void* ctx, bool clearAfter) = 0;
virtual void DrawSpaceWarp(const zeus::CVector3f& pt, float strength) = 0;
virtual void DrawThermalModel(const CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
virtual void DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) = 0;
virtual void DrawModelDisintegrate(const CModel& model, const CTexture& tex, const zeus::CColor& color,
TConstVectorRef positions, TConstVectorRef normals) = 0;
virtual void DrawModelFlat(const CModel& model, const CModelFlags& flags, bool unsortedOnly) = 0;
virtual void DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color, TConstVectorRef positions,
TConstVectorRef normals, float t) = 0;
virtual void DrawModelFlat(CModel& model, const CModelFlags& flags, bool unsortedOnly, TConstVectorRef positions,
TConstVectorRef normals) = 0;
virtual void SetWireframeFlags(s32 flags) = 0;
virtual void SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) = 0;
virtual void RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, const TLockedToken<CModel>* model,

View File

@ -332,7 +332,7 @@ void CSamusDoll::Draw(const CStateManager& mgr, float alpha) {
bool phazonSuit = x44_suit == CPlayerState::EPlayerSuit::Phazon;
if (phazonSuit) {
aurora::gfx::set_dst_alpha(true, 1.f);
GXSetDstAlpha(true, 1.f);
}
for (size_t i = 0; i <= x118_suitModel1and2.size(); ++i) {

View File

@ -100,7 +100,7 @@ private:
bool x26d_27_enableOPTS : 1;
bool x26d_28_enableADV : 1 = false;
int x270_MBSP = 0;
std::bitset<aurora::gfx::MaxLights> x274_backupLightActive{};
GX::LightMask x274_backupLightActive{};
std::array<bool, 4> x278_hasVMD{};
CRandom16 x27c_randState;
std::array<CModVectorElement*, 4> x280_VELSources{};

View File

@ -616,7 +616,7 @@ void CActorModelParticles::LightDudeOnFire(CActor& act) {
iter->x70_onFire = true;
}
const CTexture* CActorModelParticles::GetAshyTexture(const CActor& act) {
CTexture* CActorModelParticles::GetAshyTexture(const CActor& act) {
auto iter = FindSystem(act.GetUniqueId());
if (iter != x0_items.cend() && iter->xdc_ashy && iter->xdc_ashy.IsLoaded()) {
// iter->xdc_ashy->GetBooTexture()->setClampMode(boo::TextureClampMode::ClampToEdge);

View File

@ -169,6 +169,6 @@ public:
void EnsureFirePopLoaded(CActor& act);
void EnsureIceBreakLoaded(CActor& act);
void LightDudeOnFire(CActor& act);
const CTexture* GetAshyTexture(const CActor& act);
CTexture* GetAshyTexture(const CActor& act);
};
} // namespace metaforce

View File

@ -1713,7 +1713,7 @@ void CPatterned::Render(CStateManager& mgr) {
(mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot && x402_31_thawed) ||
mgr.GetThermalDrawFlag() == EThermalDrawFlag::Bypass) {
if (x401_28_burning) {
const CTexture* ashy = mgr.GetActorModelParticles()->GetAshyTexture(*this);
CTexture* ashy = mgr.GetActorModelParticles()->GetAshyTexture(*this);
u8 alpha = GetModelAlphau8(mgr);
if (ashy != nullptr && ((!x401_29_laggedBurnDeath && alpha <= 255) || alpha <= 127)) {
if (xe5_31_pointGeneratorParticles) {

View File

@ -400,7 +400,7 @@ void CScriptPlayerActor::AddToRenderer(const zeus::CFrustum& frustum, CStateMana
void CScriptPlayerActor::Render(CStateManager& mgr) {
const bool phazonSuit = x2e8_suitRes.GetCharacterNodeId() == 3;
if (phazonSuit) {
aurora::gfx::set_dst_alpha(true, 1.f);
GXSetDstAlpha(true, 1.f);
}
CPhysicsActor::Render(mgr);

View File

@ -5,6 +5,7 @@
// TODO make this shared?
#include "../../../Runtime/Graphics/GX.hpp"
#include <bit>
#include <cstdint>
#include <utility>
@ -33,77 +34,6 @@ enum class ERglFogMode : uint32_t {
OrthoRevExp2 = 0x0F
};
enum class ERglCullMode { None = 0, Front = 1, Back = 2, All = 3 };
enum class ERglBlendMode { None = 0, Blend = 1, Logic = 2, Subtract = 3 };
enum class ERglBlendFactor {
Zero = 0,
One = 1,
SrcColor = 2,
InvSrcColor = 3,
SrcAlpha = 4,
InvSrcAlpha = 5,
DstAlpha = 6,
InvDstAlpha = 7,
DstColor = 8,
InvDstColor = 9,
};
enum class ERglLogicOp {
Clear = 0,
And = 1,
RevAnd = 2,
Copy = 3,
InvAnd = 4,
NoOp = 5,
Xor = 6,
Or = 7,
Nor = 8,
Equiv = 9,
Inv = 10,
RevOr = 11,
InvCopy = 12,
InvOr = 13,
NAnd = 14,
Set = 15
};
enum class ERglAlphaFunc {
Never = 0,
Less = 1,
Equal = 2,
LEqual = 3,
Greater = 4,
NEqual = 5,
GEqual = 6,
Always = 7
};
enum class ERglAlphaOp { And = 0, Or = 1, Xor = 2, XNor = 3 };
enum class ERglEnum { Never = 0, Less = 1, Equal = 2, LEqual = 3, Greater = 4, NEqual = 5, GEqual = 6, Always = 7 };
enum class ERglTevStage : u32 {
Stage0,
Stage1,
Stage2,
Stage3,
Stage4,
Stage5,
Stage6,
Stage7,
Stage8,
Stage9,
Stage10,
Stage11,
Stage12,
Stage13,
Stage14,
Stage15,
MAX
};
enum class ETexelFormat {
Invalid = -1,
I4 = 0,
@ -142,60 +72,6 @@ enum class EStreamFlagBits : u8 {
fHasTexture = 0x4,
};
using EStreamFlags = Flags<EStreamFlagBits>;
namespace CTevCombiners {
struct CTevOp {
bool x0_clamp = true;
GX::TevOp x4_op = GX::TevOp::TEV_ADD;
GX::TevBias x8_bias = GX::TevBias::TB_ZERO;
GX::TevScale xc_scale = GX::TevScale::CS_SCALE_1;
GX::TevRegID x10_regId = GX::TevRegID::TEVPREV;
constexpr CTevOp() = default;
constexpr CTevOp(bool clamp, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, GX::TevRegID regId)
: x0_clamp(clamp), x4_op(op), x8_bias(bias), xc_scale(scale), x10_regId(regId) {}
constexpr CTevOp(u32 compressedDesc)
: x0_clamp((compressedDesc >> 8 & 1) != 0)
, x4_op(static_cast<GX::TevOp>(compressedDesc & 0xF))
, x8_bias(static_cast<GX::TevBias>(compressedDesc >> 4 & 3))
, xc_scale(static_cast<GX::TevScale>(compressedDesc >> 6 & 3))
, x10_regId(static_cast<GX::TevRegID>(compressedDesc >> 9 & 3)) {}
auto operator<=>(const CTevOp&) const = default;
};
struct ColorPass {
GX::TevColorArg x0_a;
GX::TevColorArg x4_b;
GX::TevColorArg x8_c;
GX::TevColorArg xc_d;
constexpr ColorPass(GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c, GX::TevColorArg d)
: x0_a(a), x4_b(b), x8_c(c), xc_d(d) {}
constexpr ColorPass(u32 compressedDesc)
: x0_a(static_cast<GX::TevColorArg>(compressedDesc & 0x1F))
, x4_b(static_cast<GX::TevColorArg>(compressedDesc >> 5 & 0x1F))
, x8_c(static_cast<GX::TevColorArg>(compressedDesc >> 10 & 0x1F))
, xc_d(static_cast<GX::TevColorArg>(compressedDesc >> 15 & 0x1F)) {}
auto operator<=>(const ColorPass&) const = default;
};
struct AlphaPass {
GX::TevAlphaArg x0_a;
GX::TevAlphaArg x4_b;
GX::TevAlphaArg x8_c;
GX::TevAlphaArg xc_d;
constexpr AlphaPass(GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c, GX::TevAlphaArg d)
: x0_a(a), x4_b(b), x8_c(c), xc_d(d) {}
constexpr AlphaPass(u32 compressedDesc)
: x0_a(static_cast<GX::TevAlphaArg>(compressedDesc & 0x1F))
, x4_b(static_cast<GX::TevAlphaArg>(compressedDesc >> 5 & 0x1F))
, x8_c(static_cast<GX::TevAlphaArg>(compressedDesc >> 10 & 0x1F))
, xc_d(static_cast<GX::TevAlphaArg>(compressedDesc >> 15 & 0x1F)) {}
auto operator<=>(const AlphaPass&) const = default;
};
} // namespace CTevCombiners
} // namespace metaforce
namespace aurora::gfx {
@ -246,7 +122,6 @@ enum class ZComp : uint8_t {
Always,
};
constexpr u32 MaxLights = 8;
struct Light {
zeus::CVector3f pos{0.f, 0.f, 0.f};
zeus::CVector3f dir{0.f, 0.f, -1.f};
@ -265,36 +140,13 @@ void stream_end() noexcept;
// GX state
void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept;
void unbind_texture(GX::TexMapID id) noexcept;
void disable_tev_stage(metaforce::ERglTevStage stage) noexcept;
void update_tev_stage(metaforce::ERglTevStage stage, const metaforce::CTevCombiners::ColorPass& colPass,
const metaforce::CTevCombiners::AlphaPass& alphaPass,
const metaforce::CTevCombiners::CTevOp& colorOp,
const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept;
void set_cull_mode(metaforce::ERglCullMode mode) noexcept;
void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst,
metaforce::ERglLogicOp op) noexcept;
void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept;
void set_tev_reg_color(GX::TevRegID id, const zeus::CColor& color) noexcept;
void set_tev_k_color(GX::TevKColorID id, const zeus::CColor& color) noexcept;
void set_alpha_update(bool enabled) noexcept;
void set_dst_alpha(bool enabled, float value) noexcept;
void set_clear_color(const zeus::CColor& color) noexcept;
void set_tev_order(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept;
void set_tev_k_color_sel(GX::TevStageID id, GX::TevKColorSel sel) noexcept;
void set_tev_k_alpha_sel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept;
void set_chan_amb_color(GX::ChannelID id, const zeus::CColor& color) noexcept;
void set_chan_mat_color(GX::ChannelID id, const zeus::CColor& color) noexcept;
void set_chan_mat_src(GX::ChannelID id, GX::ColorSrc src) noexcept;
// Model state
void set_alpha_discard(bool v);
void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept;
void update_projection(const zeus::CMatrix4f& proj) noexcept;
void update_fog_state(const metaforce::CFogState& state) noexcept;
void load_light(GX::LightID id, const Light& light) noexcept;
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept;
void set_light_state(std::bitset<MaxLights> bits) noexcept;
void set_light_state(GX::LightMask bits) noexcept;
void set_viewport(const zeus::CRectangle& rect, float znear, float zfar) noexcept;
void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept;

View File

@ -3,11 +3,5 @@
#include "common.hpp"
namespace aurora::gfx::model {
void set_vertex_buffer(const std::vector<zeus::CVector3f>* data) noexcept;
void set_normal_buffer(const std::vector<zeus::CVector3f>* norm) noexcept;
void set_tex0_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept; // Tex coords for TEX0
void set_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept; // Tex coords for the TEX1-7
void set_vtx_desc_compressed(u32 vtxDesc) noexcept;
void queue_surface(const u8* dlStart, u32 dlSize) noexcept;
} // namespace aurora::gfx::model

View File

@ -301,10 +301,10 @@ void app_run(std::unique_ptr<AppDelegate> app, Icon icon, int argc, char** argv)
.storeOp = wgpu::StoreOp::Store,
.clearColor =
{
.r = gfx::gx::g_clearColor.r(),
.g = gfx::gx::g_clearColor.g(),
.b = gfx::gx::g_clearColor.b(),
.a = gfx::gx::g_clearColor.a(),
.r = gfx::gx::g_gxState.clearColor.r(),
.g = gfx::gx::g_gxState.clearColor.g(),
.b = gfx::gx::g_gxState.clearColor.b(),
.a = gfx::gx::g_gxState.clearColor.a(),
},
},
};

View File

@ -4,7 +4,119 @@
#include "common.hpp"
#include <unordered_map>
#include <magic_enum.hpp>
using aurora::gfx::gx::g_gxState;
static logvisor::Module Log("aurora::gx");
void GXSetNumChans(u8 num) noexcept { g_gxState.numChans = num; }
void GXSetNumIndStages(u8 num) noexcept { g_gxState.numIndStages = num; }
void GXSetNumTevStages(u8 num) noexcept { g_gxState.numTevStages = num; }
void GXSetNumTexGens(u8 num) noexcept { g_gxState.numTexGens = num; }
void GXSetTevAlphaIn(GX::TevStageID stageId, GX::TevAlphaArg a, GX::TevAlphaArg b, GX::TevAlphaArg c,
GX::TevAlphaArg d) noexcept {
g_gxState.tevStages[stageId].alphaPass = {a, b, c, d};
}
void GXSetTevAlphaOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, bool clamp,
GX::TevRegID outReg) noexcept {
g_gxState.tevStages[stageId].alphaOp = {op, bias, scale, outReg, clamp};
}
void GXSetTevColorIn(GX::TevStageID stageId, GX::TevColorArg a, GX::TevColorArg b, GX::TevColorArg c,
GX::TevColorArg d) noexcept {
g_gxState.tevStages[stageId].colorPass = {a, b, c, d};
}
void GXSetTevColorOp(GX::TevStageID stageId, GX::TevOp op, GX::TevBias bias, GX::TevScale scale, bool clamp,
GX::TevRegID outReg) noexcept {
g_gxState.tevStages[stageId].colorOp = {op, bias, scale, outReg, clamp};
}
void GXSetCullMode(GX::CullMode mode) noexcept { g_gxState.cullMode = mode; }
void GXSetBlendMode(GX::BlendMode mode, GX::BlendFactor src, GX::BlendFactor dst, GX::LogicOp op) noexcept {
g_gxState.blendMode = mode;
g_gxState.blendFacSrc = src;
g_gxState.blendFacDst = dst;
g_gxState.blendOp = op;
}
void GXSetZMode(bool compare_enable, GX::Compare func, bool update_enable) noexcept {
g_gxState.depthCompare = compare_enable;
g_gxState.depthFunc = func;
g_gxState.depthUpdate = update_enable;
}
void GXSetTevColor(GX::TevRegID id, const zeus::CColor& color) noexcept {
if (id < GX::TEVREG0 || id > GX::TEVREG2) {
Log.report(logvisor::Fatal, FMT_STRING("bad tevreg {}"), id);
unreachable();
}
g_gxState.colorRegs[id - 1] = color;
}
void GXSetTevKColor(GX::TevKColorID id, const zeus::CColor& color) noexcept {
if (id >= GX::MAX_KCOLOR) {
Log.report(logvisor::Fatal, FMT_STRING("bad kcolor {}"), id);
unreachable();
}
g_gxState.kcolors[id] = color;
}
void GXSetAlphaUpdate(bool enabled) noexcept { g_gxState.alphaUpdate = enabled; }
void GXSetDstAlpha(bool enabled, float value) noexcept {
if (enabled) {
g_gxState.dstAlpha = value;
} else {
g_gxState.dstAlpha.reset();
}
}
void GXSetCopyClear(const zeus::CColor& color, float depth) noexcept { g_gxState.clearColor = color; }
void GXSetTevOrder(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept {
auto& stage = g_gxState.tevStages[id];
stage.texCoordId = tcid;
stage.texMapId = tmid;
stage.channelId = cid;
}
void GXSetTevKColorSel(GX::TevStageID id, GX::TevKColorSel sel) noexcept { g_gxState.tevStages[id].kcSel = sel; }
void GXSetTevKAlphaSel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept { g_gxState.tevStages[id].kaSel = sel; }
void GXSetChanAmbColor(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id);
unreachable();
}
g_gxState.colorChannelState[id - GX::COLOR0A0].ambColor = color;
}
void GXSetChanMatColor(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id);
unreachable();
}
g_gxState.colorChannelState[id - GX::COLOR0A0].matColor = color;
}
void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc, GX::ColorSrc matSrc,
GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id);
unreachable();
}
if (diffFn != GX::DF_NONE && diffFn != GX::DF_CLAMP) {
Log.report(logvisor::Fatal, FMT_STRING("unhandled diffuse fn {}"), diffFn);
unreachable();
}
if (attnFn != GX::AF_NONE && attnFn != GX::AF_SPOT) {
Log.report(logvisor::Fatal, FMT_STRING("unhandled attn fn {}"), attnFn);
unreachable();
}
u32 idx = id - GX::COLOR0A0;
auto& chan = g_gxState.colorChannelConfig[idx];
chan.lightingEnabled = lightingEnabled;
chan.ambSrc = ambSrc;
chan.matSrc = matSrc;
g_gxState.colorChannelState[idx].lightState = lightState;
}
void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept {
if (comp0 == GX::ALWAYS && comp1 == GX::ALWAYS) {
g_gxState.alphaDiscard.reset();
} else if (comp0 == GX::GEQUAL && comp1 == GX::NEVER) {
g_gxState.alphaDiscard = ref0;
} else {
Log.report(logvisor::Fatal, FMT_STRING("GXSetAlphaCompare: unknown operands"));
unreachable();
}
}
void GXSetVtxDescv(GX::VtxDescList* list) noexcept;
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx");
@ -14,51 +126,13 @@ extern std::mutex g_pipelineMutex;
// GX state
void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept {
gx::g_textures[static_cast<size_t>(id)] = {tex, clamp, lod};
gx::g_gxState.textures[static_cast<size_t>(id)] = {tex, clamp, lod};
}
void unbind_texture(GX::TexMapID id) noexcept { gx::g_textures[static_cast<size_t>(id)].reset(); }
void set_cull_mode(metaforce::ERglCullMode mode) noexcept { gx::g_cullMode = mode; }
void set_blend_mode(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor src, metaforce::ERglBlendFactor dst,
metaforce::ERglLogicOp op) noexcept {
gx::g_blendMode = mode;
gx::g_blendFacSrc = src;
gx::g_blendFacDst = dst;
gx::g_blendOp = op;
}
void set_depth_mode(bool compare_enable, metaforce::ERglEnum func, bool update_enable) noexcept {
gx::g_depthCompare = compare_enable;
gx::g_depthFunc = func;
gx::g_depthUpdate = update_enable;
}
void set_tev_reg_color(GX::TevRegID id, const zeus::CColor& color) noexcept {
if (id < GX::TEVREG0 || id > GX::TEVREG2) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_reg_color: bad reg {}"), id);
unreachable();
}
gx::g_colorRegs[id - 1] = color;
}
void set_tev_k_color(GX::TevKColorID id, const zeus::CColor& color) noexcept {
if (id >= GX::MAX_KCOLOR) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_color: bad reg {}"), id);
unreachable();
}
gx::g_kcolors[id] = color;
}
void set_alpha_update(bool enabled) noexcept { gx::g_alphaUpdate = enabled; }
void set_dst_alpha(bool enabled, float value) noexcept {
if (enabled) {
gx::g_dstAlpha = value;
} else {
gx::g_dstAlpha.reset();
}
}
void set_clear_color(const zeus::CColor& color) noexcept { gx::g_clearColor = color; }
void set_alpha_discard(bool v) { gx::g_alphaDiscard = v; }
void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast<size_t>(id)].reset(); }
void update_model_view(const zeus::CMatrix4f& mv, const zeus::CMatrix4f& mv_inv) noexcept {
gx::g_mv = mv;
gx::g_mvInv = mv_inv;
gx::g_gxState.mv = mv;
gx::g_gxState.mvInv = mv_inv;
}
constexpr zeus::CMatrix4f DepthCorrect{
// clang-format off
@ -68,133 +142,44 @@ constexpr zeus::CMatrix4f DepthCorrect{
0.f, 0.f, 0.f, 1.f,
// clang-format on
};
void update_projection(const zeus::CMatrix4f& proj) noexcept { gx::g_proj = DepthCorrect * proj; }
void update_fog_state(const metaforce::CFogState& state) noexcept { gx::g_fogState = state; }
void update_projection(const zeus::CMatrix4f& proj) noexcept { gx::g_gxState.proj = DepthCorrect * proj; }
void update_fog_state(const metaforce::CFogState& state) noexcept { gx::g_gxState.fogState = state; }
void disable_tev_stage(metaforce::ERglTevStage stage) noexcept { gx::g_tevStages[static_cast<size_t>(stage)].reset(); }
void update_tev_stage(metaforce::ERglTevStage stage, const metaforce::CTevCombiners::ColorPass& colPass,
const metaforce::CTevCombiners::AlphaPass& alphaPass,
const metaforce::CTevCombiners::CTevOp& colorOp,
const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept {
gx::g_tevStages[static_cast<size_t>(stage)] = {colPass, alphaPass, colorOp, alphaOp};
void load_light(GX::LightID id, const Light& light) noexcept { gx::g_gxState.lights[std::log2<u32>(id)] = light; }
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept {
gx::g_gxState.lights[std::log2<u32>(id)] = ambient;
}
void set_tev_order(GX::TevStageID id, GX::TexCoordID tcid, GX::TexMapID tmid, GX::ChannelID cid) noexcept {
auto& stage = gx::g_tevStages[id];
if (!stage) {
// Log.report(logvisor::Fatal, FMT_STRING("set_tev_order: disabled stage {}"), id);
// unreachable();
return;
}
stage->texCoordId = tcid;
stage->texMapId = tmid;
stage->channelId = cid;
}
void set_tev_k_color_sel(GX::TevStageID id, GX::TevKColorSel sel) noexcept {
auto& stage = gx::g_tevStages[id];
if (!stage) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_color_sel: disabled stage {}"), id);
unreachable();
}
stage->kcSel = sel;
}
void set_tev_k_alpha_sel(GX::TevStageID id, GX::TevKAlphaSel sel) noexcept {
auto& stage = gx::g_tevStages[id];
if (!stage) {
Log.report(logvisor::Fatal, FMT_STRING("set_tev_k_alpha_sel: disabled stage {}"), id);
unreachable();
}
stage->kaSel = sel;
}
void set_chan_amb_color(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("set_chan_amb_color: invalid channel {}"), id);
unreachable();
}
gx::g_colorChannels[id - GX::COLOR0A0].ambColor = color;
}
void set_chan_mat_color(GX::ChannelID id, const zeus::CColor& color) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("set_chan_mat_color: invalid channel {}"), id);
unreachable();
}
gx::g_colorChannels[id - GX::COLOR0A0].matColor = color;
}
void set_chan_mat_src(GX::ChannelID id, GX::ColorSrc src) noexcept {
if (id < GX::COLOR0A0 || id > GX::COLOR1A1) {
Log.report(logvisor::Fatal, FMT_STRING("set_chan_mat_src: invalid channel {}"), id);
unreachable();
}
gx::g_colorChannels[id - GX::COLOR0A0].matSrc = src;
}
static inline u8 light_idx(GX::LightID id) {
#ifdef _MSC_VER
unsigned long r = 0;
_BitScanForward(&r, id);
return r;
#else
return __builtin_ctz(id);
#endif
}
void load_light(GX::LightID id, const Light& light) noexcept { gx::g_lights[light_idx(id)] = light; }
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept { gx::g_lights[light_idx(id)] = ambient; }
void set_light_state(std::bitset<MaxLights> bits) noexcept { gx::g_lightState = bits; }
void set_light_state(GX::LightMask bits) noexcept { gx::g_gxState.lightState = bits; }
namespace gx {
using gpu::g_device;
using gpu::g_graphicsConfig;
zeus::CMatrix4f g_mv;
zeus::CMatrix4f g_mvInv;
zeus::CMatrix4f g_proj;
metaforce::CFogState g_fogState;
metaforce::ERglCullMode g_cullMode;
metaforce::ERglBlendMode g_blendMode;
metaforce::ERglBlendFactor g_blendFacSrc;
metaforce::ERglBlendFactor g_blendFacDst;
metaforce::ERglLogicOp g_blendOp;
bool g_depthCompare;
bool g_depthUpdate;
metaforce::ERglEnum g_depthFunc;
std::array<zeus::CColor, 3> g_colorRegs;
std::array<zeus::CColor, GX::MAX_KCOLOR> g_kcolors;
bool g_alphaUpdate;
std::optional<float> g_dstAlpha;
zeus::CColor g_clearColor = zeus::skClear;
bool g_alphaDiscard;
GXState g_gxState;
std::array<SChannelState, 2> g_colorChannels;
std::array<LightVariant, MaxLights> g_lights;
std::bitset<MaxLights> g_lightState;
const TextureBind& get_texture(GX::TexMapID id) noexcept { return g_gxState.textures[static_cast<size_t>(id)]; }
std::array<std::optional<STevStage>, maxTevStages> g_tevStages;
std::array<TextureBind, maxTextures> g_textures;
const gx::TextureBind& get_texture(GX::TexMapID id) noexcept { return gx::g_textures[static_cast<size_t>(id)]; }
static inline wgpu::BlendFactor to_blend_factor(metaforce::ERglBlendFactor fac) {
static inline wgpu::BlendFactor to_blend_factor(GX::BlendFactor fac) {
switch (fac) {
case metaforce::ERglBlendFactor::Zero:
case GX::BL_ZERO:
return wgpu::BlendFactor::Zero;
case metaforce::ERglBlendFactor::One:
case GX::BL_ONE:
return wgpu::BlendFactor::One;
case metaforce::ERglBlendFactor::SrcColor:
case GX::BL_SRCCLR:
return wgpu::BlendFactor::Src;
case metaforce::ERglBlendFactor::InvSrcColor:
case GX::BL_INVSRCCLR:
return wgpu::BlendFactor::OneMinusSrc;
case metaforce::ERglBlendFactor::SrcAlpha:
case GX::BL_SRCALPHA:
return wgpu::BlendFactor::SrcAlpha;
case metaforce::ERglBlendFactor::InvSrcAlpha:
case GX::BL_INVSRCALPHA:
return wgpu::BlendFactor::OneMinusSrcAlpha;
case metaforce::ERglBlendFactor::DstAlpha:
case GX::BL_DSTALPHA:
return wgpu::BlendFactor::DstAlpha;
case metaforce::ERglBlendFactor::InvDstAlpha:
case GX::BL_INVDSTALPHA:
return wgpu::BlendFactor::OneMinusDstAlpha;
case metaforce::ERglBlendFactor::DstColor:
case GX::BL_DSTCLR:
return wgpu::BlendFactor::Dst;
case metaforce::ERglBlendFactor::InvDstColor:
case GX::BL_INVDSTCLR:
return wgpu::BlendFactor::OneMinusDst;
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid blend factor {}"), fac);
@ -202,23 +187,23 @@ static inline wgpu::BlendFactor to_blend_factor(metaforce::ERglBlendFactor fac)
}
}
static inline wgpu::CompareFunction to_compare_function(metaforce::ERglEnum func) {
static inline wgpu::CompareFunction to_compare_function(GX::Compare func) {
switch (func) {
case metaforce::ERglEnum::Never:
case GX::NEVER:
return wgpu::CompareFunction::Never;
case metaforce::ERglEnum::Less:
case GX::LESS:
return wgpu::CompareFunction::Less;
case metaforce::ERglEnum::Equal:
case GX::EQUAL:
return wgpu::CompareFunction::Equal;
case metaforce::ERglEnum::LEqual:
case GX::LEQUAL:
return wgpu::CompareFunction::LessEqual;
case metaforce::ERglEnum::Greater:
case GX::GREATER:
return wgpu::CompareFunction::Greater;
case metaforce::ERglEnum::NEqual:
case GX::NEQUAL:
return wgpu::CompareFunction::NotEqual;
case metaforce::ERglEnum::GEqual:
case GX::GEQUAL:
return wgpu::CompareFunction::GreaterEqual;
case metaforce::ERglEnum::Always:
case GX::ALWAYS:
return wgpu::CompareFunction::Always;
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid depth fn {}"), func);
@ -226,10 +211,10 @@ static inline wgpu::CompareFunction to_compare_function(metaforce::ERglEnum func
}
}
static inline wgpu::BlendState to_blend_state(metaforce::ERglBlendMode mode, metaforce::ERglBlendFactor srcFac,
metaforce::ERglBlendFactor dstFac, std::optional<float> dstAlpha) {
if (mode != metaforce::ERglBlendMode::Blend) {
Log.report(logvisor::Fatal, FMT_STRING("How to {}?"), magic_enum::enum_name(mode));
static inline wgpu::BlendState to_blend_state(GX::BlendMode mode, GX::BlendFactor srcFac, GX::BlendFactor dstFac,
std::optional<float> dstAlpha) {
if (mode != GX::BM_BLEND) {
Log.report(logvisor::Fatal, FMT_STRING("How to {}?"), mode);
}
const auto colorBlendComponent = wgpu::BlendComponent{
.operation = wgpu::BlendOperation::Add,
@ -258,7 +243,7 @@ static inline wgpu::ColorWriteMask to_write_mask(bool alphaUpdate) {
return writeMask;
}
static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, metaforce::ERglCullMode e_cullMode) {
static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, GX::CullMode gx_cullMode) {
wgpu::PrimitiveTopology primitive = wgpu::PrimitiveTopology::TriangleList;
switch (gx_prim) {
case GX::TRIANGLES:
@ -272,14 +257,17 @@ static inline wgpu::PrimitiveState to_primitive_state(GX::Primitive gx_prim, met
}
wgpu::FrontFace frontFace = wgpu::FrontFace::CCW;
wgpu::CullMode cullMode = wgpu::CullMode::None;
switch (e_cullMode) {
case metaforce::ERglCullMode::Front:
switch (gx_cullMode) {
case GX::CULL_FRONT:
frontFace = wgpu::FrontFace::CW;
cullMode = wgpu::CullMode::Front;
break;
case metaforce::ERglCullMode::Back:
case GX::CULL_BACK:
cullMode = wgpu::CullMode::Back;
break;
case GX::CULL_ALL:
Log.report(logvisor::Fatal, FMT_STRING("Unsupported cull mode {}"), gx_cullMode);
unreachable();
default:
break;
}
@ -345,29 +333,24 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn
ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive,
const BindGroupRanges& ranges) noexcept {
for (size_t idx = 0; const auto& item : g_tevStages) {
// Copy until disabled TEV stage (indicating end)
if (!item) {
break;
}
config.shaderConfig.tevStages[idx++] = item;
for (size_t i = 0; i < g_gxState.numTevStages; ++i) {
config.shaderConfig.tevStages[i] = g_gxState.tevStages[i];
}
config.shaderConfig.channelMatSrcs[0] = g_colorChannels[0].matSrc;
config.shaderConfig.channelMatSrcs[1] = g_colorChannels[1].matSrc;
config.shaderConfig.alphaDiscard = g_alphaDiscard;
config.shaderConfig.colorChannels = g_gxState.colorChannelConfig;
config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard;
config = {
.shaderConfig = config.shaderConfig,
.primitive = primitive,
.depthFunc = g_depthFunc,
.cullMode = g_cullMode,
.blendMode = g_blendMode,
.blendFacSrc = g_blendFacSrc,
.blendFacDst = g_blendFacDst,
.blendOp = g_blendOp,
.dstAlpha = g_dstAlpha,
.depthCompare = g_depthCompare,
.depthUpdate = g_depthUpdate,
.alphaUpdate = g_alphaUpdate,
.depthFunc = g_gxState.depthFunc,
.cullMode = g_gxState.cullMode,
.blendMode = g_gxState.blendMode,
.blendFacSrc = g_gxState.blendFacSrc,
.blendFacDst = g_gxState.blendFacDst,
.blendOp = g_gxState.blendOp,
.dstAlpha = g_gxState.dstAlpha,
.depthCompare = g_gxState.depthCompare,
.depthUpdate = g_gxState.depthUpdate,
.alphaUpdate = g_gxState.alphaUpdate,
};
// TODO separate shader info from build_shader for async
{
@ -381,51 +364,51 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit
Range build_uniform(const ShaderInfo& info) noexcept {
auto [buf, range] = map_uniform(info.uniformSize);
{
buf.append(&g_mv, 64);
buf.append(&g_mvInv, 64);
buf.append(&g_proj, 64);
buf.append(&g_gxState.mv, 64);
buf.append(&g_gxState.mvInv, 64);
buf.append(&g_gxState.proj, 64);
}
for (int i = 0; i < info.usesTevReg.size(); ++i) {
if (!info.usesTevReg.test(i)) {
continue;
}
buf.append(&g_colorRegs[i], 16);
}
if (info.sampledColorChannels.any()) {
zeus::CColor ambient = zeus::skClear;
int addedLights = 0;
for (int i = 0; i < g_lightState.size(); ++i) {
if (!g_lightState.test(i)) {
continue;
}
const auto& variant = g_lights[i];
if (std::holds_alternative<zeus::CColor>(variant)) {
ambient += std::get<zeus::CColor>(variant);
} else if (std::holds_alternative<Light>(variant)) {
static_assert(sizeof(Light) == 80);
buf.append(&std::get<Light>(variant), sizeof(Light));
++addedLights;
}
}
constexpr Light emptyLight{};
for (int i = addedLights; i < MaxLights; ++i) {
buf.append(&emptyLight, sizeof(Light));
}
buf.append(&ambient, 16);
// fmt::print(FMT_STRING("Added lights: {}, ambient: {},{},{},{}\n"), addedLights, ambient.r(), ambient.g(), ambient.b(), ambient.a());
buf.append(&g_gxState.colorRegs[i], 16);
}
for (int i = 0; i < info.sampledColorChannels.size(); ++i) {
if (!info.sampledColorChannels.test(i)) {
continue;
}
buf.append(&g_colorChannels[i].ambColor, 16);
buf.append(&g_colorChannels[i].matColor, 16);
buf.append(&g_gxState.colorChannelState[i].ambColor, 16);
buf.append(&g_gxState.colorChannelState[i].matColor, 16);
if (g_gxState.colorChannelConfig[i].lightingEnabled) {
zeus::CColor ambient = zeus::skClear;
int addedLights = 0;
for (int li = 0; li < g_gxState.lightState.size(); ++li) {
if (!g_gxState.lightState.test(li)) {
continue;
}
const auto& variant = g_gxState.lights[li];
if (std::holds_alternative<zeus::CColor>(variant)) {
ambient += std::get<zeus::CColor>(variant);
} else if (std::holds_alternative<Light>(variant)) {
static_assert(sizeof(Light) == 80);
buf.append(&std::get<Light>(variant), sizeof(Light));
++addedLights;
}
}
constexpr Light emptyLight{};
for (int li = addedLights; li < GX::MaxLights; ++li) {
buf.append(&emptyLight, sizeof(Light));
}
buf.append(&ambient, 16);
}
}
for (int i = 0; i < info.sampledKcolors.size(); ++i) {
if (!info.sampledKcolors.test(i)) {
for (int i = 0; i < info.sampledKColors.size(); ++i) {
if (!info.sampledKColors.test(i)) {
continue;
}
buf.append(&g_kcolors[i], 16);
buf.append(&g_gxState.kcolors[i], 16);
}
for (int i = 0; i < info.sampledTextures.size(); ++i) {
if (!info.sampledTextures.test(i)) {
@ -480,13 +463,13 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
.size = ranges.packedTcDataRange.second - ranges.packedTcDataRange.first,
},
};
std::array<wgpu::BindGroupEntry, maxTextures> samplerEntries;
std::array<wgpu::BindGroupEntry, maxTextures> textureEntries;
std::array<wgpu::BindGroupEntry, MaxTextures> samplerEntries;
std::array<wgpu::BindGroupEntry, MaxTextures> textureEntries;
for (u32 texIdx = 0, i = 0; texIdx < info.sampledTextures.size(); ++texIdx) {
if (!info.sampledTextures.test(texIdx)) {
continue;
}
const auto& tex = g_textures[texIdx];
const auto& tex = g_gxState.textures[texIdx];
if (!tex) {
Log.report(logvisor::Fatal, FMT_STRING("unbound texture {}"), texIdx);
unreachable();
@ -592,8 +575,8 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
out.samplerLayout = sl;
out.textureLayout = tl;
} else {
std::array<wgpu::BindGroupLayoutEntry, maxTextures> samplerEntries;
std::array<wgpu::BindGroupLayoutEntry, maxTextures> textureEntries;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> samplerEntries;
std::array<wgpu::BindGroupLayoutEntry, MaxTextures> textureEntries;
for (u32 i = 0; i < textureCount; ++i) {
samplerEntries[i] = {
.binding = i,
@ -637,7 +620,7 @@ void shutdown() noexcept {
// TODO we should probably store this all in g_state.gx instead
sUniformBindGroupLayouts.clear();
sTextureBindGroupLayouts.clear();
g_textures.fill({});
g_gxState.textures.fill({});
g_gxCachedShaders.clear();
}

View File

@ -5,51 +5,36 @@
#include <variant>
namespace aurora::gfx::gx {
extern zeus::CMatrix4f g_mv;
extern zeus::CMatrix4f g_mvInv;
extern zeus::CMatrix4f g_proj;
extern metaforce::CFogState g_fogState;
extern metaforce::ERglCullMode g_cullMode;
extern metaforce::ERglBlendMode g_blendMode;
extern metaforce::ERglBlendFactor g_blendFacSrc;
extern metaforce::ERglBlendFactor g_blendFacDst;
extern metaforce::ERglLogicOp g_blendOp;
extern bool g_depthCompare;
extern bool g_depthUpdate;
extern metaforce::ERglEnum g_depthFunc;
extern std::array<zeus::CColor, 3> g_colorRegs;
extern std::array<zeus::CColor, GX::MAX_KCOLOR> g_kcolors;
extern bool g_alphaUpdate;
extern std::optional<float> g_dstAlpha;
extern zeus::CColor g_clearColor;
extern bool g_alphaDiscard;
constexpr u32 MaxTextures = GX::MAX_TEXMAP;
constexpr u32 MaxTevStages = GX::MAX_TEVSTAGE;
constexpr u32 MaxColorChannels = 2; // COLOR0A0, COLOR1A1
constexpr u32 MaxTevRegs = 3; // TEVREG0-2
constexpr u32 MaxKColors = GX::MAX_KCOLOR;
struct SChannelState {
zeus::CColor matColor;
zeus::CColor ambColor;
GX::ColorSrc matSrc;
template <typename Arg, Arg Default>
struct TevPass {
Arg a = Default;
Arg b = Default;
Arg c = Default;
Arg d = Default;
};
extern std::array<SChannelState, 2> g_colorChannels;
using LightVariant = std::variant<std::monostate, Light, zeus::CColor>;
extern std::array<LightVariant, MaxLights> g_lights;
extern std::bitset<MaxLights> g_lightState;
struct STevStage {
metaforce::CTevCombiners::ColorPass colorPass;
metaforce::CTevCombiners::AlphaPass alphaPass;
metaforce::CTevCombiners::CTevOp colorOp;
metaforce::CTevCombiners::CTevOp alphaOp;
struct TevOp {
GX::TevOp op = GX::TevOp::TEV_ADD;
GX::TevBias bias = GX::TevBias::TB_ZERO;
GX::TevScale scale = GX::TevScale::CS_SCALE_1;
GX::TevRegID outReg = GX::TevRegID::TEVPREV;
bool clamp = true;
};
struct TevStage {
TevPass<GX::TevColorArg, GX::CC_ZERO> colorPass;
TevPass<GX::TevAlphaArg, GX::CA_ZERO> alphaPass;
TevOp colorOp;
TevOp alphaOp;
GX::TevKColorSel kcSel = GX::TEV_KCSEL_1;
GX::TevKAlphaSel kaSel = GX::TEV_KASEL_1;
GX::TexCoordID texCoordId = GX::TEXCOORD_NULL;
GX::TexMapID texMapId = GX::TEXMAP_NULL;
GX::ChannelID channelId = GX::COLOR_NULL;
constexpr STevStage(const metaforce::CTevCombiners::ColorPass& colPass,
const metaforce::CTevCombiners::AlphaPass& alphaPass,
const metaforce::CTevCombiners::CTevOp& colorOp,
const metaforce::CTevCombiners::CTevOp& alphaOp) noexcept
: colorPass(colPass), alphaPass(alphaPass), colorOp(colorOp), alphaOp(alphaOp) {}
};
struct TextureBind {
aurora::gfx::TextureHandle handle;
@ -63,32 +48,72 @@ struct TextureBind {
[[nodiscard]] wgpu::SamplerDescriptor get_descriptor() const noexcept;
operator bool() const noexcept { return handle; }
};
// For shader generation
struct ColorChannelConfig {
GX::ColorSrc matSrc = GX::SRC_REG;
GX::ColorSrc ambSrc = GX::SRC_REG;
bool lightingEnabled = false;
};
// For uniform generation
struct ColorChannelState {
zeus::CColor matColor = zeus::skClear;
zeus::CColor ambColor = zeus::skClear;
GX::LightMask lightState;
};
using LightVariant = std::variant<std::monostate, Light, zeus::CColor>;
constexpr u32 maxTevStages = GX::MAX_TEVSTAGE;
extern std::array<std::optional<STevStage>, maxTevStages> g_tevStages;
constexpr u32 maxTextures = 8;
extern std::array<TextureBind, maxTextures> g_textures;
struct GXState {
zeus::CMatrix4f mv;
zeus::CMatrix4f mvInv;
zeus::CMatrix4f proj;
metaforce::CFogState fogState;
GX::CullMode cullMode = GX::CULL_BACK;
GX::BlendMode blendMode = GX::BM_NONE;
GX::BlendFactor blendFacSrc = GX::BL_SRCALPHA;
GX::BlendFactor blendFacDst = GX::BL_INVSRCALPHA;
GX::LogicOp blendOp = GX::LO_CLEAR;
GX::Compare depthFunc = GX::LEQUAL;
zeus::CColor clearColor = zeus::skBlack;
std::optional<float> dstAlpha;
std::optional<float> alphaDiscard;
std::array<zeus::CColor, MaxTevRegs> colorRegs;
std::array<zeus::CColor, GX::MAX_KCOLOR> kcolors;
std::array<ColorChannelConfig, MaxColorChannels> colorChannelConfig;
std::array<ColorChannelState, MaxColorChannels> colorChannelState;
std::array<LightVariant, GX::MaxLights> lights;
std::array<TevStage, MaxTevStages> tevStages;
std::array<TextureBind, MaxTextures> textures;
GX::LightMask lightState;
bool depthCompare = true;
bool depthUpdate = true;
bool alphaUpdate = true;
u8 numChans = 0;
u8 numIndStages = 0;
u8 numTevStages = 0;
u8 numTexGens = 0;
};
extern GXState g_gxState;
static inline Mat4x4<float> get_combined_matrix() noexcept { return g_proj * g_mv; }
static inline Mat4x4<float> get_combined_matrix() noexcept { return g_gxState.proj * g_gxState.mv; }
void shutdown() noexcept;
const TextureBind& get_texture(GX::TexMapID id) noexcept;
struct ShaderConfig {
std::array<std::optional<STevStage>, maxTevStages> tevStages;
std::array<GX::ColorSrc, 2> channelMatSrcs;
bool alphaDiscard = false;
std::array<std::optional<TevStage>, MaxTevStages> tevStages;
std::array<ColorChannelConfig, MaxColorChannels> colorChannels;
std::optional<float> alphaDiscard;
bool denormalizedVertexAttributes = false;
bool denormalizedHasNrm = false; // TODO this is a hack
};
struct PipelineConfig {
ShaderConfig shaderConfig;
GX::Primitive primitive;
metaforce::ERglEnum depthFunc;
metaforce::ERglCullMode cullMode;
metaforce::ERglBlendMode blendMode;
metaforce::ERglBlendFactor blendFacSrc, blendFacDst;
metaforce::ERglLogicOp blendOp;
GX::Compare depthFunc;
GX::CullMode cullMode;
GX::BlendMode blendMode;
GX::BlendFactor blendFacSrc, blendFacDst;
GX::LogicOp blendOp;
std::optional<float> dstAlpha;
bool depthCompare, depthUpdate, alphaUpdate;
};
@ -105,10 +130,10 @@ struct GXBindGroups {
// Output info from shader generation
struct ShaderInfo {
GXBindGroups bindGroups;
std::bitset<maxTextures> sampledTextures;
std::bitset<4> sampledKcolors;
std::bitset<2> sampledColorChannels;
std::bitset<3> usesTevReg;
std::bitset<MaxTextures> sampledTextures;
std::bitset<MaxKColors> sampledKColors;
std::bitset<MaxColorChannels> sampledColorChannels;
std::bitset<MaxTevRegs> usesTevReg;
u32 uniformSize = 0;
bool usesVtxColor : 1 = false;
bool usesNormal : 1 = false;
@ -143,25 +168,41 @@ struct DlVert {
} // namespace aurora::gfx::gx
namespace aurora {
template <>
inline void xxh3_update(XXH3_state_t& state, const metaforce::CTevCombiners::CTevOp& input) {
XXH3_64bits_update(&state, &input.x0_clamp, sizeof(bool));
XXH3_64bits_update(&state, &input.x4_op, sizeof(metaforce::CTevCombiners::CTevOp::x4_op));
XXH3_64bits_update(&state, &input.x8_bias, sizeof(metaforce::CTevCombiners::CTevOp::x8_bias));
XXH3_64bits_update(&state, &input.xc_scale, sizeof(metaforce::CTevCombiners::CTevOp::xc_scale));
XXH3_64bits_update(&state, &input.x10_regId, sizeof(metaforce::CTevCombiners::CTevOp::x10_regId));
template <typename Arg, Arg Default>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevPass<Arg, Default>& input) {
XXH3_64bits_update(&state, &input.a, sizeof(Arg));
XXH3_64bits_update(&state, &input.b, sizeof(Arg));
XXH3_64bits_update(&state, &input.c, sizeof(Arg));
XXH3_64bits_update(&state, &input.d, sizeof(Arg));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::STevStage& input) {
XXH3_64bits_update(&state, &input.colorPass, sizeof(gfx::gx::STevStage::colorPass));
XXH3_64bits_update(&state, &input.alphaPass, sizeof(gfx::gx::STevStage::alphaPass));
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevOp& input) {
XXH3_64bits_update(&state, &input.op, sizeof(gfx::gx::TevOp::op));
XXH3_64bits_update(&state, &input.bias, sizeof(gfx::gx::TevOp::bias));
XXH3_64bits_update(&state, &input.scale, sizeof(gfx::gx::TevOp::scale));
XXH3_64bits_update(&state, &input.outReg, sizeof(gfx::gx::TevOp::outReg));
XXH3_64bits_update(&state, &input.clamp, sizeof(bool));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TevStage& input) {
xxh3_update(state, input.colorPass);
xxh3_update(state, input.alphaPass);
xxh3_update(state, input.colorOp);
xxh3_update(state, input.alphaOp);
XXH3_64bits_update(&state, &input.kcSel, sizeof(gfx::gx::STevStage::kcSel));
XXH3_64bits_update(&state, &input.kaSel, sizeof(gfx::gx::STevStage::kaSel));
XXH3_64bits_update(&state, &input.texCoordId, sizeof(gfx::gx::STevStage::texCoordId));
XXH3_64bits_update(&state, &input.texMapId, sizeof(gfx::gx::STevStage::texMapId));
XXH3_64bits_update(&state, &input.channelId, sizeof(gfx::gx::STevStage::channelId));
XXH3_64bits_update(&state, &input.kcSel, sizeof(gfx::gx::TevStage::kcSel));
XXH3_64bits_update(&state, &input.kaSel, sizeof(gfx::gx::TevStage::kaSel));
XXH3_64bits_update(&state, &input.texCoordId, sizeof(gfx::gx::TevStage::texCoordId));
XXH3_64bits_update(&state, &input.texMapId, sizeof(gfx::gx::TevStage::texMapId));
XXH3_64bits_update(&state, &input.channelId, sizeof(gfx::gx::TevStage::channelId));
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ColorChannelConfig& input) {
XXH3_64bits_update(&state, &input.lightingEnabled, sizeof(gfx::gx::ColorChannelConfig::lightingEnabled));
XXH3_64bits_update(&state, &input.matSrc, sizeof(gfx::gx::ColorChannelConfig::matSrc));
if (input.lightingEnabled) {
// Unused when lighting is disabled
XXH3_64bits_update(&state, &input.ambSrc, sizeof(gfx::gx::ColorChannelConfig::ambSrc));
}
}
template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) {
@ -171,10 +212,12 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input)
}
xxh3_update(state, *item);
}
for (const auto& item : input.channelMatSrcs) {
XXH3_64bits_update(&state, &item, sizeof(GX::ColorSrc));
for (const auto& item : input.colorChannels) {
xxh3_update(state, item);
}
if (input.alphaDiscard) {
XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float));
}
XXH3_64bits_update(&state, &input.alphaDiscard, sizeof(bool));
XXH3_64bits_update(&state, &input.denormalizedVertexAttributes, sizeof(bool));
XXH3_64bits_update(&state, &input.denormalizedHasNrm, sizeof(bool));
}

View File

@ -12,7 +12,7 @@ static logvisor::Module Log("aurora::gfx::gx");
std::unordered_map<ShaderRef, std::pair<wgpu::ShaderModule, gx::ShaderInfo>> g_gxCachedShaders;
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STevStage& stage, ShaderInfo& info) {
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) {
switch (arg) {
case GX::CC_CPREV:
return "prev.rgb";
@ -105,64 +105,64 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STe
case GX::TEV_KCSEL_1_8:
return "(1.0/8.0)";
case GX::TEV_KCSEL_K0:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.rgb";
case GX::TEV_KCSEL_K1:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.rgb";
case GX::TEV_KCSEL_K2:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.rgb";
case GX::TEV_KCSEL_K3:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.rgb";
case GX::TEV_KCSEL_K0_R:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.r";
case GX::TEV_KCSEL_K1_R:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.r";
case GX::TEV_KCSEL_K2_R:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.r";
case GX::TEV_KCSEL_K3_R:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.r";
case GX::TEV_KCSEL_K0_G:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.g";
case GX::TEV_KCSEL_K1_G:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.g";
case GX::TEV_KCSEL_K2_G:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.g";
case GX::TEV_KCSEL_K3_G:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.g";
case GX::TEV_KCSEL_K0_B:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.b";
case GX::TEV_KCSEL_K1_B:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.b";
case GX::TEV_KCSEL_K2_B:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.b";
case GX::TEV_KCSEL_K3_B:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.b";
case GX::TEV_KCSEL_K0_A:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.a";
case GX::TEV_KCSEL_K1_A:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.a";
case GX::TEV_KCSEL_K2_A:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.a";
case GX::TEV_KCSEL_K3_A:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.a";
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid kcSel {}"), stage.kcSel);
@ -177,7 +177,7 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const STe
}
}
static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const STevStage& stage, ShaderInfo& info) {
static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) {
switch (arg) {
case GX::CA_APREV:
return "prev.a";
@ -232,52 +232,52 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const STe
case GX::TEV_KASEL_1_8:
return "(1.0/8.0)";
case GX::TEV_KASEL_K0_R:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.r";
case GX::TEV_KASEL_K1_R:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.r";
case GX::TEV_KASEL_K2_R:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.r";
case GX::TEV_KASEL_K3_R:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.r";
case GX::TEV_KASEL_K0_G:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.g";
case GX::TEV_KASEL_K1_G:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.g";
case GX::TEV_KASEL_K2_G:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.g";
case GX::TEV_KASEL_K3_G:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.g";
case GX::TEV_KASEL_K0_B:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.b";
case GX::TEV_KASEL_K1_B:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.b";
case GX::TEV_KASEL_K2_B:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.b";
case GX::TEV_KASEL_K3_B:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.b";
case GX::TEV_KASEL_K0_A:
info.sampledKcolors.set(0);
info.sampledKColors.set(0);
return "ubuf.kcolor0.a";
case GX::TEV_KASEL_K1_A:
info.sampledKcolors.set(1);
info.sampledKColors.set(1);
return "ubuf.kcolor1.a";
case GX::TEV_KASEL_K2_A:
info.sampledKcolors.set(2);
info.sampledKColors.set(2);
return "ubuf.kcolor2.a";
case GX::TEV_KASEL_K3_A:
info.sampledKcolors.set(3);
info.sampledKColors.set(3);
return "ubuf.kcolor3.a";
default:
Log.report(logvisor::Fatal, FMT_STRING("invalid kaSel {}"), stage.kaSel);
@ -352,34 +352,34 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
break;
}
Log.report(logvisor::Info, FMT_STRING(" tevStages[{}]:"), i);
Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage->colorPass.x0_a);
Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage->colorPass.x4_b);
Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage->colorPass.x8_c);
Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage->colorPass.xc_d);
Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage->alphaPass.x0_a);
Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage->alphaPass.x4_b);
Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage->alphaPass.x8_c);
Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage->alphaPass.xc_d);
Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage->colorOp.x0_clamp);
Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage->colorOp.x4_op);
Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage->colorOp.x8_bias);
Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage->colorOp.xc_scale);
Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage->colorOp.x10_regId);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage->alphaOp.x0_clamp);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage->alphaOp.x4_op);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage->alphaOp.x8_bias);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage->alphaOp.xc_scale);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage->alphaOp.x10_regId);
Log.report(logvisor::Info, FMT_STRING(" color_a: {}"), stage->colorPass.a);
Log.report(logvisor::Info, FMT_STRING(" color_b: {}"), stage->colorPass.b);
Log.report(logvisor::Info, FMT_STRING(" color_c: {}"), stage->colorPass.c);
Log.report(logvisor::Info, FMT_STRING(" color_d: {}"), stage->colorPass.d);
Log.report(logvisor::Info, FMT_STRING(" alpha_a: {}"), stage->alphaPass.a);
Log.report(logvisor::Info, FMT_STRING(" alpha_b: {}"), stage->alphaPass.b);
Log.report(logvisor::Info, FMT_STRING(" alpha_c: {}"), stage->alphaPass.c);
Log.report(logvisor::Info, FMT_STRING(" alpha_d: {}"), stage->alphaPass.d);
Log.report(logvisor::Info, FMT_STRING(" color_op_clamp: {}"), stage->colorOp.clamp);
Log.report(logvisor::Info, FMT_STRING(" color_op_op: {}"), stage->colorOp.op);
Log.report(logvisor::Info, FMT_STRING(" color_op_bias: {}"), stage->colorOp.bias);
Log.report(logvisor::Info, FMT_STRING(" color_op_scale: {}"), stage->colorOp.scale);
Log.report(logvisor::Info, FMT_STRING(" color_op_reg_id: {}"), stage->colorOp.outReg);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_clamp: {}"), stage->alphaOp.clamp);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_op: {}"), stage->alphaOp.op);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_bias: {}"), stage->alphaOp.bias);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_scale: {}"), stage->alphaOp.scale);
Log.report(logvisor::Info, FMT_STRING(" alpha_op_reg_id: {}"), stage->alphaOp.outReg);
Log.report(logvisor::Info, FMT_STRING(" kc_sel: {}"), stage->kcSel);
Log.report(logvisor::Info, FMT_STRING(" ka_sel: {}"), stage->kaSel);
Log.report(logvisor::Info, FMT_STRING(" texCoordId: {}"), stage->texCoordId);
Log.report(logvisor::Info, FMT_STRING(" texMapId: {}"), stage->texMapId);
Log.report(logvisor::Info, FMT_STRING(" channelId: {}"), stage->channelId);
}
for (int i = 0; i < config.channelMatSrcs.size(); ++i) {
Log.report(logvisor::Info, FMT_STRING(" channelMatSrcs[{}]: {}"), i, config.channelMatSrcs[i]);
}
Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard);
// for (int i = 0; i < config.channelMatSrcs.size(); ++i) {
// Log.report(logvisor::Info, FMT_STRING(" channelMatSrcs[{}]: {}"), i, config.channelMatSrcs[i]);
// }
// Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard);
Log.report(logvisor::Info, FMT_STRING(" denormalizedVertexAttributes: {}"), config.denormalizedVertexAttributes);
}
@ -396,14 +396,16 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
if (config.denormalizedVertexAttributes) {
vtxInAttrs += "\n @location(0) in_pos: vec3<f32>";
vtxOutAttrs += "\n @builtin(position) pos: vec4<f32>;";
vtxXfrAttrsPre += "\n var obj_pos = vec4<f32>(in_pos, 1.0);"
vtxXfrAttrsPre +=
"\n var obj_pos = vec4<f32>(in_pos, 1.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n out.pos = ubuf.proj * mv_pos;";
if (config.denormalizedHasNrm) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3<f32>;"), locIdx);
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_nrm: vec3<f32>"), ++locIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.nrm = in_nrm;"));
vtxXfrAttrsPre += "\n var obj_norm = vec4<f32>(in_nrm, 0.0);"
vtxXfrAttrsPre +=
"\n var obj_norm = vec4<f32>(in_nrm, 0.0);"
"\n var mv_norm = ubuf.mv_inv * obj_norm;";
info.usesNormal = true;
}
@ -429,7 +431,8 @@ var<storage, read> v_packed_uvs: Vec2Block;
"\n , @location(1) in_uv_0_4_idx: vec4<i32>"
"\n , @location(2) in_uv_5_7_idx: vec4<i32>";
vtxOutAttrs += "\n @builtin(position) pos: vec4<f32>;";
vtxXfrAttrsPre += "\n var obj_pos = vec4<f32>(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);"
vtxXfrAttrsPre +=
"\n var obj_pos = vec4<f32>(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);"
"\n var obj_norm = vec4<f32>(v_verts.data[in_pos_nrm_idx[1]].xyz, 0.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n var mv_norm = ubuf.mv_inv * obj_norm;"
@ -444,7 +447,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
}
{
std::string outReg;
switch (stage->colorOp.x10_regId) {
switch (stage->colorOp.outReg) {
case GX::TevRegID::TEVPREV:
outReg = "prev";
break;
@ -461,23 +464,21 @@ var<storage, read> v_packed_uvs: Vec2Block;
info.usesTevReg.set(2);
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("TODO: colorOp outReg {}"), stage->colorOp.x10_regId);
Log.report(logvisor::Fatal, FMT_STRING("TODO: colorOp outReg {}"), stage->colorOp.outReg);
}
std::string op =
fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
color_arg_reg(stage->colorPass.x0_a, idx, *stage, info),
color_arg_reg(stage->colorPass.x4_b, idx, *stage, info),
color_arg_reg(stage->colorPass.x8_c, idx, *stage, info),
color_arg_reg(stage->colorPass.xc_d, idx, *stage, info), tev_op(stage->colorOp.x4_op),
tev_bias(stage->colorOp.x8_bias), tev_scale(stage->colorOp.xc_scale));
if (stage->colorOp.x0_clamp) {
std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
color_arg_reg(stage->colorPass.a, idx, *stage, info), color_arg_reg(stage->colorPass.b, idx, *stage, info),
color_arg_reg(stage->colorPass.c, idx, *stage, info), color_arg_reg(stage->colorPass.d, idx, *stage, info),
tev_op(stage->colorOp.op), tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale));
if (stage->colorOp.clamp) {
op = fmt::format(FMT_STRING("clamp(vec3<f32>({}), vec3<f32>(0.0), vec3<f32>(1.0))"), op);
}
fragmentFn += fmt::format(FMT_STRING("\n {0} = vec4<f32>({1}, {0}.a);"), outReg, op);
}
{
std::string outReg;
switch (stage->alphaOp.x10_regId) {
switch (stage->alphaOp.outReg) {
case GX::TevRegID::TEVPREV:
outReg = "prev.a";
break;
@ -494,16 +495,14 @@ var<storage, read> v_packed_uvs: Vec2Block;
info.usesTevReg.set(2);
break;
default:
Log.report(logvisor::Fatal, FMT_STRING("TODO: alphaOp outReg {}"), stage->alphaOp.x10_regId);
Log.report(logvisor::Fatal, FMT_STRING("TODO: alphaOp outReg {}"), stage->alphaOp.outReg);
}
std::string op =
fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
alpha_arg_reg(stage->alphaPass.x0_a, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.x4_b, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.x8_c, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.xc_d, idx, *stage, info), tev_op(stage->alphaOp.x4_op),
tev_bias(stage->alphaOp.x8_bias), tev_scale(stage->alphaOp.xc_scale));
if (stage->alphaOp.x0_clamp) {
std::string op = fmt::format(
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"),
alpha_arg_reg(stage->alphaPass.a, idx, *stage, info), alpha_arg_reg(stage->alphaPass.b, idx, *stage, info),
alpha_arg_reg(stage->alphaPass.c, idx, *stage, info), alpha_arg_reg(stage->alphaPass.d, idx, *stage, info),
tev_op(stage->alphaOp.op), tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale));
if (stage->alphaOp.clamp) {
op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op);
}
fragmentFn += fmt::format(FMT_STRING("\n {0} = {1};"), outReg, op);
@ -518,19 +517,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i);
info.uniformSize += 16;
}
if (info.sampledColorChannels.any()) {
uniformPre += "\n"
"struct Light {\n"
" pos: vec3<f32>;\n"
" dir: vec3<f32>;\n"
" color: vec4<f32>;\n"
" lin_att: vec3<f32>;\n"
" ang_att: vec3<f32>;\n"
"};";
uniBufAttrs += fmt::format(FMT_STRING("\n lights: array<Light, {}>;"), MaxLights);
uniBufAttrs += "\n lighting_ambient: vec4<f32>;";
info.uniformSize += (80 * MaxLights) + 16;
}
bool addedLightStruct = false;
for (int i = 0; i < info.sampledColorChannels.size(); ++i) {
if (!info.sampledColorChannels.test(i)) {
continue;
@ -540,26 +527,30 @@ var<storage, read> v_packed_uvs: Vec2Block;
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>;"), i);
info.uniformSize += 32;
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i);
if (config.channelMatSrcs[i] == GX::SRC_VTX) {
if (config.denormalizedVertexAttributes) {
if (!info.usesVtxColor) {
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4<f32>"), locIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i);
}
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else {
Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes"));
if (config.colorChannels[i].lightingEnabled) {
if (!addedLightStruct) {
uniformPre +=
"\n"
"struct Light {\n"
" pos: vec3<f32>;\n"
" dir: vec3<f32>;\n"
" color: vec4<f32>;\n"
" lin_att: vec3<f32>;\n"
" ang_att: vec3<f32>;\n"
"};";
addedLightStruct = true;
}
info.usesVtxColor = true;
} else {
// TODO only perform lighting on CC0 when enabled
uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array<Light, {}>;"), i, GX::MaxLights);
uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4<f32>;"), i);
info.uniformSize += (80 * GX::MaxLights) + 16;
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING(R"""(
{{
var lighting = ubuf.lighting_ambient + ubuf.cc{0}_amb;
var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb;
for (var i = 0; i < {1}; i = i + 1) {{
var light = ubuf.lights[i];
var light = ubuf.lights{0}[i];
var delta = mv_pos.xyz - light.pos;
var dist = length(delta);
var delta_norm = delta / dist;
@ -575,12 +566,27 @@ var<storage, read> v_packed_uvs: Vec2Block;
lighting = lighting + vec4<f32>(this_color, 0.0);
}}
out.cc{0} = clamp(lighting, vec4<f32>(0.0), vec4<f32>(1.0));
}})"""), i, MaxLights);
}})"""),
i, GX::MaxLights);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else if (config.colorChannels[i].matSrc == GX::SRC_VTX) {
if (config.denormalizedVertexAttributes) {
if (!info.usesVtxColor) {
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4<f32>"), locIdx);
}
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else {
Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes"));
}
info.usesVtxColor = true;
} else {
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i);
}
}
for (int i = 0; i < info.sampledKcolors.size(); ++i) {
if (!info.sampledKcolors.test(i)) {
for (int i = 0; i < info.sampledKColors.size(); ++i) {
if (!info.sampledKColors.test(i)) {
continue;
}
uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4<f32>;"), i);
@ -622,6 +628,9 @@ var<storage, read> v_packed_uvs: Vec2Block;
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i);
locIdx++;
}
if (config.alphaDiscard) {
fragmentFn += fmt::format(FMT_STRING("\n if (prev.a < {}f) {{ discard; }}"), *config.alphaDiscard);
}
const auto shaderSource =
fmt::format(FMT_STRING(R"""({uniformPre}

View File

@ -54,10 +54,10 @@ static const std::vector<zeus::CVector3f>* nrmData;
static const std::vector<Vec2<float>>* tex0TcData;
static const std::vector<Vec2<float>>* tcData;
void set_vertex_buffer(const std::vector<zeus::CVector3f>* data) noexcept { vtxData = data; }
void set_normal_buffer(const std::vector<zeus::CVector3f>* norm) noexcept { nrmData = norm; }
void set_tex0_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tex0TcData = tcs; }
void set_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tcData = tcs; }
// void set_vertex_buffer(const std::vector<zeus::CVector3f>* data) noexcept { vtxData = data; }
// void set_normal_buffer(const std::vector<zeus::CVector3f>* norm) noexcept { nrmData = norm; }
// void set_tex0_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tex0TcData = tcs; }
// void set_tc_buffer(const std::vector<Vec2<float>>* tcs) noexcept { tcData = tcs; }
enum class VertexFormat : u8 {
F32F32,
@ -233,3 +233,27 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco
pass.DrawIndexed(data.indexCount);
}
} // namespace aurora::gfx::model
void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept {
switch (attr) {
case GX::VA_POS:
aurora::gfx::model::vtxData = static_cast<const std::vector<zeus::CVector3f>*>(data);
break;
case GX::VA_NRM:
aurora::gfx::model::nrmData = static_cast<const std::vector<zeus::CVector3f>*>(data);
break;
case GX::VA_TEX0:
aurora::gfx::model::tex0TcData = static_cast<const std::vector<aurora::Vec2<float>>*>(data);
break;
case GX::VA_TEX1:
aurora::gfx::model::tcData = static_cast<const std::vector<aurora::Vec2<float>>*>(data);
break;
default:
aurora::gfx::model::Log.report(logvisor::Fatal, FMT_STRING("GXSetArray: invalid attr {}"), attr);
unreachable();
}
}
void GXCallDisplayList(const void* data, u32 nbytes) noexcept {
aurora::gfx::model::queue_surface(static_cast<const u8*>(data), nbytes);
}