diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 89404930e..492a4c2e6 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -1049,6 +1049,7 @@ public: DVector3 OldRenderPos; DVector3 Vel; DVector2 SpriteOffset; + DVector3 WorldOffset; double Speed; double FloatSpeed; diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 3416102b9..67073da00 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -371,7 +371,8 @@ void AActor::Serialize(FSerializer &arc) A("friction", Friction) A("SpriteOffset", SpriteOffset) ("viewpos", ViewPos) - A("userlights", UserLights); + A("userlights", UserLights) + A("WorldOffset", WorldOffset); SerializeTerrain(arc, "floorterrain", floorterrain, &def->floorterrain); SerializeArgs(arc, "args", args, def->args, special); diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index b6a9c204b..a9cf31608 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -702,7 +702,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t return; } - const auto &vp = di->Viewpoint; + const auto &vp = di->Viewpoint; AActor *camera = vp.camera; if (thing->renderflags & RF_INVISIBLE || !thing->RenderStyle.IsVisible(thing->Alpha)) @@ -797,9 +797,9 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t bottomclip = rendersector->PortalBlocksMovement(sector_t::floor) ? -LARGE_VALUE : rendersector->GetPortalPlaneZ(sector_t::floor); uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK); - x = thingpos.X; - z = thingpos.Z; - y = thingpos.Y; + x = thingpos.X + thing->WorldOffset.X; + z = thingpos.Z + thing->WorldOffset.Z; + y = thingpos.Y + thing->WorldOffset.Y; if (spritetype == RF_FACESPRITE) z -= thing->Floorclip; // wall and flat sprites are to be considered di->Level-> geometry so this may not apply. // snap shadow Z to the floor @@ -917,7 +917,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t thing->renderflags ^= RF_XFLIP; r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 : sprscale.Y); - + float SpriteOffY = thing->SpriteOffset.Y; float rightfac = -r.left - thing->SpriteOffset.X; float leftfac = rightfac - r.width; diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.cpp b/src/rendering/swrenderer/scene/r_opaque_pass.cpp index dc6d22e7e..2b83867f2 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.cpp +++ b/src/rendering/swrenderer/scene/r_opaque_pass.cpp @@ -1027,6 +1027,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.spritenum = thing->sprite; sprite.tex = nullptr; diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index d5fe7118b..37a9a0794 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -1851,6 +1851,7 @@ DEFINE_FIELD_NAMED(AActor, __Pos.X, x) DEFINE_FIELD_NAMED(AActor, __Pos.Y, y) DEFINE_FIELD_NAMED(AActor, __Pos.Z, z) DEFINE_FIELD(AActor, SpriteOffset) +DEFINE_FIELD(AActor, WorldOffset) DEFINE_FIELD(AActor, Prev) DEFINE_FIELD(AActor, SpriteAngle) DEFINE_FIELD(AActor, SpriteRotation) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 57ff2e587..b3989ede2 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -100,6 +100,7 @@ class Actor : Thinker native native vector3 Prev; native uint ThruBits; native vector2 SpriteOffset; + native vector3 WorldOffset; native double spriteAngle; native double spriteRotation; native float VisibleStartAngle;