2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-14 21:11:22 +00:00
metaforce/Runtime/Particle/CParticleElectric.cpp
Lioncash 221cc5c6b8 RuntimeCommonB: Normalize cpp file includes
Like the prior changes normalizing the inclusions within headers, this
tackles the cpp files of the RuntimeCommonB target, making these source
files consistent with their headers.
2019-12-22 18:12:04 -05:00

749 lines
24 KiB
C++

#include "Runtime/Particle/CParticleElectric.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Graphics/CGraphics.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/Particle/CElectricDescription.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/Particle/CGenDescription.hpp"
#include "Runtime/Particle/CParticleGlobals.hpp"
#include "Runtime/Particle/CParticleSwoosh.hpp"
#include "Runtime/Particle/CSwooshDescription.hpp"
#include <zeus/CQuaternion.hpp>
#include <zeus/CRelAngle.hpp>
namespace urde {
u16 CParticleElectric::g_GlobalSeed = 99;
CParticleElectric::CParticleElectric(const TToken<CElectricDescription>& token)
: x1c_elecDesc(token), x14c_randState(g_GlobalSeed++) {
x1bc_allocated.resize(32);
x450_24_emitting = true;
x450_29_transformDirty = true;
CElectricDescription* desc = x1c_elecDesc.GetObj();
if (CIntElement* sseg = desc->x10_SSEG.get())
sseg->GetValue(x28_currentFrame, x150_SSEG);
if (CIntElement* scnt = desc->xc_SCNT.get())
scnt->GetValue(x28_currentFrame, x154_SCNT);
x154_SCNT = std::min(x154_SCNT, 32);
if (CIntElement* life = desc->x0_LIFE.get())
life->GetValue(0, x2c_LIFE);
else
x2c_LIFE = INT_MAX;
if (desc->x40_SSWH) {
x450_27_haveSSWH = true;
for (int i = 0; i < x154_SCNT; ++i) {
x1e0_swooshGenerators.emplace_back(new CParticleSwoosh(desc->x40_SSWH.m_token, x150_SSEG));
x1e0_swooshGenerators.back()->DoElectricWarmup();
}
}
++x150_SSEG;
x420_calculatedVerts.resize(x150_SSEG);
x440_fractalOffsets.resize(x150_SSEG);
x430_fractalMags.resize(x150_SSEG);
if (desc->x50_GPSM) {
x450_25_haveGPSM = true;
x400_gpsmGenerators.reserve(x154_SCNT);
for (int i = 0; i < x154_SCNT; ++i) {
x400_gpsmGenerators.emplace_back(new CElementGen(desc->x50_GPSM.m_token));
x400_gpsmGenerators.back()->SetParticleEmission(false);
}
}
if (desc->x60_EPSM) {
x450_26_haveEPSM = true;
x410_epsmGenerators.reserve(x154_SCNT);
for (int i = 0; i < x154_SCNT; ++i) {
x410_epsmGenerators.emplace_back(new CElementGen(desc->x60_EPSM.m_token));
x410_epsmGenerators.back()->SetParticleEmission(false);
}
}
if (x1c_elecDesc->x28_LWD1 || x1c_elecDesc->x2c_LWD2 || x1c_elecDesc->x30_LWD3) {
x450_28_haveLWD = true;
for (int i = 0; i < x154_SCNT; ++i)
x2e4_lineManagers.emplace_back(new CLineManager());
}
}
void CParticleElectric::RenderSwooshes() {
for (CParticleElectricManager& elec : x3e8_electricManagers)
x1e0_swooshGenerators[elec.x0_idx]->Render();
}
void CParticleElectric::SetupLineGXMaterial() {
// Konst color/alpha 0
}
void CParticleElectric::DrawLineStrip(const std::vector<zeus::CVector3f>& verts, float width,
const zeus::CColor& color) {
size_t useIdx = m_nextLineRenderer;
if (++m_nextLineRenderer > m_lineRenderers.size())
m_lineRenderers.resize(m_nextLineRenderer);
if (!m_lineRenderers[useIdx])
m_lineRenderers[useIdx] =
std::make_unique<CLineRenderer>(CLineRenderer::EPrimitiveMode::LineStrip, x150_SSEG, nullptr, true, true);
CLineRenderer& renderer = *m_lineRenderers[useIdx];
zeus::CColor useColor = x1b8_moduColor * color;
renderer.Reset();
for (const zeus::CVector3f& vert : verts)
renderer.AddVertex(vert, useColor, width);
renderer.Render(g_Renderer->IsThermalVisorHotPass());
}
void CParticleElectric::RenderLines() {
m_nextLineRenderer = 0;
CGraphics::DisableAllLights();
// Z-test, no write
// Additive blend
CGraphics::SetModelMatrix(zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation *
zeus::CTransform::Translate(x38_translation) * x44_orientation *
zeus::CTransform::Scale(xe0_globalScale) * zeus::CTransform::Scale(xec_localScale));
// Disable culling
SetupLineGXMaterial();
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CLineManager& line = *x2e4_lineManagers[elec.x0_idx];
if (x1c_elecDesc->x28_LWD1)
DrawLineStrip(line.x0_verts, line.x10_widths[0], line.x1c_colors[0]);
if (x1c_elecDesc->x2c_LWD2)
DrawLineStrip(line.x0_verts, line.x10_widths[1], line.x1c_colors[1]);
if (x1c_elecDesc->x30_LWD3)
DrawLineStrip(line.x0_verts, line.x10_widths[2], line.x1c_colors[2]);
}
// Enable culling
// Line Width 1
}
void CParticleElectric::UpdateCachedTransform() {
xf8_cachedXf = zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation *
zeus::CTransform::Translate(x38_translation) * x44_orientation;
x450_29_transformDirty = false;
}
void CParticleElectric::UpdateLine(int idx, int frame) {
CLineManager& line = *x2e4_lineManagers[idx];
if (CColorElement* lcl1 = x1c_elecDesc->x34_LCL1.get())
lcl1->GetValue(frame, line.x1c_colors[0]);
if (CColorElement* lcl2 = x1c_elecDesc->x38_LCL2.get())
lcl2->GetValue(frame, line.x1c_colors[1]);
if (CColorElement* lcl3 = x1c_elecDesc->x3c_LCL3.get())
lcl3->GetValue(frame, line.x1c_colors[2]);
if (CRealElement* lwd1 = x1c_elecDesc->x28_LWD1.get())
lwd1->GetValue(frame, line.x10_widths[0]);
if (CRealElement* lwd2 = x1c_elecDesc->x2c_LWD2.get())
lwd2->GetValue(frame, line.x10_widths[1]);
if (CRealElement* lwd3 = x1c_elecDesc->x30_LWD3.get())
lwd3->GetValue(frame, line.x10_widths[2]);
}
void CParticleElectric::UpdateElectricalEffects() {
for (auto it = x3e8_electricManagers.begin(); it != x3e8_electricManagers.end();) {
CParticleElectricManager& elec = *it;
if (elec.x4_slif <= 1) {
x1bc_allocated[elec.x0_idx] = false;
if (elec.x10_gpsmIdx != -1)
x400_gpsmGenerators[elec.x10_gpsmIdx]->SetParticleEmission(false);
if (elec.x14_epsmIdx != -1)
x410_epsmGenerators[elec.x14_epsmIdx]->SetParticleEmission(false);
it = x3e8_electricManagers.erase(it);
continue;
}
CParticleGlobals::instance()->SetParticleLifetime(elec.xc_endFrame - elec.x8_startFrame);
int frame = x28_currentFrame - elec.x8_startFrame;
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(frame);
if (x450_27_haveSSWH) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
zeus::CColor color = zeus::skWhite;
if (CColorElement* colr = x1c_elecDesc->x14_COLR.get())
colr->GetValue(frame, color);
swoosh.SetModulationColor(color * x1b8_moduColor);
}
if (x450_28_haveLWD)
UpdateLine(elec.x0_idx, frame);
elec.x4_slif -= 1;
++it;
}
}
void CParticleElectric::CalculateFractal(int start, int end, float ampl, float ampd) {
float tmp = (end - start) / float(x430_fractalMags.size()) * ampl;
int storeIdx = (start + end) / 2;
x430_fractalMags[storeIdx] = (x430_fractalMags[start] + x430_fractalMags[end]) * 0.5f + tmp * x14c_randState.Float() -
tmp * 0.5f + ampd * x14c_randState.Float() - ampd * 0.5f;
if ((start + end) & 1)
x430_fractalMags[end - 1] = x430_fractalMags[end];
if (storeIdx - start > 1)
CalculateFractal(start, storeIdx, ampl, ampd);
if (end - storeIdx > 1)
CalculateFractal(storeIdx, end, ampl, ampd);
}
void CParticleElectric::CalculatePoints() {
zeus::CVector3f pos, vel;
if (CEmitterElement* iemt = x1c_elecDesc->x18_IEMT.get())
iemt->GetValue(x28_currentFrame, pos, vel);
if (x178_overrideIPos)
pos = *x178_overrideIPos;
if (x188_overrideIVel)
vel = *x188_overrideIVel;
rstl::reserved_vector<zeus::CVector3f, 4> points;
if (!vel.isZero()) {
points.push_back(pos);
points.push_back(pos + vel);
points.push_back(pos + vel * 2.f);
} else {
points.push_back(pos);
}
zeus::CVector3f fpos = zeus::skForward;
zeus::CVector3f fvel;
if (CEmitterElement* femt = x1c_elecDesc->x1c_FEMT.get())
femt->GetValue(x28_currentFrame, fpos, fvel);
if (x198_overrideFPos)
fpos = *x198_overrideFPos;
if (x1a8_overrideFVel)
fvel = *x1a8_overrideFVel;
if (!fvel.isZero()) {
if (points.size() == 3) {
points.push_back(fpos);
points[2] = fpos + fvel;
} else {
points.push_back(fpos + fvel * 2.f);
points.push_back(fpos + fvel);
points.push_back(fpos);
}
} else {
points.push_back(fpos);
}
if (points.size() == 4) {
int segs = x150_SSEG - 1;
float segDiv = 1.f / float(segs);
float curDiv = segDiv;
for (int i = 1; i < segs; ++i) {
float t = segDiv * x14c_randState.Range(-0.45f, 0.45f) + curDiv;
x420_calculatedVerts[i] = zeus::getBezierPoint(points[0], points[1], points[2], points[3], t);
curDiv += segDiv;
}
x420_calculatedVerts[segs] = points[3];
} else {
x420_calculatedVerts[0] = pos;
int segs = x150_SSEG - 1;
float segDiv = 1.f / float(segs);
zeus::CVector3f accum = x420_calculatedVerts[0];
zeus::CVector3f segDelta = (fpos - pos) * segDiv;
for (int i = 1; i < segs; ++i) {
float r = x14c_randState.Range(-0.45f, 0.45f);
x420_calculatedVerts[i] = segDelta * r + accum;
accum += segDelta;
}
x420_calculatedVerts[segs] = fpos;
}
for (int i = 0; i < x150_SSEG; ++i)
x430_fractalMags[i] = 0.f;
float amplVal = 1.f;
if (CRealElement* ampl = x1c_elecDesc->x20_AMPL.get()) {
ampl->GetValue(x28_currentFrame, amplVal);
amplVal *= 2.f;
}
float ampdVal = 0.f;
if (CRealElement* ampd = x1c_elecDesc->x24_AMPD.get())
ampd->GetValue(x28_currentFrame, ampdVal);
CalculateFractal(0, x420_calculatedVerts.size() - 1, amplVal, ampdVal);
zeus::CVector3f v0 = x420_calculatedVerts[0] - x420_calculatedVerts[1];
zeus::CVector3f v1 = x420_calculatedVerts[x420_calculatedVerts.size() - 1] - x420_calculatedVerts[1];
zeus::CVector3f upVec = zeus::skUp;
if (v0.canBeNormalized() && v1.canBeNormalized()) {
v0.normalize();
v1.normalize();
float dot = v0.dot(v1);
if (dot < 0)
dot = -dot;
if (std::fabs(dot - 1.f) < 0.00001f)
upVec = zeus::lookAt(x420_calculatedVerts[0], x420_calculatedVerts[1]).basis[2];
else
upVec = v0.cross(v1).normalized();
} else if (x420_calculatedVerts[0] != x420_calculatedVerts[1]) {
upVec = zeus::lookAt(x420_calculatedVerts[0], x420_calculatedVerts[1]).basis[2];
}
float commonRand = x14c_randState.Range(0.f, 360.f);
for (int i = 1; i < x420_calculatedVerts.size() - 1; ++i) {
zeus::CVector3f delta = x420_calculatedVerts[i] - x420_calculatedVerts[i - 1];
if (!delta.isZero()) {
zeus::CRelAngle angle =
zeus::degToRad(x430_fractalMags[i] / amplVal * 16.f * x14c_randState.Range(-1.f, 1.f) + commonRand);
x440_fractalOffsets[i] = zeus::CQuaternion::fromAxisAngle(delta, angle).transform(x430_fractalMags[i] * upVec);
}
}
for (int i = 1; i < x420_calculatedVerts.size() - 1; ++i)
x420_calculatedVerts[i] += x440_fractalOffsets[i];
if (x1c_elecDesc->x70_ZERY)
for (int i = 0; i < x420_calculatedVerts.size(); ++i)
x420_calculatedVerts[i].y() = 0.f;
}
void CParticleElectric::CreateNewParticles(int count) {
int allocIdx = 0;
for (int i = 0; i < count; ++i) {
if (x3e8_electricManagers.size() < x154_SCNT) {
zeus::CTransform cachedRot = xf8_cachedXf.getRotation();
int toAdd = x1bc_allocated.size() - allocIdx;
for (int j = 0; j < toAdd; ++j, ++allocIdx) {
if (x1bc_allocated[allocIdx])
continue;
x1bc_allocated[allocIdx] = true;
int lifetime = 1;
if (CIntElement* slif = x1c_elecDesc->x4_SLIF.get())
slif->GetValue(x28_currentFrame, lifetime);
x3e8_electricManagers.push_back(CParticleElectricManager(allocIdx, lifetime, x28_currentFrame));
CParticleElectricManager& elec = x3e8_electricManagers.back();
CParticleGlobals::instance()->SetParticleLifetime(elec.xc_endFrame - elec.x8_startFrame);
int frame = x28_currentFrame - elec.x8_startFrame;
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(frame);
CalculatePoints();
if (x450_27_haveSSWH) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[allocIdx];
swoosh.SetParticleEmission(true);
swoosh.SetGlobalTranslation(xf8_cachedXf.origin);
swoosh.SetGlobalOrientation(cachedRot);
swoosh.SetGlobalScale(xe0_globalScale);
swoosh.SetLocalScale(xec_localScale);
zeus::CColor color = zeus::skWhite;
if (CColorElement* colr = x1c_elecDesc->x14_COLR.get())
colr->GetValue(frame, color);
swoosh.SetModulationColor(color * x1b8_moduColor);
swoosh.DoElectricCreate(x420_calculatedVerts);
}
if (x450_28_haveLWD) {
CLineManager& line = *x2e4_lineManagers[allocIdx];
line.x0_verts = x420_calculatedVerts;
UpdateLine(allocIdx, 0);
if (x450_27_haveSSWH) {
x130_buildBounds = zeus::CAABox();
for (const zeus::CVector3f& vec : x420_calculatedVerts)
x130_buildBounds.accumulateBounds(vec);
line.x28_aabb = x130_buildBounds;
}
}
if (x450_25_haveGPSM) {
for (int k = 0; k < x154_SCNT; ++k) {
CElementGen& gen = *x400_gpsmGenerators[k];
if (!gen.GetParticleEmission()) {
zeus::CTransform scale =
zeus::CTransform::Scale(xe0_globalScale) * zeus::CTransform::Scale(xec_localScale);
gen.SetTranslation(scale * x420_calculatedVerts.front());
gen.SetParticleEmission(true);
elec.x10_gpsmIdx = k;
break;
}
}
}
if (x450_26_haveEPSM) {
for (int k = 0; k < x154_SCNT; ++k) {
CElementGen& gen = *x410_epsmGenerators[k];
if (!gen.GetParticleEmission()) {
zeus::CTransform scale =
zeus::CTransform::Scale(xe0_globalScale) * zeus::CTransform::Scale(xec_localScale);
gen.SetTranslation(scale * x420_calculatedVerts.back());
gen.SetParticleEmission(true);
elec.x14_epsmIdx = k;
break;
}
}
}
break;
}
}
}
}
void CParticleElectric::AddElectricalEffects() {
float genRate = 0.f;
if (CRealElement* grat = x1c_elecDesc->x8_GRAT.get()) {
if (grat->GetValue(x28_currentFrame, genRate)) {
x3e8_electricManagers.clear();
for (int i = 0; i < x1bc_allocated.size(); ++i)
x1bc_allocated[i] = false;
return;
} else {
genRate = std::max(0.f, genRate);
}
}
x15c_genRem += genRate;
int partCount = std::floor(x15c_genRem);
x15c_genRem -= partCount;
CreateNewParticles(partCount);
}
void CParticleElectric::BuildBounds() {
if (GetParticleCount() <= 0) {
x160_systemBounds = zeus::CAABox();
return;
}
x160_systemBounds = zeus::CAABox();
if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
if (auto bounds = swoosh.GetBounds())
x160_systemBounds.accumulateBounds(*bounds);
}
} else if (x450_28_haveLWD) {
zeus::CAABox tmp = zeus::CAABox();
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CLineManager& line = *x2e4_lineManagers[elec.x0_idx];
tmp.accumulateBounds(line.x28_aabb);
}
if (!tmp.invalid()) {
x160_systemBounds.accumulateBounds(tmp.getTransformedAABox(
zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation *
zeus::CTransform::Translate(x38_translation) * x44_orientation * zeus::CTransform::Scale(xe0_globalScale)));
}
}
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
if (auto bounds = x400_gpsmGenerators[i]->GetBounds())
x160_systemBounds.accumulateBounds(*bounds);
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
if (auto bounds = x410_epsmGenerators[i]->GetBounds())
x160_systemBounds.accumulateBounds(*bounds);
}
}
bool CParticleElectric::Update(double dt) {
CGlobalRandom gr(x14c_randState);
bool ret = false;
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
if (!x400_gpsmGenerators[i]->IsSystemDeletable())
break;
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
if (!x410_epsmGenerators[i]->IsSystemDeletable())
break;
}
bool emitting = x450_24_emitting && x28_currentFrame < x2c_LIFE;
double evalTime = x28_currentFrame / 60.0;
x30_curTime += dt;
if (x450_29_transformDirty) {
UpdateCachedTransform();
zeus::CTransform globalOrient = xf8_cachedXf.getRotation();
if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetGlobalTranslation(xf8_cachedXf.origin);
swoosh.SetGlobalOrientation(globalOrient);
swoosh.SetGlobalScale(xe0_globalScale);
swoosh.SetLocalScale(xec_localScale);
}
}
if (x450_25_haveGPSM) {
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CElementGen& gen = *x400_gpsmGenerators[elec.x0_idx];
gen.SetGlobalTranslation(xf8_cachedXf.origin);
gen.SetGlobalOrientation(globalOrient);
gen.SetGlobalScale(xe0_globalScale);
gen.SetLocalScale(xec_localScale);
}
}
if (x450_26_haveEPSM) {
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CElementGen& gen = *x410_epsmGenerators[elec.x0_idx];
gen.SetGlobalTranslation(xf8_cachedXf.origin);
gen.SetGlobalOrientation(globalOrient);
gen.SetGlobalScale(xe0_globalScale);
gen.SetLocalScale(xec_localScale);
}
}
ret = true;
}
while (evalTime < x30_curTime) {
CParticleGlobals::instance()->SetEmitterTime(x28_currentFrame);
UpdateElectricalEffects();
if (emitting)
AddElectricalEffects();
if (x450_25_haveGPSM) {
if (x28_currentFrame >= x2c_LIFE)
for (int i = 0; i < x154_SCNT; ++i)
x400_gpsmGenerators[i]->EndLifetime();
for (int i = 0; i < x154_SCNT; ++i)
x400_gpsmGenerators[i]->Update(1.0 / 60.0);
}
if (x450_26_haveEPSM) {
if (x28_currentFrame >= x2c_LIFE)
for (int i = 0; i < x154_SCNT; ++i)
x410_epsmGenerators[i]->EndLifetime();
for (int i = 0; i < x154_SCNT; ++i)
x410_epsmGenerators[i]->Update(1.0 / 60.0);
}
ret = true;
evalTime += (1.0 / 60.0);
x28_currentFrame += 1;
}
if (ret)
BuildBounds();
return ret;
}
void CParticleElectric::Render(const CActorLights* lights) {
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(fmt("CParticleElectric::Render {}"),
*x1c_elecDesc.GetObjectTag()).c_str(), zeus::skYellow);
if (x3e8_electricManagers.size()) {
if (x450_29_transformDirty)
UpdateCachedTransform();
if (x450_27_haveSSWH)
RenderSwooshes();
if (x450_28_haveLWD)
RenderLines();
}
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x400_gpsmGenerators[i]->Render(lights);
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x410_epsmGenerators[i]->Render(lights);
}
}
void CParticleElectric::SetOrientation(const zeus::CTransform& orientation) {
x44_orientation = orientation;
x74_invOrientation = x44_orientation.inverse();
x450_29_transformDirty = true;
}
void CParticleElectric::SetTranslation(const zeus::CVector3f& translation) {
x38_translation = translation;
x450_29_transformDirty = true;
}
void CParticleElectric::SetGlobalOrientation(const zeus::CTransform& orientation) {
xb0_globalOrientation = orientation;
x450_29_transformDirty = true;
if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetGlobalOrientation(xb0_globalOrientation);
}
}
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x400_gpsmGenerators[i]->SetGlobalOrientation(xb0_globalOrientation);
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x410_epsmGenerators[i]->SetGlobalOrientation(xb0_globalOrientation);
}
}
void CParticleElectric::SetGlobalTranslation(const zeus::CVector3f& translation) {
xa4_globalTranslation = translation;
x450_29_transformDirty = true;
if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetGlobalTranslation(xa4_globalTranslation);
}
}
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x400_gpsmGenerators[i]->SetGlobalTranslation(xa4_globalTranslation);
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x410_epsmGenerators[i]->SetGlobalTranslation(xa4_globalTranslation);
}
}
void CParticleElectric::SetGlobalScale(const zeus::CVector3f& scale) {
xe0_globalScale = scale;
x450_29_transformDirty = true;
}
void CParticleElectric::SetLocalScale(const zeus::CVector3f& scale) {
xec_localScale = scale;
x450_29_transformDirty = true;
if (x450_27_haveSSWH) {
for (CParticleElectricManager& elec : x3e8_electricManagers) {
CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx];
swoosh.SetLocalScale(xec_localScale);
}
}
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x400_gpsmGenerators[i]->SetLocalScale(xec_localScale);
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
x410_epsmGenerators[i]->SetLocalScale(xec_localScale);
}
}
void CParticleElectric::SetParticleEmission(bool e) { x450_24_emitting = e; }
void CParticleElectric::SetModulationColor(const zeus::CColor& color) { x1b8_moduColor = color; }
const zeus::CTransform& CParticleElectric::GetOrientation() const { return x44_orientation; }
const zeus::CVector3f& CParticleElectric::GetTranslation() const { return x38_translation; }
const zeus::CTransform& CParticleElectric::GetGlobalOrientation() const { return xb0_globalOrientation; }
const zeus::CVector3f& CParticleElectric::GetGlobalTranslation() const { return xa4_globalTranslation; }
const zeus::CVector3f& CParticleElectric::GetGlobalScale() const { return xe0_globalScale; }
const zeus::CColor& CParticleElectric::GetModulationColor() const { return x1b8_moduColor; }
bool CParticleElectric::IsSystemDeletable() const {
if (x450_24_emitting && x28_currentFrame < x2c_LIFE)
return false;
if (x3e8_electricManagers.size())
return false;
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
if (!x400_gpsmGenerators[i]->IsSystemDeletable())
return false;
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
if (!x410_epsmGenerators[i]->IsSystemDeletable())
return false;
}
return true;
}
std::optional<zeus::CAABox> CParticleElectric::GetBounds() const {
if (GetParticleCount() <= 0)
return {};
else
return x160_systemBounds;
}
u32 CParticleElectric::GetParticleCount() const {
u32 ret = 0;
for (const CParticleElectricManager& elec : x3e8_electricManagers) {
if (x450_27_haveSSWH)
ret += x1e0_swooshGenerators[elec.x0_idx]->GetParticleCount();
if (x450_28_haveLWD)
ret += x150_SSEG;
}
if (x450_25_haveGPSM) {
for (int i = 0; i < x154_SCNT; ++i)
ret += x400_gpsmGenerators[i]->GetParticleCount();
}
if (x450_26_haveEPSM) {
for (int i = 0; i < x154_SCNT; ++i)
ret += x410_epsmGenerators[i]->GetParticleCount();
}
return ret;
}
bool CParticleElectric::SystemHasLight() const {
if (x450_25_haveGPSM)
return x400_gpsmGenerators.front()->SystemHasLight();
else if (x450_26_haveEPSM)
return x410_epsmGenerators.front()->SystemHasLight();
return false;
}
CLight CParticleElectric::GetLight() const {
if (x450_25_haveGPSM)
return x400_gpsmGenerators.front()->GetLight();
else if (x450_26_haveEPSM)
return x410_epsmGenerators.front()->GetLight();
return CLight::BuildLocalAmbient(GetGlobalTranslation(), zeus::skOrange);
}
bool CParticleElectric::GetParticleEmission() const { return x450_24_emitting; }
void CParticleElectric::DestroyParticles() {
// Empty
}
} // namespace urde