diff --git a/Runtime/Particle/CElementGen.cpp b/Runtime/Particle/CElementGen.cpp index 2e3b5f8e6..323553b09 100644 --- a/Runtime/Particle/CElementGen.cpp +++ b/Runtime/Particle/CElementGen.cpp @@ -17,7 +17,7 @@ static logvisor::Module Log("urde::CElementGen"); URDE_DECL_SPECIALIZE_SHADER(CElementGenShaders) -CRandom16 CElementGen::g_GlobalSeed = 99; +u16 CElementGen::g_GlobalSeed = 99; int CElementGen::g_ParticleAliveCount; int CElementGen::g_ParticleSystemAliveCount; @@ -691,8 +691,8 @@ void CElementGen::UpdateChildParticleSystems(double dt) CSpawnSystemKeyframeData* kssm = desc->xd0_xbc_KSSM.get(); if (kssm && x84_prevFrame != x74_curFrame && x74_curFrame < x268_PSLT) { - CRandom16 backupSeed = g_GlobalSeed; - CRandom16 incSeed = backupSeed; + u16 backupSeed = g_GlobalSeed; + u16 incSeed = backupSeed; std::vector& systems = kssm->GetSpawnedSystemsAtFrame(x74_curFrame); @@ -706,7 +706,7 @@ void CElementGen::UpdateChildParticleSystems(double dt) std::unique_ptr chGen = ConstructChildParticleSystem(token); x290_activePartChildren.emplace_back(std::move(chGen)); } - incSeed.SetSeed(incSeed.GetSeed() + 1); + incSeed += 1; } g_GlobalSeed = backupSeed; diff --git a/Runtime/Particle/CElementGen.hpp b/Runtime/Particle/CElementGen.hpp index a4ee6ee5e..e0e845185 100644 --- a/Runtime/Particle/CElementGen.hpp +++ b/Runtime/Particle/CElementGen.hpp @@ -26,9 +26,9 @@ class CParticleElectric; class CElementGen : public CParticleGen { - static CRandom16 g_GlobalSeed; + static u16 g_GlobalSeed; public: - static void SetGlobalSeed(u16 seed) { g_GlobalSeed.SetSeed(seed); } + static void SetGlobalSeed(u16 seed) { g_GlobalSeed = seed; } enum class EModelOrientationType { Normal, diff --git a/Runtime/Particle/CParticleElectric.cpp b/Runtime/Particle/CParticleElectric.cpp index d9ee0f6b3..8fb9def9b 100644 --- a/Runtime/Particle/CParticleElectric.cpp +++ b/Runtime/Particle/CParticleElectric.cpp @@ -6,146 +6,758 @@ #include "CElementGen.hpp" #include "Graphics/CModel.hpp" #include "Graphics/CGraphics.hpp" +#include "CParticleGlobals.hpp" +#include "zeus/CRelAngle.hpp" +#include "zeus/CQuaternion.hpp" namespace urde { -CRandom16 CParticleElectric::g_GlobalSeed = 99; - -void CParticleElectric::RenderSwooshes() -{ -} +u16 CParticleElectric::g_GlobalSeed = 99; CParticleElectric::CParticleElectric(const TToken& token) - : x1c_elecDesc(token) +: x1c_elecDesc(token), x14c_randState(g_GlobalSeed++) { - x450_24 = true; - /* x438_28_x450_28 = true; demo */ - x450_29 = true; // are 28 and 29 the same between retail and demo? + x450_24_emitting = true; + x450_29_transformDirty = true; CElectricDescription* desc = x1c_elecDesc.GetObj(); - if (desc->x10_SSEG) - desc->x10_SSEG->GetValue(x28_currentFrame, x150_SSEG); - else - { - x150_SSEG++; - x154_SCNT = 1; - } - if (desc->xc_SCNT) - desc->xc_SCNT->GetValue(x28_currentFrame, x154_SCNT); - std::max(0, std::min(x154_SCNT, 32)); + if (CIntElement* sseg = desc->x10_SSEG.get()) + sseg->GetValue(x28_currentFrame, x150_SSEG); - if (desc->x0_LIFE) - desc->x0_LIFE->GetValue(x28_currentFrame, x2c_LIFE); + 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 = 0x7FFFFF; + x2c_LIFE = INT_MAX; if (desc->x40_SSWH) { - x450_27_HaveSSWH = true; - for (int i = 0 ; i < x154_SCNT ; i++) - x1e0_lineManagers[i].SSWH.reset(new CParticleSwoosh(desc->x40_SSWH.m_token, x150_SSEG)); + x450_27_haveSSWH = true; + x1e0_swooshGenerators.reserve(x154_SCNT); + for (int i=0 ; ix40_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; - for (int i = 0 ; i < x154_SCNT ; i++) - x1e0_lineManagers[i].GPSM.reset(new CElementGen(desc->x50_GPSM.m_token, - CElementGen::EModelOrientationType::Normal, - CElementGen::EOptionalSystemFlags::One)); + x450_25_haveGPSM = true; + x400_gpsmGenerators.reserve(x154_SCNT); + for (int i=0 ; ix50_GPSM.m_token, + CElementGen::EModelOrientationType::Normal, + CElementGen::EOptionalSystemFlags::One)); + x400_gpsmGenerators.back()->SetParticleEmission(false); + } } if (desc->x60_EPSM) { - x450_26_HaveEPSM = true; - for (int i = 0 ; i < x154_SCNT ; i++) - x1e0_lineManagers[i].EPSM.reset(new CElementGen(desc->x60_EPSM.m_token, - CElementGen::EModelOrientationType::Normal, - CElementGen::EOptionalSystemFlags::One)); + x450_26_haveEPSM = true; + x410_epsmGenerators.reserve(x154_SCNT); + for (int i=0 ; ix60_EPSM.m_token, + CElementGen::EModelOrientationType::Normal, + CElementGen::EOptionalSystemFlags::One)); + 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 ; iRender(); } void CParticleElectric::SetupLineGXMaterial() { + // Konst color/alpha 0 +} +void CParticleElectric::DrawLineStrip(const std::vector& 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::EPrimitiveMode::LineStrip, + x150_SSEG, nullptr, 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(); } void CParticleElectric::RenderLines() { + m_nextLineRenderer = 0; CGraphics::DisableAllLights(); - CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false); - CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, ERglLogicOp::Clear); + // Z-test, no write + // Additive blend - zeus::CTransform viewXfrm = CGraphics::g_ViewMatrix; - zeus::CTransform localScale; - localScale.Scale(xec_localScale); - zeus::CTransform globalScale; - globalScale.Scale(xe0_globalScale); - zeus::CTransform localTranslation; - localTranslation.Translate(x38_translation); - zeus::CTransform globalTranslation; - globalTranslation.Translate(xa4_globalTranslation); - CGraphics::SetModelMatrix(xb0_globalOrientation * globalTranslation * localTranslation * x44_orientation * globalScale); - CGraphics::SetCullMode(ERglCullMode::None); - SetupLineGXMaterial(); - /* Iterate line managers */ + 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]); + } - CGraphics::SetCullMode(ERglCullMode::Front); - //CGraphics::SetLineWidth(1.f, ERglTexOffset); - CGraphics::SetViewPointMatrix(viewXfrm); + // Enable culling + // Line Width 1 } -bool CParticleElectric::Update(double) +void CParticleElectric::UpdateCachedTransform() { - return false; + 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::SetParticleLifetime(elec.xc_endFrame - elec.x8_startFrame); + int frame = x28_currentFrame - elec.x8_startFrame; + CParticleGlobals::UpdateParticleLifetimeTweenValues(frame); + + if (x450_27_haveSSWH) + { + CParticleSwoosh& swoosh = *x1e0_swooshGenerators[elec.x0_idx]; + zeus::CColor color = zeus::CColor::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 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::CVector3f::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 ; ix20_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::CVector3f::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 ; ix70_ZERY) + for (int i=0 ; ix4_SLIF.get()) + slif->GetValue(x28_currentFrame, lifetime); + + x3e8_electricManagers.push_back(CParticleElectricManager(allocIdx, lifetime, x28_currentFrame)); + CParticleElectricManager& elec = x3e8_electricManagers.back(); + CParticleGlobals::SetParticleLifetime(elec.xc_endFrame - elec.x8_startFrame); + int frame = x28_currentFrame - elec.x8_startFrame; + CParticleGlobals::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::CColor::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::skInvertedBox; + for (const zeus::CVector3f& vec : x420_calculatedVerts) + x130_buildBounds.accumulateBounds(vec); + line.x28_aabb = x130_buildBounds; + } + } + + if (x450_25_haveGPSM) + { + for (int k=0 ; kx8_GRAT.get()) + { + if (grat->GetValue(x28_currentFrame, genRate)) + { + x3e8_electricManagers.clear(); + for (int i=0 ; iGetBounds()) + x160_systemBounds.accumulateBounds(*bounds); + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iGetBounds()) + x160_systemBounds.accumulateBounds(*bounds); + } +} + +bool CParticleElectric::Update(double dt) +{ + CGlobalRandom gr(x14c_randState); + bool ret = false; + + if (x450_25_haveGPSM) + { + for (int i=0 ; iIsSystemDeletable()) + break; + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iIsSystemDeletable()) + 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::SetEmitterTime(x28_currentFrame); + UpdateElectricalEffects(); + if (emitting) + AddElectricalEffects(); + + if (x450_25_haveGPSM) + { + if (x28_currentFrame >= x2c_LIFE) + for (int i=0 ; iEndLifetime(); + for (int i=0 ; iUpdate(1.0 / 60.0); + } + + if (x450_26_haveEPSM) + { + if (x28_currentFrame >= x2c_LIFE) + for (int i=0 ; iEndLifetime(); + for (int i=0 ; iUpdate(1.0 / 60.0); + } + + ret = true; + evalTime += (1.0 / 60.0); + x28_currentFrame += 1; + } + + if (ret) + BuildBounds(); + + return ret; } void CParticleElectric::Render() { + 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 ; iRender(); + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iRender(); + } } void CParticleElectric::SetOrientation(const zeus::CTransform& orientation) { x44_orientation = orientation; - x450_28 = true; + x74_invOrientation = x44_orientation.inverse(); + x450_29_transformDirty = true; } void CParticleElectric::SetTranslation(const zeus::CVector3f& translation) { x38_translation = translation; - x450_28 = true; + x450_29_transformDirty = true; } void CParticleElectric::SetGlobalOrientation(const zeus::CTransform& orientation) { xb0_globalOrientation = orientation; - x450_28 = true; + 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 ; iSetGlobalOrientation(xb0_globalOrientation); + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iSetGlobalOrientation(xb0_globalOrientation); + } } void CParticleElectric::SetGlobalTranslation(const zeus::CVector3f& translation) { xa4_globalTranslation = translation; - x450_28 = true; + 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 ; iSetGlobalTranslation(xa4_globalTranslation); + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iSetGlobalTranslation(xa4_globalTranslation); + } } void CParticleElectric::SetGlobalScale(const zeus::CVector3f& scale) { xe0_globalScale = scale; - x450_28 = true; + x450_29_transformDirty = true; } void CParticleElectric::SetLocalScale(const zeus::CVector3f& scale) { xec_localScale = scale; - x450_29 = true; - if (x450_27_HaveSSWH) + 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 ; iSetLocalScale(xec_localScale); + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iSetLocalScale(xec_localScale); } } -void CParticleElectric::SetParticleEmission(bool) +void CParticleElectric::SetParticleEmission(bool e) { + x450_24_emitting = e; } void CParticleElectric::SetModulationColor(const zeus::CColor& color) @@ -185,37 +797,90 @@ const zeus::CColor& CParticleElectric::GetModulationColor() const bool CParticleElectric::IsSystemDeletable() const { - return false; + if (x450_24_emitting && x28_currentFrame < x2c_LIFE) + return false; + + if (x3e8_electricManagers.size()) + return false; + + if (x450_25_haveGPSM) + { + for (int i=0 ; iIsSystemDeletable()) + return false; + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iIsSystemDeletable()) + return false; + } + + return true; } rstl::optional_object CParticleElectric::GetBounds() const { - return {}; + if (GetParticleCount() <= 0) + return {}; + else + return x160_systemBounds; } u32 CParticleElectric::GetParticleCount() const { - return 0; + 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 ; iGetParticleCount(); + } + + if (x450_26_haveEPSM) + { + for (int i=0 ; iGetParticleCount(); + } + + 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 { - return CLight(zeus::CVector3f::skZero, zeus::CVector3f::skZero, - zeus::CColor::skBlack, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f); + if (x450_25_haveGPSM) + return x400_gpsmGenerators.front()->GetLight(); + else if (x450_26_haveEPSM) + return x410_epsmGenerators.front()->GetLight(); + return CLight::BuildLocalAmbient(GetGlobalTranslation(), zeus::CColor::skOrange); } bool CParticleElectric::GetParticleEmission() const { - return false; + return x450_24_emitting; } void CParticleElectric::DestroyParticles() { + // Empty } } diff --git a/Runtime/Particle/CParticleElectric.hpp b/Runtime/Particle/CParticleElectric.hpp index abd87190d..2bc506f66 100644 --- a/Runtime/Particle/CParticleElectric.hpp +++ b/Runtime/Particle/CParticleElectric.hpp @@ -4,6 +4,7 @@ #include "CParticleGen.hpp" #include "CToken.hpp" #include "CRandom16.hpp" +#include "Graphics/CLineRenderer.hpp" namespace urde { @@ -13,78 +14,100 @@ class CElementGen; class CParticleElectric : public CParticleGen { - static CRandom16 g_GlobalSeed; + static u16 g_GlobalSeed; public: - static void SetGlobalSeed(u16 seed) { g_GlobalSeed.SetSeed(seed); } - struct CLineManager + static void SetGlobalSeed(u16 seed) { g_GlobalSeed = seed; } + class CLineManager { - std::unique_ptr SSWH; - std::unique_ptr GPSM; - std::unique_ptr EPSM; + friend class CParticleElectric; + std::vector x0_verts; + float x10_widths[3] = {1.f, 2.f, 3.f}; + zeus::CColor x1c_colors[3]; + zeus::CAABox x28_aabb = zeus::CAABox::skInvertedBox; + }; + + class CParticleElectricManager + { + friend class CParticleElectric; + u32 x0_idx; + u32 x4_slif; + u32 x8_startFrame; + u32 xc_endFrame; + int x10_gpsmIdx = -1; + int x14_epsmIdx = -1; + public: + CParticleElectricManager(u32 idx, u32 slif, u32 startFrame) + : x0_idx(idx), x4_slif(slif), x8_startFrame(startFrame), xc_endFrame(startFrame + slif) {} }; private: TLockedToken x1c_elecDesc; int x28_currentFrame = 0; - int x2c_LIFE = 0x7FFFFF; - double x30 = 0.0; + int x2c_LIFE; + double x30_curTime = 0.0; zeus::CVector3f x38_translation; zeus::CTransform x44_orientation; + zeus::CTransform x74_invOrientation; zeus::CVector3f xa4_globalTranslation; zeus::CTransform xb0_globalOrientation; zeus::CVector3f xe0_globalScale; zeus::CVector3f xec_localScale; + zeus::CTransform xf8_cachedXf; float x128 = 0.f; float x12c = 0.f; - zeus::CVector3f x130; - zeus::CVector3f x13c; + zeus::CAABox x130_buildBounds = zeus::CAABox::skInvertedBox; CRandom16 x14c_randState; int x150_SSEG = 8; int x154_SCNT = 1; int x158 = 0; - float x15c = 0.f; + float x15c_genRem = 0.f; zeus::CAABox x160_systemBounds = zeus::CAABox::skInvertedBox; - bool x184 = false; - bool x194 = false; - bool x1b4 = false; + std::experimental::optional x178_overrideIPos; + std::experimental::optional x188_overrideIVel; + std::experimental::optional x198_overrideFPos; + std::experimental::optional x1a8_overrideFVel; zeus::CColor x1b8_moduColor; - rstl::reserved_vector x1c0_; - rstl::reserved_vector x1e0_lineManagers; - int x414 = 0; - int x418 = 0; - int x41c = 0; - int x424 = 0; - int x428 = 0; - int x42c = 0; - int x434 = 0; - int x438 = 0; - int x43c = 0; - int x444 = 0; - int x448 = 0; // retail - int x44c = 0; // retail + rstl::reserved_vector x1bc_allocated; + rstl::reserved_vector, 32> x1e0_swooshGenerators; + rstl::reserved_vector, 32> x2e4_lineManagers; + std::list x3e8_electricManagers; + std::vector> x400_gpsmGenerators; + std::vector> x410_epsmGenerators; + std::vector x420_calculatedVerts; + std::vector x430_fractalMags; + std::vector x440_fractalOffsets; + + size_t m_nextLineRenderer = 0; + std::vector> m_lineRenderers; union { struct { - bool x450_24 : 1; bool x450_25_HaveGPSM : 1; bool x450_26_HaveEPSM : 1; - bool x450_27_HaveSSWH : 1; bool x450_28: 1; bool x450_29 : 1; + bool x450_24_emitting : 1; bool x450_25_haveGPSM : 1; bool x450_26_haveEPSM : 1; + bool x450_27_haveSSWH : 1; bool x450_28_haveLWD: 1; bool x450_29_transformDirty : 1; }; - u8 dummy = 0; + u32 dummy = 0; }; -public: - - - CParticleElectric(const TToken& desc); - void SetupLineGXMaterial(); - bool Update(double); + void DrawLineStrip(const std::vector& verts, float width, const zeus::CColor& color); void RenderLines(); void RenderSwooshes(); - void Render(); - void CalculateFractal(s32, s32, float, float); + void UpdateCachedTransform(); + void UpdateLine(int idx, int frame); + void UpdateElectricalEffects(); + void CalculateFractal(int start, int end, float ampl, float ampd); void CalculatePoints(); + void CreateNewParticles(int count); + void AddElectricalEffects(); + void BuildBounds(); + +public: + CParticleElectric(const TToken& desc); + + bool Update(double); + void Render(); void SetOrientation(const zeus::CTransform&); void SetTranslation(const zeus::CVector3f&); void SetGlobalOrientation(const zeus::CTransform&); diff --git a/Runtime/Particle/CParticleSwoosh.cpp b/Runtime/Particle/CParticleSwoosh.cpp index 8814ae62e..142cafc8b 100644 --- a/Runtime/Particle/CParticleSwoosh.cpp +++ b/Runtime/Particle/CParticleSwoosh.cpp @@ -227,7 +227,7 @@ bool CParticleSwoosh::Update(double dt) CParticleGlobals::UpdateParticleLifetimeTweenValues(0); CGlobalRandom gr(x1c0_rand); - float evalTime = x28_curFrame * (1.f / 60.f); + double evalTime = x28_curFrame / 60.0; float time = 1.f; if (CRealElement* timeElem = x1c_desc->x4_TIME.get()) timeElem->GetValue(x28_curFrame, time); @@ -290,7 +290,7 @@ bool CParticleSwoosh::Update(double dt) UpdateTranslationAndOrientation(); - evalTime += (1.f / 60.f); + evalTime += (1.0 / 60.0); x28_curFrame += 1; } diff --git a/Runtime/Particle/CParticleSwoosh.hpp b/Runtime/Particle/CParticleSwoosh.hpp index 00d61f56a..ba494168a 100644 --- a/Runtime/Particle/CParticleSwoosh.hpp +++ b/Runtime/Particle/CParticleSwoosh.hpp @@ -159,6 +159,25 @@ public: void DestroyParticles(); void Reset() {} FourCC Get4CharId() const { return FOURCC('SWHC'); } + + void DoElectricWarmup() + { + for (int i=0 ; i& offsets) + { + int curIdx = x158_curParticle; + for (int i=0 ; i& wDesc, const zeus::CVector3f&, const zeus::CTransform&, const zeus::CVector3f&, s32) diff --git a/Runtime/Weapon/CProjectileWeapon.hpp b/Runtime/Weapon/CProjectileWeapon.hpp index 1e359009a..ba51ca328 100644 --- a/Runtime/Weapon/CProjectileWeapon.hpp +++ b/Runtime/Weapon/CProjectileWeapon.hpp @@ -16,7 +16,7 @@ namespace urde class CModel; class CProjectileWeapon { - static CRandom16 g_GlobalSeed; + static u16 g_GlobalSeed; TLockedToken x4_weaponDesc; CRandom16 x10_random; zeus::CTransform x14_; @@ -68,7 +68,7 @@ public: void Update(float); void UpdateParticleFx(); void UpdateChildParticleSystems(float); - static void SetGlobalSeed(u16 seed) { g_GlobalSeed.SetSeed(seed); } + static void SetGlobalSeed(u16 seed) { g_GlobalSeed = seed; } }; }