Improve shadow code yet again by testing highest value of slopes

This makes it follow the sprites a bit better on slopes. Also split into a sub-function so that Banana doesn't need the duplicated code anymore.

The accuracy can be further improved on by doing the calculation 3 extra times for every surface, for each corner of the hitbox -- it wouldn't be THAT much more expensive, but it would only make subtle differences on sector boundaries that we usually zoom past anyway, so I figured it wasn't worth it. (It'll be easy enough to do so if we decide that we want the uber-accuracy)
This commit is contained in:
TehRealSalt 2019-05-31 01:08:04 -04:00
parent f3f0b5edda
commit 24feb81671
3 changed files with 170 additions and 199 deletions

View file

@ -4527,82 +4527,11 @@ static void K_MoveHeldObjects(player_t *player)
P_TeleportMove(cur, targx, targy, cur->z);
#ifdef ESLOPE
// We gotta do ALL of this... just so that bananas can tilt in OGL :V
if (P_IsObjectOnGround(cur))
{
pslope_t *slope = NULL;
sector_t *sec = R_PointInSubsector(cur->x, cur->y)->sector;
boolean flip = (cur->eflags & MFE_VERTICALFLIP);
if (flip)
{
if (sec->c_slope)
{
slope = sec->c_slope;
targz = P_GetZAt(sec->c_slope, cur->x, cur->y);
}
else
targz = sec->ceilingheight;
}
else
{
if (sec->f_slope)
{
slope = sec->f_slope;
targz = P_GetZAt(sec->f_slope, cur->x, cur->y);
}
else
targz = sec->floorheight;
}
// Check FOFs for a better suited slope
if (sec->ffloors)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
{
fixed_t surface;
if (!(rover->flags & FF_EXISTS))
continue;
if (!((rover->flags & FF_BLOCKOTHERS) || (rover->flags & FF_QUICKSAND)) || (rover->flags & FF_SWIMMABLE))
continue;
if (flip)
{
surface = *rover->bottomheight;
if (*rover->b_slope)
surface = P_GetZAt(*rover->b_slope, cur->x, cur->y);
if (surface < targz && surface > (cur->z + cur->height))
{
targz = surface;
if (*rover->b_slope)
slope = *rover->b_slope;
}
}
else
{
surface = *rover->topheight;
if (*rover->t_slope)
surface = P_GetZAt(*rover->t_slope, cur->x, cur->y);
if (surface > targz && surface < cur->z)
{
targz = surface;
if (*rover->t_slope)
slope = *rover->t_slope;
}
}
}
}
cur->standingslope = slope;
#ifdef HWRENDER
cur->modeltilt = cur->standingslope;
#endif
// Slope values are set in the function, but we DON'T want to use its return value.
P_CalculateShadowFloor(cur, cur->x, cur->y, cur->z,
cur->radius, cur->height, (cur->eflags & MFE_VERTICALFLIP), false);
}
#endif

View file

@ -227,6 +227,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state);
boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
//void P_RunShields(void);
void P_RunOverlays(void);
fixed_t P_CalculateShadowFloor(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player);
void P_RunShadows(void);
void P_MobjThinker(mobj_t *mobj);
boolean P_RailThinker(mobj_t *mobj);

View file

@ -6205,6 +6205,170 @@ static void P_RemoveOverlay(mobj_t *thing)
}
}
// Simplified version of a code bit in P_MobjFloorZ
static fixed_t P_ShadowSlopeZ(pslope_t *slope, fixed_t x, fixed_t y, fixed_t radius, boolean ceiling)
{
fixed_t testx, testy;
if (slope->d.x < 0)
testx = radius;
else
testx = -radius;
if (slope->d.y < 0)
testy = radius;
else
testy = -radius;
if ((slope->zdelta > 0) ^ !!(ceiling))
{
testx = -testx;
testy = -testy;
}
testx += x;
testy += y;
return P_GetZAt(slope, testx, testy);
}
// Sets standingslope/modeltilt, returns z position for shadows; used also for stuff like bananas
// (I would've preferred to be able to return both the slope & z, but I'll take what I can get...)
fixed_t P_CalculateShadowFloor(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player)
{
fixed_t newz;
sector_t *sec;
#ifdef ESLOPE
pslope_t *slope = NULL;
#endif
sec = R_PointInSubsector(x, y)->sector;
if (flip)
{
#ifdef ESLOPE
if (sec->c_slope)
{
slope = sec->c_slope;
newz = P_ShadowSlopeZ(slope, x, y, radius, true);
}
else
#endif
newz = sec->ceilingheight;
}
else
{
#ifdef ESLOPE
if (sec->f_slope)
{
slope = sec->f_slope;
newz = P_ShadowSlopeZ(slope, x, y, radius, false);
}
else
#endif
newz = sec->floorheight;
}
// Check FOFs for a better suited slope
if (sec->ffloors)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
{
fixed_t top, bottom;
fixed_t d1, d2;
if (!(rover->flags & FF_EXISTS))
continue;
if ((!(((rover->flags & FF_BLOCKPLAYER && player)
|| (rover->flags & FF_BLOCKOTHERS && !player))
|| (rover->flags & FF_QUICKSAND))
|| (rover->flags & FF_SWIMMABLE)))
continue;
#ifdef ESLOPE
if (*rover->t_slope)
top = P_ShadowSlopeZ(*rover->t_slope, x, y, radius, false);
else
#endif
top = *rover->topheight;
#ifdef ESLOPE
if (*rover->b_slope)
bottom = P_ShadowSlopeZ(*rover->b_slope, x, y, radius, true);
else
#endif
bottom = *rover->bottomheight;
if (flip)
{
if (rover->flags & FF_QUICKSAND)
{
if (z < top && (z + height) > bottom)
{
if (newz > (z + height))
{
newz = (z + height);
slope = NULL;
}
}
continue;
}
d1 = (z + height) - (top + ((bottom - top)/2));
d2 = z - (top + ((bottom - top)/2));
if (bottom < newz && abs(d1) < abs(d2))
{
newz = bottom;
#ifdef ESLOPE
if (*rover->b_slope)
slope = *rover->b_slope;
#endif
}
}
else
{
if (rover->flags & FF_QUICKSAND)
{
if (z < top && (z + height) > bottom)
{
if (newz < z)
{
newz = z;
slope = NULL;
}
}
continue;
}
d1 = z - (bottom + ((top - bottom)/2));
d2 = (z + height) - (bottom + ((top - bottom)/2));
if (top > newz && abs(d1) < abs(d2))
{
newz = top;
#ifdef ESLOPE
if (*rover->t_slope)
slope = *rover->t_slope;
#endif
}
}
}
}
#if 0
mobj->standingslope = slope;
#endif
#ifdef HWRENDER
mobj->modeltilt = slope;
#endif
return newz;
}
void P_RunShadows(void)
{
mobj_t *mobj, *next, *dest;
@ -6213,10 +6377,6 @@ void P_RunShadows(void)
{
boolean flip;
fixed_t newz;
sector_t *sec;
#ifdef ESLOPE
pslope_t *slope = NULL;
#endif
next = mobj->hnext;
P_SetTarget(&mobj->hnext, NULL);
@ -6230,127 +6390,8 @@ void P_RunShadows(void)
K_MatchGenericExtraFlags(mobj, mobj->target);
flip = (mobj->eflags & MFE_VERTICALFLIP);
sec = R_PointInSubsector(mobj->target->x, mobj->target->y)->sector;
if (flip)
{
#ifdef ESLOPE
if (sec->c_slope)
{
slope = sec->c_slope;
newz = P_GetZAt(sec->c_slope, mobj->target->x, mobj->target->y);
}
else
#endif
newz = sec->ceilingheight;
}
else
{
#ifdef ESLOPE
if (sec->f_slope)
{
slope = sec->f_slope;
newz = P_GetZAt(sec->f_slope, mobj->target->x, mobj->target->y);
}
else
#endif
newz = sec->floorheight;
}
// Check FOFs for a better suited slope
if (sec->ffloors)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
{
fixed_t top, bottom;
fixed_t d1, d2;
if (!(rover->flags & FF_EXISTS))
continue;
if ((!(((rover->flags & FF_BLOCKPLAYER && mobj->target->player)
|| (rover->flags & FF_BLOCKOTHERS && !mobj->target->player))
|| (rover->flags & FF_QUICKSAND))
|| (rover->flags & FF_SWIMMABLE)))
continue;
#ifdef ESLOPE
if (*rover->t_slope)
top = P_GetZAt(*rover->t_slope, mobj->target->x, mobj->target->y);
else
#endif
top = *rover->topheight;
#ifdef ESLOPE
if (*rover->b_slope)
bottom = P_GetZAt(*rover->b_slope, mobj->target->x, mobj->target->y);
else
#endif
bottom = *rover->bottomheight;
if (flip)
{
if (rover->flags & FF_QUICKSAND)
{
if (mobj->target->z < top && (mobj->target->z + mobj->target->height) > bottom)
{
if (newz > (mobj->target->z + mobj->target->height))
{
newz = (mobj->target->z + mobj->target->height);
slope = NULL;
}
}
continue;
}
d1 = (mobj->target->z + mobj->target->height) - (top + ((bottom - top)/2));
d2 = mobj->target->z - (top + ((bottom - top)/2));
if (bottom < newz && abs(d1) < abs(d2))
{
newz = bottom;
#ifdef ESLOPE
if (*rover->b_slope)
slope = *rover->b_slope;
#endif
}
}
else
{
if (rover->flags & FF_QUICKSAND)
{
if (mobj->target->z < top && (mobj->target->z + mobj->target->height) > bottom)
{
if (newz < mobj->target->z)
{
newz = mobj->target->z;
slope = NULL;
}
}
continue;
}
d1 = mobj->target->z - (bottom + ((top - bottom)/2));
d2 = (mobj->target->z + mobj->target->height) - (bottom + ((top - bottom)/2));
if (top > newz && abs(d1) < abs(d2))
{
newz = top;
#ifdef ESLOPE
if (*rover->t_slope)
slope = *rover->t_slope;
#endif
}
}
}
}
mobj->standingslope = slope;
#ifdef HWRENDER
mobj->modeltilt = mobj->standingslope;
#endif
newz = P_CalculateShadowFloor(mobj, mobj->target->x, mobj->target->y, mobj->target->z,
mobj->target->radius, mobj->target->height, flip, (mobj->target->player != NULL));
if (flip)
{