From cc5f1d9fd210917fa47f15c71816b770780ad987 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 4 Feb 2025 03:33:23 +0100 Subject: [PATCH] Fix issues in first map of the "UAC Franchise 666" user campaign, #651 somehow the collision code managed to spread NaNs on Win32, which caused a horrible framerate, "GetPointOutsideObstacles: no valid point found" warnings in the console and assertions in debug builds. Didn't happen in Vanilla Doom3 though. At the location I changed the code in, I saw the following values in the debugger: normal: {x=0.00610326231 y=5.58793545e-09 z=1.19209290e-07 } trmEdge->start: {x=-1358.00000 y=913.948975 z=25.2637405 } start: {x=-1358.00000 y=916.000000 z=34.0000000 } end: {x=-1358.00000 y=810.000000 z=34.0000000 } dist (normal*trmEdge->start): -8.28822231 d1: 9.53674316e-07 d2: 9.53674316e-07 f1 (d1/(d1-d2)): inf "normal" isn't normalized and also very small (in all directions), "start" and "end" have quite different y values, but still doing scalar multiplications of each with "normal" gave the same result.. No idea what this all means exactly, but checking if d1 - d2 is (almost) 0 to prevent INF solved the problems. In the end it will be some tiny differences in floating point calculations between different platforms and compilers.. In my test d1-d2 was exactly 0, but I compare with FLT_EPSILON to be on the safer side. --- neo/cm/CollisionModel_translate.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/neo/cm/CollisionModel_translate.cpp b/neo/cm/CollisionModel_translate.cpp index 1c6982ba..7a55dfd1 100644 --- a/neo/cm/CollisionModel_translate.cpp +++ b/neo/cm/CollisionModel_translate.cpp @@ -319,7 +319,10 @@ void idCollisionModelManagerLocal::TranslateTrmEdgeThroughPolygon( cm_traceWork_ dist = normal * trmEdge->start; d1 = normal * start - dist; d2 = normal * end - dist; - f1 = d1 / ( d1 - d2 ); + float d1d2diff = d1 - d2; + // DG: d1 - d2 was 0 in some weird case, which caused f1 to be INF, + // which caused NaN mayhem all over the place + f1 = ( fabsf(d1d2diff) > idMath::FLT_EPSILON ) ? d1 / d1d2diff : 0.0f; //assert( f1 >= 0.0f && f1 <= 1.0f ); tw->trace.c.point = start + f1 * ( end - start ); // if retrieving contacts