mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
2303 lines
64 KiB
C++
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 == ©) {
|
|
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();
|
|
}
|