Merge pull request 'Merge SRB2 Classic's Antimony PathTraverse' (#79) from antimony-pathtraverse into blankart-dev

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/79
This commit is contained in:
NepDisk 2025-08-18 00:46:15 +02:00
commit a4b695da04
4 changed files with 61 additions and 339 deletions

View file

@ -167,7 +167,6 @@ extern fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS], t_cam_height[MAXSPLITSCREENPLA
void P_AddPlayerScore(player_t *player, UINT32 amount);
void P_ResetCamera(player_t *player, camera_t *thiscam);
boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam);
void P_SlideCameraMove(camera_t *thiscam);
void P_DemoCameraMovement(camera_t *cam, UINT8 num);
void P_ToggleDemoCamera(UINT8 viewnum);
boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled);

View file

@ -3115,55 +3115,10 @@ static boolean P_ThingHeightClip(mobj_t *thing)
// SLIDE MOVE
// Allows the player to slide along any angled walls.
//
static fixed_t bestslidefrac, secondslidefrac;
static line_t *bestslideline;
static line_t *secondslideline;
static mobj_t *slidemo;
static fixed_t tmxmove, tmymove;
//
// P_HitCameraSlideLine
//
static void P_HitCameraSlideLine(line_t *ld, camera_t *thiscam)
{
INT32 side;
angle_t lineangle, moveangle, deltaangle;
fixed_t movelen, newlen;
if (ld->slopetype == ST_HORIZONTAL)
{
tmymove = 0;
return;
}
if (ld->slopetype == ST_VERTICAL)
{
tmxmove = 0;
return;
}
side = P_PointOnLineSide(thiscam->x, thiscam->y, ld);
lineangle = ld->angle;
if (side == 1)
lineangle += ANGLE_180;
moveangle = R_PointToAngle2(0, 0, tmxmove, tmymove);
deltaangle = moveangle-lineangle;
if (deltaangle > ANGLE_180)
deltaangle += ANGLE_180;
lineangle >>= ANGLETOFINESHIFT;
deltaangle >>= ANGLETOFINESHIFT;
movelen = P_AproxDistance(tmxmove, tmymove);
newlen = FixedMul(movelen, FINECOSINE(deltaangle));
tmxmove = FixedMul(newlen, FINECOSINE(lineangle));
tmymove = FixedMul(newlen, FINESINE(lineangle));
}
//
// P_HitSlideLine
// Adjusts the xmove / ymove
@ -3271,57 +3226,6 @@ static void P_HitBounceLine(line_t *ld)
deltaangle = R_PointToAngle2(0, 0, tmxmove, tmymove);
}
//
// PTR_SlideCameraTraverse
//
static boolean PTR_SlideCameraTraverse(intercept_t *in)
{
line_t *li;
opening_t open = {0};
I_Assert(in->isaline);
li = in->d.line;
// one-sided linedef
if (!li->backsector)
{
if (P_PointOnLineSide(mapcampointer->x, mapcampointer->y, li))
return true; // don't hit the back side
goto isblocking;
}
// set openrange, opentop, openbottom
P_CameraLineOpening(li, &open);
if (open.range < mapcampointer->height)
goto isblocking; // doesn't fit
if (open.ceiling - mapcampointer->z < mapcampointer->height)
goto isblocking; // mobj is too high
if (open.floor - mapcampointer->z > 0) // We don't want to make the camera step up.
goto isblocking; // too big a step up
// this line doesn't block movement
return true;
// the line does block movement,
// see if it is closer than best so far
isblocking:
{
if (in->frac < bestslidefrac)
{
secondslidefrac = bestslidefrac;
secondslideline = bestslideline;
bestslidefrac = in->frac;
bestslideline = li;
}
}
return false; // stop
}
/*
static boolean PTR_LineIsBlocking(line_t *li)
{
@ -3382,105 +3286,6 @@ static boolean PTR_SlideTraverse(intercept_t *in)
}
*/
//
// P_SlideCameraMove
//
// Tries to slide the camera along a wall.
//
void P_SlideCameraMove(camera_t *thiscam)
{
fixed_t leadx, leady, trailx, traily, newx, newy;
INT32 hitcount = 0;
INT32 retval = 0;
bestslideline = NULL;
retry:
if (++hitcount == 3)
goto stairstep; // don't loop forever
// trace along the three leading corners
if (thiscam->momx > 0)
{
leadx = thiscam->x + thiscam->radius;
trailx = thiscam->x - thiscam->radius;
}
else
{
leadx = thiscam->x - thiscam->radius;
trailx = thiscam->x + thiscam->radius;
}
if (thiscam->momy > 0)
{
leady = thiscam->y + thiscam->radius;
traily = thiscam->y - thiscam->radius;
}
else
{
leady = thiscam->y - thiscam->radius;
traily = thiscam->y + thiscam->radius;
}
bestslidefrac = FRACUNIT+1;
mapcampointer = thiscam;
P_PathTraverse(leadx, leady, leadx + thiscam->momx, leady + thiscam->momy,
PT_ADDLINES, PTR_SlideCameraTraverse);
P_PathTraverse(trailx, leady, trailx + thiscam->momx, leady + thiscam->momy,
PT_ADDLINES, PTR_SlideCameraTraverse);
P_PathTraverse(leadx, traily, leadx + thiscam->momx, traily + thiscam->momy,
PT_ADDLINES, PTR_SlideCameraTraverse);
// move up to the wall
if (bestslidefrac == FRACUNIT+1)
{
retval = P_TryCameraMove(thiscam->x, thiscam->y + thiscam->momy, thiscam);
// the move must have hit the middle, so stairstep
stairstep:
if (!retval) // Allow things to drop off.
P_TryCameraMove(thiscam->x + thiscam->momx, thiscam->y, thiscam);
return;
}
// fudge a bit to make sure it doesn't hit
bestslidefrac -= 0x800;
if (bestslidefrac > 0)
{
newx = FixedMul(thiscam->momx, bestslidefrac);
newy = FixedMul(thiscam->momy, bestslidefrac);
retval = P_TryCameraMove(thiscam->x + newx, thiscam->y + newy, thiscam);
if (!retval)
goto stairstep;
}
// Now continue along the wall.
// First calculate remainder.
bestslidefrac = FRACUNIT - (bestslidefrac+0x800);
if (bestslidefrac > FRACUNIT)
bestslidefrac = FRACUNIT;
if (bestslidefrac <= 0)
return;
tmxmove = FixedMul(thiscam->momx, bestslidefrac);
tmymove = FixedMul(thiscam->momy, bestslidefrac);
P_HitCameraSlideLine(bestslideline, thiscam); // clip the moves
thiscam->momx = tmxmove;
thiscam->momy = tmymove;
retval = P_TryCameraMove(thiscam->x + tmxmove, thiscam->y + tmymove, thiscam);
if (!retval)
goto retry;
}
static void P_CheckLavaWall(mobj_t *mo, sector_t *sec)
{
ffloor_t *rover;

View file

@ -1736,10 +1736,6 @@ static boolean P_TraverseIntercepts(traverser_t func, fixed_t maxfrac)
boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
INT32 flags, traverser_t trav)
{
fixed_t xt1, yt1, xt2, yt2;
fixed_t xstep, ystep, partialx, partialy, xintercept, yintercept;
INT32 mapx, mapy, mapxstep, mapystep, count;
validcount++;
intercept_p = intercepts;
@ -1756,170 +1752,94 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
px1 -= bmaporgx;
py1 -= bmaporgy;
xt1 = (unsigned)px1>>MAPBLOCKSHIFT;
yt1 = (unsigned)py1>>MAPBLOCKSHIFT;
px2 -= bmaporgx;
py2 -= bmaporgy;
xt2 = (unsigned)px2>>MAPBLOCKSHIFT;
yt2 = (unsigned)py2>>MAPBLOCKSHIFT;
if (xt2 > xt1)
// blockmap traversal algorithm ported from antimony
int gridpos_x = (unsigned)px1 >> MAPBLOCKSHIFT;
int gridpos_y = (unsigned)py1 >> MAPBLOCKSHIFT;
if (flags & PT_ADDLINES)
if (!P_BlockLinesIterator(gridpos_x, gridpos_y, PIT_AddLineIntercepts))
return false; // early out
if (flags & PT_ADDTHINGS)
if (!P_BlockThingsIterator(gridpos_x, gridpos_y, PIT_AddThingIntercepts))
return false; // early out
int endpos_x = (unsigned)px2 >> MAPBLOCKSHIFT;
int endpos_y = (unsigned)py2 >> MAPBLOCKSHIFT;
if (gridpos_x == endpos_x && gridpos_y == endpos_y)
return P_TraverseIntercepts(trav, FRACUNIT);
fixed_t pos_x = px1;
fixed_t pos_y = py1;
fixed_t dist_x = px2 - px1;
fixed_t dist_y = py2 - py1;
int dir_x = dist_x < 0 ? -1 : 1;
int dir_y = dist_y < 0 ? -1 : 1;
fixed_t delta_x;
fixed_t delta_y;
// special cases for 0 to avoid crashes
if (dist_y == 0)
{
mapxstep = 1;
partialx = FRACUNIT - ((px1>>MAPBTOFRAC) & FRACMASK);
ystep = FixedDiv(py2 - py1, abs(px2 - px1));
delta_x = INT32_MAX;
delta_y = 0;
}
else if (xt2 < xt1)
else if (dist_x == 0)
{
mapxstep = -1;
partialx = (px1>>MAPBTOFRAC) & FRACMASK;
ystep = FixedDiv(py2 - py1, abs(px2 - px1));
delta_x = 0;
delta_y = INT32_MAX;
}
else
{
mapxstep = 0;
partialx = FRACUNIT;
ystep = 256*FRACUNIT;
delta_x = FixedDiv2(dist_x, abs(dist_y));
delta_y = FixedDiv2(dist_y, abs(dist_x));
}
yintercept = (py1>>MAPBTOFRAC) + FixedMul(partialx, ystep);
while (gridpos_x >= 0 && gridpos_y >= 0 && gridpos_x < bmapwidth && gridpos_y < bmapheight)
{
fixed_t hitx_x;
if (dir_x > 0)
hitx_x = (gridpos_x+1) << MAPBLOCKSHIFT;
else
hitx_x = gridpos_x << MAPBLOCKSHIFT;
if (yt2 > yt1)
{
mapystep = 1;
partialy = FRACUNIT - ((py1>>MAPBTOFRAC) & FRACMASK);
xstep = FixedDiv(px2 - px1, abs(py2 - py1));
}
else if (yt2 < yt1)
{
mapystep = -1;
partialy = (py1>>MAPBTOFRAC) & FRACMASK;
xstep = FixedDiv(px2 - px1, abs(py2 - py1));
}
else
{
mapystep = 0;
partialy = FRACUNIT;
xstep = 256*FRACUNIT;
}
xintercept = (px1>>MAPBTOFRAC) + FixedMul(partialy, xstep);
fixed_t hity_y;
if (dir_y > 0)
hity_y = (gridpos_y+1) << MAPBLOCKSHIFT;
else
hity_y = gridpos_y << MAPBLOCKSHIFT;
// [RH] Fix for traces that pass only through blockmap corners. In that case,
// xintercept and yintercept can both be set ahead of mapx and mapy, so the
// for loop would never advance anywhere.
if (abs(xstep) == FRACUNIT && abs(ystep) == FRACUNIT)
{
if (ystep < 0)
hitx_x -= pos_x;
hity_y -= pos_y;
fixed_t hitx_y = FixedMul(delta_y, abs(hitx_x));
fixed_t hity_x = FixedMul(delta_x, abs(hity_y));
if (FixedMul(hitx_x, hitx_x) + FixedMul(hitx_y, hitx_y) > FixedMul(hity_x, hity_x) + FixedMul(hity_y, hity_y))
{
partialx = FRACUNIT - partialx;
gridpos_y += dir_y;
pos_x += hity_x;
pos_y += hity_y;
}
if (xstep < 0)
else
{
partialy = FRACUNIT - partialy;
gridpos_x += dir_x;
pos_x += hitx_x;
pos_y += hitx_y;
}
if (partialx == partialy)
{
xintercept = xt1 << FRACBITS;
yintercept = yt1 << FRACBITS;
}
}
// Step through map blocks.
// Count is present to prevent a round off error
// from skipping the break.
mapx = xt1;
mapy = yt1;
for (count = 0; count < 100; count++)
{
if (flags & PT_ADDLINES)
{
P_BlockLinesIterator(mapx, mapy, PIT_AddLineIntercepts);
}
if (!P_BlockLinesIterator(gridpos_x, gridpos_y, PIT_AddLineIntercepts))
return false; // early out
if (flags & PT_ADDTHINGS)
{
P_BlockThingsIterator(mapx, mapy, PIT_AddThingIntercepts);
}
// both coordinates reached the end, so end the traversing.
if ((mapxstep | mapystep) == 0)
{
if (!P_BlockThingsIterator(gridpos_x, gridpos_y, PIT_AddThingIntercepts))
return false; // early out
if (gridpos_x == endpos_x && gridpos_y == endpos_y)
break;
}
// [RH] Handle corner cases properly instead of pretending they don't exist.
switch ( (((yintercept >> FRACBITS) == mapy) << 1) | ((xintercept >> FRACBITS) == mapx) )
{
case 0: // neither xintercept nor yintercept match!
{
count = 100; // Stop traversing, because somebody screwed up.
break;
}
case 1: // xintercept matches
{
xintercept += xstep;
mapy += mapystep;
if (mapy == yt2)
{
mapystep = 0;
}
break;
}
case 2: // yintercept matches
{
yintercept += ystep;
mapx += mapxstep;
if (mapx == xt2)
{
mapxstep = 0;
}
break;
}
case 3: // xintercept and yintercept both match
{
// The trace is exiting a block through its corner. Not only does the block
// being entered need to be checked (which will happen when this loop
// continues), but the other two blocks adjacent to the corner also need to
// be checked.
if (flags & PT_ADDLINES)
{
P_BlockLinesIterator(mapx + mapxstep, mapy, PIT_AddLineIntercepts);
P_BlockLinesIterator(mapx, mapy + mapystep, PIT_AddLineIntercepts);
}
if (flags & PT_ADDTHINGS)
{
P_BlockThingsIterator(mapx + mapxstep, mapy, PIT_AddThingIntercepts);
P_BlockThingsIterator(mapx, mapy + mapystep, PIT_AddThingIntercepts);
}
xintercept += xstep;
yintercept += ystep;
mapx += mapxstep;
mapy += mapystep;
if (mapx == xt2)
{
mapxstep = 0;
}
if (mapy == yt2)
{
mapystep = 0;
}
break;
}
}
}
// Go through the sorted list
return P_TraverseIntercepts(trav, FRACUNIT);
}
// =========================================================================
// BLOCKMAP ITERATORS
// =========================================================================

View file

@ -3642,8 +3642,6 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
{
fixed_t camspeed = P_AproxDistance(thiscam->momx, thiscam->momy);
P_SlideCameraMove(thiscam);
if (!resetcalled && P_AproxDistance(thiscam->momx, thiscam->momy) == camspeed)
{
P_ResetCamera(player, thiscam);