metaforce/Runtime/Particle/CParticleSwoosh.cpp

1097 lines
37 KiB
C++
Raw Normal View History

#include "Runtime/Particle/CParticleSwoosh.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Particle/CParticleGlobals.hpp"
#include "Runtime/Particle/CSwooshDescription.hpp"
#include <chrono>
2018-12-08 05:30:43 +00:00
namespace urde {
int CParticleSwoosh::g_ParticleSystemAliveCount = 0;
CParticleSwoosh::CParticleSwoosh(const TToken<CSwooshDescription>& desc, int leng)
2018-12-08 05:30:43 +00:00
: x1c_desc(desc)
, x1c0_rand(x1c_desc->x45_26_CRND ? std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count()
: 99)
, x1d0_24_emitting(true)
, x1d0_25_AALP(false)
, x1d0_26_forceOneUpdate(false)
, x1d0_27_renderGaps(false)
, x1d0_28_LLRD(false)
, x1d0_29_VLS1(false)
, x1d0_30_VLS2(false)
, x1d0_31_constantTex(false)
, x1d1_24_constantUv(false) {
2018-12-08 05:30:43 +00:00
++g_ParticleSystemAliveCount;
if (leng > 0) {
2018-12-08 05:30:43 +00:00
x1b4_LENG = leng;
} else if (CIntElement* lengElement = x1c_desc->x10_LENG.get()) {
lengElement->GetValue(0, x1b4_LENG);
}
2018-12-08 05:30:43 +00:00
x1b4_LENG += 1;
if (CIntElement* side = x1c_desc->x18_SIDE.get()) {
2018-12-08 05:30:43 +00:00
side->GetValue(0, x1b8_SIDE);
}
2018-12-08 05:30:43 +00:00
x1d0_28_LLRD = x1c_desc->x44_24_LLRD;
x1d0_29_VLS1 = x1c_desc->x44_26_VLS1;
x1d0_30_VLS2 = x1c_desc->x44_27_VLS2;
if (IsValid()) {
if (CIntElement* pslt = x1c_desc->x0_PSLT.get()) {
2018-12-08 05:30:43 +00:00
pslt->GetValue(0, x2c_PSLT);
} else {
2018-12-08 05:30:43 +00:00
x2c_PSLT = INT_MAX;
}
2018-12-08 05:30:43 +00:00
x1d0_25_AALP = x1c_desc->x44_31_AALP;
if (CIntElement* spln = x1c_desc->x38_SPLN.get()) {
2018-12-08 05:30:43 +00:00
spln->GetValue(0, x1b0_SPLN);
}
if (x1b0_SPLN < 0) {
2018-12-08 05:30:43 +00:00
x1b0_SPLN = 0;
}
2018-12-08 05:30:43 +00:00
x15c_swooshes.clear();
x15c_swooshes.reserve(x1b4_LENG);
for (int i = 0; i < x1b4_LENG; ++i) {
x15c_swooshes.emplace_back(zeus::skZero3f, zeus::skZero3f, 0.f, 0.f, 0, false, zeus::CTransform(), zeus::skZero3f,
0.f, 0.f, zeus::skClear);
}
2018-12-08 05:30:43 +00:00
SetOrientation(zeus::CTransform());
2018-12-08 05:30:43 +00:00
x16c_p0.resize(x1b8_SIDE);
x17c_p1.resize(x1b8_SIDE);
x18c_p2.resize(x1b8_SIDE);
x19c_p3.resize(x1b8_SIDE);
if (x1c_desc->x44_29_WIRE) {
const int maxVerts = x1b4_LENG * (x1b0_SPLN + 1) * x1b8_SIDE * 12;
2018-12-08 05:30:43 +00:00
m_lineRenderer.reset(
new CLineRenderer(CLineRenderer::EPrimitiveMode::Lines, maxVerts * 2, nullptr, x1d0_25_AALP));
} else {
const auto maxVerts = size_t(x1b4_LENG * (x1b0_SPLN + 1) * x1b8_SIDE * 4);
2018-12-08 05:30:43 +00:00
m_cachedVerts.reserve(maxVerts);
CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx) {
m_vertBuf = ctx.newDynamicBuffer(boo::BufferUse::Vertex, sizeof(CParticleSwooshShaders::Vert), maxVerts);
m_uniformBuf = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(zeus::CMatrix4f), 1);
CParticleSwooshShaders::BuildShaderDataBinding(ctx, *this);
return true;
} BooTrace);
}
2018-12-08 05:30:43 +00:00
}
}
2018-12-08 05:30:43 +00:00
CParticleSwoosh::~CParticleSwoosh() { --g_ParticleSystemAliveCount; }
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::UpdateMaxRadius(float r) { x208_maxRadius = std::max(x208_maxRadius, r); }
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::UpdateBounds(const zeus::CVector3f& pos) {
x1fc_aabbMax[0] = std::max(pos[0], float(x1fc_aabbMax[0]));
x1fc_aabbMax[1] = std::max(pos[1], float(x1fc_aabbMax[1]));
x1fc_aabbMax[2] = std::max(pos[2], float(x1fc_aabbMax[2]));
x1f0_aabbMin[0] = std::min(pos[0], float(x1f0_aabbMin[0]));
x1f0_aabbMin[1] = std::min(pos[1], float(x1f0_aabbMin[1]));
x1f0_aabbMin[2] = std::min(pos[2], float(x1f0_aabbMin[2]));
2017-06-05 02:40:29 +00:00
}
float CParticleSwoosh::GetLeftRadius(size_t i) const {
2018-12-08 05:30:43 +00:00
float ret = 0.f;
if (CRealElement* lrad = x1c_desc->x8_LRAD.get()) {
2018-12-08 05:30:43 +00:00
lrad->GetValue(x15c_swooshes[i].x68_frame, ret);
}
2018-12-08 05:30:43 +00:00
return ret;
}
float CParticleSwoosh::GetRightRadius(size_t i) const {
2018-12-08 05:30:43 +00:00
float ret = 0.f;
if (CRealElement* rrad = x1c_desc->xc_RRAD.get()) {
2018-12-08 05:30:43 +00:00
rrad->GetValue(x15c_swooshes[i].x68_frame, ret);
}
2018-12-08 05:30:43 +00:00
return ret;
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::UpdateSwooshTranslation(const zeus::CVector3f& translation) {
x15c_swooshes[x158_curParticle].xc_translation = x11c_invScaleXf * translation;
2016-02-13 05:49:59 +00:00
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::UpdateTranslationAndOrientation() {
x208_maxRadius = 0.f;
x1f0_aabbMin = zeus::CVector3f(FLT_MAX);
x1fc_aabbMax = zeus::CVector3f(-FLT_MAX);
CParticleGlobals::instance()->SetParticleLifetime(x1b4_LENG);
CParticleGlobals::instance()->SetEmitterTime(x28_curFrame);
2017-06-05 02:40:29 +00:00
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
2018-12-08 05:30:43 +00:00
SSwooshData& swoosh = x15c_swooshes[i];
if (!swoosh.x0_active)
continue;
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
swoosh.x68_frame = x28_curFrame - swoosh.x70_startFrame;
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(swoosh.x68_frame);
2018-12-08 05:30:43 +00:00
if (x1c_desc->x44_28_SROT) {
if (CRealElement* irot = x1c_desc->x1c_IROT.get()) {
2018-12-08 05:30:43 +00:00
irot->GetValue(x28_curFrame, swoosh.x30_irot);
}
2018-12-08 05:30:43 +00:00
swoosh.x34_rotm = 0.f;
} else {
if (CRealElement* rotm = x1c_desc->x20_ROTM.get()) {
2018-12-08 05:30:43 +00:00
rotm->GetValue(x28_curFrame, swoosh.x34_rotm);
} else {
2018-12-08 05:30:43 +00:00
swoosh.x34_rotm = 0.f;
}
2018-12-08 05:30:43 +00:00
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (CModVectorElement* velm = x1c_desc->x30_VELM.get()) {
if (x1d0_29_VLS1) {
zeus::CVector3f localVel = x74_invOrientation * swoosh.x74_velocity;
zeus::CVector3f localTrans = x74_invOrientation * (swoosh.xc_translation - x38_translation);
velm->GetValue(swoosh.x68_frame, localVel, localTrans);
swoosh.x74_velocity = x44_orientation * localVel;
swoosh.xc_translation = x44_orientation * localTrans + x38_translation;
} else {
velm->GetValue(swoosh.x68_frame, swoosh.x74_velocity, swoosh.xc_translation);
}
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (CModVectorElement* vlm2 = x1c_desc->x34_VLM2.get()) {
if (x1d0_30_VLS2) {
zeus::CVector3f localVel = x74_invOrientation * swoosh.x74_velocity;
zeus::CVector3f localTrans = x74_invOrientation * (swoosh.xc_translation - x38_translation);
vlm2->GetValue(swoosh.x68_frame, localVel, localTrans);
swoosh.x74_velocity = x44_orientation * localVel;
swoosh.xc_translation = x44_orientation * localTrans + x38_translation;
} else {
vlm2->GetValue(swoosh.x68_frame, swoosh.x74_velocity, swoosh.xc_translation);
}
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (swoosh.x68_frame > 0) {
swoosh.xc_translation += swoosh.x74_velocity;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (CVectorElement* npos = x1c_desc->x2c_NPOS.get()) {
zeus::CVector3f vec;
npos->GetValue(swoosh.x68_frame, vec);
swoosh.x24_useOffset = swoosh.x18_offset + vec;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (CColorElement* colr = x1c_desc->x14_COLR.get()) {
colr->GetValue(swoosh.x68_frame, swoosh.x6c_color);
}
2018-12-08 05:30:43 +00:00
swoosh.x4_leftRad = GetLeftRadius(i);
UpdateMaxRadius(swoosh.x4_leftRad);
if (x1d0_28_LLRD) {
swoosh.x8_rightRad = swoosh.x4_leftRad;
} else {
swoosh.x8_rightRad = GetRightRadius(i);
UpdateMaxRadius(swoosh.x8_rightRad);
2017-06-05 02:40:29 +00:00
}
2018-12-08 05:30:43 +00:00
UpdateBounds(swoosh.xc_translation + swoosh.x24_useOffset);
}
}
2018-12-08 05:30:43 +00:00
bool CParticleSwoosh::Update(double dt) {
if (!IsValid()) {
2018-12-08 05:30:43 +00:00
return false;
}
CParticleGlobals::instance()->SetParticleLifetime(x1b4_LENG);
CParticleGlobals::instance()->SetEmitterTime(x28_curFrame);
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(0);
2018-12-08 05:30:43 +00:00
CGlobalRandom gr(x1c0_rand);
2018-12-08 05:30:43 +00:00
double evalTime = x28_curFrame / 60.0;
float time = 1.f;
if (CRealElement* timeElem = x1c_desc->x4_TIME.get()) {
2018-12-08 05:30:43 +00:00
timeElem->GetValue(x28_curFrame, time);
}
2018-12-08 05:30:43 +00:00
x30_curTime += std::max(0.0, dt * time);
while (x1d0_26_forceOneUpdate || evalTime < x30_curTime) {
x1d0_26_forceOneUpdate = false;
2018-12-08 05:30:43 +00:00
x158_curParticle += 1;
if (x158_curParticle >= x15c_swooshes.size()) {
2018-12-08 05:30:43 +00:00
x158_curParticle = 0;
}
2018-12-08 05:30:43 +00:00
if (x1d0_24_emitting && x28_curFrame < x2c_PSLT) {
UpdateSwooshTranslation(x38_translation);
if (CRealElement* irot = x1c_desc->x1c_IROT.get()) {
2018-12-08 05:30:43 +00:00
irot->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x30_irot);
} else {
2018-12-08 05:30:43 +00:00
x15c_swooshes[x158_curParticle].x30_irot = 0.f;
}
2018-12-08 05:30:43 +00:00
x15c_swooshes[x158_curParticle].x34_rotm = 0.f;
x15c_swooshes[x158_curParticle].x70_startFrame = x28_curFrame;
2018-12-08 05:30:43 +00:00
if (!x15c_swooshes[x158_curParticle].x0_active) {
x1ac_particleCount += 1;
x15c_swooshes[x158_curParticle].x0_active = true;
}
2018-12-08 05:30:43 +00:00
x15c_swooshes[x158_curParticle].x38_orientation = x44_orientation;
2018-12-08 05:30:43 +00:00
if (CVectorElement* ivel = x1c_desc->x28_IVEL.get()) {
ivel->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x74_velocity);
x15c_swooshes[x158_curParticle].x74_velocity = x44_orientation * x15c_swooshes[x158_curParticle].x74_velocity;
}
2017-06-05 02:40:29 +00:00
if (CVectorElement* pofs = x1c_desc->x24_POFS.get()) {
2018-12-08 05:30:43 +00:00
pofs->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x18_offset);
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
x15c_swooshes[x158_curParticle].x24_useOffset = x15c_swooshes[x158_curParticle].x18_offset;
2017-06-05 02:40:29 +00:00
if (CColorElement* colr = x1c_desc->x14_COLR.get()) {
2018-12-08 05:30:43 +00:00
colr->GetValue(x28_curFrame, x15c_swooshes[x158_curParticle].x6c_color);
} else {
x15c_swooshes[x158_curParticle].x6c_color = zeus::skWhite;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
int tspn = 0;
if (CIntElement* tspnElem = x1c_desc->x40_TSPN.get()) {
2018-12-08 05:30:43 +00:00
tspnElem->GetValue(x28_curFrame, tspn);
}
x1cc_TSPN = float(tspn);
2018-12-08 05:30:43 +00:00
} else if (x15c_swooshes[x158_curParticle].x0_active) {
x1ac_particleCount = std::max(0, int(x1ac_particleCount) - 1);
x15c_swooshes[x158_curParticle].x0_active = false;
}
2018-12-08 05:30:43 +00:00
UpdateTranslationAndOrientation();
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
evalTime += (1.0 / 60.0);
x28_curFrame += 1;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
return false;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
zeus::CVector3f CParticleSwoosh::GetSplinePoint(const zeus::CVector3f& p0, const zeus::CVector3f& p1,
const zeus::CVector3f& p2, const zeus::CVector3f& p3, float t) {
if (t > 0.f) {
2018-12-08 05:30:43 +00:00
return p1;
}
if (t >= 1.f) {
2018-12-08 05:30:43 +00:00
return p2;
}
2018-12-08 05:30:43 +00:00
// Tricubic spline interpolation
const float t2 = t * t;
const float t3 = t2 * t;
2018-12-08 05:30:43 +00:00
const float p0Coef = -0.5f * t3 + t2 - 0.5f * t;
const float p1Coef = 1.5f * t3 - 2.5f * t2 + 1.f;
const float p2Coef = -1.5f * t3 + 2.f * t2 + 0.5f * t;
const float p3Coef = 0.5f * t3 + 0.5f * t2;
2018-12-08 05:30:43 +00:00
return p0 * p0Coef + p1 * p1Coef + p2 * p2Coef + p3 * p3Coef;
}
int CParticleSwoosh::WrapIndex(int i) const {
while (i < 0) {
2018-12-08 05:30:43 +00:00
i += x1b4_LENG;
}
while (i >= x1b4_LENG) {
2018-12-08 05:30:43 +00:00
i -= x1b4_LENG;
}
2018-12-08 05:30:43 +00:00
return i;
}
void CParticleSwoosh::RenderNSidedSpline() {
if (x1c_desc->x44_29_WIRE) {
x1bc_prim = GX::LINES;
m_lineRenderer->Reset();
} else {
x1bc_prim = GX::QUADS;
}
bool cros = x1c_desc->x44_25_CROS;
if (x1b8_SIDE >= 4 || (x1b8_SIDE & 0x1) != 0) {
2018-12-08 05:30:43 +00:00
cros = false;
}
2018-12-08 05:30:43 +00:00
int curIdx = x158_curParticle;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
const bool a0 = x15c_swooshes[WrapIndex(curIdx - 1)].x0_active;
const bool a1 = x15c_swooshes[WrapIndex(curIdx)].x0_active;
2018-12-08 05:30:43 +00:00
if (!a1 || (a1 && !a0)) {
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 1;
}
2018-12-08 05:30:43 +00:00
continue;
}
2017-06-05 02:40:29 +00:00
const SSwooshData& refSwoosh = x15c_swooshes[curIdx];
2018-12-08 05:30:43 +00:00
const float sideDiv = 360.f / float(x1b8_SIDE);
2018-12-08 05:30:43 +00:00
for (int j = 0; j < 4; ++j) {
int crossRefIdx = 0;
if (j == 0) {
crossRefIdx = WrapIndex(curIdx + 1);
if (!x15c_swooshes[crossRefIdx].x0_active) {
2018-12-08 05:30:43 +00:00
crossRefIdx = curIdx;
}
2018-12-08 05:30:43 +00:00
} else if (j == 1) {
crossRefIdx = WrapIndex(curIdx);
} else if (j == 2) {
crossRefIdx = WrapIndex(curIdx - 1);
} else if (j == 3) {
crossRefIdx = WrapIndex(curIdx - 2);
if (!x15c_swooshes[crossRefIdx].x0_active) {
2018-12-08 05:30:43 +00:00
crossRefIdx = WrapIndex(curIdx - 1);
}
2018-12-08 05:30:43 +00:00
}
if (x1b4_LENG == 2) {
if (j == 0) {
2018-12-08 05:30:43 +00:00
crossRefIdx = WrapIndex(curIdx);
}
if (j == 3) {
2018-12-08 05:30:43 +00:00
crossRefIdx = WrapIndex(curIdx - 1);
}
2018-12-08 05:30:43 +00:00
} else if (x158_curParticle == curIdx && j == 0) {
crossRefIdx = x158_curParticle;
} else {
if (WrapIndex(x158_curParticle + 2) == curIdx && j == 3) {
2018-12-08 05:30:43 +00:00
crossRefIdx = WrapIndex(x158_curParticle + 1);
} else if (x1ac_particleCount - 2 == i && j == 3) {
2018-12-08 05:30:43 +00:00
crossRefIdx = 0;
}
2018-12-08 05:30:43 +00:00
}
const SSwooshData& crossSwoosh = x15c_swooshes[crossRefIdx];
2018-12-08 05:30:43 +00:00
for (int k = 0; k < x1b8_SIDE; ++k) {
const float n = sideDiv * k;
2018-12-08 05:30:43 +00:00
float ang = zeus::degToRad(n + crossSwoosh.x30_irot + crossSwoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) {
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) {
2018-12-08 05:30:43 +00:00
ang -= 2.f * M_PIF;
} else if (ang < -M_PIF) {
2018-12-08 05:30:43 +00:00
ang += 2.f * M_PIF;
}
2018-12-08 05:30:43 +00:00
}
const float z = std::sin(ang);
const float x = std::cos(ang);
2018-12-08 05:30:43 +00:00
const float rad = (n > 0.f && n <= 180.f) ? crossSwoosh.x4_leftRad : crossSwoosh.x8_rightRad;
const zeus::CVector3f offset = crossSwoosh.xc_translation + crossSwoosh.x24_useOffset;
2018-12-08 05:30:43 +00:00
if (j == 0) {
2018-12-08 05:30:43 +00:00
x16c_p0[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
} else if (j == 1) {
2018-12-08 05:30:43 +00:00
x17c_p1[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
} else if (j == 2) {
2018-12-08 05:30:43 +00:00
x18c_p2[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
} else if (j == 3) {
2018-12-08 05:30:43 +00:00
x19c_p3[k] = crossSwoosh.x38_orientation * zeus::CVector3f(rad * x, 0.f, rad * z) + offset;
}
2018-12-08 05:30:43 +00:00
}
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (x1c_desc->x3c_TEXR) {
if (x1ec_TSPN > 0) {
x1d4_uvs.xMin = float((i % x1ec_TSPN) * x1e8_uvSpan);
} else {
x1d4_uvs.xMin = float(i * x1e8_uvSpan);
}
2017-06-05 02:40:29 +00:00
}
const float segUvSpan = x1e8_uvSpan / float(x1b0_SPLN + 1);
2018-12-08 05:30:43 +00:00
for (int j = 0; j < x1b0_SPLN + 1; ++j) {
const float t0 = j / float(x1b0_SPLN + 1);
const float t1 = (j + 1) / float(x1b0_SPLN + 1);
2018-12-08 05:30:43 +00:00
int faces = x1b8_SIDE;
if (x1b8_SIDE <= 2) {
2018-12-08 05:30:43 +00:00
faces = 1;
} else if (cros) {
2018-12-08 05:30:43 +00:00
faces = x1b8_SIDE / 2;
}
2018-12-08 05:30:43 +00:00
x1d4_uvs.xMax = x1d4_uvs.xMin + segUvSpan;
for (int k = 0; k < faces; ++k) {
int otherK = k + 1;
if (k + 1 >= x1b8_SIDE) {
2018-12-08 05:30:43 +00:00
otherK = 0;
}
const zeus::CColor color = refSwoosh.x6c_color * x20c_moduColor;
2018-12-08 05:30:43 +00:00
if (cros) {
otherK = k + x1b8_SIDE / 2;
const auto v0 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t0);
const auto v1 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t0);
const auto v2 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t1);
const auto v3 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t1);
2018-12-08 05:30:43 +00:00
m_cachedVerts.push_back({v0, {x1d4_uvs.xMin, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {x1d4_uvs.xMin, x1d4_uvs.yMax}, color});
m_cachedVerts.push_back({v2, {x1d4_uvs.xMax, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v3, {x1d4_uvs.xMax, x1d4_uvs.yMax}, color});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
} else {
const auto v0 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t0);
const auto v1 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t0);
const auto v2 = GetSplinePoint(x16c_p0[otherK], x17c_p1[otherK], x18c_p2[otherK], x19c_p3[otherK], t1);
const auto v3 = GetSplinePoint(x16c_p0[k], x17c_p1[k], x18c_p2[k], x19c_p3[k], t1);
2018-12-08 05:30:43 +00:00
if (x1bc_prim == GX::LINES) {
m_lineRenderer->AddVertex(v0, color, 1.f);
m_lineRenderer->AddVertex(v1, color, 1.f);
m_lineRenderer->AddVertex(v1, color, 1.f);
m_lineRenderer->AddVertex(v2, color, 1.f);
m_lineRenderer->AddVertex(v2, color, 1.f);
m_lineRenderer->AddVertex(v0, color, 1.f);
m_lineRenderer->AddVertex(v0, color, 1.f);
m_lineRenderer->AddVertex(v2, color, 1.f);
m_lineRenderer->AddVertex(v2, color, 1.f);
m_lineRenderer->AddVertex(v3, color, 1.f);
m_lineRenderer->AddVertex(v3, color, 1.f);
m_lineRenderer->AddVertex(v0, color, 1.f);
} else if (x1bc_prim == GX::QUADS) {
m_cachedVerts.push_back({v0, {x1d4_uvs.xMin, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {x1d4_uvs.xMin, x1d4_uvs.yMax}, color});
m_cachedVerts.push_back({v2, {x1d4_uvs.xMax, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v3, {x1d4_uvs.xMax, x1d4_uvs.yMax}, color});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
}
}
}
if (x1c_desc->x3c_TEXR && x1b0_SPLN > 0) {
2018-12-08 05:30:43 +00:00
x1d4_uvs.xMin += segUvSpan;
}
2018-12-08 05:30:43 +00:00
}
2018-12-08 05:30:43 +00:00
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 1;
}
2018-12-08 05:30:43 +00:00
}
if (x1bc_prim == GX::LINES) {
2019-03-03 06:19:42 +00:00
m_lineRenderer->Render(g_Renderer->IsThermalVisorHotPass());
}
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::RenderNSidedNoSpline() { RenderNSidedSpline(); }
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::Render3SidedSolidSpline() {
if (x15c_swooshes.size() < 2) {
2018-12-08 05:30:43 +00:00
return;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
int curIdx = x158_curParticle;
float curUvSpan = -x1e8_uvSpan;
zeus::CColor prevColor0 = zeus::skClear;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
const SSwooshData& swoosh = x15c_swooshes[curIdx];
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 1;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
float ang1 = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang1) > M_PIF) {
ang1 -= std::floor(ang1 / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang1 > M_PIF) {
2018-12-08 05:30:43 +00:00
ang1 -= 2.f * M_PIF;
} else if (ang1 < -M_PIF) {
2018-12-08 05:30:43 +00:00
ang1 += 2.f * M_PIF;
}
2018-12-08 05:30:43 +00:00
}
2017-06-05 02:40:29 +00:00
const zeus::CVector3f ang1Vec(std::sin(ang1) * swoosh.x4_leftRad, 0.f, std::cos(ang1) * swoosh.x4_leftRad);
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
float ang2 = ang1 + 2.0943952f; // +120 degrees
if (ang2 > M_PIF) {
2018-12-08 05:30:43 +00:00
ang2 -= 2.f * M_PIF;
}
2017-06-05 02:40:29 +00:00
const zeus::CVector3f ang2Vec(std::sin(ang2) * swoosh.x4_leftRad, 0.f, std::cos(ang2) * swoosh.x4_leftRad);
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
float ang3 = ang2 + 2.0943952f; // +120 degrees
if (ang3 > M_PIF) {
2018-12-08 05:30:43 +00:00
ang3 -= 2.f * M_PIF;
}
2017-06-05 02:40:29 +00:00
const zeus::CVector3f ang3Vec(std::sin(ang3) * swoosh.x4_leftRad, 0.f, std::cos(ang3) * swoosh.x4_leftRad);
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (i == 2) {
x19c_p3[0] = x17c_p1[0] * 2.f - x16c_p0[0];
x19c_p3[1] = x17c_p1[1] * 2.f - x16c_p0[1];
x19c_p3[2] = x17c_p1[2] * 2.f - x16c_p0[2];
} else {
x19c_p3[0] = x18c_p2[0];
x19c_p3[1] = x18c_p2[1];
x19c_p3[2] = x18c_p2[2];
}
2018-12-08 05:30:43 +00:00
x18c_p2[0] = x17c_p1[0];
x18c_p2[1] = x17c_p1[1];
x18c_p2[2] = x17c_p1[2];
x17c_p1[0] = x16c_p0[0];
x17c_p1[1] = x16c_p0[1];
x17c_p1[2] = x16c_p0[2];
const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
2018-12-08 05:30:43 +00:00
x16c_p0[0] = swoosh.x38_orientation * ang1Vec + useOffset;
x16c_p0[1] = swoosh.x38_orientation * ang2Vec + useOffset;
x16c_p0[2] = swoosh.x38_orientation * ang3Vec + useOffset;
const zeus::CColor useColor0 = prevColor0;
2018-12-08 05:30:43 +00:00
if (swoosh.x0_active) {
const zeus::CColor prevColor1 = prevColor0;
2018-12-08 05:30:43 +00:00
prevColor0 = swoosh.x6c_color * x20c_moduColor;
float prevUvSpan = curUvSpan;
curUvSpan += x1e8_uvSpan;
if (i > 1) {
// int vertCount = (x1b0_SPLN + 1) * 12;
float uv1 = 0.f;
zeus::CColor useColor1 = prevColor1;
zeus::CVector3f v01 = zeus::skZero3f;
zeus::CVector3f v11 = zeus::skZero3f;
zeus::CVector3f v21 = zeus::skZero3f;
zeus::CColor c1 = zeus::skClear;
2018-12-08 05:30:43 +00:00
float uvDelta = prevUvSpan - curUvSpan;
for (int j = 0; j < x1b0_SPLN + 1; ++j) {
float uv0 = uv1;
float t1 = (j + 1) / float(x1b0_SPLN + 1);
zeus::CVector3f v00 = v01;
zeus::CVector3f v10 = v11;
zeus::CVector3f v20 = v21;
zeus::CColor c0 = c1;
if (j == 0) {
float t0 = j / float(x1b0_SPLN + 1);
v00 = GetSplinePoint(x16c_p0[0], x17c_p1[0], x18c_p2[0], x19c_p3[0], t0);
v10 = GetSplinePoint(x16c_p0[1], x17c_p1[1], x18c_p2[1], x19c_p3[1], t0);
v20 = GetSplinePoint(x16c_p0[2], x17c_p1[2], x18c_p2[2], x19c_p3[2], t0);
c0 = zeus::CColor::lerp(useColor0, useColor1, t0);
uv0 = t0 * uvDelta + curUvSpan;
}
v01 = GetSplinePoint(x16c_p0[0], x17c_p1[0], x18c_p2[0], x19c_p3[0], t1);
v11 = GetSplinePoint(x16c_p0[1], x17c_p1[1], x18c_p2[1], x19c_p3[1], t1);
v21 = GetSplinePoint(x16c_p0[2], x17c_p1[2], x18c_p2[2], x19c_p3[2], t1);
c1 = zeus::CColor::lerp(useColor0, useColor1, t1);
uv1 = t1 * uvDelta + curUvSpan;
m_cachedVerts.push_back({v00, {uv0, x1d4_uvs.yMin}, c0});
m_cachedVerts.push_back({v10, {uv0, x1d4_uvs.yMax}, c0});
m_cachedVerts.push_back({v01, {uv1, x1d4_uvs.yMin}, c1});
m_cachedVerts.push_back({v11, {uv1, x1d4_uvs.yMax}, c1});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
m_cachedVerts.push_back({v10, {uv0, x1d4_uvs.yMin}, c0});
m_cachedVerts.push_back({v20, {uv0, x1d4_uvs.yMax}, c0});
m_cachedVerts.push_back({v11, {uv1, x1d4_uvs.yMin}, c1});
m_cachedVerts.push_back({v21, {uv1, x1d4_uvs.yMax}, c1});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
m_cachedVerts.push_back({v20, {uv0, x1d4_uvs.yMin}, c0});
m_cachedVerts.push_back({v00, {uv0, x1d4_uvs.yMax}, c0});
m_cachedVerts.push_back({v21, {uv1, x1d4_uvs.yMin}, c1});
m_cachedVerts.push_back({v01, {uv1, x1d4_uvs.yMax}, c1});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
}
}
}
}
}
void CParticleSwoosh::Render3SidedSolidNoSplineNoGaps() {
if (x15c_swooshes.size() < 2) {
2018-12-08 05:30:43 +00:00
return;
}
2018-12-08 05:30:43 +00:00
std::array<zeus::CVector3f, 2> p0;
std::array<zeus::CVector3f, 2> p1;
std::array<zeus::CVector3f, 2> p2;
2018-12-08 05:30:43 +00:00
int curIdx = x158_curParticle;
bool lastActive = false;
zeus::CColor c0 = zeus::skClear;
2018-12-08 05:30:43 +00:00
float uv0 = -x1e8_uvSpan;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
const SSwooshData& swoosh = x15c_swooshes[curIdx];
2018-12-08 05:30:43 +00:00
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 1;
}
2018-12-08 05:30:43 +00:00
float ang1 = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang1) > M_PIF) {
ang1 -= std::floor(ang1 / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang1 > M_PIF) {
2018-12-08 05:30:43 +00:00
ang1 -= 2.f * M_PIF;
} else if (ang1 < -M_PIF) {
2018-12-08 05:30:43 +00:00
ang1 += 2.f * M_PIF;
}
2017-06-05 02:40:29 +00:00
}
const zeus::CVector3f ang1Vec(std::sin(ang1) * swoosh.x4_leftRad, 0.f, std::cos(ang1) * swoosh.x4_leftRad);
2018-12-08 05:30:43 +00:00
float ang2 = ang1 + 2.0943952f; // +120 degrees
if (ang2 > M_PIF) {
2018-12-08 05:30:43 +00:00
ang2 -= 2.f * M_PIF;
}
const zeus::CVector3f ang2Vec(std::sin(ang2) * swoosh.x4_leftRad, 0.f, std::cos(ang2) * swoosh.x4_leftRad);
2018-12-08 05:30:43 +00:00
float ang3 = ang2 + 2.0943952f; // +120 degrees
if (ang3 > M_PIF) {
2018-12-08 05:30:43 +00:00
ang3 -= 2.f * M_PIF;
}
const zeus::CVector3f ang3Vec(std::sin(ang3) * swoosh.x4_leftRad, 0.f, std::cos(ang3) * swoosh.x4_leftRad);
const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
2018-12-08 05:30:43 +00:00
p0[i & 1] = swoosh.x38_orientation * ang1Vec + useOffset;
p1[i & 1] = swoosh.x38_orientation * ang2Vec + useOffset;
p2[i & 1] = swoosh.x38_orientation * ang3Vec + useOffset;
2018-12-08 05:30:43 +00:00
if (!swoosh.x0_active) {
lastActive = false;
continue;
}
2018-12-08 05:30:43 +00:00
if (!lastActive) {
lastActive = true;
continue;
}
2018-12-08 05:30:43 +00:00
lastActive = true;
const zeus::CColor c1 = c0;
2018-12-08 05:30:43 +00:00
c0 = swoosh.x6c_color * x20c_moduColor;
const float uv1 = uv0;
2018-12-08 05:30:43 +00:00
uv0 += x1e8_uvSpan;
m_cachedVerts.push_back({p0[i & 1], {uv0, x1d4_uvs.yMin}, c0});
m_cachedVerts.push_back({p1[i & 1], {uv0, x1d4_uvs.yMax}, c0});
m_cachedVerts.push_back({p0[!(i & 1)], {uv1, x1d4_uvs.yMin}, c1});
m_cachedVerts.push_back({p1[!(i & 1)], {uv1, x1d4_uvs.yMax}, c1});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
m_cachedVerts.push_back({p1[i & 1], {uv0, x1d4_uvs.yMin}, c0});
m_cachedVerts.push_back({p2[i & 1], {uv0, x1d4_uvs.yMax}, c0});
m_cachedVerts.push_back({p1[!(i & 1)], {uv1, x1d4_uvs.yMin}, c1});
m_cachedVerts.push_back({p2[!(i & 1)], {uv1, x1d4_uvs.yMax}, c1});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
m_cachedVerts.push_back({p2[i & 1], {uv0, x1d4_uvs.yMin}, c0});
m_cachedVerts.push_back({p0[i & 1], {uv0, x1d4_uvs.yMax}, c0});
m_cachedVerts.push_back({p2[!(i & 1)], {uv1, x1d4_uvs.yMin}, c1});
m_cachedVerts.push_back({p0[!(i & 1)], {uv1, x1d4_uvs.yMax}, c1});
CGraphics::DrawArray(m_cachedVerts.size() - 4, 4);
}
}
void CParticleSwoosh::Render2SidedSpline() { RenderNSidedSpline(); }
void CParticleSwoosh::Render2SidedNoSplineGaps() {
int drawStart = 0;
bool streaming = false;
int curIdx = x158_curParticle;
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
const SSwooshData& swoosh = x15c_swooshes[curIdx];
const bool otherActive = x15c_swooshes[WrapIndex(curIdx - 1)].x0_active;
2018-12-08 05:30:43 +00:00
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 2;
}
2018-12-08 05:30:43 +00:00
if (!swoosh.x0_active) {
if (streaming) {
streaming = false;
CGraphics::DrawArray(drawStart, m_cachedVerts.size() - drawStart);
}
continue;
}
2018-12-08 05:30:43 +00:00
if (!streaming) {
if (!otherActive) {
2018-12-08 05:30:43 +00:00
continue;
}
if (i >= x15c_swooshes.size() - 2) {
2018-12-08 05:30:43 +00:00
continue;
}
2018-12-08 05:30:43 +00:00
streaming = true;
drawStart = m_cachedVerts.size();
}
2018-12-08 05:30:43 +00:00
float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) {
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) {
2018-12-08 05:30:43 +00:00
ang -= 2.f * M_PIF;
} else if (ang < -M_PIF) {
2018-12-08 05:30:43 +00:00
ang += 2.f * M_PIF;
}
2018-12-08 05:30:43 +00:00
}
const float sinAng = std::sin(ang);
const float cosAng = std::cos(ang);
2018-12-08 05:30:43 +00:00
const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
const zeus::CVector3f v0 =
2018-12-08 05:30:43 +00:00
swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) +
useOffset;
const zeus::CVector3f v1 =
2018-12-08 05:30:43 +00:00
swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f, -sinAng * swoosh.x8_rightRad) +
useOffset;
const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
2018-12-08 05:30:43 +00:00
m_cachedVerts.push_back({v0, {1.f, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {1.f, x1d4_uvs.yMax}, color});
m_cachedVerts.push_back({v0, {0.f, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {0.f, x1d4_uvs.yMax}, color});
}
if (streaming)
CGraphics::DrawArray(drawStart, m_cachedVerts.size() - drawStart);
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::Render2SidedNoSplineNoGaps() {
int drawStart = 0;
int curIdx = x158_curParticle;
int particleCount = x1ac_particleCount;
float uvOffset = 0.f;
2018-12-08 05:30:43 +00:00
if (x1c_desc->x3c_TEXR) {
if (x1c_desc->x45_25_ORNT) {
const zeus::CVector3f camToParticle =
2018-12-08 05:30:43 +00:00
((zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation * xec_scaleXf).inverse() *
CGraphics::g_ViewMatrix)
.origin;
zeus::CVector3f dotVec = zeus::skZero3f;
2018-12-08 05:30:43 +00:00
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
const SSwooshData& swoosh = x15c_swooshes[curIdx];
2017-06-05 02:40:29 +00:00
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 1;
}
2018-12-08 05:30:43 +00:00
if (swoosh.x0_active) {
particleCount -= 1;
int otherIdx = curIdx - 1;
if (otherIdx < 0) {
2018-12-08 05:30:43 +00:00
otherIdx = x15c_swooshes.size() - 1;
}
2018-12-08 05:30:43 +00:00
const SSwooshData& otherSwoosh = x15c_swooshes[otherIdx];
2018-12-08 05:30:43 +00:00
zeus::CVector3f delta = otherSwoosh.xc_translation - swoosh.xc_translation;
if (otherIdx == x158_curParticle) {
2018-12-08 05:30:43 +00:00
delta = swoosh.xc_translation - x15c_swooshes[(curIdx + 1) % x15c_swooshes.size()].xc_translation;
}
2018-12-08 05:30:43 +00:00
if (delta.canBeNormalized()) {
zeus::CVector3f deltaCross = delta.cross(camToParticle - swoosh.xc_translation);
if (deltaCross.canBeNormalized()) {
deltaCross.normalize();
dotVec = (deltaCross.dot(dotVec) < 0.f ? -1.f : 1.f) * deltaCross;
const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
const zeus::CVector3f v0 = dotVec * swoosh.x4_leftRad + useOffset;
const zeus::CVector3f v1 = dotVec * -swoosh.x8_rightRad + useOffset;
2018-12-08 05:30:43 +00:00
const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
2018-12-08 05:30:43 +00:00
m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
if (uvOffset >= 1.f && particleCount) {
CGraphics::DrawArray(drawStart, m_cachedVerts.size() - drawStart);
2018-12-08 05:30:43 +00:00
drawStart = m_cachedVerts.size();
uvOffset -= 1.f;
m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
}
if (x1ec_TSPN > 0) {
2018-12-08 05:30:43 +00:00
uvOffset += x1e8_uvSpan;
} else {
uvOffset = float(i * x1e8_uvSpan);
}
2017-06-05 02:40:29 +00:00
}
2018-12-08 05:30:43 +00:00
}
2017-06-05 02:40:29 +00:00
}
2018-12-08 05:30:43 +00:00
}
} else {
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
const SSwooshData& swoosh = x15c_swooshes[curIdx];
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 1;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (swoosh.x0_active) {
particleCount -= 1;
float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) {
2017-06-05 02:40:29 +00:00
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) {
2018-12-08 05:30:43 +00:00
ang -= 2.f * M_PIF;
} else if (ang < -M_PIF) {
2018-12-08 05:30:43 +00:00
ang += 2.f * M_PIF;
}
2018-12-08 05:30:43 +00:00
}
float sinAng = std::sin(ang);
float cosAng = std::cos(ang);
const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
const zeus::CVector3f v0 =
2018-12-08 05:30:43 +00:00
swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) +
useOffset;
const zeus::CVector3f v1 = swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f,
-sinAng * swoosh.x8_rightRad) +
useOffset;
2018-12-08 05:30:43 +00:00
const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
2018-12-08 05:30:43 +00:00
m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
if (uvOffset >= 1.f && particleCount) {
CGraphics::DrawArray(drawStart, m_cachedVerts.size() - drawStart);
drawStart = m_cachedVerts.size();
uvOffset -= 1.f;
m_cachedVerts.push_back({v0, {uvOffset, x1d4_uvs.yMin}, color});
m_cachedVerts.push_back({v1, {uvOffset, x1d4_uvs.yMax}, color});
}
if (x1ec_TSPN > 0) {
2018-12-08 05:30:43 +00:00
uvOffset += x1e8_uvSpan;
} else {
uvOffset = float(i * x1e8_uvSpan);
}
2018-12-08 05:30:43 +00:00
}
}
}
} else {
for (size_t i = 0; i < x15c_swooshes.size(); ++i) {
const SSwooshData& swoosh = x15c_swooshes[curIdx];
2018-12-08 05:30:43 +00:00
curIdx -= 1;
if (curIdx < 0) {
2018-12-08 05:30:43 +00:00
curIdx = x15c_swooshes.size() - 1;
}
2018-12-08 05:30:43 +00:00
if (swoosh.x0_active) {
float ang = zeus::degToRad(swoosh.x30_irot + swoosh.x34_rotm);
if (std::fabs(ang) > M_PIF) {
ang -= std::floor(ang / (2.f * M_PIF)) * 2.f * M_PIF;
if (ang > M_PIF) {
2018-12-08 05:30:43 +00:00
ang -= 2.f * M_PIF;
} else if (ang < -M_PIF) {
2018-12-08 05:30:43 +00:00
ang += 2.f * M_PIF;
}
2017-06-05 02:40:29 +00:00
}
const float sinAng = std::sin(ang);
const float cosAng = std::cos(ang);
2017-06-05 02:40:29 +00:00
const zeus::CVector3f useOffset = swoosh.xc_translation + swoosh.x24_useOffset;
const zeus::CVector3f v0 =
2018-12-08 05:30:43 +00:00
swoosh.x38_orientation * zeus::CVector3f(cosAng * swoosh.x4_leftRad, 0.f, sinAng * swoosh.x4_leftRad) +
useOffset;
const zeus::CVector3f v1 =
2018-12-08 05:30:43 +00:00
swoosh.x38_orientation * zeus::CVector3f(-cosAng * swoosh.x8_rightRad, 0.f, -sinAng * swoosh.x8_rightRad) +
useOffset;
2017-06-05 02:40:29 +00:00
const zeus::CColor color = swoosh.x6c_color * x20c_moduColor;
2018-12-08 05:30:43 +00:00
m_cachedVerts.push_back({v0, {}, color});
m_cachedVerts.push_back({v1, {}, color});
}
2017-06-05 02:40:29 +00:00
}
2018-12-08 05:30:43 +00:00
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
CGraphics::DrawArray(drawStart, m_cachedVerts.size() - drawStart);
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::Render(const CActorLights*) {
if (x1b4_LENG < 2 || x1ac_particleCount <= 1) {
2018-12-08 05:30:43 +00:00
return;
}
2020-04-11 22:51:39 +00:00
SCOPED_GRAPHICS_DEBUG_GROUP(fmt::format(FMT_STRING("CParticleSwoosh::Render {}"),
2019-07-21 08:42:52 +00:00
*x1c_desc.GetObjectTag()).c_str(), zeus::skYellow);
2018-12-08 05:30:43 +00:00
m_cachedVerts.clear();
if (m_dataBind[0]) {
2019-03-03 06:19:42 +00:00
CGraphics::SetShaderDataBinding(m_dataBind[g_Renderer->IsThermalVisorHotPass()]);
}
2016-02-13 05:49:59 +00:00
CParticleGlobals::instance()->SetParticleLifetime(x1b4_LENG);
2018-12-08 05:30:43 +00:00
CGlobalRandom gr(x1c0_rand);
CGraphics::DisableAllLights();
// Z-test, Z-update if x45_24_ZBUF
// Additive if x1d0_25_AALP, otherwise alpha blend
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
CGraphics::SetModelMatrix(zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation * xec_scaleXf *
zeus::CTransform::Scale(x14c_localScale));
2018-12-08 05:30:43 +00:00
// Disable face culling
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (CUVElement* texr = x1c_desc->x3c_TEXR.get()) {
TLockedToken<CTexture> tex = texr->GetValueTexture(x28_curFrame);
// Load tex
x1e4_tex = tex.GetObj();
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
texr->GetValueUV(x28_curFrame, x1d4_uvs);
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
x1d0_31_constantTex = texr->HasConstantTexture();
x1d1_24_constantUv = texr->HasConstantUV();
2017-06-05 02:40:29 +00:00
if (CIntElement* tspn = x1c_desc->x40_TSPN.get()) {
2018-12-08 05:30:43 +00:00
tspn->GetValue(x28_curFrame, x1ec_TSPN);
}
2017-06-05 02:40:29 +00:00
if (x1ec_TSPN <= 0) {
2018-12-08 05:30:43 +00:00
x1ec_TSPN = x15c_swooshes.size() - 1;
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
x1e8_uvSpan = 1.f;
if (x1ec_TSPN > 0) {
2018-12-08 05:30:43 +00:00
x1e8_uvSpan = 1.f / float(x1ec_TSPN);
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
// TEV0 modulate
} else {
// TEV0 passthru
}
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
// TEV1 passthru
2017-06-05 02:40:29 +00:00
2018-12-08 05:30:43 +00:00
if (x1b8_SIDE == 2) {
if (x1b0_SPLN <= 0) {
if (x1d0_27_renderGaps) {
2018-12-08 05:30:43 +00:00
Render2SidedNoSplineGaps();
} else {
2018-12-08 05:30:43 +00:00
Render2SidedNoSplineNoGaps();
}
2018-12-08 05:30:43 +00:00
} else {
Render2SidedSpline();
2017-06-05 02:40:29 +00:00
}
2018-12-08 05:30:43 +00:00
} else if (x1b8_SIDE == 3) {
if (x1b0_SPLN > 0) {
2018-12-08 05:30:43 +00:00
Render3SidedSolidSpline();
} else {
2018-12-08 05:30:43 +00:00
Render3SidedSolidNoSplineNoGaps();
}
2018-12-08 05:30:43 +00:00
} else {
if (x1b0_SPLN > 0) {
2018-12-08 05:30:43 +00:00
RenderNSidedSpline();
} else {
2018-12-08 05:30:43 +00:00
RenderNSidedNoSpline();
}
2018-12-08 05:30:43 +00:00
}
2018-12-08 05:30:43 +00:00
zeus::CMatrix4f mvp = CGraphics::GetPerspectiveProjectionMatrix(true) * CGraphics::g_GXModelView.toMatrix4f();
m_uniformBuf->load(&mvp, sizeof(zeus::CMatrix4f));
if (m_cachedVerts.size()) {
2018-12-08 05:30:43 +00:00
m_vertBuf->load(m_cachedVerts.data(), m_cachedVerts.size() * sizeof(CParticleSwooshShaders::Vert));
}
2016-02-13 05:49:59 +00:00
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetOrientation(const zeus::CTransform& xf) {
x44_orientation = xf;
x74_invOrientation = xf.inverse();
x15c_swooshes[x158_curParticle].x38_orientation = xf;
2016-02-13 05:49:59 +00:00
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetTranslation(const zeus::CVector3f& translation) {
x38_translation = translation;
UpdateSwooshTranslation(x38_translation);
2016-02-13 05:49:59 +00:00
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetGlobalOrientation(const zeus::CTransform& xf) { xb0_globalOrientation = xf.getRotation(); }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetGlobalTranslation(const zeus::CVector3f& translation) { xa4_globalTranslation = translation; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetGlobalScale(const zeus::CVector3f& scale) {
xe0_globalScale = scale;
xec_scaleXf = zeus::CTransform::Scale(scale);
x11c_invScaleXf = zeus::CTransform::Scale(1.f / scale);
2016-02-13 05:49:59 +00:00
}
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetLocalScale(const zeus::CVector3f& scale) { x14c_localScale = scale; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetParticleEmission(bool e) { x1d0_24_emitting = e; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::SetModulationColor(const zeus::CColor& color) { x20c_moduColor = color; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
const zeus::CTransform& CParticleSwoosh::GetOrientation() const { return x44_orientation; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
const zeus::CVector3f& CParticleSwoosh::GetTranslation() const { return x38_translation; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
const zeus::CTransform& CParticleSwoosh::GetGlobalOrientation() const { return xb0_globalOrientation; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
const zeus::CVector3f& CParticleSwoosh::GetGlobalTranslation() const { return xa4_globalTranslation; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
const zeus::CVector3f& CParticleSwoosh::GetGlobalScale() const { return xe0_globalScale; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
const zeus::CColor& CParticleSwoosh::GetModulationColor() const { return x20c_moduColor; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
bool CParticleSwoosh::IsSystemDeletable() const {
if (x1d0_24_emitting && x28_curFrame < x2c_PSLT) {
2018-12-08 05:30:43 +00:00
return false;
}
return GetParticleCount() < 2;
2016-02-13 05:49:59 +00:00
}
std::optional<zeus::CAABox> CParticleSwoosh::GetBounds() const {
2018-12-08 05:30:43 +00:00
if (GetParticleCount() <= 1) {
const zeus::CVector3f trans = x38_translation + xa4_globalTranslation;
2018-12-08 05:30:43 +00:00
return zeus::CAABox(trans, trans);
} else {
const zeus::CTransform xf = zeus::CTransform::Translate(xa4_globalTranslation) * xb0_globalOrientation * xec_scaleXf;
2018-12-08 05:30:43 +00:00
return zeus::CAABox(x1f0_aabbMin - x208_maxRadius, x1fc_aabbMax + x208_maxRadius).getTransformedAABox(xf);
}
2016-02-13 05:49:59 +00:00
}
2018-12-08 05:30:43 +00:00
u32 CParticleSwoosh::GetParticleCount() const { return x1ac_particleCount; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
bool CParticleSwoosh::SystemHasLight() const { return false; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
CLight CParticleSwoosh::GetLight() const {
return CLight::BuildLocalAmbient(zeus::skZero3f, zeus::skWhite);
2016-02-13 05:49:59 +00:00
}
2018-12-08 05:30:43 +00:00
bool CParticleSwoosh::GetParticleEmission() const { return x1d0_24_emitting; }
2016-02-13 05:49:59 +00:00
2018-12-08 05:30:43 +00:00
void CParticleSwoosh::DestroyParticles() {
// Empty
}
2018-12-08 05:30:43 +00:00
} // namespace urde