From a1ad9d8113827f41398f45cf72a64f3e6b3ca43d Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Sun, 16 Mar 2025 12:37:54 -0600 Subject: [PATCH 1/4] Viewed-Angle-dependent sprite rolling flags for rendering realistic sprite-actor tilts. Good with mirrors and multiplayer lean mechanics. --- src/playsim/actor.h | 3 ++ src/playsim/p_mobj.cpp | 1 + src/rendering/hwrenderer/scene/hw_sprites.cpp | 28 +++++++++++++++++++ src/scripting/thingdef_data.cpp | 2 ++ src/scripting/thingdef_properties.cpp | 19 +++++++++++++ src/scripting/vmthunks_actors.cpp | 1 + wadsrc/static/zscript/actors/actor.zs | 2 ++ 7 files changed, 56 insertions(+) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 3339adeb99..be4c3a9b0f 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -508,6 +508,8 @@ enum ActorRenderFlag2 RF2_ISOMETRICSPRITES = 0x0080, RF2_SQUAREPIXELS = 0x0100, // apply +ROLLSPRITE scaling math so that non rolling sprites get the same scaling RF2_STRETCHPIXELS = 0x0200, // don't apply SQUAREPIXELS for ROLLSPRITES + RF2_ANGLEDROLL = 0x0400, // Sprite roll amount depends on (actor.Angle - actor.AngledRollOffset) + RF2_ANGLEDROLLYSCALE = 0x0800, // Sprite y-scales to simulate projected height on angled roll }; // This translucency value produces the closest match to Heretic's TINTTAB. @@ -1123,6 +1125,7 @@ public: DAngle SpriteAngle; DAngle SpriteRotation; + DAngle AngledRollOffset; // Offset for angle-dependent sprite rolling (see RF2_ANGLEDROLL, RF2_ANGLEDROLLYSCALE) DVector2 AutomapOffsets; // Offset the actors' sprite view on the automap by these coordinates. float isoscaleY; // Y-scale to compensate for Y-billboarding for isometric sprites float isotheta; // Rotation angle to compensate for Y-billboarding for isometric sprites diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 8dc686f71c..e78229e08e 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -395,6 +395,7 @@ void AActor::Serialize(FSerializer &arc) A("devthreshold", DefThreshold) A("spriteangle", SpriteAngle) A("spriterotation", SpriteRotation) + A("angledrolloffset", AngledRollOffset) ("alternative", alternative) A("thrubits", ThruBits) A("cameraheight", CameraHeight) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 26643e7459..812fc9d823 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -421,6 +421,10 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) const bool drawRollParticle = (particle != nullptr && particle->flags & SPF_ROLL); const bool doRoll = (drawRollSpriteActor || drawRollParticle); + // [DVR] +ANGLEDROLL, +ANGLEDROLLYSCALE + const bool AngledRoll = (actor != nullptr && actor->renderflags2 & RF2_ANGLEDROLL); + const bool AngledRollYScale = (actor != nullptr && actor->renderflags2 & RF2_ANGLEDROLLYSCALE); + // [fgsfds] check sprite type mask uint32_t spritetype = (uint32_t)-1; if (actor != nullptr) spritetype = actor->renderflags & RF_SPRITETYPEMASK; @@ -516,11 +520,35 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) // Compute center of sprite float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians(); float rollDegrees = Angles.Roll.Degrees(); + float AngledRollScaleFactor = 1.0; + + if (AngledRoll) + { + rollDegrees = fmodf(rollDegrees, 360.0f); + DAngle ang = (actor->Pos() - di->Viewpoint.Pos).Angle(); + if (di->Viewpoint.IsOrtho()) ang = di->Viewpoint.Angles.Yaw; + ang += actor->AngledRollOffset; + DAngle sprang = actor->GetSpriteAngle(ang, di->Viewpoint.TicFrac); + + // [DVR] Jerky angle-shift at cardinal roll angles when viewed from 45-degrees, etc. + if (rollDegrees < 90.0) rollDegrees *= sprang.Cos(); + else if (rollDegrees > 270.0) rollDegrees = (rollDegrees - 360.0) * sprang.Cos(); + else rollDegrees += (180.0 - rollDegrees) * (1.0 - sprang.Cos()); + + if (AngledRollYScale) + { + float cos2sprang = cos( M_PI * (sprang.Degrees()) / 90.0); + float cosroll = fabs(Angles.Roll.Cos()); + AngledRollScaleFactor = 0.5 * (1.0 + cosroll); + AngledRollScaleFactor += 0.5 * (1.0 - cosroll) * cos2sprang; + } + } mat.Translate(center.X, center.Z, center.Y); mat.Scale(1.0, 1.0/pixelstretch, 1.0); // unstretch sprite by level aspect ratio if (useOffsets) mat.Translate(xx, zz, yy); mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); + if (AngledRollYScale) mat.Scale(1.0, AngledRollScaleFactor, 1.0); if (useOffsets) mat.Translate(-xx, -zz, -yy); mat.Scale(1.0, pixelstretch, 1.0); // stretch sprite by level aspect ratio mat.Translate(-center.X, -center.Z, -center.Y); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index c1e8dd045f..525ff45e96 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -390,6 +390,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF2, ISOMETRICSPRITES, AActor, renderflags2), DEFINE_FLAG(RF2, SQUAREPIXELS, AActor, renderflags2), DEFINE_FLAG(RF2, STRETCHPIXELS, AActor, renderflags2), + DEFINE_FLAG(RF2, ANGLEDROLL, AActor, renderflags2), + DEFINE_FLAG(RF2, ANGLEDROLLYSCALE, AActor, renderflags2), // Bounce flags DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags), diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 2154f4db59..73ee3fdb37 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -602,6 +602,16 @@ DEFINE_PROPERTY(tag, S, Actor) defaults->SetTag(str); } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(leanroll, 0, Actor) +{ + // sets the standard flags for a monster + defaults->renderflags|=RF_ROLLSPRITE|RF_ROLLCENTER; + defaults->renderflags2|=RF2_STRETCHPIXELS|RF2_ANGLEDROLL|RF2_ANGLEDROLLYSCALE; +} + //========================================================================== // //========================================================================== @@ -1023,6 +1033,15 @@ DEFINE_PROPERTY(spriteangle, F, Actor) defaults->SpriteAngle = DAngle::fromDeg(i); } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(angledrolloffset, F, Actor) +{ + PROP_DOUBLE_PARM(i, 0); + defaults->AngledRollOffset = DAngle::fromDeg(i); +} + //========================================================================== // //========================================================================== diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index f5efbab3a3..d5b72c5ad4 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -1951,6 +1951,7 @@ DEFINE_FIELD(AActor, WorldOffset) DEFINE_FIELD(AActor, Prev) DEFINE_FIELD(AActor, SpriteAngle) DEFINE_FIELD(AActor, SpriteRotation) +DEFINE_FIELD(AActor, AngledRollOffset) DEFINE_FIELD(AActor, VisibleStartAngle) DEFINE_FIELD(AActor, VisibleStartPitch) DEFINE_FIELD(AActor, VisibleEndAngle) diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 31b44fa1d3..de059ca163 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -128,6 +128,7 @@ class Actor : Thinker native native double Angle; native double Pitch; native double Roll; + native double AngledRollOffset; native vector3 Vel; native double Speed; native double FloatSpeed; @@ -463,6 +464,7 @@ class Actor : Thinker native MissileHeight 32; SpriteAngle 0; SpriteRotation 0; + AngledRollOffset 0; StencilColor "00 00 00"; VisibleAngles 0, 0; VisiblePitch 0, 0; From a22f57c3ae667def75afcf335cfaf92574e58684 Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Sat, 22 Mar 2025 13:04:08 -0600 Subject: [PATCH 2/4] Actually tilting the angled-roll sprite in 3D-space for proper occlusion (think lasers). --- src/playsim/actor.h | 3 +- src/rendering/hwrenderer/scene/hw_sprites.cpp | 60 +++++++++++-------- src/scripting/thingdef_data.cpp | 1 - src/scripting/thingdef_properties.cpp | 6 +- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index be4c3a9b0f..c882012358 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -509,7 +509,6 @@ enum ActorRenderFlag2 RF2_SQUAREPIXELS = 0x0100, // apply +ROLLSPRITE scaling math so that non rolling sprites get the same scaling RF2_STRETCHPIXELS = 0x0200, // don't apply SQUAREPIXELS for ROLLSPRITES RF2_ANGLEDROLL = 0x0400, // Sprite roll amount depends on (actor.Angle - actor.AngledRollOffset) - RF2_ANGLEDROLLYSCALE = 0x0800, // Sprite y-scales to simulate projected height on angled roll }; // This translucency value produces the closest match to Heretic's TINTTAB. @@ -1125,7 +1124,7 @@ public: DAngle SpriteAngle; DAngle SpriteRotation; - DAngle AngledRollOffset; // Offset for angle-dependent sprite rolling (see RF2_ANGLEDROLL, RF2_ANGLEDROLLYSCALE) + DAngle AngledRollOffset; // Offset for angle-dependent sprite rolling (see RF2_ANGLEDROLL) DVector2 AutomapOffsets; // Offset the actors' sprite view on the automap by these coordinates. float isoscaleY; // Y-scale to compensate for Y-billboarding for isometric sprites float isotheta; // Rotation angle to compensate for Y-billboarding for isometric sprites diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 812fc9d823..cc7bfabd3a 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -421,9 +421,8 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) const bool drawRollParticle = (particle != nullptr && particle->flags & SPF_ROLL); const bool doRoll = (drawRollSpriteActor || drawRollParticle); - // [DVR] +ANGLEDROLL, +ANGLEDROLLYSCALE + // [DVR] +ANGLEDROLL const bool AngledRoll = (actor != nullptr && actor->renderflags2 & RF2_ANGLEDROLL); - const bool AngledRollYScale = (actor != nullptr && actor->renderflags2 & RF2_ANGLEDROLLYSCALE); // [fgsfds] check sprite type mask uint32_t spritetype = (uint32_t)-1; @@ -520,38 +519,35 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) // Compute center of sprite float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians(); float rollDegrees = Angles.Roll.Degrees(); - float AngledRollScaleFactor = 1.0; + float pitchDegrees = 0.0; if (AngledRoll) { rollDegrees = fmodf(rollDegrees, 360.0f); - DAngle ang = (actor->Pos() - di->Viewpoint.Pos).Angle(); - if (di->Viewpoint.IsOrtho()) ang = di->Viewpoint.Angles.Yaw; - ang += actor->AngledRollOffset; - DAngle sprang = actor->GetSpriteAngle(ang, di->Viewpoint.TicFrac); + DAngle ang = di->Viewpoint.Angles.Yaw + actor->Angles.Yaw + actor->AngledRollOffset - DAngle::fromDeg(90.0); + angleRad = ang.Radians(); + FVector3 relPos = center - FVector3(di->Viewpoint.Pos); + if (useOffsets) relPos += FVector3(xx, yy, zz); + pitchDegrees = 270.0 - DVector3(relPos).Angle().Degrees(); - // [DVR] Jerky angle-shift at cardinal roll angles when viewed from 45-degrees, etc. - if (rollDegrees < 90.0) rollDegrees *= sprang.Cos(); - else if (rollDegrees > 270.0) rollDegrees = (rollDegrees - 360.0) * sprang.Cos(); - else rollDegrees += (180.0 - rollDegrees) * (1.0 - sprang.Cos()); - - if (AngledRollYScale) - { - float cos2sprang = cos( M_PI * (sprang.Degrees()) / 90.0); - float cosroll = fabs(Angles.Roll.Cos()); - AngledRollScaleFactor = 0.5 * (1.0 + cosroll); - AngledRollScaleFactor += 0.5 * (1.0 - cosroll) * cos2sprang; - } + Matrix3x4 rolltilt; + rolltilt.MakeIdentity(); + ang = actor->Angles.Yaw + actor->AngledRollOffset; + rolltilt.Rotate(ang.Cos(), ang.Sin(), 0.0, -rollDegrees); + float between = (DVector3(rolltilt * relPos).Angle() - (actor->Pos() - di->Viewpoint.Pos).Angle()).Degrees(); + if (fabs(between) > 90.0) pitchDegrees *= -1.0; + if (Angles.Roll.Cos() < 0.0) pitchDegrees *= -1.0; } - mat.Translate(center.X, center.Z, center.Y); mat.Scale(1.0, 1.0/pixelstretch, 1.0); // unstretch sprite by level aspect ratio + mat.Translate(center.X, center.Z, center.Y); if (useOffsets) mat.Translate(xx, zz, yy); + if (AngledRoll) mat.Rotate(0.0, 1.0, 0.0, -HWAngles.Yaw.Degrees()); // Cancel regular Y-billboarding mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); - if (AngledRollYScale) mat.Scale(1.0, AngledRollScaleFactor, 1.0); + if (AngledRoll) mat.Rotate(0.0, 1.0, 0.0, pitchDegrees); // New Y-billboarding about rolled z-axis if (useOffsets) mat.Translate(-xx, -zz, -yy); - mat.Scale(1.0, pixelstretch, 1.0); // stretch sprite by level aspect ratio mat.Translate(-center.X, -center.Z, -center.Y); + mat.Scale(1.0, pixelstretch, 1.0); // stretch sprite by level aspect ratio } if (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES) && di->Viewpoint.IsOrtho()) @@ -956,8 +952,22 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (!modelframe) { bool mirror = false; + bool backfaced = false; DAngle ang = (thingpos - vp.Pos).Angle(); if (di->Viewpoint.IsOrtho()) ang = vp.Angles.Yaw; + else if (actor && thing->renderflags2 & RF2_ANGLEDROLL) + { + Matrix3x4 rolltilt; + rolltilt.MakeIdentity(); + DAngle tempang = thing->Angles.Yaw + thing->AngledRollOffset; + rolltilt.Rotate(tempang.Cos(), tempang.Sin(), 0.0, -thing->Angles.Roll.Degrees()); + tempang = DVector3(rolltilt * FVector3(thingpos - vp.Pos)).Angle(); + backfaced = fabs((ang - tempang).Degrees()) > 90.0; + if (backfaced) // (ang - tempang).Cos() < 0.0) + { + ang = DAngle::fromDeg(180.0) - ang; + } + } FTextureID patch; // [ZZ] add direct picnum override if (isPicnumOverride) @@ -1029,7 +1039,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t auto r = spi.GetSpriteRect(); // [SP] SpriteFlip - if (thing->renderflags & RF_SPRITEFLIP) + if ((thing->renderflags & RF_SPRITEFLIP) || backfaced) thing->renderflags ^= RF_XFLIP; if (mirror ^ !!(thing->renderflags & RF_XFLIP)) @@ -1048,7 +1058,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (!texture || !texture->isValid()) return; - if (thing->renderflags & RF_SPRITEFLIP) // [SP] Flip back + if ((thing->renderflags & RF_SPRITEFLIP) || backfaced) // [SP] Flip back thing->renderflags ^= RF_XFLIP; // If sprite is isometric, do both vertical scaling and partial rotation to face the camera to compensate for Y-billboarding. @@ -1199,7 +1209,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t z1 = z1 * spbias + vpz * vpbias; x2 = x2 * spbias + vpx * vpbias; y2 = y2 * spbias + vpy * vpbias; - z2 = z2 * spbias + vpz * vpbias; + z2 = z2 * spbias + vpz * vpbias; } // light calculation diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 525ff45e96..f57395cf1c 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -391,7 +391,6 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF2, SQUAREPIXELS, AActor, renderflags2), DEFINE_FLAG(RF2, STRETCHPIXELS, AActor, renderflags2), DEFINE_FLAG(RF2, ANGLEDROLL, AActor, renderflags2), - DEFINE_FLAG(RF2, ANGLEDROLLYSCALE, AActor, renderflags2), // Bounce flags DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags), diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 73ee3fdb37..dd03c27c5b 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -607,9 +607,9 @@ DEFINE_PROPERTY(tag, S, Actor) //========================================================================== DEFINE_PROPERTY(leanroll, 0, Actor) { - // sets the standard flags for a monster - defaults->renderflags|=RF_ROLLSPRITE|RF_ROLLCENTER; - defaults->renderflags2|=RF2_STRETCHPIXELS|RF2_ANGLEDROLL|RF2_ANGLEDROLLYSCALE; + // sets the standard flags for angle-dependent roll + defaults->renderflags|=RF_ROLLSPRITE; + defaults->renderflags2|=RF2_STRETCHPIXELS|RF2_ANGLEDROLL; } //========================================================================== From 8bc529d7eb42cc03e3d2418f895b453757b51002 Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Sat, 22 Mar 2025 13:12:48 -0600 Subject: [PATCH 3/4] Superfluous additional sprite x-flips removed. --- src/rendering/hwrenderer/scene/hw_sprites.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index cc7bfabd3a..a5d12add32 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -1039,7 +1039,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t auto r = spi.GetSpriteRect(); // [SP] SpriteFlip - if ((thing->renderflags & RF_SPRITEFLIP) || backfaced) + if (thing->renderflags & RF_SPRITEFLIP) thing->renderflags ^= RF_XFLIP; if (mirror ^ !!(thing->renderflags & RF_XFLIP)) @@ -1058,7 +1058,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (!texture || !texture->isValid()) return; - if ((thing->renderflags & RF_SPRITEFLIP) || backfaced) // [SP] Flip back + if (thing->renderflags & RF_SPRITEFLIP) // [SP] Flip back thing->renderflags ^= RF_XFLIP; // If sprite is isometric, do both vertical scaling and partial rotation to face the camera to compensate for Y-billboarding. From 34370d96320709b01ad9fca7e90918fa86f0d641 Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Sat, 22 Mar 2025 21:06:13 -0600 Subject: [PATCH 4/4] Sprite occlusion depth now computed from center of sprite instead of actor position. Not perfect but pretty good. --- src/rendering/hwrenderer/scene/hw_sprites.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index a5d12add32..6414c6e4b2 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -528,26 +528,23 @@ bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) angleRad = ang.Radians(); FVector3 relPos = center - FVector3(di->Viewpoint.Pos); if (useOffsets) relPos += FVector3(xx, yy, zz); - pitchDegrees = 270.0 - DVector3(relPos).Angle().Degrees(); Matrix3x4 rolltilt; rolltilt.MakeIdentity(); ang = actor->Angles.Yaw + actor->AngledRollOffset; rolltilt.Rotate(ang.Cos(), ang.Sin(), 0.0, -rollDegrees); - float between = (DVector3(rolltilt * relPos).Angle() - (actor->Pos() - di->Viewpoint.Pos).Angle()).Degrees(); - if (fabs(between) > 90.0) pitchDegrees *= -1.0; - if (Angles.Roll.Cos() < 0.0) pitchDegrees *= -1.0; + pitchDegrees = 270.0 - DVector3(rolltilt * relPos).Angle().Degrees(); } - mat.Scale(1.0, 1.0/pixelstretch, 1.0); // unstretch sprite by level aspect ratio mat.Translate(center.X, center.Z, center.Y); if (useOffsets) mat.Translate(xx, zz, yy); + mat.Scale(1.0, 1.0/pixelstretch, 1.0); // unstretch sprite by level aspect ratio if (AngledRoll) mat.Rotate(0.0, 1.0, 0.0, -HWAngles.Yaw.Degrees()); // Cancel regular Y-billboarding mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); if (AngledRoll) mat.Rotate(0.0, 1.0, 0.0, pitchDegrees); // New Y-billboarding about rolled z-axis + mat.Scale(1.0, pixelstretch, 1.0); // stretch sprite by level aspect ratio if (useOffsets) mat.Translate(-xx, -zz, -yy); mat.Translate(-center.X, -center.Z, -center.Y); - mat.Scale(1.0, pixelstretch, 1.0); // stretch sprite by level aspect ratio } if (actor && (actor->renderflags2 & RF2_ISOMETRICSPRITES) && di->Viewpoint.IsOrtho()) @@ -1160,6 +1157,15 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t depth = (float)((x - vp.Pos.X) * vp.TanCos + (y - vp.Pos.Y) * vp.TanSin); if(thing->renderflags2 & RF2_ISOMETRICSPRITES) depth = depth * vp.PitchCos - vp.PitchSin * z2; // Helps with stacking actors with small xy offsets + if(actor && (thing->renderflags2 & RF2_ANGLEDROLL) && !(thing->renderflags & RF_ROLLCENTER)) + { + double rollsin = thing->Angles.Roll.Sin(); + DAngle tempang2 = thing->Angles.Yaw + thing->AngledRollOffset + DAngle::fromDeg(rollsin < 0.0 + ? 90.0 : -90.0); + double r2 = 0.5 * fabs((z2 - z1) * rollsin); + depth = (float)((x + r2 * tempang2.Cos() - vp.Pos.X) * vp.TanCos + + (y + r2 * tempang2.Sin() - vp.Pos.Y) * vp.TanSin); + } if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite. if (gl_spriteclip == -1 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE) // perform anamorphosis