diff --git a/Runtime/Particle/CDecal.cpp b/Runtime/Particle/CDecal.cpp index 012b62991..a36ade61e 100644 --- a/Runtime/Particle/CDecal.cpp +++ b/Runtime/Particle/CDecal.cpp @@ -3,6 +3,7 @@ #include "Runtime/Graphics/CModel.hpp" #include "Runtime/Graphics/Shaders/CDecalShaders.hpp" #include "Runtime/Particle/CParticleGlobals.hpp" +#include "Runtime/Graphics/CGX.hpp" namespace metaforce { CRandom16 CDecal::sDecalRandom; @@ -41,18 +42,20 @@ bool CDecal::InitQuad(CQuadDecal& quad, const SQuadDescr& desc) { } if (desc.x8_ROT) { desc.x8_ROT->GetValue(0, quad.x8_rotation); - quad.x0_24_invalid = desc.x8_ROT->IsConstant(); + quad.x0_24_invalid &= desc.x8_ROT->IsConstant(); } if (desc.x4_SZE) { - quad.x0_24_invalid = desc.x4_SZE->IsConstant(); - float size = 1.f; - desc.x4_SZE->GetValue(0, size); - quad.x0_24_invalid = size <= 1.f; + quad.x0_24_invalid &= desc.x4_SZE->IsConstant(); + if (quad.x0_24_invalid) { + float size = 1.f; + desc.x4_SZE->GetValue(0, size); + quad.x0_24_invalid = size <= 1.f; + } } if (desc.xc_OFF) { - quad.x0_24_invalid = desc.xc_OFF->IsFastConstant(); + quad.x0_24_invalid &= desc.xc_OFF->IsFastConstant(); } return false; } @@ -86,73 +89,104 @@ void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const { zeus::CTransform modXf = xc_transform; modXf.origin += offset; CGraphics::SetModelMatrix(modXf); + CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0); -// 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; - - SUVElementSet uvSet = {0.f, 1.f, 0.f, 1.f}; - if (CUVElement* tex = desc.x14_TEX.get()) { - TLockedToken texObj = tex->GetValueTexture(x58_frameIdx); - if (!texObj.IsLoaded()) - return; - tex->GetValueUV(x58_frameIdx, uvSet); -// if (redToAlpha) -// CGraphics::SetShaderDataBinding(decal.m_redToAlphaDataBind); -// else -// CGraphics::SetShaderDataBinding(decal.m_normalDataBind); - -// 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); - -// decal.m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex)); -// CGraphics::DrawInstances(0, 4, g_instTexData.size()); + bool redToAlpha = CDecal::sMoveRedToAlphaBuffer && desc.x18_ADD && desc.x14_TEX; + if (desc.x18_ADD) { + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false); + if (redToAlpha) { + CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear); + } else { + CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, + ERglLogicOp::Clear); + } } else { -// g_instNoTexData.clear(); -// g_instNoTexData.reserve(1); + CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false); + CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, + ERglLogicOp::Clear); + } -// 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; + SUVElementSet uvSet{0.f, 1.f, 0.f, 1.f}; + if (desc.x14_TEX) { + TLockedToken tex = desc.x14_TEX->GetValueTexture(x58_frameIdx); + tex->Load(GX_TEXMAP0, EClampMode::Repeat); + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::kEnvModulate); + desc.x14_TEX->GetValueUV(x58_frameIdx, uvSet); + if (redToAlpha) { + CGX::SetNumTevStages(2); + 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::SetAlphaCompare(GX_GREATER, 0, GX_AOP_OR, GX_NEVER, 0); + GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP1); + } else { + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::kEnvPassthru); + } + } else { + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::kEnvPassthru); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::kEnvPassthru); + } -// decal.m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex)); -// CGraphics::DrawInstances(0, 4, g_instNoTexData.size()); + CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + CGX::SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); + CGX::SetNumTexGens(1); + CGX::SetNumChans(1); + CGX::SetNumIndStages(0); + CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, false, GX_PTIDENTITY); + CGX::SetChanCtrl(CGX::EChannelId::Channel0, false, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + static const GXVtxDescList vtxDesc[4] = { + {GX_VA_POS, GX_DIRECT}, + {GX_VA_CLR0, GX_DIRECT}, + {GX_VA_TEX0, GX_DIRECT}, + {GX_VA_NULL, GX_NONE}, + }; + CGX::SetVtxDescv(vtxDesc); + CGX::Begin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4); + + float y = 0.001f; + if (decal.x8_rotation == 0.f) { + // Vertex 0 + GXPosition3f32(-size, y, size); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMin, uvSet.yMin); + // Vertex 1 + GXPosition3f32(size, y, size); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMax, uvSet.yMin); + // Vertex 2 + GXPosition3f32(-size, y, -size); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMin, uvSet.yMax); + // Vertex 3 + GXPosition3f32(size, y, -size); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMax, uvSet.yMax); + } else { + float ang = zeus::degToRad(decal.x8_rotation); + float sinSize = sin(ang) * size; + float cosSize = cos(ang) * size; + // Vertex 0 + GXPosition3f32(sinSize - cosSize, y, cosSize + sinSize); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMin, uvSet.yMin); + // Vertex 1 + GXPosition3f32(cosSize + sinSize, y, cosSize - sinSize); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMax, uvSet.yMin); + // Vertex 2 + GXPosition3f32(-(cosSize + sinSize), y, -(cosSize - sinSize)); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMin, uvSet.yMax); + // Vertex 3 + GXPosition3f32(-sinSize + cosSize, y, -cosSize - sinSize); + GXColor4f32(color); + GXTexCoord2f32(uvSet.xMax, uvSet.yMax); + } + + CGX::End(); + if (redToAlpha) { + GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0); + CGX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0); } }