Bounds.cpp (10806B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../precompiled.h" 31 32 idBounds bounds_zero( vec3_zero, vec3_zero ); 33 idBounds bounds_zeroOneCube( idVec3( 0.0f ), idVec3( 1.0f ) ); 34 idBounds bounds_unitCube( idVec3( -1.0f ), idVec3( 1.0f ) ); 35 36 /* 37 ============ 38 idBounds::GetRadius 39 ============ 40 */ 41 float idBounds::GetRadius() const { 42 int i; 43 float total, b0, b1; 44 45 total = 0.0f; 46 for ( i = 0; i < 3; i++ ) { 47 b0 = (float)idMath::Fabs( b[0][i] ); 48 b1 = (float)idMath::Fabs( b[1][i] ); 49 if ( b0 > b1 ) { 50 total += b0 * b0; 51 } else { 52 total += b1 * b1; 53 } 54 } 55 return idMath::Sqrt( total ); 56 } 57 58 /* 59 ============ 60 idBounds::GetRadius 61 ============ 62 */ 63 float idBounds::GetRadius( const idVec3 ¢er ) const { 64 int i; 65 float total, b0, b1; 66 67 total = 0.0f; 68 for ( i = 0; i < 3; i++ ) { 69 b0 = (float)idMath::Fabs( center[i] - b[0][i] ); 70 b1 = (float)idMath::Fabs( b[1][i] - center[i] ); 71 if ( b0 > b1 ) { 72 total += b0 * b0; 73 } else { 74 total += b1 * b1; 75 } 76 } 77 return idMath::Sqrt( total ); 78 } 79 80 /* 81 ================ 82 idBounds::PlaneDistance 83 ================ 84 */ 85 float idBounds::PlaneDistance( const idPlane &plane ) const { 86 idVec3 center; 87 float d1, d2; 88 89 center = ( b[0] + b[1] ) * 0.5f; 90 91 d1 = plane.Distance( center ); 92 d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) + 93 idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) + 94 idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] ); 95 96 if ( d1 - d2 > 0.0f ) { 97 return d1 - d2; 98 } 99 if ( d1 + d2 < 0.0f ) { 100 return d1 + d2; 101 } 102 return 0.0f; 103 } 104 105 /* 106 ================ 107 idBounds::PlaneSide 108 ================ 109 */ 110 int idBounds::PlaneSide( const idPlane &plane, const float epsilon ) const { 111 idVec3 center; 112 float d1, d2; 113 114 center = ( b[0] + b[1] ) * 0.5f; 115 116 d1 = plane.Distance( center ); 117 d2 = idMath::Fabs( ( b[1][0] - center[0] ) * plane.Normal()[0] ) + 118 idMath::Fabs( ( b[1][1] - center[1] ) * plane.Normal()[1] ) + 119 idMath::Fabs( ( b[1][2] - center[2] ) * plane.Normal()[2] ); 120 121 if ( d1 - d2 > epsilon ) { 122 return PLANESIDE_FRONT; 123 } 124 if ( d1 + d2 < -epsilon ) { 125 return PLANESIDE_BACK; 126 } 127 return PLANESIDE_CROSS; 128 } 129 130 /* 131 ============ 132 idBounds::LineIntersection 133 134 Returns true if the line intersects the bounds between the start and end point. 135 ============ 136 */ 137 bool idBounds::LineIntersection( const idVec3 &start, const idVec3 &end ) const { 138 const idVec3 center = ( b[0] + b[1] ) * 0.5f; 139 const idVec3 extents = b[1] - center; 140 const idVec3 lineDir = 0.5f * ( end - start ); 141 const idVec3 lineCenter = start + lineDir; 142 const idVec3 dir = lineCenter - center; 143 144 const float ld0 = idMath::Fabs( lineDir[0] ); 145 if ( idMath::Fabs( dir[0] ) > extents[0] + ld0 ) { 146 return false; 147 } 148 149 const float ld1 = idMath::Fabs( lineDir[1] ); 150 if ( idMath::Fabs( dir[1] ) > extents[1] + ld1 ) { 151 return false; 152 } 153 154 const float ld2 = idMath::Fabs( lineDir[2] ); 155 if ( idMath::Fabs( dir[2] ) > extents[2] + ld2 ) { 156 return false; 157 } 158 159 const idVec3 cross = lineDir.Cross( dir ); 160 161 if ( idMath::Fabs( cross[0] ) > extents[1] * ld2 + extents[2] * ld1 ) { 162 return false; 163 } 164 165 if ( idMath::Fabs( cross[1] ) > extents[0] * ld2 + extents[2] * ld0 ) { 166 return false; 167 } 168 169 if ( idMath::Fabs( cross[2] ) > extents[0] * ld1 + extents[1] * ld0 ) { 170 return false; 171 } 172 173 return true; 174 } 175 176 /* 177 ============ 178 idBounds::RayIntersection 179 180 Returns true if the ray intersects the bounds. 181 The ray can intersect the bounds in both directions from the start point. 182 If start is inside the bounds it is considered an intersection with scale = 0 183 ============ 184 */ 185 bool idBounds::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const { 186 int i, ax0, ax1, ax2, side, inside; 187 float f; 188 idVec3 hit; 189 190 ax0 = -1; 191 inside = 0; 192 for ( i = 0; i < 3; i++ ) { 193 if ( start[i] < b[0][i] ) { 194 side = 0; 195 } 196 else if ( start[i] > b[1][i] ) { 197 side = 1; 198 } 199 else { 200 inside++; 201 continue; 202 } 203 if ( dir[i] == 0.0f ) { 204 continue; 205 } 206 f = ( start[i] - b[side][i] ); 207 if ( ax0 < 0 || idMath::Fabs( f ) > idMath::Fabs( scale * dir[i] ) ) { 208 scale = - ( f / dir[i] ); 209 ax0 = i; 210 } 211 } 212 213 if ( ax0 < 0 ) { 214 scale = 0.0f; 215 // return true if the start point is inside the bounds 216 return ( inside == 3 ); 217 } 218 219 ax1 = (ax0+1)%3; 220 ax2 = (ax0+2)%3; 221 hit[ax1] = start[ax1] + scale * dir[ax1]; 222 hit[ax2] = start[ax2] + scale * dir[ax2]; 223 224 return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] && 225 hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] ); 226 } 227 228 /* 229 ============ 230 idBounds::FromTransformedBounds 231 ============ 232 */ 233 void idBounds::FromTransformedBounds( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis ) { 234 int i; 235 idVec3 center, extents, rotatedExtents; 236 237 center = (bounds[0] + bounds[1]) * 0.5f; 238 extents = bounds[1] - center; 239 240 for ( i = 0; i < 3; i++ ) { 241 rotatedExtents[i] = idMath::Fabs( extents[0] * axis[0][i] ) + 242 idMath::Fabs( extents[1] * axis[1][i] ) + 243 idMath::Fabs( extents[2] * axis[2][i] ); 244 } 245 246 center = origin + center * axis; 247 b[0] = center - rotatedExtents; 248 b[1] = center + rotatedExtents; 249 } 250 251 /* 252 ============ 253 idBounds::FromPoints 254 255 Most tight bounds for a point set. 256 ============ 257 */ 258 void idBounds::FromPoints( const idVec3 *points, const int numPoints ) { 259 SIMDProcessor->MinMax( b[0], b[1], points, numPoints ); 260 } 261 262 /* 263 ============ 264 idBounds::FromPointTranslation 265 266 Most tight bounds for the translational movement of the given point. 267 ============ 268 */ 269 void idBounds::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) { 270 int i; 271 272 for ( i = 0; i < 3; i++ ) { 273 if ( translation[i] < 0.0f ) { 274 b[0][i] = point[i] + translation[i]; 275 b[1][i] = point[i]; 276 } 277 else { 278 b[0][i] = point[i]; 279 b[1][i] = point[i] + translation[i]; 280 } 281 } 282 } 283 284 /* 285 ============ 286 idBounds::FromBoundsTranslation 287 288 Most tight bounds for the translational movement of the given bounds. 289 ============ 290 */ 291 void idBounds::FromBoundsTranslation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idVec3 &translation ) { 292 int i; 293 294 if ( axis.IsRotated() ) { 295 FromTransformedBounds( bounds, origin, axis ); 296 } 297 else { 298 b[0] = bounds[0] + origin; 299 b[1] = bounds[1] + origin; 300 } 301 for ( i = 0; i < 3; i++ ) { 302 if ( translation[i] < 0.0f ) { 303 b[0][i] += translation[i]; 304 } 305 else { 306 b[1][i] += translation[i]; 307 } 308 } 309 } 310 311 /* 312 ================ 313 BoundsForPointRotation 314 315 only for rotations < 180 degrees 316 ================ 317 */ 318 idBounds BoundsForPointRotation( const idVec3 &start, const idRotation &rotation ) { 319 int i; 320 float radiusSqr; 321 idVec3 v1, v2; 322 idVec3 origin, axis, end; 323 idBounds bounds; 324 325 end = start * rotation; 326 axis = rotation.GetVec(); 327 origin = rotation.GetOrigin() + axis * ( axis * ( start - rotation.GetOrigin() ) ); 328 radiusSqr = ( start - origin ).LengthSqr(); 329 v1 = ( start - origin ).Cross( axis ); 330 v2 = ( end - origin ).Cross( axis ); 331 332 for ( i = 0; i < 3; i++ ) { 333 // if the derivative changes sign along this axis during the rotation from start to end 334 if ( ( v1[i] > 0.0f && v2[i] < 0.0f ) || ( v1[i] < 0.0f && v2[i] > 0.0f ) ) { 335 if ( ( 0.5f * (start[i] + end[i]) - origin[i] ) > 0.0f ) { 336 bounds[0][i] = Min( start[i], end[i] ); 337 bounds[1][i] = origin[i] + idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) ); 338 } 339 else { 340 bounds[0][i] = origin[i] - idMath::Sqrt( radiusSqr * ( 1.0f - axis[i] * axis[i] ) ); 341 bounds[1][i] = Max( start[i], end[i] ); 342 } 343 } 344 else if ( start[i] > end[i] ) { 345 bounds[0][i] = end[i]; 346 bounds[1][i] = start[i]; 347 } 348 else { 349 bounds[0][i] = start[i]; 350 bounds[1][i] = end[i]; 351 } 352 } 353 354 return bounds; 355 } 356 357 /* 358 ============ 359 idBounds::FromPointRotation 360 361 Most tight bounds for the rotational movement of the given point. 362 ============ 363 */ 364 void idBounds::FromPointRotation( const idVec3 &point, const idRotation &rotation ) { 365 float radius; 366 367 if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) { 368 (*this) = BoundsForPointRotation( point, rotation ); 369 } 370 else { 371 372 radius = ( point - rotation.GetOrigin() ).Length(); 373 374 // FIXME: these bounds are usually way larger 375 b[0].Set( -radius, -radius, -radius ); 376 b[1].Set( radius, radius, radius ); 377 } 378 } 379 380 /* 381 ============ 382 idBounds::FromBoundsRotation 383 384 Most tight bounds for the rotational movement of the given bounds. 385 ============ 386 */ 387 void idBounds::FromBoundsRotation( const idBounds &bounds, const idVec3 &origin, const idMat3 &axis, const idRotation &rotation ) { 388 int i; 389 float radius; 390 idVec3 point; 391 idBounds rBounds; 392 393 if ( idMath::Fabs( rotation.GetAngle() ) < 180.0f ) { 394 395 (*this) = BoundsForPointRotation( bounds[0] * axis + origin, rotation ); 396 for ( i = 1; i < 8; i++ ) { 397 point[0] = bounds[(i^(i>>1))&1][0]; 398 point[1] = bounds[(i>>1)&1][1]; 399 point[2] = bounds[(i>>2)&1][2]; 400 (*this) += BoundsForPointRotation( point * axis + origin, rotation ); 401 } 402 } 403 else { 404 405 point = (bounds[1] - bounds[0]) * 0.5f; 406 radius = (bounds[1] - point).Length() + (point - rotation.GetOrigin()).Length(); 407 408 // FIXME: these bounds are usually way larger 409 b[0].Set( -radius, -radius, -radius ); 410 b[1].Set( radius, radius, radius ); 411 } 412 } 413 414 /* 415 ============ 416 idBounds::ToPoints 417 ============ 418 */ 419 void idBounds::ToPoints( idVec3 points[8] ) const { 420 for ( int i = 0; i < 8; i++ ) { 421 points[i][0] = b[(i^(i>>1))&1][0]; 422 points[i][1] = b[(i>>1)&1][1]; 423 points[i][2] = b[(i>>2)&1][2]; 424 } 425 }