Aded FLIPSPRITEOFFSET<X/Y> for actors and bFlipOffset<X/Y> for visual thinkers.

- Inverts the direction that (Sprite)Offset pushes the sprite without affecting *any* other offsets, allowing them to combine seemlessly.
This commit is contained in:
Major Cooke 2024-01-19 21:29:57 -06:00 committed by Rachael Alexanderson
parent 4e48250cf2
commit 278ebf3202
8 changed files with 37 additions and 11 deletions

View file

@ -498,6 +498,8 @@ enum ActorRenderFlag2
RF2_ONLYVISIBLEINMIRRORS = 0x0002, // [Nash] only renders in mirrors
RF2_BILLBOARDFACECAMERA = 0x0004, // Sprite billboard face camera (override gl_billboard_faces_camera)
RF2_BILLBOARDNOFACECAMERA = 0x0008, // Sprite billboard face camera angle (override gl_billboard_faces_camera)
RF2_FLIPSPRITEOFFSETX = 0x0010,
RF2_FLIPSPRITEOFFSETY = 0x0020,
};
// This translucency value produces the closest match to Heretic's TINTTAB.
@ -1472,6 +1474,11 @@ public:
result.Roll = PrevAngles.Roll + deltaangle(PrevAngles.Roll, Angles.Roll) * ticFrac;
return result;
}
float GetSpriteOffset(bool y) const
{
if (y) return (float)(renderflags2 & RF2_FLIPSPRITEOFFSETY ? SpriteOffset.Y : -SpriteOffset.Y);
else return (float)(renderflags2 & RF2_FLIPSPRITEOFFSETX ? SpriteOffset.X : -SpriteOffset.X);
}
DAngle GetSpriteAngle(DAngle viewangle, double ticFrac)
{
if (flags7 & MF7_SPRITEANGLE)

View file

@ -1206,7 +1206,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DVisualThinker, SetTranslation, SetTranslation)
static int IsFrozen(DVisualThinker * self)
{
return (self->Level->isFrozen() && !(self->PT.flags & SPF_NOTIMEFREEZE));
return !!(self->Level->isFrozen() && !(self->PT.flags & SPF_NOTIMEFREEZE));
}
bool DVisualThinker::isFrozen()
@ -1242,6 +1242,14 @@ int DVisualThinker::GetRenderStyle()
return PT.style;
}
float DVisualThinker::GetOffset(bool y) const // Needed for the renderer.
{
if (y)
return (float)(bFlipOffsetY ? Offset.Y : -Offset.Y);
else
return (float)(bFlipOffsetX ? Offset.X : -Offset.X);
}
void DVisualThinker::Serialize(FSerializer& arc)
{
Super::Serialize(arc);
@ -1264,6 +1272,8 @@ void DVisualThinker::Serialize(FSerializer& arc)
("flipy", bYFlip)
("dontinterpolate", bDontInterpolate)
("addlightlevel", bAddLightLevel)
("flipoffsetx", bFlipOffsetX)
("flipoffsetY", bFlipOffsetY)
("lightlevel", LightLevel)
("flags", PT.flags);
@ -1289,3 +1299,5 @@ DEFINE_FIELD(DVisualThinker, bXFlip);
DEFINE_FIELD(DVisualThinker, bYFlip);
DEFINE_FIELD(DVisualThinker, bDontInterpolate);
DEFINE_FIELD(DVisualThinker, bAddLightLevel);
DEFINE_FIELD(DVisualThinker, bFlipOffsetX);
DEFINE_FIELD(DVisualThinker, bFlipOffsetY);

View file

@ -166,7 +166,9 @@ public:
FTextureID AnimatedTexture;
sector_t *cursector;
bool bXFlip,
bool bFlipOffsetX,
bFlipOffsetY,
bXFlip,
bYFlip, // flip the sprite on the x/y axis.
bDontInterpolate, // disable all interpolation
bAddLightLevel; // adds sector light level to 'LightLevel'
@ -191,4 +193,5 @@ public:
void UpdateSpriteInfo();
void Serialize(FSerializer& arc) override;
};
float GetOffset(bool y) const;
};

View file

@ -414,7 +414,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp)
const bool isWallSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE);
const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER);
FVector2 offset = FVector2( -offx, -offy );
FVector2 offset = FVector2( offx, offy );
// Account for +ROLLCENTER flag. Takes the embedded image offsets and adds them in with SpriteOffsets.
if (drawRollSpriteActor && useOffsets)
@ -961,8 +961,8 @@ 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;
offx = (float)thing->GetSpriteOffset(false);
offy = (float)thing->GetSpriteOffset(true);
vt = spi.GetSpriteVT();
vb = spi.GetSpriteVB();
@ -1491,8 +1491,8 @@ void HWSprite::AdjustVisualThinker(HWDrawInfo* di, DVisualThinker* spr, sector_t
y = interp.Y;
z = interp.Z;
offx = (float)spr->Offset.X;
offy = (float)spr->Offset.Y;
offx = (float)spr->GetOffset(false);
offy = (float)spr->GetOffset(true);
if (spr->PT.flags & SPF_ROLL)
Angles.Roll = TAngle<double>::fromDeg(spr->InterpolatedRoll(timefrac));

View file

@ -1046,7 +1046,7 @@ namespace swrenderer
// The X offsetting (SpriteOffset.X) is performed in r_sprite.cpp, in RenderSprite::Project().
sprite.pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac);
sprite.pos += thing->WorldOffset;
sprite.pos.Z += thing->GetBobOffset(Thread->Viewport->viewpoint.TicFrac) - thing->SpriteOffset.Y;
sprite.pos.Z += thing->GetBobOffset(Thread->Viewport->viewpoint.TicFrac) + thing->GetSpriteOffset(true);
sprite.spritenum = thing->sprite;
sprite.tex = nullptr;
sprite.voxel = nullptr;

View file

@ -81,7 +81,7 @@ namespace swrenderer
const double thingxscalemul = spriteScale.X / tex->GetScale().X;
// Calculate billboard line for the sprite
double SpriteOffX = (thing) ? thing->SpriteOffset.X : 0.;
double SpriteOffX = (thing) ? -thing->GetSpriteOffset(false) : 0.;
DVector2 dir = { viewport->viewpoint.Sin, -viewport->viewpoint.Cos };
DVector2 trs = pos.XY() - viewport->viewpoint.Pos.XY();
trs = { trs.X + SpriteOffX * dir.X, trs.Y + SpriteOffX * dir.Y };

View file

@ -381,6 +381,8 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(RF2, ONLYVISIBLEINMIRRORS, AActor, renderflags2),
DEFINE_FLAG(RF2, BILLBOARDFACECAMERA, AActor, renderflags2),
DEFINE_FLAG(RF2, BILLBOARDNOFACECAMERA, AActor, renderflags2),
DEFINE_FLAG(RF2, FLIPSPRITEOFFSETX, AActor, renderflags2),
DEFINE_FLAG(RF2, FLIPSPRITEOFFSETY, AActor, renderflags2),
// Bounce flags
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),

View file

@ -12,7 +12,9 @@ Class VisualThinker : Thinker native
native TranslationID Translation;
native uint16 Flags;
native int16 LightLevel;
native bool bXFlip,
native bool bFlipOffsetX,
bFlipOffsetY,
bXFlip,
bYFlip,
bDontInterpolate,
bAddLightLevel;