Finished implementing PSprite interpolation for vertices.

- Setting WOF_INTERPOLATE on any of the functions with flags (except A_OverlayFlags) will enable one tic for interpolating.
- Setting PSPF_INTERPOLATE with A_OverlayFlags will permanently enable it for that layer, but requires manual calling.
This commit is contained in:
Major Cooke 2020-10-03 16:16:56 -05:00 committed by Christoph Oelckers
parent c41733e436
commit a6bbddf167
7 changed files with 106 additions and 109 deletions

View file

@ -136,10 +136,7 @@ DEFINE_FIELD(DPSprite, px)
DEFINE_FIELD(DPSprite, py)
DEFINE_FIELD(DPSprite, scalex)
DEFINE_FIELD(DPSprite, scaley)
DEFINE_FIELD(DPSprite, oldscalex)
DEFINE_FIELD(DPSprite, oldscaley)
DEFINE_FIELD(DPSprite, rotation)
DEFINE_FIELD(DPSprite, oldrotation)
DEFINE_FIELD_NAMED(DPSprite, Coord[0], Coord0)
DEFINE_FIELD_NAMED(DPSprite, Coord[1], Coord1)
DEFINE_FIELD_NAMED(DPSprite, Coord[2], Coord2)
@ -150,6 +147,7 @@ DEFINE_FIELD(DPSprite, Translation)
DEFINE_FIELD(DPSprite, HAlign)
DEFINE_FIELD(DPSprite, VAlign)
DEFINE_FIELD(DPSprite, alpha)
DEFINE_FIELD(DPSprite, InterpolateTic)
DEFINE_FIELD_BIT(DPSprite, Flags, bAddWeapon, PSPF_ADDWEAPON)
DEFINE_FIELD_BIT(DPSprite, Flags, bAddBob, PSPF_ADDBOB)
DEFINE_FIELD_BIT(DPSprite, Flags, bPowDouble, PSPF_POWDOUBLE)
@ -158,6 +156,7 @@ DEFINE_FIELD_BIT(DPSprite, Flags, bFlip, PSPF_FLIP)
DEFINE_FIELD_BIT(DPSprite, Flags, bMirror, PSPF_MIRROR)
DEFINE_FIELD_BIT(DPSprite, Flags, bPlayerTranslated, PSPF_PLAYERTRANSLATED)
DEFINE_FIELD_BIT(DPSprite, Flags, bPivotPercent, PSPF_PIVOTPERCENT)
DEFINE_FIELD_BIT(DPSprite, Flags, bInterpolate, PSPF_INTERPOLATE)
//------------------------------------------------------------------------
//
@ -182,14 +181,15 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id)
scalex(1.0), scaley(1.0),
px(.0), py(.0),
rotation(.0),
oldscalex(.0), oldscaley(.0),
oldrotation(.0),
PivotPercent(true),
HAlign(0),
VAlign(0)
VAlign(0),
InterpolateTic(false)
{
for (int i = 0; i < 4; i++)
Coord[i] = DVector2(0,0);
{
Coord[i] = DVector2(0, 0);
Prev.v[i] = Vert.v[i] = FVector2(0,0);
}
alpha = 1;
Renderstyle = STYLE_Normal;
@ -698,8 +698,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayVertexOffset)
if (pspr == nullptr)
return 0;
if (!(flags & WOF_KEEPX)) pspr->Coord[index].X = x;
if (!(flags & WOF_KEEPY)) pspr->Coord[index].Y = y;
if (!(flags & WOF_KEEPX)) pspr->Coord[index].X = (flags & WOF_ADD) ? pspr->Coord[index].X + x : x;
if (!(flags & WOF_KEEPY)) pspr->Coord[index].Y = (flags & WOF_ADD) ? pspr->Coord[index].Y + y : y;
if (flags & WOF_INTERPOLATE) pspr->InterpolateTic = true;
return 0;
}
@ -729,16 +731,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayScale)
if (!(flags & WOF_ZEROY) && wy == 0.0)
wy = wx;
if (!(flags & WOF_KEEPX))
pspr->scalex = (flags & WOF_ADD) ? pspr->scalex + wx : wx;
if (!(flags & WOF_KEEPY))
pspr->scaley = (flags & WOF_ADD) ? pspr->scaley + wy : wy;
if (!(flags & WOF_KEEPX)) pspr->scalex = (flags & WOF_ADD) ? pspr->scalex + wx : wx;
if (!(flags & WOF_KEEPY)) pspr->scaley = (flags & WOF_ADD) ? pspr->scaley + wy : wy;
if (!(flags & WOF_INTERPOLATE))
{
pspr->oldscalex = pspr->scalex;
pspr->oldscaley = pspr->scaley;
}
if (flags & WOF_INTERPOLATE) pspr->InterpolateTic = true;
return 0;
}
@ -761,13 +757,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayRotate)
DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex));
if (pspr == nullptr)
return 0;
if (pspr != nullptr)
{
pspr->rotation = (flags & WOF_ADD) ? pspr->rotation + degrees : degrees;
if (!(flags & WOF_INTERPOLATE))
pspr->oldrotation = degrees;
if (flags & WOF_INTERPOLATE) pspr->InterpolateTic = true;
}
return 0;
}
@ -803,10 +797,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayPivot)
wx = nx; wy = ny;
}
if (!(flags & WOF_KEEPX))
pspr->px = (flags & WOF_ADD) ? pspr->px + wx : wx;
if (!(flags & WOF_KEEPY))
pspr->py = (flags & WOF_ADD) ? pspr->py + wy : wy;
if (!(flags & WOF_KEEPX)) pspr->px = (flags & WOF_ADD) ? pspr->px + wx : wx;
if (!(flags & WOF_KEEPY)) pspr->py = (flags & WOF_ADD) ? pspr->py + wy : wy;
if (flags & WOF_INTERPOLATE) pspr->InterpolateTic = true;
return 0;
}
@ -843,30 +837,17 @@ void A_OverlayOffset(AActor *self, int layer, double wx, double wy, int flags)
wx = nx; wy = ny;
}
if (!(flags & WOF_KEEPX))
if (!(flags & WOF_KEEPX)) psp->x = (flags & WOF_ADD) ? psp->x + wx : wx;
if (!(flags & WOF_KEEPY)) psp->y = (flags & WOF_ADD) ? psp->y + wy : wy;
if (flags & WOF_INTERPOLATE) psp->InterpolateTic = true;
/*
if (!(flags & (WOF_INTERPOLATE|WOF_ADD)))
{
if (flags & WOF_ADD)
{
psp->x += wx;
}
else
{
psp->x = wx;
if (!(flags & WOF_INTERPOLATE)) psp->oldx = psp->x;
}
}
if (!(flags & WOF_KEEPY))
{
if (flags & WOF_ADD)
{
psp->y += wy;
}
else
{
psp->y = wy;
if (!(flags & WOF_INTERPOLATE)) psp->oldy = psp->y;
}
psp->oldx = psp->x;
psp->oldy = psp->y;
}
*/
}
}
@ -915,8 +896,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags)
if (set)
pspr->Flags |= flags;
else
{
pspr->Flags &= ~flags;
// This is the only way to shut off the temporary interpolation tic
// in the event another mod is causing potential interference
if (flags & PSPF_INTERPOLATE)
pspr->ResetInterpolation();
}
return 0;
}
@ -1268,10 +1255,7 @@ void DPSprite::Serialize(FSerializer &arc)
("py", py)
("scalex", scalex)
("scaley", scaley)
("oldscalex", oldscalex)
("oldscaley", oldscaley)
("rotation", rotation)
("oldrotation", oldrotation)
("halign", HAlign)
("valign", VAlign)
("renderstyle_", Renderstyle); // The underscore is intentional to avoid problems with old savegames which had this as an ERenderStyle (which is not future proof.)

View file

@ -72,6 +72,7 @@ enum PSPFlags
PSPF_MIRROR = 1 << 9,
PSPF_PLAYERTRANSLATED = 1 << 10,
PSPF_PIVOTPERCENT = 1 << 11,
PSPF_INTERPOLATE = 1 << 12,
};
enum PSPAlign
@ -83,6 +84,11 @@ enum PSPAlign
PSPA_RIGHT = 2
};
struct WeaponInterp
{
FVector2 v[4];
};
class DPSprite : public DObject
{
DECLARE_CLASS (DPSprite, DObject)
@ -102,21 +108,21 @@ public:
DPSprite* GetNext() { return Next; }
AActor* GetCaller() { return Caller; }
void SetCaller(AActor *newcaller) { Caller = newcaller; }
void ResetInterpolation() { oldx = x; oldy = y; }
void ResetInterpolation() { oldx = x; oldy = y; Prev = Vert; InterpolateTic = false; }
void OnDestroy() override;
std::pair<FRenderStyle, float> GetRenderStyle(FRenderStyle ownerstyle, double owneralpha);
float GetYAdjust(bool fullscreen);
int HAlign, VAlign; // Horizontal and vertical alignment
bool PivotPercent; // If true, the pivot goes between [0.0, 1.0]. Otherwise, it's a pixel position offset from the image size.
double px, py; // pivot points
double rotation; // How much rotation to apply.
double oldrotation;
double scalex, scaley; // Scale
double oldscalex, oldscaley;
double x, y, alpha;
double oldx, oldy;
DVector2 Coord[4];
bool InterpolateTic;
DVector2 Coord[4]; // Offsets
WeaponInterp Prev; // Interpolation
WeaponInterp Vert; // Current Position
bool firstTic;
int Tics;
uint32_t Translation;

View file

@ -291,7 +291,7 @@ public:
void GetDynSpriteLight(AActor *thing, particle_t *particle, float *out);
void PreparePlayerSprites(sector_t * viewsector, area_t in_area);
void PrepareTargeterSprites(WeaponPosition *weap);
void PrepareTargeterSprites(double ticfrac);
void UpdateCurrentMapSection();
void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror);

View file

@ -169,26 +169,17 @@ static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac)
{
w.wx = (float)w.weapon->x;
w.wy = (float)w.weapon->y;
w.sx = (float)w.weapon->scalex;
w.sy = (float)w.weapon->scaley;
w.r = (float)w.weapon->rotation;
}
else
{
w.wx = (float)(w.weapon->oldx + (w.weapon->x - w.weapon->oldx) * ticFrac);
w.wy = (float)(w.weapon->oldy + (w.weapon->y - w.weapon->oldy) * ticFrac);
w.sx = (float)(w.weapon->oldscalex + (w.weapon->scalex - w.weapon->oldscalex) * ticFrac);
w.sy = (float)(w.weapon->oldscaley + (w.weapon->scaley - w.weapon->oldscaley) * ticFrac);
w.r = (float)(w.weapon->oldrotation + (w.weapon->rotation - w.weapon->oldrotation) * ticFrac);
}
}
else
{
w.wx = 0;
w.wy = 0;
w.sx = 0;
w.sy = 0;
w.r = 0;
}
return w;
}
@ -204,8 +195,7 @@ static FVector2 BobWeapon(WeaponPosition &weap, DPSprite *psp, double ticFrac)
if (psp->firstTic)
{ // Can't interpolate the first tic.
psp->firstTic = false;
psp->oldx = psp->x;
psp->oldy = psp->y;
psp->ResetInterpolation();
}
float sx = float(psp->oldx + (psp->x - psp->oldx) * ticFrac);
@ -416,7 +406,7 @@ bool HUDSprite::GetWeaponRenderStyle(DPSprite *psp, AActor *playermo, sector_t *
//
//==========================================================================
bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player, WeaponPosition *weap)
bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player, double ticfrac)
{
float tx;
float scale;
@ -444,13 +434,14 @@ bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy,
tx = (psp->Flags & PSPF_MIRROR) ? ((160 - r.width) - (sx + r.left)) : (sx - (160 - r.left));
x1 = tx * scalex + vw / 2;
if (x1 > vw) return false; // off the right side
// [MC] Disabled these because vertices can be manipulated now.
//if (x1 > vw) return false; // off the right side
x1 += viewwindowx;
tx += r.width;
x2 = tx * scalex + vw / 2;
if (x2 < 0) return false; // off the left side
//if (x2 < 0) return false; // off the left side
x2 += viewwindowx;
// killough 12/98: fix psprite positioning problem
@ -476,29 +467,22 @@ bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy,
v2 = spi.GetSpriteVB();
}
auto verts = screen->mVertexData->AllocVertices(4);
mx = verts.second;
// [MC] Code copied from DTA_Rotate.
// Big thanks to IvanDobrovski who helped me modify this.
FVector2 c[4];
c[0] = FVector2(x1, y1);
c[1] = FVector2(x1, y2);
c[2] = FVector2(x2, y1);
c[3] = FVector2(x2, y2);
WeaponInterp Vert;
Vert.v[0] = FVector2(x1, y1);
Vert.v[1] = FVector2(x1, y2);
Vert.v[2] = FVector2(x2, y1);
Vert.v[3] = FVector2(x2, y2);
for (int i = 0; i < 4; i++)
{
const float cx = (flip) ? -psp->Coord[i].X : psp->Coord[i].X;
c[i] += FVector2(cx * scalex, psp->Coord[i].Y * scale);
Vert.v[i] += FVector2(cx * scalex, psp->Coord[i].Y * scale);
}
if (psp->rotation != 0.0 || psp->scalex != 1.0 || psp->scaley != 1.0)
{
// Nothing to draw in this case.
if (psp->scalex == 0.0 || psp->scaley == 0.0)
return false;
// [MC] Sets up the alignment for starting the pivot at, in a corner.
float anchorx, anchory;
switch (psp->VAlign)
@ -546,17 +530,42 @@ bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy,
// Now adjust the position, rotation and scale of the image based on the latter two.
for (int i = 0; i < 4; i++)
{
c[i] -= {xcenter, ycenter};
const float xx = xcenter + psp->scalex * (c[i].X * cosang + c[i].Y * sinang);
const float yy = ycenter - psp->scaley * (c[i].X * sinang - c[i].Y * cosang);
c[i] = {xx, yy};
Vert.v[i] -= {xcenter, ycenter};
const float xx = xcenter + psp->scalex * (Vert.v[i].X * cosang + Vert.v[i].Y * sinang);
const float yy = ycenter - psp->scaley * (Vert.v[i].X * sinang - Vert.v[i].Y * cosang);
Vert.v[i] = {xx, yy};
}
}
psp->Vert = Vert;
if (psp->scalex == 0.0 || psp->scaley == 0.0)
return false;
bool vertsOnScreen = false;
const bool interp = (psp->InterpolateTic || psp->Flags & PSPF_INTERPOLATE);
for (int i = 0; i < 4; i++)
{
FVector2 t = Vert.v[i];
if (interp)
t = psp->Prev.v[i] + (psp->Vert.v[i] - psp->Prev.v[i]) * ticfrac;
if (!vertsOnScreen)
vertsOnScreen = (t.X >= 0.0 && t.X <= vw);
Vert.v[i] = t;
}
verts.first[0].Set(c[0].X, c[0].Y, 0, u1, v1);
verts.first[1].Set(c[1].X, c[1].Y, 0, u1, v2);
verts.first[2].Set(c[2].X, c[2].Y, 0, u2, v1);
verts.first[3].Set(c[3].X, c[3].Y, 0, u2, v2);
if (!vertsOnScreen)
return false;
auto verts = screen->mVertexData->AllocVertices(4);
mx = verts.second;
verts.first[0].Set(Vert.v[0].X, Vert.v[0].Y, 0, u1, v1);
verts.first[1].Set(Vert.v[1].X, Vert.v[1].Y, 0, u1, v2);
verts.first[2].Set(Vert.v[2].X, Vert.v[2].Y, 0, u2, v1);
verts.first[3].Set(Vert.v[3].X, Vert.v[3].Y, 0, u2, v2);
texture = tex;
return true;
@ -637,12 +646,12 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
}
else
{
if (!hudsprite.GetWeaponRect(this, psp, spos.X, spos.Y, player, &weap)) continue;
if (!hudsprite.GetWeaponRect(this, psp, spos.X, spos.Y, player, vp.TicFrac)) continue;
}
hudsprites.Push(hudsprite);
}
lightmode = oldlightmode;
PrepareTargeterSprites(&weap);
PrepareTargeterSprites(vp.TicFrac);
}
@ -652,7 +661,7 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area)
//
//==========================================================================
void HWDrawInfo::PrepareTargeterSprites(WeaponPosition *weap)
void HWDrawInfo::PrepareTargeterSprites(double ticfrac)
{
AActor * playermo = players[consoleplayer].camera;
player_t * player = playermo->player;
@ -685,7 +694,7 @@ void HWDrawInfo::PrepareTargeterSprites(WeaponPosition *weap)
{
hudsprite.weapon = psp;
if (hudsprite.GetWeaponRect(this, psp, psp->x, psp->y, player, weap))
if (hudsprite.GetWeaponRect(this, psp, psp->x, psp->y, player, ticfrac))
{
hudsprites.Push(hudsprite);
}

View file

@ -15,8 +15,6 @@ struct WeaponPosition
{
float wx, wy;
float bobx, boby;
float sx, sy;
float r;
DPSprite *weapon;
};
@ -49,6 +47,6 @@ struct HUDSprite
void SetBright(bool isbelow);
bool GetWeaponRenderStyle(DPSprite *psp, AActor *playermo, sector_t *viewsector, WeaponLighting &light);
bool GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player, WeaponPosition *weap);
bool GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, player_t *player, double ticfrac);
};

View file

@ -2565,17 +2565,15 @@ class PSprite : Object native play
native double py;
native double scalex;
native double scaley;
native double oldscalex;
native double oldscaley;
native double rotation;
native double oldrotation;
native int HAlign, VAlign;
native Vector2 Coord0;
native Vector2 Coord0; // [MC] Not the actual coordinates. Just the offsets by A_OverlayVertexOffset.
native Vector2 Coord1;
native Vector2 Coord2;
native Vector2 Coord3;
native double alpha;
native Bool firstTic;
native bool InterpolateTic;
native int Tics;
native uint Translation;
native bool bAddWeapon;
@ -2586,6 +2584,7 @@ class PSprite : Object native play
native bool bMirror;
native bool bPlayerTranslated;
native bool bPivotPercent;
native bool bInterpolate;
native void SetState(State newstate, bool pending = false);

View file

@ -713,6 +713,7 @@ enum EPSpriteFlags
PSPF_MIRROR = 1 << 9,
PSPF_PLAYERTRANSLATED = 1 << 10,
PSPF_PIVOTPERCENT = 1 << 11,
PSPF_INTERPOLATE = 1 << 12,
};
// Alignment constants for A_OverlayPivotAlign