diff --git a/src/playsim/p_pspr.cpp b/src/playsim/p_pspr.cpp index 591364b3c..79077c4ea 100644 --- a/src/playsim/p_pspr.cpp +++ b/src/playsim/p_pspr.cpp @@ -134,17 +134,21 @@ DEFINE_FIELD(DPSprite, oldx) DEFINE_FIELD(DPSprite, oldy) DEFINE_FIELD(DPSprite, px) DEFINE_FIELD(DPSprite, py) -DEFINE_FIELD(DPSprite, oldpx) -DEFINE_FIELD(DPSprite, oldpy) 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) +DEFINE_FIELD_NAMED(DPSprite, Coord[3], Coord3) DEFINE_FIELD(DPSprite, firstTic) DEFINE_FIELD(DPSprite, Tics) DEFINE_FIELD(DPSprite, Translation) +DEFINE_FIELD(DPSprite, HAlign) +DEFINE_FIELD(DPSprite, VAlign) DEFINE_FIELD(DPSprite, alpha) DEFINE_FIELD_BIT(DPSprite, Flags, bAddWeapon, PSPF_ADDWEAPON) DEFINE_FIELD_BIT(DPSprite, Flags, bAddBob, PSPF_ADDBOB) @@ -154,7 +158,6 @@ 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, bPivotScreen, PSPF_PIVOTSCREEN) //------------------------------------------------------------------------ // @@ -180,11 +183,14 @@ DPSprite::DPSprite(player_t *owner, AActor *caller, int id) px(.0), py(.0), rotation(.0), oldscalex(.0), oldscaley(.0), - oldpx(.0), oldpy(.0), oldrotation(.0), PivotPercent(true), - PivotScreen(false) + HAlign(0), + VAlign(0) { + for (int i = 0; i < 4; i++) + Coord[i] = DVector2(0,0); + alpha = 1; Renderstyle = STYLE_Normal; @@ -657,11 +663,7 @@ DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponButtons) return 0; } -//--------------------------------------------------------------------------- -// -// PROC A_OverlayScale -// -//--------------------------------------------------------------------------- + enum WOFFlags { @@ -673,6 +675,41 @@ enum WOFFlags WOF_ZEROY = 1 << 5, }; +//--------------------------------------------------------------------------- +// +// PROC A_OverlayVertexOffset +// +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayVertexOffset) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer) + PARAM_INT(index) + PARAM_FLOAT(x) + PARAM_FLOAT(y) + PARAM_INT(flags) + + if (index < 0 || index > 3 || ((flags & WOF_KEEPX) && (flags & WOF_KEEPY)) || !ACTION_CALL_FROM_PSPRITE()) + return 0; + + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + + if (pspr == nullptr) + return 0; + + if (!(flags & WOF_KEEPX)) pspr->Coord[index].X = x; + if (!(flags & WOF_KEEPY)) pspr->Coord[index].Y = y; + + return 0; +} + +//--------------------------------------------------------------------------- +// +// PROC A_OverlayScale +// +//--------------------------------------------------------------------------- + DEFINE_ACTION_FUNCTION(AActor, A_OverlayScale) { PARAM_ACTION_PROLOGUE(AActor); @@ -771,12 +808,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayPivot) if (!(flags & WOF_KEEPY)) pspr->py = (flags & WOF_ADD) ? pspr->py + wy : wy; - if (!(flags & WOF_INTERPOLATE)) - { - pspr->oldpx = pspr->px; - pspr->oldpy = pspr->py; - } - return 0; } @@ -889,6 +920,28 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) return 0; } +DEFINE_ACTION_FUNCTION(AActor, A_OverlayPivotAlign) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(layer); + PARAM_INT(halign); + PARAM_INT(valign); + + if (!ACTION_CALL_FROM_PSPRITE()) + return 0; + + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); + + if (pspr != nullptr) + { + if (halign >= PSPA_LEFT && halign <= PSPA_RIGHT) + pspr->HAlign |= halign; + if (valign >= PSPA_TOP && valign <= PSPA_BOTTOM) + pspr->VAlign |= valign; + } + return 0; +} + //--------------------------------------------------------------------------- // // PROC A_OverlayTranslation @@ -1211,6 +1264,16 @@ void DPSprite::Serialize(FSerializer &arc) ("oldx", oldx) ("oldy", oldy) ("alpha", alpha) + ("px", px) + ("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 e5d7ad10b..cb39903e8 100644 --- a/src/playsim/p_pspr.h +++ b/src/playsim/p_pspr.h @@ -72,7 +72,15 @@ enum PSPFlags PSPF_MIRROR = 1 << 9, PSPF_PLAYERTRANSLATED = 1 << 10, PSPF_PIVOTPERCENT = 1 << 11, - PSPF_PIVOTSCREEN = 1 << 12, +}; + +enum PSPAlign +{ + PSPA_TOP = 0, + PSPA_CENTER, + PSPA_BOTTOM, + PSPA_LEFT = PSPA_TOP, + PSPA_RIGHT = 2 }; class DPSprite : public DObject @@ -99,16 +107,16 @@ public: std::pair GetRenderStyle(FRenderStyle ownerstyle, double owneralpha); float GetYAdjust(bool fullscreen); - bool PivotScreen; // If true, the pivot is based on the entire screen width/height instead of the image's dimensions/position. + 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 oldpx, oldpy; 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 firstTic; int Tics; uint32_t Translation; diff --git a/src/rendering/hwrenderer/scene/hw_weapon.cpp b/src/rendering/hwrenderer/scene/hw_weapon.cpp index 4573790c4..4e0e4ad98 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.cpp +++ b/src/rendering/hwrenderer/scene/hw_weapon.cpp @@ -171,16 +171,12 @@ static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac) w.wy = (float)w.weapon->y; w.sx = (float)w.weapon->scalex; w.sy = (float)w.weapon->scaley; - w.px = (float)w.weapon->px; - w.py = (float)w.weapon->py; 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.px = (float)(w.weapon->oldpx + (w.weapon->px - w.weapon->oldpx) * ticFrac); - w.py = (float)(w.weapon->oldpy + (w.weapon->py - w.weapon->oldpy) * 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); @@ -190,8 +186,6 @@ static WeaponPosition GetWeaponPosition(player_t *player, double ticFrac) { w.wx = 0; w.wy = 0; - w.px = 0; - w.py = 0; w.sx = 0; w.sy = 0; w.r = 0; @@ -487,8 +481,21 @@ bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, // [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); + + for (int i = 0; i < 4; i++) + c[i] += FVector2(psp->Coord[i].X * scalex, psp->Coord[i].Y * scale); + if (psp->rotation != 0.0 || psp->scalex != 1.0 || psp->scaley != 1.0) { + if (psp->scalex == 0.0 || psp->scaley == 0.0) + return false; + FAngle rot = float(psp->rotation); rot.Normalized360(); float cosang = rot.Cos(); @@ -496,68 +503,61 @@ bool HUDSprite::GetWeaponRect(HWDrawInfo *di, DPSprite *psp, float sx, float sy, float px = float(psp->px); float py = float(psp->py); - float xcenter, ycenter; - float width = MAX(x1, x2) - MIN(x1, x2); - float height = MAX(y1, y2) - MIN(y1, y2); - if (psp->Flags & PSPF_PIVOTSCREEN) + float anchorx, anchory, xcenter, ycenter; + float minx = MIN(x1, x2); + float miny = MIN(y1, y2); + float width = MAX(x1, x2) - minx; + float height = MAX(y1, y2) - miny; + + switch (psp->VAlign) { - if (psp->Flags & PSPF_PIVOTPERCENT) - { - xcenter = vw * px + viewwindowx; - ycenter = vh * py + viewwindowy; - } - else - { - xcenter = vw * 0.5 + viewwindowx + px; - ycenter = vh * 0.5 + viewwindowy + py; - } + default: + case PSPA_TOP: anchory = 0.0; break; + case PSPA_CENTER: anchory = 0.5; break; + case PSPA_BOTTOM: anchory = 1.0; break; + } + + switch (psp->HAlign) + { + default: + case PSPA_LEFT: anchorx = 0.0; break; + case PSPA_CENTER: anchorx = 0.5; break; + case PSPA_RIGHT: anchorx = 1.0; break; + } + + if (psp->Flags & PSPF_PIVOTPERCENT) + { + xcenter = minx + (width * anchorx + width * px); + ycenter = miny + (height * anchory + height * py); } else { - if (psp->Flags & PSPF_PIVOTPERCENT) - { - xcenter = (x1 + width * px); - ycenter = (y1 + height * py); - } - else - { - xcenter = (x1 + width * 0.5) + px; - ycenter = (y1 + height * 0.5) - py; - } + xcenter = minx + (width * anchorx + scalex * px); + ycenter = miny + (height * anchory + scale * py); } + x1 -= xcenter; y1 -= ycenter; x2 -= xcenter; y2 -= ycenter; - + float ssx = float(psp->scalex); float ssy = float(psp->scaley); - float xx1 = xcenter + ssx * (x1 * cosang + y1 * sinang); - float xx2 = xcenter + ssx * (x1 * cosang + y2 * sinang); - float xx3 = xcenter + ssx * (x2 * cosang + y1 * sinang); - float xx4 = xcenter + ssx * (x2 * cosang + y2 * sinang); - - float yy1 = ycenter - ssy * (x1 * sinang - y1 * cosang); - float yy2 = ycenter - ssy * (x1 * sinang - y2 * cosang); - float yy3 = ycenter - ssy * (x2 * sinang - y1 * cosang); - float yy4 = ycenter - ssy * (x2 * sinang - y2 * cosang); - - - verts.first[0].Set(xx1, yy1, 0, u1, v1); - verts.first[1].Set(xx2, yy2, 0, u1, v2); - verts.first[2].Set(xx3, yy3, 0, u2, v1); - verts.first[3].Set(xx4, yy4, 0, u2, v2); - - } - else - { - verts.first[0].Set(x1, y1, 0, u1, v1); - verts.first[1].Set(x1, y2, 0, u1, v2); - verts.first[2].Set(x2, y1, 0, u2, v1); - verts.first[3].Set(x2, y2, 0, u2, v2); + for (int i = 0; i < 4; i++) + { + c[i] -= {xcenter, ycenter}; + float xx = xcenter + ssx * (c[i].X * cosang + c[i].Y * sinang); + float yy = ycenter - ssy * (c[i].X * sinang - c[i].Y * cosang); + c[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); texture = tex; return true; diff --git a/src/rendering/hwrenderer/scene/hw_weapon.h b/src/rendering/hwrenderer/scene/hw_weapon.h index d9817bbaa..48d930e86 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.h +++ b/src/rendering/hwrenderer/scene/hw_weapon.h @@ -16,7 +16,6 @@ struct WeaponPosition float wx, wy; float bobx, boby; float sx, sy; - float px, py; float r; DPSprite *weapon; }; diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 2d0818b2b..2526be303 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1186,6 +1186,8 @@ class Actor : Thinker native action native void A_OverlayScale(int layer, double wx = 1, double wy = 0, int flags = 0); action native void A_OverlayRotate(int layer, double degrees = 0, int flags = 0); action native void A_OverlayPivot(int layer, double wx = 0.5, double wy = 0.5, int flags = 0); + action native void A_OverlayPivotAlign(int layer, int halign, int valign); + action native void A_OverlayVertexOffset(int layer, int index, double x, double y, int flags = 0); action native void A_OverlayOffset(int layer = PSP_WEAPON, double wx = 0, double wy = 32, int flags = 0); action native void A_OverlayFlags(int layer, int flags, bool set); action native void A_OverlayAlpha(int layer, double alph); diff --git a/wadsrc/static/zscript/actors/heretic/chicken.zs b/wadsrc/static/zscript/actors/heretic/chicken.zs index 6e5354623..4bc2e20de 100644 --- a/wadsrc/static/zscript/actors/heretic/chicken.zs +++ b/wadsrc/static/zscript/actors/heretic/chicken.zs @@ -60,6 +60,7 @@ class Beak : Weapon if (psp) { psp.y = WEAPONTOP; + ResetPSprite(psp); } player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); } diff --git a/wadsrc/static/zscript/actors/inventory/weapons.zs b/wadsrc/static/zscript/actors/inventory/weapons.zs index 06854da9d..15d95d979 100644 --- a/wadsrc/static/zscript/actors/inventory/weapons.zs +++ b/wadsrc/static/zscript/actors/inventory/weapons.zs @@ -213,6 +213,20 @@ class Weapon : StateProvider // //--------------------------------------------------------------------------- + action void ResetPSprite(PSprite psp) + { + if (!psp) return; + psp.rotation = 0; + psp.scalex = 1.0; + psp.scaley = 1.0; + psp.valign = 0; + psp.halign = 0; + psp.Coord0 = (0,0); + psp.Coord1 = (0,0); + psp.Coord2 = (0,0); + psp.Coord3 = (0,0); + } + action void A_Lower(int lowerspeed = 6) { let player = player; @@ -240,6 +254,8 @@ class Weapon : StateProvider { // Not lowered all the way yet return; } + ResetPSprite(psp); + if (player.playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon // Player is dead, so keep the weapon off screen @@ -278,12 +294,18 @@ class Weapon : StateProvider } let psp = player.GetPSprite(PSP_WEAPON); if (!psp) return; + + if (psp.y <= WEAPONBOTTOM) + { + ResetPSprite(psp); + } psp.y -= raisespeed; if (psp.y > WEAPONTOP) { // Not raised all the way yet return; } psp.y = WEAPONTOP; + psp.SetState(player.ReadyWeapon.GetReadyState()); return; } diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index f076e680a..4541a91bc 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -1664,7 +1664,11 @@ class PlayerPawn : Actor if (player.ReadyWeapon != null) { let psp = player.GetPSprite(PSP_WEAPON); - if (psp) psp.y = WEAPONTOP; + if (psp) + { + psp.y = WEAPONTOP; + player.ReadyWeapon.ResetPSprite(psp); + } player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); } return; @@ -2559,14 +2563,17 @@ class PSprite : Object native play native double oldy; native double px; native double py; - native double oldpx; - native double oldpy; 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 Coord1; + native Vector2 Coord2; + native Vector2 Coord3; native double alpha; native Bool firstTic; native int Tics; @@ -2579,7 +2586,6 @@ class PSprite : Object native play native bool bMirror; native bool bPlayerTranslated; native bool bPivotPercent; - native bool bPivotScreen; native void SetState(State newstate, bool pending = false); diff --git a/wadsrc/static/zscript/actors/player/player_morph.zs b/wadsrc/static/zscript/actors/player/player_morph.zs index 391be4a06..e6ca560a4 100644 --- a/wadsrc/static/zscript/actors/player/player_morph.zs +++ b/wadsrc/static/zscript/actors/player/player_morph.zs @@ -60,7 +60,11 @@ extend class PlayerPawn if (player.ReadyWeapon != null) { let psp = player.GetPSprite(PSP_WEAPON); - if (psp) psp.y = WEAPONTOP; + if (psp) + { + psp.y = WEAPONTOP; + player.ReadyWeapon.ResetPSprite(psp); + } } if (morphweaponcls == null || !(morphweaponcls is 'Weapon')) diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index c391832da..5aa8cec49 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -701,17 +701,28 @@ enum EWeaponOffsetFlags // Flags for psprite layers enum EPSpriteFlags { - PSPF_ADDWEAPON = 1 << 0, - PSPF_ADDBOB = 1 << 1, - PSPF_POWDOUBLE = 1 << 2, - PSPF_CVARFAST = 1 << 3, - PSPF_ALPHA = 1 << 4, - PSPF_RENDERSTYLE= 1 << 5, - PSPF_FLIP = 1 << 6, - PSPF_FORCEALPHA = 1 << 7, - PSPF_FORCESTYLE = 1 << 8, - PSPF_MIRROR = 1 << 9, - PSPF_PLAYERTRANSLATED = 1 << 10 + PSPF_ADDWEAPON = 1 << 0, + PSPF_ADDBOB = 1 << 1, + PSPF_POWDOUBLE = 1 << 2, + PSPF_CVARFAST = 1 << 3, + PSPF_ALPHA = 1 << 4, + PSPF_RENDERSTYLE = 1 << 5, + PSPF_FLIP = 1 << 6, + PSPF_FORCEALPHA = 1 << 7, + PSPF_FORCESTYLE = 1 << 8, + PSPF_MIRROR = 1 << 9, + PSPF_PLAYERTRANSLATED = 1 << 10, + PSPF_PIVOTPERCENT = 1 << 11, +}; + +// Alignment constants for A_OverlayPivotAlign +enum EPSpriteAlign +{ + PSPA_TOP = 0, + PSPA_CENTER, + PSPA_BOTTOM, + PSPA_LEFT = PSPA_TOP, + PSPA_RIGHT = 2 }; // Default psprite layers