From 8ac3cb45cc032e6fa4aee00c9e464873c3c758a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Mon, 7 Oct 2024 18:19:54 +0200 Subject: [PATCH 1/7] Port R_PointOnSide calculation from GZDoom --- src/p_map.c | 5 +++-- src/r_main.c | 49 ------------------------------------------------- src/r_main.h | 19 +++++++++++++++++-- 3 files changed, 20 insertions(+), 53 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 1116ae06a..98a85e614 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2021,7 +2021,7 @@ static boolean PIT_CheckLine(line_t *ld) boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { INT32 xl, xh, yl, yh, bx, by; - subsector_t *newsubsec; + subsector_t *newsubsec = thing->subsector; boolean blockval = true; ps_checkposition_calls.value.i++; @@ -2043,7 +2043,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; - newsubsec = R_PointInSubsector(x, y); + if (thing->x != x || thing->y != y) + newsubsec = R_PointInSubsector(x, y); ceilingline = blockingline = NULL; // The base floor / ceiling is from the subsector diff --git a/src/r_main.c b/src/r_main.c index 32e3138eb..c0b97616a 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -246,55 +246,6 @@ static void FlipCam2_OnChange(void) SendWeaponPref2(); } -// -// R_PointOnSide -// Traverse BSP (sub) tree, -// check point against partition plane. -// Returns side 0 (front) or 1 (back). -// -// killough 5/2/98: reformatted -// -INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *restrict node) -{ - if (!node->dx) - return x <= node->x ? node->dy > 0 : node->dy < 0; - - if (!node->dy) - return y <= node->y ? node->dx < 0 : node->dx > 0; - - fixed_t dx = (x >> 1) - (node->x >> 1); - fixed_t dy = (y >> 1) - (node->y >> 1); - - // Try to quickly decide by looking at sign bits. - // also use a mask to avoid branch prediction - INT32 mask = (node->dy ^ node->dx ^ dx ^ dy) >> 31; - return (mask & ((node->dy ^ dx) < 0)) | // (left is negative) - (~mask & (FixedMul(dy, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, dx))); -} - -// killough 5/2/98: reformatted -INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) -{ - fixed_t lx = line->v1->x; - fixed_t ly = line->v1->y; - fixed_t ldx = line->v2->x - lx; - fixed_t ldy = line->v2->y - ly; - - if (!ldx) - return x <= lx ? ldy > 0 : ldy < 0; - - if (!ldy) - return y <= ly ? ldx < 0 : ldx > 0; - - fixed_t dx = (x >> 1) - (lx >> 1); - fixed_t dy = (y >> 1) - (ly >> 1); - - // Try to quickly decide by looking at sign bits. - if ((ldy ^ ldx ^ dx ^ dy) < 0) - return (ldy ^ dx) < 0; // (left is negative) - return FixedMul(dy, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, dx); -} - // // R_PointToAngle // To get a global angle from cartesian coordinates, diff --git a/src/r_main.h b/src/r_main.h index af7086e83..164952769 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -72,8 +72,23 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; #define NUMCOLORMAPS 32 // Utility functions. -INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node); -INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line); +static inline INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) +{ + // heavily optimized version of R_PointOnSide, stolen from GZDoom. + return (INT64)(y - node->y) * node->dx + (INT64)(node->x - x) * node->dy > 0; +} + +static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) +{ + fixed_t lx = line->v1->x; + fixed_t ly = line->v1->y; + fixed_t ldx = line->v2->x - lx; + fixed_t ldy = line->v2->y - ly; + + // heavily optimized version of R_PointOnSide, stolen from GZDoom. + return (INT64)(y - ly) * ldx + (INT64)(lx - x) * ldy > 0; +} + angle_t R_PointToAngle(fixed_t x, fixed_t y); angle_t R_PointToAngle64(INT64 x, INT64 y); angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); From dafaae65fb4bf5732ebf2d82b034dd2a30262031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Mon, 7 Oct 2024 21:24:37 +0200 Subject: [PATCH 2/7] Avoid dereferencing thing before assertion checks --- src/p_map.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index 98a85e614..c1e73e9f8 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2021,7 +2021,7 @@ static boolean PIT_CheckLine(line_t *ld) boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { INT32 xl, xh, yl, yh, bx, by; - subsector_t *newsubsec = thing->subsector; + subsector_t *newsubsec; boolean blockval = true; ps_checkposition_calls.value.i++; @@ -2045,6 +2045,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (thing->x != x || thing->y != y) newsubsec = R_PointInSubsector(x, y); + else + newsubsec = thing->subsector; ceilingline = blockingline = NULL; // The base floor / ceiling is from the subsector From b8dd0f69e7a64e307034329ce2880b6332f61321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Mon, 21 Oct 2024 17:02:14 +0200 Subject: [PATCH 3/7] Clarify we're calculating a cross product --- src/r_main.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/r_main.h b/src/r_main.h index 164952769..737fb409d 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -74,8 +74,8 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // Utility functions. static inline INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) { - // heavily optimized version of R_PointOnSide, stolen from GZDoom. - return (INT64)(y - node->y) * node->dx + (INT64)(node->x - x) * node->dy > 0; + // use cross product to determine side quickly + return (INT64)(y - node->y) * node->dx - (INT64)(x - node->x) * node->dy > 0; } static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) @@ -85,8 +85,8 @@ static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) fixed_t ldx = line->v2->x - lx; fixed_t ldy = line->v2->y - ly; - // heavily optimized version of R_PointOnSide, stolen from GZDoom. - return (INT64)(y - ly) * ldx + (INT64)(lx - x) * ldy > 0; + // use cross product to determine side quickly + return (INT64)(y - ly) * ldx - (INT64)(x - lx) * ldy > 0; } angle_t R_PointToAngle(fixed_t x, fixed_t y); From a90f495b423b50d4ab4d5492d65d5bb006324fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Wed, 20 Nov 2024 10:35:26 +0100 Subject: [PATCH 4/7] Fix integer overflows on very large numbers --- src/r_main.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_main.h b/src/r_main.h index 737fb409d..c65154dd2 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -75,7 +75,7 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; static inline INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) { // use cross product to determine side quickly - return (INT64)(y - node->y) * node->dx - (INT64)(x - node->x) * node->dy > 0; + return ((INT64)y - node->y) * node->dx - ((INT64)x - node->x) * node->dy > 0; } static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) @@ -86,7 +86,7 @@ static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) fixed_t ldy = line->v2->y - ly; // use cross product to determine side quickly - return (INT64)(y - ly) * ldx - (INT64)(x - lx) * ldy > 0; + return ((INT64)y - ly) * ldx - ((INT64)x - lx) * ldy > 0; } angle_t R_PointToAngle(fixed_t x, fixed_t y); From 3c39edc1ef25003285f0edb01754c6d17a98857b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Sun, 15 Dec 2024 13:24:54 +0100 Subject: [PATCH 5/7] Fall back to old algorithm when on the line --- src/r_main.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/r_main.h | 13 +++++++++++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index c0b97616a..7cacbb610 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -246,6 +246,55 @@ static void FlipCam2_OnChange(void) SendWeaponPref2(); } +// +// R_PointOnSide +// Traverse BSP (sub) tree, +// check point against partition plane. +// Returns side 0 (front) or 1 (back). +// +// killough 5/2/98: reformatted +// +INT32 R_OldPointOnSide(fixed_t x, fixed_t y, node_t *restrict node) +{ + if (!node->dx) + return x <= node->x ? node->dy > 0 : node->dy < 0; + + if (!node->dy) + return y <= node->y ? node->dx < 0 : node->dx > 0; + + fixed_t dx = (x >> 1) - (node->x >> 1); + fixed_t dy = (y >> 1) - (node->y >> 1); + + // Try to quickly decide by looking at sign bits. + // also use a mask to avoid branch prediction + INT32 mask = (node->dy ^ node->dx ^ dx ^ dy) >> 31; + return (mask & ((node->dy ^ dx) < 0)) | // (left is negative) + (~mask & (FixedMul(dy, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, dx))); +} + +// killough 5/2/98: reformatted +INT32 R_OldPointOnSegSide(fixed_t x, fixed_t y, seg_t *line) +{ + fixed_t lx = line->v1->x; + fixed_t ly = line->v1->y; + fixed_t ldx = line->v2->x - lx; + fixed_t ldy = line->v2->y - ly; + + if (!ldx) + return x <= lx ? ldy > 0 : ldy < 0; + + if (!ldy) + return y <= ly ? ldx < 0 : ldx > 0; + + fixed_t dx = (x >> 1) - (lx >> 1); + fixed_t dy = (y >> 1) - (ly >> 1); + + // Try to quickly decide by looking at sign bits. + if ((ldy ^ ldx ^ dx ^ dy) < 0) + return (ldy ^ dx) < 0; // (left is negative) + return FixedMul(dy, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, dx); +} + // // R_PointToAngle // To get a global angle from cartesian coordinates, diff --git a/src/r_main.h b/src/r_main.h index c65154dd2..9767f4b69 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -71,11 +71,17 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; // There a 0-31, i.e. 32 LUT in the COLORMAP lump. #define NUMCOLORMAPS 32 +INT32 R_OldPointOnSide(fixed_t x, fixed_t y, node_t *node); +INT32 R_OldPointOnSegSide(fixed_t x, fixed_t y, seg_t *line); + // Utility functions. static inline INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) { // use cross product to determine side quickly - return ((INT64)y - node->y) * node->dx - ((INT64)x - node->x) * node->dy > 0; + INT64 v = ((INT64)y - node->y) * node->dx - ((INT64)x - node->x) * node->dy; + if (v == 0) // if we're on the line, use the old algorithm + return R_OldPointOnSide(x, y, node); + return v > 0; } static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) @@ -86,7 +92,10 @@ static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) fixed_t ldy = line->v2->y - ly; // use cross product to determine side quickly - return ((INT64)y - ly) * ldx - ((INT64)x - lx) * ldy > 0; + INT64 v = ((INT64)y - ly) * ldx - ((INT64)x - lx) * ldy > 0; + if (v == 0) // if we're on the line, use the old algorithm + return R_OldPointOnSegSide(x, y, line); + return v > 0; } angle_t R_PointToAngle(fixed_t x, fixed_t y); From 1ef47ea1785080296ac40c78564499acd464d38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Wed, 18 Dec 2024 16:50:06 +0100 Subject: [PATCH 6/7] Fix tiny mistake in R_PointOnSegSide --- src/r_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_main.h b/src/r_main.h index 9767f4b69..1c110c1a6 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -92,7 +92,7 @@ static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) fixed_t ldy = line->v2->y - ly; // use cross product to determine side quickly - INT64 v = ((INT64)y - ly) * ldx - ((INT64)x - lx) * ldy > 0; + INT64 v = ((INT64)y - ly) * ldx - ((INT64)x - lx) * ldy; if (v == 0) // if we're on the line, use the old algorithm return R_OldPointOnSegSide(x, y, line); return v > 0; From a33cf4225c7a8b927c0fdfa5b5452ded7bece8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Thu, 2 Jan 2025 13:28:17 +0100 Subject: [PATCH 7/7] Fall back to old R_PointInSubsector for slopes --- src/p_slopes.c | 2 +- src/r_main.c | 10 ++++++++++ src/r_main.h | 9 +++------ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/p_slopes.c b/src/p_slopes.c index 7f070e2a1..62c013d48 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -588,7 +588,7 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag vx[i].y = mt->y << FRACBITS; vx[i].z = mt->z << FRACBITS; if (!mt->args[0]) - vx[i].z += R_PointInSubsector(vx[i].x, vx[i].y)->sector->floorheight; + vx[i].z += R_OldPointInSubsector(vx[i].x, vx[i].y)->sector->floorheight; } ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]); diff --git a/src/r_main.c b/src/r_main.c index 7cacbb610..01ad8b3e4 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1036,6 +1036,16 @@ boolean R_IsPointInSector(sector_t *sector, fixed_t x, fixed_t y) return passes % 2; } +subsector_t *R_OldPointInSubsector(fixed_t x, fixed_t y) +{ + size_t nodenum = numnodes-1; + + while (!(nodenum & NF_SUBSECTOR)) + nodenum = nodes[nodenum].children[R_OldPointOnSide(x, y, nodes+nodenum)]; + + return &subsectors[nodenum & ~NF_SUBSECTOR]; +} + // // R_PointInSubsector // diff --git a/src/r_main.h b/src/r_main.h index 1c110c1a6..ef9f37a4c 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -79,9 +79,7 @@ static inline INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) { // use cross product to determine side quickly INT64 v = ((INT64)y - node->y) * node->dx - ((INT64)x - node->x) * node->dy; - if (v == 0) // if we're on the line, use the old algorithm - return R_OldPointOnSide(x, y, node); - return v > 0; + return v >= 0; } static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) @@ -93,9 +91,7 @@ static inline INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line) // use cross product to determine side quickly INT64 v = ((INT64)y - ly) * ldx - ((INT64)x - lx) * ldy; - if (v == 0) // if we're on the line, use the old algorithm - return R_OldPointOnSegSide(x, y, line); - return v > 0; + return v >= 0; } angle_t R_PointToAngle(fixed_t x, fixed_t y); @@ -105,6 +101,7 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y); fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); boolean R_IsPointInSector(sector_t *sector, fixed_t x, fixed_t y); +subsector_t *R_OldPointInSubsector(fixed_t x, fixed_t y); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y);