From 278ebf3202e3559efb0608df05b9e1a996804822 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Fri, 19 Jan 2024 21:29:57 -0600 Subject: [PATCH] Aded `FLIPSPRITEOFFSET` for actors and `bFlipOffset` for visual thinkers. - Inverts the direction that (Sprite)Offset pushes the sprite without affecting *any* other offsets, allowing them to combine seemlessly. --- src/playsim/actor.h | 7 +++++++ src/playsim/p_effect.cpp | 14 +++++++++++++- src/playsim/p_effect.h | 7 +++++-- src/rendering/hwrenderer/scene/hw_sprites.cpp | 10 +++++----- src/rendering/swrenderer/scene/r_opaque_pass.cpp | 2 +- src/rendering/swrenderer/things/r_sprite.cpp | 2 +- src/scripting/thingdef_data.cpp | 2 ++ wadsrc/static/zscript/visualthinker.zs | 4 +++- 8 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 43e8b5b2e..d7b51b45a 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -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) diff --git a/src/playsim/p_effect.cpp b/src/playsim/p_effect.cpp index 430265a75..7b1b0a87b 100644 --- a/src/playsim/p_effect.cpp +++ b/src/playsim/p_effect.cpp @@ -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); diff --git a/src/playsim/p_effect.h b/src/playsim/p_effect.h index 98f3d6789..0f439785c 100644 --- a/src/playsim/p_effect.h +++ b/src/playsim/p_effect.h @@ -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; +}; \ No newline at end of file diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 59da44b84..09db1101d 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -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::fromDeg(spr->InterpolatedRoll(timefrac)); diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.cpp b/src/rendering/swrenderer/scene/r_opaque_pass.cpp index 17291bb49..f94244644 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.cpp +++ b/src/rendering/swrenderer/scene/r_opaque_pass.cpp @@ -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; diff --git a/src/rendering/swrenderer/things/r_sprite.cpp b/src/rendering/swrenderer/things/r_sprite.cpp index 39c2e82e3..b05a67448 100644 --- a/src/rendering/swrenderer/things/r_sprite.cpp +++ b/src/rendering/swrenderer/things/r_sprite.cpp @@ -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 }; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 49fc9bc5e..50b0589b1 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -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), diff --git a/wadsrc/static/zscript/visualthinker.zs b/wadsrc/static/zscript/visualthinker.zs index e18fe1823..12a8c41d6 100644 --- a/wadsrc/static/zscript/visualthinker.zs +++ b/wadsrc/static/zscript/visualthinker.zs @@ -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;