aurora: GX Stream API, VtxDesc, TevSwap & more

This commit is contained in:
Luke Street 2022-03-19 13:30:25 -04:00
parent ecb4645e89
commit b9b635b311
17 changed files with 1024 additions and 696 deletions

View File

@ -813,9 +813,7 @@ void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& co
// TODO // TODO
} }
void CCubeRenderer::SetThermalColdScale(float scale) { void CCubeRenderer::SetThermalColdScale(float scale) { x2f8_thermColdScale = zeus::clamp(0.f, scale, 1.f); }
// TODO
}
void CCubeRenderer::DoThermalBlendCold() { void CCubeRenderer::DoThermalBlendCold() {
// TODO // TODO

View File

@ -3,11 +3,12 @@
#include "Graphics/CTexture.hpp" #include "Graphics/CTexture.hpp"
namespace metaforce::CGX { namespace metaforce::CGX {
SGXState sGXState; SGXState sGXState{};
std::array<GX::VtxDescList, 11> sVtxDescList{};
void ResetGXStates() noexcept { void ResetGXStates() noexcept {
sGXState.x48_descList = nullptr; sGXState.x48_descList = 0;
// GXClearVtxDesc(); GXClearVtxDesc();
sGXState.x0_arrayPtrs.fill(nullptr); sGXState.x0_arrayPtrs.fill(nullptr);
for (GX::TexMapID id = GX::TEXMAP0; id < GX::MAX_TEXMAP; id = static_cast<GX::TexMapID>(id + 1)) { for (GX::TexMapID id = GX::TEXMAP0; id < GX::MAX_TEXMAP; id = static_cast<GX::TexMapID>(id + 1)) {
CTexture::InvalidateTexMap(id); CTexture::InvalidateTexMap(id);
@ -16,7 +17,9 @@ void ResetGXStates() noexcept {
GXSetTevKColor(id, item); GXSetTevKColor(id, item);
id = static_cast<GX::TevKColorID>(id + 1); id = static_cast<GX::TevKColorID>(id + 1);
} }
// GXSetTevSwapModeTable GXSetTevSwapModeTable(GX::TEV_SWAP1, GX::CH_RED, GX::CH_GREEN, GX::CH_BLUE, GX::CH_RED);
GXSetTevSwapModeTable(GX::TEV_SWAP2, GX::CH_RED, GX::CH_GREEN, GX::CH_BLUE, GX::CH_GREEN);
GXSetTevSwapModeTable(GX::TEV_SWAP3, GX::CH_RED, GX::CH_GREEN, GX::CH_BLUE, GX::CH_BLUE);
SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0); SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_AND, GX::ALWAYS, 0);
// GXSetCurrentMtx(0); // GXSetCurrentMtx(0);
SetNumIndStages(0); SetNumIndStages(0);

View File

@ -31,7 +31,7 @@ struct SGXState {
std::array<u16, 2> x34_chanCtrls{0x4000, 0x4000}; std::array<u16, 2> x34_chanCtrls{0x4000, 0x4000};
std::array<GXColor, 2> x38_chanAmbColors; std::array<GXColor, 2> x38_chanAmbColors;
std::array<GXColor, 2> x40_chanMatColors; std::array<GXColor, 2> x40_chanMatColors;
GX::VtxDescList* x48_descList = nullptr; u32 x48_descList = 0;
u8 x4c_dirtyChans = 0; u8 x4c_dirtyChans = 0;
u8 x4d_prevNumChans = 0; u8 x4d_prevNumChans = 0;
u8 x4e_numChans = 0; u8 x4e_numChans = 0;
@ -53,6 +53,7 @@ struct SGXState {
GXColor x25c_fogColor; GXColor x25c_fogColor;
}; };
extern SGXState sGXState; extern SGXState sGXState;
extern std::array<GX::VtxDescList, 11> sVtxDescList;
static inline void update_fog(u32 value) noexcept { static inline void update_fog(u32 value) noexcept {
if (sGXState.x53_fogType == GX::FOG_NONE || (sGXState.x56_blendMode & 0xE0) == (value & 0xE0)) { if (sGXState.x53_fogType == GX::FOG_NONE || (sGXState.x56_blendMode & 0xE0) == (value & 0xE0)) {
@ -92,9 +93,11 @@ static inline void Begin(GX::Primitive primitive, GX::VtxFmt fmt, u16 nverts) no
if (sGXState.x4c_dirtyChans != 0) { if (sGXState.x4c_dirtyChans != 0) {
FlushState(); FlushState();
} }
// TODO GXBegin(type, fmt, nverts); GXBegin(primitive, fmt, nverts);
} }
static inline void End() noexcept { GXEnd(); }
static inline void CallDisplayList(const void* data, u32 nbytes) noexcept { static inline void CallDisplayList(const void* data, u32 nbytes) noexcept {
if (sGXState.x4c_dirtyChans != 0) { if (sGXState.x4c_dirtyChans != 0) {
FlushState(); FlushState();
@ -102,10 +105,6 @@ static inline void CallDisplayList(const void* data, u32 nbytes) noexcept {
GXCallDisplayList(data, nbytes); GXCallDisplayList(data, nbytes);
} }
static inline void End() noexcept {
// no-op
}
static inline const GXColor& GetChanAmbColor(EChannelId id) noexcept { static inline const GXColor& GetChanAmbColor(EChannelId id) noexcept {
const auto idx = std::underlying_type_t<EChannelId>(id); const auto idx = std::underlying_type_t<EChannelId>(id);
return sGXState.x38_chanAmbColors[idx]; return sGXState.x38_chanAmbColors[idx];
@ -394,11 +393,33 @@ static inline void SetTexCoordGen(GX::TexCoordID dstCoord, u32 flags) noexcept {
} }
} }
void SetVtxDescv(GX::VtxDescList* descList) noexcept;
static inline void SetVtxDescv_Compressed(u32 descList) noexcept { static inline void SetVtxDescv_Compressed(u32 descList) noexcept {
// TODO convert to GX::VtxDescList u32 currentDescList = sGXState.x48_descList;
aurora::gfx::model::set_vtx_desc_compressed(descList); if (descList != currentDescList) {
size_t remain = sVtxDescList.size();
u32 shift = 0;
u32 attrIdx = 0;
do {
sVtxDescList[attrIdx] = {
GX::Attr(GX::VA_POS + attrIdx),
GX::AttrType(descList >> shift & 3),
};
shift += 2;
++attrIdx;
--remain;
} while (remain != 0);
sVtxDescList[attrIdx] = {};
GXSetVtxDescv(sVtxDescList.data());
sGXState.x48_descList = descList;
}
}
static inline void SetVtxDescv(const GX::VtxDescList* descList) noexcept {
u32 flags = 0;
for (; descList->attr != GX::VA_NULL; ++descList) {
flags |= (descList->type & 3) << (descList->attr - GX::VA_POS) * 2;
}
SetVtxDescv_Compressed(flags);
} }
static inline void SetZMode(GXBool compareEnable, GX::Compare func, GXBool updateEnable) noexcept { static inline void SetZMode(GXBool compareEnable, GX::Compare func, GXBool updateEnable) noexcept {

View File

@ -59,9 +59,16 @@ const std::array<zeus::CMatrix3f, 6> CGraphics::skCubeBasisMats{{
// Stream API // Stream API
static EStreamFlags sStreamFlags; static EStreamFlags sStreamFlags;
static zeus::CColor sQueuedColor; static GX::Primitive sStreamPrimitive;
static zeus::CVector2f sQueuedTexCoord; static u32 sVerticesCount;
static zeus::CVector3f sQueuedNormal; // Originally writes directly to GX FIFO
struct StreamVertex {
zeus::CColor color;
zeus::CVector2f texCoord;
zeus::CVector3f normal;
zeus::CVector3f vertex;
};
static std::vector<StreamVertex> sQueuedVertices;
void CGraphics::DisableAllLights() { void CGraphics::DisableAllLights() {
g_LightActive.reset(); g_LightActive.reset();
@ -518,55 +525,102 @@ void CGraphics::SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass
} }
void CGraphics::StreamBegin(GX::Primitive primitive) { void CGraphics::StreamBegin(GX::Primitive primitive) {
sStreamFlags = {}; // Originally ResetVertexDataStream(true);
aurora::gfx::stream_begin(primitive); sQueuedVertices.clear();
sQueuedVertices.emplace_back();
sVerticesCount = 0;
// End
sStreamFlags = EStreamFlagBits::fHasColor;
sStreamPrimitive = primitive;
} }
void CGraphics::StreamNormal(const zeus::CVector3f& nrm) { void CGraphics::StreamNormal(const zeus::CVector3f& nrm) {
sQueuedNormal = nrm; sQueuedVertices.back().normal = nrm;
sStreamFlags |= EStreamFlagBits::fHasNormal; sStreamFlags |= EStreamFlagBits::fHasNormal;
} }
void CGraphics::StreamColor(float r, float g, float b, float a) {
sQueuedColor = zeus::CColor{r, g, b, a};
sStreamFlags |= EStreamFlagBits::fHasColor;
}
void CGraphics::StreamColor(const zeus::CColor& color) { void CGraphics::StreamColor(const zeus::CColor& color) {
sQueuedColor = color; sQueuedVertices.back().color = color;
sStreamFlags |= EStreamFlagBits::fHasColor; sStreamFlags |= EStreamFlagBits::fHasColor;
} }
void CGraphics::StreamTexcoord(float x, float y) {
sQueuedTexCoord = {x, y};
sStreamFlags |= EStreamFlagBits::fHasTexture;
}
void CGraphics::StreamTexcoord(const zeus::CVector2f& uv) { void CGraphics::StreamTexcoord(const zeus::CVector2f& uv) {
sQueuedTexCoord = uv; sQueuedVertices.back().texCoord = uv;
sStreamFlags |= EStreamFlagBits::fHasTexture; sStreamFlags |= EStreamFlagBits::fHasTexture;
} }
void CGraphics::StreamVertex(float xyz) {
const zeus::CVector3f pos{xyz, xyz, xyz};
aurora::gfx::stream_vertex(sStreamFlags, pos, sQueuedNormal, sQueuedColor, sQueuedTexCoord);
}
void CGraphics::StreamVertex(float x, float y, float z) {
const zeus::CVector3f pos{x, y, z};
aurora::gfx::stream_vertex(sStreamFlags, pos, sQueuedNormal, sQueuedColor, sQueuedTexCoord);
}
void CGraphics::StreamVertex(const zeus::CVector3f& pos) { void CGraphics::StreamVertex(const zeus::CVector3f& pos) {
aurora::gfx::stream_vertex(sStreamFlags, pos, sQueuedNormal, sQueuedColor, sQueuedTexCoord); sQueuedVertices.back().vertex = pos;
UpdateVertexDataStream();
} }
void CGraphics::StreamEnd() { void CGraphics::StreamEnd() {
SetTevStates(sStreamFlags); if (sVerticesCount != 0) {
aurora::gfx::stream_end(); FlushStream();
}
sStreamFlags = {}; sStreamFlags = {};
} }
void CGraphics::UpdateVertexDataStream() {
++sVerticesCount;
if (sVerticesCount == 240) {
FlushStream();
ResetVertexDataStream(false);
} else {
sQueuedVertices.emplace_back(sQueuedVertices.back());
}
}
void CGraphics::FlushStream() {
std::array<GX::VtxDescList, 5> vtxDescList{};
size_t idx = 0;
vtxDescList[idx++] = {GX::VA_POS, GX::DIRECT};
if (sStreamFlags & EStreamFlagBits::fHasNormal) {
vtxDescList[idx++] = {GX::VA_NRM, GX::DIRECT};
}
if (sStreamFlags & EStreamFlagBits::fHasColor) {
vtxDescList[idx++] = {GX::VA_CLR0, GX::DIRECT};
}
if (sStreamFlags & EStreamFlagBits::fHasTexture) {
vtxDescList[idx++] = {GX::VA_TEX0, GX::DIRECT};
}
CGX::SetVtxDescv(vtxDescList.data());
SetTevStates(sStreamFlags);
FullRender();
}
void CGraphics::FullRender() {
CGX::Begin(sStreamPrimitive, GX::VTXFMT0, sVerticesCount);
for (size_t i = 0; i < sVerticesCount; ++i) {
const auto& item = sQueuedVertices[i];
GXPosition3f32(item.vertex);
if (sStreamFlags & EStreamFlagBits::fHasNormal) {
GXNormal3f32(item.normal);
}
if (sStreamFlags & EStreamFlagBits::fHasColor) {
GXColor4f32(item.color);
}
if (sStreamFlags & EStreamFlagBits::fHasTexture) {
GXTexCoord2f32(item.texCoord);
}
}
CGX::End();
}
void CGraphics::ResetVertexDataStream(bool end) {
if (end) {
sQueuedVertices.clear();
} else {
const auto lastVertex = sQueuedVertices.back();
sQueuedVertices.clear();
sQueuedVertices.emplace_back(lastVertex);
}
sVerticesCount = 0;
if (!end) {
// TODO something with triangle fans
}
}
void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal, void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal,
const zeus::CColor& col, s32 numVerts) { const zeus::CColor& col, s32 numVerts) {
StreamBegin(primitive); StreamBegin(primitive);
@ -580,12 +634,12 @@ void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* po
void CGraphics::SetTevStates(EStreamFlags flags) noexcept { void CGraphics::SetTevStates(EStreamFlags flags) noexcept {
if (flags & EStreamFlagBits::fHasTexture) { if (flags & EStreamFlagBits::fHasTexture) {
CGX::SetNumTexGens(0); CGX::SetNumTexGens(1); // sTextureUsed & 3?
CGX::SetNumTevStages(1);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0); CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0); CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0);
} else /* if (flags < 8) ? */ { } else {
CGX::SetNumTexGens(2); // sTextureUsed & 3? CGX::SetNumTexGens(0);
CGX::SetNumTevStages(1);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0); 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::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD_NULL, GX::TEXMAP_NULL, GX::COLOR0A0);
} }
@ -599,4 +653,67 @@ void CGraphics::SetTevStates(EStreamFlags flags) noexcept {
hasLights ? GX::DF_CLAMP : GX::DF_NONE, hasLights ? GX::AF_SPOT : GX::AF_NONE); hasLights ? GX::DF_CLAMP : GX::DF_NONE, hasLights ? GX::AF_SPOT : GX::AF_NONE);
CGX::FlushState(); // normally would be handled in FullRender TODO CGX::FlushState(); // normally would be handled in FullRender TODO
} }
void CGraphics::Startup() {
// Setup GXFifo
CGX::ResetGXStates();
InitGraphicsVariables();
// ConfigureFrameBuffer(...);
InitGraphicsDefaults();
// GXInitTexCacheRegion
// GXSetTexRegionCallback
}
void CGraphics::InitGraphicsVariables() {
// g_lightTypes[0..n] = Directional;
g_LightActive = {};
SetDepthWriteMode(false, g_depthFunc, false);
SetCullMode(ERglCullMode::None);
SetAmbientColor(zeus::CColor{0.2f, 1.f});
g_IsGXModelMatrixIdentity = false;
// SetIdentityViewPointMatrix();
// SetIdentityModelMatrix();
// SetViewport(...);
// SetPerspective(...);
SetCopyClear(g_ClearColor, 1.f);
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
// g_RenderState.ResetFlushAll();
}
void CGraphics::InitGraphicsDefaults() {
SetDepthRange(0.f, 1.f);
g_IsGXModelMatrixIdentity = false;
SetModelMatrix(g_GXModelMatrix);
SetViewPointMatrix(g_GXModelView);
SetDepthWriteMode(false, g_depthFunc, false);
SetCullMode(g_cullMode);
SetViewport(g_Viewport.x0_left, g_Viewport.x4_top, g_Viewport.x8_width, g_Viewport.xc_height);
FlushProjection();
CTevCombiners::Init();
DisableAllLights();
SetDefaultVtxAttrFmt();
}
void CGraphics::SetDefaultVtxAttrFmt() {
// Unneeded, all attributes are expected to be full floats
// Left here for reference
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_POS, GX::POS_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_POS, GX::POS_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_POS, GX::POS_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_NRM, GX::NRM_XYZ, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_NRM, GX::NRM_XYZ, GX::S16, 14);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_NRM, GX::NRM_XYZ, GX::S16, 14);
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_CLR0, GX::CLR_RGBA, GX::RGBA8, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_CLR0, GX::CLR_RGBA, GX::RGBA8, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_CLR0, GX::CLR_RGBA, GX::RGBA8, 0);
// GXSetVtxAttrFmt(GX::VTXFMT0, GX::VA_TEX0, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, GX::VA_TEX0, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, GX::VA_TEX0, GX::TEX_ST, GX::U16, 15);
// for (GX::Attr attr = GX::VA_TEX1; attr <= GX::VA_TEX7; attr = GX::Attr(attr + 1)) {
// GXSetVtxAttrFmt(GX::VTXFMT0, attr, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT1, attr, GX::TEX_ST, GX::F32, 0);
// GXSetVtxAttrFmt(GX::VTXFMT2, attr, GX::TEX_ST, GX::F32, 0);
// }
}
} // namespace metaforce } // namespace metaforce

View File

@ -205,6 +205,10 @@ public:
static ERglEnum g_depthFunc; static ERglEnum g_depthFunc;
static ERglCullMode g_cullMode; static ERglCullMode g_cullMode;
static void Startup();
static void InitGraphicsVariables();
static void InitGraphicsDefaults();
static void SetDefaultVtxAttrFmt();
static void DisableAllLights(); static void DisableAllLights();
static void LoadLight(ERglLight light, const CLight& info); static void LoadLight(ERglLight light, const CLight& info);
static void EnableLight(ERglLight light); static void EnableLight(ERglLight light);
@ -353,14 +357,18 @@ public:
static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass); static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass);
static void StreamBegin(GX::Primitive primitive); static void StreamBegin(GX::Primitive primitive);
static void StreamNormal(const zeus::CVector3f& nrm); static void StreamNormal(const zeus::CVector3f& nrm);
static void StreamColor(float r, float g, float b, float a);
static void StreamColor(const zeus::CColor& color); static void StreamColor(const zeus::CColor& color);
static void StreamTexcoord(float x, float y); static inline void StreamColor(float r, float g, float b, float a) { StreamColor({r, g, b, a}); }
static void StreamTexcoord(const zeus::CVector2f& uv); static void StreamTexcoord(const zeus::CVector2f& uv);
static void StreamVertex(float xyz); static inline void StreamTexcoord(float x, float y) { StreamTexcoord({x, y}); }
static void StreamVertex(float x, float y, float z);
static void StreamVertex(const zeus::CVector3f& pos); static void StreamVertex(const zeus::CVector3f& pos);
static inline void StreamVertex(float xyz) { StreamVertex({xyz, xyz, xyz}); }
static inline void StreamVertex(float x, float y, float z) { StreamVertex({x, y, z}); }
static void StreamEnd(); static void StreamEnd();
static void UpdateVertexDataStream();
static void ResetVertexDataStream(bool end);
static void FlushStream();
static void FullRender();
static void DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal, static void DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* pos, const zeus::CVector3f& normal,
const zeus::CColor& col, s32 numVerts); const zeus::CColor& col, s32 numVerts);
}; };

View File

@ -49,8 +49,9 @@ enum AttrType {
}; };
struct VtxDescList { struct VtxDescList {
Attr attr; Attr attr = GX::VA_NULL;
AttrType type; AttrType type = GX::NONE;
operator bool() const { return attr != GX::VA_NULL; }
}; };
enum VtxFmt { enum VtxFmt {
@ -665,6 +666,32 @@ enum ProjectionType {
ORTHOGRAPHIC, ORTHOGRAPHIC,
}; };
enum CompCnt {
CLR_RGB = 0,
POS_XY = 0,
TEX_S = 0,
NRM_XYZ = 0,
CLR_RGBA = 1,
POS_XYZ = 1,
NRM_NBT = 1,
TEX_ST = 1,
NRM_NBT3 = 2,
};
enum CompType {
RGB565 = 0,
U8 = 0,
RGB8 = 1,
S8 = 1,
U16 = 2,
RGBX8 = 2,
S16 = 3,
RGBA4 = 3,
F32 = 4,
RGBA6 = 4,
RGBA8 = 5,
};
} // namespace GX } // namespace GX
using GXColor = zeus::CColor; using GXColor = zeus::CColor;
@ -700,6 +727,7 @@ void GXSetChanCtrl(GX::ChannelID id, GXBool lightingEnabled, GX::ColorSrc ambSrc
GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept; GX::LightMask lightState, GX::DiffuseFn diffFn, GX::AttnFn attnFn) noexcept;
// Originally u8 instead of floats // Originally u8 instead of floats
void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept; void GXSetAlphaCompare(GX::Compare comp0, float ref0, GX::AlphaOp op, GX::Compare comp1, float ref1) noexcept;
void GXSetVtxDesc(GX::Attr attr, GX::AttrType type) noexcept;
void GXSetVtxDescv(GX::VtxDescList* list) noexcept; void GXSetVtxDescv(GX::VtxDescList* list) noexcept;
void GXClearVtxDesc() noexcept; void GXClearVtxDesc() noexcept;
void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept; void GXSetArray(GX::Attr attr, const void* data, u8 stride) noexcept;
@ -715,3 +743,21 @@ void GXLoadNrmMtxImm(const zeus::CTransform& xf, GX::PosNrmMtx id) noexcept;
void GXSetProjection(const zeus::CMatrix4f& mtx, GX::ProjectionType type) noexcept; void GXSetProjection(const zeus::CMatrix4f& mtx, GX::ProjectionType type) noexcept;
void GXSetViewport(float left, float top, float width, float height, float nearZ, float farZ) noexcept; void GXSetViewport(float left, float top, float width, float height, float nearZ, float farZ) noexcept;
void GXSetScissor(u32 left, u32 top, u32 width, u32 height) noexcept; void GXSetScissor(u32 left, u32 top, u32 width, u32 height) noexcept;
// Unneeded, all attributes are expected to be full floats
// void GXSetVtxAttrFmt(GX::VtxFmt vtxfmt, GX::Attr attr, GX::CompCnt cnt, GX::CompType type, u8 frac) noexcept;
// Streaming
void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept;
void GXMatrixIndex1u8(u8 idx) noexcept;
void GXPosition3f32(const zeus::CVector3f& pos) noexcept;
static inline void GXPosition3f32(float x, float y, float z) noexcept { GXPosition3f32({x, y, z}); }
void GXNormal3f32(const zeus::CVector3f& nrm) noexcept;
static inline void GXNormal3f32(float x, float y, float z) noexcept { GXNormal3f32({x, y, z}); }
void GXColor4f32(const zeus::CColor& color) noexcept;
static inline void GXColor4f32(float r, float g, float b, float a) noexcept { GXColor4f32({r, g, b, a}); }
void GXTexCoord2f32(const zeus::CVector2f& uv) noexcept;
static inline void GXTexCoord2f32(float u, float v) noexcept { GXTexCoord2f32({u, v}); }
void GXEnd() noexcept;
// End streaming
void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColorChan green, GX::TevColorChan blue,
GX::TevColorChan alpha) noexcept;
void GXSetTevSwapMode(GX::TevStageID stage, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) noexcept;

View File

@ -87,8 +87,8 @@ void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const {
modXf.origin += offset; modXf.origin += offset;
CGraphics::SetModelMatrix(modXf); CGraphics::SetModelMatrix(modXf);
SParticleUniforms uniformData = { // SParticleUniforms uniformData = {
CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}}; // CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}};
// decal.m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); // decal.m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
bool redToAlpha = sMoveRedToAlphaBuffer && desc.x18_ADD && desc.x14_TEX; bool redToAlpha = sMoveRedToAlphaBuffer && desc.x18_ADD && desc.x14_TEX;
@ -104,52 +104,52 @@ void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const {
// else // else
// CGraphics::SetShaderDataBinding(decal.m_normalDataBind); // CGraphics::SetShaderDataBinding(decal.m_normalDataBind);
g_instTexData.clear(); // g_instTexData.clear();
g_instTexData.reserve(1); // g_instTexData.reserve(1);
SParticleInstanceTex& inst = g_instTexData.emplace_back(); // SParticleInstanceTex& inst = g_instTexData.emplace_back();
if (decal.x8_rotation == 0.f) { // if (decal.x8_rotation == 0.f) {
inst.pos[0] = zeus::CVector3f(-size, 0.001f, size); // inst.pos[0] = zeus::CVector3f(-size, 0.001f, size);
inst.pos[1] = zeus::CVector3f(size, 0.001f, size); // inst.pos[1] = zeus::CVector3f(size, 0.001f, size);
inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size); // inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size);
inst.pos[3] = zeus::CVector3f(size, 0.001f, -size); // inst.pos[3] = zeus::CVector3f(size, 0.001f, -size);
} else { // } else {
float ang = zeus::degToRad(decal.x8_rotation); // float ang = zeus::degToRad(decal.x8_rotation);
float sinSize = std::sin(ang) * size; // float sinSize = std::sin(ang) * size;
float cosSize = std::cos(ang) * size; // float cosSize = std::cos(ang) * size;
inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize); // inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize);
inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize); // inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize);
inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize)); // inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize));
inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize); // inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize);
} // }
inst.color = color; // inst.color = color;
inst.uvs[0] = zeus::CVector2f(uvSet.xMin, uvSet.yMin); // inst.uvs[0] = zeus::CVector2f(uvSet.xMin, uvSet.yMin);
inst.uvs[1] = zeus::CVector2f(uvSet.xMax, uvSet.yMin); // inst.uvs[1] = zeus::CVector2f(uvSet.xMax, uvSet.yMin);
inst.uvs[2] = zeus::CVector2f(uvSet.xMin, uvSet.yMax); // inst.uvs[2] = zeus::CVector2f(uvSet.xMin, uvSet.yMax);
inst.uvs[3] = zeus::CVector2f(uvSet.xMax, uvSet.yMax); // inst.uvs[3] = zeus::CVector2f(uvSet.xMax, uvSet.yMax);
// decal.m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); // decal.m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size()); // CGraphics::DrawInstances(0, 4, g_instTexData.size());
} else { } else {
g_instNoTexData.clear(); // g_instNoTexData.clear();
g_instNoTexData.reserve(1); // g_instNoTexData.reserve(1);
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); // SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
if (decal.x8_rotation == 0.f) { // if (decal.x8_rotation == 0.f) {
inst.pos[0] = zeus::CVector3f(-size, 0.001f, size); // inst.pos[0] = zeus::CVector3f(-size, 0.001f, size);
inst.pos[1] = zeus::CVector3f(size, 0.001f, size); // inst.pos[1] = zeus::CVector3f(size, 0.001f, size);
inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size); // inst.pos[2] = zeus::CVector3f(-size, 0.001f, -size);
inst.pos[3] = zeus::CVector3f(size, 0.001f, -size); // inst.pos[3] = zeus::CVector3f(size, 0.001f, -size);
} else { // } else {
float ang = zeus::degToRad(decal.x8_rotation); // float ang = zeus::degToRad(decal.x8_rotation);
float sinSize = std::sin(ang) * size; // float sinSize = std::sin(ang) * size;
float cosSize = std::cos(ang) * size; // float cosSize = std::cos(ang) * size;
inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize); // inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 0.001f, cosSize + sinSize);
inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize); // inst.pos[1] = zeus::CVector3f(cosSize + sinSize, 0.001f, cosSize - sinSize);
inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize)); // inst.pos[2] = zeus::CVector3f(-(cosSize + sinSize), 0.001f, -(cosSize - sinSize));
inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize); // inst.pos[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize);
} // }
inst.color = color; // inst.color = color;
// decal.m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); // decal.m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); // CGraphics::DrawInstances(0, 4, g_instNoTexData.size());

View File

@ -3,6 +3,7 @@
#include "Runtime/GameGlobalObjects.hpp" #include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Character/CActorLights.hpp" #include "Runtime/Character/CActorLights.hpp"
#include "Runtime/Graphics/CCubeRenderer.hpp" #include "Runtime/Graphics/CCubeRenderer.hpp"
#include "Runtime/Graphics/CGX.hpp"
#include "Runtime/Graphics/CModel.hpp" #include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Graphics/Shaders/CElementGenShaders.hpp" #include "Runtime/Graphics/Shaders/CElementGenShaders.hpp"
#include "Runtime/Particle/CElectricDescription.hpp" #include "Runtime/Particle/CElectricDescription.hpp"
@ -19,11 +20,11 @@ namespace metaforce {
namespace { namespace {
logvisor::Module Log("metaforce::CElementGen"); logvisor::Module Log("metaforce::CElementGen");
constexpr std::array ShadClsSizes{ // constexpr std::array ShadClsSizes{
sizeof(SParticleInstanceTex), // sizeof(SParticleInstanceTex),
sizeof(SParticleInstanceIndTex), // sizeof(SParticleInstanceIndTex),
sizeof(SParticleInstanceNoTex), // sizeof(SParticleInstanceNoTex),
}; // };
} // Anonymous namespace } // Anonymous namespace
u16 CElementGen::g_GlobalSeed = 99; u16 CElementGen::g_GlobalSeed = 99;
@ -35,9 +36,9 @@ bool CElementGen::g_ParticleSystemInitialized = false;
bool CElementGen::sMoveRedToAlphaBuffer = false; bool CElementGen::sMoveRedToAlphaBuffer = false;
CParticle* CElementGen::g_currentParticle = nullptr; CParticle* CElementGen::g_currentParticle = nullptr;
std::vector<SParticleInstanceTex> g_instTexData; // std::vector<SParticleInstanceTex> g_instTexData;
std::vector<SParticleInstanceIndTex> g_instIndTexData; // std::vector<SParticleInstanceIndTex> g_instIndTexData;
std::vector<SParticleInstanceNoTex> g_instNoTexData; // std::vector<SParticleInstanceNoTex> g_instNoTexData;
void CElementGen::Initialize() { void CElementGen::Initialize() {
if (g_ParticleSystemInitialized) if (g_ParticleSystemInitialized)
@ -210,21 +211,21 @@ CElementGen::CElementGen(TToken<CGenDescription> gen, EModelOrientationType orie
if (x26c_31_LINE) { if (x26c_31_LINE) {
CUVElement* texr = desc->x54_x40_TEXR.get(); CUVElement* texr = desc->x54_x40_TEXR.get();
// TODO // TODO
// aurora::gfx::TextureHandle tex; // aurora::gfx::TextureHandle tex;
// if (texr) // if (texr)
// tex = texr->GetValueTexture(0).GetObj()->GetTexture(); // tex = texr->GetValueTexture(0).GetObj()->GetTexture();
int maxVerts = x90_MAXP; int maxVerts = x90_MAXP;
// m_lineRenderer.reset( // m_lineRenderer.reset(
// new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, tex, x26c_26_AAPH, x26c_28_zTest)); // new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, tex, x26c_26_AAPH, x26c_28_zTest));
} else { } else {
m_shaderClass = CElementGenShaders::GetShaderClass(*this); m_shaderClass = CElementGenShaders::GetShaderClass(*this);
} }
_RecreatePipelines(); _RecreatePipelines();
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { // CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
// CElementGenShaders::BuildShaderDataBinding(ctx, *this); // CElementGenShaders::BuildShaderDataBinding(ctx, *this);
// return true; // return true;
// } BooTrace); // } BooTrace);
} }
CElementGen::~CElementGen() { CElementGen::~CElementGen() {
@ -260,17 +261,17 @@ void CElementGen::_RecreatePipelines() {
size_t maxInsts = x26c_30_MBLR ? 2560 * 2 : 2560; // x26c_30_MBLR ? (x270_MBSP * x90_MAXP) : x90_MAXP; size_t maxInsts = x26c_30_MBLR ? 2560 * 2 : 2560; // x26c_30_MBLR ? (x270_MBSP * x90_MAXP) : x90_MAXP;
maxInsts = (maxInsts == 0 ? 256 : maxInsts); maxInsts = (maxInsts == 0 ? 256 : maxInsts);
// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { // CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
// if (!x26c_31_LINE) { // if (!x26c_31_LINE) {
// m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts); // m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts);
// m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1); // m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
// } // }
// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // if (x28_loadedGenDesc->x45_24_x31_26_PMUS) {
// m_instBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts); // m_instBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts);
// m_uniformBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1); // m_uniformBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
// } // }
// return true; // return true;
// } BooTrace); // } BooTrace);
} }
bool CElementGen::InternalUpdate(double dt) { bool CElementGen::InternalUpdate(double dt) {
@ -838,12 +839,12 @@ u32 CElementGen::GetSystemCount() const {
void CElementGen::Render(const CActorLights* actorLights) { void CElementGen::Render(const CActorLights* actorLights) {
// Check to make sure our buffers are ready to render // Check to make sure our buffers are ready to render
if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf) // if (!x26c_31_LINE) {
return; // return;
} // }
if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus) // if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus)
return; // return;
} // }
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CElementGen::Render {}"), *x1c_genDesc.GetObjectTag()).c_str(), SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CElementGen::Render {}"), *x1c_genDesc.GetObjectTag()).c_str(),
zeus::skYellow); zeus::skYellow);
@ -876,16 +877,19 @@ void CElementGen::Render(const CActorLights* actorLights) {
void CElementGen::RenderModels(const CActorLights* actorLights) { void CElementGen::RenderModels(const CActorLights* actorLights) {
// Check to make sure our buffers are ready to render // Check to make sure our buffers are ready to render
if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf) // if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf)
return; // return;
} // }
if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus) // if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus)
return; // return;
} // }
CParticleGlobals::instance()->m_particleAccessParameters = nullptr; CParticleGlobals::instance()->m_particleAccessParameters = nullptr;
if (x26d_26_modelsUseLights) if (x26d_26_modelsUseLights) {
CGraphics::SetLightState(x274_backupLightActive); CGraphics::SetLightState(x274_backupLightActive);
} else {
CGraphics::SetAmbientColor(zeus::skWhite);
}
CGlobalRandom gr(x27c_randState); CGlobalRandom gr(x27c_randState);
CGenDescription* desc = x1c_genDesc.GetObj(); CGenDescription* desc = x1c_genDesc.GetObj();
@ -897,20 +901,24 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
bool moveRedToAlphaBuffer = false; bool moveRedToAlphaBuffer = false;
if (desc->x45_24_x31_26_PMUS) { if (desc->x45_24_x31_26_PMUS) {
if (sMoveRedToAlphaBuffer && desc->x44_31_x31_25_PMAB && desc->x54_x40_TEXR) if (sMoveRedToAlphaBuffer && desc->x44_31_x31_25_PMAB && desc->x54_x40_TEXR) {
moveRedToAlphaBuffer = true; moveRedToAlphaBuffer = true;
}
if (desc->x44_31_x31_25_PMAB) { if (desc->x44_31_x31_25_PMAB) {
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false); CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false);
if (moveRedToAlphaBuffer) if (moveRedToAlphaBuffer) {
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear); CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear);
else } else {
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One,
ERglLogicOp::Clear); ERglLogicOp::Clear);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Greater, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
}
} else { } else {
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
ERglLogicOp::Clear); ERglLogicOp::Clear);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Greater, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
} }
CGraphics::SetCullMode(ERglCullMode::None); CGraphics::SetCullMode(ERglCullMode::None);
@ -920,37 +928,60 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
int partFrame = x74_curFrame - target.x28_startFrame; int partFrame = x74_curFrame - target.x28_startFrame;
cachedTex = texr->GetValueTexture(partFrame).GetObj(); cachedTex = texr->GetValueTexture(partFrame).GetObj();
cachedTex->Load(GX::TEXMAP0, EClampMode::Repeat); cachedTex->Load(GX::TEXMAP0, EClampMode::Repeat);
/* Shade as TEXC * RASC and TEXA * RASA */
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc);
if (moveRedToAlphaBuffer) { if (moveRedToAlphaBuffer) {
/* Color = Prev.rgb * Prev.a */ CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_CPREV, GX::CC_APREV, GX::CC_ZERO);
/* Alpha = Tex.r * Prev.a */ CGX::SetTevAlphaIn(GX::TEVSTAGE1, GX::CA_ZERO, GX::CA_TEXA, GX::CA_APREV, GX::CA_ZERO);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE1);
CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL);
GXSetTevSwapMode(GX::TEVSTAGE1, GX::TEV_SWAP0, GX::TEV_SWAP1);
CGX::SetNumTevStages(2);
constexpr std::array vtxDescList{
GX::VtxDescList{GX::VA_POS, GX::DIRECT},
GX::VtxDescList{GX::VA_CLR0, GX::DIRECT},
GX::VtxDescList{GX::VA_TEX0, GX::DIRECT},
GX::VtxDescList{},
};
CGX::SetVtxDescv(vtxDescList.data());
CGX::SetChanCtrl(CGX::EChannelId::Channel0, {});
CGX::SetNumChans(1);
CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY);
CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0);
CGX::SetNumTexGens(1);
} else {
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
} }
texConst = texr->HasConstantTexture(); texConst = texr->HasConstantTexture();
texr->GetValueUV(partFrame, uvs); texr->GetValueUV(partFrame, uvs);
} else {
CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassThru);
CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru);
} }
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: // case CElementGenShaders::EShaderClass::Tex:
g_instTexData.clear(); // g_instTexData.clear();
g_instTexData.reserve(x30_particles.size()); // g_instTexData.reserve(x30_particles.size());
break; // break;
case CElementGenShaders::EShaderClass::NoTex: // case CElementGenShaders::EShaderClass::NoTex:
g_instNoTexData.clear(); // g_instNoTexData.clear();
g_instNoTexData.reserve(x30_particles.size()); // g_instNoTexData.reserve(x30_particles.size());
break; // break;
default: // default:
Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); // Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class"));
break; // break;
} // }
SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/), {1.f, 1.f, 1.f, 1.f}}; // SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/), {1.f, 1.f, 1.f, 1.f}};
// m_uniformBufPmus->load(&uniformData, sizeof(SParticleUniforms)); // m_uniformBufPmus->load(&uniformData, sizeof(SParticleUniforms));
// //
// if (moveRedToAlphaBuffer) // if (moveRedToAlphaBuffer)
// CGraphics::SetShaderDataBinding(m_redToAlphaDataBindPmus[g_Renderer->IsThermalVisorHotPass()]); // CGraphics::SetShaderDataBinding(m_redToAlphaDataBindPmus[g_Renderer->IsThermalVisorHotPass()]);
// else // else
// CGraphics::SetShaderDataBinding(m_normalDataBindPmus[g_Renderer->IsThermalVisorHotPass()]); // CGraphics::SetShaderDataBinding(m_normalDataBindPmus[g_Renderer->IsThermalVisorHotPass()]);
} }
zeus::CTransform orient = zeus::CTransform(); zeus::CTransform orient = zeus::CTransform();
@ -1041,54 +1072,44 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
CGraphics::SetModelMatrix((x10c_globalScaleTransform * partTrans) * x178_localScaleTransform); CGraphics::SetModelMatrix((x10c_globalScaleTransform * partTrans) * x178_localScaleTransform);
if (desc->x45_24_x31_26_PMUS) { if (desc->x45_24_x31_26_PMUS) {
if (!texConst) { if (moveRedToAlphaBuffer) {
CTexture* tex = texr->GetValueTexture(x74_curFrame - particle.x28_startFrame).GetObj(); CGX::Begin(GX::QUADS, GX::VTXFMT0, 4);
if (tex != cachedTex) { GXPosition3f32(0.5f, 0.f, 0.5f);
tex->Load(GX::TEXMAP0, EClampMode::Repeat); GXColor4f32(col);
cachedTex = tex; GXTexCoord2f32(uvs.xMax, uvs.yMax);
} GXPosition3f32(-0.5f, 0.f, 0.5f);
} GXColor4f32(col);
GXTexCoord2f32(uvs.xMin, uvs.yMax);
switch (m_shaderClass) { GXPosition3f32(-0.5f, 0.f, -0.5f);
case CElementGenShaders::EShaderClass::Tex: { GXColor4f32(col);
SParticleInstanceTex& inst = g_instTexData.emplace_back(); GXTexCoord2f32(uvs.xMin, uvs.yMin);
inst.pos[0] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, 0.5f}; GXPosition3f32(0.5f, 0.f, -0.5f);
inst.pos[1] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, 0.5f}; GXColor4f32(col);
inst.pos[2] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, -0.5f}; GXTexCoord2f32(uvs.xMax, uvs.yMin);
inst.pos[3] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, -0.5f}; CGX::End();
inst.color = col; } else {
inst.uvs[0] = {uvs.xMax, uvs.yMax}; CGraphics::StreamBegin(GX::QUADS);
inst.uvs[1] = {uvs.xMin, uvs.yMax}; CGraphics::StreamColor(col);
inst.uvs[2] = {uvs.xMax, uvs.yMin}; CGraphics::StreamTexcoord(uvs.xMax, uvs.yMax);
inst.uvs[3] = {uvs.xMin, uvs.yMin}; CGraphics::StreamVertex(0.5f, 0.f, 0.5f);
break; CGraphics::StreamTexcoord(uvs.xMin, uvs.yMax);
} CGraphics::StreamVertex(-0.5f, 0.f, 0.5f);
case CElementGenShaders::EShaderClass::NoTex: { CGraphics::StreamTexcoord(uvs.xMin, uvs.yMin);
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); CGraphics::StreamVertex(-0.5f, 0.f, -0.5f);
inst.pos[0] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, 0.5f}; CGraphics::StreamTexcoord(uvs.xMax, uvs.yMin);
inst.pos[1] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, 0.5f}; CGraphics::StreamVertex(0.5f, 0.f, -0.5f);
inst.pos[2] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, -0.5f}; CGraphics::StreamEnd();
inst.pos[3] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, -0.5f};
inst.color = col;
break;
}
default:
break;
} }
} else { } else {
CModel* model = desc->x5c_x48_PMDL.GetObj(); CModel* model = desc->x5c_x48_PMDL.GetObj();
if (actorLights)
actorLights->ActivateLights();
if (g_subtractBlend) { if (g_subtractBlend) {
model->Draw({5, 0, 1, zeus::CColor(1.f, 0.5f)}); model->Draw({5, 0, 1, zeus::CColor{1.f, 0.5f}});
} else if (desc->x44_31_x31_25_PMAB) { } else if (desc->x44_31_x31_25_PMAB) {
CModelFlags flags{7, 0, 1, col}; model->Draw({7, 0, 1, col});
// flags.m_extendedShader = EExtendedShader::ForcedAdditiveNoZWrite;
model->Draw(flags);
} else if (1.f == col.a()) { } else if (1.f == col.a()) {
model->Draw({0, 0, 3, zeus::skWhite}); model->Draw({0, 0, 3, zeus::skWhite});
} else { } else {
model->Draw({5, 0, 1, zeus::CColor(1.f, col.a())}); model->Draw({5, 0, 1, zeus::CColor{1.f, col.a()}});
} }
} }
@ -1096,28 +1117,15 @@ void CElementGen::RenderModels(const CActorLights* actorLights) {
++matrixIt; ++matrixIt;
} }
if (desc->x45_24_x31_26_PMUS) { if (x26d_26_modelsUseLights) {
switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex:
// m_instBufPmus->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size());
break;
case CElementGenShaders::EShaderClass::NoTex:
// m_instBufPmus->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
break;
default:
break;
}
}
if (x26d_26_modelsUseLights)
CGraphics::DisableAllLights(); CGraphics::DisableAllLights();
}
CGraphics::SetCullMode(ERglCullMode::Front); CGraphics::SetCullMode(ERglCullMode::Front);
if (moveRedToAlphaBuffer) { if (moveRedToAlphaBuffer) {
/* Restore passthrough */ GXSetTevSwapMode(GX::TEVSTAGE1, GX::TEV_SWAP0, GX::TEV_SWAP0);
} }
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
} }
void CElementGen::RenderLines() { void CElementGen::RenderLines() {
@ -1258,8 +1266,9 @@ void CElementGen::RenderParticles() {
bool constUVs = true; bool constUVs = true;
CTexture* cachedTex = nullptr; CTexture* cachedTex = nullptr;
SParticleUniforms uniformData = { // SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/) *
CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}}; // CGraphics::g_GXModelView.toMatrix4f(),
// {1.f, 1.f, 1.f, 1.f}};
if (texr) { if (texr) {
CParticle& target = x30_particles[0]; CParticle& target = x30_particles[0];
@ -1269,14 +1278,14 @@ void CElementGen::RenderParticles() {
if (x338_moduColor != zeus::skBlack) { if (x338_moduColor != zeus::skBlack) {
/* Add RASC * PREVC pass for MODU color loaded into channel mat-color */ /* Add RASC * PREVC pass for MODU color loaded into channel mat-color */
uniformData.moduColor = x338_moduColor; // uniformData.moduColor = x338_moduColor;
} }
texr->GetValueUV(partFrame, uvs); texr->GetValueUV(partFrame, uvs);
constUVs = texr->HasConstantUV(); constUVs = texr->HasConstantUV();
} }
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); // m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
std::vector<CParticleListItem> sortItems; std::vector<CParticleListItem> sortItems;
if (desc->x44_28_x30_28_SORT) { if (desc->x44_28_x30_28_SORT) {
@ -1301,15 +1310,15 @@ void CElementGen::RenderParticles() {
if (g_subtractBlend) { if (g_subtractBlend) {
// FIXME should there be NoTex specializations for RedToAlpha? // FIXME should there be NoTex specializations for RedToAlpha?
// if (moveRedToAlphaBuffer && desc->x54_x40_TEXR) // if (moveRedToAlphaBuffer && desc->x54_x40_TEXR)
// CGraphics::SetShaderDataBinding(m_redToAlphaSubDataBind[g_Renderer->IsThermalVisorHotPass()]); // CGraphics::SetShaderDataBinding(m_redToAlphaSubDataBind[g_Renderer->IsThermalVisorHotPass()]);
// else // else
// CGraphics::SetShaderDataBinding(m_normalSubDataBind[g_Renderer->IsThermalVisorHotPass()]); // CGraphics::SetShaderDataBinding(m_normalSubDataBind[g_Renderer->IsThermalVisorHotPass()]);
} else { } else {
// if (moveRedToAlphaBuffer && desc->x54_x40_TEXR) // if (moveRedToAlphaBuffer && desc->x54_x40_TEXR)
// CGraphics::SetShaderDataBinding(m_redToAlphaDataBind[g_Renderer->IsThermalVisorHotPass()]); // CGraphics::SetShaderDataBinding(m_redToAlphaDataBind[g_Renderer->IsThermalVisorHotPass()]);
// else // else
// CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]); // CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]);
} }
int mbspVal = std::max(1, x270_MBSP); int mbspVal = std::max(1, x270_MBSP);
@ -1344,19 +1353,19 @@ void CElementGen::RenderParticles() {
} }
#endif #endif
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: // case CElementGenShaders::EShaderClass::Tex:
g_instTexData.clear(); // g_instTexData.clear();
g_instTexData.reserve(x30_particles.size()); // g_instTexData.reserve(x30_particles.size());
break; // break;
case CElementGenShaders::EShaderClass::NoTex: // case CElementGenShaders::EShaderClass::NoTex:
g_instNoTexData.clear(); // g_instNoTexData.clear();
g_instNoTexData.reserve(x30_particles.size()); // g_instNoTexData.reserve(x30_particles.size());
break; // break;
default: // default:
Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); // Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class"));
break; // break;
} // }
if (!x26c_29_ORNT) { if (!x26c_29_ORNT) {
for (size_t i = 0; i < x30_particles.size(); ++i) { for (size_t i = 0; i < x30_particles.size(); ++i) {
@ -1381,67 +1390,67 @@ void CElementGen::RenderParticles() {
const float size = 0.5f * particle.x2c_lineLengthOrSize; const float size = 0.5f * particle.x2c_lineLengthOrSize;
if (0.f == particle.x30_lineWidthOrRota) { if (0.f == particle.x30_lineWidthOrRota) {
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: { // case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back(); // SParticleInstanceTex& inst = g_instTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f}; // inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f};
inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f}; // inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f};
inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f}; // inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f};
inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f}; // inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
inst.uvs[0] = {uvs.xMax, uvs.yMax}; // inst.uvs[0] = {uvs.xMax, uvs.yMax};
inst.uvs[1] = {uvs.xMin, uvs.yMax}; // inst.uvs[1] = {uvs.xMin, uvs.yMax};
inst.uvs[2] = {uvs.xMax, uvs.yMin}; // inst.uvs[2] = {uvs.xMax, uvs.yMin};
inst.uvs[3] = {uvs.xMin, uvs.yMin}; // inst.uvs[3] = {uvs.xMin, uvs.yMin};
break; // break;
} // }
case CElementGenShaders::EShaderClass::NoTex: { // case CElementGenShaders::EShaderClass::NoTex: {
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); // SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f}; // inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f};
inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f}; // inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f};
inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f}; // inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f};
inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f}; // inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
break; // break;
} // }
default: // default:
break; // break;
} // }
} else { } else {
float theta = zeus::degToRad(particle.x30_lineWidthOrRota); float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
float sinT = std::sin(theta) * size; float sinT = std::sin(theta) * size;
float cosT = std::cos(theta) * size; float cosT = std::cos(theta) * size;
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: { // case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back(); // SParticleInstanceTex& inst = g_instTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{viewPoint.x() + sinT + cosT, viewPoint.y(), viewPoint.z() + cosT - sinT, 1.f}; // inst.pos[0] = zeus::CVector4f{viewPoint.x() + sinT + cosT, viewPoint.y(), viewPoint.z() + cosT - sinT, 1.f};
inst.pos[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f}; // inst.pos[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f};
inst.pos[2] = // inst.pos[2] =
zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f}; // zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f};
inst.pos[3] = // inst.pos[3] =
zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f}; // zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
inst.uvs[0] = {uvs.xMax, uvs.yMax}; // inst.uvs[0] = {uvs.xMax, uvs.yMax};
inst.uvs[1] = {uvs.xMin, uvs.yMax}; // inst.uvs[1] = {uvs.xMin, uvs.yMax};
inst.uvs[2] = {uvs.xMax, uvs.yMin}; // inst.uvs[2] = {uvs.xMax, uvs.yMin};
inst.uvs[3] = {uvs.xMin, uvs.yMin}; // inst.uvs[3] = {uvs.xMin, uvs.yMin};
break; // break;
} // }
case CElementGenShaders::EShaderClass::NoTex: { // case CElementGenShaders::EShaderClass::NoTex: {
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); // SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{viewPoint.x() + sinT + cosT, viewPoint.y(), viewPoint.z() + cosT - sinT, 1.f}; // inst.pos[0] = zeus::CVector4f{viewPoint.x() + sinT + cosT, viewPoint.y(), viewPoint.z() + cosT - sinT, 1.f};
inst.pos[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f}; // inst.pos[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f};
inst.pos[2] = // inst.pos[2] =
zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f}; // zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f};
inst.pos[3] = // inst.pos[3] =
zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f}; // zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
break; // break;
} // }
default: // default:
break; // break;
} // }
} }
} }
} else { } else {
@ -1487,65 +1496,65 @@ void CElementGen::RenderParticles() {
texr->GetValueUV(partFrame, uvs); texr->GetValueUV(partFrame, uvs);
} }
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: { // case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back(); // SParticleInstanceTex& inst = g_instTexData.emplace_back();
viewPoint += rightVec * 0.5f; // viewPoint += rightVec * 0.5f;
inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; // inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; // inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
viewPoint -= rightVec; // viewPoint -= rightVec;
inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; // inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; // inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
inst.uvs[0] = {uvs.xMax, uvs.yMax}; // inst.uvs[0] = {uvs.xMax, uvs.yMax};
inst.uvs[1] = {uvs.xMin, uvs.yMax}; // inst.uvs[1] = {uvs.xMin, uvs.yMax};
inst.uvs[2] = {uvs.xMax, uvs.yMin}; // inst.uvs[2] = {uvs.xMax, uvs.yMin};
inst.uvs[3] = {uvs.xMin, uvs.yMin}; // inst.uvs[3] = {uvs.xMin, uvs.yMin};
break; // break;
} // }
case CElementGenShaders::EShaderClass::NoTex: { // case CElementGenShaders::EShaderClass::NoTex: {
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); // SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
viewPoint += rightVec * 0.5f; // viewPoint += rightVec * 0.5f;
inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; // inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; // inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
viewPoint -= rightVec; // viewPoint -= rightVec;
inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; // inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec};
inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; // inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
break; // break;
} // }
default: // default:
break; // break;
} // }
} }
} }
switch (m_shaderClass) { switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: case CElementGenShaders::EShaderClass::Tex:
// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); // m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size()); // CGraphics::DrawInstances(0, 4, g_instTexData.size());
break; break;
case CElementGenShaders::EShaderClass::NoTex: case CElementGenShaders::EShaderClass::NoTex:
// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); // m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); // CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
break; break;
default: default:
break; break;
} }
} else { } else {
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: // case CElementGenShaders::EShaderClass::Tex:
g_instTexData.clear(); // g_instTexData.clear();
g_instTexData.reserve(x30_particles.size() * mbspVal); // g_instTexData.reserve(x30_particles.size() * mbspVal);
break; // break;
case CElementGenShaders::EShaderClass::NoTex: // case CElementGenShaders::EShaderClass::NoTex:
g_instNoTexData.clear(); // g_instNoTexData.clear();
g_instNoTexData.reserve(x30_particles.size() * mbspVal); // g_instNoTexData.reserve(x30_particles.size() * mbspVal);
break; // break;
default: // default:
Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); // Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class"));
break; // break;
} // }
const float mbspFac = 1.f / float(mbspVal); const float mbspFac = 1.f / float(mbspVal);
for (size_t i = 0; i < x30_particles.size(); ++i) { for (size_t i = 0; i < x30_particles.size(); ++i) {
const int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : int(i); const int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : int(i);
@ -1569,32 +1578,32 @@ void CElementGen::RenderParticles() {
vec += mbspVec; vec += mbspVec;
zeus::CVector3f vec2 = systemCameraMatrix * vec; zeus::CVector3f vec2 = systemCameraMatrix * vec;
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: { // case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back(); // SParticleInstanceTex& inst = g_instTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f}; // inst.pos[0] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f}; // inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f}; // inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() - size, 1.f}; // inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() - size, 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
inst.uvs[0] = {uvs.xMax, uvs.yMax}; // inst.uvs[0] = {uvs.xMax, uvs.yMax};
inst.uvs[1] = {uvs.xMin, uvs.yMax}; // inst.uvs[1] = {uvs.xMin, uvs.yMax};
inst.uvs[2] = {uvs.xMax, uvs.yMin}; // inst.uvs[2] = {uvs.xMax, uvs.yMin};
inst.uvs[3] = {uvs.xMin, uvs.yMin}; // inst.uvs[3] = {uvs.xMin, uvs.yMin};
break; // break;
} // }
case CElementGenShaders::EShaderClass::NoTex: { // case CElementGenShaders::EShaderClass::NoTex: {
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); // SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f}; // inst.pos[0] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f}; // inst.pos[1] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() + size, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f}; // inst.pos[2] = zeus::CVector4f{vec2.x() + size, vec2.y(), vec2.z() - size, 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() - size, 1.f}; // inst.pos[3] = zeus::CVector4f{vec2.x() - size, vec2.y(), vec2.z() - size, 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
break; // break;
} // }
default: // default:
break; // break;
} // }
} }
} else { } else {
float theta = zeus::degToRad(particle.x30_lineWidthOrRota); float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
@ -1605,43 +1614,43 @@ void CElementGen::RenderParticles() {
vec += mbspVec; vec += mbspVec;
zeus::CVector3f vec2 = systemCameraMatrix * vec; zeus::CVector3f vec2 = systemCameraMatrix * vec;
switch (m_shaderClass) { // switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: { // case CElementGenShaders::EShaderClass::Tex: {
SParticleInstanceTex& inst = g_instTexData.emplace_back(); // SParticleInstanceTex& inst = g_instTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f}; // inst.pos[0] = zeus::CVector4f{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f}; // inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f}; // inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f}; // inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
inst.uvs[0] = {uvs.xMax, uvs.yMax}; // inst.uvs[0] = {uvs.xMax, uvs.yMax};
inst.uvs[1] = {uvs.xMin, uvs.yMax}; // inst.uvs[1] = {uvs.xMin, uvs.yMax};
inst.uvs[2] = {uvs.xMax, uvs.yMin}; // inst.uvs[2] = {uvs.xMax, uvs.yMin};
inst.uvs[3] = {uvs.xMin, uvs.yMin}; // inst.uvs[3] = {uvs.xMin, uvs.yMin};
break; // break;
} // }
case CElementGenShaders::EShaderClass::NoTex: { // case CElementGenShaders::EShaderClass::NoTex: {
SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); // SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f}; // inst.pos[0] = zeus::CVector4f{vec2.x() + sinT + cosT, vec2.y(), vec2.z() + cosT - sinT, 1.f};
inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f}; // inst.pos[1] = zeus::CVector4f{vec2.x() + sinT - cosT, vec2.y(), vec2.z() + sinT + cosT, 1.f};
inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f}; // inst.pos[2] = zeus::CVector4f{vec2.x() + (cosT - sinT), vec2.y(), vec2.z() + (-cosT - sinT), 1.f};
inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f}; // inst.pos[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
break; // break;
} // }
default: // default:
break; // break;
} // }
} }
} }
} }
switch (m_shaderClass) { switch (m_shaderClass) {
case CElementGenShaders::EShaderClass::Tex: case CElementGenShaders::EShaderClass::Tex:
// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); // m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
// CGraphics::DrawInstances(0, 4, g_instTexData.size()); // CGraphics::DrawInstances(0, 4, g_instTexData.size());
break; break;
case CElementGenShaders::EShaderClass::NoTex: case CElementGenShaders::EShaderClass::NoTex:
// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); // m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
// CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); // CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
break; break;
default: default:
break; break;
@ -1660,9 +1669,10 @@ void CElementGen::RenderParticlesIndirectTexture() {
x178_localScaleTransform; x178_localScaleTransform;
CGraphics::SetModelMatrix(systemViewPointMatrix); CGraphics::SetModelMatrix(systemViewPointMatrix);
SParticleUniforms uniformData = { // SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/) *
CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}}; // CGraphics::g_GXModelView.toMatrix4f(),
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); // {1.f, 1.f, 1.f, 1.f}};
// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
@ -1712,11 +1722,11 @@ void CElementGen::RenderParticlesIndirectTexture() {
}); });
} }
g_instIndTexData.clear(); // g_instIndTexData.clear();
g_instIndTexData.reserve(x30_particles.size()); // g_instIndTexData.reserve(x30_particles.size());
// if (!x30_particles.empty()) // if (!x30_particles.empty())
// CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]); // CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]);
for (size_t i = 0; i < x30_particles.size(); ++i) { for (size_t i = 0; i < x30_particles.size(); ++i) {
const int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : int(i); const int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : int(i);
@ -1764,35 +1774,35 @@ void CElementGen::RenderParticlesIndirectTexture() {
CGraphics::ResolveSpareTexture(clipRect); CGraphics::ResolveSpareTexture(clipRect);
SParticleInstanceIndTex& inst = g_instIndTexData.emplace_back(); // SParticleInstanceIndTex& inst = g_instIndTexData.emplace_back();
inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f}; // inst.pos[0] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() + size, 1.f};
inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f}; // inst.pos[1] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() + size, 1.f};
inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f}; // inst.pos[2] = zeus::CVector4f{viewPoint.x() + size, viewPoint.y(), viewPoint.z() - size, 1.f};
inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f}; // inst.pos[3] = zeus::CVector4f{viewPoint.x() - size, viewPoint.y(), viewPoint.z() - size, 1.f};
inst.color = particle.x34_color; // inst.color = particle.x34_color;
inst.texrTindUVs[0] = zeus::CVector4f{uvs.xMax, uvs.yMax, uvsInd.xMax, uvsInd.yMax}; // inst.texrTindUVs[0] = zeus::CVector4f{uvs.xMax, uvs.yMax, uvsInd.xMax, uvsInd.yMax};
inst.texrTindUVs[1] = zeus::CVector4f{uvs.xMin, uvs.yMax, uvsInd.xMin, uvsInd.yMax}; // inst.texrTindUVs[1] = zeus::CVector4f{uvs.xMin, uvs.yMax, uvsInd.xMin, uvsInd.yMax};
inst.texrTindUVs[2] = zeus::CVector4f{uvs.xMax, uvs.yMin, uvsInd.xMax, uvsInd.yMin}; // inst.texrTindUVs[2] = zeus::CVector4f{uvs.xMax, uvs.yMin, uvsInd.xMax, uvsInd.yMin};
inst.texrTindUVs[3] = zeus::CVector4f{uvs.xMin, uvs.yMin, uvsInd.xMin, uvsInd.yMin}; // inst.texrTindUVs[3] = zeus::CVector4f{uvs.xMin, uvs.yMin, uvsInd.xMin, uvsInd.yMin};
// switch (CGraphics::g_BooPlatform) { // switch (CGraphics::g_BooPlatform) {
// case boo::IGraphicsDataFactory::Platform::OpenGL: // case boo::IGraphicsDataFactory::Platform::OpenGL:
// inst.sceneUVs = // inst.sceneUVs =
// zeus::CVector4f{clipRect.x18_uvXMin, clipRect.x24_uvYMax, clipRect.x1c_uvXMax, clipRect.x20_uvYMin}; // zeus::CVector4f{clipRect.x18_uvXMin, clipRect.x24_uvYMax, clipRect.x1c_uvXMax, clipRect.x20_uvYMin};
// break; // break;
// default: // default:
inst.sceneUVs = zeus::CVector4f{clipRect.x18_uvXMin, 1.f - clipRect.x24_uvYMax, clipRect.x1c_uvXMax, // inst.sceneUVs =
1.f - clipRect.x20_uvYMin}; // zeus::CVector4f{clipRect.x18_uvXMin, 1.f - clipRect.x24_uvYMax, clipRect.x1c_uvXMax, 1.f - clipRect.x20_uvYMin};
// break; // break;
// } // }
// CGraphics::DrawInstances(0, 4, 1, g_instIndTexData.size() - 1); // CGraphics::DrawInstances(0, 4, 1, g_instIndTexData.size() - 1);
} }
if (g_instIndTexData.size()) { // if (g_instIndTexData.size()) {
// m_instBuf->load(g_instIndTexData.data(), g_instIndTexData.size() * sizeof(SParticleInstanceIndTex)); // m_instBuf->load(g_instIndTexData.data(), g_instIndTexData.size() * sizeof(SParticleInstanceIndTex));
// TODO! this looks like a bug // TODO! this looks like a bug
// CGraphics::SetShaderDataBinding(m_normalDataBind); // CGraphics::SetShaderDataBinding(m_normalDataBind);
// CGraphics::DrawInstances(0, 4, g_instIndTexData.size()); // CGraphics::DrawInstances(0, 4, g_instIndTexData.size());
} // }
} }
void CElementGen::SetOrientation(const zeus::CTransform& orientation) { void CElementGen::SetOrientation(const zeus::CTransform& orientation) {

View File

@ -59,30 +59,30 @@ public:
} }
}; };
struct SParticleInstanceTex { //struct SParticleInstanceTex {
std::array<zeus::CVector4f, 4> pos; // std::array<zeus::CVector4f, 4> pos;
zeus::CColor color; // zeus::CColor color;
std::array<zeus::CVector2f, 4> uvs; // std::array<zeus::CVector2f, 4> uvs;
}; //};
extern std::vector<SParticleInstanceTex> g_instTexData; //extern std::vector<SParticleInstanceTex> g_instTexData;
//
struct SParticleInstanceIndTex { //struct SParticleInstanceIndTex {
std::array<zeus::CVector4f, 4> pos; // std::array<zeus::CVector4f, 4> pos;
zeus::CColor color; // zeus::CColor color;
std::array<zeus::CVector4f, 4> texrTindUVs; // std::array<zeus::CVector4f, 4> texrTindUVs;
zeus::CVector4f sceneUVs; // zeus::CVector4f sceneUVs;
}; //};
extern std::vector<SParticleInstanceIndTex> g_instIndTexData; //extern std::vector<SParticleInstanceIndTex> g_instIndTexData;
//
struct SParticleInstanceNoTex { //struct SParticleInstanceNoTex {
std::array<zeus::CVector4f, 4> pos; // std::array<zeus::CVector4f, 4> pos;
zeus::CColor color; // zeus::CColor color;
}; //};
extern std::vector<SParticleInstanceNoTex> g_instNoTexData; //extern std::vector<SParticleInstanceNoTex> g_instNoTexData;
//
struct SParticleUniforms { //struct SParticleUniforms {
zeus::CMatrix4f mvp; // zeus::CMatrix4f mvp;
zeus::CColor moduColor; // zeus::CColor moduColor;
}; //};
} // namespace metaforce } // namespace metaforce

View File

@ -132,11 +132,6 @@ struct Light {
[[nodiscard]] bool get_dxt_compression_supported() noexcept; [[nodiscard]] bool get_dxt_compression_supported() noexcept;
void stream_begin(GX::Primitive primitive) noexcept;
void stream_vertex(metaforce::EStreamFlags flags, const zeus::CVector3f& pos, const zeus::CVector3f& nrm,
const zeus::CColor& color, const zeus::CVector2f& uv) noexcept;
void stream_end() noexcept;
// GX state // GX state
void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept; void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept;
void unbind_texture(GX::TexMapID id) noexcept; void unbind_texture(GX::TexMapID id) noexcept;

View File

@ -1,6 +1,7 @@
#include "gx.hpp" #include "gx.hpp"
#include "../gpu.hpp" #include "../gpu.hpp"
#include "Runtime/Graphics/GX.hpp"
#include "common.hpp" #include "common.hpp"
#include <absl/container/flat_hash_map.h> #include <absl/container/flat_hash_map.h>
@ -187,6 +188,28 @@ void GXSetFog(GX::FogType type, float startZ, float endZ, float nearZ, float far
g_gxState.fog = {type, startZ, endZ, nearZ, farZ, color}; g_gxState.fog = {type, startZ, endZ, nearZ, farZ, color};
} }
void GXSetFogColor(const GXColor& color) noexcept { g_gxState.fog.color = color; } void GXSetFogColor(const GXColor& color) noexcept { g_gxState.fog.color = color; }
void GXSetVtxDesc(GX::Attr attr, GX::AttrType type) noexcept { g_gxState.vtxDesc[attr] = type; }
void GXSetVtxDescv(GX::VtxDescList* list) noexcept {
g_gxState.vtxDesc.fill({});
while (*list) {
g_gxState.vtxDesc[list->attr] = list->type;
++list;
}
}
void GXClearVtxDesc() noexcept { g_gxState.vtxDesc.fill({}); }
void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColorChan green, GX::TevColorChan blue,
GX::TevColorChan alpha) noexcept {
if (id < GX::TEV_SWAP0 || id >= GX::MAX_TEVSWAP) {
Log.report(logvisor::Fatal, FMT_STRING("invalid tev swap sel {}"), id);
unreachable();
}
g_gxState.tevSwapTable[id] = {red, green, blue, alpha};
}
void GXSetTevSwapMode(GX::TevStageID stageId, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) noexcept {
auto& stage = g_gxState.tevStages[stageId];
stage.tevSwapRas = rasSel;
stage.tevSwapTex = texSel;
}
namespace aurora::gfx { namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx"); static logvisor::Module Log("aurora::gfx::gx");
@ -387,6 +410,9 @@ wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, const ShaderIn
ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive, ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primitive,
const BindGroupRanges& ranges) noexcept { const BindGroupRanges& ranges) noexcept {
config.shaderConfig.fogType = g_gxState.fog.type;
config.shaderConfig.vtxAttrs = g_gxState.vtxDesc;
config.shaderConfig.tevSwapTable = g_gxState.tevSwapTable;
for (u8 i = 0; i < g_gxState.numTevStages; ++i) { for (u8 i = 0; i < g_gxState.numTevStages; ++i) {
config.shaderConfig.tevStages[i] = g_gxState.tevStages[i]; config.shaderConfig.tevStages[i] = g_gxState.tevStages[i];
} }
@ -397,7 +423,10 @@ ShaderInfo populate_pipeline_config(PipelineConfig& config, GX::Primitive primit
config.shaderConfig.tcgs[i] = g_gxState.tcgs[i]; config.shaderConfig.tcgs[i] = g_gxState.tcgs[i];
} }
config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard; config.shaderConfig.alphaDiscard = g_gxState.alphaDiscard;
config.shaderConfig.fogType = g_gxState.fog.type; if (std::any_of(config.shaderConfig.vtxAttrs.begin(), config.shaderConfig.vtxAttrs.end(),
[](const auto type) { return type == GX::INDEX8 || type == GX::INDEX16; })) {
config.shaderConfig.hasIndexedAttributes = true;
}
config = { config = {
.shaderConfig = config.shaderConfig, .shaderConfig = config.shaderConfig,
.primitive = primitive, .primitive = primitive,
@ -601,7 +630,7 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
.uniformBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{ .uniformBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
.label = "GX Uniform Bind Group", .label = "GX Uniform Bind Group",
.layout = layouts.uniformLayout, .layout = layouts.uniformLayout,
.entryCount = static_cast<uint32_t>(config.denormalizedVertexAttributes ? 1 : uniformEntries.size()), .entryCount = static_cast<uint32_t>(config.hasIndexedAttributes ? uniformEntries.size() : 1),
.entries = uniformEntries.data(), .entries = uniformEntries.data(),
}), }),
.samplerBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{ .samplerBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{
@ -621,7 +650,7 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const ShaderConfig& config) noexcept { GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const ShaderConfig& config) noexcept {
GXBindGroupLayouts out; GXBindGroupLayouts out;
u32 uniformSizeKey = info.uniformSize + (config.denormalizedVertexAttributes ? 0 : 1); u32 uniformSizeKey = info.uniformSize + (config.hasIndexedAttributes ? 1 : 0);
const auto uniformIt = sUniformBindGroupLayouts.find(uniformSizeKey); const auto uniformIt = sUniformBindGroupLayouts.find(uniformSizeKey);
if (uniformIt != sUniformBindGroupLayouts.end()) { if (uniformIt != sUniformBindGroupLayouts.end()) {
out.uniformLayout = uniformIt->second; out.uniformLayout = uniformIt->second;
@ -676,7 +705,7 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader
}; };
const auto uniformLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{ const auto uniformLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{
.label = "GX Uniform Bind Group Layout", .label = "GX Uniform Bind Group Layout",
.entryCount = static_cast<uint32_t>(config.denormalizedVertexAttributes ? 1 : uniformLayoutEntries.size()), .entryCount = static_cast<uint32_t>(config.hasIndexedAttributes ? uniformLayoutEntries.size() : 1),
.entries = uniformLayoutEntries.data(), .entries = uniformLayoutEntries.data(),
}; };
out.uniformLayout = g_device.CreateBindGroupLayout(&uniformLayoutDescriptor); out.uniformLayout = g_device.CreateBindGroupLayout(&uniformLayoutDescriptor);

View File

@ -13,6 +13,8 @@ constexpr u32 MaxKColors = GX::MAX_KCOLOR;
constexpr u32 MaxTexMtx = 10; constexpr u32 MaxTexMtx = 10;
constexpr u32 MaxPTTexMtx = 20; constexpr u32 MaxPTTexMtx = 20;
constexpr u32 MaxTexCoord = GX::MAX_TEXCOORD; constexpr u32 MaxTexCoord = GX::MAX_TEXCOORD;
constexpr u32 MaxVtxAttr = GX::VA_MAX_ATTR;
constexpr u32 MaxTevSwap = GX::MAX_TEVSWAP;
template <typename Arg, Arg Default> template <typename Arg, Arg Default>
struct TevPass { struct TevPass {
@ -40,6 +42,8 @@ struct TevStage {
GX::TexCoordID texCoordId = GX::TEXCOORD_NULL; GX::TexCoordID texCoordId = GX::TEXCOORD_NULL;
GX::TexMapID texMapId = GX::TEXMAP_NULL; GX::TexMapID texMapId = GX::TEXMAP_NULL;
GX::ChannelID channelId = GX::COLOR_NULL; GX::ChannelID channelId = GX::COLOR_NULL;
GX::TevSwapSel tevSwapRas = GX::TEV_SWAP0;
GX::TevSwapSel tevSwapTex = GX::TEV_SWAP0;
bool operator==(const TevStage&) const = default; bool operator==(const TevStage&) const = default;
}; };
struct TextureBind { struct TextureBind {
@ -86,6 +90,14 @@ struct FogState {
float farZ = 0.f; float farZ = 0.f;
zeus::CColor color; zeus::CColor color;
}; };
struct TevSwap {
GX::TevColorChan red = GX::CH_RED;
GX::TevColorChan green = GX::CH_GREEN;
GX::TevColorChan blue = GX::CH_BLUE;
GX::TevColorChan alpha = GX::CH_ALPHA;
bool operator==(const TevSwap&) const = default;
operator bool() const { return *this != TevSwap{}; }
};
struct GXState { struct GXState {
zeus::CMatrix4f mv; zeus::CMatrix4f mv;
@ -111,6 +123,13 @@ struct GXState {
std::array<TexMtxVariant, MaxTexMtx> texMtxs; std::array<TexMtxVariant, MaxTexMtx> texMtxs;
std::array<Mat4x4<float>, MaxPTTexMtx> ptTexMtxs; std::array<Mat4x4<float>, MaxPTTexMtx> ptTexMtxs;
std::array<TcgConfig, MaxTexCoord> tcgs; std::array<TcgConfig, MaxTexCoord> tcgs;
std::array<GX::AttrType, MaxVtxAttr> vtxDesc;
std::array<TevSwap, MaxTevSwap> tevSwapTable{
TevSwap{},
TevSwap{GX::CH_RED, GX::CH_RED, GX::CH_RED, GX::CH_ALPHA},
TevSwap{GX::CH_GREEN, GX::CH_GREEN, GX::CH_GREEN, GX::CH_ALPHA},
TevSwap{GX::CH_BLUE, GX::CH_BLUE, GX::CH_BLUE, GX::CH_ALPHA},
};
bool depthCompare = true; bool depthCompare = true;
bool depthUpdate = true; bool depthUpdate = true;
bool alphaUpdate = true; bool alphaUpdate = true;
@ -128,12 +147,13 @@ const TextureBind& get_texture(GX::TexMapID id) noexcept;
struct ShaderConfig { struct ShaderConfig {
GX::FogType fogType; GX::FogType fogType;
std::array<GX::AttrType, MaxVtxAttr> vtxAttrs;
std::array<TevSwap, MaxTevSwap> tevSwapTable;
std::array<std::optional<TevStage>, MaxTevStages> tevStages; std::array<std::optional<TevStage>, MaxTevStages> tevStages;
std::array<ColorChannelConfig, MaxColorChannels> colorChannels; std::array<ColorChannelConfig, MaxColorChannels> colorChannels;
std::array<TcgConfig, MaxTexCoord> tcgs; std::array<TcgConfig, MaxTexCoord> tcgs;
std::optional<float> alphaDiscard; std::optional<float> alphaDiscard;
bool denormalizedVertexAttributes = false; bool hasIndexedAttributes = false;
bool denormalizedHasNrm = false; // TODO this is a hack
bool operator==(const ShaderConfig&) const = default; bool operator==(const ShaderConfig&) const = default;
}; };
struct PipelineConfig { struct PipelineConfig {
@ -168,8 +188,6 @@ struct ShaderInfo {
std::bitset<MaxPTTexMtx> usesPTTexMtx; std::bitset<MaxPTTexMtx> usesPTTexMtx;
std::array<GX::TexGenType, MaxTexMtx> texMtxTypes; std::array<GX::TexGenType, MaxTexMtx> texMtxTypes;
u32 uniformSize = 0; u32 uniformSize = 0;
bool usesVtxColor : 1 = false;
bool usesNormal : 1 = false;
bool usesFog : 1 = false; bool usesFog : 1 = false;
}; };
struct BindGroupRanges { struct BindGroupRanges {
@ -248,6 +266,9 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TcgConfig& input) {
} }
template <> template <>
inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) { inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) {
XXH3_64bits_update(&state, &input.fogType, sizeof(gfx::gx::ShaderConfig::fogType));
XXH3_64bits_update(&state, &input.vtxAttrs, sizeof(gfx::gx::ShaderConfig::vtxAttrs));
XXH3_64bits_update(&state, &input.tevSwapTable, sizeof(gfx::gx::ShaderConfig::tevSwapTable));
for (const auto& item : input.tevStages) { for (const auto& item : input.tevStages) {
if (!item) { if (!item) {
break; break;
@ -263,9 +284,6 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input)
if (input.alphaDiscard) { if (input.alphaDiscard) {
XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float)); XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float));
} }
XXH3_64bits_update(&state, &input.denormalizedVertexAttributes, XXH3_64bits_update(&state, &input.hasIndexedAttributes, sizeof(gfx::gx::ShaderConfig::hasIndexedAttributes));
sizeof(gfx::gx::ShaderConfig::denormalizedVertexAttributes));
XXH3_64bits_update(&state, &input.denormalizedHasNrm, sizeof(gfx::gx::ShaderConfig::denormalizedHasNrm));
XXH3_64bits_update(&state, &input.fogType, sizeof(gfx::gx::ShaderConfig::fogType));
} }
} // namespace aurora } // namespace aurora

View File

@ -15,7 +15,21 @@ absl::flat_hash_map<ShaderRef, std::pair<wgpu::ShaderModule, gx::ShaderInfo>> g_
static absl::flat_hash_map<ShaderRef, gx::ShaderConfig> g_gxCachedShaderConfigs; static absl::flat_hash_map<ShaderRef, gx::ShaderConfig> g_gxCachedShaderConfigs;
#endif #endif
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) { static inline std::string_view chan_comp(GX::TevColorChan chan) noexcept {
switch (chan) {
case GX::CH_RED:
return "r";
case GX::CH_GREEN:
return "g";
case GX::CH_BLUE:
return "b";
case GX::CH_ALPHA:
return "a";
}
}
static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const ShaderConfig& config,
const TevStage& stage, ShaderInfo& info) {
switch (arg) { switch (arg) {
case GX::CC_CPREV: case GX::CC_CPREV:
return "prev.rgb"; return "prev.rgb";
@ -48,7 +62,9 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
unreachable(); unreachable();
} }
info.sampledTextures.set(stage.texMapId); info.sampledTextures.set(stage.texMapId);
return fmt::format(FMT_STRING("sampled{}.rgb"), stage.texMapId); const auto swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}{}{}"), stage.texMapId, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue));
} }
case GX::CC_TEXA: { case GX::CC_TEXA: {
if (stage.texMapId == GX::TEXMAP_NULL) { if (stage.texMapId == GX::TEXMAP_NULL) {
@ -59,7 +75,8 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
unreachable(); unreachable();
} }
info.sampledTextures.set(stage.texMapId); info.sampledTextures.set(stage.texMapId);
return fmt::format(FMT_STRING("sampled{}.a"), stage.texMapId); const auto swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha));
} }
case GX::CC_RASC: { case GX::CC_RASC: {
if (stage.channelId == GX::COLOR_NULL) { if (stage.channelId == GX::COLOR_NULL) {
@ -71,7 +88,9 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
} }
u32 idx = stage.channelId - GX::COLOR0A0; u32 idx = stage.channelId - GX::COLOR0A0;
info.sampledColorChannels.set(idx); info.sampledColorChannels.set(idx);
return fmt::format(FMT_STRING("rast{}.rgb"), idx); const auto swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}{}{}"), idx, chan_comp(swap.red), chan_comp(swap.green),
chan_comp(swap.blue));
} }
case GX::CC_RASA: { case GX::CC_RASA: {
if (stage.channelId == GX::COLOR_NULL) { if (stage.channelId == GX::COLOR_NULL) {
@ -83,7 +102,8 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
} }
u32 idx = stage.channelId - GX::COLOR0A0; u32 idx = stage.channelId - GX::COLOR0A0;
info.sampledColorChannels.set(idx); info.sampledColorChannels.set(idx);
return fmt::format(FMT_STRING("rast{}.a"), idx); const auto swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha));
} }
case GX::CC_ONE: case GX::CC_ONE:
return "1.0"; return "1.0";
@ -180,7 +200,8 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev
} }
} }
static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const TevStage& stage, ShaderInfo& info) { static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const ShaderConfig& config,
const TevStage& stage, ShaderInfo& info) {
switch (arg) { switch (arg) {
case GX::CA_APREV: case GX::CA_APREV:
return "prev.a"; return "prev.a";
@ -202,7 +223,8 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Tev
unreachable(); unreachable();
} }
info.sampledTextures.set(stage.texMapId); info.sampledTextures.set(stage.texMapId);
return fmt::format(FMT_STRING("sampled{}.a"), stage.texMapId); const auto swap = config.tevSwapTable[stage.tevSwapTex];
return fmt::format(FMT_STRING("sampled{}.{}"), stage.texMapId, chan_comp(swap.alpha));
} }
case GX::CA_RASA: { case GX::CA_RASA: {
if (stage.channelId == GX::COLOR_NULL) { if (stage.channelId == GX::COLOR_NULL) {
@ -214,7 +236,8 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Tev
} }
u32 idx = stage.channelId - GX::COLOR0A0; u32 idx = stage.channelId - GX::COLOR0A0;
info.sampledColorChannels.set(idx); info.sampledColorChannels.set(idx);
return fmt::format(FMT_STRING("rast{}.a"), idx); const auto swap = config.tevSwapTable[stage.tevSwapRas];
return fmt::format(FMT_STRING("rast{}.{}"), idx, chan_comp(swap.alpha));
} }
case GX::CA_KONST: { case GX::CA_KONST: {
switch (stage.kaSel) { switch (stage.kaSel) {
@ -337,14 +360,51 @@ static std::string_view tev_scale(GX::TevScale scale) {
} }
} }
static std::string in_uv(u32 idx) { static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) {
if (idx == 0) { const auto type = config.vtxAttrs[attr];
return "v_packed_uvs.data[in_uv_0_4_idx[0]]"; if (type == GX::NONE) {
if (attr == GX::VA_NRM) {
// Default normal
return "vec3<f32>(1.0, 0.0, 0.0)";
}
Log.report(logvisor::Fatal, FMT_STRING("unmapped attr {}"), attr);
unreachable();
} }
if (idx < 4) { if (attr == GX::VA_POS) {
return fmt::format(FMT_STRING("v_uvs.data[in_uv_0_4_idx[{}]]"), idx); if (type == GX::DIRECT) {
return "in_pos";
}
return "v_verts.data[in_pos_nrm_idx[0]].xyz";
} }
return fmt::format(FMT_STRING("v_uvs.data[in_uv_5_7_idx[{}]]"), idx - 4); if (attr == GX::VA_NRM) {
if (type == GX::DIRECT) {
return "in_nrm";
}
return "v_norms.data[in_pos_nrm_idx[1]].xyz";
}
if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) {
const auto idx = attr - GX::VA_CLR0;
if (type == GX::DIRECT) {
return fmt::format(FMT_STRING("in_clr{}"), idx);
}
Log.report(logvisor::Fatal, FMT_STRING("indexed color unsupported"));
unreachable();
}
if (attr >= GX::VA_TEX0 && attr <= GX::VA_TEX7) {
const auto idx = attr - GX::VA_TEX0;
if (type == GX::DIRECT) {
return fmt::format(FMT_STRING("in_tex{}_uv"), idx);
}
if (idx == 0) {
return "v_packed_uvs.data[in_uv_0_4_idx[0]]";
}
if (idx < 4) {
return fmt::format(FMT_STRING("v_uvs.data[in_uv_0_4_idx[{}]]"), idx);
}
return fmt::format(FMT_STRING("v_uvs.data[in_uv_5_7_idx[{}]]"), idx - 4);
}
Log.report(logvisor::Fatal, FMT_STRING("unhandled attr {}"), attr);
unreachable();
} }
std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& config) noexcept { std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& config) noexcept {
@ -409,7 +469,7 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
} }
} }
Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard.value_or(0.f)); Log.report(logvisor::Info, FMT_STRING(" alphaDiscard: {}"), config.alphaDiscard.value_or(0.f));
Log.report(logvisor::Info, FMT_STRING(" denormalizedVertexAttributes: {}"), config.denormalizedVertexAttributes); Log.report(logvisor::Info, FMT_STRING(" hasIndexedAttributes: {}"), config.hasIndexedAttributes);
Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType); Log.report(logvisor::Info, FMT_STRING(" fogType: {}"), config.fogType);
} }
@ -423,23 +483,14 @@ std::pair<wgpu::ShaderModule, ShaderInfo> build_shader(const ShaderConfig& confi
std::string vtxXfrAttrsPre; std::string vtxXfrAttrsPre;
std::string vtxXfrAttrs; std::string vtxXfrAttrs;
size_t locIdx = 0; size_t locIdx = 0;
if (config.denormalizedVertexAttributes) { size_t vtxOutIdx = 0;
vtxInAttrs += "\n @location(0) in_pos: vec3<f32>"; if (config.hasIndexedAttributes) {
vtxOutAttrs += "\n @builtin(position) pos: vec4<f32>;"; // Display list attributes
vtxXfrAttrsPre += vtxInAttrs +=
"\n var obj_pos = vec4<f32>(in_pos, 1.0);" "\n @location(0) in_pos_nrm_idx: vec2<i32>"
"\n var mv_pos = ubuf.mv * obj_pos;" "\n , @location(1) in_uv_0_4_idx: vec4<i32>"
"\n out.pos = ubuf.proj * mv_pos;"; "\n , @location(2) in_uv_5_7_idx: vec4<i32>";
if (config.denormalizedHasNrm) { locIdx += 3;
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);"
"\n var mv_norm = ubuf.mv_inv * obj_norm;";
info.usesNormal = true;
}
} else {
uniformBindings += R"""( uniformBindings += R"""(
struct Vec3Block { struct Vec3Block {
data: array<vec4<f32>>; data: array<vec4<f32>>;
@ -456,18 +507,33 @@ var<storage, read> v_uvs: Vec2Block;
@group(0) @binding(4) @group(0) @binding(4)
var<storage, read> v_packed_uvs: Vec2Block; var<storage, read> v_packed_uvs: Vec2Block;
)"""; )""";
vtxInAttrs +=
"\n @location(0) in_pos_nrm_idx: vec2<i32>"
"\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);"
"\n var obj_norm = vec4<f32>(v_norms.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;"
"\n out.pos = ubuf.proj * mv_pos;";
} }
for (GX::Attr attr{}; attr < MaxVtxAttr; attr = GX::Attr(attr + 1)) {
// Direct attributes
if (config.vtxAttrs[attr] != GX::DIRECT) {
continue;
}
if (locIdx > 0) {
vtxInAttrs += "\n , ";
} else {
vtxInAttrs += "\n ";
}
if (attr == GX::VA_POS) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_pos: vec3<f32>"), locIdx++);
} else if (attr == GX::VA_NRM) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_nrm: vec3<f32>"), locIdx++);
} else if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_clr{}: vec4<f32>"), locIdx++, attr - GX::VA_CLR0);
} else if (attr >= GX::VA_TEX0 && attr <= GX::VA_TEX7) {
vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_tex{}_uv: vec2<f32>"), locIdx++, attr - GX::VA_TEX0);
}
}
vtxXfrAttrsPre += fmt::format(FMT_STRING("\n var obj_pos = vec4<f32>({}, 1.0);"
"\n var obj_norm = vec4<f32>({}, 0.0);"
"\n var mv_pos = ubuf.mv * obj_pos;"
"\n var mv_norm = ubuf.mv_inv * obj_norm;"
"\n out.pos = ubuf.proj * mv_pos;"),
vtx_attr(config, GX::VA_POS), vtx_attr(config, GX::VA_NRM));
std::string fragmentFnPre; std::string fragmentFnPre;
std::string fragmentFn; std::string fragmentFn;
@ -478,7 +544,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
{ {
std::string outReg; std::string outReg;
switch (stage->colorOp.outReg) { switch (stage->colorOp.outReg) {
case GX::TevRegID::TEVPREV: case GX::TEVPREV:
outReg = "prev"; outReg = "prev";
break; break;
case GX::TEVREG0: case GX::TEVREG0:
@ -496,11 +562,13 @@ var<storage, read> v_packed_uvs: Vec2Block;
default: default:
Log.report(logvisor::Fatal, FMT_STRING("invalid colorOp outReg {}"), stage->colorOp.outReg); Log.report(logvisor::Fatal, FMT_STRING("invalid colorOp outReg {}"), stage->colorOp.outReg);
} }
std::string op = fmt::format( std::string op =
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), 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.a, idx, config, *stage, info),
color_arg_reg(stage->colorPass.c, idx, *stage, info), color_arg_reg(stage->colorPass.d, idx, *stage, info), color_arg_reg(stage->colorPass.b, idx, config, *stage, info),
tev_op(stage->colorOp.op), tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale)); color_arg_reg(stage->colorPass.c, idx, config, *stage, info),
color_arg_reg(stage->colorPass.d, idx, config, *stage, info), tev_op(stage->colorOp.op),
tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale));
if (stage->colorOp.clamp) { if (stage->colorOp.clamp) {
op = fmt::format(FMT_STRING("clamp(vec3<f32>({}), vec3<f32>(0.0), vec3<f32>(1.0))"), op); op = fmt::format(FMT_STRING("clamp(vec3<f32>({}), vec3<f32>(0.0), vec3<f32>(1.0))"), op);
} }
@ -509,7 +577,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
{ {
std::string outReg; std::string outReg;
switch (stage->alphaOp.outReg) { switch (stage->alphaOp.outReg) {
case GX::TevRegID::TEVPREV: case GX::TEVPREV:
outReg = "prev.a"; outReg = "prev.a";
break; break;
case GX::TEVREG0: case GX::TEVREG0:
@ -527,11 +595,13 @@ var<storage, read> v_packed_uvs: Vec2Block;
default: default:
Log.report(logvisor::Fatal, FMT_STRING("invalid alphaOp outReg {}"), stage->alphaOp.outReg); Log.report(logvisor::Fatal, FMT_STRING("invalid alphaOp outReg {}"), stage->alphaOp.outReg);
} }
std::string op = fmt::format( std::string op =
FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), 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.a, idx, config, *stage, info),
alpha_arg_reg(stage->alphaPass.c, idx, *stage, info), alpha_arg_reg(stage->alphaPass.d, idx, *stage, info), alpha_arg_reg(stage->alphaPass.b, idx, config, *stage, info),
tev_op(stage->alphaOp.op), tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale)); alpha_arg_reg(stage->alphaPass.c, idx, config, *stage, info),
alpha_arg_reg(stage->alphaPass.d, idx, config, *stage, info), tev_op(stage->alphaOp.op),
tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale));
if (stage->alphaOp.clamp) { if (stage->alphaOp.clamp) {
op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op); op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op);
} }
@ -557,11 +627,6 @@ var<storage, read> v_packed_uvs: Vec2Block;
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>;"), i);
info.uniformSize += 32; info.uniformSize += 32;
if (config.denormalizedVertexAttributes && !info.usesVtxColor) {
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4<f32>"), ++locIdx);
info.usesVtxColor = true;
}
if (config.colorChannels[i].lightingEnabled) { if (config.colorChannels[i].lightingEnabled) {
if (!addedLightStruct) { if (!addedLightStruct) {
uniformPre += uniformPre +=
@ -580,7 +645,7 @@ var<storage, read> v_packed_uvs: Vec2Block;
uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4<f32>;"), i);
info.uniformSize += (80 * GX::MaxLights) + 16; info.uniformSize += (80 * GX::MaxLights) + 16;
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx++, i); vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), vtxOutIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING(R"""( vtxXfrAttrs += fmt::format(FMT_STRING(R"""(
{{ {{
var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb; var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb;
@ -604,13 +669,9 @@ var<storage, read> v_packed_uvs: Vec2Block;
i, GX::MaxLights); i, GX::MaxLights);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else if (config.colorChannels[i].matSrc == GX::SRC_VTX) { } else if (config.colorChannels[i].matSrc == GX::SRC_VTX) {
if (config.denormalizedVertexAttributes) { vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), vtxOutIdx++, i);
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), locIdx - 1, i); vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = {};"), i, vtx_attr(config, GX::Attr(GX::VA_CLR0 + 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);
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"));
}
} else { } else {
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i);
} }
@ -628,23 +689,17 @@ var<storage, read> v_packed_uvs: Vec2Block;
continue; continue;
} }
const auto& tcg = config.tcgs[i]; const auto& tcg = config.tcgs[i];
if (config.denormalizedVertexAttributes) { vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>;"), vtxOutIdx++, i);
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>;"), locIdx, i); if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) {
vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_tex{}_uv: vec2<f32>"), locIdx + 1, i); vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>({}, 0.0, 1.0);"), i,
// TODO check tcg src for denorm? vtx_attr(config, GX::Attr(GX::VA_TEX0 + (tcg.src - GX::TG_TEX0))));
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0} = vec4<f32>(in_tex{0}_uv, 0.0, 1.0);"), i); } else if (tcg.src == GX::TG_POS) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_pos.xyz, 1.0);"), i);
} else if (tcg.src == GX::TG_NRM) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_norm.xyz, 1.0);"), i);
} else { } else {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>;"), locIdx, i); Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {}"), tcg.src);
if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) { unreachable();
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>({}, 0.0, 1.0);"), i, in_uv(tcg.src - GX::TG_TEX0));
} else if (tcg.src == GX::TG_POS) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_pos.xyz, 1.0);"), i);
} else if (tcg.src == GX::TG_NRM) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>(obj_norm.xyz, 1.0);"), i);
} else {
Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {}"), tcg.src);
unreachable();
}
} }
// TODO this all assumes MTX3x4 currently // TODO this all assumes MTX3x4 currently
if (tcg.mtx == GX::IDENTITY) { if (tcg.mtx == GX::IDENTITY) {
@ -663,12 +718,12 @@ var<storage, read> v_packed_uvs: Vec2Block;
} else { } else {
u32 postMtxIdx = (tcg.postMtx - GX::PTTEXMTX0) / 3; u32 postMtxIdx = (tcg.postMtx - GX::PTTEXMTX0) / 3;
info.usesPTTexMtx.set(postMtxIdx); info.usesPTTexMtx.set(postMtxIdx);
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = ubuf.postmtx{1} * vec4<f32>(tc{0}_tmp.xyz, 1.0);"), i, postMtxIdx); vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = ubuf.postmtx{1} * vec4<f32>(tc{0}_tmp.xyz, 1.0);"),
i, postMtxIdx);
} }
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i); vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i);
fragmentFnPre += fmt::format( fragmentFnPre += fmt::format(
FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i); FMT_STRING("\n var sampled{0} = textureSampleBias(tex{0}, tex{0}_samp, in.tex{0}_uv, ubuf.tex{0}_lod);"), i);
locIdx++;
} }
for (int i = 0; i < info.usesTexMtx.size(); ++i) { for (int i = 0; i < info.usesTexMtx.size(); ++i) {
if (!info.usesTexMtx.test(i)) { if (!info.usesTexMtx.test(i)) {
@ -698,7 +753,8 @@ var<storage, read> v_packed_uvs: Vec2Block;
if (config.fogType != GX::FOG_NONE) { if (config.fogType != GX::FOG_NONE) {
info.usesFog = true; info.usesFog = true;
uniformPre += "\n" uniformPre +=
"\n"
"struct Fog {\n" "struct Fog {\n"
" color: vec4<f32>;\n" " color: vec4<f32>;\n"
" a: f32;\n" " a: f32;\n"
@ -729,7 +785,8 @@ var<storage, read> v_packed_uvs: Vec2Block;
break; break;
case GX::FOG_PERSP_REVEXP2: case GX::FOG_PERSP_REVEXP2:
case GX::FOG_ORTHO_REVEXP2: case GX::FOG_ORTHO_REVEXP2:
fragmentFn += "\n fogF = 1.0 - fogF;" fragmentFn +=
"\n fogF = 1.0 - fogF;"
"\n var fogZ = exp2(-8.0 * fogF * fogF);"; "\n var fogZ = exp2(-8.0 * fogF * fogF);";
break; break;
default: default:
@ -767,7 +824,8 @@ struct Uniform {{
@group(0) @binding(0) @group(0) @binding(0)
var<uniform> ubuf: Uniform;{uniformBindings}{sampBindings}{texBindings} var<uniform> ubuf: Uniform;{uniformBindings}{sampBindings}{texBindings}
struct VertexOutput {{{vtxOutAttrs} struct VertexOutput {{
@builtin(position) pos: vec4<f32>;{vtxOutAttrs}
}}; }};
@stage(vertex) @stage(vertex)

View File

@ -5,47 +5,6 @@
#include <absl/container/flat_hash_map.h> #include <absl/container/flat_hash_map.h>
#include <aurora/model.hpp> #include <aurora/model.hpp>
#include <magic_enum.hpp>
enum class VtxDescAttr : u8 {
Position = 0,
Normal = 2,
Color0 = 4,
Color1 = 6,
Tex0 = 8,
Tex1 = 10,
Tex2 = 12,
Tex3 = 14,
Tex4 = 16,
Tex5 = 18,
Tex6 = 20,
PnMatIdx = 24,
Tex0MatIdx = 25,
Tex1MatIdx = 26,
Tex2MatIdx = 27,
Tex3MatIdx = 28,
Tex4MatIdx = 29,
Tex5MatIdx = 30,
Tex6MatIdx = 31,
};
enum class VtxDescAttrType : u8 { None = 0, Direct = 1, Index8 = 2, Index16 = 3 };
class VtxDescFlags {
u32 m_flags = 0;
public:
constexpr VtxDescFlags() noexcept = default;
constexpr VtxDescFlags(u32 flags) noexcept : m_flags(flags){};
[[nodiscard]] constexpr VtxDescAttrType GetAttributeType(VtxDescAttr attribute) const noexcept {
return VtxDescAttrType((m_flags >> u32(attribute)) & 0x3);
}
[[nodiscard]] constexpr VtxDescAttrType GetDirectAttributeType(VtxDescAttr attribute) const noexcept {
return VtxDescAttrType((m_flags >> u32(attribute)) & 0x1);
}
constexpr void SetAttributeType(VtxDescAttr attribute, VtxDescAttrType type) noexcept {
m_flags &= ~(u32(0x3) << u32(attribute));
m_flags |= u32(type) << u32(attribute);
}
};
namespace aurora::gfx::model { namespace aurora::gfx::model {
static logvisor::Module Log("aurora::gfx::model"); static logvisor::Module Log("aurora::gfx::model");
@ -59,53 +18,52 @@ static std::optional<Range> staticNrmRange;
static std::optional<Range> staticPackedTcRange; static std::optional<Range> staticPackedTcRange;
static std::optional<Range> staticTcRange; static std::optional<Range> staticTcRange;
enum class VertexFormat : u8 {
F32F32,
S16F32,
S16S16,
};
static VtxDescFlags sVtxDescFlags;
void set_vtx_desc_compressed(u32 vtxDesc) noexcept { sVtxDescFlags = vtxDesc; }
static inline std::pair<gx::DlVert, size_t> readVert(const u8* data) noexcept { static inline std::pair<gx::DlVert, size_t> readVert(const u8* data) noexcept {
gx::DlVert out{}; gx::DlVert out{};
size_t offset = 0; size_t offset = 0;
const auto read8 = [data, &offset](VtxDescAttrType type) -> s8 { const auto vtxTypes = gx::g_gxState.vtxDesc;
if (type == VtxDescAttrType::Direct) { const auto read8 = [/*data, &offset*/](GX::AttrType type) -> s8 {
s8 v = static_cast<s8>(data[offset]); // if (type == GX::INDEX8) {
++offset; // s8 v = static_cast<s8>(data[offset]);
return v; // ++offset;
// return v;
// }
#ifndef NDEBUG
if (type != GX::NONE) {
Log.report(logvisor::Fatal, FMT_STRING("unsupported vtx attr"));
unreachable();
} }
#endif
return 0; return 0;
}; };
const auto read16 = [data, &offset](VtxDescAttrType type) -> s16 { const auto read16 = [data, &offset](GX::AttrType type) -> s16 {
if (type == VtxDescAttrType::Index16) { if (type == GX::INDEX16) {
s16 v = metaforce::SBig(*reinterpret_cast<const u16*>(data + offset)); s16 v = metaforce::SBig(*reinterpret_cast<const u16*>(data + offset));
offset += 2; offset += 2;
return v; return v;
} }
return 0; return 0;
}; };
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::PnMatIdx)); read8(vtxTypes[GX::VA_PNMTXIDX]);
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex0MatIdx)); read8(vtxTypes[GX::VA_TEX0MTXIDX]);
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex1MatIdx)); read8(vtxTypes[GX::VA_TEX1MTXIDX]);
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex2MatIdx)); read8(vtxTypes[GX::VA_TEX2MTXIDX]);
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex3MatIdx)); read8(vtxTypes[GX::VA_TEX3MTXIDX]);
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex4MatIdx)); read8(vtxTypes[GX::VA_TEX4MTXIDX]);
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex5MatIdx)); read8(vtxTypes[GX::VA_TEX5MTXIDX]);
read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex6MatIdx)); read8(vtxTypes[GX::VA_TEX6MTXIDX]);
out.pos = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Position)); out.pos = read16(vtxTypes[GX::VA_POS]);
out.norm = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Normal)); out.norm = read16(vtxTypes[GX::VA_NRM]);
read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Color0)); read16(vtxTypes[GX::VA_CLR0]);
read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Color1)); read16(vtxTypes[GX::VA_CLR1]);
out.uvs[0] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex0)); out.uvs[0] = read16(vtxTypes[GX::VA_TEX0]);
out.uvs[1] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex1)); out.uvs[1] = read16(vtxTypes[GX::VA_TEX1]);
out.uvs[2] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex2)); out.uvs[2] = read16(vtxTypes[GX::VA_TEX2]);
out.uvs[3] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex3)); out.uvs[3] = read16(vtxTypes[GX::VA_TEX3]);
out.uvs[4] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex4)); out.uvs[4] = read16(vtxTypes[GX::VA_TEX4]);
out.uvs[5] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex5)); out.uvs[5] = read16(vtxTypes[GX::VA_TEX5]);
out.uvs[6] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex6)); out.uvs[6] = read16(vtxTypes[GX::VA_TEX6]);
return {out, offset}; return {out, offset};
} }
@ -130,7 +88,6 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept {
while (offset < dlSize - 6) { while (offset < dlSize - 6) {
const auto header = dlStart[offset]; const auto header = dlStart[offset];
const auto primitive = static_cast<GX::Primitive>(header & 0xF8); const auto primitive = static_cast<GX::Primitive>(header & 0xF8);
const auto vtxFmt = static_cast<VertexFormat>(header & 0x3);
const auto vtxCount = metaforce::SBig(*reinterpret_cast<const u16*>(dlStart + offset + 1)); const auto vtxCount = metaforce::SBig(*reinterpret_cast<const u16*>(dlStart + offset + 1));
offset += 3; offset += 3;

View File

@ -4,71 +4,138 @@
#include "common.hpp" #include "common.hpp"
#include "gx.hpp" #include "gx.hpp"
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::stream"); static logvisor::Module Log("aurora::gfx::stream");
using aurora::gfx::gx::g_gxState;
struct SStreamState { struct SStreamState {
GX::Primitive primitive; GX::Primitive primitive;
metaforce::EStreamFlags flags; u16 vertexCount = 0;
uint32_t vertexCount = 0; aurora::ByteBuffer vertexBuffer;
ByteBuffer vertexBuffer; std::vector<u16> indices;
#ifndef NDEBUG
GX::Attr currentAttr{};
#endif
explicit SStreamState(GX::Primitive primitive) noexcept : primitive(primitive) {} explicit SStreamState(GX::Primitive primitive, u16 numVerts, u16 vertexSize) noexcept : primitive(primitive) {
vertexBuffer.reserve_extra(size_t(numVerts) * vertexSize);
if (numVerts > 3 && (primitive == GX::TRIANGLEFAN || primitive == GX::TRIANGLESTRIP)) {
indices.reserve((u32(numVerts) - 3) * 3 + 3);
} else if (numVerts > 4 && primitive == GX::QUADS) {
indices.reserve(u32(numVerts) / 4 * 6);
} else {
indices.reserve(numVerts);
}
}
}; };
static std::optional<SStreamState> sStreamState; static std::optional<SStreamState> sStreamState;
void stream_begin(GX::Primitive primitive) noexcept { void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept {
#ifndef NDEBUG
if (sStreamState) { if (sStreamState) {
Log.report(logvisor::Fatal, FMT_STRING("Stream began twice!")); Log.report(logvisor::Fatal, FMT_STRING("Stream began twice!"));
unreachable(); unreachable();
} }
sStreamState.emplace(primitive); #endif
uint16_t vertexSize = 0;
for (GX::Attr attr{}; const auto type : g_gxState.vtxDesc) {
if (type == GX::DIRECT) {
if (attr == GX::VA_POS || attr == GX::VA_NRM) {
vertexSize += 12;
} else if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) {
vertexSize += 16;
} else if (attr >= GX::VA_TEX0 && attr <= GX::VA_TEX7) {
vertexSize += 8;
} else {
Log.report(logvisor::Fatal, FMT_STRING("don't know how to handle attr {}"), attr);
unreachable();
}
} else if (type != GX::NONE) {
Log.report(logvisor::Fatal, FMT_STRING("invalid vtx type {} for attr {}"), type, attr);
unreachable();
}
attr = GX::Attr(attr + 1);
}
if (vertexSize == 0) {
Log.report(logvisor::Fatal, FMT_STRING("no vtx attributes enabled?"));
unreachable();
}
sStreamState.emplace(primitive, nVerts, vertexSize);
} }
static inline void check_attr_order(GX::Attr attr) noexcept {
void stream_vertex(metaforce::EStreamFlags flags, const zeus::CVector3f& pos, const zeus::CVector3f& nrm, #ifndef NDEBUG
const zeus::CColor& color, const zeus::CVector2f& uv) noexcept {
if (!sStreamState) { if (!sStreamState) {
Log.report(logvisor::Fatal, FMT_STRING("Stream not started!")); Log.report(logvisor::Fatal, FMT_STRING("Stream not started!"));
unreachable(); unreachable();
} }
if (sStreamState->flags) { if (sStreamState->currentAttr >= attr) {
if (sStreamState->flags != flags) { Log.report(logvisor::Fatal, FMT_STRING("bad attribute order: {}, last {}"), attr, sStreamState->currentAttr);
Log.report(logvisor::Fatal, FMT_STRING("Stream changed flags?")); unreachable();
unreachable();
}
} else {
sStreamState->flags = flags;
} }
sStreamState->vertexBuffer.append(&pos, 12); sStreamState->currentAttr = attr;
if (flags & metaforce::EStreamFlagBits::fHasNormal) { #endif
sStreamState->vertexBuffer.append(&nrm, 12);
}
if (flags & metaforce::EStreamFlagBits::fHasColor) {
sStreamState->vertexBuffer.append(&color, 16);
}
if (flags & metaforce::EStreamFlagBits::fHasTexture) {
sStreamState->vertexBuffer.append(&uv, 8);
}
sStreamState->vertexCount++;
} }
void GXPosition3f32(const zeus::CVector3f& pos) noexcept {
void stream_end() noexcept { #ifndef NDEBUG
const auto vertRange = push_verts(sStreamState->vertexBuffer.data(), sStreamState->vertexBuffer.size()); if (!sStreamState) {
Log.report(logvisor::Fatal, FMT_STRING("Stream not started!"));
stream::PipelineConfig config{}; unreachable();
config.shaderConfig.denormalizedVertexAttributes = true; }
config.shaderConfig.denormalizedHasNrm = sStreamState->flags.IsSet(metaforce::EStreamFlagBits::fHasNormal); sStreamState->currentAttr = GX::VA_POS;
const auto info = populate_pipeline_config(config, sStreamState->primitive, {}); #endif
const auto pipeline = pipeline_ref(config); auto& state = *sStreamState;
state.vertexBuffer.append(&pos, 12);
push_draw_command(stream::DrawData{ if (state.primitive == GX::TRIANGLES || state.vertexCount < 3) {
state.indices.push_back(state.vertexCount);
} else if (state.primitive == GX::TRIANGLEFAN) {
state.indices.push_back(0);
state.indices.push_back(state.vertexCount - 1);
state.indices.push_back(state.vertexCount);
} else if (state.primitive == GX::TRIANGLESTRIP) {
if ((state.vertexCount & 1) == 0) {
state.indices.push_back(state.vertexCount - 2);
state.indices.push_back(state.vertexCount - 1);
} else {
state.indices.push_back(state.vertexCount - 1);
state.indices.push_back(state.vertexCount - 2);
}
state.indices.push_back(state.vertexCount);
} else if (state.primitive == GX::QUADS) {
if ((state.vertexCount & 3) == 3) {
state.indices.push_back(state.vertexCount - 1);
state.indices.push_back(state.vertexCount);
state.indices.push_back(state.vertexCount - 3);
} else {
state.indices.push_back(state.vertexCount);
}
}
++state.vertexCount;
}
void GXNormal3f32(const zeus::CVector3f& nrm) noexcept {
check_attr_order(GX::VA_NRM);
sStreamState->vertexBuffer.append(&nrm, 12);
}
void GXColor4f32(const zeus::CColor& color) noexcept {
check_attr_order(GX::VA_CLR0);
sStreamState->vertexBuffer.append(&color, 16);
}
void GXTexCoord2f32(const zeus::CVector2f& uv) noexcept {
check_attr_order(GX::VA_TEX0);
sStreamState->vertexBuffer.append(&uv, 8);
}
void GXEnd() noexcept {
const auto vertRange = aurora::gfx::push_verts(sStreamState->vertexBuffer.data(), sStreamState->vertexBuffer.size());
const auto indexRange = aurora::gfx::push_indices(aurora::ArrayRef{sStreamState->indices});
aurora::gfx::stream::PipelineConfig config{};
const auto info = populate_pipeline_config(config, GX::TRIANGLES, {});
const auto pipeline = aurora::gfx::pipeline_ref(config);
aurora::gfx::push_draw_command(aurora::gfx::stream::DrawData{
.pipeline = pipeline, .pipeline = pipeline,
.vertRange = vertRange, .vertRange = vertRange,
.uniformRange = build_uniform(info), .uniformRange = build_uniform(info),
.vertexCount = sStreamState->vertexCount, .indexRange = indexRange,
.indexCount = static_cast<uint32_t>(sStreamState->indices.size()),
.bindGroups = info.bindGroups, .bindGroups = info.bindGroups,
}); });
sStreamState.reset(); sStreamState.reset();
} }
} // namespace aurora::gfx

View File

@ -22,7 +22,7 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli
}; };
uint64_t offset = 12; uint64_t offset = 12;
uint32_t shaderLocation = 1; uint32_t shaderLocation = 1;
if (info.usesNormal) { if (config.shaderConfig.vtxAttrs[GX::VA_NRM] == GX::DIRECT) {
attributes[shaderLocation] = wgpu::VertexAttribute{ attributes[shaderLocation] = wgpu::VertexAttribute{
.format = wgpu::VertexFormat::Float32x3, .format = wgpu::VertexFormat::Float32x3,
.offset = offset, .offset = offset,
@ -31,7 +31,7 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli
offset += 12; offset += 12;
shaderLocation++; shaderLocation++;
} }
if (info.usesVtxColor) { if (config.shaderConfig.vtxAttrs[GX::VA_CLR0] == GX::DIRECT) {
attributes[shaderLocation] = wgpu::VertexAttribute{ attributes[shaderLocation] = wgpu::VertexAttribute{
.format = wgpu::VertexFormat::Float32x4, .format = wgpu::VertexFormat::Float32x4,
.offset = offset, .offset = offset,
@ -40,9 +40,8 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli
offset += 16; offset += 16;
shaderLocation++; shaderLocation++;
} }
// TODO only sample 1? for (int i = GX::VA_TEX0; i < GX::VA_TEX7; ++i) {
for (int i = 0; i < info.sampledTextures.size(); ++i) { if (config.shaderConfig.vtxAttrs[i] != GX::DIRECT) {
if (!info.sampledTextures.test(i)) {
continue; continue;
} }
attributes[shaderLocation] = wgpu::VertexAttribute{ attributes[shaderLocation] = wgpu::VertexAttribute{
@ -76,6 +75,7 @@ void render(const State& state, const DrawData& data, const wgpu::RenderPassEnco
pass.SetBindGroup(2, find_bind_group(data.bindGroups.textureBindGroup)); pass.SetBindGroup(2, find_bind_group(data.bindGroups.textureBindGroup));
} }
pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size); pass.SetVertexBuffer(0, g_vertexBuffer, data.vertRange.offset, data.vertRange.size);
pass.Draw(data.vertexCount); pass.SetIndexBuffer(g_indexBuffer, wgpu::IndexFormat::Uint16, data.indexRange.offset, data.indexRange.size);
pass.DrawIndexed(data.indexCount);
} }
} // namespace aurora::gfx::stream } // namespace aurora::gfx::stream

View File

@ -8,7 +8,8 @@ struct DrawData {
PipelineRef pipeline; PipelineRef pipeline;
Range vertRange; Range vertRange;
Range uniformRange; Range uniformRange;
uint32_t vertexCount; Range indexRange;
uint32_t indexCount;
gx::GXBindGroups bindGroups; gx::GXBindGroups bindGroups;
}; };