Files
DoomRTX/neo/quake4/bse/BSE_ParseParticle2.cpp
2026-05-09 22:10:40 -07:00

2303 lines
64 KiB
C++

// BSE_ParseParticle2.cpp
//
#include "precompiled.h"
#include "BSE_Envelope.h"
#include "BSE_Particle.h"
#include "BSE.h"
#include "BSE_SpawnDomains.h"
rvTrailInfo rvParticleTemplate::sTrailInfo;
rvElectricityInfo rvParticleTemplate::sElectricityInfo;
rvEnvParms rvParticleTemplate::sDefaultEnvelope;
rvEnvParms rvParticleTemplate::sEmptyEnvelope;
rvParticleParms rvParticleTemplate::sSPF_ONE_1;
rvParticleParms rvParticleTemplate::sSPF_ONE_2;
rvParticleParms rvParticleTemplate::sSPF_ONE_3;
rvParticleParms rvParticleTemplate::sSPF_NONE_0;
rvParticleParms rvParticleTemplate::sSPF_NONE_1;
rvParticleParms rvParticleTemplate::sSPF_NONE_3;
bool rvParticleTemplate::sInited = false;
float rvSegmentTemplate::mSegmentBaseCosts[SEG_COUNT];
namespace {
static rvParticleParms* BSE_DuplicateParm(rvParticleParms* source) {
if (source == NULL || source->mStatic) {
return source;
}
rvParticleParms* copy = new rvParticleParms();
*copy = *source;
copy->mStatic = 0;
return copy;
}
static rvEnvParms* BSE_DuplicateEnv(rvEnvParms* source) {
if (source == NULL || source->mStatic) {
return source;
}
rvEnvParms* copy = new rvEnvParms();
*copy = *source;
copy->mStatic = 0;
return copy;
}
static void BSE_AssignParmPtr(rvParticleParms*& dest, rvParticleParms* source) {
if (dest != source && dest != NULL && !dest->mStatic) {
delete dest;
}
dest = source;
}
static void BSE_AssignEnvPtr(rvEnvParms*& dest, rvEnvParms* source) {
if (dest != source && dest != NULL && !dest->mStatic) {
delete dest;
}
dest = source;
}
static void BSE_DeleteOwnedParm(rvParticleParms*& value, rvParticleParms** seen, int& seenCount) {
if (value == NULL || value->mStatic) {
value = NULL;
return;
}
for (int i = 0; i < seenCount; ++i) {
if (seen[i] == value) {
value = NULL;
return;
}
}
seen[seenCount++] = value;
delete value;
value = NULL;
}
static void BSE_DeleteOwnedEnv(rvEnvParms*& value, rvEnvParms** seen, int& seenCount) {
if (value == NULL || value->mStatic) {
value = NULL;
return;
}
for (int i = 0; i < seenCount; ++i) {
if (seen[i] == value) {
value = NULL;
return;
}
}
seen[seenCount++] = value;
delete value;
value = NULL;
}
}
namespace {
ID_INLINE const char* BSE_ResolveEffectCompatAlias(const char* effectName) {
// Stock splash FX reference "effects/ambient/drip_ring", but the shipped
// data only provides "effects/ambient/drip_splash". Remap at parse-time to
// preserve vanilla secondary splash behavior without shipping replacement data.
if (!idStr::Icmp(effectName, "effects/ambient/drip_ring")) {
return "effects/ambient/drip_splash";
}
return effectName;
}
ID_INLINE void BSE_UpdateExtents(const idVec3& sample, idVec3& mins, idVec3& maxs) {
mins.x = Min(mins.x, sample.x);
mins.y = Min(mins.y, sample.y);
mins.z = Min(mins.z, sample.z);
maxs.x = Max(maxs.x, sample.x);
maxs.y = Max(maxs.y, sample.y);
maxs.z = Max(maxs.z, sample.z);
}
}
float rvParticleTemplate::GetSpawnVolume(rvBSE* effect) {
if (!mpSpawnPosition) {
return 1.0f;
}
float xExtent = 0.0f;
if ((mpSpawnPosition->mFlags & PPFLAG_USEENDORIGIN) && effect) {
const idVec3 delta = effect->GetOriginalEndOrigin() - effect->GetOriginalOrigin();
xExtent = delta.Length() - mpSpawnPosition->mMins.x;
}
else {
xExtent = mpSpawnPosition->mMaxs.x - mpSpawnPosition->mMins.x;
}
const float yExtent = mpSpawnPosition->mMaxs.y - mpSpawnPosition->mMins.y;
const float zExtent = mpSpawnPosition->mMaxs.z - mpSpawnPosition->mMins.z;
const float volume = (idMath::Fabs(xExtent) + idMath::Fabs(yExtent) + idMath::Fabs(zExtent)) * 0.01f;
return Max(0.0f, volume);
}
float rvParticleTemplate::GetMaxParmValue(rvParticleParms& spawn, rvParticleParms& death, rvEnvParms& envelope) {
idVec3 spawnMins;
idVec3 spawnMaxs;
idVec3 deathMins;
idVec3 deathMaxs;
spawn.GetMinsMaxs(spawnMins, spawnMaxs);
death.GetMinsMaxs(deathMins, deathMaxs);
idBounds bounds;
bounds.Clear();
float envMin = 0.0f;
float envMax = 0.0f;
if (envelope.GetMinMax(envMin, envMax)) {
const idVec3 samples[] = {
spawnMins * envMin, spawnMaxs * envMin, spawnMins * envMax, spawnMaxs * envMax,
deathMins * envMin, deathMaxs * envMin, deathMins * envMax, deathMaxs * envMax
};
for (int i = 0; i < 8; ++i) {
bounds.AddPoint(samples[i]);
}
}
else {
bounds.AddPoint(spawnMins);
bounds.AddPoint(spawnMaxs);
bounds.AddPoint(deathMins);
bounds.AddPoint(deathMaxs);
}
return Max(bounds[0].Length(), bounds[1].Length());
}
float rvParticleTemplate::GetMaxSize(void) {
if (!mpSpawnSize || !mpDeathSize || !mpSizeEnvelope) {
return 0.0f;
}
return GetMaxParmValue(*mpSpawnSize, *mpDeathSize, *mpSizeEnvelope);
}
float rvParticleTemplate::GetMaxOffset(void) {
if (!mpSpawnOffset || !mpDeathOffset || !mpOffsetEnvelope) {
return 0.0f;
}
return GetMaxParmValue(*mpSpawnOffset, *mpDeathOffset, *mpOffsetEnvelope);
}
float rvParticleTemplate::GetMaxLength(void) {
if (!mpSpawnLength || !mpDeathLength || !mpLengthEnvelope) {
return 0.0f;
}
return GetMaxParmValue(*mpSpawnLength, *mpDeathLength, *mpLengthEnvelope);
}
void rvParticleTemplate::EvaluateSimplePosition(
idVec3& pos,
float time,
float lifeTime,
idVec3& initPos,
idVec3& velocity,
idVec3& acceleration,
idVec3& friction) {
const float t = time;
const float halfT2 = 0.5f * t * t;
pos.x = initPos.x + velocity.x * t + acceleration.x * halfT2;
pos.y = initPos.y + velocity.y * t + acceleration.y * halfT2;
pos.z = initPos.z + velocity.z * t + acceleration.z * halfT2;
const float safeLifetime = Max(BSE_TIME_EPSILON, lifeTime);
const float expFactor = idMath::Exp((safeLifetime - halfT2) / safeLifetime) - 1.0f;
const float frictionScale = (halfT2 * halfT2 * expFactor) / 3.0f;
pos += friction * frictionScale;
}
float rvParticleTemplate::GetFurthestDistance(void) {
if (!mpSpawnPosition || !mpSpawnVelocity || !mpSpawnAcceleration || !mpSpawnFriction) {
return 0.0f;
}
idVec3 minPos;
idVec3 maxPos;
idVec3 minVel;
idVec3 maxVel;
idVec3 minAccel;
idVec3 maxAccel;
idVec3 minFriction;
idVec3 maxFriction;
mpSpawnPosition->GetMinsMaxs(minPos, maxPos);
mpSpawnVelocity->GetMinsMaxs(minVel, maxVel);
mpSpawnAcceleration->GetMinsMaxs(minAccel, maxAccel);
mpSpawnFriction->GetMinsMaxs(minFriction, maxFriction);
const bool multiplayer = (game != NULL) ? game->IsMultiplayer() : false;
const float gravityMagnitude = cvarSystem->GetCVarFloat(multiplayer ? "g_mp_gravity" : "g_gravity");
const float gravityScale = Max(idMath::Fabs(mGravity.x), idMath::Fabs(mGravity.y));
const idVec3 gravityVec(0.0f, 0.0f, -gravityMagnitude * gravityScale);
minAccel -= gravityVec;
maxAccel -= gravityVec;
const float duration = Max(BSE_TIME_EPSILON, mDuration.y);
const float step = duration * 0.125f;
idVec3 overallMins(1.0e30f, 1.0e30f, 1.0e30f);
idVec3 overallMaxs(-1.0e30f, -1.0e30f, -1.0e30f);
idVec3 pos;
for (int i = 0; i < 8; ++i) {
const float sampleTime = i * step;
for (int p = 0; p < 2; ++p) {
idVec3 initPos = p ? maxPos : minPos;
for (int v = 0; v < 2; ++v) {
idVec3 velocity = v ? maxVel : minVel;
for (int a = 0; a < 2; ++a) {
idVec3 accel = a ? maxAccel : minAccel;
for (int f = 0; f < 2; ++f) {
idVec3 friction = f ? maxFriction : minFriction;
EvaluateSimplePosition(pos, sampleTime, duration, initPos, velocity, accel, friction);
BSE_UpdateExtents(pos, overallMins, overallMaxs);
}
}
}
}
}
return Max(overallMins.Length() * 0.5f, overallMaxs.Length() * 0.5f);
}
void rvParticleTemplate::AllocTrail()
{
if (mTrailInfo != NULL && !mTrailInfo->mStatic) {
return;
}
rvTrailInfo* info = new rvTrailInfo();
*info = sTrailInfo;
info->mStatic = 0;
mTrailInfo = info;
}
void rvParticleTemplate::AllocElectricityInfo() {
if (mElecInfo != NULL && !mElecInfo->mStatic) {
return;
}
rvElectricityInfo* info = new rvElectricityInfo();
*info = sElectricityInfo;
info->mStatic = 0;
mElecInfo = info;
}
bool rvParticleTemplate::ParseBlendParms(rvDeclEffect* effect, idParser* src)
{
rvParticleTemplate* v3; // edi
char result; // al
idLexer* v5; // eax
int v6; // edi
idBitMsg** v7; // esi
int v8; // eax
idToken token; // [esp+0h] [ebp-60h]
short v10; // [esp+50h] [ebp-10h]
int v11; // [esp+5Ch] [ebp-4h]
v3 = this;
v10 = 0;
v11 = 0;
if (src->ReadToken(&token))
{
if (idStr::Icmp(token, "add"))
{
src->Error("Invalid blend type");
return false;
}
else
{
v3->mFlags |= 0x8000u;
}
v11 = -1;
//idStr::FreeData((idStr*)&token.data);
result = 1;
}
else
{
v11 = -1;
// idStr::FreeData((idStr*)&token.data);
result = 0;
}
return result;
}
bool rvParticleTemplate::ParseImpact(rvDeclEffect* effect, idParser* src)
{
int v3; // ebp
rvParticleTemplate* v4; // esi
int v6; // edi
//sdDeclTypeHolder* v7; // eax
idLexer* v8; // eax
idBitMsg** v9; // edi
int v10; // ST0C_4
idLexer* v11; // eax
idBitMsg** v12; // edi
int v13; // ST0C_4
idToken token; // [esp+4h] [ebp-60h]
short v15; // [esp+54h] [ebp-10h]
int v16; // [esp+60h] [ebp-4h]
v3 = 0;
v4 = this;
v15 = 0;
v16 = 0;
if (!src->ExpectTokenString("{"))
{
v16 = -1;
return false;
}
v4->mFlags |= 0x200u;
if (!src->ReadToken(&token))
{
LABEL_30:
v16 = -1;
return 0;
}
while (idStr::Cmp(token, "}"))
{
if (idStr::Icmp(token, "effect"))
{
if (!idStr::Icmp(token, "remove"))
{
if (src->ParseInt() != 0)
v4->mFlags |= 0x400u;
else
v4->mFlags &= 0xFFFFFBFF;
goto LABEL_29;
}
if (idStr::Icmp(token, "bounce"))
{
if (idStr::Icmp(token, "physicsDistance"))
{
//v11 = src->scriptstack;
//if (v11)
// v3 = v11->line;
//if (v11)
// v12 = (idBitMsg**)v11->filename.data;
//else
// v12 = &s2;
//v13 = (*(int (**)(void))effect->base->vfptr->gap4)();
//(*(void(__cdecl**)(netadrtype_t, const char*, int, int, idBitMsg**, int))(*(_DWORD*)common.type + 68))(
// common.type,
// "^4BSE:^1 Invalid impact parameter '%s' in '%s' (file: %s, line: %d)",
// token.alloced,
// v13,
// v12,
// v3);
src->Error("Invalid impact parameter");
return false;
}
v4->mPhysicsDistance = src->ParseFloat();
}
else
{
v4->mBounce = src->ParseFloat();
}
}
else
{
//idParser::ReadToken(src, (idToken*)((char*)&token + 4));
if (!src->ReadToken(&token)) {
return false;
}
if (v4->mNumImpactEffects >= 4)
{
src->Error("too many impact effects");
goto LABEL_29;
}
//v7 = sdSingleton<sdDeclTypeHolder>::GetInstance();
//v4->mImpactEffects[v4->mNumImpactEffects++] = (rvDeclEffect*)((int(__stdcall*)(int, int, signed int))declManager->vfptr->FindType)(
// v7->declEffectsType.declTypeHandle,
// v6,
// 1);
v4->mImpactEffects[v4->mNumImpactEffects++] = declManager->FindEffect(BSE_ResolveEffectCompatAlias(token));
}
LABEL_29:
if (!src->ReadToken(&token))
goto LABEL_30;
}
v16 = -1;
return true;
}
bool rvParticleTemplate::ParseTimeout(rvDeclEffect* effect, idParser* src)
{
rvParticleTemplate* v3; // edi
idParser* v4; // ebp
char result; // al
int v6; // esi
//sdDeclTypeHolder* v7; // eax
idLexer* v8; // eax
int v9; // ebp
idBitMsg** v10; // esi
int v11; // ST0C_4
idLexer* v12; // eax
int v13; // ebp
idBitMsg** v14; // esi
int v15; // ST0C_4
idToken token; // [esp+4h] [ebp-60h]
short v17; // [esp+54h] [ebp-10h]
int v18; // [esp+60h] [ebp-4h]
v3 = this;
v17 = 0;
v4 = src;
v18 = 0;
if (src->ExpectTokenString("{"))
{
if (src->ReadToken(&token))
{
while (idStr::Cmp(token, "}"))
{
if (idStr::Icmp(token, "effect"))
{
//v12 = v4->scriptstack;
//if (v12)
// v13 = v12->line;
//else
// v13 = 0;
//if (v12)
// v14 = (idBitMsg**)v12->filename.data;
//else
// v14 = &s2;
//v15 = (*(int (**)(void))effect->base->vfptr->gap4)();
//(*(void(__cdecl**)(netadrtype_t, const char*, int, int, idBitMsg**, int))(*(_DWORD*)common.type + 68))(
// common.type,
// "^4BSE:^1 Invalid timeout parameter '%s' in '%s' (file: %s, line: %d)",
// token.alloced,
// v15,
// v14,
// v13);
src->Error("Invalid timeout parameter");
}
else
{
if (!src->ReadToken(&token)) {
return false;
}
if (v3->mNumTimeoutEffects >= 4)
{
//v8 = v4->scriptstack;
//if (v8)
// v9 = v8->line;
//else
// v9 = 0;
//if (v8)
// v10 = (idBitMsg**)v8->filename.data;
//else
// v10 = &s2;
//v11 = (*(int (**)(void))effect->base->vfptr->gap4)();
//(*(void(__cdecl**)(netadrtype_t, const char*, int, int, idBitMsg**, int))(*(_DWORD*)common.type + 68))(
// common.type,
// "^4BSE:^1 Too many timeout effects '%s' in '%s' (file: %s, line: %d)",
// token.alloced,
// v11,
// v10,
// v9);
src->Error("Too many timeout effects");
}
else
{
//v6 = token.alloced;
//v7 = sdSingleton<sdDeclTypeHolder>::GetInstance();
//v3->mTimeoutEffects[v3->mNumTimeoutEffects++] = (rvDeclEffect*)((int(__stdcall*)(int, int, signed int))declManager->vfptr->FindType)(
// v7->declEffectsType.declTypeHandle,
// v6,
// 1);
v3->mTimeoutEffects[v3->mNumTimeoutEffects++] = declManager->FindEffect(token);
}
}
if (!src->ReadToken(&token))
goto LABEL_25;
v4 = src;
}
v18 = -1;
//idStr::FreeData((idStr*)&token.data);
result = 1;
}
else
{
LABEL_25:
v18 = -1;
//idStr::FreeData((idStr*)&token.data);
result = 0;
}
}
else
{
v18 = -1;
// idStr::FreeData((idStr*)&token.data);
result = 0;
}
return result;
}
rvEnvParms* rvParticleTemplate::ParseMotionParms(idParser* src, int count, rvEnvParms* def)
{
rvEnvParms* result; // eax
//sdDetails::sdPoolAlloc<rvEnvParms, 128>* v4; // ecx
//rvEnvParms* v5; // eax
rvEnvParms* v6; // esi
int v7; // ebp
//sdDeclTypeHolder* v8; // eax
idLexer* v9; // eax
int v10; // edx
idBitMsg** v11; // ecx
//sdDetails::sdPoolAlloc<rvEnvParms, 128>* v12; // eax
//sdDetails::sdPoolAlloc<rvEnvParms, 128>* v13; // eax
idToken token; // [esp+4h] [ebp-60h]
short v15; // [esp+54h] [ebp-10h]
int v16; // [esp+60h] [ebp-4h]
v15 = 0;
v16 = 0;
if (src->ExpectTokenString("{"))
{
//v4 = sdPoolAllocator<rvEnvParms, &char const* const sdPoolAllocator_rvEnvParms, 128, sdLockingPolicy_None>::GetMemoryManager()->allocator;
//if (v4 && (v5 = sdDetails::sdPoolAlloc<rvEnvParms, 128>::Alloc(v4)) != 0)
//{
// v5->mStatic = 0;
// v5->mFastLookUp = 0;
// v6 = v5;
//}
//else
//{
// v6 = 0;
//}
v6 = new rvEnvParms(); // jmarshall: mem leak
v6->Init();
if (src->ReadToken(&token))
{
while (idStr::Cmp(token, "}"))
{
if (idStr::Icmp(token, "envelope"))
{
if (idStr::Icmp(token, "rate"))
{
if (idStr::Icmp(token, "count"))
{
if (idStr::Icmp(token, "offset"))
{
//v9 = src->scriptstack;
//if (v9)
// v10 = v9->line;
//else
// v10 = 0;
//if (v9)
// v11 = (idBitMsg**)v9->filename.data;
//else
// v11 = &s2;
//(*(void (**)(netadrtype_t, const char*, ...))(*(_DWORD*)common.type + 68))(
// common.type,
// "^4BSE:^1 Invalid motion parameter '%s' (file: %s, line: %d)",
// token.alloced,
// v11,
// v10);
src->Error("Invalid motion parameter");
src->SkipBracedSection(1);
}
else
{
// rvParticleTemplate::GetVector(src, count, v6->mEnvOffset);
src->Parse1DMatrix(count, v6->mEnvOffset.ToFloatPtr(), true);
}
}
else
{
//rvParticleTemplate::GetVector(src, count, v6->mRate);
src->Parse1DMatrix(count, v6->mRate.ToFloatPtr(), true);
v6->mIsCount = 1;
}
}
else
{
//rvParticleTemplate::GetVector(src, count, v6->mRate);
src->Parse1DMatrix(count, v6->mRate.ToFloatPtr(), true);
v6->mIsCount = 0;
}
}
else
{
//idParser::ReadToken(src, (idToken*)((char*)&token + 4));
//v7 = token.alloced;
//v8 = sdSingleton<sdDeclTypeHolder>::GetInstance();
//v6->mTable = (idDeclTable*)((int(__stdcall*)(int, int, signed int))declManager->vfptr->FindType)(
// v8->declTableType.declTypeHandle,
// v7,
// 1);
if (!src->ReadToken(&token)) {
goto LABEL_25;
}
v6->mTable = declManager->FindTable(token);
}
if (!src->ReadToken(&token))
goto LABEL_25;
}
v6->Finalize();
if (v6->Compare(*def))
{
delete v6;
v16 = -1;
//idStr::FreeData((idStr*)&token.data);
result = def;
}
else
{
v16 = -1;
//idStr::FreeData((idStr*)&token.data);
result = v6;
}
}
else
{
LABEL_25:
if (v6)
{
delete v6;
}
v16 = -1;
// idStr::FreeData((idStr*)&token.data);
result = def;
}
}
else
{
v16 = -1;
//idStr::FreeData((idStr*)&token.data);
result = def;
}
return result;
}
bool rvParticleTemplate::ParseMotionDomains(rvDeclEffect* effect, idParser* src)
{
rvParticleTemplate* v3; // esi
idParser* v4; // edi
char result; // al
idLexer* v6; // eax
idBitMsg** v7; // ebp
int v8; // eax
idToken token; // [esp+0h] [ebp-60h]
short v10; // [esp+50h] [ebp-10h]
int v11; // [esp+5Ch] [ebp-4h]
idParser* srca; // [esp+68h] [ebp+8h]
v3 = this;
v10 = 0;
v4 = src;
v11 = 0;
if (src->ExpectTokenString("{"))
{
if (src->ReadToken(&token))
{
while (token.Cmp("}"))
{
if (token.Icmp("tint"))
{
if (token.Icmp("fade"))
{
if (token.Icmp("size"))
{
if (token.Icmp("rotate"))
{
if (token.Icmp("angle"))
{
if (token.Icmp("offset"))
{
if (token.Icmp("length"))
{
//v6 = v4->scriptstack;
//if (v6)
// srca = (idParser*)v6->line;
//else
// srca = 0;
//if (v6)
// v7 = (idBitMsg**)v6->filename.data;
//else
// v7 = &s2;
//v8 = (*(int (**)(void))effect->base->vfptr->gap4)();
//(*(void (**)(netadrtype_t, const char*, ...))(*(_DWORD*)common.type + 68))(
// common.type,
// "^4BSE:^1 Invalid motion domain '%s' in %s (file: %s, line: %d)",
// token.alloced,
// v8,
// v7,
// srca);
src->Error("Invalid motion domain");
src->SkipBracedSection(1);
}
else
{
BSE_AssignEnvPtr(v3->mpLengthEnvelope, rvParticleTemplate::ParseMotionParms(
v4,
3,
&rvParticleTemplate::sDefaultEnvelope));
}
}
else
{
BSE_AssignEnvPtr(v3->mpOffsetEnvelope, rvParticleTemplate::ParseMotionParms(
v4,
3,
&rvParticleTemplate::sDefaultEnvelope));
}
}
else
{
BSE_AssignEnvPtr(v3->mpAngleEnvelope, rvParticleTemplate::ParseMotionParms(
v4,
3,
&rvParticleTemplate::sDefaultEnvelope));
}
}
else
{
BSE_AssignEnvPtr(v3->mpRotateEnvelope, rvParticleTemplate::ParseMotionParms(
v4,
(unsigned char)v3->mNumRotateParms,
&rvParticleTemplate::sDefaultEnvelope));
}
}
else
{
BSE_AssignEnvPtr(v3->mpSizeEnvelope, rvParticleTemplate::ParseMotionParms(
v4,
(unsigned char)v3->mNumSizeParms,
&rvParticleTemplate::sDefaultEnvelope));
}
}
else
{
BSE_AssignEnvPtr(v3->mpFadeEnvelope, rvParticleTemplate::ParseMotionParms(v4, 1, &rvParticleTemplate::sDefaultEnvelope));
}
}
else
{
BSE_AssignEnvPtr(v3->mpTintEnvelope, rvParticleTemplate::ParseMotionParms(v4, 3, &rvParticleTemplate::sDefaultEnvelope));
}
if (!src->ReadToken(&token))
goto LABEL_27;
}
v11 = -1;
//idStr::FreeData((idStr*)&token.data);
result = 1;
}
else
{
LABEL_27:
v11 = -1;
//idStr::FreeData((idStr*)&token.data);
result = 0;
}
}
else
{
v11 = -1;
//idStr::FreeData((idStr*)&token.data);
result = 0;
}
return result;
}
void rvParticleTemplate::FixupParms(rvParticleParms* parms)
{
if (!parms) {
return;
}
const int axisBits = parms->mSpawnType & 3;
const int shapeBits = parms->mSpawnType & ~3;
// Preserve explicit point/unit and tapered legacy variants.
if (shapeBits == 0 || shapeBits == 4 || parms->mSpawnType == 43 || parms->mSpawnType == 47) {
return;
}
const idVec3& mins = parms->mMins;
const idVec3& maxs = parms->mMaxs;
const bool minsEqualY = (axisBits < 2) || (mins.y == mins.x);
const bool minsEqualZ = (axisBits < 3) || (mins.z == mins.x);
const bool maxsEqualX = (maxs.x == mins.x);
const bool maxsEqualY = (axisBits < 2) || (maxs.y == mins.x);
const bool maxsEqualZ = (axisBits < 3) || (maxs.z == mins.x);
if (shapeBits == 8 && minsEqualY && minsEqualZ && maxsEqualX && maxsEqualY && maxsEqualZ) {
if (mins.x == 0.0f) {
parms->mSpawnType = axisBits;
}
else if (idMath::Fabs(mins.x - 1.0f) < idMath::FLOAT_EPSILON) {
parms->mSpawnType = axisBits + 4;
}
else {
parms->mSpawnType = axisBits + 8;
}
}
else if (shapeBits == 8) {
parms->mSpawnType = axisBits + 8;
}
if (parms->mSpawnType >= 8) {
if (axisBits == 1) {
parms->mMins.y = 0.0f;
parms->mMaxs.y = 0.0f;
parms->mMins.z = 0.0f;
parms->mMaxs.z = 0.0f;
}
else if (axisBits == 2) {
parms->mMins.z = 0.0f;
parms->mMaxs.z = 0.0f;
}
}
else {
parms->mMins = vec3_origin;
parms->mMaxs = vec3_origin;
}
if (parms->mSpawnType <= 11) {
parms->mMaxs = parms->mMins;
}
if ((parms->mFlags & 2) && parms->mSpawnType <= 12) {
parms->mSpawnType = axisBits + 12;
}
}
bool rvParticleTemplate::CheckCommonParms(idParser* src, rvParticleParms& parms)
{
bool result; // al
idToken token; // [esp+0h] [ebp-60h]
short v4; // [esp+50h] [ebp-10h]
int v5; // [esp+5Ch] [ebp-4h]
if (src->ReadToken(&token))
{
while (idStr::Cmp((const char*)token, "}"))
{
if (idStr::Icmp((const char*)token, "surface"))
{
if (idStr::Icmp((const char*)token, "useEndOrigin"))
{
if (idStr::Icmp((const char*)token, "cone"))
{
if (idStr::Icmp((const char*)token, "relative"))
{
if (idStr::Icmp((const char*)token, "linearSpacing"))
{
if (idStr::Icmp((const char*)token, "attenuate"))
{
if (!idStr::Icmp((const char*)token, "inverseAttenuate"))
parms.mFlags |= 0x40u;
}
else
{
parms.mFlags |= 0x20u;
}
}
else
{
parms.mFlags |= 0x10u;
}
}
else
{
parms.mFlags |= 8u;
}
}
else
{
parms.mFlags |= 4u;
}
}
else
{
parms.mFlags |= 2u;
}
}
else
{
parms.mFlags |= 1u;
}
if (!src->ReadToken(&token))
goto LABEL_18;
}
v5 = -1;
// idStr::FreeData((idStr*)&token.data);
result = 1;
}
else
{
LABEL_18:
v5 = -1;
// idStr::FreeData((idStr*)&token.data);
result = 0;
}
return result;
}
rvParticleParms* rvParticleTemplate::ParseSpawnParms(rvDeclEffect* effect, idParser* src, int count, rvParticleParms* def) {
idToken token;
rvParticleParms* v8;
if (!src->ExpectTokenString("{")) {
return def;
}
if (!src->ReadToken(&token)) {
return def;
}
if (token == "}") {
return def;
}
v8 = new rvParticleParms();
v8->Init();
if (token == "box") {
v8->mSpawnType = count + 16;
src->Parse1DMatrix(count, v8->mMins.ToFloatPtr(), true);
src->ExpectTokenString(",");
src->Parse1DMatrix(count, v8->mMaxs.ToFloatPtr(), true);
if (!rvParticleTemplate::CheckCommonParms(src, *v8))
{
src->Error("Invalid box parameter!");
}
if (v8->mFlags & 1)
v8->mSpawnType = count + 20;
FixupParms(v8);
return v8;
}
else if (token == "sphere") {
v8->mSpawnType = count + 24;
src->Parse1DMatrix(count, v8->mMins.ToFloatPtr(), true);
src->ExpectTokenString(",");
src->Parse1DMatrix(count, v8->mMaxs.ToFloatPtr(), true);
if (!rvParticleTemplate::CheckCommonParms(src, *v8))
{
src->Error("Invalid sphere parameter!");
}
if (v8->mFlags & 1)
v8->mSpawnType = count + 28;
FixupParms(v8);
return v8;
}
else if (token == "cylinder") {
v8->mSpawnType = count + 32;
src->Parse1DMatrix(count, v8->mMins.ToFloatPtr(), true);
src->ExpectTokenString(",");
src->Parse1DMatrix(count, v8->mMaxs.ToFloatPtr(), true);
if (!rvParticleTemplate::CheckCommonParms(src, *v8))
{
src->Error("Invalid cylinder parameter!");
}
if (v8->mFlags & 1)
v8->mSpawnType = count + 36;
FixupParms(v8);
return v8;
}
else if (token == "model") {
v8->mSpawnType = count + 44;
if (!src->ReadToken(&token)) {
delete v8;
return def;
}
idRenderModel* model = renderModelManager->FindModel(token);
if (model == NULL) {
src->Error("Failed to load model %s\n", token.c_str());
}
v8->mModelInfo = new sdModelInfo();
v8->mModelInfo->model = model;
src->ExpectTokenString(",");
src->Parse1DMatrix(count, v8->mMins.ToFloatPtr(), true);
src->ExpectTokenString(",");
src->Parse1DMatrix(count, v8->mMaxs.ToFloatPtr(), true);
if (!rvParticleTemplate::CheckCommonParms(src, *v8))
{
src->Error("Invalid model parameter!");
}
FixupParms(v8);
return v8;
}
else if (token == "spiral") {
v8->mSpawnType = count + 40;
src->Parse1DMatrix(count, v8->mMins.ToFloatPtr(), true);
src->ExpectTokenString(",");
src->Parse1DMatrix(count, v8->mMaxs.ToFloatPtr(), true);
src->CheckTokenString(",");
v8->mRange = src->ParseFloat();
if (!rvParticleTemplate::CheckCommonParms(src, *v8))
{
src->Error("Invalid spiral parameter!");
}
FixupParms(v8);
return v8;
}
else if (token == "line") {
v8->mSpawnType = count + 12;
src->Parse1DMatrix(count, v8->mMins.ToFloatPtr(), true);
src->ExpectTokenString(",");
src->Parse1DMatrix(count, v8->mMaxs.ToFloatPtr(), true);
if (!rvParticleTemplate::CheckCommonParms(src, *v8))
{
src->Error("Invalid line parameter!");
}
FixupParms(v8);
return v8;
}
else if (token == "point") {
v8->mSpawnType = count + 8;
src->Parse1DMatrix(count, v8->mMins.ToFloatPtr(), true);
if (!rvParticleTemplate::CheckCommonParms(src, *v8))
{
src->Error("Invalid point parameter!");
}
FixupParms(v8);
return v8;
}
src->Error("Invalid spawn type %s\n", token.c_str());
while (token != "}") {
if (!src->ReadToken(&token)) {
break;
}
}
delete v8;
return def;
}
bool rvParticleTemplate::ParseSpawnDomains(rvDeclEffect* effect, idParser* src) {
idToken token;
if (!src->ExpectTokenString("{")) {
return false;
}
while (src->ReadToken(&token)) {
if (token == "}") {
return true;
}
if (token == "windStrength") {
BSE_AssignParmPtr(mpSpawnWindStrength, ParseSpawnParms(effect, src, 1, &rvParticleTemplate::sSPF_NONE_1));
}
else if (token == "length") {
BSE_AssignParmPtr(mpSpawnLength, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
}
else if (token == "offset") {
BSE_AssignParmPtr(mpSpawnOffset, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
}
else if (token == "angle") {
BSE_AssignParmPtr(mpSpawnAngle, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
}
else if (token == "rotate") {
BSE_AssignParmPtr(mpSpawnRotate, ParseSpawnParms(effect, src, mNumRotateParms, &rvParticleTemplate::sSPF_NONE_3));
}
else if (token == "size") {
BSE_AssignParmPtr(mpSpawnSize, ParseSpawnParms(effect, src, mNumSizeParms, &rvParticleTemplate::sSPF_ONE_3));
}
else if (token == "fade") {
BSE_AssignParmPtr(mpSpawnFade, ParseSpawnParms(effect, src, 1, &rvParticleTemplate::sSPF_ONE_1));
}
else if (token == "tint") {
BSE_AssignParmPtr(mpSpawnTint, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_ONE_3));
}
else if (token == "friction") {
BSE_AssignParmPtr(mpSpawnFriction, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
}
else if (token == "acceleration") {
BSE_AssignParmPtr(mpSpawnAcceleration, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
}
else if (token == "velocity") {
BSE_AssignParmPtr(mpSpawnVelocity, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
}
else if (token == "direction") {
BSE_AssignParmPtr(mpSpawnDirection, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
mFlags |= 0x4000u;
}
else if (token == "position") {
BSE_AssignParmPtr(mpSpawnPosition, ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3));
}
else {
src->Error("Invalid spawn type %s\n", token.c_str());
}
}
return false;
}
bool rvParticleTemplate::ParseDeathDomains(rvDeclEffect* effect, idParser* src) {
idToken token;
if (!src->ExpectTokenString("{")) {
return false;
}
while (src->ReadToken(&token)) {
if (token == "}") {
return true;
}
if (token == "length") {
rvParticleParms* v13 = ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3);
bool v7 = mpLengthEnvelope == &rvParticleTemplate::sEmptyEnvelope;
BSE_AssignParmPtr(mpDeathLength, v13);
if (v7) {
BSE_AssignEnvPtr(mpLengthEnvelope, &rvParticleTemplate::sDefaultEnvelope);
}
}
else if (token == "offset") {
rvParticleParms* v13 = ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3);
bool v7 = mpOffsetEnvelope == &rvParticleTemplate::sEmptyEnvelope;
BSE_AssignParmPtr(mpDeathOffset, v13);
if (v7) {
BSE_AssignEnvPtr(mpOffsetEnvelope, &rvParticleTemplate::sDefaultEnvelope);
}
}
else if (token == "angle") {
rvParticleParms* v13 = ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3);
bool v7 = mpAngleEnvelope == &rvParticleTemplate::sEmptyEnvelope;
BSE_AssignParmPtr(mpDeathAngle, v13);
if (v7) {
BSE_AssignEnvPtr(mpAngleEnvelope, &rvParticleTemplate::sDefaultEnvelope);
}
}
else if (token == "rotate") {
rvParticleParms* v10 = ParseSpawnParms(effect, src, mNumRotateParms, &rvParticleTemplate::sSPF_NONE_3);
BSE_AssignParmPtr(mpDeathRotate, v10);
if (mpRotateEnvelope == &rvParticleTemplate::sEmptyEnvelope) {
BSE_AssignEnvPtr(mpRotateEnvelope, &rvParticleTemplate::sDefaultEnvelope);
}
}
else if (token == "size") {
rvParticleParms* v9 = ParseSpawnParms(effect, src, mNumSizeParms, &rvParticleTemplate::sSPF_ONE_3);
BSE_AssignParmPtr(mpDeathSize, v9);
if (mpSizeEnvelope == &rvParticleTemplate::sEmptyEnvelope) {
BSE_AssignEnvPtr(mpSizeEnvelope, &rvParticleTemplate::sDefaultEnvelope);
}
}
else if (token == "fade") {
rvParticleParms* v8 = ParseSpawnParms(effect, src, 1, &rvParticleTemplate::sSPF_NONE_1);
BSE_AssignParmPtr(mpDeathFade, v8);
if (mpFadeEnvelope == &rvParticleTemplate::sEmptyEnvelope) {
BSE_AssignEnvPtr(mpFadeEnvelope, &rvParticleTemplate::sDefaultEnvelope);
}
}
else if (token == "tint") {
rvParticleParms* v6 = ParseSpawnParms(effect, src, 3, &rvParticleTemplate::sSPF_NONE_3);
BSE_AssignParmPtr(mpDeathTint, v6);
if (mpTintEnvelope == &rvParticleTemplate::sEmptyEnvelope) {
BSE_AssignEnvPtr(mpTintEnvelope, &rvParticleTemplate::sDefaultEnvelope);
}
}
else {
src->Error("Invalid end type %s\n", token.c_str());
}
}
return false;
}
bool rvParticleTemplate::Parse(rvDeclEffect* effect, idParser* src) {
idToken token;
if (!src->ExpectTokenString("{")) {
return false;
}
while (src->ReadToken(&token)) {
if (token == "}") {
Finish();
return true;
}
if (token == "windDeviationAngle") {
mWindDeviationAngle = src->ParseFloat();
}
else if (token == "timeout") {
if (!ParseTimeout(effect, src)) {
return false;
}
}
else if (token == "impact") {
if (!ParseImpact(effect, src)) {
return false;
}
}
else if (token == "model") {
if (!src->ReadToken(&token)) {
return false;
}
mModel = renderModelManager->FindModel(token);
if (mModel == NULL) {
mModel = renderModelManager->FindModel("_default");
src->Warning("No surfaces defined in model %s", token.c_str());
}
}
else if (token == "numFrames") {
mNumFrames = src->ParseInt();
}
else if (token == "fadeIn") {
mFlags |= PTFLAG_FADE_IN;
}
else if (token == "useLightningAxis") {
mFlags |= 0x400000u;
}
else if (token == "specular") {
mFlags |= 0x40000u;
}
else if (token == "shadows") {
mFlags |= 0x20000u;
}
else if (token == "blend") {
if (!ParseBlendParms(effect, src)) {
return false;
}
}
else if (token == "entityDef") {
if (!src->ReadToken(&token)) {
return false;
}
mEntityDefName = token;
}
else if (token == "material") {
if (!src->ReadToken(&token)) {
return false;
}
mMaterial = declManager->FindMaterial(token);
}
else if (token == "trailScale") {
AllocTrail();
mTrailInfo->mTrailScale = src->ParseFloat();
}
else if (token == "trailCount") {
AllocTrail();
mTrailInfo->mTrailCount.x = src->ParseFloat();
src->ExpectTokenString(",");
mTrailInfo->mTrailCount.y = src->ParseFloat();
}
else if (token == "trailRepeat") {
AllocTrail();
mTrailRepeat = src->ParseInt();
}
else if (token == "trailTime") {
AllocTrail();
mTrailInfo->mTrailTime.x = src->ParseFloat();
src->ExpectTokenString(",");
mTrailInfo->mTrailTime.y = src->ParseFloat();
}
else if (token == "trailMaterial") {
AllocTrail();
if (!src->ReadToken(&token)) {
return false;
}
mTrailInfo->mTrailMaterial = declManager->FindMaterial(token);
}
else if (token == "trailType") {
AllocTrail();
if (!src->ReadToken(&token)) {
return false;
}
if (token == "burn") {
mTrailInfo->mTrailType = 1;
mTrailInfo->mTrailTypeName = "";
}
else if (token == "motion") {
mTrailInfo->mTrailType = 2;
mTrailInfo->mTrailTypeName = "";
}
else {
mTrailInfo->mTrailType = 3;
mTrailInfo->mTrailTypeName = token;
}
}
else if (token == "fork") {
AllocElectricityInfo();
int forks = src->ParseInt();
if (forks < 0) {
forks = 0;
} else if (forks > BSE_MAX_FORKS) {
forks = BSE_MAX_FORKS;
}
mElecInfo->mNumForks = forks;
}
else if (token == "forkMins") {
AllocElectricityInfo();
src->Parse1DMatrix(3, mElecInfo->mForkSizeMins.ToFloatPtr(), true);
}
else if (token == "forkMaxs") {
AllocElectricityInfo();
src->Parse1DMatrix(3, mElecInfo->mForkSizeMaxs.ToFloatPtr(), true);
}
else if (token == "jitterSize") {
AllocElectricityInfo();
src->Parse1DMatrix(3, mElecInfo->mJitterSize.ToFloatPtr(), true);
}
else if (token == "jitterRate") {
AllocElectricityInfo();
mElecInfo->mJitterRate = src->ParseFloat();
}
else if (token == "jitterTable") {
AllocElectricityInfo();
if (!src->ReadToken(&token)) {
return false;
}
mElecInfo->mJitterTableName = token;
mElecInfo->mJitterTable = declManager->FindTable(token, false);
}
else if (token == "gravity") {
mGravity.x = src->ParseFloat();
src->ExpectTokenString(",");
mGravity.y = src->ParseFloat();
}
else if (token == "duration") {
float srcb = src->ParseFloat();
float v8 = 0.0020000001;
if (srcb >= 0.0020000001)
{
v8 = srcb;
if (srcb > 300.0)
v8 = 300.0;
}
float srcg = v8;
mDuration.x = srcg;
src->ExpectTokenString(",");
float srcc = src->ParseFloat();
float v9 = 0.0020000001;
if (srcc < 0.0020000001 || (v9 = srcc, srcc <= 300.0))
{
float srch = v9;
mDuration.y = srch;
}
else
{
mDuration.y = 300.0;
}
}
else if (token == "parentvelocity") {
mFlags |= 0x2000000u;
}
else if (token == "tiling") {
mFlags |= 0x100000u;
float srca = src->ParseFloat();
float v7 = 0.0020000001;
if (srca < 0.0020000001 || (v7 = srca, srca <= 1024.0))
{
float srcf = v7;
mTiling = srcf;
}
else
{
mTiling = 1024.0;
}
}
else if (token == "persist") {
mFlags |= 0x200000u;
}
else if (token == "generatedLine") {
mFlags |= 0x10000u;
}
else if (token == "flipNormal") {
mFlags |= 0x2000u;
}
else if (token == "lineHit") {
mFlags |= 0x4000000u;
}
else if (token == "generatedOriginNormal") {
mFlags |= 0x1000u;
}
else if (token == "generatedNormal") {
mFlags |= 0x800u;
}
else if (token == "motion") {
if (!ParseMotionDomains(effect, src)) {
return false;
}
}
else if (token == "end") {
if (!ParseDeathDomains(effect, src)) {
return false;
}
}
else if (token == "start") {
if (!ParseSpawnDomains(effect, src)) {
return false;
}
}
else {
src->Error("Invalid particle keyword %s\n", token.c_str());
}
}
return false;
}
void rvParticleTemplate::Duplicate(rvParticleTemplate const& copy) {
if (this == &copy) {
return;
}
Purge();
PurgeTraceModel();
*this = copy;
if (copy.mTrailInfo != NULL && !copy.mTrailInfo->mStatic) {
mTrailInfo = new rvTrailInfo(*copy.mTrailInfo);
mTrailInfo->mStatic = 0;
}
if (copy.mElecInfo != NULL && !copy.mElecInfo->mStatic) {
mElecInfo = new rvElectricityInfo(*copy.mElecInfo);
mElecInfo->mStatic = 0;
}
mpSpawnPosition = BSE_DuplicateParm(copy.mpSpawnPosition);
mpSpawnDirection = BSE_DuplicateParm(copy.mpSpawnDirection);
mpSpawnVelocity = BSE_DuplicateParm(copy.mpSpawnVelocity);
mpSpawnAcceleration = BSE_DuplicateParm(copy.mpSpawnAcceleration);
mpSpawnFriction = BSE_DuplicateParm(copy.mpSpawnFriction);
mpSpawnTint = BSE_DuplicateParm(copy.mpSpawnTint);
mpSpawnFade = BSE_DuplicateParm(copy.mpSpawnFade);
mpSpawnSize = BSE_DuplicateParm(copy.mpSpawnSize);
mpSpawnRotate = BSE_DuplicateParm(copy.mpSpawnRotate);
mpSpawnAngle = BSE_DuplicateParm(copy.mpSpawnAngle);
mpSpawnOffset = BSE_DuplicateParm(copy.mpSpawnOffset);
mpSpawnLength = BSE_DuplicateParm(copy.mpSpawnLength);
mpSpawnWindStrength = BSE_DuplicateParm(copy.mpSpawnWindStrength);
mpDeathTint = BSE_DuplicateParm(copy.mpDeathTint);
mpDeathFade = BSE_DuplicateParm(copy.mpDeathFade);
mpDeathSize = BSE_DuplicateParm(copy.mpDeathSize);
mpDeathRotate = BSE_DuplicateParm(copy.mpDeathRotate);
mpDeathAngle = BSE_DuplicateParm(copy.mpDeathAngle);
mpDeathOffset = BSE_DuplicateParm(copy.mpDeathOffset);
mpDeathLength = BSE_DuplicateParm(copy.mpDeathLength);
mpTintEnvelope = BSE_DuplicateEnv(copy.mpTintEnvelope);
mpFadeEnvelope = BSE_DuplicateEnv(copy.mpFadeEnvelope);
mpSizeEnvelope = BSE_DuplicateEnv(copy.mpSizeEnvelope);
mpRotateEnvelope = BSE_DuplicateEnv(copy.mpRotateEnvelope);
mpAngleEnvelope = BSE_DuplicateEnv(copy.mpAngleEnvelope);
mpOffsetEnvelope = BSE_DuplicateEnv(copy.mpOffsetEnvelope);
mpLengthEnvelope = BSE_DuplicateEnv(copy.mpLengthEnvelope);
if (mpSpawnPosition == NULL) { mpSpawnPosition = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnDirection == NULL) { mpSpawnDirection = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnVelocity == NULL) { mpSpawnVelocity = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnAcceleration == NULL) { mpSpawnAcceleration = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnFriction == NULL) { mpSpawnFriction = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnTint == NULL) { mpSpawnTint = &rvParticleTemplate::sSPF_ONE_3; }
if (mpSpawnFade == NULL) { mpSpawnFade = &rvParticleTemplate::sSPF_ONE_1; }
if (mpSpawnSize == NULL) { mpSpawnSize = &rvParticleTemplate::sSPF_ONE_3; }
if (mpSpawnRotate == NULL) { mpSpawnRotate = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnAngle == NULL) { mpSpawnAngle = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnOffset == NULL) { mpSpawnOffset = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnLength == NULL) { mpSpawnLength = &rvParticleTemplate::sSPF_NONE_3; }
if (mpSpawnWindStrength == NULL) { mpSpawnWindStrength = &rvParticleTemplate::sSPF_NONE_1; }
if (mpDeathTint == NULL) { mpDeathTint = &rvParticleTemplate::sSPF_NONE_3; }
if (mpDeathFade == NULL) { mpDeathFade = &rvParticleTemplate::sSPF_NONE_1; }
if (mpDeathSize == NULL) { mpDeathSize = &rvParticleTemplate::sSPF_ONE_3; }
if (mpDeathRotate == NULL) { mpDeathRotate = &rvParticleTemplate::sSPF_NONE_3; }
if (mpDeathAngle == NULL) { mpDeathAngle = &rvParticleTemplate::sSPF_NONE_3; }
if (mpDeathOffset == NULL) { mpDeathOffset = &rvParticleTemplate::sSPF_NONE_3; }
if (mpDeathLength == NULL) { mpDeathLength = &rvParticleTemplate::sSPF_NONE_3; }
if (mpTintEnvelope == NULL) { mpTintEnvelope = &rvParticleTemplate::sEmptyEnvelope; }
if (mpFadeEnvelope == NULL) { mpFadeEnvelope = &rvParticleTemplate::sEmptyEnvelope; }
if (mpSizeEnvelope == NULL) { mpSizeEnvelope = &rvParticleTemplate::sEmptyEnvelope; }
if (mpRotateEnvelope == NULL) { mpRotateEnvelope = &rvParticleTemplate::sEmptyEnvelope; }
if (mpAngleEnvelope == NULL) { mpAngleEnvelope = &rvParticleTemplate::sEmptyEnvelope; }
if (mpOffsetEnvelope == NULL) { mpOffsetEnvelope = &rvParticleTemplate::sEmptyEnvelope; }
if (mpLengthEnvelope == NULL) { mpLengthEnvelope = &rvParticleTemplate::sEmptyEnvelope; }
}
void rvParticleTemplate::Finish()
{
double v2; // st7
rvParticleTemplate* v3; // esi
rvTrailInfo* v4; // eax
float* v5; // eax
const modelSurface_t* v6; // eax
const modelSurface_t* v7; // ebp
idTraceModel* v8; // eax
idTraceModel* v9; // edi
idBounds* v10; // ebp
rvTrailInfo* v11; // ecx
rvElectricityInfo* v12; // eax
float v13; // ST10_4
float v14; // ST10_4
rvTrailInfo* v15; // ecx
float v16; // ST10_4
rvTrailInfo* v17; // ecx
double v18; // st6
float* v19; // ecx
float v20; // ST10_4
float* v21; // eax
float v22; // ST14_4
float v23; // ST18_4
float v24; // ST1C_4
float v25; // ST20_4
float v26; // ST24_4
float v27; // ST28_4
signed int retaddr; // [esp+2Ch] [ebp+0h]
v2 = 0.0;
v3 = this;
v3->mFlags |= 0x100u;
v4 = this->mTrailInfo;
if ((!v4->mTrailType || v4->mTrailType == 3) && !v4->mStatic)
{
v4->mTrailTime.y = 0.0;
v4->mTrailTime.x = 0.0;
v5 = &this->mTrailInfo->mTrailCount.x;
v5[1] = 0.0;
*v5 = 0.0;
}
switch (this->mType)
{
case 1:
case 2:
v11 = this->mTrailInfo;
v3->mVertexCount = 4;
v3->mIndexCount = 6;
if (0.0 != v11->mTrailCount.y && v11->mTrailType == 1)
{
v3->mVertexCount *= (unsigned short)v3->GetMaxTrailCount();
v2 = 0.0;
v3->mIndexCount *= (unsigned short)v3->GetMaxTrailCount();
}
break;
case 4:
case 6:
case 8:
case 9:
this->mVertexCount = 4;
this->mIndexCount = 6;
break;
case 5:
{
idBounds modelBounds;
bool hasValidBounds = false;
v6 = ( this->mModel != NULL ) ? this->mModel->Surface( 0 ) : NULL;
v7 = v6;
if ( v6 != NULL && v6->geometry != NULL ) {
v3->mVertexCount = v6->geometry->numVerts;
v3->mIndexCount = v6->geometry->numIndexes;
v3->mMaterial = v6->shader;
modelBounds = v6->geometry->bounds;
hasValidBounds = !modelBounds.IsCleared();
} else if ( this->mModel != NULL ) {
modelBounds = this->mModel->Bounds();
hasValidBounds = !modelBounds.IsCleared();
}
// Corrupt/missing model bounds can come from partially loaded surfaces.
// Fall back to a small cube so trace model creation remains safe.
if ( !hasValidBounds ||
idMath::Fabs( modelBounds[0].x ) > 1000000.0f || idMath::Fabs( modelBounds[0].y ) > 1000000.0f || idMath::Fabs( modelBounds[0].z ) > 1000000.0f ||
idMath::Fabs( modelBounds[1].x ) > 1000000.0f || idMath::Fabs( modelBounds[1].y ) > 1000000.0f || idMath::Fabs( modelBounds[1].z ) > 1000000.0f ) {
modelBounds[0].Set( -8.0f, -8.0f, -8.0f );
modelBounds[1].Set( 8.0f, 8.0f, 8.0f );
}
v3->PurgeTraceModel();
v8 = new idTraceModel();
v9 = v8;
retaddr = 0;
if ( v8 ) {
v8->InitBox();
v9->SetupBox( modelBounds );
}
retaddr = -1;
v2 = 0.0;
v3->mTraceModelIndex = bse->AddTraceModel( v8 );
}
break;
case 7:
v12 = this->mElecInfo;
this->mVertexCount = 20 * ((unsigned short)v12->mNumForks + 1);
this->mIndexCount = 60 * ((unsigned short)v12->mNumForks + 1);
break;
case 0xA:
this->mVertexCount = 0;
this->mIndexCount = 0;
break;
default:
break;
}
if (v3->mDuration.y <= (double)v3->mDuration.x)
{
v13 = v3->mDuration.x;
v3->mDuration.x = v3->mDuration.y;
v3->mDuration.y = v13;
}
if (v3->mGravity.y <= (double)v3->mGravity.x)
{
v14 = v3->mGravity.x;
v3->mGravity.x = v3->mGravity.y;
v3->mGravity.y = v14;
}
v15 = v3->mTrailInfo;
if (!v15->mStatic)
{
if (v15->mTrailTime.y <= (double)v15->mTrailTime.x)
{
v16 = v15->mTrailTime.x;
v15->mTrailTime.x = v15->mTrailTime.y;
v15->mTrailTime.y = v16;
}
v17 = v3->mTrailInfo;
v18 = v17->mTrailCount.x;
v19 = &v17->mTrailCount.x;
if (v19[1] <= v18)
{
v20 = *v19;
*v19 = v19[1];
v19[1] = v20;
}
}
v3->mCentre.z = v2;
v3->mCentre.y = v2;
v3->mCentre.x = v2;
if (!(((unsigned int)v3->mFlags >> 12) & 1))
{
v21 = (float*)&v3->mpSpawnPosition->mSpawnType;
switch (*reinterpret_cast<unsigned char*>(v21))
{
case 0xBu:
v3->mCentre.x = v21[3];
v3->mCentre.y = v21[4];
v3->mCentre.z = v21[5];
break;
case 0xFu:
case 0x13u:
case 0x17u:
case 0x1Bu:
case 0x1Fu:
case 0x23u:
case 0x27u:
case 0x2Bu:
case 0x2Fu:
v22 = v21[6] + v21[3];
v23 = v21[7] + v21[4];
v24 = v21[8] + v21[5];
v25 = v22 * 0.5;
v26 = v23 * 0.5;
v27 = 0.5 * v24;
v3->mCentre.x = v25;
v3->mCentre.y = v26;
v3->mCentre.z = v27;
break;
default:
return;
}
}
}
void rvParticleTemplate::InitStatic()
{
//sdDeclTypeHolder* v0; // eax
int v1; // eax
//sdDeclTypeHolder* v2; // eax
if (!rvParticleTemplate::sInited)
{
rvParticleTemplate::sInited = 1;
rvParticleTemplate::sTrailInfo.mTrailType = 0;
rvParticleTemplate::sTrailInfo.mStatic = 1;
rvParticleTemplate::sTrailInfo.mPad = 0;
rvParticleTemplate::sTrailInfo.mTrailTypeName = "";
// Match stock Q4 behavior: motion trails default to the motionblur
// material when trailMaterial isn't authored.
const idMaterial* defaultTrailMaterial = declManager->FindMaterial("gfx/effects/particles_shapes/motionblur", false);
if (defaultTrailMaterial == NULL) {
defaultTrailMaterial = declManager->FindMaterial("_default");
}
rvParticleTemplate::sTrailInfo.mTrailMaterial = defaultTrailMaterial;
rvParticleTemplate::sTrailInfo.mTrailTime.x = 0.0f;
rvParticleTemplate::sTrailInfo.mTrailTime.y = 0.0f;
rvParticleTemplate::sTrailInfo.mTrailCount.x = 0.0f;
rvParticleTemplate::sTrailInfo.mTrailCount.y = 0.0f;
rvParticleTemplate::sTrailInfo.mTrailScale = 0.0f;
//unk_7E672A = 1;
//v0 = sdSingleton<sdDeclTypeHolder>::GetInstance();
//v1 = ((int(__stdcall*)(int, const char*, signed int))declManager->vfptr->FindType)(
// v0->declMaterialType.declTypeHandle,
// "_default",
// 1);
//unk_7E6754 = 0.0;
//unk_7E674C = v1;
//unk_7E6750 = 0.0;
rvParticleTemplate::sElectricityInfo.mNumForks = 0;
//unk_7E675C = 0.0;
rvParticleTemplate::sElectricityInfo.mStatic = 1;
//unk_7E6758 = 0.0;
//unk_7E6760 = 0.5;
rvParticleTemplate::sElectricityInfo.mForkSizeMins.x = -20.0;
rvParticleTemplate::sElectricityInfo.mForkSizeMins.y = -20.0;
rvParticleTemplate::sElectricityInfo.mForkSizeMins.z = -20.0;
rvParticleTemplate::sElectricityInfo.mForkSizeMaxs.x = 20.0;
rvParticleTemplate::sElectricityInfo.mForkSizeMaxs.y = 20.0;
rvParticleTemplate::sElectricityInfo.mForkSizeMaxs.z = 20.0;
rvParticleTemplate::sElectricityInfo.mJitterSize.x = 3.0;
rvParticleTemplate::sElectricityInfo.mJitterSize.y = 7.0;
rvParticleTemplate::sElectricityInfo.mJitterSize.z = 7.0;
rvParticleTemplate::sElectricityInfo.mJitterRate = 0.0;
rvParticleTemplate::sElectricityInfo.mJitterTableName = "halfsintable";
//v2 = sdSingleton<sdDeclTypeHolder>::GetInstance();
rvParticleTemplate::sElectricityInfo.mJitterTable = declManager->FindTable("halfsintable", false);
rvParticleTemplate::sDefaultEnvelope.Init(); //rvEnvParms::Init(&rvParticleTemplate::sDefaultEnvelope);
rvParticleTemplate::sDefaultEnvelope.SetDefaultType(); // rvEnvParms::SetDefaultType(&rvParticleTemplate::sDefaultEnvelope);
rvParticleTemplate::sDefaultEnvelope.mStatic = 1;
rvParticleTemplate::sEmptyEnvelope.Init(); // rvEnvParms::Init(&rvParticleTemplate::sEmptyEnvelope);
rvParticleTemplate::sSPF_ONE_1.mRange = 0.0;
rvParticleTemplate::sEmptyEnvelope.mStatic = 1;
rvParticleTemplate::sSPF_ONE_1.mMins.z = 0.0;
rvParticleTemplate::sSPF_ONE_1.mSpawnType = 5;
rvParticleTemplate::sSPF_ONE_1.mMins.y = 0.0;
rvParticleTemplate::sSPF_ONE_1.mFlags = 0;
rvParticleTemplate::sSPF_ONE_1.mMins.x = 0.0;
rvParticleTemplate::sSPF_ONE_1.mModelInfo = 0;
rvParticleTemplate::sSPF_ONE_1.mMaxs.z = 0.0;
rvParticleTemplate::sSPF_ONE_1.mStatic = 1;
rvParticleTemplate::sSPF_ONE_1.mMaxs.y = 0.0;
rvParticleTemplate::sSPF_ONE_2.mSpawnType = 6;
rvParticleTemplate::sSPF_ONE_1.mMaxs.x = 0.0;
rvParticleTemplate::sSPF_ONE_2.mFlags = 0;
rvParticleTemplate::sSPF_ONE_2.mRange = 0.0;
rvParticleTemplate::sSPF_ONE_2.mModelInfo = 0;
rvParticleTemplate::sSPF_ONE_2.mMins.z = 0.0;
rvParticleTemplate::sSPF_ONE_2.mStatic = 1;
rvParticleTemplate::sSPF_ONE_2.mMins.y = 0.0;
rvParticleTemplate::sSPF_ONE_3.mSpawnType = 7;
rvParticleTemplate::sSPF_ONE_2.mMins.x = 0.0;
rvParticleTemplate::sSPF_ONE_3.mFlags = 0;
rvParticleTemplate::sSPF_ONE_2.mMaxs.z = 0.0;
rvParticleTemplate::sSPF_ONE_2.mMaxs.y = 0.0;
rvParticleTemplate::sSPF_ONE_2.mMaxs.x = 0.0;
rvParticleTemplate::sSPF_ONE_3.mRange = 0.0;
rvParticleTemplate::sSPF_ONE_3.mMins.z = 0.0;
rvParticleTemplate::sSPF_ONE_3.mModelInfo = 0;
rvParticleTemplate::sSPF_ONE_3.mMins.y = 0.0;
rvParticleTemplate::sSPF_ONE_3.mStatic = 1;
rvParticleTemplate::sSPF_ONE_3.mMins.x = 0.0;
rvParticleTemplate::sSPF_NONE_0.mSpawnType = 0;
rvParticleTemplate::sSPF_ONE_3.mMaxs.z = 0.0;
rvParticleTemplate::sSPF_NONE_0.mFlags = 0;
rvParticleTemplate::sSPF_ONE_3.mMaxs.y = 0.0;
rvParticleTemplate::sSPF_NONE_0.mModelInfo = 0;
rvParticleTemplate::sSPF_ONE_3.mMaxs.x = 0.0;
rvParticleTemplate::sSPF_NONE_0.mStatic = 1;
rvParticleTemplate::sSPF_NONE_0.mRange = 0.0;
rvParticleTemplate::sSPF_NONE_1.mSpawnType = 1;
rvParticleTemplate::sSPF_NONE_0.mMins.z = 0.0;
rvParticleTemplate::sSPF_NONE_1.mFlags = 0;
rvParticleTemplate::sSPF_NONE_0.mMins.y = 0.0;
rvParticleTemplate::sSPF_NONE_1.mModelInfo = 0;
rvParticleTemplate::sSPF_NONE_0.mMins.x = 0.0;
rvParticleTemplate::sSPF_NONE_1.mStatic = 1;
rvParticleTemplate::sSPF_NONE_0.mMaxs.z = 0.0;
rvParticleTemplate::sSPF_NONE_3.mSpawnType = 3;
rvParticleTemplate::sSPF_NONE_0.mMaxs.y = 0.0;
rvParticleTemplate::sSPF_NONE_3.mFlags = 0;
rvParticleTemplate::sSPF_NONE_0.mMaxs.x = 0.0;
rvParticleTemplate::sSPF_NONE_3.mModelInfo = 0;
rvParticleTemplate::sSPF_NONE_1.mRange = 0.0;
rvParticleTemplate::sSPF_NONE_3.mStatic = 1;
rvParticleTemplate::sSPF_NONE_1.mMins.z = 0.0;
rvParticleTemplate::sSPF_NONE_1.mMins.y = 0.0;
rvParticleTemplate::sSPF_NONE_1.mMins.x = 0.0;
rvParticleTemplate::sSPF_NONE_1.mMaxs.z = 0.0;
rvParticleTemplate::sSPF_NONE_1.mMaxs.y = 0.0;
rvParticleTemplate::sSPF_NONE_1.mMaxs.x = 0.0;
rvParticleTemplate::sSPF_NONE_3.mRange = 0.0;
rvParticleTemplate::sSPF_NONE_3.mMins.z = 0.0;
rvParticleTemplate::sSPF_NONE_3.mMins.y = 0.0;
rvParticleTemplate::sSPF_NONE_3.mMins.x = 0.0;
rvParticleTemplate::sSPF_NONE_3.mMaxs.z = 0.0;
rvParticleTemplate::sSPF_NONE_3.mMaxs.y = 0.0;
rvParticleTemplate::sSPF_NONE_3.mMaxs.x = 0.0;
}
}
void rvParticleTemplate::Init(void)
{
rvParticleTemplate* v1; // esi
//sdDeclTypeHolder* v2; // eax
rvDeclEffect** v3; // eax
signed int v4; // ecx
v1 = this;
rvParticleTemplate::InitStatic();
v1->mFlags = 0;
v1->mType = 0;
//v2 = sdSingleton<sdDeclTypeHolder>::GetInstance();
v1->SetMaterial((idMaterial *)declManager->FindMaterial("_default"));
v1->mModel = renderModelManager->FindModel("_default");
//v1->mMaterial = (idMaterial*)((int(__stdcall*)(int, const char*, signed int))declManager->vfptr->FindType)(
// v2->declMaterialType.declTypeHandle,
// "_default",
// 1);
//v1->mModel = (idRenderModel*)((int(__stdcall*)(const char*))renderModelManager->vfptr->FindModel)("_default");
v1->mTraceModelIndex = -1;
v1->mGravity.y = 0.0;
v1->mGravity.x = 0.0;
v1->mTiling = 8.0;
v1->mPhysicsDistance = 0.0;
v1->mBounce = 0.0;
v1->mDuration.x = 0.0020000001;
v1->mDuration.y = 0.0020000001;
v1->mCentre.z = 0.0;
v1->mCentre.y = 0.0;
v1->mCentre.x = 0.0;
v1->mFlags |= 0x4000000u;
v1->mpSpawnPosition = &rvParticleTemplate::sSPF_NONE_3;
v1->mWindDeviationAngle = 0.0;
v1->mpSpawnDirection = &rvParticleTemplate::sSPF_NONE_3;
v1->mpSpawnVelocity = &rvParticleTemplate::sSPF_NONE_3;
v1->mpSpawnAcceleration = &rvParticleTemplate::sSPF_NONE_3;
v1->mpSpawnFriction = &rvParticleTemplate::sSPF_NONE_3;
v1->mpSpawnRotate = &rvParticleTemplate::sSPF_NONE_3;
v1->mpSpawnAngle = &rvParticleTemplate::sSPF_NONE_3;
v1->mpSpawnOffset = &rvParticleTemplate::sSPF_NONE_3;
v1->mpSpawnLength = &rvParticleTemplate::sSPF_NONE_3;
v1->mpDeathTint = &rvParticleTemplate::sSPF_NONE_3;
v1->mpDeathRotate = &rvParticleTemplate::sSPF_NONE_3;
v1->mpDeathAngle = &rvParticleTemplate::sSPF_NONE_3;
v1->mpDeathOffset = &rvParticleTemplate::sSPF_NONE_3;
v1->mpDeathLength = &rvParticleTemplate::sSPF_NONE_3;
v1->mNumSizeParms = 2;
v1->mNumRotateParms = 1;
v1->mVertexCount = 4;
v1->mIndexCount = 6;
v1->mTrailInfo = &rvParticleTemplate::sTrailInfo;
v1->mElecInfo = &rvParticleTemplate::sElectricityInfo;
v1->mpSpawnTint = &rvParticleTemplate::sSPF_ONE_3;
v1->mpSpawnFade = &rvParticleTemplate::sSPF_ONE_1;
v1->mpSpawnSize = &rvParticleTemplate::sSPF_ONE_3;
v1->mpSpawnWindStrength = &rvParticleTemplate::sSPF_NONE_1;
v1->mpTintEnvelope = &rvParticleTemplate::sEmptyEnvelope;
v1->mpFadeEnvelope = &rvParticleTemplate::sEmptyEnvelope;
v1->mpSizeEnvelope = &rvParticleTemplate::sEmptyEnvelope;
v1->mpRotateEnvelope = &rvParticleTemplate::sEmptyEnvelope;
v1->mpAngleEnvelope = &rvParticleTemplate::sEmptyEnvelope;
v1->mpOffsetEnvelope = &rvParticleTemplate::sEmptyEnvelope;
v1->mpLengthEnvelope = &rvParticleTemplate::sEmptyEnvelope;
v1->mpDeathFade = &rvParticleTemplate::sSPF_NONE_1;
v1->mpDeathSize = &rvParticleTemplate::sSPF_ONE_3;
v1->mTrailRepeat = 1;
v1->mNumFrames = 0;
v1->mNumImpactEffects = 0;
v1->mNumTimeoutEffects = 0;
v1->mImpactEffects[0] = NULL;
v1->mImpactEffects[1] = NULL;
v1->mImpactEffects[2] = NULL;
v1->mImpactEffects[3] = NULL;
v1->mTimeoutEffects[0] = NULL;
v1->mTimeoutEffects[1] = NULL;
v1->mTimeoutEffects[2] = NULL;
v1->mTimeoutEffects[3] = NULL;
// jmarshall: no idea
//v3 = &v1->mTimeoutEffects[0];
// jmarshall end
v4 = 4;
// jmarshall: no idea
//do
//{
// *(v3 - 5) = 0;
// *v3 = 0;
// ++v3;
// --v4;
//} while (v4);
// jmarshall end
v1->mFlags |= 0x8000000u;
}
void rvParticleTemplate::SetParameterCounts()
{
rvParticleParms* v1; // eax
rvParticleParms* v2; // edx
switch (this->mType)
{
case 1:
case 4:
this->mNumSizeParms = 2;
this->mNumRotateParms = 1;
v1 = &rvParticleTemplate::sSPF_ONE_2;
v2 = &rvParticleTemplate::sSPF_NONE_1;
goto LABEL_11;
case 2:
case 7:
case 8:
case 9:
this->mNumSizeParms = 1;
this->mNumRotateParms = 0;
v1 = &rvParticleTemplate::sSPF_ONE_1;
v2 = &rvParticleTemplate::sSPF_NONE_0;
goto LABEL_11;
case 3:
this->mNumSizeParms = 2;
this->mNumRotateParms = 3;
v1 = &rvParticleTemplate::sSPF_ONE_2;
v2 = &rvParticleTemplate::sSPF_NONE_3;
goto LABEL_11;
case 5:
this->mNumSizeParms = 3;
this->mNumRotateParms = 3;
goto LABEL_9;
case 6:
this->mNumSizeParms = 3;
this->mNumRotateParms = 0;
v2 = &rvParticleTemplate::sSPF_NONE_0;
goto LABEL_10;
case 0xA:
this->mNumSizeParms = 0;
this->mNumRotateParms = 3;
LABEL_9:
v2 = &rvParticleTemplate::sSPF_NONE_3;
LABEL_10:
v1 = &rvParticleTemplate::sSPF_ONE_3;
LABEL_11:
this->mpSpawnSize = v1;
this->mpSpawnRotate = v2;
this->mpDeathSize = v1;
this->mpDeathRotate = v2;
break;
default:
return;
}
}
void rvParticleTemplate::PurgeTraceModel(void) {
rvParticleTemplate* v1; // esi
int v2; // eax
v1 = this;
v2 = this->mTraceModelIndex;
if (v2 != -1)
{
bse->FreeTraceModel(v2);
v1->mTraceModelIndex = -1;
}
}
void rvParticleTemplate::Purge() {
PurgeTraceModel();
rvParticleParms* seenParms[20];
int seenParmCount = 0;
BSE_DeleteOwnedParm(mpSpawnPosition, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnDirection, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnVelocity, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnAcceleration, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnFriction, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnTint, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnFade, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnSize, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnRotate, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnAngle, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnOffset, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnLength, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpSpawnWindStrength, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpDeathTint, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpDeathFade, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpDeathSize, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpDeathRotate, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpDeathAngle, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpDeathOffset, seenParms, seenParmCount);
BSE_DeleteOwnedParm(mpDeathLength, seenParms, seenParmCount);
rvEnvParms* seenEnvs[7];
int seenEnvCount = 0;
BSE_DeleteOwnedEnv(mpTintEnvelope, seenEnvs, seenEnvCount);
BSE_DeleteOwnedEnv(mpFadeEnvelope, seenEnvs, seenEnvCount);
BSE_DeleteOwnedEnv(mpSizeEnvelope, seenEnvs, seenEnvCount);
BSE_DeleteOwnedEnv(mpRotateEnvelope, seenEnvs, seenEnvCount);
BSE_DeleteOwnedEnv(mpAngleEnvelope, seenEnvs, seenEnvCount);
BSE_DeleteOwnedEnv(mpOffsetEnvelope, seenEnvs, seenEnvCount);
BSE_DeleteOwnedEnv(mpLengthEnvelope, seenEnvs, seenEnvCount);
if (mTrailInfo != NULL && !mTrailInfo->mStatic) {
delete mTrailInfo;
}
if (mElecInfo != NULL && !mElecInfo->mStatic) {
delete mElecInfo;
}
mTrailInfo = &rvParticleTemplate::sTrailInfo;
mElecInfo = &rvParticleTemplate::sElectricityInfo;
mpSpawnPosition = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnDirection = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnVelocity = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnAcceleration = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnFriction = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnRotate = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnAngle = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnOffset = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnLength = &rvParticleTemplate::sSPF_NONE_3;
mpSpawnTint = &rvParticleTemplate::sSPF_ONE_3;
mpSpawnFade = &rvParticleTemplate::sSPF_ONE_1;
mpSpawnSize = &rvParticleTemplate::sSPF_ONE_3;
mpSpawnWindStrength = &rvParticleTemplate::sSPF_NONE_1;
mpTintEnvelope = &rvParticleTemplate::sEmptyEnvelope;
mpFadeEnvelope = &rvParticleTemplate::sEmptyEnvelope;
mpSizeEnvelope = &rvParticleTemplate::sEmptyEnvelope;
mpRotateEnvelope = &rvParticleTemplate::sEmptyEnvelope;
mpAngleEnvelope = &rvParticleTemplate::sEmptyEnvelope;
mpOffsetEnvelope = &rvParticleTemplate::sEmptyEnvelope;
mpLengthEnvelope = &rvParticleTemplate::sEmptyEnvelope;
mpDeathTint = &rvParticleTemplate::sSPF_NONE_3;
mpDeathFade = &rvParticleTemplate::sSPF_NONE_1;
mpDeathSize = &rvParticleTemplate::sSPF_ONE_3;
mpDeathRotate = &rvParticleTemplate::sSPF_NONE_3;
mpDeathAngle = &rvParticleTemplate::sSPF_NONE_3;
mpDeathOffset = &rvParticleTemplate::sSPF_NONE_3;
mpDeathLength = &rvParticleTemplate::sSPF_NONE_3;
mNumImpactEffects = 0;
mNumTimeoutEffects = 0;
mImpactEffects[0] = NULL;
mImpactEffects[1] = NULL;
mImpactEffects[2] = NULL;
mImpactEffects[3] = NULL;
mTimeoutEffects[0] = NULL;
mTimeoutEffects[1] = NULL;
mTimeoutEffects[2] = NULL;
mTimeoutEffects[3] = NULL;
}
float rvParticleTemplate::CostTrail(float cost) const
{
rvTrailInfo* v2; // eax
double result; // st7
float costa; // [esp+4h] [ebp+4h]
float costb; // [esp+4h] [ebp+4h]
v2 = this->mTrailInfo;
switch (v2->mTrailType)
{
case 1:
costa = v2->mTrailCount.y * (cost + cost);
result = costa;
break;
case 2:
costb = v2->mTrailCount.y * (cost * 1.5) + 20.0;
result = costb;
break;
default:
result = cost;
break;
}
return result;
}
bool rvParticleTemplate::UsesEndOrigin(void) {
bool result; // al
if (this->mpSpawnPosition->mFlags & 2 || this->mpSpawnLength->mFlags & 2)
result = 1;
else
result = ((unsigned int)this->mFlags >> 22) & 1;
return result;
}
idTraceModel* rvParticleTemplate::GetTraceModel(void) const {
if (mTraceModelIndex < 0) {
return NULL;
}
return bse->GetTraceModel(mTraceModelIndex);
}
int rvParticleTemplate::GetTrailCount(void) const {
const int count = idMath::FtoiFast(rvRandom::flrand(mTrailInfo->mTrailCount.x, mTrailInfo->mTrailCount.y));
return Max(0, count);
}
bool rvParticleTemplate::Compare(const rvParticleTemplate& a) const {
if (this == &a) {
return true;
}
if (mFlags != a.mFlags ||
mTraceModelIndex != a.mTraceModelIndex ||
mType != a.mType ||
mMaterial != a.mMaterial ||
mModel != a.mModel ||
mEntityDefName != a.mEntityDefName ||
mGravity != a.mGravity ||
mDuration != a.mDuration ||
mCentre != a.mCentre ||
mTiling != a.mTiling ||
mBounce != a.mBounce ||
mPhysicsDistance != a.mPhysicsDistance ||
mWindDeviationAngle != a.mWindDeviationAngle ||
mVertexCount != a.mVertexCount ||
mIndexCount != a.mIndexCount ||
mTrailRepeat != a.mTrailRepeat ||
mNumSizeParms != a.mNumSizeParms ||
mNumRotateParms != a.mNumRotateParms ||
mNumFrames != a.mNumFrames ||
mNumImpactEffects != a.mNumImpactEffects ||
mNumTimeoutEffects != a.mNumTimeoutEffects) {
return false;
}
if (mTrailInfo != a.mTrailInfo) {
if (!mTrailInfo || !a.mTrailInfo) {
return false;
}
if (mTrailInfo->mTrailType != a.mTrailInfo->mTrailType ||
mTrailInfo->mTrailTypeName != a.mTrailInfo->mTrailTypeName ||
mTrailInfo->mTrailMaterial != a.mTrailInfo->mTrailMaterial ||
mTrailInfo->mTrailTime != a.mTrailInfo->mTrailTime ||
mTrailInfo->mTrailCount != a.mTrailInfo->mTrailCount ||
mTrailInfo->mTrailScale != a.mTrailInfo->mTrailScale) {
return false;
}
}
if (mElecInfo != a.mElecInfo) {
if (!mElecInfo || !a.mElecInfo) {
return false;
}
if (mElecInfo->mNumForks != a.mElecInfo->mNumForks ||
mElecInfo->mForkSizeMins != a.mElecInfo->mForkSizeMins ||
mElecInfo->mForkSizeMaxs != a.mElecInfo->mForkSizeMaxs ||
mElecInfo->mJitterSize != a.mElecInfo->mJitterSize ||
mElecInfo->mJitterRate != a.mElecInfo->mJitterRate ||
mElecInfo->mJitterTableName != a.mElecInfo->mJitterTableName) {
return false;
}
}
auto parmEqual = [](const rvParticleParms* lhs, const rvParticleParms* rhs) {
if (lhs == rhs) {
return true;
}
if (!lhs || !rhs) {
return false;
}
return (*lhs) == (*rhs);
};
auto envEqual = [](const rvEnvParms* lhs, const rvEnvParms* rhs) {
if (lhs == rhs) {
return true;
}
if (!lhs || !rhs) {
return false;
}
return lhs->Compare(*rhs);
};
if (!parmEqual(mpSpawnPosition, a.mpSpawnPosition) ||
!parmEqual(mpSpawnDirection, a.mpSpawnDirection) ||
!parmEqual(mpSpawnVelocity, a.mpSpawnVelocity) ||
!parmEqual(mpSpawnAcceleration, a.mpSpawnAcceleration) ||
!parmEqual(mpSpawnFriction, a.mpSpawnFriction) ||
!parmEqual(mpSpawnTint, a.mpSpawnTint) ||
!parmEqual(mpSpawnFade, a.mpSpawnFade) ||
!parmEqual(mpSpawnSize, a.mpSpawnSize) ||
!parmEqual(mpSpawnRotate, a.mpSpawnRotate) ||
!parmEqual(mpSpawnAngle, a.mpSpawnAngle) ||
!parmEqual(mpSpawnOffset, a.mpSpawnOffset) ||
!parmEqual(mpSpawnLength, a.mpSpawnLength) ||
!parmEqual(mpSpawnWindStrength, a.mpSpawnWindStrength) ||
!parmEqual(mpDeathTint, a.mpDeathTint) ||
!parmEqual(mpDeathFade, a.mpDeathFade) ||
!parmEqual(mpDeathSize, a.mpDeathSize) ||
!parmEqual(mpDeathRotate, a.mpDeathRotate) ||
!parmEqual(mpDeathAngle, a.mpDeathAngle) ||
!parmEqual(mpDeathOffset, a.mpDeathOffset) ||
!parmEqual(mpDeathLength, a.mpDeathLength) ||
!envEqual(mpTintEnvelope, a.mpTintEnvelope) ||
!envEqual(mpFadeEnvelope, a.mpFadeEnvelope) ||
!envEqual(mpSizeEnvelope, a.mpSizeEnvelope) ||
!envEqual(mpRotateEnvelope, a.mpRotateEnvelope) ||
!envEqual(mpAngleEnvelope, a.mpAngleEnvelope) ||
!envEqual(mpOffsetEnvelope, a.mpOffsetEnvelope) ||
!envEqual(mpLengthEnvelope, a.mpLengthEnvelope)) {
return false;
}
for (int i = 0; i < BSE_NUM_SPAWNABLE; ++i) {
if (mImpactEffects[i] != a.mImpactEffects[i] ||
mTimeoutEffects[i] != a.mTimeoutEffects[i]) {
return false;
}
}
return true;
}
void rvParticleTemplate::ShutdownStatic(void) {
if (!sInited) {
return;
}
sInited = false;
sTrailInfo.mTrailTypeName = "";
sTrailInfo.mTrailMaterial = NULL;
sTrailInfo.mTrailTime.Zero();
sTrailInfo.mTrailCount.Zero();
sTrailInfo.mTrailScale = 0.0f;
sElectricityInfo.mNumForks = 0;
sElectricityInfo.mForkSizeMins.Zero();
sElectricityInfo.mForkSizeMaxs.Zero();
sElectricityInfo.mJitterSize.Zero();
sElectricityInfo.mJitterRate = 0.0f;
sElectricityInfo.mJitterTableName = "";
sElectricityInfo.mJitterTable = NULL;
sDefaultEnvelope.Init();
sEmptyEnvelope.Init();
sSPF_ONE_1 = rvParticleParms();
sSPF_ONE_2 = rvParticleParms();
sSPF_ONE_3 = rvParticleParms();
sSPF_NONE_0 = rvParticleParms();
sSPF_NONE_1 = rvParticleParms();
sSPF_NONE_3 = rvParticleParms();
}