diff --git a/src/playsim/p_effect.cpp b/src/playsim/p_effect.cpp index c16d4a9826..dabf0ed164 100644 --- a/src/playsim/p_effect.cpp +++ b/src/playsim/p_effect.cpp @@ -1108,7 +1108,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnVisualThinker, SpawnVisualThink void DVisualThinker::UpdateSpriteInfo() { PT.style = ERenderStyle(GetRenderStyle()); - if((PT.flags & SPF_LOCAL_ANIM) && PT.texture != AnimatedTexture) + + if ((PT.flags & SPF_LOCAL_ANIM) && PT.texture != AnimatedTexture) { AnimatedTexture = PT.texture; TexAnim.InitStandaloneAnimation(PT.animData, PT.texture, Level->maptime); @@ -1127,6 +1128,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, UpdateSpriteInfo, UpdateSpriteInfo return 0; } +bool DVisualThinker::ValidTexture() +{ + return ((flags & VTF_IsParticle) || PT.texture.isValid()); +} // This runs just like Actor's, make sure to call Super.Tick() in ZScript. void DVisualThinker::Tick() @@ -1134,10 +1139,8 @@ void DVisualThinker::Tick() if (ObjectFlags & OF_EuthanizeMe) return; - // There won't be a standard particle for this, it's only for graphics. - if (!PT.texture.isValid()) + if (!ValidTexture()) { - Printf("No valid texture, destroyed"); Destroy(); return; } @@ -1156,7 +1159,6 @@ void DVisualThinker::Tick() PT.Pos.X = newxy.X; PT.Pos.Y = newxy.Y; PT.Pos.Z += PT.Vel.Z; - subsector_t * ss = Level->PointInRenderSubsector(PT.Pos); // Handle crossing a sector portal. @@ -1246,7 +1248,33 @@ DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, SetTranslation, SetTranslation) return 0; } -static int IsFrozen(DVisualThinker * self) +int DVisualThinker::GetParticleType() const +{ + int flag = (flags & VTF_IsParticle); + switch (flag) + { + case VTF_ParticleSquare: + return PT_SQUARE; + case VTF_ParticleRound: + return PT_ROUND; + case VTF_ParticleSmooth: + return PT_SMOOTH; + } + return PT_DEFAULT; +} + +static int GetParticleType(DVisualThinker* self) +{ + return self->GetParticleType(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, GetParticleType, GetParticleType) +{ + PARAM_SELF_PROLOGUE(DVisualThinker); + ACTION_RETURN_INT(self->GetParticleType()); +} + +static int IsFrozen(DVisualThinker* self) { return !!(self->Level->isFrozen() && !(self->PT.flags & SPF_NOTIMEFREEZE)); } diff --git a/src/playsim/p_effect.h b/src/playsim/p_effect.h index 29042b293d..b23efb01b1 100644 --- a/src/playsim/p_effect.h +++ b/src/playsim/p_effect.h @@ -53,6 +53,14 @@ struct FLevelLocals; // [RH] Particle details +enum EParticleStyle +{ + PT_DEFAULT = -1, // Use gl_particles_style + PT_SQUARE = 0, + PT_ROUND = 1, + PT_SMOOTH = 2, +}; + enum EParticleFlags { SPF_FULLBRIGHT = 1 << 0, diff --git a/src/playsim/p_visualthinker.h b/src/playsim/p_visualthinker.h index 16043effd3..69faada9f2 100644 --- a/src/playsim/p_visualthinker.h +++ b/src/playsim/p_visualthinker.h @@ -20,6 +20,12 @@ enum EVisualThinkerFlags VTF_FlipY = 1 << 3, // flip the sprite on the x/y axis. VTF_DontInterpolate = 1 << 4, // disable all interpolation VTF_AddLightLevel = 1 << 5, // adds sector light level to 'LightLevel' + + VTF_ParticleDefault = 0x40, + VTF_ParticleSquare = 0x80, + VTF_ParticleRound = 0xC0, + VTF_ParticleSmooth = 0x100, + VTF_IsParticle = 0x1C0, // Renders as a particle instead }; class DVisualThinker : public DThinker @@ -53,6 +59,8 @@ public: void SetTranslation(FName trname); int GetRenderStyle() const; bool isFrozen(); + bool ValidTexture(); + int GetParticleType() const; int GetLightLevel(sector_t *rendersector) const; FVector3 InterpolatedPosition(double ticFrac) const; float InterpolatedRoll(double ticFrac) const; diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index f3ab6d4c32..26643e7459 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -1409,7 +1409,7 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *s if (!particle || particle->alpha <= 0) return; - if (spr && spr->PT.texture.isNull()) + if (spr && !spr->ValidTexture()) return; lightlevel = hw_ClampLight(spr ? spr->GetLightLevel(sector) : sector->GetSpriteLight()); @@ -1477,17 +1477,29 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *s if (paused || (di->Level->isFrozen() && !(particle->flags & SPF_NOTIMEFREEZE))) timefrac = 0.; - if (spr) + + if (spr && !(spr->flags & VTF_IsParticle)) { AdjustVisualThinker(di, spr, sector); } else { - bool has_texture = particle->texture.isValid(); - bool custom_animated_texture = (particle->flags & SPF_LOCAL_ANIM) && particle->animData.ok; - - int particle_style = has_texture ? 2 : gl_particles_style; // Treat custom texture the same as smooth particles - + bool has_texture = false; + bool custom_animated_texture = false; + int particle_style = 0; + float size = particle->size; + if (!spr) + { + has_texture = particle->texture.isValid(); + custom_animated_texture = (particle->flags & SPF_LOCAL_ANIM) && particle->animData.ok; + particle_style = has_texture ? 2 : gl_particles_style; // Treat custom texture the same as smooth particles + } + else + { + size = float(spr->Scale.X); + const int ptype = spr->GetParticleType(); + particle_style = (ptype != PT_DEFAULT) ? ptype : gl_particles_style; + } // [BB] Load the texture for round or smooth particles if (particle_style) { @@ -1549,7 +1561,7 @@ void HWSprite::ProcessParticle(HWDrawInfo *di, particle_t *particle, sector_t *s if (particle_style == 1) factor = 1.3f / 7.f; else if (particle_style == 2) factor = 2.5f / 7.f; else factor = 1 / 7.f; - float scalefac=particle->size * factor; + float scalefac= size * factor; float ps = di->Level->pixelstretch; diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index d0356ee0d3..249d031bbd 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -1532,4 +1532,18 @@ enum EVisualThinkerFlags VTF_FlipY = 1 << 3, // flip the sprite on the x/y axis. VTF_DontInterpolate = 1 << 4, // disable all interpolation VTF_AddLightLevel = 1 << 5, // adds sector light level to 'LightLevel' + + VTF_ParticleDefault = 0x40, + VTF_ParticleSquare = 0x80, + VTF_ParticleRound = 0xC0, + VTF_ParticleSmooth = 0x100, + VTF_IsParticle = 0x1C0 +}; + +enum EParticleStyle +{ + PT_DEFAULT = -1, // Use gl_particles_style + PT_SQUARE = 0, + PT_ROUND = 1, + PT_SMOOTH = 2, }; diff --git a/wadsrc/static/zscript/visualthinker.zs b/wadsrc/static/zscript/visualthinker.zs index d5dc2253aa..34c4643f5d 100644 --- a/wadsrc/static/zscript/visualthinker.zs +++ b/wadsrc/static/zscript/visualthinker.zs @@ -60,4 +60,30 @@ Class VisualThinker : Thinker native } return p; } + + native int GetParticleType() const; + + void SetParticleType(EParticleStyle type = PT_DEFAULT) + { + switch(type) + { + Default: + VisualThinkerFlags = (VisualThinkerFlags & ~VTF_IsParticle) | VTF_ParticleDefault; + break; + case PT_SQUARE: + VisualThinkerFlags = (VisualThinkerFlags & ~VTF_IsParticle) | VTF_ParticleSquare; + break; + case PT_ROUND: + VisualThinkerFlags = (VisualThinkerFlags & ~VTF_IsParticle) | VTF_ParticleRound; + break; + case PT_SMOOTH: + VisualThinkerFlags = (VisualThinkerFlags & ~VTF_IsParticle) | VTF_ParticleSmooth; + break; + } + } + + void DisableParticle() + { + VisualThinkerFlags &= ~VTF_IsParticle; + } }