metaforce/Runtime/Particle/CElementGen.cpp

2149 lines
76 KiB
C++
Raw Normal View History

2016-02-08 05:10:17 +00:00
#include "CElementGen.hpp"
#include "CGenDescription.hpp"
2016-02-17 05:20:34 +00:00
#include "CSwooshDescription.hpp"
#include "CElectricDescription.hpp"
2016-02-10 02:00:28 +00:00
#include "CParticleGlobals.hpp"
2016-02-11 22:38:25 +00:00
#include "CParticleSwoosh.hpp"
#include "CParticleElectric.hpp"
2016-03-04 23:04:53 +00:00
#include "Graphics/CModel.hpp"
#include "Graphics/Shaders/CElementGenShaders.hpp"
2018-05-14 21:44:09 +00:00
#include "Character/CActorLights.hpp"
2017-09-10 09:04:51 +00:00
#include "CWarp.hpp"
2016-02-15 04:00:26 +00:00
2016-02-14 03:42:36 +00:00
#define MAX_GLOBAL_PARTICLES 2560
2016-03-04 23:04:53 +00:00
namespace urde
2016-02-08 05:10:17 +00:00
{
2016-03-04 23:04:53 +00:00
static logvisor::Module Log("urde::CElementGen");
2016-02-10 02:00:28 +00:00
URDE_DECL_SPECIALIZE_SHADER(CElementGenShaders)
2017-06-11 02:57:35 +00:00
u16 CElementGen::g_GlobalSeed = 99;
2017-09-05 03:00:19 +00:00
bool CElementGen::g_subtractBlend = false;
2017-03-24 05:30:16 +00:00
2016-02-09 22:52:33 +00:00
int CElementGen::g_ParticleAliveCount;
int CElementGen::g_ParticleSystemAliveCount;
2017-06-04 01:01:09 +00:00
bool CElementGen::g_ParticleSystemInitialized = false;
2017-01-22 17:36:25 +00:00
bool CElementGen::sMoveRedToAlphaBuffer = false;
2017-09-10 09:04:51 +00:00
CParticle* CElementGen::g_currentParticle = nullptr;
2016-02-15 04:00:26 +00:00
2018-03-17 03:41:01 +00:00
std::vector<SParticleInstanceTex> g_instTexData;
std::vector<SParticleInstanceIndTex> g_instIndTexData;
std::vector<SParticleInstanceNoTex> g_instNoTexData;
2016-02-15 04:00:26 +00:00
2016-02-09 22:52:33 +00:00
void CElementGen::Initialize()
{
2017-06-04 01:01:09 +00:00
if (g_ParticleSystemInitialized)
2016-02-11 02:36:21 +00:00
return;
2016-02-09 22:52:33 +00:00
g_ParticleAliveCount = 0;
g_ParticleSystemAliveCount = 0;
2017-06-04 01:01:09 +00:00
g_ParticleSystemInitialized = true;
2016-02-09 22:52:33 +00:00
2016-02-15 04:00:26 +00:00
/* Compile shaders */
TShader<CElementGenShaders>::Initialize();
2016-02-15 04:00:26 +00:00
}
2016-02-16 19:42:24 +00:00
void CElementGen::Shutdown()
{
TShader<CElementGenShaders>::Shutdown();
2016-02-16 19:42:24 +00:00
}
static const size_t ShadClsSizes[] =
{
sizeof(SParticleInstanceTex),
sizeof(SParticleInstanceIndTex),
sizeof(SParticleInstanceNoTex)
};
2016-02-08 05:10:17 +00:00
CElementGen::CElementGen(const TToken<CGenDescription>& gen,
EModelOrientationType orientType,
EOptionalSystemFlags flags)
2017-06-04 01:01:09 +00:00
: x1c_genDesc(gen), x2c_orientType(orientType),
x27c_randState(x94_randomSeed)
2016-02-09 22:52:33 +00:00
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2017-06-04 01:01:09 +00:00
x28_loadedGenDesc = desc;
x26d_27_enableOPTS = (flags & EOptionalSystemFlags::Two) != EOptionalSystemFlags::None;
if (desc->x54_x40_TEXR)
desc->x54_x40_TEXR->GetValueTexture(0).GetObj();
if (desc->x58_x44_TIND)
desc->x58_x44_TIND->GetValueTexture(0).GetObj();
2017-06-04 01:01:09 +00:00
if (CIntElement* seedElem = desc->x1c_x10_SEED.get())
2016-02-09 22:52:33 +00:00
{
int seedVal;
2017-06-04 01:01:09 +00:00
seedElem->GetValue(x74_curFrame, seedVal);
2017-05-06 05:21:42 +00:00
x94_randomSeed = seedVal;
2016-02-09 22:52:33 +00:00
}
2017-05-06 05:21:42 +00:00
x27c_randState.SetSeed(x94_randomSeed);
2016-02-09 22:52:33 +00:00
++g_ParticleSystemAliveCount;
2017-06-04 01:01:09 +00:00
x26c_25_LIT_ = desc->x44_29_x30_29_LIT_;
x26c_26_AAPH = desc->x44_26_x30_26_AAPH;
x26c_27_ZBUF = desc->x44_27_x30_27_ZBUF;
x26c_28_zTest = true;
x26c_29_ORNT = desc->x30_30_ORNT;
x26c_30_MBLR = x26c_29_ORNT ? false : desc->x44_30_x31_24_MBLR;
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CIntElement* mbspElem = desc->x48_x34_MBSP.get())
mbspElem->GetValue(x74_curFrame, x270_MBSP);
m_maxMBSP = x270_MBSP;
if (CModVectorElement* elem = desc->x7c_x68_VEL1.get())
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
x280_VELSources[0] = elem;
x278_hasVMD[0] = desc->x45_26_x31_28_VMD1;
}
if (CModVectorElement* elem = desc->x80_x6c_VEL2.get())
{
x280_VELSources[1] = elem;
x278_hasVMD[1] = desc->x45_27_x31_29_VMD2;
}
if (CModVectorElement* elem = desc->x84_x70_VEL3.get())
{
x280_VELSources[2] = elem;
x278_hasVMD[2] = desc->x45_28_x31_30_VMD3;
}
if (CModVectorElement* elem = desc->x88_x74_VEL4.get())
{
x280_VELSources[3] = elem;
x278_hasVMD[3] = desc->x45_29_x31_31_VMD4;
2016-02-09 22:52:33 +00:00
}
2017-06-04 01:01:09 +00:00
if (desc->x10c_ADV1 || desc->x110_ADV2 || desc->x114_ADV3 || desc->x118_ADV4 ||
desc->x11c_ADV5 || desc->x120_ADV6 || desc->x124_ADV7 || desc->x128_ADV8)
x26d_28_enableADV = true;
if (CIntElement* cssdElem = desc->xa0_x8c_CSSD.get())
cssdElem->GetValue(0, x2a0_CSSD);
if (CIntElement* pisyElem = desc->xc8_xb4_PISY.get())
2016-02-09 22:52:33 +00:00
{
2017-05-06 05:21:42 +00:00
pisyElem->GetValue(0, x2a8_PISY);
if (x2a8_PISY <= 0)
x2a8_PISY = 1;
2016-02-09 22:52:33 +00:00
}
2017-06-04 01:01:09 +00:00
if (CIntElement* sisyElem = desc->xcc_xb8_SISY.get())
sisyElem->GetValue(0, x2a4_SISY);
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CIntElement* sssdElem = desc->xe4_xd0_SSSD.get())
2017-05-06 05:21:42 +00:00
sssdElem->GetValue(0, x2ac_SSSD);
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CVectorElement* sspoElem = desc->xe8_xd4_SSPO.get())
2017-05-06 05:21:42 +00:00
{
sspoElem->GetValue(0, x2b0_SSPO);
if (!sspoElem->IsFastConstant())
2017-06-04 01:01:09 +00:00
x26c_24_translationDirty = true;
2017-05-06 05:21:42 +00:00
}
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CIntElement* sesdElem = desc->xf8_xe4_SESD.get())
2017-05-06 05:21:42 +00:00
sesdElem->GetValue(0, x2bc_SESD);
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CVectorElement* sepoElem = desc->xfc_xe8_SEPO.get())
2017-05-06 05:21:42 +00:00
{
sepoElem->GetValue(0, x2c0_SEPO);
if (!sepoElem->IsFastConstant())
2017-06-04 01:01:09 +00:00
x26c_24_translationDirty = true;
2017-05-06 05:21:42 +00:00
}
2017-06-04 01:01:09 +00:00
if (CVectorElement* pofsElem = desc->x18_xc_POFS.get())
2017-05-06 05:21:42 +00:00
{
2017-06-04 01:01:09 +00:00
pofsElem->GetValue(x74_curFrame, xf4_POFS);
2017-05-06 05:21:42 +00:00
if (!pofsElem->IsFastConstant())
2017-06-04 01:01:09 +00:00
x26c_24_translationDirty = true;
2017-05-06 05:21:42 +00:00
}
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CIntElement* psltElem = desc->xc_x0_PSLT.get())
2017-05-06 05:21:42 +00:00
psltElem->GetValue(0, x268_PSLT);
else
x268_PSLT = INT_MAX;
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CIntElement* maxpElem = desc->x28_x1c_MAXP.get())
maxpElem->GetValue(x74_curFrame, x90_MAXP);
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
int useMAXP = std::min(x90_MAXP, 256);
x30_particles.reserve(useMAXP);
if (x2c_orientType == EModelOrientationType::One)
x50_parentMatrices.resize(useMAXP);
2016-02-09 22:52:33 +00:00
2017-05-06 05:21:42 +00:00
x26c_31_LINE = desc->x44_24_x30_24_LINE;
x26d_24_FXLL = desc->x44_25_x30_25_FXLL;
2016-02-09 22:52:33 +00:00
2017-06-04 01:01:09 +00:00
if (CIntElement* ltypElem = desc->x100_xec_LTYP.get())
2016-02-09 22:52:33 +00:00
{
int ltyp;
2017-06-04 01:01:09 +00:00
ltypElem->GetValue(x74_curFrame, ltyp);
switch (LightType(ltyp))
2016-02-09 22:52:33 +00:00
{
case LightType::None:
2016-02-09 22:52:33 +00:00
default:
2017-05-06 05:21:42 +00:00
x308_lightType = LightType::None;
2016-02-09 22:52:33 +00:00
break;
case LightType::Directional:
2017-05-06 05:21:42 +00:00
x308_lightType = LightType::Directional;
2016-02-09 22:52:33 +00:00
break;
case LightType::Custom:
2017-05-06 05:21:42 +00:00
x308_lightType = LightType::Custom;
2016-02-09 22:52:33 +00:00
break;
case LightType::Spot:
2017-05-06 05:21:42 +00:00
x308_lightType = LightType::Spot;
2016-02-09 22:52:33 +00:00
break;
}
}
2017-06-04 01:01:09 +00:00
if (CIntElement* lfotElem = desc->x114_x100_LFOT.get())
2016-02-09 22:52:33 +00:00
{
int lfot;
2017-06-04 01:01:09 +00:00
lfotElem->GetValue(x74_curFrame, lfot);
2016-02-09 22:52:33 +00:00
switch (EFalloffType(lfot))
{
case EFalloffType::Constant:
2017-05-06 05:21:42 +00:00
x32c_falloffType = EFalloffType::Constant;
2016-02-09 22:52:33 +00:00
break;
case EFalloffType::Linear:
default:
2017-05-06 05:21:42 +00:00
x32c_falloffType = EFalloffType::Linear;
2016-02-09 22:52:33 +00:00
break;
case EFalloffType::Quadratic:
2017-05-06 05:21:42 +00:00
x32c_falloffType = EFalloffType::Quadratic;
2016-02-09 22:52:33 +00:00
break;
}
}
2016-02-15 04:00:26 +00:00
2017-05-06 05:21:42 +00:00
if (x26c_31_LINE)
2016-02-15 04:00:26 +00:00
{
2016-03-03 01:06:42 +00:00
CUVElement* texr = desc->x54_x40_TEXR.get();
boo::ObjToken<boo::ITexture> tex;
if (texr)
tex = texr->GetValueTexture(0).GetObj()->GetBooTexture();
2017-05-06 05:21:42 +00:00
int maxVerts = (x90_MAXP == 0 ? 256 : x90_MAXP);
m_lineRenderer.reset(new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines,
2017-06-04 01:01:09 +00:00
maxVerts * 2, tex, x26c_26_AAPH));
}
else
{
m_shaderClass = CElementGenShaders::GetShaderClass(*this);
}
size_t maxInsts = x26c_30_MBLR ? (m_maxMBSP * x90_MAXP) : x90_MAXP;
maxInsts = (maxInsts == 0 ? 256 : maxInsts);
CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) -> bool
{
if (!x26c_31_LINE)
2016-03-30 19:16:01 +00:00
{
m_instBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[int(m_shaderClass)], maxInsts);
m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
}
if (desc->x45_24_x31_26_PMUS)
{
m_instBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Vertex, ShadClsSizes[int(m_shaderClass)], maxInsts);
m_uniformBufPmus = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(SParticleUniforms), 1);
}
CElementGenShaders::BuildShaderDataBinding(ctx, *this);
return true;
});
2016-02-09 22:52:33 +00:00
}
CElementGen::~CElementGen()
{
--g_ParticleSystemAliveCount;
2017-06-04 01:01:09 +00:00
g_ParticleAliveCount -= x30_particles.size();
2016-02-09 22:52:33 +00:00
}
bool CElementGen::Update(double t)
2016-02-10 02:00:28 +00:00
{
CParticleGlobals::SParticleSystem* prevSystem = CParticleGlobals::g_currentParticleSystem;
CParticleGlobals::SParticleSystem thisSystem { FOURCC('PART'), this };
CParticleGlobals::g_currentParticleSystem = &thisSystem;
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2016-03-03 01:06:42 +00:00
CIntElement* pswtElem = desc->x10_x4_PSWT.get();
2017-06-04 01:01:09 +00:00
if (pswtElem && !x26d_25_warmedUp)
2016-02-10 02:00:28 +00:00
{
int pswt = 0;
2017-06-04 01:01:09 +00:00
pswtElem->GetValue(x74_curFrame, pswt);
Log.report(logvisor::Info,
"Running warmup on particle system 0x%08x for %d ticks.",
desc, pswt);
InternalUpdate(pswt / 60.0);
x26d_25_warmedUp = true;
2016-02-10 02:00:28 +00:00
}
bool ret = InternalUpdate(t);
CParticleGlobals::g_currentParticleSystem = prevSystem;
return ret;
2016-02-10 02:00:28 +00:00
}
bool CElementGen::InternalUpdate(double dt)
{
2017-05-06 05:21:42 +00:00
CGlobalRandom gr(x27c_randState);
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2016-02-10 02:00:28 +00:00
2016-03-04 23:04:53 +00:00
double dt1 = 1.0 / 60.0;
if (std::fabs(dt - 1.0 / 60.0) >= 1.0 / 60000.0)
2016-02-10 02:00:28 +00:00
dt1 = dt;
2017-06-04 01:01:09 +00:00
double t = x74_curFrame / 60.0;
CParticleGlobals::SetEmitterTime(x74_curFrame);
2016-02-10 02:00:28 +00:00
2017-06-04 01:01:09 +00:00
if (CRealElement* pstsElem = desc->x14_x8_PSTS.get())
2016-02-10 02:00:28 +00:00
{
float psts;
2017-06-04 01:01:09 +00:00
pstsElem->GetValue(x74_curFrame, psts);
2016-02-10 02:00:28 +00:00
double dt1Scaled = psts * dt1;
dt1 = std::max(0.0, dt1Scaled);
}
2017-06-04 01:01:09 +00:00
x78_curSeconds += dt1;
2016-02-10 02:00:28 +00:00
2017-06-04 01:01:09 +00:00
if (x26c_30_MBLR && dt > 0.0)
2016-02-10 02:00:28 +00:00
{
2017-06-04 01:01:09 +00:00
if (CIntElement* mbspElem = desc->x48_x34_MBSP.get())
mbspElem->GetValue(x74_curFrame, x270_MBSP);
x270_MBSP = std::min(x270_MBSP, m_maxMBSP);
2016-02-10 02:00:28 +00:00
}
int frameUpdateCount = 0;
2017-06-04 01:01:09 +00:00
while (t < x78_curSeconds && std::fabs(t - x78_curSeconds) >= 1.0 / 60000.0)
{
x2d4_aabbMin.splat(FLT_MAX);
2017-12-10 05:30:01 +00:00
x2e0_aabbMax.splat(-FLT_MAX);
2017-06-04 01:01:09 +00:00
x2ec_maxSize = 0.f;
CParticleGlobals::SetEmitterTime(x74_curFrame);
UpdateExistingParticles();
CParticleGlobals::SetParticleLifetime(x268_PSLT);
2016-02-10 02:00:28 +00:00
2017-06-04 01:01:09 +00:00
if (x74_curFrame < x268_PSLT && x88_particleEmission)
{
float grte = 0.f;
if (CRealElement* grteElem = desc->x2c_x20_GRTE.get())
{
if (grteElem->GetValue(x74_curFrame, grte))
{
x30_particles.clear();
return true;
}
}
2016-02-10 02:00:28 +00:00
2017-06-04 01:01:09 +00:00
grte = std::max(0.f, grte * x98_generatorRate);
x8c_generatorRemainder += grte;
int genCount = floorf(x8c_generatorRemainder);
x8c_generatorRemainder = x8c_generatorRemainder - genCount;
2016-02-10 02:00:28 +00:00
2017-06-04 01:01:09 +00:00
if (CIntElement* maxpElem = desc->x28_x1c_MAXP.get())
maxpElem->GetValue(x74_curFrame, x90_MAXP);
2016-02-10 02:00:28 +00:00
2017-06-04 01:01:09 +00:00
CreateNewParticles(genCount);
}
2016-02-10 02:00:28 +00:00
2017-06-04 01:01:09 +00:00
if (x26c_24_translationDirty)
UpdatePSTranslationAndOrientation();
2016-02-10 02:00:28 +00:00
2017-05-06 05:21:42 +00:00
if (x308_lightType != LightType::None)
2016-02-10 02:00:28 +00:00
UpdateLightParameters();
2017-06-04 01:01:09 +00:00
UpdateChildParticleSystems(1 / 60.0);
2016-02-10 02:00:28 +00:00
++frameUpdateCount;
2017-06-04 01:01:09 +00:00
++x74_curFrame;
2016-02-10 02:00:28 +00:00
t += 1 / 60.0;
}
2017-06-04 01:01:09 +00:00
if (std::fabs(t - x78_curSeconds) < 1.0 / 60000.0)
{
x78_curSeconds = t;
x80_timeDeltaScale = 1.f;
}
else
{
UpdateChildParticleSystems(dt1 - (frameUpdateCount / 60.0));
x80_timeDeltaScale = 1.f - (t - x78_curSeconds) * 60.f;
}
2016-02-10 02:00:28 +00:00
BuildParticleSystemBounds();
return false;
}
2016-03-04 23:04:53 +00:00
void CElementGen::AccumulateBounds(zeus::CVector3f& pos, float size)
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
x2e0_aabbMax[0] = std::max(pos[0], x2e0_aabbMax[0]);
x2e0_aabbMax[1] = std::max(pos[1], x2e0_aabbMax[1]);
x2e0_aabbMax[2] = std::max(pos[2], x2e0_aabbMax[2]);
x2d4_aabbMin[0] = std::min(pos[0], x2d4_aabbMin[0]);
x2d4_aabbMin[1] = std::min(pos[1], x2d4_aabbMin[1]);
x2d4_aabbMin[2] = std::min(pos[2], x2d4_aabbMin[2]);
x2ec_maxSize = std::max(size, x2ec_maxSize);
}
void CElementGen::UpdateAdvanceAccessParameters(u32 activeParticleCount, u32 particleFrame)
{
CGenDescription* desc = x1c_genDesc.GetObj();
std::array<float, 8>& arr = x60_advValues[activeParticleCount];
CParticleGlobals::g_particleAccessParameters = &arr;
if (CRealElement* adv1 = desc->x10c_ADV1.get())
adv1->GetValue(particleFrame, arr[0]);
if (CRealElement* adv2 = desc->x110_ADV2.get())
adv2->GetValue(particleFrame, arr[1]);
if (CRealElement* adv3 = desc->x114_ADV3.get())
adv3->GetValue(particleFrame, arr[2]);
if (CRealElement* adv4 = desc->x118_ADV4.get())
adv4->GetValue(particleFrame, arr[3]);
if (CRealElement* adv5 = desc->x11c_ADV5.get())
adv5->GetValue(particleFrame, arr[4]);
if (CRealElement* adv6 = desc->x120_ADV6.get())
adv6->GetValue(particleFrame, arr[5]);
if (CRealElement* adv7 = desc->x124_ADV7.get())
adv7->GetValue(particleFrame, arr[6]);
if (CRealElement* adv8 = desc->x128_ADV8.get())
adv8->GetValue(particleFrame, arr[7]);
}
bool CElementGen::UpdateVelocitySource(u32 idx, u32 particleFrame, CParticle& particle)
{
bool err;
if (x278_hasVMD[idx])
{
zeus::CVector3f localVel = x208_orientationInverse * particle.x1c_vel;
zeus::CVector3f localPos = x208_orientationInverse * (particle.x4_pos - xdc_translation);
err = x280_VELSources[idx]->GetValue(particleFrame, localVel, localPos);
particle.x1c_vel = x1d8_orientation.rotate(localVel);
particle.x4_pos = x1d8_orientation.rotate(localVel) + xdc_translation;
}
else
{
err = x280_VELSources[idx]->GetValue(particleFrame, particle.x1c_vel, particle.x4_pos);
}
if (err)
{
particle.x0_endFrame = -1;
return true;
}
return false;
2016-02-11 02:36:21 +00:00
}
2016-02-10 02:00:28 +00:00
void CElementGen::UpdateExistingParticles()
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2017-06-04 01:01:09 +00:00
x25c_activeParticleCount = 0;
CParticleGlobals::SetEmitterTime(x74_curFrame);
CParticleGlobals::g_particleAccessParameters = &x60_advValues[x25c_activeParticleCount];
2017-06-04 01:01:09 +00:00
for (auto it = x30_particles.begin(); it != x30_particles.end();)
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
CParticle& particle = *it;
2016-02-25 06:23:35 +00:00
2017-06-04 01:01:09 +00:00
if (particle.x0_endFrame < x74_curFrame)
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
--g_ParticleAliveCount;
if (it+1 == x30_particles.end())
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
x30_particles.pop_back();
2016-02-11 02:36:21 +00:00
break;
}
else
{
2017-06-04 01:01:09 +00:00
particle = x30_particles.back();
if (x2c_orientType == EModelOrientationType::One)
x50_parentMatrices[x25c_activeParticleCount] = x50_parentMatrices[x30_particles.size()-1];
if (x26d_28_enableADV)
x60_advValues[x25c_activeParticleCount] = x60_advValues[x30_particles.size()-1];
x30_particles.pop_back();
if (particle.x0_endFrame < x74_curFrame)
continue;
2016-02-11 02:36:21 +00:00
}
}
2017-06-04 01:01:09 +00:00
particle.x10_prevPos = particle.x4_pos;
particle.x4_pos += particle.x1c_vel;
g_currentParticle = &particle;
2016-02-11 02:36:21 +00:00
CParticleGlobals::SetParticleLifetime(particle.x0_endFrame - particle.x28_startFrame);
2017-06-04 01:01:09 +00:00
int particleFrame = x74_curFrame - particle.x28_startFrame;
2016-02-11 02:36:21 +00:00
CParticleGlobals::UpdateParticleLifetimeTweenValues(particleFrame);
2017-06-04 01:01:09 +00:00
if (x26d_28_enableADV)
UpdateAdvanceAccessParameters(x25c_activeParticleCount, particleFrame);
2016-02-11 02:36:21 +00:00
2017-06-04 01:01:09 +00:00
++x25c_activeParticleCount;
2016-02-11 02:36:21 +00:00
2017-06-04 01:01:09 +00:00
for (int i=0 ; i<4 ; ++i)
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
if (!x280_VELSources[i])
break;
UpdateVelocitySource(i, particleFrame, particle);
2016-02-11 02:36:21 +00:00
}
2017-05-06 05:21:42 +00:00
if (x26c_31_LINE)
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
if (CRealElement* leng = desc->x20_x14_LENG.get())
leng->GetValue(particleFrame, particle.x2c_lineLengthOrSize);
if (CRealElement* widt = desc->x24_x18_WIDT.get())
widt->GetValue(particleFrame, particle.x30_lineWidthOrRota);
2016-02-11 02:36:21 +00:00
}
else
{
2017-06-04 01:01:09 +00:00
if (CRealElement* rota = desc->x50_x3c_ROTA.get())
rota->GetValue(particleFrame, particle.x30_lineWidthOrRota);
if (CRealElement* size = desc->x4c_x38_SIZE.get())
size->GetValue(particleFrame, particle.x2c_lineLengthOrSize);
2016-02-11 02:36:21 +00:00
}
2017-06-04 01:01:09 +00:00
if (CColorElement* colr = desc->x30_x24_COLR.get())
colr->GetValue(particleFrame, particle.x34_color);
2016-02-11 02:36:21 +00:00
AccumulateBounds(particle.x4_pos, particle.x2c_lineLengthOrSize);
2017-06-04 01:01:09 +00:00
++it;
2016-02-11 02:36:21 +00:00
}
2017-09-10 09:04:51 +00:00
if (x30_particles.empty())
return;
for (CWarp* warp : x4_modifierList)
if (warp->UpdateWarp())
warp->ModifyParticles(x30_particles);
2016-02-10 02:00:28 +00:00
}
2016-02-11 02:36:21 +00:00
void CElementGen::CreateNewParticles(int count)
2016-02-10 02:00:28 +00:00
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2017-06-04 01:01:09 +00:00
if (!g_ParticleSystemInitialized)
2016-02-11 02:36:21 +00:00
Initialize();
2017-06-04 01:01:09 +00:00
if (!count || x30_particles.size() >= x90_MAXP)
2016-02-11 02:36:21 +00:00
return;
2017-06-04 01:01:09 +00:00
if (count + x30_particles.size() > x90_MAXP)
count = x90_MAXP - x30_particles.size();
int newTotalCount = g_ParticleAliveCount + count;
if (newTotalCount > 2560)
count = 2560 - g_ParticleAliveCount;
2017-05-06 05:21:42 +00:00
CGlobalRandom gr(x27c_randState);
2017-06-04 01:01:09 +00:00
x30_particles.reserve(x90_MAXP);
if (x26d_28_enableADV && x60_advValues.empty())
x60_advValues.resize(x90_MAXP);
CParticleGlobals::g_particleAccessParameters = nullptr;
2016-02-11 02:36:21 +00:00
for (int i=0 ; i<count ; ++i)
{
2017-06-04 01:01:09 +00:00
x30_particles.emplace_back();
++g_ParticleAliveCount;
++x25c_activeParticleCount;
++x260_cumulativeParticles;
if (x2c_orientType == EModelOrientationType::One)
x50_parentMatrices[x30_particles.size()-1] = x1d8_orientation.buildMatrix3f();
2016-02-11 02:36:21 +00:00
2017-09-10 09:04:51 +00:00
CParticle& particle = x30_particles.back();
2017-06-04 01:01:09 +00:00
particle.x28_startFrame = x74_curFrame;
if (CIntElement* ltme = desc->x34_x28_LTME.get())
2016-02-11 02:36:21 +00:00
ltme->GetValue(0, particle.x0_endFrame);
CParticleGlobals::SetParticleLifetime(particle.x0_endFrame);
CParticleGlobals::UpdateParticleLifetimeTweenValues(0);
2017-06-04 01:01:09 +00:00
g_currentParticle = &particle;
if (x26d_28_enableADV)
UpdateAdvanceAccessParameters(x30_particles.size()-1, 0);
particle.x0_endFrame += x74_curFrame;
2016-02-11 02:36:21 +00:00
2017-06-04 01:01:09 +00:00
if (CColorElement* colr = desc->x30_x24_COLR.get())
2016-02-11 02:36:21 +00:00
colr->GetValue(0, particle.x34_color);
else
2016-03-04 23:04:53 +00:00
particle.x34_color = zeus::CColor::skWhite;
2016-02-11 02:36:21 +00:00
2017-06-04 01:01:09 +00:00
if (CEmitterElement* emtr = desc->x40_x2c_EMTR.get())
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
emtr->GetValue(x74_curFrame, particle.x4_pos, particle.x1c_vel);
zeus::CVector3f compXf1 = (x13c_globalScaleTransformInverse * x1a8_localScaleTransformInverse) * xdc_translation;
zeus::CVector3f compXf2 = x1d8_orientation.rotate(particle.x4_pos);
2017-05-06 05:21:42 +00:00
particle.x4_pos = compXf1 + compXf2 + xf4_POFS;
2017-06-04 01:01:09 +00:00
particle.x1c_vel = x1d8_orientation.rotate(particle.x1c_vel);
2016-02-11 02:36:21 +00:00
}
else
{
2017-06-04 01:01:09 +00:00
zeus::CVector3f compXf1 = (x13c_globalScaleTransformInverse * x1a8_localScaleTransformInverse) * xdc_translation;
2017-05-06 05:21:42 +00:00
particle.x4_pos = compXf1 + xf4_POFS;
2016-02-11 02:36:21 +00:00
particle.x1c_vel.zeroOut();
}
particle.x10_prevPos = particle.x4_pos;
2017-05-06 05:21:42 +00:00
if (x26c_31_LINE)
2016-02-11 02:36:21 +00:00
{
2017-06-04 01:01:09 +00:00
if (CRealElement* leng = desc->x20_x14_LENG.get())
2016-02-11 02:36:21 +00:00
leng->GetValue(0, particle.x2c_lineLengthOrSize);
else
particle.x2c_lineLengthOrSize = 1.f;
2017-06-04 01:01:09 +00:00
if (CRealElement* widt = desc->x24_x18_WIDT.get())
2016-02-11 02:36:21 +00:00
widt->GetValue(0, particle.x30_lineWidthOrRota);
else
particle.x30_lineWidthOrRota = 1.f;
}
else
{
2017-06-04 01:01:09 +00:00
if (CRealElement* rota = desc->x50_x3c_ROTA.get())
2016-02-11 02:36:21 +00:00
rota->GetValue(0, particle.x30_lineWidthOrRota);
else
particle.x30_lineWidthOrRota = 0.f;
2017-06-04 01:01:09 +00:00
if (CRealElement* size = desc->x4c_x38_SIZE.get())
2016-02-11 02:36:21 +00:00
size->GetValue(0, particle.x2c_lineLengthOrSize);
else
particle.x2c_lineLengthOrSize = 0.1f;
}
AccumulateBounds(particle.x4_pos, particle.x2c_lineLengthOrSize);
}
2016-02-10 02:00:28 +00:00
}
void CElementGen::UpdatePSTranslationAndOrientation()
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2017-05-06 05:21:42 +00:00
CGlobalRandom gr(x27c_randState);
2017-06-04 01:01:09 +00:00
if (x268_PSLT < x74_curFrame)
2016-02-11 02:36:21 +00:00
return;
2017-06-04 01:01:09 +00:00
if (CVectorElement* pofs = desc->x18_xc_POFS.get())
pofs->GetValue(x74_curFrame, xf4_POFS);
2016-02-11 02:36:21 +00:00
2017-06-04 01:01:09 +00:00
if (CVectorElement* sspo = desc->xe8_xd4_SSPO.get())
sspo->GetValue(x74_curFrame, x2b0_SSPO);
2016-02-11 02:36:21 +00:00
2017-06-04 01:01:09 +00:00
if (CVectorElement* sepo = desc->xfc_xe8_SEPO.get())
sepo->GetValue(x74_curFrame, x2c0_SEPO);
2016-02-10 02:00:28 +00:00
}
2017-06-04 01:01:09 +00:00
std::unique_ptr<CParticleGen> CElementGen::ConstructChildParticleSystem(const TToken<CGenDescription>& desc)
2016-02-11 06:58:33 +00:00
{
2016-02-11 22:38:25 +00:00
CElementGen* ret = new CElementGen(desc, EModelOrientationType::Normal,
2017-06-04 01:01:09 +00:00
x26d_27_enableOPTS ? EOptionalSystemFlags::Two : EOptionalSystemFlags::One);
ret->x26d_26_modelsUseLights = x26d_26_modelsUseLights;
ret->SetGlobalTranslation(xe8_globalTranslation);
ret->SetGlobalOrientation(x22c_globalOrientation);
ret->SetGlobalScale(x100_globalScale);
ret->SetLocalScale(x16c_localScale);
ret->SetTranslation(xdc_translation);
ret->SetOrientation(x1d8_orientation);
ret->SetParticleEmission(x88_particleEmission);
ret->SetModulationColor(x338_moduColor);
return std::unique_ptr<CParticleGen>(ret);
2016-02-11 06:58:33 +00:00
}
2016-02-10 02:00:28 +00:00
void CElementGen::UpdateChildParticleSystems(double dt)
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2017-05-06 05:21:42 +00:00
CGlobalRandom gr(x27c_randState);
2017-06-04 01:01:09 +00:00
2016-03-03 01:06:42 +00:00
SChildGeneratorDesc& icts = desc->x8c_x78_ICTS;
2017-06-04 01:01:09 +00:00
if (icts.m_found && x84_prevFrame != x74_curFrame && x2a0_CSSD == x74_curFrame)
2016-02-11 06:58:33 +00:00
{
int ncsyVal = 1;
2017-06-04 01:01:09 +00:00
if (CIntElement* ncsy = desc->x9c_x88_NCSY.get())
ncsy->GetValue(x74_curFrame, ncsyVal);
2016-02-11 06:58:33 +00:00
CGenDescription* ictsDesc = icts.m_token.GetObj();
2017-06-04 01:01:09 +00:00
if (!(x26d_27_enableOPTS && ictsDesc->x45_31_x32_25_OPTS))
2016-02-11 06:58:33 +00:00
{
2017-05-06 05:21:42 +00:00
x290_activePartChildren.reserve(ncsyVal + x290_activePartChildren.size());
2016-02-11 06:58:33 +00:00
for (int i=0 ; i<ncsyVal ; ++i)
{
2017-06-04 01:01:09 +00:00
std::unique_ptr<CParticleGen> chGen = ConstructChildParticleSystem(icts.m_token);
x290_activePartChildren.emplace_back(std::move(chGen));
2016-02-11 06:58:33 +00:00
}
}
}
2016-03-03 01:06:42 +00:00
SChildGeneratorDesc& iits = desc->xb8_xa4_IITS;
2017-06-04 01:01:09 +00:00
if (iits.m_found && x84_prevFrame != x74_curFrame && x74_curFrame < x268_PSLT &&
x88_particleEmission == 1 && x74_curFrame >= x2a4_SISY &&
((x74_curFrame - x2a4_SISY) % x2a8_PISY) == 0)
2016-02-11 06:58:33 +00:00
{
CGenDescription* iitsDesc = iits.m_token.GetObj();
2017-06-04 01:01:09 +00:00
if (!(x26d_27_enableOPTS && iitsDesc->x45_31_x32_25_OPTS))
2016-02-11 06:58:33 +00:00
{
2017-06-04 01:01:09 +00:00
std::unique_ptr<CParticleGen> chGen = ConstructChildParticleSystem(iits.m_token);
x290_activePartChildren.emplace_back(std::move(chGen));
2016-02-11 06:58:33 +00:00
}
}
2016-03-03 01:06:42 +00:00
CSpawnSystemKeyframeData* kssm = desc->xd0_xbc_KSSM.get();
2017-06-04 01:01:09 +00:00
if (kssm && x84_prevFrame != x74_curFrame && x74_curFrame < x268_PSLT)
2016-02-11 22:38:25 +00:00
{
2017-06-11 02:57:35 +00:00
u16 backupSeed = g_GlobalSeed;
u16 incSeed = backupSeed;
2017-06-04 01:01:09 +00:00
2016-02-11 22:38:25 +00:00
std::vector<CSpawnSystemKeyframeData::CSpawnSystemKeyframeInfo>& systems =
2017-06-04 01:01:09 +00:00
kssm->GetSpawnedSystemsAtFrame(x74_curFrame);
2017-05-06 05:21:42 +00:00
x290_activePartChildren.reserve(x290_activePartChildren.size() + systems.size());
2016-02-11 22:38:25 +00:00
for (CSpawnSystemKeyframeData::CSpawnSystemKeyframeInfo& system : systems)
{
TLockedToken<CGenDescription>& token = system.GetToken();
2017-06-04 01:01:09 +00:00
if (!(x26d_27_enableOPTS && token.GetObj()->x45_31_x32_25_OPTS))
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
g_GlobalSeed = incSeed;
std::unique_ptr<CParticleGen> chGen = ConstructChildParticleSystem(token);
x290_activePartChildren.emplace_back(std::move(chGen));
2016-02-11 22:38:25 +00:00
}
2017-06-11 02:57:35 +00:00
incSeed += 1;
2016-02-11 22:38:25 +00:00
}
2017-06-04 01:01:09 +00:00
g_GlobalSeed = backupSeed;
2016-02-11 22:38:25 +00:00
}
2017-06-04 01:01:09 +00:00
SChildGeneratorDesc& idts = desc->xa4_x90_IDTS;
if (idts.m_found && x74_curFrame == x268_PSLT && x84_prevFrame != x74_curFrame)
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
int ndsyVal = 1;
if (CIntElement* ndsy = desc->xb4_xa0_NDSY.get())
ndsy->GetValue(0, ndsyVal);
2016-02-11 22:38:25 +00:00
2017-06-04 01:01:09 +00:00
CGenDescription* idtsDesc = idts.m_token.GetObj();
if (!(x26d_27_enableOPTS && idtsDesc->x45_31_x32_25_OPTS))
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
x290_activePartChildren.reserve(ndsyVal + x290_activePartChildren.size());
for (int i=0 ; i<ndsyVal ; ++i)
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
std::unique_ptr<CParticleGen> chGen = ConstructChildParticleSystem(idts.m_token);
x290_activePartChildren.emplace_back(std::move(chGen));
2016-02-11 22:38:25 +00:00
}
}
}
2017-06-04 01:01:09 +00:00
SSwooshGeneratorDesc& sswh = desc->xd4_xc0_SSWH;
if (sswh.m_found && x84_prevFrame != x74_curFrame && x74_curFrame == x2ac_SSSD)
{
std::unique_ptr<CParticleGen> sswhGen = std::make_unique<CParticleSwoosh>(sswh.m_token, 0);
sswhGen->SetGlobalTranslation(xe8_globalTranslation);
sswhGen->SetGlobalScale(x100_globalScale);
sswhGen->SetLocalScale(x16c_localScale);
sswhGen->SetTranslation(xdc_translation + x2b0_SSPO);
sswhGen->SetOrientation(x1d8_orientation);
sswhGen->SetParticleEmission(x88_particleEmission);
x290_activePartChildren.emplace_back(std::move(sswhGen));
}
2016-02-11 22:38:25 +00:00
2017-06-04 01:01:09 +00:00
SElectricGeneratorDesc& selc = desc->xec_xd8_SELC;
if (selc.m_found && x84_prevFrame != x74_curFrame && x74_curFrame == x2bc_SESD)
{
std::unique_ptr<CParticleGen> selcGen = std::make_unique<CParticleElectric>(selc.m_token);
selcGen->SetGlobalTranslation(xe8_globalTranslation);
selcGen->SetGlobalScale(x100_globalScale);
selcGen->SetLocalScale(x16c_localScale);
selcGen->SetTranslation(xdc_translation + x2c0_SEPO);
selcGen->SetOrientation(x1d8_orientation);
selcGen->SetParticleEmission(x88_particleEmission);
x290_activePartChildren.emplace_back(std::move(selcGen));
2016-02-11 22:38:25 +00:00
}
2017-06-04 01:01:09 +00:00
for (auto p = x290_activePartChildren.begin() ; p != x290_activePartChildren.end() ;)
2016-02-11 06:58:33 +00:00
{
2017-06-04 01:01:09 +00:00
std::unique_ptr<CParticleGen>& ch = *p;
2016-02-11 22:38:25 +00:00
ch->Update(dt);
if (ch->IsSystemDeletable())
{
2017-06-04 01:01:09 +00:00
p = x290_activePartChildren.erase(p);
2016-02-11 22:38:25 +00:00
continue;
}
++p;
2016-02-11 06:58:33 +00:00
}
2017-06-04 01:01:09 +00:00
x84_prevFrame = x74_curFrame;
2016-02-10 02:00:28 +00:00
}
void CElementGen::UpdateLightParameters()
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2017-06-04 01:01:09 +00:00
if (CColorElement* lclr = desc->x104_xf0_LCLR.get())
lclr->GetValue(x74_curFrame, x30c_LCLR);
2016-02-11 22:38:25 +00:00
2017-06-04 01:01:09 +00:00
if (CRealElement* lint = desc->x108_xf4_LINT.get())
lint->GetValue(x74_curFrame, x310_LINT);
2016-02-11 22:38:25 +00:00
2017-05-06 05:21:42 +00:00
switch (x308_lightType)
2016-02-11 22:38:25 +00:00
{
default:
case LightType::None:
case LightType::Custom:
case LightType::Spot:
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
if (CVectorElement* loff = desc->x10c_xf8_LOFF.get())
loff->GetValue(x74_curFrame, x314_LOFF);
2016-02-11 22:38:25 +00:00
2017-06-04 01:01:09 +00:00
if (CRealElement* lfor = desc->x118_x104_LFOR.get())
lfor->GetValue(x74_curFrame, x330_LFOR);
2016-02-11 22:38:25 +00:00
2017-05-06 05:21:42 +00:00
if (x308_lightType == LightType::Spot)
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
if (CRealElement* lsla = desc->x11c_x108_LSLA.get())
lsla->GetValue(x74_curFrame, x334_LSLA);
2016-02-11 22:38:25 +00:00
}
}
case LightType::Directional:
2016-02-11 22:38:25 +00:00
{
2017-05-06 05:21:42 +00:00
if (x308_lightType != LightType::Custom)
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
if (CVectorElement* ldir = desc->x110_xfc_LDIR.get())
ldir->GetValue(x74_curFrame, x320_LDIR);
2016-02-11 22:38:25 +00:00
}
}
}
}
u32 CElementGen::GetParticleCountAllInternal() const
{
2017-06-04 01:01:09 +00:00
u32 ret = x25c_activeParticleCount;
2016-02-11 22:38:25 +00:00
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
if (ch->Get4CharId() == FOURCC('PART'))
ret += static_cast<CElementGen&>(*ch).GetParticleCountAll();
2016-02-11 22:38:25 +00:00
return ret;
2016-02-10 02:00:28 +00:00
}
2016-02-26 03:31:00 +00:00
void CElementGen::EndLifetime()
{
2017-05-06 05:21:42 +00:00
x268_PSLT = 0;
2017-06-04 01:01:09 +00:00
for (std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
{
if (ch->Get4CharId() == FOURCC('PART'))
static_cast<CElementGen&>(*ch).EndLifetime();
else
ch->SetParticleEmission(false);
}
2016-02-26 03:31:00 +00:00
}
void CElementGen::ForceParticleCreation(int amount)
{
CParticleGlobals::SParticleSystem* prevSystem = CParticleGlobals::g_currentParticleSystem;
CParticleGlobals::SParticleSystem thisSystem{ FOURCC('PART'), this };
CParticleGlobals::g_currentParticleSystem = &thisSystem;
2017-06-04 01:01:09 +00:00
CParticleGlobals::SetEmitterTime(x74_curFrame);
CreateNewParticles(amount);
CParticleGlobals::g_currentParticleSystem = prevSystem;
}
2016-02-10 02:00:28 +00:00
void CElementGen::BuildParticleSystemBounds()
2016-02-09 22:52:33 +00:00
{
2016-03-04 23:04:53 +00:00
zeus::CAABox aabb;
2016-02-11 22:38:25 +00:00
bool accumulated = false;
2017-06-04 01:01:09 +00:00
for (std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
2016-02-11 22:38:25 +00:00
{
2017-01-21 06:03:37 +00:00
auto chBounds = ch->GetBounds();
if (chBounds)
2016-02-11 22:38:25 +00:00
{
accumulated = true;
2017-01-21 06:03:37 +00:00
aabb.accumulateBounds(chBounds.value());
2016-02-11 22:38:25 +00:00
}
}
2017-06-04 01:01:09 +00:00
x264_recursiveParticleCount = GetParticleCountAllInternal();
if (GetParticleCount() > 0)
2016-02-11 22:38:25 +00:00
{
2017-06-04 01:01:09 +00:00
zeus::CVector3f scale = x100_globalScale * x2ec_maxSize;
zeus::CTransform xf = (x10c_globalScaleTransform * x22c_globalOrientation) * x178_localScaleTransform;
zeus::CAABox box = zeus::CAABox(x2d4_aabbMin, x2e0_aabbMax).getTransformedAABox(xf);
zeus::CVector3f min = box.min + xe8_globalTranslation - scale;
zeus::CVector3f max = box.max + xe8_globalTranslation + scale;
x2f0_systemBounds = zeus::CAABox(min, max);
2016-02-11 22:38:25 +00:00
}
else
2017-06-04 01:01:09 +00:00
x2f0_systemBounds = zeus::CAABox::skInvertedBox;
2016-02-11 22:38:25 +00:00
if (accumulated)
2017-06-04 01:01:09 +00:00
x2f0_systemBounds.accumulateBounds(aabb);
2016-02-09 22:52:33 +00:00
}
2016-02-11 19:18:14 +00:00
u32 CElementGen::GetSystemCount()
{
u32 ret = 0;
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& child : x290_activePartChildren)
{
if (child->Get4CharId() == FOURCC('PART'))
ret += static_cast<CElementGen&>(*child).GetSystemCount();
else
ret += 1;
}
2016-02-11 19:18:14 +00:00
2017-06-04 01:01:09 +00:00
return (ret + (x25c_activeParticleCount != 0));
2016-02-11 19:18:14 +00:00
}
2018-05-14 21:44:09 +00:00
void CElementGen::Render(const CActorLights* actorLights)
2016-02-12 02:36:34 +00:00
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2016-02-12 02:36:34 +00:00
2017-06-04 01:01:09 +00:00
x274_backupLightActive = CGraphics::g_LightActive;
2016-02-12 02:36:34 +00:00
CGraphics::DisableAllLights();
2017-06-04 01:01:09 +00:00
for (std::unique_ptr<CParticleGen>& child : x290_activePartChildren)
2016-02-12 02:36:34 +00:00
child->Render();
2017-06-04 01:01:09 +00:00
CParticleGlobals::SParticleSystem* prevSystem = CParticleGlobals::g_currentParticleSystem;
CParticleGlobals::SParticleSystem thisSystem{ FOURCC('PART'), this };
CParticleGlobals::g_currentParticleSystem = &thisSystem;
2016-02-12 02:36:34 +00:00
2017-06-04 01:01:09 +00:00
if (x30_particles.size())
2016-02-12 02:36:34 +00:00
{
2016-03-03 01:06:42 +00:00
SParticleModel& pmdl = desc->x5c_x48_PMDL;
if (pmdl.m_found || desc->x45_24_x31_26_PMUS)
2018-05-14 21:44:09 +00:00
RenderModels(actorLights);
2016-02-12 02:36:34 +00:00
2017-05-06 05:21:42 +00:00
if (x26c_31_LINE)
2016-02-12 02:36:34 +00:00
RenderLines();
else
RenderParticles();
}
2017-06-04 01:01:09 +00:00
CParticleGlobals::g_currentParticleSystem = prevSystem;
2016-02-12 02:36:34 +00:00
}
2018-05-14 21:44:09 +00:00
void CElementGen::RenderModels(const CActorLights* actorLights)
2016-02-12 02:36:34 +00:00
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2016-02-13 00:57:09 +00:00
2017-06-04 01:01:09 +00:00
if (x26d_26_modelsUseLights)
CGraphics::SetLightState(x274_backupLightActive);
2017-05-06 05:21:42 +00:00
CGlobalRandom gr(x27c_randState);
2016-02-13 00:57:09 +00:00
SUVElementSet uvs = {0.f, 0.f, 1.f, 1.f};
2016-03-03 01:06:42 +00:00
CUVElement* texr = desc->x54_x40_TEXR.get();
2016-02-13 00:57:09 +00:00
CTexture* cachedTex = nullptr;
bool texConst = true;
bool moveRedToAlphaBuffer = false;
2016-03-03 01:06:42 +00:00
if (desc->x45_24_x31_26_PMUS)
2016-02-13 00:57:09 +00:00
{
2017-01-22 17:36:25 +00:00
if (sMoveRedToAlphaBuffer && desc->x44_31_x31_25_PMAB && desc->x54_x40_TEXR)
2016-02-13 00:57:09 +00:00
moveRedToAlphaBuffer = true;
2016-03-03 01:06:42 +00:00
if (desc->x44_31_x31_25_PMAB)
2016-02-13 00:57:09 +00:00
{
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false);
if (moveRedToAlphaBuffer)
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear);
else
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, ERglLogicOp::Clear);
}
else
{
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, ERglLogicOp::Clear);
}
2016-02-12 02:36:34 +00:00
2016-02-13 00:57:09 +00:00
CGraphics::SetCullMode(ERglCullMode::None);
if (texr)
{
2017-06-04 01:01:09 +00:00
CParticle& target = x30_particles[0];
int partFrame = x74_curFrame - target.x28_startFrame;
2016-02-13 00:57:09 +00:00
cachedTex = texr->GetValueTexture(partFrame).GetObj();
cachedTex->Load(0, CTexture::EClampMode::One);
/* Shade as TEXC * RASC and TEXA * RASA */
if (moveRedToAlphaBuffer)
{
/* Color = Prev.rgb * Prev.a */
/* Alpha = Tex.r * Prev.a */
}
texConst = texr->HasConstantTexture();
texr->GetValueUV(partFrame, uvs);
}
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, "unexpected particle shader class");
break;
}
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);
else
CGraphics::SetShaderDataBinding(m_normalDataBindPmus);
2016-02-13 00:57:09 +00:00
}
2016-03-04 23:04:53 +00:00
zeus::CTransform orient = zeus::CTransform::Identity();
2016-03-03 01:06:42 +00:00
if (desc->x45_25_x31_27_PMOO)
2017-06-04 01:01:09 +00:00
orient = x1d8_orientation;
orient = orient * x22c_globalOrientation;
2016-02-13 00:57:09 +00:00
2016-03-03 01:06:42 +00:00
CVectorElement* pmrt = desc->x70_x5c_PMRT.get();
2016-02-13 00:57:09 +00:00
bool pmrtConst = false;
if (pmrt)
pmrtConst = pmrt->IsFastConstant();
2017-06-04 01:01:09 +00:00
zeus::CVector3f trans = (x13c_globalScaleTransformInverse * x1a8_localScaleTransformInverse) * xe8_globalTranslation;
2016-02-13 00:57:09 +00:00
2016-03-04 23:04:53 +00:00
zeus::CTransform rot = zeus::CTransform::Identity();
2016-02-13 00:57:09 +00:00
if (pmrtConst)
{
2016-03-04 23:04:53 +00:00
zeus::CVector3f pmrtVal;
2017-06-04 01:01:09 +00:00
pmrt->GetValue(x74_curFrame, pmrtVal);
2016-03-04 23:04:53 +00:00
rot = zeus::CTransform::RotateZ(zeus::degToRad(pmrtVal[2]));
rot.rotateLocalY(zeus::degToRad(pmrtVal[1]));
rot.rotateLocalX(zeus::degToRad(pmrtVal[0]));
2016-02-13 00:57:09 +00:00
}
rot = orient * rot;
2017-06-04 01:01:09 +00:00
CParticleGlobals::SetEmitterTime(x74_curFrame);
2016-03-04 23:04:53 +00:00
zeus::CColor col = {1.f, 1.f, 1.f, 1.f};
2016-02-13 00:57:09 +00:00
2016-03-04 23:04:53 +00:00
zeus::CVector3f pmopVec;
2017-06-04 01:01:09 +00:00
auto matrixIt = x50_parentMatrices.begin();
for (int i=0 ; i<x30_particles.size() ; ++i)
2016-02-13 00:57:09 +00:00
{
2017-06-04 01:01:09 +00:00
CParticle& particle = x30_particles[i];
2016-02-25 06:23:35 +00:00
g_currentParticle = &particle;
2016-02-13 00:57:09 +00:00
if (particle.x0_endFrame == -1)
{
++matrixIt;
continue;
}
CParticleGlobals::SetParticleLifetime(particle.x0_endFrame - particle.x28_startFrame);
2017-06-04 01:01:09 +00:00
int partFrame = x74_curFrame - particle.x28_startFrame - 1;
2016-02-13 00:57:09 +00:00
CParticleGlobals::UpdateParticleLifetimeTweenValues(partFrame);
CParticleGlobals::g_particleAccessParameters = &x60_advValues[i];
2016-03-03 01:06:42 +00:00
CVectorElement* pmop = desc->x6c_x58_PMOP.get();
2016-02-13 00:57:09 +00:00
if (pmop)
pmop->GetValue(partFrame, pmopVec);
2016-03-04 23:04:53 +00:00
zeus::CTransform partTrans = zeus::CTransform::Translate(particle.x4_pos + trans);
2017-06-04 01:01:09 +00:00
if (x2c_orientType == EModelOrientationType::One)
2016-02-13 00:57:09 +00:00
{
2016-03-04 23:04:53 +00:00
zeus::CTransform partRot(*matrixIt);
zeus::CVector3f pmopRotateOffset = (orient * partRot) * pmopVec;
2016-02-13 00:57:09 +00:00
partTrans = partTrans * partRot;
partTrans += pmopRotateOffset;
}
else
{
partTrans += orient * pmopVec;
}
if (pmrtConst)
{
partTrans = partTrans * rot;
}
else
{
if (pmrt)
{
2016-03-04 23:04:53 +00:00
zeus::CVector3f pmrtVal;
2016-02-13 00:57:09 +00:00
pmrt->GetValue(partFrame, pmrtVal);
2016-03-04 23:04:53 +00:00
rot = zeus::CTransform::RotateZ(zeus::degToRad(pmrtVal[2]));
rot.rotateLocalY(zeus::degToRad(pmrtVal[1]));
rot.rotateLocalX(zeus::degToRad(pmrtVal[0]));
2016-02-13 00:57:09 +00:00
partTrans = partTrans * (orient * rot);
}
else
{
partTrans = partTrans * rot;
}
}
2016-03-03 01:06:42 +00:00
CVectorElement* pmsc = desc->x74_x60_PMSC.get();
2016-02-13 00:57:09 +00:00
if (pmsc)
{
2016-03-04 23:04:53 +00:00
zeus::CVector3f pmscVal;
2016-02-13 00:57:09 +00:00
pmsc->GetValue(partFrame, pmscVal);
2016-03-04 23:04:53 +00:00
partTrans = partTrans * zeus::CTransform::Scale(pmscVal);
2016-02-13 00:57:09 +00:00
}
2016-03-03 01:06:42 +00:00
CColorElement* pmcl = desc->x78_x64_PMCL.get();
2016-02-13 00:57:09 +00:00
if (pmcl)
pmcl->GetValue(partFrame, col);
2017-06-04 01:01:09 +00:00
CGraphics::SetModelMatrix((x10c_globalScaleTransform * partTrans) * x178_localScaleTransform);
2016-02-13 00:57:09 +00:00
2016-03-03 01:06:42 +00:00
if (desc->x45_24_x31_26_PMUS)
2016-02-13 00:57:09 +00:00
{
if (!texConst)
{
2017-06-04 01:01:09 +00:00
CTexture* tex = texr->GetValueTexture(x74_curFrame - particle.x28_startFrame).GetObj();
2016-02-13 00:57:09 +00:00
if (tex != cachedTex)
{
tex->Load(0, CTexture::EClampMode::One);
cachedTex = tex;
}
}
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
{
g_instTexData.emplace_back();
SParticleInstanceTex& inst = g_instTexData.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:
{
g_instNoTexData.emplace_back();
SParticleInstanceNoTex& inst = g_instNoTexData.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;
}
2016-02-13 00:57:09 +00:00
}
else
{
2016-03-03 01:06:42 +00:00
CModel* model = desc->x5c_x48_PMDL.m_token.GetObj();
2018-05-14 21:44:09 +00:00
if (actorLights)
actorLights->ActivateLights(model->GetInstance());
2017-09-05 03:00:19 +00:00
if (g_subtractBlend)
2016-02-13 00:57:09 +00:00
{
2017-09-05 03:00:19 +00:00
model->Draw({5, 0, 1, zeus::CColor(1.f, 0.5f)});
}
else if (desc->x44_31_x31_25_PMAB)
{
model->Draw({7, 0, 1, col});
2016-02-13 00:57:09 +00:00
}
else
{
if (1.f == col.a)
2016-03-04 23:04:53 +00:00
model->Draw({0, 0, 3, zeus::CColor::skWhite});
2016-02-13 00:57:09 +00:00
else
2017-09-05 03:00:19 +00:00
model->Draw({5, 0, 1, col});
2016-02-13 00:57:09 +00:00
}
}
++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;
}
}
2017-06-04 01:01:09 +00:00
if (x26d_26_modelsUseLights)
2016-02-13 00:57:09 +00:00
CGraphics::DisableAllLights();
CGraphics::SetCullMode(ERglCullMode::Front);
if (moveRedToAlphaBuffer)
{
/* Restore passthrough */
}
2016-02-12 02:36:34 +00:00
}
void CElementGen::RenderLines()
2016-02-15 04:00:26 +00:00
{
CGenDescription* desc = x1c_genDesc.GetObj();
2017-05-06 05:21:42 +00:00
CGlobalRandom gr(x27c_randState);
2016-02-15 04:00:26 +00:00
2016-03-04 23:04:53 +00:00
zeus::CTransform systemViewPointMatrix(CGraphics::g_ViewMatrix);
2016-04-29 10:08:46 +00:00
systemViewPointMatrix.origin.zeroOut();
2017-06-04 01:01:09 +00:00
zeus::CTransform systemCameraMatrix = systemViewPointMatrix.inverse() * x22c_globalOrientation;
systemViewPointMatrix = ((zeus::CTransform::Translate(xe8_globalTranslation) * x10c_globalScaleTransform) * systemViewPointMatrix) * x178_localScaleTransform;
2016-02-15 04:00:26 +00:00
CGraphics::SetModelMatrix(systemViewPointMatrix);
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
2017-06-04 01:01:09 +00:00
if (x26c_26_AAPH)
2016-02-15 04:00:26 +00:00
{
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, ERglLogicOp::Clear);
}
else
{
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, ERglLogicOp::Clear);
}
2016-03-04 01:01:37 +00:00
CRealElement* widt = desc->x24_x18_WIDT.get();
2016-02-15 04:00:26 +00:00
bool widtConst = false;
if (widt)
widtConst = widt->IsConstant();
2016-03-03 01:06:42 +00:00
CUVElement* texr = desc->x54_x40_TEXR.get();
2016-02-15 04:00:26 +00:00
SUVElementSet uvs = {0.f, 0.f, 1.f, 1.f};
bool constTexr = true;
bool constUVs = true;
CTexture* cachedTex = nullptr;
2016-03-04 23:04:53 +00:00
zeus::CColor moduColor = zeus::CColor::skWhite;
2016-02-15 04:00:26 +00:00
if (texr)
{
2017-06-04 01:01:09 +00:00
CParticle& target = x30_particles[0];
int partFrame = x74_curFrame - target.x28_startFrame;
2016-02-15 04:00:26 +00:00
cachedTex = texr->GetValueTexture(partFrame).GetObj();
cachedTex->Load(0, CTexture::EClampMode::One);
/* Set TEXC * RASC */
2017-06-04 01:01:09 +00:00
if (x338_moduColor != zeus::CColor::skBlack)
2016-02-15 04:00:26 +00:00
{
/* Add RASC * PREVC pass for MODU color loaded into channel mat-color */
2017-06-04 01:01:09 +00:00
moduColor = x338_moduColor;
2016-02-15 04:00:26 +00:00
}
constTexr = texr->HasConstantTexture();
texr->GetValueUV(partFrame, uvs);
constUVs = texr->HasConstantUV();
}
float constWidth = 1.f;
2016-02-15 04:00:26 +00:00
if (widtConst)
{
widt->GetValue(0, constWidth);
constWidth = std::max(0.f, std::min(constWidth, 42.5f));
2016-02-15 04:00:26 +00:00
}
m_lineRenderer->Reset();
2017-06-04 01:01:09 +00:00
for (int i=0 ; i<x30_particles.size() ; ++i)
2016-02-15 04:00:26 +00:00
{
2017-06-04 01:01:09 +00:00
CParticle& particle = x30_particles[i];
2016-02-25 06:23:35 +00:00
g_currentParticle = &particle;
2017-06-04 01:01:09 +00:00
int partFrame = x74_curFrame - particle.x28_startFrame;
2016-02-15 04:00:26 +00:00
if (!constTexr)
{
CTexture* tex = texr->GetValueTexture(partFrame).GetObj();
if (tex != cachedTex)
{
tex->Load(0, CTexture::EClampMode::One);
cachedTex = tex;
}
}
if (!constUVs)
texr->GetValueUV(partFrame, uvs);
2016-03-04 23:04:53 +00:00
zeus::CVector3f dVec = particle.x4_pos - particle.x10_prevPos;
2017-05-06 05:21:42 +00:00
if (x26d_24_FXLL)
2016-02-15 04:00:26 +00:00
if (dVec.magSquared() >= 0.f)
dVec.normalize();
2016-03-04 23:04:53 +00:00
zeus::CVector3f p1 = systemCameraMatrix * particle.x4_pos;
zeus::CVector3f p2 = systemCameraMatrix * (particle.x2c_lineLengthOrSize * dVec + particle.x4_pos);
2016-02-15 04:00:26 +00:00
if (widtConst)
{
m_lineRenderer->AddVertex(p1, particle.x34_color, constWidth, {uvs.xMin, uvs.yMin});
m_lineRenderer->AddVertex(p2, particle.x34_color, constWidth, {uvs.xMax, uvs.yMax});
2016-02-15 04:00:26 +00:00
}
else if (widt)
2016-02-15 04:00:26 +00:00
{
float width = 1.f;
widt->GetValue(0, width);
width = std::max(0.f, std::min(width, 42.5f));
m_lineRenderer->AddVertex(p1, particle.x34_color, width, {uvs.xMin, uvs.yMin});
m_lineRenderer->AddVertex(p2, particle.x34_color, width, {uvs.xMax, uvs.yMax});
2016-02-15 04:00:26 +00:00
}
}
m_lineRenderer->Render(moduColor);
2016-02-12 02:36:34 +00:00
}
void CElementGen::RenderParticles()
2016-02-13 00:57:09 +00:00
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2017-05-06 05:21:42 +00:00
CGlobalRandom gr(x27c_randState);
2016-02-13 00:57:09 +00:00
2016-03-03 01:06:42 +00:00
CUVElement* texr = desc->x54_x40_TEXR.get();
CUVElement* tind = desc->x58_x44_TIND.get();
2016-02-13 00:57:09 +00:00
if (texr && tind)
{
2016-02-25 02:55:38 +00:00
RenderParticlesIndirectTexture();
2016-02-13 00:57:09 +00:00
return;
}
2016-03-03 01:06:42 +00:00
CRealElement* size = desc->x4c_x38_SIZE.get();
2016-02-13 00:57:09 +00:00
if (size && size->IsConstant())
{
float sizeVal;
size->GetValue(0, sizeVal);
if (sizeVal == 0.f)
{
size->GetValue(1, sizeVal);
if (sizeVal == 0.f)
return;
}
}
2018-05-13 23:27:47 +00:00
zeus::CTransform systemModelMatrix(CGraphics::g_ViewMatrix);
systemModelMatrix.origin.zeroOut();
zeus::CTransform systemCameraMatrix = systemModelMatrix.inverse() * x22c_globalOrientation;
systemModelMatrix = ((zeus::CTransform::Translate(xe8_globalTranslation) * x10c_globalScaleTransform) *
systemModelMatrix) * x178_localScaleTransform;
if (x26c_29_ORNT)
2018-05-13 23:27:47 +00:00
CGraphics::SetModelMatrix(systemModelMatrix * systemCameraMatrix);
else
2018-05-13 23:27:47 +00:00
CGraphics::SetModelMatrix(systemModelMatrix);
2016-02-13 00:57:09 +00:00
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
SUVElementSet uvs = {0.f, 0.f, 1.f, 1.f};
bool constUVs = true;
CTexture* cachedTex = nullptr;
2016-02-15 04:00:26 +00:00
SParticleUniforms uniformData =
{
2016-04-03 05:25:34 +00:00
CGraphics::GetPerspectiveProjectionMatrix(true) * CGraphics::g_GXModelView.toMatrix4f(),
2016-02-15 04:00:26 +00:00
{1.f, 1.f, 1.f, 1.f}
};
2016-02-13 00:57:09 +00:00
if (texr)
{
2017-06-04 01:01:09 +00:00
CParticle& target = x30_particles[0];
int partFrame = x74_curFrame - target.x28_startFrame;
2016-02-13 00:57:09 +00:00
cachedTex = texr->GetValueTexture(partFrame).GetObj();
cachedTex->Load(0, CTexture::EClampMode::One);
2017-06-04 01:01:09 +00:00
if (x338_moduColor != zeus::CColor::skBlack)
2016-02-13 00:57:09 +00:00
{
/* Add RASC * PREVC pass for MODU color loaded into channel mat-color */
2017-06-04 01:01:09 +00:00
uniformData.moduColor = x338_moduColor;
2016-02-13 00:57:09 +00:00
}
texr->GetValueUV(partFrame, uvs);
constUVs = texr->HasConstantUV();
}
2016-02-15 04:00:26 +00:00
m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
2016-02-13 00:57:09 +00:00
2017-06-04 01:01:09 +00:00
std::vector<CParticleListItem> sortItems;
2016-03-03 01:06:42 +00:00
if (desc->x44_28_x30_28_SORT)
2016-02-13 00:57:09 +00:00
{
2017-06-04 01:01:09 +00:00
sortItems.reserve(x30_particles.size());
for (int i=0 ; i<x30_particles.size() ; ++i)
2016-02-13 00:57:09 +00:00
{
2017-06-04 01:01:09 +00:00
const CParticle& particle = x30_particles[i];
sortItems.emplace_back(i);
CParticleListItem& sortItem = sortItems.back();
2018-01-30 01:04:01 +00:00
sortItem.x4_viewPoint = systemCameraMatrix * ((particle.x4_pos - particle.x10_prevPos) *
x80_timeDeltaScale + particle.x10_prevPos);
2016-02-13 00:57:09 +00:00
}
2017-06-04 01:01:09 +00:00
std::sort(sortItems.begin(), sortItems.end(),
2016-02-13 00:57:09 +00:00
[](const CParticleListItem& a, const CParticleListItem& b) -> bool
{return a.x4_viewPoint[1] >= b.x4_viewPoint[1];});
}
bool moveRedToAlphaBuffer = false;
2017-06-04 01:01:09 +00:00
if (sMoveRedToAlphaBuffer && x26c_26_AAPH)
2016-02-13 00:57:09 +00:00
moveRedToAlphaBuffer = true;
2017-09-05 03:00:19 +00:00
if (g_subtractBlend)
{
if (moveRedToAlphaBuffer)
CGraphics::SetShaderDataBinding(m_redToAlphaSubDataBind);
else
CGraphics::SetShaderDataBinding(m_normalSubDataBind);
}
2016-02-13 00:57:09 +00:00
else
2017-09-05 03:00:19 +00:00
{
if (moveRedToAlphaBuffer)
CGraphics::SetShaderDataBinding(m_redToAlphaDataBind);
else
CGraphics::SetShaderDataBinding(m_normalDataBind);
}
2016-02-13 00:57:09 +00:00
2017-06-04 01:01:09 +00:00
int mbspVal = std::max(1, x270_MBSP);
2016-02-13 00:57:09 +00:00
2017-06-04 01:01:09 +00:00
CParticleGlobals::SetEmitterTime(x74_curFrame);
if (!x26c_30_MBLR)
2016-02-13 00:57:09 +00:00
{
#if 0
if (!desc->x44_28_x30_28_SORT && constUVs && !x26c_29_ORNT)
{
if (!desc->x50_x3c_ROTA)
{
if (!zeus::close_enough(x80_timeDeltaScale, 1.f))
{
RenderBasicParticlesNoRotNoTS(systemCameraMatrix);
}
else
{
RenderBasicParticlesNoRotTS(systemCameraMatrix);
}
}
else
{
if (!zeus::close_enough(x80_timeDeltaScale, 1.f))
{
RenderBasicParticlesRotNoTS(systemCameraMatrix);
}
else
{
RenderBasicParticlesRotTS(systemCameraMatrix);
}
}
}
#endif
2016-02-15 04:00:26 +00:00
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
g_instTexData.clear();
2017-06-04 01:01:09 +00:00
g_instTexData.reserve(x30_particles.size());
2016-02-15 04:00:26 +00:00
break;
case CElementGenShaders::EShaderClass::NoTex:
g_instNoTexData.clear();
2017-06-04 01:01:09 +00:00
g_instNoTexData.reserve(x30_particles.size());
2016-02-15 04:00:26 +00:00
break;
default:
2016-03-04 23:04:53 +00:00
Log.report(logvisor::Fatal, "unexpected particle shader class");
2016-02-15 04:00:26 +00:00
break;
}
if (!x26c_29_ORNT)
2016-02-13 00:57:09 +00:00
{
for (int i = 0; i < x30_particles.size(); ++i)
{
int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : i;
CParticle& particle = x30_particles[partIdx];
g_currentParticle = &particle;
int partFrame = x74_curFrame - particle.x28_startFrame - 1;
zeus::CVector3f viewPoint;
if (desc->x44_28_x30_28_SORT)
viewPoint = sortItems[i].x4_viewPoint;
else
viewPoint = systemCameraMatrix * ((particle.x4_pos - particle.x10_prevPos) *
2018-01-30 01:04:01 +00:00
x80_timeDeltaScale + particle.x10_prevPos);
2016-02-13 00:57:09 +00:00
if (!constUVs)
{
CParticleGlobals::SetParticleLifetime(particle.x0_endFrame - particle.x28_startFrame);
CParticleGlobals::UpdateParticleLifetimeTweenValues(partFrame);
texr->GetValueUV(partFrame, uvs);
}
2016-02-13 00:57:09 +00:00
float size = 0.5f * particle.x2c_lineLengthOrSize;
if (0.f == particle.x30_lineWidthOrRota)
{
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
{
g_instTexData.emplace_back();
SParticleInstanceTex& inst = g_instTexData.back();
2018-05-13 23:27:47 +00:00
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:
{
g_instNoTexData.emplace_back();
SParticleInstanceNoTex& inst = g_instNoTexData.back();
2018-05-13 23:27:47 +00:00
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:
{
g_instTexData.emplace_back();
SParticleInstanceTex& inst = g_instTexData.back();
2018-05-13 23:27:47 +00:00
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};
2018-05-13 23:27:47 +00:00
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:
{
g_instNoTexData.emplace_back();
SParticleInstanceNoTex& inst = g_instNoTexData.back();
2018-05-13 23:27:47 +00:00
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};
2018-05-13 23:27:47 +00:00
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
{
for (int i = 0; i < x30_particles.size(); ++i)
2016-02-13 00:57:09 +00:00
{
int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : i;
CParticle& particle = x30_particles[partIdx];
g_currentParticle = &particle;
int partFrame = x74_curFrame - particle.x28_startFrame - 1;
zeus::CVector3f viewPoint = ((particle.x4_pos - particle.x10_prevPos) *
x80_timeDeltaScale + particle.x10_prevPos);
float width = !desc->x50_x3c_ROTA ? 1.f : particle.x30_lineWidthOrRota;
zeus::CVector3f dir;
if (particle.x1c_vel.canBeNormalized())
2016-02-15 04:00:26 +00:00
{
dir = particle.x1c_vel.normalized();
}
else
2016-02-15 04:00:26 +00:00
{
zeus::CVector3f delta = particle.x4_pos - particle.x10_prevPos;
if (delta.canBeNormalized())
dir = delta.normalized();
else
dir = zeus::CVector3f::skUp;
2016-02-15 04:00:26 +00:00
}
zeus::CVector3f foreVec = particle.x2c_lineLengthOrSize * dir;
zeus::CVector3f rightVec;
if (desc->x30_31_RSOP)
2016-02-15 04:00:26 +00:00
{
rightVec = dir.cross(CGraphics::g_ViewMatrix.basis[1]);
if (rightVec.canBeNormalized())
{
rightVec = rightVec.normalized() * (particle.x2c_lineLengthOrSize * width);
}
else
{
rightVec = dir.cross((CGraphics::g_ViewMatrix.origin - particle.x4_pos).normalized());
if (rightVec.canBeNormalized())
{
rightVec = rightVec.normalized() * (particle.x2c_lineLengthOrSize * width);
}
}
}
else
{
rightVec = foreVec.cross(CGraphics::g_ViewMatrix.basis[1]) * width;
2016-02-15 04:00:26 +00:00
}
if (!constUVs)
{
CParticleGlobals::SetParticleLifetime(particle.x0_endFrame - particle.x28_startFrame);
CParticleGlobals::UpdateParticleLifetimeTweenValues(partFrame);
texr->GetValueUV(partFrame, uvs);
2016-02-15 04:00:26 +00:00
}
2016-02-13 00:57:09 +00:00
2016-02-15 04:00:26 +00:00
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
{
g_instTexData.emplace_back();
SParticleInstanceTex& inst = g_instTexData.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};
2016-02-15 04:00:26 +00:00
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:
{
g_instNoTexData.emplace_back();
SParticleInstanceNoTex& inst = g_instNoTexData.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};
2016-02-15 04:00:26 +00:00
inst.color = particle.x34_color;
break;
}
default:
break;
2016-02-15 04:00:26 +00:00
}
2016-02-13 00:57:09 +00:00
}
}
2016-02-15 04:00:26 +00:00
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
2016-02-23 02:34:16 +00:00
CGraphics::DrawInstances(0, 4, g_instTexData.size());
2016-02-15 04:00:26 +00:00
break;
case CElementGenShaders::EShaderClass::NoTex:
m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
2016-02-23 02:34:16 +00:00
CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
2016-02-15 04:00:26 +00:00
break;
default: break;
}
2016-02-13 00:57:09 +00:00
}
else
{
2016-02-15 04:00:26 +00:00
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
g_instTexData.clear();
2017-06-04 01:01:09 +00:00
g_instTexData.reserve(x30_particles.size() * mbspVal);
2016-02-15 04:00:26 +00:00
break;
case CElementGenShaders::EShaderClass::NoTex:
g_instNoTexData.clear();
2017-06-04 01:01:09 +00:00
g_instNoTexData.reserve(x30_particles.size() * mbspVal);
2016-02-15 04:00:26 +00:00
break;
default:
2016-03-04 23:04:53 +00:00
Log.report(logvisor::Fatal, "unexpected particle shader class");
2016-02-15 04:00:26 +00:00
break;
}
2016-02-13 00:57:09 +00:00
float mbspFac = 1.f / float(mbspVal);
2017-06-04 01:01:09 +00:00
for (int i=0 ; i<x30_particles.size() ; ++i)
2016-02-13 00:57:09 +00:00
{
2017-06-04 01:01:09 +00:00
int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : i;
CParticle& particle = x30_particles[partIdx];
2016-02-25 06:23:35 +00:00
g_currentParticle = &particle;
2017-06-04 01:01:09 +00:00
int partFrame = x74_curFrame - particle.x28_startFrame - 1;
2016-02-13 00:57:09 +00:00
if (!constUVs)
{
CParticleGlobals::SetParticleLifetime(particle.x0_endFrame - particle.x28_startFrame);
CParticleGlobals::UpdateParticleLifetimeTweenValues(partFrame);
texr->GetValueUV(partFrame, uvs);
}
2016-03-04 23:04:53 +00:00
zeus::CVector3f dVec = particle.x4_pos - particle.x10_prevPos;
2017-06-04 01:01:09 +00:00
zeus::CVector3f vec = dVec * x80_timeDeltaScale + particle.x10_prevPos;
2016-03-04 23:04:53 +00:00
zeus::CVector3f mbspVec = dVec * mbspFac;
2016-02-13 00:57:09 +00:00
float size = 0.5f * particle.x2c_lineLengthOrSize;
if (0.f == particle.x30_lineWidthOrRota)
{
2018-01-30 01:04:01 +00:00
for (int j=0 ; j<mbspVal ; ++j)
2016-02-13 00:57:09 +00:00
{
vec += mbspVec;
2016-03-04 23:04:53 +00:00
zeus::CVector3f vec2 = systemCameraMatrix * vec;
2016-02-15 04:00:26 +00:00
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
{
g_instTexData.emplace_back();
SParticleInstanceTex& inst = g_instTexData.back();
2016-03-04 23:04:53 +00:00
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};
2016-02-15 04:00:26 +00:00
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:
{
g_instNoTexData.emplace_back();
SParticleInstanceNoTex& inst = g_instNoTexData.back();
2016-03-04 23:04:53 +00:00
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};
2016-02-15 04:00:26 +00:00
inst.color = particle.x34_color;
break;
}
default: break;
}
2016-02-13 00:57:09 +00:00
}
}
else
{
2016-03-04 23:04:53 +00:00
float theta = zeus::degToRad(particle.x30_lineWidthOrRota);
float sinT = std::sin(theta) * size;
2018-01-27 08:34:46 +00:00
float cosT = std::cos(theta) * size;
2016-02-13 00:57:09 +00:00
2018-01-30 01:04:01 +00:00
for (int j=0 ; j<mbspVal ; ++j)
2016-02-13 00:57:09 +00:00
{
vec += mbspVec;
2016-03-04 23:04:53 +00:00
zeus::CVector3f vec2 = systemCameraMatrix * vec;
2016-02-15 04:00:26 +00:00
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
{
g_instTexData.emplace_back();
SParticleInstanceTex& inst = g_instTexData.back();
2016-03-04 23:04:53 +00:00
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};
2016-02-15 04:00:26 +00:00
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:
{
g_instNoTexData.emplace_back();
SParticleInstanceNoTex& inst = g_instNoTexData.back();
2016-03-04 23:04:53 +00:00
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};
2016-02-15 04:00:26 +00:00
inst.color = particle.x34_color;
break;
}
default: break;
}
2016-02-13 00:57:09 +00:00
}
}
}
2016-02-15 04:00:26 +00:00
switch (m_shaderClass)
{
case CElementGenShaders::EShaderClass::Tex:
m_instBuf->load(g_instTexData.data(), g_instTexData.size() * sizeof(SParticleInstanceTex));
2016-02-23 02:34:16 +00:00
CGraphics::DrawInstances(0, 4, g_instTexData.size());
2016-02-15 04:00:26 +00:00
break;
case CElementGenShaders::EShaderClass::NoTex:
m_instBuf->load(g_instNoTexData.data(), g_instNoTexData.size() * sizeof(SParticleInstanceNoTex));
2016-02-23 02:34:16 +00:00
CGraphics::DrawInstances(0, 4, g_instNoTexData.size());
2016-02-15 04:00:26 +00:00
break;
default: break;
}
2016-02-13 00:57:09 +00:00
}
}
void CElementGen::RenderParticlesIndirectTexture()
2016-02-09 22:52:33 +00:00
{
2016-02-13 05:49:59 +00:00
CGenDescription* desc = x1c_genDesc.GetObj();
2016-03-04 23:04:53 +00:00
zeus::CTransform systemViewPointMatrix(CGraphics::g_ViewMatrix);
2016-04-29 10:08:46 +00:00
systemViewPointMatrix.origin.zeroOut();
2017-06-04 01:01:09 +00:00
zeus::CTransform systemCameraMatrix = systemViewPointMatrix.inverse() * x22c_globalOrientation;
systemViewPointMatrix = ((zeus::CTransform::Translate(xe8_globalTranslation) * x10c_globalScaleTransform) * systemViewPointMatrix) * x178_localScaleTransform;
2016-02-14 03:42:36 +00:00
CGraphics::SetModelMatrix(systemViewPointMatrix);
2016-02-25 02:55:38 +00:00
SParticleUniforms uniformData =
{
2016-04-03 05:25:34 +00:00
CGraphics::GetPerspectiveProjectionMatrix(true) * CGraphics::g_GXModelView.toMatrix4f(),
2016-02-25 02:55:38 +00:00
{1.f, 1.f, 1.f, 1.f}
};
m_uniformBuf->load(&uniformData, sizeof(SParticleUniforms));
2016-02-14 03:42:36 +00:00
CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
2017-06-04 01:01:09 +00:00
if (x26c_26_AAPH)
2016-02-14 03:42:36 +00:00
{
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, ERglLogicOp::Clear);
}
else
{
2017-06-04 01:01:09 +00:00
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, x26c_27_ZBUF);
2016-02-14 03:42:36 +00:00
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha, ERglLogicOp::Clear);
}
2016-03-03 01:06:42 +00:00
CUVElement* texr = desc->x54_x40_TEXR.get();
2017-06-04 01:01:09 +00:00
CParticle& firstParticle = x30_particles[0];
int partFrame = x74_curFrame - firstParticle.x28_startFrame;
2016-02-14 03:42:36 +00:00
CTexture* cachedTex = texr->GetValueTexture(partFrame).GetObj();
cachedTex->Load(0, CTexture::EClampMode::One);
SUVElementSet uvs = {0.f, 0.f, 1.f, 1.f};
bool constTexr = texr->HasConstantTexture();
texr->GetValueUV(partFrame, uvs);
bool constUVs = texr->HasConstantUV();
2016-03-03 01:06:42 +00:00
CUVElement* tind = desc->x58_x44_TIND.get();
2016-02-14 03:42:36 +00:00
CTexture* cachedIndTex = tind->GetValueTexture(partFrame).GetObj();
cachedIndTex->Load(2, CTexture::EClampMode::One);
SUVElementSet uvsInd = {0.f, 0.f, 1.f, 1.f};
bool constIndTexr = tind->HasConstantTexture();
bool constIndUVs = tind->HasConstantUV();
tind->GetValueUV(partFrame, uvsInd);
2017-06-04 01:01:09 +00:00
std::vector<CParticleListItem> sortItems;
2016-03-03 01:06:42 +00:00
if (desc->x44_28_x30_28_SORT)
2016-02-15 04:00:26 +00:00
{
2017-06-04 01:01:09 +00:00
sortItems.reserve(x30_particles.size());
for (int i=0 ; i<x30_particles.size() ; ++i)
2016-02-15 04:00:26 +00:00
{
2017-06-04 01:01:09 +00:00
const CParticle& particle = x30_particles[i];
sortItems.emplace_back(i);
CParticleListItem& sortItem = sortItems.back();
sortItem.x4_viewPoint = systemCameraMatrix * ((particle.x4_pos - particle.x10_prevPos) * x80_timeDeltaScale + particle.x10_prevPos);
2016-02-15 04:00:26 +00:00
}
2017-06-04 01:01:09 +00:00
std::sort(sortItems.begin(), sortItems.end(),
2016-02-15 04:00:26 +00:00
[](const CParticleListItem& a, const CParticleListItem& b) -> bool
{return a.x4_viewPoint[1] >= b.x4_viewPoint[1];});
}
2016-02-25 02:55:38 +00:00
g_instIndTexData.clear();
2017-06-04 01:01:09 +00:00
g_instIndTexData.reserve(x30_particles.size());
2016-02-25 02:55:38 +00:00
2017-06-04 01:01:09 +00:00
for (int i=0 ; i<x30_particles.size() ; ++i)
2016-02-15 04:00:26 +00:00
{
2017-06-04 01:01:09 +00:00
int partIdx = desc->x44_28_x30_28_SORT ? sortItems[i].x0_partIdx : i;
CParticle& particle = x30_particles[partIdx];
2016-02-25 06:23:35 +00:00
g_currentParticle = &particle;
2017-06-04 01:01:09 +00:00
int partFrame = x74_curFrame - particle.x28_startFrame;
2016-03-04 23:04:53 +00:00
zeus::CVector3f viewPoint;
2016-03-03 01:06:42 +00:00
if (desc->x44_28_x30_28_SORT)
2017-06-04 01:01:09 +00:00
viewPoint = sortItems[i].x4_viewPoint;
2016-02-15 04:00:26 +00:00
else
2017-06-04 01:01:09 +00:00
viewPoint = systemCameraMatrix * ((particle.x4_pos - particle.x10_prevPos) * x80_timeDeltaScale + particle.x10_prevPos);
2016-02-15 04:00:26 +00:00
if (!constTexr)
{
CTexture* tex = texr->GetValueTexture(partFrame).GetObj();
if (tex != cachedTex)
{
tex->Load(0, CTexture::EClampMode::One);
cachedTex = tex;
}
}
if (!constIndTexr)
{
CTexture* tex = tind->GetValueTexture(partFrame).GetObj();
if (tex != cachedIndTex)
{
tex->Load(2, CTexture::EClampMode::One);
cachedIndTex = tex;
}
}
if (!constUVs)
texr->GetValueUV(partFrame, uvs);
if (!constIndUVs)
tind->GetValueUV(partFrame, uvsInd);
float size = 0.5f * particle.x2c_lineLengthOrSize;
2016-03-04 23:04:53 +00:00
zeus::CVector3f p1 = {viewPoint.x - size, viewPoint.y, viewPoint.z - size};
zeus::CVector3f p2 = {viewPoint.x + size, viewPoint.y, viewPoint.z + size};
2016-02-15 04:00:26 +00:00
SClipScreenRect clipRect = CGraphics::ClipScreenRectFromMS(p1, p2);
if (!clipRect.x0_valid)
continue;
2016-02-26 05:38:11 +00:00
CGraphics::ResolveSpareTexture(clipRect);
2016-02-25 02:55:38 +00:00
g_instIndTexData.emplace_back();
SParticleInstanceIndTex& inst = g_instIndTexData.back();
2016-03-04 23:04:53 +00:00
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};
2016-02-25 02:55:38 +00:00
inst.color = particle.x34_color;
2018-01-30 01:04:01 +00:00
inst.texrTindUVs[2] = zeus::CVector4f{uvs.xMax, uvs.yMax, uvsInd.xMin, uvsInd.yMin};
inst.texrTindUVs[3] = zeus::CVector4f{uvs.xMin, uvs.yMax, uvsInd.xMin, uvsInd.yMax};
inst.texrTindUVs[0] = zeus::CVector4f{uvs.xMax, uvs.yMin, uvsInd.xMax, uvsInd.yMin};
inst.texrTindUVs[1] = zeus::CVector4f{uvs.xMin, uvs.yMin, uvsInd.xMax, uvsInd.yMax};
2016-03-04 23:04:53 +00:00
inst.sceneUVs = zeus::CVector4f{clipRect.x18_uvXMin, clipRect.x24_uvYMax, clipRect.x1c_uvXMax, clipRect.x20_uvYMin};
2016-02-15 04:00:26 +00:00
}
2016-02-25 02:55:38 +00:00
if (g_instIndTexData.size())
{
m_instBuf->load(g_instIndTexData.data(), g_instIndTexData.size() * sizeof(SParticleInstanceIndTex));
CGraphics::SetShaderDataBinding(m_normalDataBind);
CGraphics::DrawInstances(0, 4, g_instIndTexData.size());
}
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
void CElementGen::SetOrientation(const zeus::CTransform& orientation)
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
x1d8_orientation = orientation;
x208_orientationInverse = x1d8_orientation.inverse();
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->SetOrientation(orientation);
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
void CElementGen::SetTranslation(const zeus::CVector3f& translation)
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
xdc_translation = translation;
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
{
switch (ch->Get4CharId())
{
case SBIG('SELC'):
ch->SetTranslation(translation + x2c0_SEPO);
break;
case SBIG('SWHC'):
ch->SetTranslation(translation + x2b0_SSPO);
break;
default:
ch->SetTranslation(translation);
break;
}
}
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
void CElementGen::SetGlobalOrientation(const zeus::CTransform& rotation)
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
x22c_globalOrientation.setRotation(rotation);
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->SetGlobalOrientation(x22c_globalOrientation);
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
void CElementGen::SetGlobalTranslation(const zeus::CVector3f& translation)
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
xe8_globalTranslation = translation;
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->SetGlobalTranslation(translation);
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
void CElementGen::SetGlobalScale(const zeus::CVector3f& scale)
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
x100_globalScale = scale;
x10c_globalScaleTransform = zeus::CTransform::Scale(scale);
x13c_globalScaleTransformInverse = zeus::CTransform::Scale(zeus::CVector3f::skOne / scale);
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->SetGlobalScale(scale);
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
void CElementGen::SetLocalScale(const zeus::CVector3f& scale)
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
x16c_localScale = scale;
x178_localScaleTransform = zeus::CTransform::Scale(scale);
x1a8_localScaleTransformInverse = zeus::CTransform::Scale(zeus::CVector3f::skOne / scale);
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->SetLocalScale(scale);
2017-06-04 01:01:09 +00:00
}
2017-06-04 01:01:09 +00:00
void CElementGen::SetGlobalOrientAndTrans(const zeus::CTransform& xf)
{
SetGlobalOrientation(xf);
SetGlobalTranslation(xf.origin);
2016-02-09 22:52:33 +00:00
}
void CElementGen::SetParticleEmission(bool enabled)
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
x88_particleEmission = enabled;
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->SetParticleEmission(enabled);
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
void CElementGen::SetModulationColor(const zeus::CColor& color)
2016-02-08 05:10:17 +00:00
{
2017-06-04 01:01:09 +00:00
x338_moduColor = color;
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->SetModulationColor(color);
2017-06-04 01:01:09 +00:00
}
2017-06-04 01:01:09 +00:00
void CElementGen::SetGeneratorRate(float rate)
{
if (rate >= 0.0f)
x98_generatorRate = rate;
else
x98_generatorRate = 0.0f;
2017-06-04 01:01:09 +00:00
for (std::unique_ptr<CParticleGen>& child : x290_activePartChildren)
{
if (child->Get4CharId() == FOURCC('PART'))
child->SetGeneratorRate(x98_generatorRate);
}
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
const zeus::CTransform& CElementGen::GetOrientation() const
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
return x1d8_orientation;
2016-02-09 22:52:33 +00:00
}
2016-02-08 05:10:17 +00:00
2016-03-04 23:04:53 +00:00
const zeus::CVector3f& CElementGen::GetTranslation() const
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
return xdc_translation;
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
const zeus::CTransform& CElementGen::GetGlobalOrientation() const
2016-02-13 05:49:59 +00:00
{
2017-06-04 01:01:09 +00:00
return x22c_globalOrientation;
2016-02-13 05:49:59 +00:00
}
2016-03-04 23:04:53 +00:00
const zeus::CVector3f& CElementGen::GetGlobalTranslation() const
2016-02-13 05:49:59 +00:00
{
2017-06-04 01:01:09 +00:00
return xe8_globalTranslation;
2016-02-13 05:49:59 +00:00
}
2016-03-04 23:04:53 +00:00
const zeus::CVector3f& CElementGen::GetGlobalScale() const
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
return x100_globalScale;
2016-02-09 22:52:33 +00:00
}
2016-03-04 23:04:53 +00:00
const zeus::CColor& CElementGen::GetModulationColor() const
2016-02-09 22:52:33 +00:00
{
2017-06-04 01:01:09 +00:00
return x338_moduColor;
2016-02-09 22:52:33 +00:00
}
bool CElementGen::IsSystemDeletable() const
{
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
if (!ch->IsSystemDeletable())
return false;
2017-06-04 01:01:09 +00:00
if (x268_PSLT < x74_curFrame && x25c_activeParticleCount == 0)
return true;
return false;
2016-02-09 22:52:33 +00:00
}
std::experimental::optional<zeus::CAABox> CElementGen::GetBounds() const
2016-02-09 22:52:33 +00:00
{
if (GetParticleCountAll() == 0)
return std::experimental::nullopt;
else
2017-06-04 01:01:09 +00:00
return {x2f0_systemBounds};
2016-02-09 22:52:33 +00:00
}
u32 CElementGen::GetParticleCount() const
{
2017-06-04 01:01:09 +00:00
return x25c_activeParticleCount;
2016-02-09 22:52:33 +00:00
}
bool CElementGen::SystemHasLight() const
{
2017-05-06 05:21:42 +00:00
return x308_lightType != LightType::None;
2016-02-09 22:52:33 +00:00
}
CLight CElementGen::GetLight() const
{
2017-05-06 05:21:42 +00:00
switch (x308_lightType)
{
case LightType::Directional:
2017-06-04 01:01:09 +00:00
return CLight::BuildDirectional(x320_LDIR.normalized(), x30c_LCLR * x310_LINT);
case LightType::Spot:
2017-06-04 01:01:09 +00:00
return CLight::BuildSpot(x314_LOFF, x320_LDIR.normalized(), x30c_LCLR * x310_LINT, x334_LSLA);
default:
{
2017-06-04 01:01:09 +00:00
float quad = x32c_falloffType == EFalloffType::Quadratic ? x330_LFOR : 0.f;
float linear = x32c_falloffType == EFalloffType::Linear ? x330_LFOR : 0.f;
2017-05-06 05:21:42 +00:00
float constant = x32c_falloffType == EFalloffType::Constant ? 1.f : 0.f;
2017-06-04 01:01:09 +00:00
return CLight::BuildCustom(x314_LOFF, {1.f, 0.f, 0.f}, x30c_LCLR,
constant, linear, quad, x310_LINT, 0.f, 0.f);
}
}
2016-02-09 22:52:33 +00:00
}
2016-02-13 05:49:59 +00:00
bool CElementGen::GetParticleEmission() const
{
2017-06-04 01:01:09 +00:00
return x88_particleEmission;
2016-02-13 05:49:59 +00:00
}
2016-02-09 22:52:33 +00:00
void CElementGen::DestroyParticles()
{
2017-06-04 01:01:09 +00:00
g_ParticleAliveCount -= x30_particles.size();
x30_particles.clear();
x50_parentMatrices.clear();
2017-06-04 01:01:09 +00:00
for (const std::unique_ptr<CParticleGen>& ch : x290_activePartChildren)
ch->DestroyParticles();
2016-02-09 22:52:33 +00:00
}
2016-02-18 04:44:06 +00:00
void CElementGen::Reset()
{
2017-06-04 01:01:09 +00:00
x30_particles.clear();
x50_parentMatrices.clear();
2017-05-06 05:21:42 +00:00
x290_activePartChildren.clear();
2017-06-04 01:01:09 +00:00
x74_curFrame = 0;
x78_curSeconds = 0.f;
x84_prevFrame = -1;
x25c_activeParticleCount = 0;
x26d_25_warmedUp = false;
2016-02-18 04:44:06 +00:00
}
2017-01-22 17:36:25 +00:00
void CElementGen::SetMoveRedToAlphaBuffer(bool move)
{
sMoveRedToAlphaBuffer = move;
}
2016-02-08 05:10:17 +00:00
}