From a6bbddf167237b1edf2c5eaf83c4434fc23aae52 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Sat, 3 Oct 2020 16:16:56 -0500 Subject: [PATCH] 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. --- src/playsim/p_pspr.cpp | 96 ++++++++----------- src/playsim/p_pspr.h | 16 +++- src/rendering/hwrenderer/scene/hw_drawinfo.h | 2 +- src/rendering/hwrenderer/scene/hw_weapon.cpp | 89 +++++++++-------- src/rendering/hwrenderer/scene/hw_weapon.h | 4 +- wadsrc/static/zscript/actors/player/player.zs | 7 +- wadsrc/static/zscript/constants.zs | 1 + 7 files changed, 106 insertions(+), 109 deletions(-) diff --git a/src/playsim/p_pspr.cpp b/src/playsim/p_pspr.cpp index 79077c4eabf..5256d20712f 100644 --- a/src/playsim/p_pspr.cpp +++ b/src/playsim/p_pspr.cpp @@ -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,15 +181,16 @@ 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; - - pspr->rotation = (flags & WOF_ADD) ? pspr->rotation + degrees : degrees; - - if (!(flags & WOF_INTERPOLATE)) - pspr->oldrotation = degrees; + if (pspr != nullptr) + { + pspr->rotation = (flags & WOF_ADD) ? pspr->rotation + degrees : 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.) diff --git a/src/playsim/p_pspr.h b/src/playsim/p_pspr.h index cb39903e886..36ffb0136a5 100644 --- a/src/playsim/p_pspr.h +++ b/src/playsim/p_pspr.h @@ -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 @@ class DPSprite : public DObject 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 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; diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index fa5c5b35802..4d92c1cbc90 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -291,7 +291,7 @@ struct HWDrawInfo 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); diff --git a/src/rendering/hwrenderer/scene/hw_weapon.cpp b/src/rendering/hwrenderer/scene/hw_weapon.cpp index f0ff7695573..b298d7e24be 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.cpp +++ b/src/rendering/hwrenderer/scene/hw_weapon.cpp @@ -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}; } } - - 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); + 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; + } + + 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); } diff --git a/src/rendering/hwrenderer/scene/hw_weapon.h b/src/rendering/hwrenderer/scene/hw_weapon.h index 48d930e867f..76df17d6c0e 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.h +++ b/src/rendering/hwrenderer/scene/hw_weapon.h @@ -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); }; diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index 4541a91bcc7..f569f70efb9 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -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); diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 5aa8cec498b..6e9349f365b 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -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