Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement animated particles that aren't tied to the global animation timer #2354

Merged
merged 4 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/common/textures/textureid.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#define TEXTUREID_H

#include <cstddef>

Expand Down Expand Up @@ -66,3 +67,13 @@ class FSetTextureID : public FTextureID
constexpr FSetTextureID(int v) : FTextureID(v) {}
};

#ifdef TARRAY_H
template<> struct THashTraits<FTextureID>
{

hash_t Hash(const FTextureID key) { return (hash_t)key.GetIndex(); }

// Compares two keys, returning zero if they are the same.
int Compare(const FTextureID left, const FTextureID right) { return left != right; }
};
#endif
12 changes: 12 additions & 0 deletions src/common/utility/tarray.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#define TARRAY_H
/*
** tarray.h
** Templated, automatically resizing array
Expand Down Expand Up @@ -943,6 +944,17 @@ template<class KT> struct THashTraits
int Compare(const KT left, const KT right) { return left != right; }
};

#ifdef TEXTUREID_H
template<> struct THashTraits<FTextureID>
{

hash_t Hash(const FTextureID key) { return (hash_t)key.GetIndex(); }

// Compares two keys, returning zero if they are the same.
int Compare(const FTextureID left, const FTextureID right) { return left != right; }
};
#endif

template<> struct THashTraits<float>
{
// Use all bits when hashing singles instead of converting them to ints.
Expand Down
166 changes: 111 additions & 55 deletions src/gamedata/textures/animations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,19 @@ void FTextureAnimator::DeleteAll()
FAnimDef *FTextureAnimator::AddAnim (FAnimDef& anim)
{
// Search for existing duplicate.
for (unsigned int i = 0; i < mAnimations.Size(); ++i)
{
if (mAnimations[i].BasePic == anim.BasePic)
{
// Found one!
mAnimations[i] = anim;
return &mAnimations[i];
}
uint16_t * index = mAnimationIndices.CheckKey(anim.BasePic);

if(index)
{ // Found one!
mAnimations[*index] = anim;
return &mAnimations[*index];
}
else
{ // Didn't find one, so add it at the end.
mAnimationIndices.Insert(anim.BasePic, mAnimations.Size());
mAnimations.Push (anim);
return &mAnimations.Last();
}
// Didn't find one, so add it at the end.
mAnimations.Push (anim);
return &mAnimations.Last();
}

//==========================================================================
Expand Down Expand Up @@ -930,6 +931,104 @@ 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)
{
animInfo.ok = false;
uint16_t * index = mAnimationIndices.CheckKey(tex);
if(!index) return false;
FAnimDef * anim = &mAnimations[*index];

animInfo.ok = true;
animInfo.AnimIndex = *index;
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);
}


//==========================================================================
//
Expand All @@ -955,50 +1054,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);
}

Expand Down
15 changes: 15 additions & 0 deletions src/gamedata/textures/animations.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -62,6 +73,7 @@ struct FDoorAnimation

class FTextureAnimator
{
TMap<FTextureID, uint16_t> mAnimationIndices;
TArray<FAnimDef> mAnimations;
TArray<FSwitchDef*> mSwitchDefs;
TArray<FDoorAnimation> mAnimatedDoors;
Expand Down Expand Up @@ -112,6 +124,9 @@ class FTextureAnimator
FixAnimations();
InitSwitchList();
}

bool InitStandaloneAnimation(FStandaloneAnimation &animInfo, FTextureID tex, uint32_t curTic);
FTextureID UpdateStandaloneAnimation(FStandaloneAnimation &animInfo, double curTic);
};

extern FTextureAnimator TexAnim;
Expand Down