mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-21 18:31:10 +00:00
Added ZSprites.
- Effectively similar to Actors, but without the excess. - Can be created with either the `level` function or the static `Spawn` function in ZSprite. - STAT_SPRITE belongs to ZSprites only; ZSprites cannot be moved out of, nor can anything else be moved in to, this statnum. Misc: - Fixed (Sprite)Offset taking roll into account. Crediting phantombeta, RicardoLuis0 and RaveYard for assistance.
This commit is contained in:
parent
3056786f38
commit
b6b1b25035
15 changed files with 601 additions and 136 deletions
|
@ -10,6 +10,7 @@ xx(Object)
|
|||
xx(Actor)
|
||||
xx(Class)
|
||||
xx(Thinker)
|
||||
xx(ZSprite)
|
||||
xx(Crosshairs)
|
||||
|
||||
xx(Untranslated)
|
||||
|
|
|
@ -427,6 +427,8 @@ public:
|
|||
DThinker *thinker = static_cast<DThinker*>(cls->CreateNew());
|
||||
assert(thinker->IsKindOf(RUNTIME_CLASS(DThinker)));
|
||||
thinker->ObjectFlags |= OF_JustSpawned;
|
||||
if (thinker->IsKindOf(RUNTIME_CLASS(DZSprite))) // [MC] This absolutely must happen for this class!
|
||||
statnum = STAT_SPRITE;
|
||||
Thinkers.Link(thinker, statnum);
|
||||
thinker->Level = this;
|
||||
return thinker;
|
||||
|
@ -665,7 +667,7 @@ public:
|
|||
DSeqNode *SequenceListHead;
|
||||
|
||||
// [RH] particle globals
|
||||
uint32_t OldestParticle; // [MC] Oldest particle for replacing with PS_REPLACE
|
||||
uint32_t OldestParticle; // [MC] Oldest particle for replacing with SPF_REPLACE
|
||||
uint32_t ActiveParticles;
|
||||
uint32_t InactiveParticles;
|
||||
TArray<particle_t> Particles;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "fcolormap.h"
|
||||
#include "r_sky.h"
|
||||
#include "p_terrain.h"
|
||||
#include "p_effect.h"
|
||||
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
|
||||
|
@ -1662,7 +1663,7 @@ struct subsector_t
|
|||
int Index() const { return subsectornum; }
|
||||
// 2: has one-sided walls
|
||||
FPortalCoverage portalcoverage[2];
|
||||
|
||||
TArray<DZSprite *> sprites;
|
||||
LightmapSurface *lightmap[2];
|
||||
};
|
||||
|
||||
|
|
|
@ -807,7 +807,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(DThinker, ChangeStatNum, ChangeStatNum)
|
|||
{
|
||||
PARAM_SELF_PROLOGUE(DThinker);
|
||||
PARAM_INT(stat);
|
||||
ChangeStatNum(self, stat);
|
||||
|
||||
// do not allow ZScript to reposition thinkers in or out of particle ticking.
|
||||
if (stat != STAT_SPRITE && !dynamic_cast<DZSprite*>(self))
|
||||
{
|
||||
ChangeStatNum(self, stat);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1607,18 +1607,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnDebris)
|
|||
// A_SpawnParticle
|
||||
//
|
||||
//===========================================================================
|
||||
enum SPFflag
|
||||
{
|
||||
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,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SpawnParticle)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,11 @@
|
|||
#include "vm.h"
|
||||
#include "actorinlines.h"
|
||||
#include "g_game.h"
|
||||
#include "serializer_doom.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 6011) // dereference null pointer in thinker iterator
|
||||
#endif
|
||||
|
||||
CVAR (Int, cl_rockettrails, 1, CVAR_ARCHIVE);
|
||||
CVAR (Bool, r_rail_smartspiral, false, CVAR_ARCHIVE);
|
||||
|
@ -202,9 +207,27 @@ void P_ClearParticles (FLevelLocals *Level)
|
|||
// Group particles by subsectors. Because particles are always
|
||||
// in motion, there is little benefit to caching this information
|
||||
// from one frame to the next.
|
||||
// [MC] ZSprites hitches a ride here
|
||||
|
||||
void P_FindParticleSubsectors (FLevelLocals *Level)
|
||||
{
|
||||
// [MC] Hitch a ride on particle subsectors since ZSprites are effectively using the same kind of system.
|
||||
for (uint32_t i = 0; i < Level->subsectors.Size(); i++)
|
||||
{
|
||||
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<DZSprite>(NAME_None, STAT_SPRITE);
|
||||
DZSprite* sp;
|
||||
while (sp = it.Next())
|
||||
{
|
||||
if (sp->sub == nullptr)
|
||||
sp->sub = Level->PointInRenderSubsector(sp->Pos);
|
||||
|
||||
sp->sub->sprites.Push(sp);
|
||||
}
|
||||
// End ZSprite hitching. Now onto the particles.
|
||||
if (Level->ParticlesInSubsec.Size() < Level->subsectors.Size())
|
||||
{
|
||||
Level->ParticlesInSubsec.Reserve (Level->subsectors.Size() - Level->ParticlesInSubsec.Size());
|
||||
|
@ -271,7 +294,7 @@ void P_ThinkParticles (FLevelLocals *Level)
|
|||
{
|
||||
particle = &Level->Particles[i];
|
||||
i = particle->tnext;
|
||||
if (Level->isFrozen() && !(particle->flags &PT_NOTIMEFREEZE))
|
||||
if (Level->isFrozen() && !(particle->flags &SPF_NOTIMEFREEZE))
|
||||
{
|
||||
prev = particle;
|
||||
continue;
|
||||
|
@ -305,7 +328,7 @@ void P_ThinkParticles (FLevelLocals *Level)
|
|||
particle->Pos.Z += particle->Vel.Z;
|
||||
particle->Vel += particle->Acc;
|
||||
|
||||
if(particle->flags & PT_DOROLL)
|
||||
if(particle->flags & SPF_ROLL)
|
||||
{
|
||||
particle->Roll += particle->RollVel;
|
||||
particle->RollVel += particle->RollAcc;
|
||||
|
@ -334,19 +357,10 @@ void P_ThinkParticles (FLevelLocals *Level)
|
|||
}
|
||||
}
|
||||
|
||||
enum PSFlag
|
||||
{
|
||||
PS_FULLBRIGHT = 1,
|
||||
PS_NOTIMEFREEZE = 1 << 5,
|
||||
PS_ROLL = 1 << 6,
|
||||
PS_REPLACE = 1 << 7,
|
||||
PS_NO_XY_BILLBOARD = 1 << 8,
|
||||
};
|
||||
|
||||
void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size,
|
||||
double fadestep, double sizestep, int flags, FTextureID texture, ERenderStyle style, double startroll, double rollvel, double rollacc)
|
||||
{
|
||||
particle_t *particle = NewParticle(Level, !!(flags & PS_REPLACE));
|
||||
particle_t *particle = NewParticle(Level, !!(flags & SPF_REPLACE));
|
||||
|
||||
if (particle)
|
||||
{
|
||||
|
@ -358,7 +372,7 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v
|
|||
if (fadestep < 0) particle->fadestep = FADEFROMTTL(lifetime);
|
||||
else particle->fadestep = float(fadestep);
|
||||
particle->ttl = lifetime;
|
||||
particle->bright = !!(flags & PS_FULLBRIGHT);
|
||||
particle->bright = !!(flags & SPF_FULLBRIGHT);
|
||||
particle->size = size;
|
||||
particle->sizestep = sizestep;
|
||||
particle->texture = texture;
|
||||
|
@ -366,18 +380,7 @@ void P_SpawnParticle(FLevelLocals *Level, const DVector3 &pos, const DVector3 &v
|
|||
particle->Roll = startroll;
|
||||
particle->RollVel = rollvel;
|
||||
particle->RollAcc = rollacc;
|
||||
if(flags & PS_NOTIMEFREEZE)
|
||||
{
|
||||
particle->flags |= PT_NOTIMEFREEZE;
|
||||
}
|
||||
if(flags & PS_ROLL)
|
||||
{
|
||||
particle->flags |= PT_DOROLL;
|
||||
}
|
||||
if(flags & PS_NO_XY_BILLBOARD)
|
||||
{
|
||||
particle->flags |= PT_NOXYBILLBOARD;
|
||||
}
|
||||
particle->flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -979,3 +982,264 @@ void P_DisconnectEffect (AActor *actor)
|
|||
p->size = 4;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ZScript Sprite (DZSprite)
|
||||
// Concept by Major Cooke
|
||||
// Most code borrowed by Actor and particles above
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DZSprite::DZSprite()
|
||||
{
|
||||
PT = {};
|
||||
PT.sprite = this;
|
||||
Pos = Vel = {0,0,0};
|
||||
Offset = {0,0};
|
||||
Scale = {1,1};
|
||||
Roll = 0.0;
|
||||
Alpha = 1.0;
|
||||
LightLevel = -1;
|
||||
Texture = FTextureID();
|
||||
Style = STYLE_Normal;
|
||||
Translation = Flags = 0;
|
||||
sub = nullptr;
|
||||
cursector = nullptr;
|
||||
}
|
||||
|
||||
void DZSprite::CallPostBeginPlay()
|
||||
{
|
||||
PT.texture = Texture;
|
||||
Super::CallPostBeginPlay();
|
||||
}
|
||||
|
||||
void DZSprite::OnDestroy()
|
||||
{
|
||||
PT.alpha = 0.0; // stops all rendering.
|
||||
spr = nullptr;
|
||||
Super::OnDestroy();
|
||||
}
|
||||
|
||||
DZSprite* DZSprite::NewZSprite(FLevelLocals* Level, PClass* type)
|
||||
{
|
||||
if (type == nullptr)
|
||||
return nullptr;
|
||||
else if (type->bAbstract)
|
||||
{
|
||||
Printf("Attempt to spawn an instance of abstract ZSprite class %s\n", type->TypeName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
else if (!type->IsDescendantOf(RUNTIME_CLASS(DZSprite)))
|
||||
{
|
||||
Printf("Attempt to spawn class not inherent to ZSprite: %s\n", type->TypeName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DZSprite *zs = static_cast<DZSprite*>(Level->CreateThinker(type, STAT_SPRITE));
|
||||
|
||||
return zs;
|
||||
}
|
||||
|
||||
static DZSprite* SpawnZSprite(FLevelLocals* Level, PClass* type)
|
||||
{
|
||||
return DZSprite::NewZSprite(Level, type);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, SpawnZSprite, SpawnZSprite)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
|
||||
PARAM_CLASS_NOT_NULL(type, DZSprite);
|
||||
DZSprite* zs = SpawnZSprite(self, type);
|
||||
ACTION_RETURN_OBJECT(zs);
|
||||
}
|
||||
|
||||
|
||||
// This runs just like Actor's, make sure to call Super.Tick() in ZScript.
|
||||
void DZSprite::Tick()
|
||||
{
|
||||
if (ObjectFlags & OF_EuthanizeMe)
|
||||
return;
|
||||
|
||||
// There won't be a standard particle for this, it's only for graphics.
|
||||
if (!Texture.isValid())
|
||||
{
|
||||
Printf("No valid texture, destroyed");
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFrozen())
|
||||
return;
|
||||
|
||||
Prev = Pos;
|
||||
PrevRoll = 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;
|
||||
|
||||
sub = Level->PointInRenderSubsector(Pos);
|
||||
cursector = sub->sector;
|
||||
// Handle crossing a sector portal.
|
||||
if (!cursector->PortalBlocksMovement(sector_t::ceiling))
|
||||
{
|
||||
if (Pos.Z > cursector->GetPortalPlaneZ(sector_t::ceiling))
|
||||
{
|
||||
Pos += cursector->GetPortalDisplacement(sector_t::ceiling);
|
||||
sub = nullptr;
|
||||
cursector = nullptr;
|
||||
}
|
||||
}
|
||||
else if (!cursector->PortalBlocksMovement(sector_t::floor))
|
||||
{
|
||||
if (Pos.Z < cursector->GetPortalPlaneZ(sector_t::floor))
|
||||
{
|
||||
Pos += cursector->GetPortalDisplacement(sector_t::floor);
|
||||
sub = nullptr;
|
||||
cursector = nullptr;
|
||||
}
|
||||
}
|
||||
PT.color = 0xffffff;
|
||||
PT.Pos = Pos;
|
||||
PT.Vel = Vel;
|
||||
PT.Roll = Roll;
|
||||
PT.size = Scale.X;
|
||||
PT.alpha = Alpha;
|
||||
PT.texture = Texture;
|
||||
PT.style = ERenderStyle(GetRenderStyle());
|
||||
PT.flags = Flags;
|
||||
PT.subsector = sub;
|
||||
PT.sprite = this;
|
||||
}
|
||||
|
||||
int DZSprite::GetLightLevel(sector_t* rendersector) const
|
||||
{
|
||||
int lightlevel = rendersector->GetSpriteLight();
|
||||
|
||||
if (bAddLightLevel)
|
||||
{
|
||||
lightlevel += LightLevel;
|
||||
}
|
||||
else if (LightLevel > -1)
|
||||
{
|
||||
lightlevel = LightLevel;
|
||||
}
|
||||
return lightlevel;
|
||||
}
|
||||
|
||||
FVector3 DZSprite::InterpolatedPosition(double ticFrac) const
|
||||
{
|
||||
if (bDontInterpolate) return FVector3(Pos);
|
||||
|
||||
DVector3 proc = Prev + (ticFrac * (Pos - Prev));
|
||||
return FVector3(proc);
|
||||
|
||||
}
|
||||
|
||||
float DZSprite::InterpolatedRoll(double ticFrac) const
|
||||
{
|
||||
if (bDontInterpolate) return Roll;
|
||||
|
||||
return float(PrevRoll + (Roll - PrevRoll) * ticFrac);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DZSprite::SetTranslation(FName trname)
|
||||
{
|
||||
// There is no constant for the empty name...
|
||||
if (trname.GetChars()[0] == 0)
|
||||
{
|
||||
// '' removes it
|
||||
Translation = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int tnum = R_FindCustomTranslation(trname);
|
||||
if (tnum >= 0)
|
||||
{
|
||||
Translation = tnum;
|
||||
}
|
||||
// silently ignore if the name does not exist, this would create some insane message spam otherwise.
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DZSprite, SetTranslation)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(DZSprite);
|
||||
PARAM_NAME(trans);
|
||||
self->SetTranslation(trans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool DZSprite::isFrozen()
|
||||
{
|
||||
return (Level->isFrozen() && !(Flags & SPF_NOTIMEFREEZE));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DZSprite, IsFrozen)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(DZSprite);
|
||||
ACTION_RETURN_BOOL(self->isFrozen());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DZSprite, SetRenderStyle)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(DZSprite);
|
||||
PARAM_INT(mode);
|
||||
|
||||
self->Style = ERenderStyle(mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DZSprite::GetRenderStyle()
|
||||
{
|
||||
for (unsigned i = 0; i < STYLE_Count; i++)
|
||||
{
|
||||
if (Style == LegacyRenderStyles[i]) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void DZSprite::Serialize(FSerializer& arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
|
||||
arc
|
||||
("pos", Pos)
|
||||
("vel", Vel)
|
||||
("prev", Prev)
|
||||
("scale", Scale)
|
||||
("roll", Roll)
|
||||
("offset", Offset)
|
||||
("alpha", Alpha)
|
||||
("texture", Texture)
|
||||
("style", Style)
|
||||
("translation", Translation)
|
||||
("cursector", cursector)
|
||||
("flipx", bXFlip)
|
||||
("flipy", bYFlip)
|
||||
("dontinterpolate", bDontInterpolate)
|
||||
("addlightlevel", bAddLightLevel)
|
||||
("flags", Flags);
|
||||
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(DZSprite, false, false);
|
||||
DEFINE_FIELD(DZSprite, Pos);
|
||||
DEFINE_FIELD(DZSprite, Vel);
|
||||
DEFINE_FIELD(DZSprite, Prev);
|
||||
DEFINE_FIELD(DZSprite, Scale);
|
||||
DEFINE_FIELD(DZSprite, Offset);
|
||||
DEFINE_FIELD(DZSprite, Roll);
|
||||
DEFINE_FIELD(DZSprite, Alpha);
|
||||
DEFINE_FIELD(DZSprite, Texture);
|
||||
DEFINE_FIELD(DZSprite, Translation);
|
||||
DEFINE_FIELD(DZSprite, Flags);
|
||||
DEFINE_FIELD(DZSprite, LightLevel);
|
||||
DEFINE_FIELD(DZSprite, cursector);
|
||||
DEFINE_FIELD(DZSprite, bXFlip);
|
||||
DEFINE_FIELD(DZSprite, bYFlip);
|
||||
DEFINE_FIELD(DZSprite, bDontInterpolate);
|
||||
DEFINE_FIELD(DZSprite, bAddLightLevel);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "vectors.h"
|
||||
#include "doomdef.h"
|
||||
#include "renderstyle.h"
|
||||
#include "dthinker.h"
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -52,11 +53,17 @@ struct FLevelLocals;
|
|||
|
||||
enum EParticleFlags
|
||||
{
|
||||
PT_NOTIMEFREEZE = 1,
|
||||
PT_DOROLL = 1 << 1,
|
||||
PT_NOXYBILLBOARD = 1 << 2,
|
||||
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,
|
||||
};
|
||||
|
||||
class DZSprite;
|
||||
struct particle_t
|
||||
{
|
||||
DVector3 Pos;
|
||||
|
@ -71,8 +78,9 @@ struct particle_t
|
|||
ERenderStyle style;
|
||||
double Roll, RollVel, RollAcc;
|
||||
uint16_t tnext, snext, tprev;
|
||||
uint8_t bright;
|
||||
uint8_t flags;
|
||||
bool bright;
|
||||
uint16_t flags;
|
||||
DZSprite *sprite;
|
||||
};
|
||||
|
||||
const uint16_t NO_PARTICLE = 0xffff;
|
||||
|
@ -130,3 +138,54 @@ void P_DrawSplash (FLevelLocals *Level, int count, const DVector3 &pos, DAngle a
|
|||
void P_DrawSplash2 (FLevelLocals *Level, int count, const DVector3 &pos, DAngle angle, int updown, int kind);
|
||||
void P_DisconnectEffect (AActor *actor);
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// ZSprites
|
||||
// by Major Cooke
|
||||
// Credit to phantombeta, RicardoLuis0 & RaveYard for aid
|
||||
//
|
||||
//===========================================================================
|
||||
class HWSprite;
|
||||
class DZSprite : public DThinker
|
||||
{
|
||||
DECLARE_CLASS(DZSprite, DThinker);
|
||||
public:
|
||||
DVector3 Pos, Vel, Prev;
|
||||
DVector2 Scale, Offset;
|
||||
double Roll, PrevRoll, Alpha;
|
||||
int16_t LightLevel;
|
||||
|
||||
FRenderStyle Style;
|
||||
FTextureID Texture;
|
||||
uint32_t Translation;
|
||||
|
||||
uint16_t Flags;
|
||||
sector_t *cursector;
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
DZSprite();
|
||||
void CallPostBeginPlay() override;
|
||||
void OnDestroy() override;
|
||||
|
||||
static DZSprite* NewZSprite(FLevelLocals* Level, PClass* type);
|
||||
void SetTranslation(FName trname);
|
||||
int GetRenderStyle();
|
||||
bool isFrozen();
|
||||
int GetLightLevel(sector_t *rendersector) const;
|
||||
FVector3 InterpolatedPosition(double ticFrac) const;
|
||||
float InterpolatedRoll(double ticFrac) const;
|
||||
|
||||
void Tick() override;
|
||||
void Serialize(FSerializer& arc) override;
|
||||
|
||||
};
|
||||
|
|
|
@ -69,6 +69,7 @@ enum
|
|||
STAT_ACTORMOVER, // actor movers
|
||||
STAT_SCRIPTS, // The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay
|
||||
STAT_BOT, // Bot thinker
|
||||
STAT_SPRITE, // ZSprite Thinker
|
||||
};
|
||||
|
||||
#endif
|
|
@ -597,6 +597,23 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector)
|
|||
void HWDrawInfo::RenderParticles(subsector_t *sub, sector_t *front)
|
||||
{
|
||||
SetupSprite.Clock();
|
||||
for (uint32_t i = 0; i < sub->sprites.Size(); i++)
|
||||
{
|
||||
DZSprite *sp = sub->sprites[i];
|
||||
if (!sp || sp->ObjectFlags & OF_EuthanizeMe)
|
||||
continue;
|
||||
if (mClipPortal)
|
||||
{
|
||||
int clipres = mClipPortal->ClipPoint(sp->PT.Pos);
|
||||
if (clipres == PClip_InFront) continue;
|
||||
}
|
||||
if (!sp->spr)
|
||||
{
|
||||
HWSprite sprite;
|
||||
sp->spr = &sprite;
|
||||
}
|
||||
sp->spr->ProcessParticle(this, &sp->PT, front);
|
||||
}
|
||||
for (int i = Level->ParticlesInSubsec[sub->Index()]; i != NO_PARTICLE; i = Level->Particles[i].snext)
|
||||
{
|
||||
if (mClipPortal)
|
||||
|
@ -669,7 +686,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub)
|
|||
}
|
||||
|
||||
// [RH] Add particles
|
||||
if (gl_render_things && Level->ParticlesInSubsec[sub->Index()] != NO_PARTICLE)
|
||||
if (gl_render_things && (sub->sprites.Size() > 0 || Level->ParticlesInSubsec[sub->Index()] != NO_PARTICLE))
|
||||
{
|
||||
if (multithread)
|
||||
{
|
||||
|
|
|
@ -382,6 +382,7 @@ public:
|
|||
float vt,vb;
|
||||
float x1,y1,z1;
|
||||
float x2,y2,z2;
|
||||
float offx, offy;
|
||||
float trans;
|
||||
int dynlightindex;
|
||||
|
||||
|
@ -402,6 +403,7 @@ public:
|
|||
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 AdjustZSprite(HWDrawInfo *di, DZSprite *spr, sector_t *sector);
|
||||
|
||||
void DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent);
|
||||
};
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "hw_dynlightdata.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "quaternion.h"
|
||||
|
||||
extern TArray<spritedef_t> sprites;
|
||||
extern TArray<spriteframe_t> SpriteFrames;
|
||||
|
@ -101,9 +102,7 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent)
|
|||
bool additivefog = false;
|
||||
bool foglayer = false;
|
||||
int rel = fullbright ? 0 : getExtraLight();
|
||||
auto &vp = di->Viewpoint;
|
||||
|
||||
const bool UseActorLight = (actor && actor->LightLevel > -1);
|
||||
auto &vp = di->Viewpoint;
|
||||
|
||||
if (translucent)
|
||||
{
|
||||
|
@ -383,7 +382,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
}
|
||||
|
||||
// [BB] Billboard stuff
|
||||
const bool drawWithXYBillboard = ((particle && gl_billboard_particles && !(particle->flags & PT_NOXYBILLBOARD)) || (!(actor && actor->renderflags & RF_FORCEYBILLBOARD)
|
||||
const bool drawWithXYBillboard = ((particle && gl_billboard_particles && !(particle->flags & SPF_NO_XY_BILLBOARD)) || (!(actor && actor->renderflags & RF_FORCEYBILLBOARD)
|
||||
//&& di->mViewActor != nullptr
|
||||
&& (gl_billboard_mode == 1 || (actor && actor->renderflags & RF_FORCEXYBILLBOARD))));
|
||||
|
||||
|
@ -391,7 +390,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
// [Nash] has +ROLLSPRITE
|
||||
const bool drawRollSpriteActor = (actor != nullptr && actor->renderflags & RF_ROLLSPRITE);
|
||||
|
||||
const bool drawRollParticle = (particle != nullptr && particle->flags & PT_DOROLL);
|
||||
const bool drawRollParticle = (particle != nullptr && particle->flags & SPF_ROLL);
|
||||
|
||||
|
||||
// [fgsfds] check sprite type mask
|
||||
|
@ -399,7 +398,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
if (actor != nullptr) spritetype = actor->renderflags & RF_SPRITETYPEMASK;
|
||||
|
||||
// [Nash] is a flat sprite
|
||||
const bool isFlatSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE || spritetype == RF_FLATSPRITE);
|
||||
const bool isFlatSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE);
|
||||
const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER);
|
||||
|
||||
// [Nash] check for special sprite drawing modes
|
||||
|
@ -416,7 +415,20 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
mat.MakeIdentity();
|
||||
mat.Translate(xcenter, zcenter, ycenter); // move to sprite center
|
||||
|
||||
// Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down).
|
||||
// [MC] Sprite offsets. These must be calculated separately in their own matrix,
|
||||
// otherwise "face sprites" would cause some issues whenever enabled. We don't
|
||||
// want those calculations here. Credit to PhantomBeta for this.
|
||||
if (offx || offy)
|
||||
{
|
||||
FAngle zero = FAngle::fromDeg(0);
|
||||
FQuaternion quat = FQuaternion::FromAngles(FAngle::fromDeg(270) - di->Viewpoint.HWAngles.Yaw, di->Viewpoint.HWAngles.Pitch, FAngle::fromDeg(0));
|
||||
FVector3 sideVec = quat * FVector3(0, 1, 0);
|
||||
FVector3 upVec = quat * FVector3(0, 0, 1);
|
||||
FVector3 res = sideVec * offx + upVec * offy;
|
||||
mat.Translate(res.X, res.Z, res.Y);
|
||||
}
|
||||
|
||||
// Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down).
|
||||
if (drawBillboardFacingCamera && !isFlatSprite)
|
||||
{
|
||||
// [CMB] Rotate relative to camera XY position, not just camera direction,
|
||||
|
@ -431,18 +443,15 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
}
|
||||
|
||||
// [fgsfds] calculate yaw vectors
|
||||
float yawvecX = 0, yawvecY = 0, rollDegrees = 0;
|
||||
float rollDegrees = 0;
|
||||
float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians();
|
||||
if (actor || drawRollParticle) rollDegrees = Angles.Roll.Degrees();
|
||||
if (isFlatSprite)
|
||||
{
|
||||
yawvecX = Angles.Yaw.Cos();
|
||||
yawvecY = Angles.Yaw.Sin();
|
||||
}
|
||||
|
||||
// [fgsfds] Rotate the sprite about the sight vector (roll)
|
||||
if (spritetype == RF_WALLSPRITE)
|
||||
{
|
||||
float yawvecX = Angles.Yaw.Cos();
|
||||
float yawvecY = Angles.Yaw.Sin();
|
||||
mat.Rotate(0, 1, 0, 0);
|
||||
if (drawRollSpriteActor)
|
||||
{
|
||||
|
@ -470,6 +479,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp)
|
|||
}
|
||||
|
||||
mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center
|
||||
|
||||
v[0] = mat * FVector3(x1, z1, y1);
|
||||
v[1] = mat * FVector3(x2, z1, y2);
|
||||
v[2] = mat * FVector3(x1, z2, y1);
|
||||
|
@ -919,6 +929,9 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
if (!tex || !tex->isValid()) return;
|
||||
auto& spi = tex->GetSpritePositioning(type == RF_FACESPRITE);
|
||||
|
||||
offx = (float)thing->SpriteOffset.X;
|
||||
offy = (float)thing->SpriteOffset.Y;
|
||||
|
||||
vt = spi.GetSpriteVT();
|
||||
vb = spi.GetSpriteVB();
|
||||
if (thing->renderflags & RF_YFLIP) std::swap(vt, vb);
|
||||
|
@ -941,7 +954,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
ur = spi.GetSpriteUL();
|
||||
}
|
||||
|
||||
texture = TexMan.GetGameTexture(patch, false);
|
||||
texture = tex;
|
||||
if (!texture || !texture->isValid())
|
||||
return;
|
||||
|
||||
|
@ -950,10 +963,9 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
|
||||
r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 : sprscale.Y);
|
||||
|
||||
float SpriteOffY = thing->SpriteOffset.Y;
|
||||
float rightfac = -r.left - thing->SpriteOffset.X;
|
||||
float rightfac = -r.left;
|
||||
float leftfac = rightfac - r.width;
|
||||
z1 = z - r.top - SpriteOffY;
|
||||
z1 = z - r.top;
|
||||
z2 = z1 - r.height;
|
||||
|
||||
float spriteheight = sprscale.Y * r.height;
|
||||
|
@ -979,7 +991,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
}
|
||||
case RF_FLATSPRITE:
|
||||
{
|
||||
float bottomfac = -r.top - SpriteOffY;
|
||||
float bottomfac = -r.top;
|
||||
float topfac = bottomfac - r.height;
|
||||
|
||||
x1 = x + leftfac;
|
||||
|
@ -989,8 +1001,8 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
|
|||
// [MC] Counteract in case of any potential problems. Tests so far haven't
|
||||
// shown any outstanding issues but that doesn't mean they won't appear later
|
||||
// when more features are added.
|
||||
z1 += SpriteOffY;
|
||||
z2 += SpriteOffY;
|
||||
z1 += offy;
|
||||
z2 += offy;
|
||||
break;
|
||||
}
|
||||
case RF_WALLSPRITE:
|
||||
|
@ -1245,11 +1257,27 @@ 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)
|
||||
{
|
||||
if (particle->alpha==0) return;
|
||||
if (!particle || particle->alpha <= 0)
|
||||
return;
|
||||
|
||||
lightlevel = hw_ClampLight(sector->GetSpriteLight());
|
||||
DZSprite *spr = particle->sprite;
|
||||
if (spr && spr->Texture.isNull())
|
||||
return;
|
||||
|
||||
lightlevel = hw_ClampLight(spr ? spr->GetLightLevel(sector) : sector->GetSpriteLight());
|
||||
foglevel = (uint8_t)clamp<short>(sector->lightlevel, 0, 255);
|
||||
|
||||
trans = particle->alpha;
|
||||
OverrideShader = 0;
|
||||
modelframe = nullptr;
|
||||
texture = nullptr;
|
||||
topclip = LARGE_VALUE;
|
||||
bottomclip = -LARGE_VALUE;
|
||||
index = 0;
|
||||
actor = nullptr;
|
||||
this->particle = particle;
|
||||
fullbright = particle->bright;
|
||||
|
||||
if (di->isFullbrightScene())
|
||||
{
|
||||
Colormap.Clear();
|
||||
|
@ -1284,8 +1312,6 @@ void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
|
|||
Colormap.ClearColor();
|
||||
}
|
||||
|
||||
trans=particle->alpha;
|
||||
|
||||
if(particle->style != STYLE_None)
|
||||
{
|
||||
RenderStyle = particle->style;
|
||||
|
@ -1295,91 +1321,85 @@ void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
|
|||
RenderStyle = STYLE_Translucent;
|
||||
}
|
||||
|
||||
OverrideShader = 0;
|
||||
|
||||
ThingColor = particle->color;
|
||||
ThingColor.a = 255;
|
||||
const auto& vp = di->Viewpoint;
|
||||
|
||||
modelframe=nullptr;
|
||||
texture=nullptr;
|
||||
topclip = LARGE_VALUE;
|
||||
bottomclip = -LARGE_VALUE;
|
||||
index = 0;
|
||||
|
||||
bool has_texture = !particle->texture.isNull();
|
||||
|
||||
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
|
||||
if (particle_style)
|
||||
if (spr)
|
||||
AdjustZSprite(di, spr, sector);
|
||||
else
|
||||
{
|
||||
FTextureID lump;
|
||||
if (particle_style == 1)
|
||||
bool has_texture = !particle->texture.isNull();
|
||||
|
||||
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
|
||||
if (particle_style)
|
||||
{
|
||||
lump = TexMan.glPart2;
|
||||
}
|
||||
else if (particle_style == 2)
|
||||
{
|
||||
lump = has_texture ? particle -> texture : TexMan.glPart;
|
||||
}
|
||||
else lump.SetNull();
|
||||
FTextureID lump;
|
||||
if (particle_style == 1)
|
||||
{
|
||||
lump = TexMan.glPart2;
|
||||
}
|
||||
else if (particle_style == 2)
|
||||
{
|
||||
lump = has_texture ? particle->texture : TexMan.glPart;
|
||||
}
|
||||
else lump.SetNull();
|
||||
|
||||
if (lump.isValid())
|
||||
{
|
||||
translation = NO_TRANSLATION;
|
||||
//auto tex = TexMan.GetGameTexture(lump, false);
|
||||
|
||||
ul = 0;
|
||||
ur = 1;
|
||||
vt = 0;
|
||||
vb = 1;
|
||||
texture = TexMan.GetGameTexture(lump, true);
|
||||
ul = 0;
|
||||
ur = 1;
|
||||
vt = 0;
|
||||
vb = 1;
|
||||
texture = TexMan.GetGameTexture(lump, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto &vp = di->Viewpoint;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
x = float(particle->Pos.X) + xvf;
|
||||
y = float(particle->Pos.Y) + yvf;
|
||||
z = float(particle->Pos.Z) + zvf;
|
||||
x = float(particle->Pos.X) + xvf;
|
||||
y = float(particle->Pos.Y) + yvf;
|
||||
z = float(particle->Pos.Z) + zvf;
|
||||
|
||||
if(particle->flags & PT_DOROLL)
|
||||
{
|
||||
float rvf = (particle->RollVel) * timefrac;
|
||||
Angles.Roll = TAngle<double>::fromDeg(particle->Roll + rvf);
|
||||
}
|
||||
if(particle->flags & SPF_ROLL)
|
||||
{
|
||||
float rvf = (particle->RollVel) * timefrac;
|
||||
Angles.Roll = TAngle<double>::fromDeg(particle->Roll + rvf);
|
||||
}
|
||||
|
||||
float factor;
|
||||
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 factor;
|
||||
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 viewvecX = vp.ViewVector.X;
|
||||
float viewvecY = vp.ViewVector.Y;
|
||||
float viewvecX = vp.ViewVector.X * scalefac;
|
||||
float viewvecY = vp.ViewVector.Y * scalefac;
|
||||
|
||||
x1=x+viewvecY*scalefac;
|
||||
x2=x-viewvecY*scalefac;
|
||||
y1=y-viewvecX*scalefac;
|
||||
y2=y+viewvecX*scalefac;
|
||||
z1=z-scalefac;
|
||||
z2=z+scalefac;
|
||||
x1=x+viewvecY;
|
||||
x2=x-viewvecY;
|
||||
y1=y-viewvecX;
|
||||
y2=y+viewvecX;
|
||||
z1=z-scalefac;
|
||||
z2=z+scalefac;
|
||||
|
||||
depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
||||
|
||||
actor=nullptr;
|
||||
this->particle=particle;
|
||||
fullbright = !!particle->bright;
|
||||
depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
||||
|
||||
// [BB] Translucent particles have to be rendered without the alpha test.
|
||||
if (particle_style != 2 && trans>=1.0f-FLT_EPSILON) hw_styleflags = STYLEHW_Solid;
|
||||
else hw_styleflags = STYLEHW_NoAlphaTest;
|
||||
// [BB] Translucent particles have to be rendered without the alpha test.
|
||||
if (particle_style != 2 && trans>=1.0f-FLT_EPSILON) hw_styleflags = STYLEHW_Solid;
|
||||
else hw_styleflags = STYLEHW_NoAlphaTest;
|
||||
}
|
||||
|
||||
if (sector->e->XFloor.lightlist.Size() != 0 && !di->isFullbrightScene() && !fullbright)
|
||||
lightlist = §or->e->XFloor.lightlist;
|
||||
|
@ -1390,6 +1410,63 @@ void HWSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
|
|||
rendered_sprites++;
|
||||
}
|
||||
|
||||
// [MC] ZSprites are to be rendered akin to actor sprites.
|
||||
void HWSprite::AdjustZSprite(HWDrawInfo* di, DZSprite* spr, sector_t* sector)
|
||||
{
|
||||
translation = spr->Translation;
|
||||
texture = TexMan.GetGameTexture(spr->Texture, true);
|
||||
|
||||
const auto& vp = di->Viewpoint;
|
||||
double timefrac = vp.TicFrac;
|
||||
if (paused || spr->isFrozen() || spr->bDontInterpolate)
|
||||
timefrac = 0.;
|
||||
|
||||
FVector3 interp = spr->InterpolatedPosition(timefrac);
|
||||
x = interp.X;
|
||||
y = interp.Y;
|
||||
z = interp.Z;
|
||||
|
||||
offx = (float)spr->Offset.X;
|
||||
offy = (float)spr->Offset.Y;
|
||||
|
||||
if (spr->Flags & SPF_ROLL)
|
||||
Angles.Roll = TAngle<double>::fromDeg(spr->InterpolatedRoll(timefrac));
|
||||
|
||||
auto& spi = texture->GetSpritePositioning(0);
|
||||
|
||||
vt = spi.GetSpriteVT();
|
||||
vb = spi.GetSpriteVB();
|
||||
ul = spi.GetSpriteUR();
|
||||
ur = spi.GetSpriteUL();
|
||||
|
||||
auto r = spi.GetSpriteRect();
|
||||
r.Scale(spr->Scale.X, spr->Scale.Y);
|
||||
|
||||
if (spr->bXFlip)
|
||||
{
|
||||
std::swap(ul,ur);
|
||||
r.left = -r.width - r.left; // mirror the sprite's x-offset
|
||||
}
|
||||
if (spr->bYFlip) std::swap(vt,vb);
|
||||
|
||||
float viewvecX = vp.ViewVector.X;
|
||||
float viewvecY = vp.ViewVector.Y;
|
||||
float rightfac = -r.left;
|
||||
float leftfac = rightfac - r.width;
|
||||
|
||||
x1 = x - viewvecY * leftfac;
|
||||
x2 = x - viewvecY * rightfac;
|
||||
y1 = y + viewvecX * leftfac;
|
||||
y2 = y + viewvecX * rightfac;
|
||||
z1 = z - r.top;
|
||||
z2 = z1 - r.height;
|
||||
|
||||
depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin);
|
||||
|
||||
// [BB] Translucent particles have to be rendered without the alpha test.
|
||||
hw_styleflags = STYLEHW_NoAlphaTest;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -926,6 +926,11 @@ static DObject *BuiltinNewDoom(PClass *cls, int outerside, int backwardscompatib
|
|||
ThrowAbortException(X_OTHER, "Cannot create actors with 'new'");
|
||||
return nullptr;
|
||||
}
|
||||
if (cls->IsDescendantOf(NAME_ZSprite)) // Same for ZSprites.
|
||||
{
|
||||
ThrowAbortException(X_OTHER, "Cannot create ZSprite or inheriting classes with 'new'. Use 'ZSprite.Spawn' instead.");
|
||||
return nullptr;
|
||||
}
|
||||
if ((vm_warnthinkercreation || !backwardscompatible) && cls->IsDescendantOf(NAME_Thinker))
|
||||
{
|
||||
// This must output a diagnostic warning
|
||||
|
|
|
@ -42,6 +42,7 @@ version "4.12"
|
|||
#include "zscript/destructible.zs"
|
||||
#include "zscript/level_postprocessor.zs"
|
||||
#include "zscript/level_compatibility.zs"
|
||||
#include "zscript/zsprite.zs"
|
||||
|
||||
#include "zscript/actors/actor.zs"
|
||||
#include "zscript/actors/checks.zs"
|
||||
|
|
|
@ -545,6 +545,7 @@ struct LevelLocals native
|
|||
native String GetEpisodeName();
|
||||
|
||||
native void SpawnParticle(FSpawnParticleParams p);
|
||||
native ZSprite SpawnZSprite(Class<ZSprite> type);
|
||||
}
|
||||
|
||||
// a few values of this need to be readable by the play code.
|
||||
|
|
41
wadsrc/static/zscript/zsprite.zs
Normal file
41
wadsrc/static/zscript/zsprite.zs
Normal file
|
@ -0,0 +1,41 @@
|
|||
Class ZSprite : Thinker native
|
||||
{
|
||||
native Vector3 Pos, Vel, Prev;
|
||||
native Vector2 Scale, Offset;
|
||||
native double Roll, Alpha;
|
||||
native TextureID Texture;
|
||||
native uint Translation;
|
||||
native uint16 Flags;
|
||||
native int16 LightLevel;
|
||||
native bool bXFlip, bYFlip,
|
||||
bDontInterpolate,
|
||||
bAddLightLevel;
|
||||
|
||||
native Sector CurSector; // can be null!
|
||||
|
||||
native void SetTranslation(Name trans);
|
||||
native void SetRenderStyle(int mode); // see ERenderStyle
|
||||
native bool IsFrozen();
|
||||
|
||||
static ZSprite Spawn(Class<ZSprite> type, TextureID tex, Vector3 pos, Vector3 vel, double alpha = 1.0, int flags = 0,
|
||||
double roll = 0.0, Vector2 scale = (1,1), Vector2 offset = (0,0), int style = STYLE_Normal, int trans = 0)
|
||||
{
|
||||
if (!Level) return null;
|
||||
|
||||
let p = level.SpawnZSprite(type);
|
||||
if (p)
|
||||
{
|
||||
p.Texture = tex;
|
||||
p.Pos = pos;
|
||||
p.Vel = vel;
|
||||
p.Alpha = alpha;
|
||||
p.Roll = roll;
|
||||
p.Scale = scale;
|
||||
p.Offset = offset;
|
||||
p.SetRenderStyle(style);
|
||||
p.Translation = trans;
|
||||
p.Flags = flags;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue