Added PS_REPLACE flag for A_SpawnParticle(Ex).

- When used, new particles that spawn when the limit is reached will replace the oldest particle.
This commit is contained in:
Major Cooke 2022-11-10 18:59:30 -06:00 committed by Christoph Oelckers
parent 31db5847cc
commit 2a9e28d949
4 changed files with 80 additions and 33 deletions

View File

@ -654,6 +654,7 @@ public:
DSeqNode *SequenceListHead;
// [RH] particle globals
uint32_t OldestParticle; // [MC] Oldest particle for replacing with PS_REPLACE
uint32_t ActiveParticles;
uint32_t InactiveParticles;
TArray<particle_t> Particles;

View File

@ -99,15 +99,57 @@ static const struct ColorList {
{NULL, 0, 0, 0 }
};
inline particle_t *NewParticle (FLevelLocals *Level)
inline particle_t *NewParticle (FLevelLocals *Level, bool replace = false)
{
particle_t *result = nullptr;
if (Level->InactiveParticles != NO_PARTICLE)
// [MC] Thanks to RaveYard and randi for helping me with this addition.
// Array's filled up
if (Level->InactiveParticles == NO_PARTICLE)
{
result = &Level->Particles[Level->InactiveParticles];
Level->InactiveParticles = result->tnext;
result->tnext = Level->ActiveParticles;
Level->ActiveParticles = uint32_t(result - Level->Particles.Data());
if (replace)
{
result = &Level->Particles[Level->OldestParticle];
// There should be NO_PARTICLE for the oldest's tnext
if (result->tprev != NO_PARTICLE)
{
// tnext: youngest to oldest
// tprev: oldest to youngest
// 2nd oldest -> oldest
particle_t *nbottom = &Level->Particles[result->tprev];
nbottom->tnext = NO_PARTICLE;
// now oldest becomes youngest
Level->OldestParticle = result->tprev;
result->tnext = Level->ActiveParticles;
result->tprev = NO_PARTICLE;
Level->ActiveParticles = uint32_t(result - Level->Particles.Data());
// youngest -> 2nd youngest
particle_t* ntop = &Level->Particles[result->tnext];
ntop->tprev = Level->ActiveParticles;
}
}
return result;
}
// Array isn't full.
uint32_t current = Level->ActiveParticles;
result = &Level->Particles[Level->InactiveParticles];
Level->InactiveParticles = result->tnext;
result->tnext = current;
result->tprev = NO_PARTICLE;
Level->ActiveParticles = uint32_t(result - Level->Particles.Data());
if (current != NO_PARTICLE) // More than one active particles
{
particle_t* next = &Level->Particles[current];
next->tprev = Level->ActiveParticles;
}
else // Just one active particle
{
Level->OldestParticle = Level->ActiveParticles;
}
return result;
}
@ -139,11 +181,16 @@ void P_ClearParticles (FLevelLocals *Level)
{
int i = 0;
memset (Level->Particles.Data(), 0, Level->Particles.Size() * sizeof(particle_t));
Level->OldestParticle = NO_PARTICLE;
Level->ActiveParticles = NO_PARTICLE;
Level->InactiveParticles = 0;
for (auto &p : Level->Particles)
{
p.tprev = i - 1;
p.tnext = ++i;
}
Level->Particles.Last().tnext = NO_PARTICLE;
Level->Particles.Data()->tprev = NO_PARTICLE;
}
// Group particles by subsectors. Because particles are always
@ -212,16 +259,13 @@ void P_InitEffects ()
void P_ThinkParticles (FLevelLocals *Level)
{
int i;
particle_t *particle, *prev;
i = Level->ActiveParticles;
prev = NULL;
int i = Level->ActiveParticles;
particle_t *particle = nullptr, *prev = nullptr;
while (i != NO_PARTICLE)
{
particle = &Level->Particles[i];
i = particle->tnext;
if (!particle->notimefreeze && Level->isFrozen())
if (Level->isFrozen() && !particle->notimefreeze)
{
prev = particle;
continue;
@ -237,6 +281,12 @@ void P_ThinkParticles (FLevelLocals *Level)
prev->tnext = i;
else
Level->ActiveParticles = i;
if (i != NO_PARTICLE)
{
particle_t *next = &Level->Particles[i];
next->tprev = particle->tprev;
}
particle->tnext = Level->InactiveParticles;
Level->InactiveParticles = (int)(particle - Level->Particles.Data());
continue;
@ -283,12 +333,13 @@ enum PSFlag
PS_FULLBRIGHT = 1,
PS_NOTIMEFREEZE = 1 << 5,
PS_ROLL = 1 << 6,
PS_REPLACE = 1 << 7,
};
void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size,
double fadestep, double sizestep, int flags, FTextureID texture, ERenderStyle style, double startroll, double rollvel, double rollacc)
{
particle_t *particle = NewParticle(Level);
particle_t *particle = NewParticle(Level, !!(flags & PS_REPLACE));
if (particle)
{

View File

@ -52,26 +52,20 @@ struct FLevelLocals;
struct particle_t
{
DVector3 Pos;
DVector3 Vel;
DVector3 Acc;
double size;
double sizestep;
subsector_t * subsector;
int32_t ttl;
uint8_t bright;
bool notimefreeze;
float fadestep;
float alpha;
int color;
uint16_t tnext;
uint16_t snext;
FTextureID texture;
ERenderStyle style;
double Roll;
double RollVel;
double RollAcc;
bool doRoll;
DVector3 Pos;
DVector3 Vel;
DVector3 Acc;
double size, sizestep;
float fadestep, alpha;
subsector_t* subsector;
int32_t ttl;
int color;
FTextureID texture;
ERenderStyle style;
double Roll, RollVel, RollAcc;
uint16_t tnext, snext, tprev;
uint8_t bright;
bool notimefreeze, doRoll;
};
const uint16_t NO_PARTICLE = 0xffff;

View File

@ -690,6 +690,7 @@ enum EParticleFlags
SPF_RELANG = 1 << 4,
SPF_NOTIMEFREEZE = 1 << 5,
SPF_ROLL = 1 << 6,
SPF_REPLACE = 1 << 7,
SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG
};