Minor optimizations to VisualThinker

* remove duplicated fields
* make native functions use direct calls
* remove unnecessary pointer from particle_t
* create HWSprite directly in Construct
This commit is contained in:
Ricardo Luís Vaz Silva 2024-01-06 20:45:40 -03:00 committed by Rachael Alexanderson
parent 5895b88799
commit 35e56d3f42
7 changed files with 117 additions and 116 deletions

View file

@ -55,7 +55,7 @@ enum ETexMode
};
// Legacy render styles
enum ERenderStyle
enum ERenderStyle : int
{
STYLE_None, // Do not draw
STYLE_Normal, // Normal; just copy the image to the screen

View file

@ -51,6 +51,8 @@
#include "g_game.h"
#include "serializer_doom.h"
#include "hwrenderer/scene/hw_drawstructs.h"
#ifdef _MSC_VER
#pragma warning(disable: 6011) // dereference null pointer in thinker iterator
#endif
@ -222,10 +224,9 @@ void P_FindParticleSubsectors (FLevelLocals *Level)
DVisualThinker* sp;
while (sp = it.Next())
{
if (sp->sub == nullptr)
sp->sub = Level->PointInRenderSubsector(sp->Pos);
if (!sp->PT.subsector) sp->PT.subsector = Level->PointInRenderSubsector(sp->PT.Pos);
sp->sub->sprites.Push(sp);
sp->PT.subsector->sprites.Push(sp);
}
// End VisualThinker hitching. Now onto the particles.
if (Level->ParticlesInSubsec.Size() < Level->subsectors.Size())
@ -994,20 +995,20 @@ void P_DisconnectEffect (AActor *actor)
void DVisualThinker::Construct()
{
PT = {};
PT.sprite = this;
Pos = Vel = { 0,0,0 };
PT.Pos = PT.Vel = { 0,0,0 };
Offset = { 0,0 };
Scale = { 1,1 };
Roll = 0.0;
Alpha = 1.0;
PT.Roll = 0.0;
PT.alpha = 1.0;
LightLevel = -1;
Texture = FTextureID();
Style = STYLE_Normal;
Flags = 0;
PT.texture = FTextureID();
PT.style = STYLE_Normal;
PT.flags = 0;
Translation = NO_TRANSLATION;
sub = nullptr;
PT.subsector = nullptr;
cursector = nullptr;
scolor = 0xffffff;
PT.color = 0xffffff;
spr = new HWSprite();
}
DVisualThinker::DVisualThinker()
@ -1015,16 +1016,14 @@ DVisualThinker::DVisualThinker()
Construct();
}
void DVisualThinker::CallPostBeginPlay()
{
PT.texture = Texture;
Super::CallPostBeginPlay();
}
void DVisualThinker::OnDestroy()
{
PT.alpha = 0.0; // stops all rendering.
if (spr) delete spr;
if(spr)
{
delete spr;
spr = nullptr;
}
Super::OnDestroy();
}
@ -1063,16 +1062,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnVisualThinker, SpawnVisualThink
void DVisualThinker::UpdateSpriteInfo()
{
PT.color = scolor;
PT.Pos = Pos;
PT.Vel = Vel;
PT.Roll = Roll;
PT.alpha = Alpha;
PT.texture = Texture;
PT.style = ERenderStyle(GetRenderStyle());
PT.flags = Flags;
PT.subsector = sub;
PT.sprite = this;
}
// This runs just like Actor's, make sure to call Super.Tick() in ZScript.
@ -1082,7 +1072,7 @@ void DVisualThinker::Tick()
return;
// There won't be a standard particle for this, it's only for graphics.
if (!Texture.isValid())
if (!PT.texture.isValid())
{
Printf("No valid texture, destroyed");
Destroy();
@ -1091,38 +1081,38 @@ void DVisualThinker::Tick()
if (isFrozen())
{ // needed here because it won't retroactively update like actors do.
sub = Level->PointInRenderSubsector(Pos);
cursector = sub->sector;
PT.subsector = Level->PointInRenderSubsector(PT.Pos);
cursector = PT.subsector->sector;
UpdateSpriteInfo();
return;
}
Prev = Pos;
PrevRoll = Roll;
Prev = PT.Pos;
PrevRoll = PT.Roll;
// Handle crossing a line portal
DVector2 newxy = Level->GetPortalOffsetPosition(Pos.X, Pos.Y, Vel.X, Vel.Y);
Pos.X = newxy.X;
Pos.Y = newxy.Y;
Pos.Z += Vel.Z;
DVector2 newxy = Level->GetPortalOffsetPosition(PT.Pos.X, PT.Pos.Y, PT.Vel.X, PT.Vel.Y);
PT.Pos.X = newxy.X;
PT.Pos.Y = newxy.Y;
PT.Pos.Z += PT.Vel.Z;
sub = Level->PointInRenderSubsector(Pos);
cursector = sub->sector;
PT.subsector = Level->PointInRenderSubsector(PT.Pos);
cursector = PT.subsector->sector;
// Handle crossing a sector portal.
if (!cursector->PortalBlocksMovement(sector_t::ceiling))
{
if (Pos.Z > cursector->GetPortalPlaneZ(sector_t::ceiling))
if (PT.Pos.Z > cursector->GetPortalPlaneZ(sector_t::ceiling))
{
Pos += cursector->GetPortalDisplacement(sector_t::ceiling);
sub = nullptr;
cursector = nullptr;
PT.Pos += cursector->GetPortalDisplacement(sector_t::ceiling);
PT.subsector = Level->PointInRenderSubsector(PT.Pos);
cursector = PT.subsector->sector;
}
}
else if (!cursector->PortalBlocksMovement(sector_t::floor))
{
if (Pos.Z < cursector->GetPortalPlaneZ(sector_t::floor))
if (PT.Pos.Z < cursector->GetPortalPlaneZ(sector_t::floor))
{
Pos += cursector->GetPortalDisplacement(sector_t::floor);
sub = nullptr;
cursector = nullptr;
PT.Pos += cursector->GetPortalDisplacement(sector_t::floor);
PT.subsector = Level->PointInRenderSubsector(PT.Pos);
cursector = PT.subsector->sector;
}
}
UpdateSpriteInfo();
@ -1145,18 +1135,18 @@ int DVisualThinker::GetLightLevel(sector_t* rendersector) const
FVector3 DVisualThinker::InterpolatedPosition(double ticFrac) const
{
if (bDontInterpolate) return FVector3(Pos);
if (bDontInterpolate) return FVector3(PT.Pos);
DVector3 proc = Prev + (ticFrac * (Pos - Prev));
DVector3 proc = Prev + (ticFrac * (PT.Pos - Prev));
return FVector3(proc);
}
float DVisualThinker::InterpolatedRoll(double ticFrac) const
{
if (bDontInterpolate) return Roll;
if (bDontInterpolate) return PT.Roll;
return float(PrevRoll + (Roll - PrevRoll) * ticFrac);
return float(PrevRoll + (PT.Roll - PrevRoll) * ticFrac);
}
@ -1179,7 +1169,13 @@ void DVisualThinker::SetTranslation(FName trname)
// silently ignore if the name does not exist, this would create some insane message spam otherwise.
}
DEFINE_ACTION_FUNCTION(DVisualThinker, SetTranslation)
void SetTranslation(DVisualThinker * self, int i_trans)
{
FName trans {ENamedName(i_trans)};
self->SetTranslation(trans);
}
DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, SetTranslation, SetTranslation)
{
PARAM_SELF_PROLOGUE(DVisualThinker);
PARAM_NAME(trans);
@ -1187,33 +1183,42 @@ DEFINE_ACTION_FUNCTION(DVisualThinker, SetTranslation)
return 0;
}
bool DVisualThinker::isFrozen()
static int IsFrozen(DVisualThinker * self)
{
return (Level->isFrozen() && !(Flags & SPF_NOTIMEFREEZE));
return (self->Level->isFrozen() && !(self->PT.flags & SPF_NOTIMEFREEZE));
}
DEFINE_ACTION_FUNCTION(DVisualThinker, IsFrozen)
bool DVisualThinker::isFrozen()
{
return IsFrozen(this);
}
DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, IsFrozen, IsFrozen)
{
PARAM_SELF_PROLOGUE(DVisualThinker);
ACTION_RETURN_BOOL(self->isFrozen());
}
DEFINE_ACTION_FUNCTION(DVisualThinker, SetRenderStyle)
static void SetRenderStyle(DVisualThinker *self, int mode)
{
if(mode >= 0 && mode < STYLE_Count)
{
self->PT.style = ERenderStyle(mode);
}
}
DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, SetRenderStyle, SetRenderStyle)
{
PARAM_SELF_PROLOGUE(DVisualThinker);
PARAM_INT(mode);
self->Style = ERenderStyle(mode);
self->PT.style = ERenderStyle(mode);
return 0;
}
int DVisualThinker::GetRenderStyle()
{
for (unsigned i = 0; i < STYLE_Count; i++)
{
if (Style == LegacyRenderStyles[i]) return i;
}
return -1;
return PT.style;
}
void DVisualThinker::Serialize(FSerializer& arc)
@ -1221,42 +1226,43 @@ void DVisualThinker::Serialize(FSerializer& arc)
Super::Serialize(arc);
arc
("pos", Pos)
("vel", Vel)
("pos", PT.Pos)
("vel", PT.Vel)
("prev", Prev)
("scale", Scale)
("roll", Roll)
("roll", PT.Roll)
("prevroll", PrevRoll)
("offset", Offset)
("alpha", Alpha)
("texture", Texture)
("style", Style)
("alpha", PT.alpha)
("texture", PT.texture)
("style", *reinterpret_cast<int*>(&PT.style))
("translation", Translation)
("cursector", cursector)
("scolor", scolor)
("scolor", PT.color)
("flipx", bXFlip)
("flipy", bYFlip)
("dontinterpolate", bDontInterpolate)
("addlightlevel", bAddLightLevel)
("lightlevel", LightLevel)
("flags", Flags);
("flags", PT.flags);
}
IMPLEMENT_CLASS(DVisualThinker, false, false);
DEFINE_FIELD(DVisualThinker, Pos);
DEFINE_FIELD(DVisualThinker, Vel);
DEFINE_FIELD_NAMED(DVisualThinker, PT.color, SColor);
DEFINE_FIELD_NAMED(DVisualThinker, PT.Pos, Pos);
DEFINE_FIELD_NAMED(DVisualThinker, PT.Vel, Vel);
DEFINE_FIELD_NAMED(DVisualThinker, PT.Roll, Roll);
DEFINE_FIELD_NAMED(DVisualThinker, PT.alpha, Alpha);
DEFINE_FIELD_NAMED(DVisualThinker, PT.texture, Texture);
DEFINE_FIELD_NAMED(DVisualThinker, PT.flags, Flags);
DEFINE_FIELD(DVisualThinker, Prev);
DEFINE_FIELD(DVisualThinker, Scale);
DEFINE_FIELD(DVisualThinker, Offset);
DEFINE_FIELD(DVisualThinker, Roll);
DEFINE_FIELD(DVisualThinker, PrevRoll);
DEFINE_FIELD(DVisualThinker, Alpha);
DEFINE_FIELD(DVisualThinker, Texture);
DEFINE_FIELD(DVisualThinker, Translation);
DEFINE_FIELD(DVisualThinker, Flags);
DEFINE_FIELD(DVisualThinker, LightLevel);
DEFINE_FIELD(DVisualThinker, scolor);
DEFINE_FIELD(DVisualThinker, cursector);
DEFINE_FIELD(DVisualThinker, bXFlip);
DEFINE_FIELD(DVisualThinker, bYFlip);

View file

@ -81,7 +81,6 @@ struct particle_t
uint16_t tnext, snext, tprev;
bool bright;
uint16_t flags;
DVisualThinker *sprite;
};
const uint16_t NO_PARTICLE = 0xffff;
@ -152,34 +151,25 @@ class DVisualThinker : public DThinker
{
DECLARE_CLASS(DVisualThinker, DThinker);
public:
DVector3 Pos, Vel, Prev;
DVector2 Scale, Offset;
double Roll, PrevRoll, Alpha;
DVector3 Prev;
DVector2 Scale,
Offset;
double PrevRoll;
int16_t LightLevel;
int scolor;
FRenderStyle Style;
FTextureID Texture;
FTranslationID Translation;
uint16_t Flags;
sector_t *cursector;
bool bXFlip, bYFlip, // flip the sprite on the x/y axis.
bool bXFlip,
bYFlip, // flip the sprite on the x/y axis.
bDontInterpolate, // disable all interpolation
bAddLightLevel; // adds sector light level to 'LightLevel'
// internal only variables
subsector_t *sub;
particle_t PT;
HWSprite *spr; //in an effort to cache the result.
DVisualThinker();
void Construct();
void CallPostBeginPlay() override;
void OnDestroy() override;
static DVisualThinker* NewVisualThinker(FLevelLocals* Level, PClass* type);

View file

@ -607,10 +607,10 @@ void HWDrawInfo::RenderParticles(subsector_t *sub, sector_t *front)
int clipres = mClipPortal->ClipPoint(sp->PT.Pos.XY());
if (clipres == PClip_InFront) continue;
}
if (!sp->spr)
sp->spr = new HWSprite();
sp->spr->ProcessParticle(this, &sp->PT, front);
assert(sp->spr);
sp->spr->ProcessParticle(this, &sp->PT, front, sp);
}
for (int i = Level->ParticlesInSubsec[sub->Index()]; i != NO_PARTICLE; i = Level->Particles[i].snext)
{
@ -621,7 +621,7 @@ void HWDrawInfo::RenderParticles(subsector_t *sub, sector_t *front)
}
HWSprite sprite;
sprite.ProcessParticle(this, &Level->Particles[i], front);
sprite.ProcessParticle(this, &Level->Particles[i], front, nullptr);
}
SetupSprite.Unclock();
}

View file

@ -402,7 +402,7 @@ public:
void CreateVertices(HWDrawInfo *di);
void PutSprite(HWDrawInfo *di, bool translucent);
void Process(HWDrawInfo *di, AActor* thing,sector_t * sector, area_t in_area, int thruportal = false, bool isSpriteShadow = false);
void ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *sector);//, int shade, int fakeside)
void ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *sector, class DVisualThinker *spr);//, int shade, int fakeside)
void AdjustVisualThinker(HWDrawInfo *di, DVisualThinker *spr, sector_t *sector);
void DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent);

View file

@ -1263,13 +1263,12 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
//
//==========================================================================
void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *sector)//, int shade, int fakeside)
void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *sector, DVisualThinker *spr)//, int shade, int fakeside)
{
if (!particle || particle->alpha <= 0)
return;
DVisualThinker *spr = particle->sprite;
if (spr && spr->Texture.isNull())
if (spr && spr->PT.texture.isNull())
return;
lightlevel = hw_ClampLight(spr ? spr->GetLightLevel(sector) : sector->GetSpriteLight());
@ -1427,7 +1426,7 @@ void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
void HWSprite::AdjustVisualThinker(HWDrawInfo* di, DVisualThinker* spr, sector_t* sector)
{
translation = spr->Translation;
texture = TexMan.GetGameTexture(spr->Texture, true);
texture = TexMan.GetGameTexture(spr->PT.texture, true);
const auto& vp = di->Viewpoint;
double timefrac = vp.TicFrac;
@ -1442,7 +1441,7 @@ void HWSprite::AdjustVisualThinker(HWDrawInfo* di, DVisualThinker* spr, sector_t
offx = (float)spr->Offset.X;
offy = (float)spr->Offset.Y;
if (spr->Flags & SPF_ROLL)
if (spr->PT.flags & SPF_ROLL)
Angles.Roll = TAngle<double>::fromDeg(spr->InterpolatedRoll(timefrac));
auto& spi = texture->GetSpritePositioning(0);

View file

@ -1,18 +1,24 @@
Class VisualThinker : Thinker native
{
native Vector3 Pos, Vel, Prev;
native Vector2 Scale, Offset;
native double Roll, Alpha, PrevRoll;
native TextureID Texture;
native Vector3 Pos,
Vel,
Prev;
native Vector2 Scale,
Offset;
native double Roll,
PrevRoll;
native float Alpha;
native TextureID Texture;
native TranslationID Translation;
native uint16 Flags;
native int16 LightLevel;
native bool bXFlip, bYFlip,
bDontInterpolate,
bAddLightLevel;
native Color scolor;
native uint16 Flags;
native int16 LightLevel;
native bool bXFlip,
bYFlip,
bDontInterpolate,
bAddLightLevel;
native Color scolor;
native Sector CurSector; // can be null!
native Sector CurSector; // can be null!
native void SetTranslation(Name trans);
native void SetRenderStyle(int mode); // see ERenderStyle