mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-25 13:31:37 +00:00
Implement animated particles that aren't tied to the global animation timer
This commit is contained in:
parent
9dd6460fe6
commit
7eab519795
8 changed files with 228 additions and 116 deletions
|
@ -930,6 +930,109 @@ void FAnimDef::SetSwitchTime (uint64_t mstime)
|
|||
}
|
||||
}
|
||||
|
||||
static void AdvanceFrame(uint16_t &frame, uint8_t &AnimType, const FAnimDef &anim)
|
||||
{
|
||||
switch (AnimType)
|
||||
{
|
||||
default:
|
||||
case FAnimDef::ANIM_Forward:
|
||||
frame = (frame + 1) % anim.NumFrames;
|
||||
break;
|
||||
|
||||
case FAnimDef::ANIM_Backward:
|
||||
if (frame == 0)
|
||||
{
|
||||
frame = anim.NumFrames - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame--;
|
||||
}
|
||||
break;
|
||||
case FAnimDef::ANIM_Random:
|
||||
// select a random frame other than the current one
|
||||
if (anim.NumFrames > 1)
|
||||
{
|
||||
uint16_t rndFrame = (uint16_t)pr_animatepictures(anim.NumFrames - 1);
|
||||
if(rndFrame == frame) rndFrame++;
|
||||
frame = rndFrame % anim.NumFrames;
|
||||
}
|
||||
break;
|
||||
|
||||
case FAnimDef::ANIM_OscillateUp:
|
||||
frame = frame + 1;
|
||||
assert(frame < anim.NumFrames);
|
||||
if (frame == anim.NumFrames - 1)
|
||||
{
|
||||
AnimType = FAnimDef::ANIM_OscillateDown;
|
||||
}
|
||||
break;
|
||||
|
||||
case FAnimDef::ANIM_OscillateDown:
|
||||
frame = frame - 1;
|
||||
if (frame == 0)
|
||||
{
|
||||
AnimType = FAnimDef::ANIM_OscillateUp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr double msPerTic = 1'000.0 / TICRATE;
|
||||
|
||||
bool FTextureAnimator::InitStandaloneAnimation(FStandaloneAnimation &animInfo, FTextureID tex, uint32_t curTic)
|
||||
{
|
||||
FAnimDef * anim;
|
||||
animInfo.ok = false;
|
||||
for(int i = 0; i < mAnimations.Size(); i++)
|
||||
{
|
||||
if(mAnimations[i].BasePic == tex)
|
||||
{
|
||||
animInfo.ok = true;
|
||||
animInfo.AnimIndex = i;
|
||||
anim = &mAnimations[i];
|
||||
}
|
||||
}
|
||||
if(!animInfo.ok) return false;
|
||||
animInfo.CurFrame = 0;
|
||||
animInfo.SwitchTic = curTic;
|
||||
animInfo.AnimType = (anim->AnimType == FAnimDef::ANIM_OscillateDown) ? FAnimDef::ANIM_OscillateUp : anim->AnimType;
|
||||
uint32_t time = anim->Frames[0].SpeedMin;
|
||||
if(anim->Frames[0].SpeedRange != 0)
|
||||
{
|
||||
time += pr_animatepictures(anim->Frames[0].SpeedRange);
|
||||
}
|
||||
animInfo.SwitchTic += time / msPerTic;
|
||||
return true;
|
||||
}
|
||||
|
||||
FTextureID FTextureAnimator::UpdateStandaloneAnimation(FStandaloneAnimation &animInfo, double curTic)
|
||||
{
|
||||
if(!animInfo.ok) return nullptr;
|
||||
auto &anim = mAnimations[animInfo.AnimIndex];
|
||||
if(animInfo.SwitchTic <= curTic)
|
||||
{
|
||||
uint16_t frame = animInfo.CurFrame;
|
||||
uint16_t speedframe = anim.bDiscrete ? frame : 0;
|
||||
while(animInfo.SwitchTic <= curTic)
|
||||
{
|
||||
AdvanceFrame(frame, animInfo.AnimType, anim);
|
||||
|
||||
if(anim.bDiscrete) speedframe = frame;
|
||||
|
||||
uint32_t time = anim.Frames[speedframe].SpeedMin;
|
||||
if(anim.Frames[speedframe].SpeedRange != 0)
|
||||
{
|
||||
time += pr_animatepictures(anim.Frames[speedframe].SpeedRange);
|
||||
}
|
||||
|
||||
animInfo.SwitchTic += time / msPerTic;
|
||||
}
|
||||
animInfo.CurFrame = frame;
|
||||
}
|
||||
return anim.bDiscrete ? anim.Frames[animInfo.CurFrame].FramePic : (anim.BasePic + animInfo.CurFrame);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -955,50 +1058,7 @@ void FTextureAnimator::UpdateAnimations (uint64_t mstime)
|
|||
{ // Multiple frames may have passed since the last time calling
|
||||
// R_UpdateAnimations, so be sure to loop through them all.
|
||||
|
||||
switch (anim->AnimType)
|
||||
{
|
||||
default:
|
||||
case FAnimDef::ANIM_Forward:
|
||||
anim->CurFrame = (anim->CurFrame + 1) % anim->NumFrames;
|
||||
break;
|
||||
|
||||
case FAnimDef::ANIM_Backward:
|
||||
if (anim->CurFrame == 0)
|
||||
{
|
||||
anim->CurFrame = anim->NumFrames - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
anim->CurFrame -= 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case FAnimDef::ANIM_Random:
|
||||
// select a random frame other than the current one
|
||||
if (anim->NumFrames > 1)
|
||||
{
|
||||
uint16_t rndFrame = (uint16_t)pr_animatepictures(anim->NumFrames - 1);
|
||||
if (rndFrame >= anim->CurFrame) rndFrame++;
|
||||
anim->CurFrame = rndFrame;
|
||||
}
|
||||
break;
|
||||
|
||||
case FAnimDef::ANIM_OscillateUp:
|
||||
anim->CurFrame = anim->CurFrame + 1;
|
||||
if (anim->CurFrame >= anim->NumFrames - 1)
|
||||
{
|
||||
anim->AnimType = FAnimDef::ANIM_OscillateDown;
|
||||
}
|
||||
break;
|
||||
|
||||
case FAnimDef::ANIM_OscillateDown:
|
||||
anim->CurFrame = anim->CurFrame - 1;
|
||||
if (anim->CurFrame == 0)
|
||||
{
|
||||
anim->AnimType = FAnimDef::ANIM_OscillateUp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
AdvanceFrame(anim->CurFrame, anim->AnimType, *anim);
|
||||
anim->SetSwitchTime (mstime);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,17 @@
|
|||
#include "tarray.h"
|
||||
#include "s_soundinternal.h"
|
||||
|
||||
struct FStandaloneAnimation
|
||||
{
|
||||
double SwitchTic;
|
||||
uint32_t AnimIndex;
|
||||
uint16_t CurFrame;
|
||||
bool ok = false;
|
||||
uint8_t AnimType;
|
||||
};
|
||||
|
||||
static_assert(sizeof(FStandaloneAnimation) == sizeof(uint64_t)*2);
|
||||
|
||||
struct FAnimDef
|
||||
{
|
||||
struct FAnimFrame
|
||||
|
@ -112,6 +123,9 @@ public:
|
|||
FixAnimations();
|
||||
InitSwitchList();
|
||||
}
|
||||
|
||||
bool InitStandaloneAnimation(FStandaloneAnimation &animInfo, FTextureID tex, uint32_t curTic);
|
||||
FTextureID UpdateStandaloneAnimation(FStandaloneAnimation &animInfo, double curTic);
|
||||
};
|
||||
|
||||
extern FTextureAnimator TexAnim;
|
||||
|
|
|
@ -297,6 +297,11 @@ void P_ThinkParticles (FLevelLocals *Level)
|
|||
i = particle->tnext;
|
||||
if (Level->isFrozen() && !(particle->flags &SPF_NOTIMEFREEZE))
|
||||
{
|
||||
if(particle->flags & SPF_STANDALONE_ANIMATIONS)
|
||||
{
|
||||
particle->animData.SwitchTic++;
|
||||
}
|
||||
|
||||
prev = particle;
|
||||
continue;
|
||||
}
|
||||
|
@ -366,14 +371,13 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v
|
|||
if (particle)
|
||||
{
|
||||
particle->Pos = pos;
|
||||
particle->Vel = vel;
|
||||
particle->Acc = accel;
|
||||
particle->Vel = FVector3(vel);
|
||||
particle->Acc = FVector3(accel);
|
||||
particle->color = ParticleColor(color);
|
||||
particle->alpha = float(startalpha);
|
||||
if (fadestep < 0) particle->fadestep = FADEFROMTTL(lifetime);
|
||||
else particle->fadestep = float(fadestep);
|
||||
particle->ttl = lifetime;
|
||||
particle->bright = !!(flags & SPF_FULLBRIGHT);
|
||||
particle->size = size;
|
||||
particle->sizestep = sizestep;
|
||||
particle->texture = texture;
|
||||
|
@ -382,6 +386,10 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v
|
|||
particle->RollVel = rollvel;
|
||||
particle->RollAcc = rollacc;
|
||||
particle->flags = flags;
|
||||
if(flags & SPF_STANDALONE_ANIMATIONS)
|
||||
{
|
||||
TexAnim.InitStandaloneAnimation(particle->animData, texture, Level->maptime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,10 +440,10 @@ static void MakeFountain (AActor *actor, int color1, int color2)
|
|||
|
||||
particle->Pos = actor->Vec3Angle(out, an, actor->Height + 1);
|
||||
if (out < actor->radius/8)
|
||||
particle->Vel.Z += 10./3;
|
||||
particle->Vel.Z += 10.f/3;
|
||||
else
|
||||
particle->Vel.Z += 3;
|
||||
particle->Acc.Z -= 1./11;
|
||||
particle->Acc.Z -= 1.f/11;
|
||||
if (M_Random() < 30) {
|
||||
particle->size = 4;
|
||||
particle->color = color2;
|
||||
|
@ -474,8 +482,8 @@ void P_RunEffect (AActor *actor, int effects)
|
|||
speed = (M_Random () - 128) * (1./200);
|
||||
particle->Vel.X += speed * an.Cos();
|
||||
particle->Vel.Y += speed * an.Sin();
|
||||
particle->Vel.Z -= 1./36;
|
||||
particle->Acc.Z -= 1./20;
|
||||
particle->Vel.Z -= 1.f/36;
|
||||
particle->Acc.Z -= 1.f/20;
|
||||
particle->color = yellow;
|
||||
particle->size = 2;
|
||||
}
|
||||
|
@ -492,8 +500,8 @@ void P_RunEffect (AActor *actor, int effects)
|
|||
speed = (M_Random () - 128) * (1./200);
|
||||
particle->Vel.X += speed * an.Cos();
|
||||
particle->Vel.Y += speed * an.Sin();
|
||||
particle->Vel.Z += 1. / 80;
|
||||
particle->Acc.Z += 1. / 40;
|
||||
particle->Vel.Z += 1.f / 80;
|
||||
particle->Acc.Z += 1.f / 40;
|
||||
if (M_Random () & 7)
|
||||
particle->color = grey2;
|
||||
else
|
||||
|
@ -635,7 +643,7 @@ void P_DrawSplash2 (FLevelLocals *Level, int count, const DVector3 &pos, DAngle
|
|||
p->size = 4;
|
||||
p->color = M_Random() & 0x80 ? color1 : color2;
|
||||
p->Vel.Z = M_Random() * zvel;
|
||||
p->Acc.Z = -1 / 22.;
|
||||
p->Acc.Z = -1 / 22.f;
|
||||
if (kind)
|
||||
{
|
||||
an = angle + DAngle::fromDeg((M_Random() - 128) * (180 / 256.));
|
||||
|
@ -788,10 +796,13 @@ void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1,
|
|||
p->ttl = spiralduration;
|
||||
p->fadestep = FADEFROMTTL(spiralduration);
|
||||
p->size = 3;
|
||||
p->bright = fullbright;
|
||||
if(fullbright)
|
||||
{
|
||||
p->flags |= SPF_FULLBRIGHT;
|
||||
}
|
||||
|
||||
tempvec = DMatrix3x3(trail[segment].dir, deg) * trail[segment].extend;
|
||||
p->Vel = tempvec * drift / 16.;
|
||||
p->Vel = FVector3(tempvec * drift / 16.);
|
||||
p->Pos = tempvec + pos;
|
||||
pos += trail[segment].dir * stepsize;
|
||||
deg += DAngle::fromDeg(r_rail_spiralsparsity * 14);
|
||||
|
@ -871,7 +882,10 @@ void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1,
|
|||
p->Acc.Z -= 1./4096;
|
||||
pos += trail[segment].dir * stepsize;
|
||||
lencount -= stepsize;
|
||||
p->bright = fullbright;
|
||||
if(fullbright)
|
||||
{
|
||||
p->flags |= SPF_FULLBRIGHT;
|
||||
}
|
||||
|
||||
if (color2 == -1)
|
||||
{
|
||||
|
@ -995,7 +1009,8 @@ void P_DisconnectEffect (AActor *actor)
|
|||
void DVisualThinker::Construct()
|
||||
{
|
||||
PT = {};
|
||||
PT.Pos = PT.Vel = { 0,0,0 };
|
||||
PT.Pos = { 0,0,0 };
|
||||
PT.Vel = { 0,0,0 };
|
||||
Offset = { 0,0 };
|
||||
Scale = { 1,1 };
|
||||
PT.Roll = 0.0;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "renderstyle.h"
|
||||
#include "dthinker.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "animations.h"
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -54,35 +55,40 @@ struct FLevelLocals;
|
|||
|
||||
enum EParticleFlags
|
||||
{
|
||||
SPF_FULLBRIGHT = 1,
|
||||
SPF_RELPOS = 1 << 1,
|
||||
SPF_RELVEL = 1 << 2,
|
||||
SPF_RELACCEL = 1 << 3,
|
||||
SPF_RELANG = 1 << 4,
|
||||
SPF_NOTIMEFREEZE = 1 << 5,
|
||||
SPF_ROLL = 1 << 6,
|
||||
SPF_REPLACE = 1 << 7,
|
||||
SPF_NO_XY_BILLBOARD = 1 << 8,
|
||||
SPF_FULLBRIGHT = 1 << 0,
|
||||
SPF_RELPOS = 1 << 1,
|
||||
SPF_RELVEL = 1 << 2,
|
||||
SPF_RELACCEL = 1 << 3,
|
||||
SPF_RELANG = 1 << 4,
|
||||
SPF_NOTIMEFREEZE = 1 << 5,
|
||||
SPF_ROLL = 1 << 6,
|
||||
SPF_REPLACE = 1 << 7,
|
||||
SPF_NO_XY_BILLBOARD = 1 << 8,
|
||||
SPF_STANDALONE_ANIMATIONS = 1 << 9,
|
||||
};
|
||||
|
||||
class DVisualThinker;
|
||||
struct particle_t
|
||||
{
|
||||
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;
|
||||
bool bright;
|
||||
uint16_t flags;
|
||||
subsector_t* subsector; //+8 = 8
|
||||
DVector3 Pos; //+24 = 32
|
||||
FVector3 Vel; //+12 = 44
|
||||
FVector3 Acc; //+12 = 56
|
||||
float size, sizestep; //+8 = 64
|
||||
float fadestep, alpha; //+8 = 72
|
||||
int32_t ttl; // +4 = 76
|
||||
int color; //+4 = 80
|
||||
FTextureID texture; // +4 = 84
|
||||
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
|
||||
FStandaloneAnimation animData; //+16 = 128
|
||||
};
|
||||
|
||||
static_assert(sizeof(particle_t) == 128);
|
||||
|
||||
const uint16_t NO_PARTICLE = 0xffff;
|
||||
|
||||
void P_InitParticles(FLevelLocals *);
|
||||
|
@ -154,7 +160,7 @@ public:
|
|||
DVector3 Prev;
|
||||
DVector2 Scale,
|
||||
Offset;
|
||||
double PrevRoll;
|
||||
float PrevRoll;
|
||||
int16_t LightLevel;
|
||||
FTranslationID Translation;
|
||||
sector_t *cursector;
|
||||
|
|
|
@ -1283,13 +1283,13 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *s
|
|||
index = 0;
|
||||
actor = nullptr;
|
||||
this->particle = particle;
|
||||
fullbright = particle->bright;
|
||||
fullbright = particle->flags & SPF_FULLBRIGHT;
|
||||
|
||||
if (di->isFullbrightScene())
|
||||
{
|
||||
Colormap.Clear();
|
||||
}
|
||||
else if (!particle->bright)
|
||||
else if (!(particle->flags & SPF_FULLBRIGHT))
|
||||
{
|
||||
TArray<lightlist_t> & lightlist=sector->e->XFloor.lightlist;
|
||||
double lightbottom;
|
||||
|
@ -1332,12 +1332,19 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *s
|
|||
ThingColor.a = 255;
|
||||
const auto& vp = di->Viewpoint;
|
||||
|
||||
double timefrac = vp.TicFrac;
|
||||
if (paused || (di->Level->isFrozen() && !(particle->flags & SPF_NOTIMEFREEZE)))
|
||||
timefrac = 0.;
|
||||
|
||||
if (spr)
|
||||
{
|
||||
AdjustVisualThinker(di, spr, sector);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool has_texture = !particle->texture.isNull();
|
||||
|
||||
bool has_texture = particle->texture.isValid();
|
||||
bool custom_animated_texture = has_texture && (particle->flags & SPF_STANDALONE_ANIMATIONS) && particle->animData.ok;
|
||||
|
||||
int particle_style = has_texture ? 2 : gl_particles_style; // Treat custom texture the same as smooth particles
|
||||
|
||||
// [BB] Load the texture for round or smooth particles
|
||||
|
@ -1350,27 +1357,36 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *s
|
|||
}
|
||||
else if (particle_style == 2)
|
||||
{
|
||||
lump = has_texture ? particle->texture : TexMan.glPart;
|
||||
if(custom_animated_texture)
|
||||
{
|
||||
lump = TexAnim.UpdateStandaloneAnimation(particle->animData, di->Level->maptime + timefrac);
|
||||
}
|
||||
else if(has_texture)
|
||||
{
|
||||
lump = particle->texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
lump = TexMan.glPart;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lump.SetNull();
|
||||
}
|
||||
else lump.SetNull();
|
||||
|
||||
if (lump.isValid())
|
||||
{
|
||||
translation = NO_TRANSLATION;
|
||||
//auto tex = TexMan.GetGameTexture(lump, false);
|
||||
if (lump.isValid())
|
||||
{
|
||||
translation = NO_TRANSLATION;
|
||||
|
||||
ul = 0;
|
||||
ur = 1;
|
||||
vt = 0;
|
||||
vb = 1;
|
||||
texture = TexMan.GetGameTexture(lump, true);
|
||||
ul = vt = 0;
|
||||
ur = vb = 1;
|
||||
|
||||
texture = TexMan.GetGameTexture(lump, !custom_animated_texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double timefrac = vp.TicFrac;
|
||||
if (paused || di->Level->isFrozen())
|
||||
timefrac = 0.;
|
||||
|
||||
float xvf = (particle->Vel.X) * timefrac;
|
||||
float yvf = (particle->Vel.Y) * timefrac;
|
||||
float zvf = (particle->Vel.Z) * timefrac;
|
||||
|
|
|
@ -223,7 +223,7 @@ namespace swrenderer
|
|||
vis->floorclip = 0;
|
||||
vis->foggy = foggy;
|
||||
|
||||
vis->Light.SetColormap(thread, tz, lightlevel, foggy, map, particle->bright != 0, false, false, false, true);
|
||||
vis->Light.SetColormap(thread, tz, lightlevel, foggy, map, particle->flags & SPF_FULLBRIGHT, false, false, false, true);
|
||||
|
||||
thread->SpriteList->Push(vis);
|
||||
}
|
||||
|
|
|
@ -701,17 +701,18 @@ enum ECheckBlockFlags
|
|||
|
||||
enum EParticleFlags
|
||||
{
|
||||
SPF_FULLBRIGHT = 1,
|
||||
SPF_RELPOS = 1 << 1,
|
||||
SPF_RELVEL = 1 << 2,
|
||||
SPF_RELACCEL = 1 << 3,
|
||||
SPF_RELANG = 1 << 4,
|
||||
SPF_NOTIMEFREEZE = 1 << 5,
|
||||
SPF_ROLL = 1 << 6,
|
||||
SPF_REPLACE = 1 << 7,
|
||||
SPF_NO_XY_BILLBOARD = 1 << 8,
|
||||
SPF_FULLBRIGHT = 1 << 0,
|
||||
SPF_RELPOS = 1 << 1,
|
||||
SPF_RELVEL = 1 << 2,
|
||||
SPF_RELACCEL = 1 << 3,
|
||||
SPF_RELANG = 1 << 4,
|
||||
SPF_NOTIMEFREEZE = 1 << 5,
|
||||
SPF_ROLL = 1 << 6,
|
||||
SPF_REPLACE = 1 << 7,
|
||||
SPF_NO_XY_BILLBOARD = 1 << 8,
|
||||
SPF_STANDALONE_ANIMATIONS = 1 << 9,
|
||||
|
||||
SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG
|
||||
SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG
|
||||
};
|
||||
|
||||
//Flags for A_FaceMovementDirection
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
Class VisualThinker : Thinker native
|
||||
{
|
||||
native Vector3 Pos,
|
||||
Vel,
|
||||
Prev;
|
||||
native FVector3 Vel;
|
||||
native Vector2 Scale,
|
||||
Offset;
|
||||
native double Roll,
|
||||
PrevRoll;
|
||||
native float Alpha;
|
||||
native float Roll,
|
||||
PrevRoll,
|
||||
Alpha;
|
||||
native TextureID Texture;
|
||||
native TranslationID Translation;
|
||||
native uint16 Flags;
|
||||
|
|
Loading…
Reference in a new issue