From 23d0d70ea65a997ee855e80ea000fc2b538a4d32 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 17 Nov 2009 13:50:46 +0000 Subject: [PATCH] - fixed: R_PointToAngle could overflow with very long vectors passed to it. This caused rendering bugs on some maps. (Interestingly the only other port having a safeguard for this in place was PrBoom.) SVN r1985 (trunk) --- docs/rh-log.txt | 3 ++ src/r_main.cpp | 95 ++++++++++++++++++++++++++++--------------------- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index c1c2593d2..453bdf4d9 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,7 @@ November 17, 2009 (Changes by Graf Zahl) +- fixed: R_PointToAngle could overflow with very long vectors passed to + it. This caused rendering bugs on some maps. (Interestingly the only + other port having a safeguard for this in place was PrBoom.) - reverted the change that makes 0-damage projectiles call P_DamageMobj. Both Hexen and Heretic depend on such projectiles not doing it as do many mods that create snow/rain effects plus any terrain splash mod. diff --git a/src/r_main.cpp b/src/r_main.cpp index bcec61c73..e960c7c5c 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -264,58 +264,71 @@ angle_t R_PointToAngle2 (fixed_t x1, fixed_t y1, fixed_t x, fixed_t y) return 0; } - if (x >= 0) + // We need to be aware of overflows here. If the values get larger than INT_MAX/4 + // this code won't work anymore. + + if (x < INT_MAX/4 && x > -INT_MAX/4 && y < INT_MAX/4 && y > -INT_MAX/4) { - if (y >= 0) + if (x >= 0) { - if (x > y) - { // octant 0 - return SlopeDiv(y, x); + if (y >= 0) + { + if (x > y) + { // octant 0 + return SlopeDiv(y, x); + } + else + { // octant 1 + return ANG90 - 1 - SlopeDiv(x, y); + } } - else - { // octant 1 - return ANG90 - 1 - SlopeDiv(x, y); + else // y < 0 + { + y = -y; + if (x > y) + { // octant 8 + return 0 - SlopeDiv(y, x); + } + else + { // octant 7 + return ANG270 + SlopeDiv(x, y); + } } } - else // y < 0 + else // x < 0 { - y = -y; - if (x > y) - { // octant 8 - return 0 - SlopeDiv(y, x); + x = -x; + if (y >= 0) + { + if (x > y) + { // octant 3 + return ANG180 - 1 - SlopeDiv(y, x); + } + else + { // octant 2 + return ANG90 + SlopeDiv(x, y); + } } - else - { // octant 7 - return ANG270 + SlopeDiv(x, y); + else // y < 0 + { + y = -y; + if (x > y) + { // octant 4 + return ANG180 + SlopeDiv(y, x); + } + else + { // octant 5 + return ANG270 - 1 - SlopeDiv(x, y); + } } } } - else // x < 0 + else { - x = -x; - if (y >= 0) - { - if (x > y) - { // octant 3 - return ANG180 - 1 - SlopeDiv(y, x); - } - else - { // octant 2 - return ANG90 + SlopeDiv(x, y); - } - } - else // y < 0 - { - y = -y; - if (x > y) - { // octant 4 - return ANG180 + SlopeDiv(y, x); - } - else - { // octant 5 - return ANG270 - 1 - SlopeDiv(x, y); - } - } + // we have to use the slower but more precise floating point atan2 function here. + // (use quickertoint to speed this up because the CRT's conversion is rather slow and + // this is used in time critical code.) + return quickertoint((float)(atan2f(float(y-viewy), float(x-viewx)) * (ANGLE_180/M_PI))); } }