Skip to content

Commit

Permalink
Added A_OverlayPivotAlign and A_OverlayVertexOffset.
Browse files Browse the repository at this point in the history
A_OverlayPivotAlign(int layer, int halign, int valign)
- Aligns the pivot point origin to a corner of the PSprite before applying offsets.
- - halign: Horizontal. Applicable constants are PSPA_<LEFT/CENTER/RIGHT>.
- - valign: Vertical. Applicable constants are PSPA_<TOP/CENTER/BOTTOM>.
- - Default is top left.

A_OverlayVertexOffset(int layer, int index, double x, double y, int flags)
- Allows offsetting the corners of the psprite, granting modders the ability to skew weapon sprites as they see fit.
- - index: The index of the vertice. Valid ranges are between [0,3].
- - x/y: Offsets of vertices.
- - flags: Takes WOF_ flags.

Other changes:
- Removed pivot point interpolation since it's pointless.
- Removed PSPF_PIVOTSCREEN due to complications with it having relativity. This will be revisited either later or in another submission.
- Added ResetPSprite() to be called with BringUpWeapon(), A_Lower(), and morph weapon raising to reset all the new properties to 0.

Nearly ready now. Just some final testing needed.
  • Loading branch information
MajorCooke authored and coelckers committed Oct 25, 2020
1 parent 4290295 commit 7c4c016
Show file tree
Hide file tree
Showing 10 changed files with 206 additions and 90 deletions.
95 changes: 79 additions & 16 deletions src/playsim/p_pspr.cpp
Expand Up @@ -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)
Expand All @@ -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)

//------------------------------------------------------------------------
//
Expand All @@ -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;

Expand Down Expand Up @@ -657,11 +663,7 @@ DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponButtons)
return 0;
}

//---------------------------------------------------------------------------
//
// PROC A_OverlayScale
//
//---------------------------------------------------------------------------


enum WOFFlags
{
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.)
}

Expand Down
14 changes: 11 additions & 3 deletions src/playsim/p_pspr.h
Expand Up @@ -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
Expand All @@ -99,16 +107,16 @@ class DPSprite : public DObject
std::pair<FRenderStyle, float> 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;
Expand Down
108 changes: 54 additions & 54 deletions src/rendering/hwrenderer/scene/hw_weapon.cpp
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -487,77 +481,83 @@ 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();
float sinang = rot.Sin();
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;
Expand Down
1 change: 0 additions & 1 deletion src/rendering/hwrenderer/scene/hw_weapon.h
Expand Up @@ -16,7 +16,6 @@ struct WeaponPosition
float wx, wy;
float bobx, boby;
float sx, sy;
float px, py;
float r;
DPSprite *weapon;
};
Expand Down
2 changes: 2 additions & 0 deletions wadsrc/static/zscript/actors/actor.zs
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions wadsrc/static/zscript/actors/heretic/chicken.zs
Expand Up @@ -60,6 +60,7 @@ class Beak : Weapon
if (psp)
{
psp.y = WEAPONTOP;
ResetPSprite(psp);
}
player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState());
}
Expand Down

0 comments on commit 7c4c016

Please sign in to comment.