mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-09 02:27:43 +00:00
macOS decal rendering support
This commit is contained in:
@@ -1,38 +1,56 @@
|
||||
#include "CDecal.hpp"
|
||||
#include "CParticleGlobals.hpp"
|
||||
#include "Graphics/Shaders/CDecalShaders.hpp"
|
||||
#include "Graphics/CModel.hpp"
|
||||
|
||||
namespace urde
|
||||
{
|
||||
CRandom16 CDecal::sDecalRandom(99);
|
||||
bool CDecal::sMoveRedToAphaBuffer = false;
|
||||
bool CDecal::sMoveRedToAlphaBuffer = false;
|
||||
|
||||
CDecal::CDecal(const TToken<CDecalDescription>& desc, const zeus::CTransform& xf)
|
||||
: x0_description(desc),
|
||||
xc_transform(xf),
|
||||
x3c_decalQuad1(0, 0.f),
|
||||
x48_decalQuad2(0, 0.f)
|
||||
: x0_description(desc),
|
||||
xc_transform(xf)
|
||||
{
|
||||
CGlobalRandom gr(sDecalRandom);
|
||||
|
||||
x5c_31_quad1Invalid = InitQuad(x3c_decalQuad1, x0_description.GetObj()->x0_Quad);
|
||||
x5c_30_quad2Invalid = InitQuad(x48_decalQuad2, x0_description.GetObj()->x1c_Quad);
|
||||
CDecalDescription& desco = *x0_description;
|
||||
x5c_31_quad1Invalid = InitQuad(x3c_decalQuads[0], desco.x0_Quads[0]);
|
||||
x5c_30_quad2Invalid = InitQuad(x3c_decalQuads[1], desco.x0_Quads[1]);
|
||||
|
||||
CDecalDescription* d = x0_description.GetObj();
|
||||
if (d->x38_DMDL)
|
||||
{
|
||||
if (d->x48_DLFT)
|
||||
d->x48_DLFT->GetValue(0, x54_lifetime);
|
||||
d->x48_DLFT->GetValue(0, x54_modelLifetime);
|
||||
else
|
||||
x54_lifetime = 0x7FFFFF;
|
||||
x54_modelLifetime = 0x7FFFFF;
|
||||
|
||||
if (d->x50_DMRT)
|
||||
d->x50_DMRT->GetValue(0, x60_rotation);
|
||||
}
|
||||
else
|
||||
x5c_29_modelInvalid = true;
|
||||
|
||||
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx)
|
||||
{
|
||||
for (int i=0 ; i<2 ; ++i)
|
||||
{
|
||||
CQuadDecal& decal = x3c_decalQuads[i];
|
||||
if (decal.m_desc->x14_TEX)
|
||||
decal.m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SParticleInstanceTex), 1);
|
||||
else
|
||||
decal.m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SParticleInstanceNoTex), 1);
|
||||
decal.m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
|
||||
CDecalShaders::BuildShaderDataBinding(ctx, decal);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool CDecal::InitQuad(CDecal::CQuadDecal& quad, const CDecalDescription::SQuadDescr& desc)
|
||||
bool CDecal::InitQuad(CQuadDecal& quad, const SQuadDescr& desc)
|
||||
{
|
||||
quad.m_desc = &desc;
|
||||
if (desc.x14_TEX)
|
||||
{
|
||||
if (desc.x0_LFT)
|
||||
@@ -70,11 +88,237 @@ void CDecal::SetGlobalSeed(u16 seed)
|
||||
|
||||
void CDecal::SetMoveRedToAlphaBuffer(bool move)
|
||||
{
|
||||
sMoveRedToAphaBuffer = move;
|
||||
sMoveRedToAlphaBuffer = move;
|
||||
}
|
||||
|
||||
void CDecal::RenderQuad(CQuadDecal& decal, const SQuadDescr& desc) const
|
||||
{
|
||||
zeus::CColor color = zeus::CColor::skWhite;
|
||||
float size = 1.f;
|
||||
zeus::CVector3f offset;
|
||||
if (CColorElement* clr = desc.x10_CLR.get())
|
||||
clr->GetValue(x58_frameIdx, color);
|
||||
if (CRealElement* sze = desc.x4_SZE.get())
|
||||
{
|
||||
sze->GetValue(x58_frameIdx, size);
|
||||
size *= 0.5f;
|
||||
}
|
||||
if (CRealElement* rot = desc.x8_ROT.get())
|
||||
rot->GetValue(x58_frameIdx, decal.x8_rotation);
|
||||
if (CVectorElement* off = desc.xc_OFF.get())
|
||||
{
|
||||
off->GetValue(x58_frameIdx, offset);
|
||||
offset.y = 0.f;
|
||||
}
|
||||
zeus::CTransform modXf = xc_transform;
|
||||
modXf.origin += offset;
|
||||
CGraphics::SetModelMatrix(modXf);
|
||||
|
||||
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<CTexture> 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);
|
||||
|
||||
g_instTexData.emplace_back();
|
||||
SParticleInstanceTex& inst = g_instTexData.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.emplace_back();
|
||||
SParticleInstanceNoTex& inst = g_instNoTexData.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());
|
||||
}
|
||||
}
|
||||
|
||||
void CDecal::RenderMdl() const
|
||||
{
|
||||
const CDecalDescription& desc = *x0_description;
|
||||
zeus::CColor color = zeus::CColor::skWhite;
|
||||
zeus::CVector3f dmop;
|
||||
zeus::CTransform rotXf;
|
||||
|
||||
if (!desc.x5c_25_DMOO)
|
||||
rotXf = xc_transform.getRotation();
|
||||
|
||||
bool dmrtIsConst = false;
|
||||
if (CVectorElement* dmrt = desc.x50_DMRT.get())
|
||||
dmrtIsConst = dmrt->IsFastConstant();
|
||||
|
||||
zeus::CTransform dmrtXf;
|
||||
if (dmrtIsConst)
|
||||
{
|
||||
desc.x50_DMRT->GetValue(x58_frameIdx, const_cast<zeus::CVector3f&>(x60_rotation));
|
||||
dmrtXf = zeus::CTransform::RotateZ(zeus::degToRad(x60_rotation.z));
|
||||
dmrtXf.rotateLocalY(zeus::degToRad(x60_rotation.y));
|
||||
dmrtXf.rotateLocalX(zeus::degToRad(x60_rotation.x));
|
||||
}
|
||||
|
||||
dmrtXf = rotXf * dmrtXf;
|
||||
|
||||
if (CVectorElement* dmopo = desc.x4c_DMOP.get())
|
||||
dmopo->GetValue(x58_frameIdx, dmop);
|
||||
|
||||
zeus::CTransform worldXf = zeus::CTransform::Translate(rotXf * dmop + xc_transform.origin);
|
||||
|
||||
if (dmrtIsConst)
|
||||
{
|
||||
worldXf = worldXf * dmrtXf;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CVectorElement* dmrt = desc.x50_DMRT.get())
|
||||
{
|
||||
zeus::CVector3f dmrtVec;
|
||||
dmrt->GetValue(x58_frameIdx, dmrtVec);
|
||||
dmrtXf = zeus::CTransform::RotateZ(zeus::degToRad(dmrtVec.z));
|
||||
dmrtXf.rotateLocalY(zeus::degToRad(dmrtVec.y));
|
||||
dmrtXf.rotateLocalX(zeus::degToRad(dmrtVec.x));
|
||||
worldXf = worldXf * rotXf * dmrtXf;
|
||||
}
|
||||
else
|
||||
{
|
||||
worldXf = worldXf * dmrtXf;
|
||||
}
|
||||
}
|
||||
|
||||
if (CVectorElement* dmsc = desc.x54_DMSC.get())
|
||||
{
|
||||
zeus::CVector3f dmscVec;
|
||||
dmsc->GetValue(x58_frameIdx, dmscVec);
|
||||
worldXf = worldXf * zeus::CTransform::Scale(dmscVec);
|
||||
}
|
||||
|
||||
if (CColorElement* dmcl = desc.x58_DMCL.get())
|
||||
dmcl->GetValue(x58_frameIdx, color);
|
||||
|
||||
CGraphics::SetModelMatrix(worldXf);
|
||||
|
||||
if (desc.x5c_24_DMAB)
|
||||
{
|
||||
CModelFlags flags(7, 0, 1, color);
|
||||
desc.x38_DMDL.m_token->Draw(flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (color.a == 1.f)
|
||||
{
|
||||
CModelFlags flags(0, 0, 3, zeus::CColor::skWhite);
|
||||
desc.x38_DMDL.m_token->Draw(flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
CModelFlags flags(5, 0, 1, color);
|
||||
desc.x38_DMDL.m_token->Draw(flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDecal::Render() const
|
||||
{
|
||||
CGlobalRandom gr(sDecalRandom);
|
||||
if (x5c_29_modelInvalid && x5c_30_quad2Invalid && x5c_31_quad1Invalid)
|
||||
return;
|
||||
|
||||
CGraphics::DisableAllLights();
|
||||
CParticleGlobals::SetEmitterTime(x58_frameIdx);
|
||||
|
||||
const CDecalDescription& desc = *x0_description;
|
||||
if (desc.x0_Quads[0].x14_TEX && !x5c_31_quad1Invalid)
|
||||
{
|
||||
CParticleGlobals::SetParticleLifetime(x3c_decalQuads[0].x4_lifetime);
|
||||
CParticleGlobals::UpdateParticleLifetimeTweenValues(x58_frameIdx);
|
||||
RenderQuad(const_cast<CQuadDecal&>(x3c_decalQuads[0]), desc.x0_Quads[0]);
|
||||
}
|
||||
if (desc.x0_Quads[1].x14_TEX && !x5c_30_quad2Invalid)
|
||||
{
|
||||
CParticleGlobals::SetParticleLifetime(x3c_decalQuads[1].x4_lifetime);
|
||||
CParticleGlobals::UpdateParticleLifetimeTweenValues(x58_frameIdx);
|
||||
RenderQuad(const_cast<CQuadDecal&>(x3c_decalQuads[1]), desc.x0_Quads[1]);
|
||||
}
|
||||
if (desc.x38_DMDL && !x5c_29_modelInvalid)
|
||||
{
|
||||
CParticleGlobals::SetParticleLifetime(x54_modelLifetime);
|
||||
CParticleGlobals::UpdateParticleLifetimeTweenValues(x58_frameIdx);
|
||||
RenderMdl();
|
||||
}
|
||||
}
|
||||
|
||||
void CDecal::Update(float dt)
|
||||
{
|
||||
if (x58_frameIdx >= x3c_decalQuads[0].x4_lifetime)
|
||||
x5c_31_quad1Invalid = true;
|
||||
if (x58_frameIdx >= x3c_decalQuads[1].x4_lifetime)
|
||||
x5c_30_quad2Invalid = true;
|
||||
if (x58_frameIdx >= x54_modelLifetime)
|
||||
x5c_29_modelInvalid = true;
|
||||
++x58_frameIdx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user