Allow particle fade-out and fade-in to be defined individually for FSpawnParticleParams and A_SpawnParticleEx. Requires either SPF_FADE_IN_OUT or SPF_FADE_IN_HOLD_OUT flags to be enabled first, and startalpha to be 0 for fading in. The old fadestep parameter serves as the fade-in time, while the new fadeoutstep parameter controls the fade-out time. SPF_FADE_IN_HOLD_OUT ensures the particle will stay solid for the duration of its lifetime before starting to fade out.

This commit is contained in:
nashmuhandes 2025-07-05 03:19:39 +08:00 committed by Ricardo Luís Vaz Silva
commit a8c5355f31
8 changed files with 46 additions and 11 deletions

View file

@ -1689,6 +1689,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticleEx)
PARAM_FLOAT (startroll)
PARAM_FLOAT (rollvel)
PARAM_FLOAT (rollacc)
PARAM_FLOAT (fadeoutstep)
startalpha = clamp(startalpha, 0., 1.);
fadestep = clamp(fadestep, -1.0, 1.0);
@ -1729,7 +1730,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticleEx)
style = STYLE_None;
}
P_SpawnParticle(self->Level, self->Vec3Offset(pos), vel, acc, color, startalpha, lifetime, size, fadestep, sizestep, flags, texid, ERenderStyle(style), startroll, rollvel, rollacc);
P_SpawnParticle(self->Level, self->Vec3Offset(pos), vel, acc, color, startalpha, lifetime, size, fadestep, sizestep, flags, texid, ERenderStyle(style), startroll, rollvel, rollacc, fadeoutstep);
}
return 0;
}

View file

@ -301,6 +301,18 @@ void P_ThinkParticles (FLevelLocals *Level)
}
particle->alpha -= particle->fadestep;
if ( (!!(particle->flags & SPF_FADE_IN_OUT) && particle->alpha >= 1.0)
|| (!!(particle->flags & SPF_FADE_IN_HOLD_OUT) && (particle->ttl * fabs(particle->fadeoutstep)) <= std::min(1.0f, fabs(particle->alpha)))
) { // [Jay] if SPF_FADE_IN_HOLD_OUT, hold until the fade out would line up with ttl
particle->alpha = std::min(1.0f, fabs(particle->alpha));
particle->fadestep = particle->fadeoutstep;
particle->flags &= ~(SPF_FADE_IN_OUT|SPF_FADE_IN_HOLD_OUT);
}
// It looks really glitchy if the alpha is allowed to overshoot
if (particle->alpha > 1.0)
particle->alpha = 1.0;
particle->size += particle->sizestep;
if (particle->alpha <= 0 || --particle->ttl <= 0 || (particle->size <= 0))
{ // The particle has expired, so free it
@ -345,7 +357,7 @@ void P_ThinkParticles (FLevelLocals *Level)
}
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)
double fadestep, double sizestep, int flags, FTextureID texture, ERenderStyle style, double startroll, double rollvel, double rollacc, double fadeoutstep)
{
particle_t *particle = NewParticle(Level, !!(flags & SPF_REPLACE));
@ -356,8 +368,21 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v
particle->Acc = FVector3(accel);
particle->color = ParticleColor(color);
particle->alpha = float(startalpha);
if ((fadestep < 0 && !(flags & SPF_NEGATIVE_FADESTEP)) || fadestep <= -1.0) particle->fadestep = FADEFROMTTL(lifetime);
else particle->fadestep = float(fadestep);
if ((flags & SPF_FADE_IN_OUT) || (flags & SPF_FADE_IN_HOLD_OUT))
particle->fadeoutstep = fadeoutstep;
if ((fadestep < 0 && !(flags & SPF_NEGATIVE_FADESTEP)) || fadestep <= -1.0)
{
particle->fadestep = FADEFROMTTL(lifetime);
if (flags & SPF_FADE_IN_OUT)
particle->fadestep *= (float)-2;
else if (flags & SPF_FADE_IN_HOLD_OUT)
particle->fadestep *= (float)-3;
particle->fadeoutstep = -particle->fadestep;
}
else
{
particle->fadestep = float(fadestep);
}
particle->ttl = lifetime;
particle->size = size;
particle->sizestep = sizestep;

View file

@ -79,6 +79,8 @@ enum EParticleFlags
SPF_ROLLCENTER = 1 << 13,
SPF_STRETCHPIXELS = 1 << 14,
SPF_ALLOWSHADERS = 1 << 15,
SPF_FADE_IN_OUT = 1 << 16,
SPF_FADE_IN_HOLD_OUT = 1 << 17,
};
class DVisualThinker;
@ -96,12 +98,14 @@ struct particle_t
ERenderStyle style; //+4 = 88
float Roll, RollVel, RollAcc; //+12 = 100
uint16_t tnext, snext, tprev; //+6 = 106
uint16_t flags; //+2 = 108
// uint32_t padding; //+4 = 112
// uint16_t padding; //+2 = 108
uint32_t flags; //+4 = 112
FStandaloneAnimation animData; //+16 = 128
float fadeoutstep; //+4 = 132
// float padding2; //+4 = 136
};
static_assert(sizeof(particle_t) == 128, "Only LP64/LLP64 is supported");
static_assert(sizeof(particle_t) == 136, "Only LP64/LLP64 is supported");
const uint16_t NO_PARTICLE = 0xffff;
@ -134,13 +138,14 @@ struct FSpawnParticleParams
double startalpha;
double fadestep;
double fadeoutstep;
double startroll;
double rollvel;
double rollacc;
};
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 = 0, FTextureID texture = FNullTextureID(), ERenderStyle style = STYLE_None, double startroll = 0, double rollvel = 0, double rollacc = 0);
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 = 0, FTextureID texture = FNullTextureID(), ERenderStyle style = STYLE_None, double startroll = 0, double rollvel = 0, double rollacc = 0, double fadeoutstep = 0);
void P_InitEffects (void);

View file

@ -2205,6 +2205,7 @@ DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, vel);
DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, accel);
DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, startalpha);
DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, fadestep);
DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, fadeoutstep);
DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, startroll);
DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, rollvel);
DEFINE_FIELD_X(FSpawnParticleParams, FSpawnParticleParams, rollacc);
@ -2215,7 +2216,7 @@ static void SpawnParticle(FLevelLocals *Level, FSpawnParticleParams *params)
params->color, params->startalpha, params->lifetime,
params->size, params->fadestep, params->sizestep,
params->flags, params->texture, ERenderStyle(params->style),
params->startroll, params->rollvel, params->rollacc);
params->startroll, params->rollvel, params->rollacc, params->fadeoutstep);
}
DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnParticle, SpawnParticle)

View file

@ -1285,7 +1285,7 @@ class Actor : Thinker native
native void A_FadeTo(double target, double amount = 0.1, int flags = 0);
native void A_SpawnDebris(class<Actor> spawntype, bool transfer_translation = false, double mult_h = 1, double mult_v = 1);
native void A_SpawnParticle(color color1, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0);
native void A_SpawnParticleEx(color color1, TextureID texture, int style = STYLE_None, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0, double startroll = 0, double rollvel = 0, double rollacc = 0);
native void A_SpawnParticleEx(color color1, TextureID texture, int style = STYLE_None, int flags = 0, int lifetime = TICRATE, double size = 1, double angle = 0, double xoff = 0, double yoff = 0, double zoff = 0, double velx = 0, double vely = 0, double velz = 0, double accelx = 0, double accely = 0, double accelz = 0, double startalphaf = 1, double fadestepf = -1, double sizestep = 0, double startroll = 0, double rollvel = 0, double rollacc = 0, double fadeoutstepf = 0);
native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false);
native void A_DropInventory(class<Inventory> itemtype, int amount = -1);
native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0, double alpha2 = 0.);

View file

@ -726,6 +726,8 @@ enum EParticleFlags
SPF_ROLLCENTER = 1 << 13,
SPF_STRETCHPIXELS = 1 << 14,
SPF_ALLOWSHADERS = 1 << 15,
SPF_FADE_IN_OUT = 1 << 16,
SPF_FADE_IN_HOLD_OUT = 1 << 17,
SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG
};

View file

@ -473,6 +473,7 @@ struct FSpawnParticleParams
native double startalpha;
native double fadestep;
native double fadeoutstep; // unlike fadestep, this is always expected to be a positive value.
native double startroll;
native double rollvel;

View file

@ -12,7 +12,7 @@ Class VisualThinker : Thinker native
native TranslationID Translation;
native int16 LightLevel;
native uint16 Flags;
native uint Flags;
native int VisualThinkerFlags;
FlagDef FlipOffsetX : VisualThinkerFlags, 0;