diff --git a/Runtime/Graphics/CCubeRenderer.cpp b/Runtime/Graphics/CCubeRenderer.cpp index ac7cb7087..eb933a373 100644 --- a/Runtime/Graphics/CCubeRenderer.cpp +++ b/Runtime/Graphics/CCubeRenderer.cpp @@ -813,9 +813,7 @@ void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& co // TODO } -void CCubeRenderer::SetThermalColdScale(float scale) { - // TODO -} +void CCubeRenderer::SetThermalColdScale(float scale) { x2f8_thermColdScale = zeus::clamp(0.f, scale, 1.f); } void CCubeRenderer::DoThermalBlendCold() { // TODO diff --git a/Runtime/Graphics/CGX.cpp b/Runtime/Graphics/CGX.cpp index d1a9b73e0..eb4283efd 100644 --- a/Runtime/Graphics/CGX.cpp +++ b/Runtime/Graphics/CGX.cpp @@ -3,11 +3,12 @@ #include "Graphics/CTexture.hpp" namespace metaforce::CGX { -SGXState sGXState; +SGXState sGXState{}; +std::array sVtxDescList{}; void ResetGXStates() noexcept { - sGXState.x48_descList = nullptr; - // GXClearVtxDesc(); + sGXState.x48_descList = 0; + GXClearVtxDesc(); sGXState.x0_arrayPtrs.fill(nullptr); for (GX::TexMapID id = GX::TEXMAP0; id < GX::MAX_TEXMAP; id = static_cast(id + 1)) { CTexture::InvalidateTexMap(id); @@ -16,7 +17,9 @@ void ResetGXStates() noexcept { GXSetTevKColor(id, item); id = static_cast(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); // GXSetCurrentMtx(0); SetNumIndStages(0); diff --git a/Runtime/Graphics/CGX.hpp b/Runtime/Graphics/CGX.hpp index 6e8b39674..b21ef7a4e 100644 --- a/Runtime/Graphics/CGX.hpp +++ b/Runtime/Graphics/CGX.hpp @@ -31,7 +31,7 @@ struct SGXState { std::array x34_chanCtrls{0x4000, 0x4000}; std::array x38_chanAmbColors; std::array x40_chanMatColors; - GX::VtxDescList* x48_descList = nullptr; + u32 x48_descList = 0; u8 x4c_dirtyChans = 0; u8 x4d_prevNumChans = 0; u8 x4e_numChans = 0; @@ -53,6 +53,7 @@ struct SGXState { GXColor x25c_fogColor; }; extern SGXState sGXState; +extern std::array sVtxDescList; static inline void update_fog(u32 value) noexcept { 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) { 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 { if (sGXState.x4c_dirtyChans != 0) { FlushState(); @@ -102,10 +105,6 @@ static inline void CallDisplayList(const void* data, u32 nbytes) noexcept { GXCallDisplayList(data, nbytes); } -static inline void End() noexcept { - // no-op -} - static inline const GXColor& GetChanAmbColor(EChannelId id) noexcept { const auto idx = std::underlying_type_t(id); 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 { - // TODO convert to GX::VtxDescList - aurora::gfx::model::set_vtx_desc_compressed(descList); + u32 currentDescList = sGXState.x48_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 { diff --git a/Runtime/Graphics/CGraphics.cpp b/Runtime/Graphics/CGraphics.cpp index 5383dd5ac..d1a5c4a67 100644 --- a/Runtime/Graphics/CGraphics.cpp +++ b/Runtime/Graphics/CGraphics.cpp @@ -59,9 +59,16 @@ const std::array CGraphics::skCubeBasisMats{{ // Stream API static EStreamFlags sStreamFlags; -static zeus::CColor sQueuedColor; -static zeus::CVector2f sQueuedTexCoord; -static zeus::CVector3f sQueuedNormal; +static GX::Primitive sStreamPrimitive; +static u32 sVerticesCount; +// Originally writes directly to GX FIFO +struct StreamVertex { + zeus::CColor color; + zeus::CVector2f texCoord; + zeus::CVector3f normal; + zeus::CVector3f vertex; +}; +static std::vector sQueuedVertices; void CGraphics::DisableAllLights() { g_LightActive.reset(); @@ -518,55 +525,102 @@ void CGraphics::SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass } void CGraphics::StreamBegin(GX::Primitive primitive) { - sStreamFlags = {}; - aurora::gfx::stream_begin(primitive); + // Originally ResetVertexDataStream(true); + sQueuedVertices.clear(); + sQueuedVertices.emplace_back(); + sVerticesCount = 0; + // End + sStreamFlags = EStreamFlagBits::fHasColor; + sStreamPrimitive = primitive; } void CGraphics::StreamNormal(const zeus::CVector3f& nrm) { - sQueuedNormal = nrm; + sQueuedVertices.back().normal = nrm; 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) { - sQueuedColor = color; + sQueuedVertices.back().color = color; sStreamFlags |= EStreamFlagBits::fHasColor; } -void CGraphics::StreamTexcoord(float x, float y) { - sQueuedTexCoord = {x, y}; - sStreamFlags |= EStreamFlagBits::fHasTexture; -} - void CGraphics::StreamTexcoord(const zeus::CVector2f& uv) { - sQueuedTexCoord = uv; + sQueuedVertices.back().texCoord = uv; 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) { - aurora::gfx::stream_vertex(sStreamFlags, pos, sQueuedNormal, sQueuedColor, sQueuedTexCoord); + sQueuedVertices.back().vertex = pos; + UpdateVertexDataStream(); } void CGraphics::StreamEnd() { - SetTevStates(sStreamFlags); - aurora::gfx::stream_end(); + if (sVerticesCount != 0) { + FlushStream(); + } sStreamFlags = {}; } +void CGraphics::UpdateVertexDataStream() { + ++sVerticesCount; + if (sVerticesCount == 240) { + FlushStream(); + ResetVertexDataStream(false); + } else { + sQueuedVertices.emplace_back(sQueuedVertices.back()); + } +} + +void CGraphics::FlushStream() { + std::array 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, const zeus::CColor& col, s32 numVerts) { StreamBegin(primitive); @@ -580,12 +634,12 @@ void CGraphics::DrawPrimitive(GX::Primitive primitive, const zeus::CVector3f* po void CGraphics::SetTevStates(EStreamFlags flags) noexcept { if (flags & EStreamFlagBits::fHasTexture) { - CGX::SetNumTexGens(0); - CGX::SetNumTevStages(1); + CGX::SetNumTexGens(1); // sTextureUsed & 3? CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR0A0); CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD1, GX::TEXMAP1, GX::COLOR0A0); - } else /* if (flags < 8) ? */ { - CGX::SetNumTexGens(2); // sTextureUsed & 3? + } else { + CGX::SetNumTexGens(0); + CGX::SetNumTevStages(1); CGX::SetTevOrder(GX::TEVSTAGE0, 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); 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 diff --git a/Runtime/Graphics/CGraphics.hpp b/Runtime/Graphics/CGraphics.hpp index f8542080e..fb2fe0203 100644 --- a/Runtime/Graphics/CGraphics.hpp +++ b/Runtime/Graphics/CGraphics.hpp @@ -205,6 +205,10 @@ public: static ERglEnum g_depthFunc; static ERglCullMode g_cullMode; + static void Startup(); + static void InitGraphicsVariables(); + static void InitGraphicsDefaults(); + static void SetDefaultVtxAttrFmt(); static void DisableAllLights(); static void LoadLight(ERglLight light, const CLight& info); static void EnableLight(ERglLight light); @@ -353,14 +357,18 @@ public: static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass); static void StreamBegin(GX::Primitive primitive); 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 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 StreamVertex(float xyz); - static void StreamVertex(float x, float y, float z); + static inline void StreamTexcoord(float x, float y) { StreamTexcoord({x, y}); } 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 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, const zeus::CColor& col, s32 numVerts); }; diff --git a/Runtime/Graphics/GX.hpp b/Runtime/Graphics/GX.hpp index 4c39cb9b2..1087407d5 100644 --- a/Runtime/Graphics/GX.hpp +++ b/Runtime/Graphics/GX.hpp @@ -49,8 +49,9 @@ enum AttrType { }; struct VtxDescList { - Attr attr; - AttrType type; + Attr attr = GX::VA_NULL; + AttrType type = GX::NONE; + operator bool() const { return attr != GX::VA_NULL; } }; enum VtxFmt { @@ -665,6 +666,32 @@ enum ProjectionType { 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 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; // Originally u8 instead of floats 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 GXClearVtxDesc() 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 GXSetViewport(float left, float top, float width, float height, float nearZ, float farZ) noexcept; void GXSetScissor(u32 left, u32 top, u32 width, u32 height) noexcept; +// Unneeded, all attributes are expected to be full floats +// void GXSetVtxAttrFmt(GX::VtxFmt vtxfmt, GX::Attr attr, GX::CompCnt cnt, GX::CompType type, u8 frac) noexcept; +// 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; diff --git a/Runtime/Particle/CDecal.cpp b/Runtime/Particle/CDecal.cpp index cfa910262..012b62991 100644 --- a/Runtime/Particle/CDecal.cpp +++ b/Runtime/Particle/CDecal.cpp @@ -87,8 +87,8 @@ void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const { modXf.origin += offset; CGraphics::SetModelMatrix(modXf); - SParticleUniforms uniformData = { - CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}}; +// SParticleUniforms uniformData = { +// CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}}; // decal.m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); bool redToAlpha = sMoveRedToAlphaBuffer && desc.x18_ADD && desc.x14_TEX; @@ -104,52 +104,52 @@ void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const { // else // CGraphics::SetShaderDataBinding(decal.m_normalDataBind); - g_instTexData.clear(); - g_instTexData.reserve(1); +// g_instTexData.clear(); +// g_instTexData.reserve(1); - SParticleInstanceTex& inst = g_instTexData.emplace_back(); - if (decal.x8_rotation == 0.f) { - inst.pos[0] = 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[3] = zeus::CVector3f(size, 0.001f, -size); - } else { - float ang = zeus::degToRad(decal.x8_rotation); - float sinSize = std::sin(ang) * size; - float cosSize = std::cos(ang) * size; - inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 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[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize); - } - inst.color = color; - inst.uvs[0] = zeus::CVector2f(uvSet.xMin, uvSet.yMin); - inst.uvs[1] = zeus::CVector2f(uvSet.xMax, uvSet.yMin); - inst.uvs[2] = zeus::CVector2f(uvSet.xMin, uvSet.yMax); - inst.uvs[3] = zeus::CVector2f(uvSet.xMax, uvSet.yMax); +// SParticleInstanceTex& inst = g_instTexData.emplace_back(); +// if (decal.x8_rotation == 0.f) { +// inst.pos[0] = 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[3] = zeus::CVector3f(size, 0.001f, -size); +// } else { +// float ang = zeus::degToRad(decal.x8_rotation); +// float sinSize = std::sin(ang) * size; +// float cosSize = std::cos(ang) * size; +// inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 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[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize); +// } +// inst.color = color; +// inst.uvs[0] = zeus::CVector2f(uvSet.xMin, uvSet.yMin); +// inst.uvs[1] = zeus::CVector2f(uvSet.xMax, uvSet.yMin); +// inst.uvs[2] = zeus::CVector2f(uvSet.xMin, uvSet.yMax); +// inst.uvs[3] = zeus::CVector2f(uvSet.xMax, uvSet.yMax); // decal.m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); // CGraphics::DrawInstances(0, 4, g_instTexData.size()); } else { - g_instNoTexData.clear(); - g_instNoTexData.reserve(1); +// g_instNoTexData.clear(); +// g_instNoTexData.reserve(1); - SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); - if (decal.x8_rotation == 0.f) { - inst.pos[0] = 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[3] = zeus::CVector3f(size, 0.001f, -size); - } else { - float ang = zeus::degToRad(decal.x8_rotation); - float sinSize = std::sin(ang) * size; - float cosSize = std::cos(ang) * size; - inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 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[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize); - } - inst.color = color; +// SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); +// if (decal.x8_rotation == 0.f) { +// inst.pos[0] = 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[3] = zeus::CVector3f(size, 0.001f, -size); +// } else { +// float ang = zeus::degToRad(decal.x8_rotation); +// float sinSize = std::sin(ang) * size; +// float cosSize = std::cos(ang) * size; +// inst.pos[0] = zeus::CVector3f(sinSize - cosSize, 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[3] = zeus::CVector3f(-sinSize + cosSize, 0.001f, -cosSize - sinSize); +// } +// inst.color = color; // decal.m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); // CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); diff --git a/Runtime/Particle/CElementGen.cpp b/Runtime/Particle/CElementGen.cpp index bd2c4c149..471ecb38a 100644 --- a/Runtime/Particle/CElementGen.cpp +++ b/Runtime/Particle/CElementGen.cpp @@ -3,6 +3,7 @@ #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/Character/CActorLights.hpp" #include "Runtime/Graphics/CCubeRenderer.hpp" +#include "Runtime/Graphics/CGX.hpp" #include "Runtime/Graphics/CModel.hpp" #include "Runtime/Graphics/Shaders/CElementGenShaders.hpp" #include "Runtime/Particle/CElectricDescription.hpp" @@ -19,11 +20,11 @@ namespace metaforce { namespace { logvisor::Module Log("metaforce::CElementGen"); -constexpr std::array ShadClsSizes{ - sizeof(SParticleInstanceTex), - sizeof(SParticleInstanceIndTex), - sizeof(SParticleInstanceNoTex), -}; +// constexpr std::array ShadClsSizes{ +// sizeof(SParticleInstanceTex), +// sizeof(SParticleInstanceIndTex), +// sizeof(SParticleInstanceNoTex), +// }; } // Anonymous namespace u16 CElementGen::g_GlobalSeed = 99; @@ -35,9 +36,9 @@ bool CElementGen::g_ParticleSystemInitialized = false; bool CElementGen::sMoveRedToAlphaBuffer = false; CParticle* CElementGen::g_currentParticle = nullptr; -std::vector g_instTexData; -std::vector g_instIndTexData; -std::vector g_instNoTexData; +// std::vector g_instTexData; +// std::vector g_instIndTexData; +// std::vector g_instNoTexData; void CElementGen::Initialize() { if (g_ParticleSystemInitialized) @@ -210,21 +211,21 @@ CElementGen::CElementGen(TToken gen, EModelOrientationType orie if (x26c_31_LINE) { CUVElement* texr = desc->x54_x40_TEXR.get(); // TODO -// aurora::gfx::TextureHandle tex; -// if (texr) -// tex = texr->GetValueTexture(0).GetObj()->GetTexture(); + // aurora::gfx::TextureHandle tex; + // if (texr) + // tex = texr->GetValueTexture(0).GetObj()->GetTexture(); int maxVerts = x90_MAXP; -// m_lineRenderer.reset( -// new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, tex, x26c_26_AAPH, x26c_28_zTest)); + // m_lineRenderer.reset( + // new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, tex, x26c_26_AAPH, x26c_28_zTest)); } else { m_shaderClass = CElementGenShaders::GetShaderClass(*this); } _RecreatePipelines(); -// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { -// CElementGenShaders::BuildShaderDataBinding(ctx, *this); -// return true; -// } BooTrace); + // CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { + // CElementGenShaders::BuildShaderDataBinding(ctx, *this); + // return true; + // } BooTrace); } 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; maxInsts = (maxInsts == 0 ? 256 : maxInsts); -// CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { -// if (!x26c_31_LINE) { -// m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts); -// m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1); -// } -// if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { -// m_instBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts); -// m_uniformBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1); -// } -// return true; -// } BooTrace); + // CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) { + // if (!x26c_31_LINE) { + // m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts); + // m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1); + // } + // if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { + // m_instBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[size_t(m_shaderClass)], maxInsts); + // m_uniformBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1); + // } + // return true; + // } BooTrace); } bool CElementGen::InternalUpdate(double dt) { @@ -838,12 +839,12 @@ u32 CElementGen::GetSystemCount() const { void CElementGen::Render(const CActorLights* actorLights) { // Check to make sure our buffers are ready to render - if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf) - return; - } - if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus) - return; - } + // if (!x26c_31_LINE) { + // return; + // } + // if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus) + // return; + // } SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CElementGen::Render {}"), *x1c_genDesc.GetObjectTag()).c_str(), zeus::skYellow); @@ -876,16 +877,19 @@ void CElementGen::Render(const CActorLights* actorLights) { void CElementGen::RenderModels(const CActorLights* actorLights) { // Check to make sure our buffers are ready to render - if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf) - return; - } - if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus) - return; - } + // if (!x26c_31_LINE) { // && (!m_instBuf || !m_uniformBuf) + // return; + // } + // if (x28_loadedGenDesc->x45_24_x31_26_PMUS) { // && (!m_instBufPmus || !m_uniformBufPmus) + // return; + // } CParticleGlobals::instance()->m_particleAccessParameters = nullptr; - if (x26d_26_modelsUseLights) + if (x26d_26_modelsUseLights) { CGraphics::SetLightState(x274_backupLightActive); + } else { + CGraphics::SetAmbientColor(zeus::skWhite); + } CGlobalRandom gr(x27c_randState); CGenDescription* desc = x1c_genDesc.GetObj(); @@ -897,20 +901,24 @@ void CElementGen::RenderModels(const CActorLights* actorLights) { bool moveRedToAlphaBuffer = false; 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; + } if (desc->x44_31_x31_25_PMAB) { CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false); - if (moveRedToAlphaBuffer) + if (moveRedToAlphaBuffer) { CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear); - else + } else { CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, ERglLogicOp::Clear); + CGraphics::SetAlphaCompare(ERglAlphaFunc::Greater, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); + } } else { CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true); CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, ERglLogicOp::Clear); + CGraphics::SetAlphaCompare(ERglAlphaFunc::Greater, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); } CGraphics::SetCullMode(ERglCullMode::None); @@ -920,37 +928,60 @@ void CElementGen::RenderModels(const CActorLights* actorLights) { int partFrame = x74_curFrame - target.x28_startFrame; cachedTex = texr->GetValueTexture(partFrame).GetObj(); cachedTex->Load(GX::TEXMAP0, EClampMode::Repeat); - /* Shade as TEXC * RASC and TEXA * RASA */ + + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc); if (moveRedToAlphaBuffer) { - /* Color = Prev.rgb * Prev.a */ - /* Alpha = Tex.r * Prev.a */ + CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_CPREV, GX::CC_APREV, GX::CC_ZERO); + 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(); texr->GetValueUV(partFrame, uvs); + } else { + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::skPassThru); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); } - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: - g_instTexData.clear(); - g_instTexData.reserve(x30_particles.size()); - break; - case CElementGenShaders::EShaderClass::NoTex: - g_instNoTexData.clear(); - g_instNoTexData.reserve(x30_particles.size()); - break; - default: - Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); - break; - } + // switch (m_shaderClass) { + // case CElementGenShaders::EShaderClass::Tex: + // g_instTexData.clear(); + // g_instTexData.reserve(x30_particles.size()); + // break; + // case CElementGenShaders::EShaderClass::NoTex: + // g_instNoTexData.clear(); + // g_instNoTexData.reserve(x30_particles.size()); + // break; + // default: + // Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); + // 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)); -// -// if (moveRedToAlphaBuffer) -// CGraphics::SetShaderDataBinding(m_redToAlphaDataBindPmus[g_Renderer->IsThermalVisorHotPass()]); -// else -// CGraphics::SetShaderDataBinding(m_normalDataBindPmus[g_Renderer->IsThermalVisorHotPass()]); + // m_uniformBufPmus->load(&uniformData, sizeof(SParticleUniforms)); + // + // if (moveRedToAlphaBuffer) + // CGraphics::SetShaderDataBinding(m_redToAlphaDataBindPmus[g_Renderer->IsThermalVisorHotPass()]); + // else + // CGraphics::SetShaderDataBinding(m_normalDataBindPmus[g_Renderer->IsThermalVisorHotPass()]); } zeus::CTransform orient = zeus::CTransform(); @@ -1041,54 +1072,44 @@ void CElementGen::RenderModels(const CActorLights* actorLights) { CGraphics::SetModelMatrix((x10c_globalScaleTransform * partTrans) * x178_localScaleTransform); if (desc->x45_24_x31_26_PMUS) { - if (!texConst) { - CTexture* tex = texr->GetValueTexture(x74_curFrame - particle.x28_startFrame).GetObj(); - if (tex != cachedTex) { - tex->Load(GX::TEXMAP0, EClampMode::Repeat); - cachedTex = tex; - } - } - - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: { - SParticleInstanceTex& inst = g_instTexData.emplace_back(); - inst.pos[0] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, 0.5f}; - inst.pos[1] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, 0.5f}; - inst.pos[2] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, -0.5f}; - inst.pos[3] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, -0.5f}; - inst.color = col; - inst.uvs[0] = {uvs.xMax, uvs.yMax}; - inst.uvs[1] = {uvs.xMin, uvs.yMax}; - inst.uvs[2] = {uvs.xMax, uvs.yMin}; - inst.uvs[3] = {uvs.xMin, uvs.yMin}; - break; - } - case CElementGenShaders::EShaderClass::NoTex: { - SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); - inst.pos[0] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, 0.5f}; - inst.pos[1] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, 0.5f}; - inst.pos[2] = CGraphics::g_GXModelView * zeus::CVector3f{0.5f, 0.f, -0.5f}; - inst.pos[3] = CGraphics::g_GXModelView * zeus::CVector3f{-0.5f, 0.f, -0.5f}; - inst.color = col; - break; - } - default: - break; + if (moveRedToAlphaBuffer) { + CGX::Begin(GX::QUADS, GX::VTXFMT0, 4); + GXPosition3f32(0.5f, 0.f, 0.5f); + GXColor4f32(col); + GXTexCoord2f32(uvs.xMax, uvs.yMax); + GXPosition3f32(-0.5f, 0.f, 0.5f); + GXColor4f32(col); + GXTexCoord2f32(uvs.xMin, uvs.yMax); + GXPosition3f32(-0.5f, 0.f, -0.5f); + GXColor4f32(col); + GXTexCoord2f32(uvs.xMin, uvs.yMin); + GXPosition3f32(0.5f, 0.f, -0.5f); + GXColor4f32(col); + GXTexCoord2f32(uvs.xMax, uvs.yMin); + CGX::End(); + } else { + CGraphics::StreamBegin(GX::QUADS); + CGraphics::StreamColor(col); + CGraphics::StreamTexcoord(uvs.xMax, uvs.yMax); + CGraphics::StreamVertex(0.5f, 0.f, 0.5f); + CGraphics::StreamTexcoord(uvs.xMin, uvs.yMax); + CGraphics::StreamVertex(-0.5f, 0.f, 0.5f); + CGraphics::StreamTexcoord(uvs.xMin, uvs.yMin); + CGraphics::StreamVertex(-0.5f, 0.f, -0.5f); + CGraphics::StreamTexcoord(uvs.xMax, uvs.yMin); + CGraphics::StreamVertex(0.5f, 0.f, -0.5f); + CGraphics::StreamEnd(); } } else { CModel* model = desc->x5c_x48_PMDL.GetObj(); - if (actorLights) - actorLights->ActivateLights(); 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) { - CModelFlags flags{7, 0, 1, col}; - // flags.m_extendedShader = EExtendedShader::ForcedAdditiveNoZWrite; - model->Draw(flags); + model->Draw({7, 0, 1, col}); } else if (1.f == col.a()) { model->Draw({0, 0, 3, zeus::skWhite}); } 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; } - if (desc->x45_24_x31_26_PMUS) { - 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) + if (x26d_26_modelsUseLights) { CGraphics::DisableAllLights(); + } CGraphics::SetCullMode(ERglCullMode::Front); 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() { @@ -1258,8 +1266,9 @@ void CElementGen::RenderParticles() { bool constUVs = true; CTexture* cachedTex = nullptr; - SParticleUniforms uniformData = { - CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}}; +// SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * +// CGraphics::g_GXModelView.toMatrix4f(), +// {1.f, 1.f, 1.f, 1.f}}; if (texr) { CParticle& target = x30_particles[0]; @@ -1269,14 +1278,14 @@ void CElementGen::RenderParticles() { if (x338_moduColor != zeus::skBlack) { /* Add RASC * PREVC pass for MODU color loaded into channel mat-color */ - uniformData.moduColor = x338_moduColor; +// uniformData.moduColor = x338_moduColor; } texr->GetValueUV(partFrame, uvs); constUVs = texr->HasConstantUV(); } -// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); + // m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); std::vector sortItems; if (desc->x44_28_x30_28_SORT) { @@ -1301,15 +1310,15 @@ void CElementGen::RenderParticles() { if (g_subtractBlend) { // FIXME should there be NoTex specializations for RedToAlpha? -// if (moveRedToAlphaBuffer && desc->x54_x40_TEXR) -// CGraphics::SetShaderDataBinding(m_redToAlphaSubDataBind[g_Renderer->IsThermalVisorHotPass()]); -// else -// CGraphics::SetShaderDataBinding(m_normalSubDataBind[g_Renderer->IsThermalVisorHotPass()]); + // if (moveRedToAlphaBuffer && desc->x54_x40_TEXR) + // CGraphics::SetShaderDataBinding(m_redToAlphaSubDataBind[g_Renderer->IsThermalVisorHotPass()]); + // else + // CGraphics::SetShaderDataBinding(m_normalSubDataBind[g_Renderer->IsThermalVisorHotPass()]); } else { -// if (moveRedToAlphaBuffer && desc->x54_x40_TEXR) -// CGraphics::SetShaderDataBinding(m_redToAlphaDataBind[g_Renderer->IsThermalVisorHotPass()]); -// else -// CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]); + // if (moveRedToAlphaBuffer && desc->x54_x40_TEXR) + // CGraphics::SetShaderDataBinding(m_redToAlphaDataBind[g_Renderer->IsThermalVisorHotPass()]); + // else + // CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]); } int mbspVal = std::max(1, x270_MBSP); @@ -1344,19 +1353,19 @@ void CElementGen::RenderParticles() { } #endif - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: - g_instTexData.clear(); - g_instTexData.reserve(x30_particles.size()); - break; - case CElementGenShaders::EShaderClass::NoTex: - g_instNoTexData.clear(); - g_instNoTexData.reserve(x30_particles.size()); - break; - default: - Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); - break; - } +// switch (m_shaderClass) { +// case CElementGenShaders::EShaderClass::Tex: +// g_instTexData.clear(); +// g_instTexData.reserve(x30_particles.size()); +// break; +// case CElementGenShaders::EShaderClass::NoTex: +// g_instNoTexData.clear(); +// g_instNoTexData.reserve(x30_particles.size()); +// break; +// default: +// Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); +// break; +// } if (!x26c_29_ORNT) { 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; if (0.f == particle.x30_lineWidthOrRota) { - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: { - SParticleInstanceTex& inst = g_instTexData.emplace_back(); - 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[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.color = particle.x34_color; - inst.uvs[0] = {uvs.xMax, uvs.yMax}; - inst.uvs[1] = {uvs.xMin, uvs.yMax}; - inst.uvs[2] = {uvs.xMax, uvs.yMin}; - inst.uvs[3] = {uvs.xMin, uvs.yMin}; - break; - } - case CElementGenShaders::EShaderClass::NoTex: { - SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); - 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[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.color = particle.x34_color; - break; - } - default: - break; - } +// switch (m_shaderClass) { +// case CElementGenShaders::EShaderClass::Tex: { +// SParticleInstanceTex& inst = g_instTexData.emplace_back(); +// 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[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.color = particle.x34_color; +// inst.uvs[0] = {uvs.xMax, uvs.yMax}; +// inst.uvs[1] = {uvs.xMin, uvs.yMax}; +// inst.uvs[2] = {uvs.xMax, uvs.yMin}; +// inst.uvs[3] = {uvs.xMin, uvs.yMin}; +// break; +// } +// case CElementGenShaders::EShaderClass::NoTex: { +// SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); +// 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[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.color = particle.x34_color; +// break; +// } +// default: +// break; +// } } else { float theta = zeus::degToRad(particle.x30_lineWidthOrRota); float sinT = std::sin(theta) * size; float cosT = std::cos(theta) * size; - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: { - 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[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f}; - inst.pos[2] = - zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f}; - inst.pos[3] = - zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f}; - inst.color = particle.x34_color; - inst.uvs[0] = {uvs.xMax, uvs.yMax}; - inst.uvs[1] = {uvs.xMin, uvs.yMax}; - inst.uvs[2] = {uvs.xMax, uvs.yMin}; - inst.uvs[3] = {uvs.xMin, uvs.yMin}; - break; - } - case CElementGenShaders::EShaderClass::NoTex: { - 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[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f}; - inst.pos[2] = - zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f}; - inst.pos[3] = - zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f}; - inst.color = particle.x34_color; - break; - } - default: - break; - } +// switch (m_shaderClass) { +// case CElementGenShaders::EShaderClass::Tex: { +// 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[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f}; +// inst.pos[2] = +// zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f}; +// inst.pos[3] = +// zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f}; +// inst.color = particle.x34_color; +// inst.uvs[0] = {uvs.xMax, uvs.yMax}; +// inst.uvs[1] = {uvs.xMin, uvs.yMax}; +// inst.uvs[2] = {uvs.xMax, uvs.yMin}; +// inst.uvs[3] = {uvs.xMin, uvs.yMin}; +// break; +// } +// case CElementGenShaders::EShaderClass::NoTex: { +// 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[1] = zeus::CVector4f{viewPoint.x() + sinT - cosT, viewPoint.y(), viewPoint.z() + sinT + cosT, 1.f}; +// inst.pos[2] = +// zeus::CVector4f{viewPoint.x() + (cosT - sinT), viewPoint.y(), viewPoint.z() + (-cosT - sinT), 1.f}; +// inst.pos[3] = +// zeus::CVector4f{viewPoint.x() - (sinT + cosT), viewPoint.y(), viewPoint.z() - (cosT - sinT), 1.f}; +// inst.color = particle.x34_color; +// break; +// } +// default: +// break; +// } } } } else { @@ -1487,65 +1496,65 @@ void CElementGen::RenderParticles() { texr->GetValueUV(partFrame, uvs); } - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: { - SParticleInstanceTex& inst = g_instTexData.emplace_back(); - viewPoint += rightVec * 0.5f; - inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; - inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; - viewPoint -= rightVec; - inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; - inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; - inst.color = particle.x34_color; - inst.uvs[0] = {uvs.xMax, uvs.yMax}; - inst.uvs[1] = {uvs.xMin, uvs.yMax}; - inst.uvs[2] = {uvs.xMax, uvs.yMin}; - inst.uvs[3] = {uvs.xMin, uvs.yMin}; - break; - } - case CElementGenShaders::EShaderClass::NoTex: { - SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); - viewPoint += rightVec * 0.5f; - inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; - inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; - viewPoint -= rightVec; - inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; - inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; - inst.color = particle.x34_color; - break; - } - default: - break; - } +// switch (m_shaderClass) { +// case CElementGenShaders::EShaderClass::Tex: { +// SParticleInstanceTex& inst = g_instTexData.emplace_back(); +// viewPoint += rightVec * 0.5f; +// inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; +// inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; +// viewPoint -= rightVec; +// inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; +// inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; +// inst.color = particle.x34_color; +// inst.uvs[0] = {uvs.xMax, uvs.yMax}; +// inst.uvs[1] = {uvs.xMin, uvs.yMax}; +// inst.uvs[2] = {uvs.xMax, uvs.yMin}; +// inst.uvs[3] = {uvs.xMin, uvs.yMin}; +// break; +// } +// case CElementGenShaders::EShaderClass::NoTex: { +// SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); +// viewPoint += rightVec * 0.5f; +// inst.pos[0] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; +// inst.pos[1] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; +// viewPoint -= rightVec; +// inst.pos[2] = zeus::CVector4f{viewPoint + 0.5f * foreVec}; +// inst.pos[3] = zeus::CVector4f{viewPoint - 0.5f * foreVec}; +// inst.color = particle.x34_color; +// break; +// } +// default: +// break; +// } } } switch (m_shaderClass) { case CElementGenShaders::EShaderClass::Tex: -// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); -// CGraphics::DrawInstances(0, 4, g_instTexData.size()); + // m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); + // CGraphics::DrawInstances(0, 4, g_instTexData.size()); break; case CElementGenShaders::EShaderClass::NoTex: -// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); -// CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); + // m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); + // CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); break; default: break; } } else { - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: - g_instTexData.clear(); - g_instTexData.reserve(x30_particles.size() * mbspVal); - break; - case CElementGenShaders::EShaderClass::NoTex: - g_instNoTexData.clear(); - g_instNoTexData.reserve(x30_particles.size() * mbspVal); - break; - default: - Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); - break; - } +// switch (m_shaderClass) { +// case CElementGenShaders::EShaderClass::Tex: +// g_instTexData.clear(); +// g_instTexData.reserve(x30_particles.size() * mbspVal); +// break; +// case CElementGenShaders::EShaderClass::NoTex: +// g_instNoTexData.clear(); +// g_instNoTexData.reserve(x30_particles.size() * mbspVal); +// break; +// default: +// Log.report(logvisor::Fatal, FMT_STRING("unexpected particle shader class")); +// break; +// } const float mbspFac = 1.f / float(mbspVal); 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); @@ -1569,32 +1578,32 @@ void CElementGen::RenderParticles() { vec += mbspVec; zeus::CVector3f vec2 = systemCameraMatrix * vec; - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: { - SParticleInstanceTex& inst = g_instTexData.emplace_back(); - 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[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.color = particle.x34_color; - inst.uvs[0] = {uvs.xMax, uvs.yMax}; - inst.uvs[1] = {uvs.xMin, uvs.yMax}; - inst.uvs[2] = {uvs.xMax, uvs.yMin}; - inst.uvs[3] = {uvs.xMin, uvs.yMin}; - break; - } - case CElementGenShaders::EShaderClass::NoTex: { - SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); - 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[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.color = particle.x34_color; - break; - } - default: - break; - } +// switch (m_shaderClass) { +// case CElementGenShaders::EShaderClass::Tex: { +// SParticleInstanceTex& inst = g_instTexData.emplace_back(); +// 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[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.color = particle.x34_color; +// inst.uvs[0] = {uvs.xMax, uvs.yMax}; +// inst.uvs[1] = {uvs.xMin, uvs.yMax}; +// inst.uvs[2] = {uvs.xMax, uvs.yMin}; +// inst.uvs[3] = {uvs.xMin, uvs.yMin}; +// break; +// } +// case CElementGenShaders::EShaderClass::NoTex: { +// SParticleInstanceNoTex& inst = g_instNoTexData.emplace_back(); +// 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[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.color = particle.x34_color; +// break; +// } +// default: +// break; +// } } } else { float theta = zeus::degToRad(particle.x30_lineWidthOrRota); @@ -1605,43 +1614,43 @@ void CElementGen::RenderParticles() { vec += mbspVec; zeus::CVector3f vec2 = systemCameraMatrix * vec; - switch (m_shaderClass) { - case CElementGenShaders::EShaderClass::Tex: { - 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[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[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f}; - inst.color = particle.x34_color; - inst.uvs[0] = {uvs.xMax, uvs.yMax}; - inst.uvs[1] = {uvs.xMin, uvs.yMax}; - inst.uvs[2] = {uvs.xMax, uvs.yMin}; - inst.uvs[3] = {uvs.xMin, uvs.yMin}; - break; - } - case CElementGenShaders::EShaderClass::NoTex: { - 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[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[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f}; - inst.color = particle.x34_color; - break; - } - default: - break; - } +// switch (m_shaderClass) { +// case CElementGenShaders::EShaderClass::Tex: { +// 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[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[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f}; +// inst.color = particle.x34_color; +// inst.uvs[0] = {uvs.xMax, uvs.yMax}; +// inst.uvs[1] = {uvs.xMin, uvs.yMax}; +// inst.uvs[2] = {uvs.xMax, uvs.yMin}; +// inst.uvs[3] = {uvs.xMin, uvs.yMin}; +// break; +// } +// case CElementGenShaders::EShaderClass::NoTex: { +// 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[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[3] = zeus::CVector4f{vec2.x() - (sinT + cosT), vec2.y(), vec2.z() - (cosT - sinT), 1.f}; +// inst.color = particle.x34_color; +// break; +// } +// default: +// break; +// } } } } switch (m_shaderClass) { case CElementGenShaders::EShaderClass::Tex: -// m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); -// CGraphics::DrawInstances(0, 4, g_instTexData.size()); + // m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); + // CGraphics::DrawInstances(0, 4, g_instTexData.size()); break; case CElementGenShaders::EShaderClass::NoTex: -// m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); -// CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); + // m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); + // CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); break; default: break; @@ -1660,9 +1669,10 @@ void CElementGen::RenderParticlesIndirectTexture() { x178_localScaleTransform; CGraphics::SetModelMatrix(systemViewPointMatrix); - SParticleUniforms uniformData = { - CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * CGraphics::g_GXModelView.toMatrix4f(), {1.f, 1.f, 1.f, 1.f}}; -// m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); +// SParticleUniforms uniformData = {CGraphics::GetPerspectiveProjectionMatrix(/*true*/) * +// CGraphics::g_GXModelView.toMatrix4f(), +// {1.f, 1.f, 1.f, 1.f}}; + // m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms)); CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); @@ -1712,11 +1722,11 @@ void CElementGen::RenderParticlesIndirectTexture() { }); } - g_instIndTexData.clear(); - g_instIndTexData.reserve(x30_particles.size()); +// g_instIndTexData.clear(); +// g_instIndTexData.reserve(x30_particles.size()); -// if (!x30_particles.empty()) -// CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]); + // if (!x30_particles.empty()) + // CGraphics::SetShaderDataBinding(m_normalDataBind[g_Renderer->IsThermalVisorHotPass()]); 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); @@ -1764,35 +1774,35 @@ void CElementGen::RenderParticlesIndirectTexture() { CGraphics::ResolveSpareTexture(clipRect); - SParticleInstanceIndTex& inst = g_instIndTexData.emplace_back(); - 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[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.color = particle.x34_color; - 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[2] = zeus::CVector4f{uvs.xMax, uvs.yMin, uvsInd.xMax, uvsInd.yMin}; - inst.texrTindUVs[3] = zeus::CVector4f{uvs.xMin, uvs.yMin, uvsInd.xMin, uvsInd.yMin}; -// switch (CGraphics::g_BooPlatform) { -// case boo::IGraphicsDataFactory::Platform::OpenGL: -// inst.sceneUVs = -// zeus::CVector4f{clipRect.x18_uvXMin, clipRect.x24_uvYMax, clipRect.x1c_uvXMax, clipRect.x20_uvYMin}; -// break; -// default: - inst.sceneUVs = zeus::CVector4f{clipRect.x18_uvXMin, 1.f - clipRect.x24_uvYMax, clipRect.x1c_uvXMax, - 1.f - clipRect.x20_uvYMin}; -// break; -// } -// CGraphics::DrawInstances(0, 4, 1, g_instIndTexData.size() - 1); +// SParticleInstanceIndTex& inst = g_instIndTexData.emplace_back(); +// 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[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.color = particle.x34_color; +// 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[2] = zeus::CVector4f{uvs.xMax, uvs.yMin, uvsInd.xMax, uvsInd.yMin}; +// inst.texrTindUVs[3] = zeus::CVector4f{uvs.xMin, uvs.yMin, uvsInd.xMin, uvsInd.yMin}; + // switch (CGraphics::g_BooPlatform) { + // case boo::IGraphicsDataFactory::Platform::OpenGL: + // inst.sceneUVs = + // zeus::CVector4f{clipRect.x18_uvXMin, clipRect.x24_uvYMax, clipRect.x1c_uvXMax, clipRect.x20_uvYMin}; + // break; + // default: +// inst.sceneUVs = +// zeus::CVector4f{clipRect.x18_uvXMin, 1.f - clipRect.x24_uvYMax, clipRect.x1c_uvXMax, 1.f - clipRect.x20_uvYMin}; + // break; + // } + // CGraphics::DrawInstances(0, 4, 1, g_instIndTexData.size() - 1); } - if (g_instIndTexData.size()) { -// m_instBuf->load(g_instIndTexData.data(), g_instIndTexData.size() * sizeof(SParticleInstanceIndTex)); -// TODO! this looks like a bug +// if (g_instIndTexData.size()) { + // m_instBuf->load(g_instIndTexData.data(), g_instIndTexData.size() * sizeof(SParticleInstanceIndTex)); + // TODO! this looks like a bug // CGraphics::SetShaderDataBinding(m_normalDataBind); // CGraphics::DrawInstances(0, 4, g_instIndTexData.size()); - } +// } } void CElementGen::SetOrientation(const zeus::CTransform& orientation) { diff --git a/Runtime/Particle/CParticleGlobals.hpp b/Runtime/Particle/CParticleGlobals.hpp index 66487048f..86569e462 100644 --- a/Runtime/Particle/CParticleGlobals.hpp +++ b/Runtime/Particle/CParticleGlobals.hpp @@ -59,30 +59,30 @@ public: } }; -struct SParticleInstanceTex { - std::array pos; - zeus::CColor color; - std::array uvs; -}; -extern std::vector g_instTexData; - -struct SParticleInstanceIndTex { - std::array pos; - zeus::CColor color; - std::array texrTindUVs; - zeus::CVector4f sceneUVs; -}; -extern std::vector g_instIndTexData; - -struct SParticleInstanceNoTex { - std::array pos; - zeus::CColor color; -}; -extern std::vector g_instNoTexData; - -struct SParticleUniforms { - zeus::CMatrix4f mvp; - zeus::CColor moduColor; -}; +//struct SParticleInstanceTex { +// std::array pos; +// zeus::CColor color; +// std::array uvs; +//}; +//extern std::vector g_instTexData; +// +//struct SParticleInstanceIndTex { +// std::array pos; +// zeus::CColor color; +// std::array texrTindUVs; +// zeus::CVector4f sceneUVs; +//}; +//extern std::vector g_instIndTexData; +// +//struct SParticleInstanceNoTex { +// std::array pos; +// zeus::CColor color; +//}; +//extern std::vector g_instNoTexData; +// +//struct SParticleUniforms { +// zeus::CMatrix4f mvp; +// zeus::CColor moduColor; +//}; } // namespace metaforce diff --git a/aurora/include/aurora/gfx.hpp b/aurora/include/aurora/gfx.hpp index 165456223..1334c4cc7 100644 --- a/aurora/include/aurora/gfx.hpp +++ b/aurora/include/aurora/gfx.hpp @@ -132,11 +132,6 @@ struct Light { [[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 void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept; void unbind_texture(GX::TexMapID id) noexcept; diff --git a/aurora/lib/gfx/gx.cpp b/aurora/lib/gfx/gx.cpp index 427b51791..9d26e8f36 100644 --- a/aurora/lib/gfx/gx.cpp +++ b/aurora/lib/gfx/gx.cpp @@ -1,6 +1,7 @@ #include "gx.hpp" #include "../gpu.hpp" +#include "Runtime/Graphics/GX.hpp" #include "common.hpp" #include @@ -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}; } 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 { 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, 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) { 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.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 = { .shaderConfig = config.shaderConfig, .primitive = primitive, @@ -601,7 +630,7 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi .uniformBindGroup = bind_group_ref(wgpu::BindGroupDescriptor{ .label = "GX Uniform Bind Group", .layout = layouts.uniformLayout, - .entryCount = static_cast(config.denormalizedVertexAttributes ? 1 : uniformEntries.size()), + .entryCount = static_cast(config.hasIndexedAttributes ? uniformEntries.size() : 1), .entries = uniformEntries.data(), }), .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 out; - u32 uniformSizeKey = info.uniformSize + (config.denormalizedVertexAttributes ? 0 : 1); + u32 uniformSizeKey = info.uniformSize + (config.hasIndexedAttributes ? 1 : 0); const auto uniformIt = sUniformBindGroupLayouts.find(uniformSizeKey); if (uniformIt != sUniformBindGroupLayouts.end()) { out.uniformLayout = uniformIt->second; @@ -676,7 +705,7 @@ GXBindGroupLayouts build_bind_group_layouts(const ShaderInfo& info, const Shader }; const auto uniformLayoutDescriptor = wgpu::BindGroupLayoutDescriptor{ .label = "GX Uniform Bind Group Layout", - .entryCount = static_cast(config.denormalizedVertexAttributes ? 1 : uniformLayoutEntries.size()), + .entryCount = static_cast(config.hasIndexedAttributes ? uniformLayoutEntries.size() : 1), .entries = uniformLayoutEntries.data(), }; out.uniformLayout = g_device.CreateBindGroupLayout(&uniformLayoutDescriptor); diff --git a/aurora/lib/gfx/gx.hpp b/aurora/lib/gfx/gx.hpp index a69bde456..3a7376728 100644 --- a/aurora/lib/gfx/gx.hpp +++ b/aurora/lib/gfx/gx.hpp @@ -13,6 +13,8 @@ constexpr u32 MaxKColors = GX::MAX_KCOLOR; constexpr u32 MaxTexMtx = 10; constexpr u32 MaxPTTexMtx = 20; constexpr u32 MaxTexCoord = GX::MAX_TEXCOORD; +constexpr u32 MaxVtxAttr = GX::VA_MAX_ATTR; +constexpr u32 MaxTevSwap = GX::MAX_TEVSWAP; template struct TevPass { @@ -40,6 +42,8 @@ struct TevStage { GX::TexCoordID texCoordId = GX::TEXCOORD_NULL; GX::TexMapID texMapId = GX::TEXMAP_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; }; struct TextureBind { @@ -86,6 +90,14 @@ struct FogState { float farZ = 0.f; 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 { zeus::CMatrix4f mv; @@ -111,6 +123,13 @@ struct GXState { std::array texMtxs; std::array, MaxPTTexMtx> ptTexMtxs; std::array tcgs; + std::array vtxDesc; + std::array 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 depthUpdate = true; bool alphaUpdate = true; @@ -128,12 +147,13 @@ const TextureBind& get_texture(GX::TexMapID id) noexcept; struct ShaderConfig { GX::FogType fogType; + std::array vtxAttrs; + std::array tevSwapTable; std::array, MaxTevStages> tevStages; std::array colorChannels; std::array tcgs; std::optional alphaDiscard; - bool denormalizedVertexAttributes = false; - bool denormalizedHasNrm = false; // TODO this is a hack + bool hasIndexedAttributes = false; bool operator==(const ShaderConfig&) const = default; }; struct PipelineConfig { @@ -168,8 +188,6 @@ struct ShaderInfo { std::bitset usesPTTexMtx; std::array texMtxTypes; u32 uniformSize = 0; - bool usesVtxColor : 1 = false; - bool usesNormal : 1 = false; bool usesFog : 1 = false; }; struct BindGroupRanges { @@ -248,6 +266,9 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::TcgConfig& input) { } template <> 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) { if (!item) { break; @@ -263,9 +284,6 @@ inline void xxh3_update(XXH3_state_t& state, const gfx::gx::ShaderConfig& input) if (input.alphaDiscard) { XXH3_64bits_update(&state, &*input.alphaDiscard, sizeof(float)); } - XXH3_64bits_update(&state, &input.denormalizedVertexAttributes, - 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)); + XXH3_64bits_update(&state, &input.hasIndexedAttributes, sizeof(gfx::gx::ShaderConfig::hasIndexedAttributes)); } } // namespace aurora diff --git a/aurora/lib/gfx/gx_shader.cpp b/aurora/lib/gfx/gx_shader.cpp index 5bc0dd78d..bb88b5887 100644 --- a/aurora/lib/gfx/gx_shader.cpp +++ b/aurora/lib/gfx/gx_shader.cpp @@ -15,7 +15,21 @@ absl::flat_hash_map> g_ static absl::flat_hash_map g_gxCachedShaderConfigs; #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) { case GX::CC_CPREV: return "prev.rgb"; @@ -48,7 +62,9 @@ static std::string color_arg_reg(GX::TevColorArg arg, size_t stageIdx, const Tev unreachable(); } 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: { 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(); } 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: { 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; 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: { 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; 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: 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) { case GX::CA_APREV: return "prev.a"; @@ -202,7 +223,8 @@ static std::string alpha_arg_reg(GX::TevAlphaArg arg, size_t stageIdx, const Tev unreachable(); } 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: { 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; 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: { switch (stage.kaSel) { @@ -337,14 +360,51 @@ static std::string_view tev_scale(GX::TevScale scale) { } } -static std::string in_uv(u32 idx) { - if (idx == 0) { - return "v_packed_uvs.data[in_uv_0_4_idx[0]]"; +static inline std::string vtx_attr(const ShaderConfig& config, GX::Attr attr) { + const auto type = config.vtxAttrs[attr]; + if (type == GX::NONE) { + if (attr == GX::VA_NRM) { + // Default normal + return "vec3(1.0, 0.0, 0.0)"; + } + Log.report(logvisor::Fatal, FMT_STRING("unmapped attr {}"), attr); + unreachable(); } - if (idx < 4) { - return fmt::format(FMT_STRING("v_uvs.data[in_uv_0_4_idx[{}]]"), idx); + if (attr == GX::VA_POS) { + 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 build_shader(const ShaderConfig& config) noexcept { @@ -409,7 +469,7 @@ std::pair build_shader(const ShaderConfig& confi } } 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); } @@ -423,23 +483,14 @@ std::pair build_shader(const ShaderConfig& confi std::string vtxXfrAttrsPre; std::string vtxXfrAttrs; size_t locIdx = 0; - if (config.denormalizedVertexAttributes) { - vtxInAttrs += "\n @location(0) in_pos: vec3"; - vtxOutAttrs += "\n @builtin(position) pos: vec4;"; - vtxXfrAttrsPre += - "\n var obj_pos = vec4(in_pos, 1.0);" - "\n var mv_pos = ubuf.mv * obj_pos;" - "\n out.pos = ubuf.proj * mv_pos;"; - if (config.denormalizedHasNrm) { - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3;"), locIdx); - vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_nrm: vec3"), ++locIdx); - vtxXfrAttrs += fmt::format(FMT_STRING("\n out.nrm = in_nrm;")); - vtxXfrAttrsPre += - "\n var obj_norm = vec4(in_nrm, 0.0);" - "\n var mv_norm = ubuf.mv_inv * obj_norm;"; - info.usesNormal = true; - } - } else { + size_t vtxOutIdx = 0; + if (config.hasIndexedAttributes) { + // Display list attributes + vtxInAttrs += + "\n @location(0) in_pos_nrm_idx: vec2" + "\n , @location(1) in_uv_0_4_idx: vec4" + "\n , @location(2) in_uv_5_7_idx: vec4"; + locIdx += 3; uniformBindings += R"""( struct Vec3Block { data: array>; @@ -456,18 +507,33 @@ var v_uvs: Vec2Block; @group(0) @binding(4) var v_packed_uvs: Vec2Block; )"""; - vtxInAttrs += - "\n @location(0) in_pos_nrm_idx: vec2" - "\n , @location(1) in_uv_0_4_idx: vec4" - "\n , @location(2) in_uv_5_7_idx: vec4"; - vtxOutAttrs += "\n @builtin(position) pos: vec4;"; - vtxXfrAttrsPre += - "\n var obj_pos = vec4(v_verts.data[in_pos_nrm_idx[0]].xyz, 1.0);" - "\n var obj_norm = vec4(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"), locIdx++); + } else if (attr == GX::VA_NRM) { + vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_nrm: vec3"), locIdx++); + } else if (attr == GX::VA_CLR0 || attr == GX::VA_CLR1) { + vtxInAttrs += fmt::format(FMT_STRING("@location({}) in_clr{}: vec4"), 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"), locIdx++, attr - GX::VA_TEX0); + } + } + vtxXfrAttrsPre += fmt::format(FMT_STRING("\n var obj_pos = vec4({}, 1.0);" + "\n var obj_norm = vec4({}, 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 fragmentFn; @@ -478,7 +544,7 @@ var v_packed_uvs: Vec2Block; { std::string outReg; switch (stage->colorOp.outReg) { - case GX::TevRegID::TEVPREV: + case GX::TEVPREV: outReg = "prev"; break; case GX::TEVREG0: @@ -496,11 +562,13 @@ var v_packed_uvs: Vec2Block; default: Log.report(logvisor::Fatal, FMT_STRING("invalid colorOp outReg {}"), stage->colorOp.outReg); } - std::string op = fmt::format( - FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), - color_arg_reg(stage->colorPass.a, idx, *stage, info), color_arg_reg(stage->colorPass.b, idx, *stage, info), - color_arg_reg(stage->colorPass.c, idx, *stage, info), color_arg_reg(stage->colorPass.d, idx, *stage, info), - tev_op(stage->colorOp.op), tev_bias(stage->colorOp.bias), tev_scale(stage->colorOp.scale)); + std::string op = + fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), + color_arg_reg(stage->colorPass.a, idx, config, *stage, info), + color_arg_reg(stage->colorPass.b, idx, config, *stage, info), + 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) { op = fmt::format(FMT_STRING("clamp(vec3({}), vec3(0.0), vec3(1.0))"), op); } @@ -509,7 +577,7 @@ var v_packed_uvs: Vec2Block; { std::string outReg; switch (stage->alphaOp.outReg) { - case GX::TevRegID::TEVPREV: + case GX::TEVPREV: outReg = "prev.a"; break; case GX::TEVREG0: @@ -527,11 +595,13 @@ var v_packed_uvs: Vec2Block; default: Log.report(logvisor::Fatal, FMT_STRING("invalid alphaOp outReg {}"), stage->alphaOp.outReg); } - std::string op = fmt::format( - FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), - alpha_arg_reg(stage->alphaPass.a, idx, *stage, info), alpha_arg_reg(stage->alphaPass.b, idx, *stage, info), - alpha_arg_reg(stage->alphaPass.c, idx, *stage, info), alpha_arg_reg(stage->alphaPass.d, idx, *stage, info), - tev_op(stage->alphaOp.op), tev_bias(stage->alphaOp.bias), tev_scale(stage->alphaOp.scale)); + std::string op = + fmt::format(FMT_STRING("({3} {4} ((1.0 - {2}) * {0} + {2} * {1}){5}){6}"), + alpha_arg_reg(stage->alphaPass.a, idx, config, *stage, info), + alpha_arg_reg(stage->alphaPass.b, idx, config, *stage, info), + 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) { op = fmt::format(FMT_STRING("clamp({}, 0.0, 1.0)"), op); } @@ -557,11 +627,6 @@ var v_packed_uvs: Vec2Block; uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4;"), i); info.uniformSize += 32; - if (config.denormalizedVertexAttributes && !info.usesVtxColor) { - vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_clr: vec4"), ++locIdx); - info.usesVtxColor = true; - } - if (config.colorChannels[i].lightingEnabled) { if (!addedLightStruct) { uniformPre += @@ -580,7 +645,7 @@ var v_packed_uvs: Vec2Block; uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4;"), i); info.uniformSize += (80 * GX::MaxLights) + 16; - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), locIdx++, i); + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), vtxOutIdx++, i); vtxXfrAttrs += fmt::format(FMT_STRING(R"""( {{ var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb; @@ -604,13 +669,9 @@ var v_packed_uvs: Vec2Block; i, GX::MaxLights); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); } else if (config.colorChannels[i].matSrc == GX::SRC_VTX) { - if (config.denormalizedVertexAttributes) { - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), locIdx - 1, i); - vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = in_clr;"), i); - fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); - } else { - Log.report(logvisor::Fatal, FMT_STRING("SRC_VTX unsupported with normalized vertex attributes")); - } + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4;"), vtxOutIdx++, i); + vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = {};"), i, vtx_attr(config, GX::Attr(GX::VA_CLR0 + i))); + fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); } else { fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = ubuf.cc{0}_mat;"), i); } @@ -628,23 +689,17 @@ var v_packed_uvs: Vec2Block; continue; } const auto& tcg = config.tcgs[i]; - if (config.denormalizedVertexAttributes) { - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2;"), locIdx, i); - vtxInAttrs += fmt::format(FMT_STRING("\n , @location({}) in_tex{}_uv: vec2"), locIdx + 1, i); - // TODO check tcg src for denorm? - vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0} = vec4(in_tex{0}_uv, 0.0, 1.0);"), i); + vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2;"), vtxOutIdx++, i); + if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) { + vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4({}, 0.0, 1.0);"), i, + vtx_attr(config, GX::Attr(GX::VA_TEX0 + (tcg.src - GX::TG_TEX0)))); + } else if (tcg.src == GX::TG_POS) { + vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4(obj_pos.xyz, 1.0);"), i); + } else if (tcg.src == GX::TG_NRM) { + vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4(obj_norm.xyz, 1.0);"), i); } else { - vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2;"), locIdx, i); - if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) { - vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4({}, 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(obj_pos.xyz, 1.0);"), i); - } else if (tcg.src == GX::TG_NRM) { - vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4(obj_norm.xyz, 1.0);"), i); - } else { - Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {}"), tcg.src); - unreachable(); - } + Log.report(logvisor::Fatal, FMT_STRING("unhandled tcg src {}"), tcg.src); + unreachable(); } // TODO this all assumes MTX3x4 currently if (tcg.mtx == GX::IDENTITY) { @@ -663,12 +718,12 @@ var v_packed_uvs: Vec2Block; } else { u32 postMtxIdx = (tcg.postMtx - GX::PTTEXMTX0) / 3; info.usesPTTexMtx.set(postMtxIdx); - vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = ubuf.postmtx{1} * vec4(tc{0}_tmp.xyz, 1.0);"), i, postMtxIdx); + vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{0}_proj = ubuf.postmtx{1} * vec4(tc{0}_tmp.xyz, 1.0);"), + i, postMtxIdx); } vtxXfrAttrs += fmt::format(FMT_STRING("\n out.tex{0}_uv = tc{0}_proj.xy;"), i); fragmentFnPre += fmt::format( 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) { if (!info.usesTexMtx.test(i)) { @@ -698,7 +753,8 @@ var v_packed_uvs: Vec2Block; if (config.fogType != GX::FOG_NONE) { info.usesFog = true; - uniformPre += "\n" + uniformPre += + "\n" "struct Fog {\n" " color: vec4;\n" " a: f32;\n" @@ -729,7 +785,8 @@ var v_packed_uvs: Vec2Block; break; case GX::FOG_PERSP_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);"; break; default: @@ -767,7 +824,8 @@ struct Uniform {{ @group(0) @binding(0) var ubuf: Uniform;{uniformBindings}{sampBindings}{texBindings} -struct VertexOutput {{{vtxOutAttrs} +struct VertexOutput {{ + @builtin(position) pos: vec4;{vtxOutAttrs} }}; @stage(vertex) diff --git a/aurora/lib/gfx/model/shader.cpp b/aurora/lib/gfx/model/shader.cpp index 1ed9f2102..c9279f15c 100644 --- a/aurora/lib/gfx/model/shader.cpp +++ b/aurora/lib/gfx/model/shader.cpp @@ -5,47 +5,6 @@ #include #include -#include - -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 { static logvisor::Module Log("aurora::gfx::model"); @@ -59,53 +18,52 @@ static std::optional staticNrmRange; static std::optional staticPackedTcRange; static std::optional 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 readVert(const u8* data) noexcept { gx::DlVert out{}; size_t offset = 0; - const auto read8 = [data, &offset](VtxDescAttrType type) -> s8 { - if (type == VtxDescAttrType::Direct) { - s8 v = static_cast(data[offset]); - ++offset; - return v; + const auto vtxTypes = gx::g_gxState.vtxDesc; + const auto read8 = [/*data, &offset*/](GX::AttrType type) -> s8 { +// if (type == GX::INDEX8) { +// s8 v = static_cast(data[offset]); +// ++offset; +// return v; +// } +#ifndef NDEBUG + if (type != GX::NONE) { + Log.report(logvisor::Fatal, FMT_STRING("unsupported vtx attr")); + unreachable(); } +#endif return 0; }; - const auto read16 = [data, &offset](VtxDescAttrType type) -> s16 { - if (type == VtxDescAttrType::Index16) { + const auto read16 = [data, &offset](GX::AttrType type) -> s16 { + if (type == GX::INDEX16) { s16 v = metaforce::SBig(*reinterpret_cast(data + offset)); offset += 2; return v; } return 0; }; - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::PnMatIdx)); - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex0MatIdx)); - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex1MatIdx)); - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex2MatIdx)); - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex3MatIdx)); - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex4MatIdx)); - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex5MatIdx)); - read8(sVtxDescFlags.GetDirectAttributeType(VtxDescAttr::Tex6MatIdx)); + read8(vtxTypes[GX::VA_PNMTXIDX]); + read8(vtxTypes[GX::VA_TEX0MTXIDX]); + read8(vtxTypes[GX::VA_TEX1MTXIDX]); + read8(vtxTypes[GX::VA_TEX2MTXIDX]); + read8(vtxTypes[GX::VA_TEX3MTXIDX]); + read8(vtxTypes[GX::VA_TEX4MTXIDX]); + read8(vtxTypes[GX::VA_TEX5MTXIDX]); + read8(vtxTypes[GX::VA_TEX6MTXIDX]); - out.pos = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Position)); - out.norm = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Normal)); - read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Color0)); - read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Color1)); - out.uvs[0] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex0)); - out.uvs[1] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex1)); - out.uvs[2] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex2)); - out.uvs[3] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex3)); - out.uvs[4] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex4)); - out.uvs[5] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex5)); - out.uvs[6] = read16(sVtxDescFlags.GetAttributeType(VtxDescAttr::Tex6)); + out.pos = read16(vtxTypes[GX::VA_POS]); + out.norm = read16(vtxTypes[GX::VA_NRM]); + read16(vtxTypes[GX::VA_CLR0]); + read16(vtxTypes[GX::VA_CLR1]); + out.uvs[0] = read16(vtxTypes[GX::VA_TEX0]); + out.uvs[1] = read16(vtxTypes[GX::VA_TEX1]); + out.uvs[2] = read16(vtxTypes[GX::VA_TEX2]); + out.uvs[3] = read16(vtxTypes[GX::VA_TEX3]); + out.uvs[4] = read16(vtxTypes[GX::VA_TEX4]); + out.uvs[5] = read16(vtxTypes[GX::VA_TEX5]); + out.uvs[6] = read16(vtxTypes[GX::VA_TEX6]); return {out, offset}; } @@ -130,7 +88,6 @@ void queue_surface(const u8* dlStart, u32 dlSize) noexcept { while (offset < dlSize - 6) { const auto header = dlStart[offset]; const auto primitive = static_cast(header & 0xF8); - const auto vtxFmt = static_cast(header & 0x3); const auto vtxCount = metaforce::SBig(*reinterpret_cast(dlStart + offset + 1)); offset += 3; diff --git a/aurora/lib/gfx/stream.cpp b/aurora/lib/gfx/stream.cpp index 46f73f025..6160d1b83 100644 --- a/aurora/lib/gfx/stream.cpp +++ b/aurora/lib/gfx/stream.cpp @@ -4,71 +4,138 @@ #include "common.hpp" #include "gx.hpp" -namespace aurora::gfx { static logvisor::Module Log("aurora::gfx::stream"); +using aurora::gfx::gx::g_gxState; + struct SStreamState { GX::Primitive primitive; - metaforce::EStreamFlags flags; - uint32_t vertexCount = 0; - ByteBuffer vertexBuffer; + u16 vertexCount = 0; + aurora::ByteBuffer vertexBuffer; + std::vector 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; -void stream_begin(GX::Primitive primitive) noexcept { +void GXBegin(GX::Primitive primitive, GX::VtxFmt vtxFmt, u16 nVerts) noexcept { +#ifndef NDEBUG if (sStreamState) { Log.report(logvisor::Fatal, FMT_STRING("Stream began twice!")); 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); } - -void stream_vertex(metaforce::EStreamFlags flags, const zeus::CVector3f& pos, const zeus::CVector3f& nrm, - const zeus::CColor& color, const zeus::CVector2f& uv) noexcept { +static inline void check_attr_order(GX::Attr attr) noexcept { +#ifndef NDEBUG if (!sStreamState) { Log.report(logvisor::Fatal, FMT_STRING("Stream not started!")); unreachable(); } - if (sStreamState->flags) { - if (sStreamState->flags != flags) { - Log.report(logvisor::Fatal, FMT_STRING("Stream changed flags?")); - unreachable(); - } - } else { - sStreamState->flags = flags; + if (sStreamState->currentAttr >= attr) { + Log.report(logvisor::Fatal, FMT_STRING("bad attribute order: {}, last {}"), attr, sStreamState->currentAttr); + unreachable(); } - sStreamState->vertexBuffer.append(&pos, 12); - if (flags & metaforce::EStreamFlagBits::fHasNormal) { - 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++; + sStreamState->currentAttr = attr; +#endif } - -void stream_end() noexcept { - const auto vertRange = push_verts(sStreamState->vertexBuffer.data(), sStreamState->vertexBuffer.size()); - - stream::PipelineConfig config{}; - config.shaderConfig.denormalizedVertexAttributes = true; - config.shaderConfig.denormalizedHasNrm = sStreamState->flags.IsSet(metaforce::EStreamFlagBits::fHasNormal); - const auto info = populate_pipeline_config(config, sStreamState->primitive, {}); - const auto pipeline = pipeline_ref(config); - - push_draw_command(stream::DrawData{ +void GXPosition3f32(const zeus::CVector3f& pos) noexcept { +#ifndef NDEBUG + if (!sStreamState) { + Log.report(logvisor::Fatal, FMT_STRING("Stream not started!")); + unreachable(); + } + sStreamState->currentAttr = GX::VA_POS; +#endif + auto& state = *sStreamState; + state.vertexBuffer.append(&pos, 12); + 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, .vertRange = vertRange, .uniformRange = build_uniform(info), - .vertexCount = sStreamState->vertexCount, + .indexRange = indexRange, + .indexCount = static_cast(sStreamState->indices.size()), .bindGroups = info.bindGroups, }); - sStreamState.reset(); } -} // namespace aurora::gfx diff --git a/aurora/lib/gfx/stream/shader.cpp b/aurora/lib/gfx/stream/shader.cpp index a6dbbc82b..0ad8d2794 100644 --- a/aurora/lib/gfx/stream/shader.cpp +++ b/aurora/lib/gfx/stream/shader.cpp @@ -22,7 +22,7 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli }; uint64_t offset = 12; uint32_t shaderLocation = 1; - if (info.usesNormal) { + if (config.shaderConfig.vtxAttrs[GX::VA_NRM] == GX::DIRECT) { attributes[shaderLocation] = wgpu::VertexAttribute{ .format = wgpu::VertexFormat::Float32x3, .offset = offset, @@ -31,7 +31,7 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli offset += 12; shaderLocation++; } - if (info.usesVtxColor) { + if (config.shaderConfig.vtxAttrs[GX::VA_CLR0] == GX::DIRECT) { attributes[shaderLocation] = wgpu::VertexAttribute{ .format = wgpu::VertexFormat::Float32x4, .offset = offset, @@ -40,9 +40,8 @@ wgpu::RenderPipeline create_pipeline(const State& state, [[maybe_unused]] Pipeli offset += 16; shaderLocation++; } - // TODO only sample 1? - for (int i = 0; i < info.sampledTextures.size(); ++i) { - if (!info.sampledTextures.test(i)) { + for (int i = GX::VA_TEX0; i < GX::VA_TEX7; ++i) { + if (config.shaderConfig.vtxAttrs[i] != GX::DIRECT) { continue; } 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.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 diff --git a/aurora/lib/gfx/stream/shader.hpp b/aurora/lib/gfx/stream/shader.hpp index 7ac66c513..80a4cdc53 100644 --- a/aurora/lib/gfx/stream/shader.hpp +++ b/aurora/lib/gfx/stream/shader.hpp @@ -8,7 +8,8 @@ struct DrawData { PipelineRef pipeline; Range vertRange; Range uniformRange; - uint32_t vertexCount; + Range indexRange; + uint32_t indexCount; gx::GXBindGroups bindGroups; };