Sprite lean/angled roll with geometric consistency in multiplayer and mirrors. An ANGLEDROLL flag ties actor's sprite-rolling axis to physical direction instead of viewpoint. Y-Billboarding occurs about a rolled axis (unlike flatsprites which don't billboard). This makes roll consistent when viewed from all angles and in reflections. Useful for sprite-based laser beams and lean mechanics with third-person cameras and/or multiplayer mods.
This commit is contained in:
parent
da13a7e839
commit
19291c5e5c
7 changed files with 73 additions and 3 deletions
|
|
@ -509,6 +509,7 @@ 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_LIGHTMULTALPHA = 0x0400, // attached lights use alpha as intensity multiplier
|
||||
RF2_ANGLEDROLL = 0x0800, // Sprite roll amount depends on (actor.Angle - actor.AngledRollOffset)
|
||||
};
|
||||
|
||||
// This translucency value produces the closest match to Heretic's TINTTAB.
|
||||
|
|
@ -1147,6 +1148,7 @@ public:
|
|||
|
||||
DAngle SpriteAngle;
|
||||
DAngle SpriteRotation;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -399,6 +399,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)
|
||||
|
|
|
|||
|
|
@ -421,6 +421,9 @@ 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
|
||||
const bool AngledRoll = (actor != nullptr && actor->renderflags2 & RF2_ANGLEDROLL);
|
||||
|
||||
// [fgsfds] check sprite type mask
|
||||
uint32_t spritetype = (uint32_t)-1;
|
||||
if (actor != nullptr) spritetype = actor->renderflags & RF_SPRITETYPEMASK;
|
||||
|
|
@ -516,13 +519,31 @@ 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 pitchDegrees = 0.0;
|
||||
|
||||
if (AngledRoll)
|
||||
{
|
||||
rollDegrees = fmodf(rollDegrees, 360.0f);
|
||||
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);
|
||||
|
||||
Matrix3x4 rolltilt;
|
||||
rolltilt.MakeIdentity();
|
||||
ang = actor->Angles.Yaw + actor->AngledRollOffset;
|
||||
rolltilt.Rotate(ang.Cos(), ang.Sin(), 0.0, -rollDegrees);
|
||||
pitchDegrees = 270.0 - DVector3(rolltilt * relPos).Angle().Degrees();
|
||||
}
|
||||
|
||||
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.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 (useOffsets) mat.Translate(-xx, -zz, -yy);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -928,8 +949,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)
|
||||
|
|
@ -1122,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
|
||||
|
|
@ -1171,7 +1215,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
|
||||
|
|
|
|||
|
|
@ -391,6 +391,7 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG(RF2, SQUAREPIXELS, AActor, renderflags2),
|
||||
DEFINE_FLAG(RF2, STRETCHPIXELS, AActor, renderflags2),
|
||||
DEFINE_FLAG(RF2, LIGHTMULTALPHA, AActor, renderflags2),
|
||||
DEFINE_FLAG(RF2, ANGLEDROLL, AActor, renderflags2),
|
||||
|
||||
// Bounce flags
|
||||
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
|
||||
|
|
|
|||
|
|
@ -602,6 +602,16 @@ DEFINE_PROPERTY(tag, S, Actor)
|
|||
defaults->SetTag(str);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(leanroll, 0, Actor)
|
||||
{
|
||||
// sets the standard flags for angle-dependent roll
|
||||
defaults->renderflags|=RF_ROLLSPRITE;
|
||||
defaults->renderflags2|=RF2_STRETCHPIXELS|RF2_ANGLEDROLL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue