diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 6156f1f63c..59da44b840 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -340,19 +340,32 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) // //========================================================================== -bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) +void HandleSpriteOffsets(Matrix3x4 *mat, const FRotator *HW, FVector2 *offset, bool XYBillboard) { - const auto &HWAngles = di->Viewpoint.HWAngles; + FAngle zero = FAngle::fromDeg(0); + FAngle pitch = (XYBillboard) ? HW->Pitch : zero; + FAngle yaw = FAngle::fromDeg(270.) - HW->Yaw; + + FQuaternion quat = FQuaternion::FromAngles(yaw, pitch, zero); + FVector3 sideVec = quat * FVector3(0, 1, 0); + FVector3 upVec = quat * FVector3(0, 0, 1); + FVector3 res = sideVec * offset->X + upVec * offset->Y; + mat->Translate(res.X, res.Z, res.Y); +} + +bool HWSprite::CalculateVertices(HWDrawInfo* di, FVector3* v, DVector3* vp) +{ + FVector3 center = FVector3((x1 + x2) * 0.5, (y1 + y2) * 0.5, (z1 + z2) * 0.5); + const auto& HWAngles = di->Viewpoint.HWAngles; + Matrix3x4 mat; if (actor != nullptr && (actor->renderflags & RF_SPRITETYPEMASK) == RF_FLATSPRITE) { - Matrix3x4 mat; - mat.MakeIdentity(); - // [MC] Rotate around the center or offsets given to the sprites. // Counteract any existing rotations, then rotate the angle. // Tilt the actor up or down based on pitch (increase 'somersaults' forward). // Then counteract the roll and DO A BARREL ROLL. + mat.MakeIdentity(); FAngle pitch = FAngle::fromDeg(-Angles.Pitch.Degrees()); pitch.Normalized180(); @@ -362,12 +375,9 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) if (actor->renderflags & RF_ROLLCENTER) { - float cx = (x1 + x2) * 0.5; - float cy = (y1 + y2) * 0.5; - - mat.Translate(cx - x, 0, cy - y); + mat.Translate(center.X - x, 0, center.Y - y); mat.Rotate(0, 1, 0, - Angles.Roll.Degrees()); - mat.Translate(-cx, -z, -cy); + mat.Translate(-center.X, -z, -center.Y); } else { @@ -393,51 +403,45 @@ 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 & SPF_ROLL); - + const bool doRoll = (drawRollSpriteActor || drawRollParticle); // [fgsfds] check sprite type mask uint32_t spritetype = (uint32_t)-1; if (actor != nullptr) spritetype = actor->renderflags & RF_SPRITETYPEMASK; // [Nash] is a flat sprite - const bool isFlatSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE); + const bool isWallSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE); const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER); + FVector2 offset = FVector2( -offx, -offy ); + + // Account for +ROLLCENTER flag. Takes the embedded image offsets and adds them in with SpriteOffsets. + if (drawRollSpriteActor && useOffsets) + { + offset.X += center.X - x; + offset.Y += center.Z - z; + } + // [Nash] check for special sprite drawing modes - if (drawWithXYBillboard || drawBillboardFacingCamera || drawRollSpriteActor || drawRollParticle || isFlatSprite) + if (drawWithXYBillboard || isWallSprite) { // Compute center of sprite - float xcenter = (x1 + x2)*0.5; - float ycenter = (y1 + y2)*0.5; - float zcenter = (z1 + z2)*0.5; - float xx = -xcenter + x; - float zz = -zcenter + z; - float yy = -ycenter + y; - Matrix3x4 mat; mat.MakeIdentity(); - mat.Translate(xcenter, zcenter, ycenter); // move to sprite center + mat.Translate(center.X, center.Z, center.Y); // move to sprite center - // [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) - { - 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); - } + + // [MC] Sprite offsets. + if (!offset.isZero()) + HandleSpriteOffsets(&mat, &HWAngles, &offset, true); // Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down). - if (drawBillboardFacingCamera && !isFlatSprite) + if (drawBillboardFacingCamera && !isWallSprite) { // [CMB] Rotate relative to camera XY position, not just camera direction, // which is nicer in VR - float xrel = xcenter - vp->X; - float yrel = ycenter - vp->Y; + float xrel = center.X - vp->X; + float yrel = center.Y - vp->Y; float absAngleDeg = atan2(-yrel, xrel) * (180 / M_PI); float counterRotationDeg = 270. - HWAngles.Yaw.Degrees(); // counteracts existing sprite rotation float relAngleDeg = counterRotationDeg + absAngleDeg; @@ -446,32 +450,27 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) } // [fgsfds] calculate yaw vectors - float rollDegrees = 0; + float rollDegrees = doRoll ? Angles.Roll.Degrees() : 0; float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians(); - if (actor || drawRollParticle) rollDegrees = Angles.Roll.Degrees(); // [fgsfds] Rotate the sprite about the sight vector (roll) - if (spritetype == RF_WALLSPRITE) + if (isWallSprite) { float yawvecX = Angles.Yaw.Cos(); float yawvecY = Angles.Yaw.Sin(); mat.Rotate(0, 1, 0, 0); if (drawRollSpriteActor) { - if (useOffsets) mat.Translate(xx, zz, yy); mat.Rotate(yawvecX, 0, yawvecY, rollDegrees); - if (useOffsets) mat.Translate(-xx, -zz, -yy); } } - else if (drawRollSpriteActor || drawRollParticle) + else if (doRoll) { - if (useOffsets) mat.Translate(xx, zz, yy); if (drawWithXYBillboard) { mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees()); } mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); - if (useOffsets) mat.Translate(-xx, -zz, -yy); } else if (drawWithXYBillboard) { @@ -481,8 +480,8 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees()); } - mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center - + mat.Translate(-center.X, -center.Z, -center.Y); // 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); @@ -490,10 +489,38 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) } else // traditional "Y" billboard mode { - v[0] = FVector3(x1, z1, y1); - v[1] = FVector3(x2, z1, y2); - v[2] = FVector3(x1, z2, y1); - v[3] = FVector3(x2, z2, y2); + if (doRoll || !offset.isZero()) + { + mat.MakeIdentity(); + + if (!offset.isZero()) + HandleSpriteOffsets(&mat, &HWAngles, &offset, false); + + if (doRoll) + { + // Compute center of sprite + float angleRad = (FAngle::fromDeg(270.) - HWAngles.Yaw).Radians(); + float rollDegrees = Angles.Roll.Degrees(); + + mat.Translate(center.X, center.Z, center.Y); + mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); + mat.Translate(-center.X, -center.Z, -center.Y); + } + + v[0] = mat * FVector3(x1, z1, y1); + v[1] = mat * FVector3(x2, z1, y2); + v[2] = mat * FVector3(x1, z2, y1); + v[3] = mat * FVector3(x2, z2, y2); + + } + else + { + v[0] = FVector3(x1, z1, y1); + v[1] = FVector3(x2, z1, y2); + v[2] = FVector3(x1, z2, y1); + v[3] = FVector3(x2, z2, y2); + } + } return false; } @@ -1252,7 +1279,6 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t { lightlist = nullptr; } - PutSprite(di, hw_styleflags != STYLEHW_Solid); rendered_sprites++; }