Skip to content

Commit

Permalink
Updated VisualThinker render linkage
Browse files Browse the repository at this point in the history
Now uses its own self-managed linked list with its level tracking the head pointer. Allows for VisualThinkers to be moved to any desired stat instead of being stuck in STAT_VISUALTHINKER.
  • Loading branch information
Boondorl authored and madame-rachelle committed Jan 14, 2025
1 parent 61df133 commit c87dc5c
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 28 deletions.
6 changes: 1 addition & 5 deletions src/g_levellocals.h
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,6 @@ struct FLevelLocals
DThinker *CreateThinker(PClass *cls, int statnum = STAT_DEFAULT)
{
DThinker *thinker = static_cast<DThinker*>(cls->CreateNew());
if (thinker->IsKindOf(RUNTIME_CLASS(DVisualThinker)))
{
statnum = STAT_VISUALTHINKER;
}

assert(thinker->IsKindOf(RUNTIME_CLASS(DThinker)));
thinker->ObjectFlags |= OF_JustSpawned;
Thinkers.Link(thinker, statnum);
Expand Down Expand Up @@ -708,6 +703,7 @@ struct FLevelLocals
int ImpactDecalCount;

FDynamicLight *lights;
DVisualThinker* VisualThinkerHead = nullptr;

// links to global game objects
TArray<TObjPtr<AActor *>> CorpseQueue;
Expand Down
3 changes: 2 additions & 1 deletion src/p_saveg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,8 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
("scrolls", Scrolls)
("automap", automap)
("interpolator", interpolator)
("frozenstate", frozenstate);
("frozenstate", frozenstate)
("visualthinkerhead", VisualThinkerHead);


// Hub transitions must keep the current total time
Expand Down
6 changes: 1 addition & 5 deletions src/playsim/dthinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -810,11 +810,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DThinker, ChangeStatNum, ChangeStatNum)
PARAM_SELF_PROLOGUE(DThinker);
PARAM_INT(stat);

// do not allow ZScript to reposition thinkers in or out of particle ticking.
if (stat != STAT_VISUALTHINKER && !dynamic_cast<DVisualThinker*>(self))
{
ChangeStatNum(self, stat);
}
ChangeStatNum(self, stat);
return 0;
}

Expand Down
47 changes: 32 additions & 15 deletions src/playsim/p_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,15 +214,13 @@ void P_FindParticleSubsectors (FLevelLocals *Level)
{
Level->subsectors[i].sprites.Clear();
}
// [MC] Not too happy about using an iterator for this but I can't think of another way to handle it.
// At least it's on its own statnum for maximum efficiency.
auto it = Level->GetThinkerIterator<DVisualThinker>(NAME_None, STAT_VISUALTHINKER);
DVisualThinker* sp;
while (sp = it.Next())
auto sp = Level->VisualThinkerHead;
while (sp != nullptr)
{
if (!sp->PT.subsector) sp->PT.subsector = Level->PointInRenderSubsector(sp->PT.Pos);

sp->PT.subsector->sprites.Push(sp);
sp = sp->GetNext();
}
// End VisualThinker hitching. Now onto the particles.
if (Level->ParticlesInSubsec.Size() < Level->subsectors.Size())
Expand Down Expand Up @@ -1007,35 +1005,52 @@ void DVisualThinker::Construct()
cursector = nullptr;
PT.color = 0xffffff;
AnimatedTexture.SetNull();
}

DVisualThinker::DVisualThinker()
{
Construct();
_prev = _next = nullptr;
if (Level->VisualThinkerHead != nullptr)
{
Level->VisualThinkerHead->_prev = this;
_next = Level->VisualThinkerHead;
}
Level->VisualThinkerHead = this;
}

void DVisualThinker::OnDestroy()
{
if (_prev != nullptr)
_prev->_next = _next;
if (_next != nullptr)
_next->_prev = _prev;
if (Level->VisualThinkerHead == this)
Level->VisualThinkerHead = _next;

PT.alpha = 0.0; // stops all rendering.
Super::OnDestroy();
}

DVisualThinker* DVisualThinker::GetNext() const
{
return _next;
}

DVisualThinker* DVisualThinker::NewVisualThinker(FLevelLocals* Level, PClass* type)
{
if (type == nullptr)
return nullptr;
else if (type->bAbstract)
{
Printf("Attempt to spawn an instance of abstract VisualThinker class %s\n", type->TypeName.GetChars());
return nullptr;
}
else if (!type->IsDescendantOf(RUNTIME_CLASS(DVisualThinker)))
{
Printf("Attempt to spawn class not inherent to VisualThinker: %s\n", type->TypeName.GetChars());
return nullptr;
}
else if (type->bAbstract)
{
Printf("Attempt to spawn an instance of abstract VisualThinker class %s\n", type->TypeName.GetChars());
return nullptr;
}

DVisualThinker *zs = static_cast<DVisualThinker*>(Level->CreateThinker(type, STAT_VISUALTHINKER));
auto zs = static_cast<DVisualThinker*>(Level->CreateThinker(type, DVisualThinker::DEFAULT_STAT));
zs->Construct();
return zs;
}
Expand Down Expand Up @@ -1284,7 +1299,7 @@ void DVisualThinker::Serialize(FSerializer& arc)
{
Super::Serialize(arc);

arc ("pos", PT.Pos)
arc("pos", PT.Pos)
("vel", PT.Vel)
("prev", Prev)
("scale", Scale)
Expand All @@ -1300,7 +1315,9 @@ void DVisualThinker::Serialize(FSerializer& arc)
("lightlevel", LightLevel)
("animData", PT.animData)
("flags", PT.flags)
("visualThinkerFlags", flags);
("visualThinkerFlags", flags)
("next", _next)
("prev", _prev);

if(arc.isReading())
{
Expand Down
6 changes: 5 additions & 1 deletion src/playsim/p_visualthinker.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ class DVisualThinker : public DThinker
{
DECLARE_CLASS(DVisualThinker, DThinker);
void UpdateSector(subsector_t * newSubsector);

DVisualThinker* _next, * _prev;
public:
static const int DEFAULT_STAT = STAT_VISUALTHINKER;

DVector3 Prev;
DVector2 Scale,
Offset;
Expand All @@ -41,9 +45,9 @@ class DVisualThinker : public DThinker
// internal only variables
particle_t PT;

DVisualThinker();
void Construct();
void OnDestroy() override;
DVisualThinker* GetNext() const;

static DVisualThinker* NewVisualThinker(FLevelLocals* Level, PClass* type);
void SetTranslation(FName trname);
Expand Down
2 changes: 1 addition & 1 deletion wadsrc/static/zscript/visualthinker.zs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Class VisualThinker : Thinker native
native protected void UpdateSector(); // needs to be called if the thinker is set to a non-ticking statnum and the position is modified (or if Tick is overriden and doesn't call Super.Tick())
native protected void UpdateSpriteInfo(); // needs to be called every time the texture is updated if the thinker uses SPF_LOCAL_ANIM and is set to a non-ticking statnum (or if Tick is overriden and doesn't call Super.Tick())

static VisualThinker Spawn(Class<VisualThinker> type, TextureID tex, Vector3 pos, Vector3 vel, double alpha = 1.0, int flags = 0,
static VisualThinker Spawn(Class<VisualThinker> type, TextureID tex, Vector3 pos, Vector3 vel = (0,0,0), double alpha = 1.0, int flags = 0,
double roll = 0.0, Vector2 scale = (1,1), Vector2 offset = (0,0), int style = STYLE_Normal, TranslationID trans = 0, int VisualThinkerFlags = 0)
{
if (!Level) return null;
Expand Down

0 comments on commit c87dc5c

Please sign in to comment.