Box.cpp (22712B)
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 idBox box_zero( vec3_zero, vec3_zero, mat3_identity ); 33 34 /* 35 4---{4}---5 36 + /| /| 37 Z {7} {8} {5} | 38 - / | / {9} 39 7--{6}----6 | 40 | | | | 41 {11} 0---|-{0}-1 42 | / | / - 43 | {3} {10} {1} Y 44 |/ |/ + 45 3---{2}---2 46 47 - X + 48 49 plane bits: 50 0 = min x 51 1 = max x 52 2 = min y 53 3 = max y 54 4 = min z 55 5 = max z 56 57 */ 58 59 /* 60 static int boxVertPlanes[8] = { 61 ( (1<<0) | (1<<2) | (1<<4) ), 62 ( (1<<1) | (1<<2) | (1<<4) ), 63 ( (1<<1) | (1<<3) | (1<<4) ), 64 ( (1<<0) | (1<<3) | (1<<4) ), 65 ( (1<<0) | (1<<2) | (1<<5) ), 66 ( (1<<1) | (1<<2) | (1<<5) ), 67 ( (1<<1) | (1<<3) | (1<<5) ), 68 ( (1<<0) | (1<<3) | (1<<5) ) 69 }; 70 71 static int boxVertEdges[8][3] = { 72 // bottom 73 { 3, 0, 8 }, 74 { 0, 1, 9 }, 75 { 1, 2, 10 }, 76 { 2, 3, 11 }, 77 // top 78 { 7, 4, 8 }, 79 { 4, 5, 9 }, 80 { 5, 6, 10 }, 81 { 6, 7, 11 } 82 }; 83 84 static int boxEdgePlanes[12][2] = { 85 // bottom 86 { 4, 2 }, 87 { 4, 1 }, 88 { 4, 3 }, 89 { 4, 0 }, 90 // top 91 { 5, 2 }, 92 { 5, 1 }, 93 { 5, 3 }, 94 { 5, 0 }, 95 // sides 96 { 0, 2 }, 97 { 2, 1 }, 98 { 1, 3 }, 99 { 3, 0 } 100 }; 101 102 static int boxEdgeVerts[12][2] = { 103 // bottom 104 { 0, 1 }, 105 { 1, 2 }, 106 { 2, 3 }, 107 { 3, 0 }, 108 // top 109 { 4, 5 }, 110 { 5, 6 }, 111 { 6, 7 }, 112 { 7, 4 }, 113 // sides 114 { 0, 4 }, 115 { 1, 5 }, 116 { 2, 6 }, 117 { 3, 7 } 118 }; 119 */ 120 121 static int boxPlaneBitsSilVerts[64][7] = { 122 { 0, 0, 0, 0, 0, 0, 0 }, // 000000 = 0 123 { 4, 7, 4, 0, 3, 0, 0 }, // 000001 = 1 124 { 4, 5, 6, 2, 1, 0, 0 }, // 000010 = 2 125 { 0, 0, 0, 0, 0, 0, 0 }, // 000011 = 3 126 { 4, 4, 5, 1, 0, 0, 0 }, // 000100 = 4 127 { 6, 3, 7, 4, 5, 1, 0 }, // 000101 = 5 128 { 6, 4, 5, 6, 2, 1, 0 }, // 000110 = 6 129 { 0, 0, 0, 0, 0, 0, 0 }, // 000111 = 7 130 { 4, 6, 7, 3, 2, 0, 0 }, // 001000 = 8 131 { 6, 6, 7, 4, 0, 3, 2 }, // 001001 = 9 132 { 6, 5, 6, 7, 3, 2, 1 }, // 001010 = 10 133 { 0, 0, 0, 0, 0, 0, 0 }, // 001011 = 11 134 { 0, 0, 0, 0, 0, 0, 0 }, // 001100 = 12 135 { 0, 0, 0, 0, 0, 0, 0 }, // 001101 = 13 136 { 0, 0, 0, 0, 0, 0, 0 }, // 001110 = 14 137 { 0, 0, 0, 0, 0, 0, 0 }, // 001111 = 15 138 { 4, 0, 1, 2, 3, 0, 0 }, // 010000 = 16 139 { 6, 0, 1, 2, 3, 7, 4 }, // 010001 = 17 140 { 6, 3, 2, 6, 5, 1, 0 }, // 010010 = 18 141 { 0, 0, 0, 0, 0, 0, 0 }, // 010011 = 19 142 { 6, 1, 2, 3, 0, 4, 5 }, // 010100 = 20 143 { 6, 1, 2, 3, 7, 4, 5 }, // 010101 = 21 144 { 6, 2, 3, 0, 4, 5, 6 }, // 010110 = 22 145 { 0, 0, 0, 0, 0, 0, 0 }, // 010111 = 23 146 { 6, 0, 1, 2, 6, 7, 3 }, // 011000 = 24 147 { 6, 0, 1, 2, 6, 7, 4 }, // 011001 = 25 148 { 6, 0, 1, 5, 6, 7, 3 }, // 011010 = 26 149 { 0, 0, 0, 0, 0, 0, 0 }, // 011011 = 27 150 { 0, 0, 0, 0, 0, 0, 0 }, // 011100 = 28 151 { 0, 0, 0, 0, 0, 0, 0 }, // 011101 = 29 152 { 0, 0, 0, 0, 0, 0, 0 }, // 011110 = 30 153 { 0, 0, 0, 0, 0, 0, 0 }, // 011111 = 31 154 { 4, 7, 6, 5, 4, 0, 0 }, // 100000 = 32 155 { 6, 7, 6, 5, 4, 0, 3 }, // 100001 = 33 156 { 6, 5, 4, 7, 6, 2, 1 }, // 100010 = 34 157 { 0, 0, 0, 0, 0, 0, 0 }, // 100011 = 35 158 { 6, 4, 7, 6, 5, 1, 0 }, // 100100 = 36 159 { 6, 3, 7, 6, 5, 1, 0 }, // 100101 = 37 160 { 6, 4, 7, 6, 2, 1, 0 }, // 100110 = 38 161 { 0, 0, 0, 0, 0, 0, 0 }, // 100111 = 39 162 { 6, 6, 5, 4, 7, 3, 2 }, // 101000 = 40 163 { 6, 6, 5, 4, 0, 3, 2 }, // 101001 = 41 164 { 6, 5, 4, 7, 3, 2, 1 }, // 101010 = 42 165 { 0, 0, 0, 0, 0, 0, 0 }, // 101011 = 43 166 { 0, 0, 0, 0, 0, 0, 0 }, // 101100 = 44 167 { 0, 0, 0, 0, 0, 0, 0 }, // 101101 = 45 168 { 0, 0, 0, 0, 0, 0, 0 }, // 101110 = 46 169 { 0, 0, 0, 0, 0, 0, 0 }, // 101111 = 47 170 { 0, 0, 0, 0, 0, 0, 0 }, // 110000 = 48 171 { 0, 0, 0, 0, 0, 0, 0 }, // 110001 = 49 172 { 0, 0, 0, 0, 0, 0, 0 }, // 110010 = 50 173 { 0, 0, 0, 0, 0, 0, 0 }, // 110011 = 51 174 { 0, 0, 0, 0, 0, 0, 0 }, // 110100 = 52 175 { 0, 0, 0, 0, 0, 0, 0 }, // 110101 = 53 176 { 0, 0, 0, 0, 0, 0, 0 }, // 110110 = 54 177 { 0, 0, 0, 0, 0, 0, 0 }, // 110111 = 55 178 { 0, 0, 0, 0, 0, 0, 0 }, // 111000 = 56 179 { 0, 0, 0, 0, 0, 0, 0 }, // 111001 = 57 180 { 0, 0, 0, 0, 0, 0, 0 }, // 111010 = 58 181 { 0, 0, 0, 0, 0, 0, 0 }, // 111011 = 59 182 { 0, 0, 0, 0, 0, 0, 0 }, // 111100 = 60 183 { 0, 0, 0, 0, 0, 0, 0 }, // 111101 = 61 184 { 0, 0, 0, 0, 0, 0, 0 }, // 111110 = 62 185 { 0, 0, 0, 0, 0, 0, 0 }, // 111111 = 63 186 }; 187 188 189 /* 190 ============ 191 idBox::AddPoint 192 ============ 193 */ 194 bool idBox::AddPoint( const idVec3 &v ) { 195 idMat3 axis2; 196 idBounds bounds1, bounds2; 197 198 if ( extents[0] < 0.0f ) { 199 extents.Zero(); 200 center = v; 201 axis.Identity(); 202 return true; 203 } 204 205 bounds1[0][0] = bounds1[1][0] = center * axis[0]; 206 bounds1[0][1] = bounds1[1][1] = center * axis[1]; 207 bounds1[0][2] = bounds1[1][2] = center * axis[2]; 208 bounds1[0] -= extents; 209 bounds1[1] += extents; 210 if ( !bounds1.AddPoint( idVec3( v * axis[0], v * axis[1], v * axis[2] ) ) ) { 211 // point is contained in the box 212 return false; 213 } 214 215 axis2[0] = v - center; 216 axis2[0].Normalize(); 217 axis2[1] = axis[ Min3Index( axis2[0] * axis[0], axis2[0] * axis[1], axis2[0] * axis[2] ) ]; 218 axis2[1] = axis2[1] - ( axis2[1] * axis2[0] ) * axis2[0]; 219 axis2[1].Normalize(); 220 axis2[2].Cross( axis2[0], axis2[1] ); 221 222 AxisProjection( axis2, bounds2 ); 223 bounds2.AddPoint( idVec3( v * axis2[0], v * axis2[1], v * axis2[2] ) ); 224 225 // create new box based on the smallest bounds 226 if ( bounds1.GetVolume() < bounds2.GetVolume() ) { 227 center = ( bounds1[0] + bounds1[1] ) * 0.5f; 228 extents = bounds1[1] - center; 229 center *= axis; 230 } 231 else { 232 center = ( bounds2[0] + bounds2[1] ) * 0.5f; 233 extents = bounds2[1] - center; 234 center *= axis2; 235 axis = axis2; 236 } 237 return true; 238 } 239 240 /* 241 ============ 242 idBox::AddBox 243 ============ 244 */ 245 bool idBox::AddBox( const idBox &a ) { 246 int i, besti; 247 float v, bestv; 248 idVec3 dir; 249 idMat3 ax[4]; 250 idBounds bounds[4], b; 251 252 if ( a.extents[0] < 0.0f ) { 253 return false; 254 } 255 256 if ( extents[0] < 0.0f ) { 257 center = a.center; 258 extents = a.extents; 259 axis = a.axis; 260 return true; 261 } 262 263 // test axis of this box 264 ax[0] = axis; 265 bounds[0][0][0] = bounds[0][1][0] = center * ax[0][0]; 266 bounds[0][0][1] = bounds[0][1][1] = center * ax[0][1]; 267 bounds[0][0][2] = bounds[0][1][2] = center * ax[0][2]; 268 bounds[0][0] -= extents; 269 bounds[0][1] += extents; 270 a.AxisProjection( ax[0], b ); 271 if ( !bounds[0].AddBounds( b ) ) { 272 // the other box is contained in this box 273 return false; 274 } 275 276 // test axis of other box 277 ax[1] = a.axis; 278 bounds[1][0][0] = bounds[1][1][0] = a.center * ax[1][0]; 279 bounds[1][0][1] = bounds[1][1][1] = a.center * ax[1][1]; 280 bounds[1][0][2] = bounds[1][1][2] = a.center * ax[1][2]; 281 bounds[1][0] -= a.extents; 282 bounds[1][1] += a.extents; 283 AxisProjection( ax[1], b ); 284 if ( !bounds[1].AddBounds( b ) ) { 285 // this box is contained in the other box 286 center = a.center; 287 extents = a.extents; 288 axis = a.axis; 289 return true; 290 } 291 292 // test axes aligned with the vector between the box centers and one of the box axis 293 dir = a.center - center; 294 dir.Normalize(); 295 for ( i = 2; i < 4; i++ ) { 296 ax[i][0] = dir; 297 ax[i][1] = ax[i-2][ Min3Index( dir * ax[i-2][0], dir * ax[i-2][1], dir * ax[i-2][2] ) ]; 298 ax[i][1] = ax[i][1] - ( ax[i][1] * dir ) * dir; 299 ax[i][1].Normalize(); 300 ax[i][2].Cross( dir, ax[i][1] ); 301 302 AxisProjection( ax[i], bounds[i] ); 303 a.AxisProjection( ax[i], b ); 304 bounds[i].AddBounds( b ); 305 } 306 307 // get the bounds with the smallest volume 308 bestv = idMath::INFINITY; 309 besti = 0; 310 for ( i = 0; i < 4; i++ ) { 311 v = bounds[i].GetVolume(); 312 if ( v < bestv ) { 313 bestv = v; 314 besti = i; 315 } 316 } 317 318 // create a box from the smallest bounds axis pair 319 center = ( bounds[besti][0] + bounds[besti][1] ) * 0.5f; 320 extents = bounds[besti][1] - center; 321 center *= ax[besti]; 322 axis = ax[besti]; 323 324 return false; 325 } 326 327 /* 328 ================ 329 idBox::PlaneDistance 330 ================ 331 */ 332 float idBox::PlaneDistance( const idPlane &plane ) const { 333 float d1, d2; 334 335 d1 = plane.Distance( center ); 336 d2 = idMath::Fabs( extents[0] * plane.Normal()[0] ) + 337 idMath::Fabs( extents[1] * plane.Normal()[1] ) + 338 idMath::Fabs( extents[2] * plane.Normal()[2] ); 339 340 if ( d1 - d2 > 0.0f ) { 341 return d1 - d2; 342 } 343 if ( d1 + d2 < 0.0f ) { 344 return d1 + d2; 345 } 346 return 0.0f; 347 } 348 349 /* 350 ================ 351 idBox::PlaneSide 352 ================ 353 */ 354 int idBox::PlaneSide( const idPlane &plane, const float epsilon ) const { 355 float d1, d2; 356 357 d1 = plane.Distance( center ); 358 d2 = idMath::Fabs( extents[0] * plane.Normal()[0] ) + 359 idMath::Fabs( extents[1] * plane.Normal()[1] ) + 360 idMath::Fabs( extents[2] * plane.Normal()[2] ); 361 362 if ( d1 - d2 > epsilon ) { 363 return PLANESIDE_FRONT; 364 } 365 if ( d1 + d2 < -epsilon ) { 366 return PLANESIDE_BACK; 367 } 368 return PLANESIDE_CROSS; 369 } 370 371 /* 372 ============ 373 idBox::IntersectsBox 374 ============ 375 */ 376 bool idBox::IntersectsBox( const idBox &a ) const { 377 idVec3 dir; // vector between centers 378 float c[3][3]; // matrix c = axis.Transpose() * a.axis 379 float ac[3][3]; // absolute values of c 380 float axisdir[3]; // axis[i] * dir 381 float d, e0, e1; // distance between centers and projected extents 382 383 dir = a.center - center; 384 385 // axis C0 + t * A0 386 c[0][0] = axis[0] * a.axis[0]; 387 c[0][1] = axis[0] * a.axis[1]; 388 c[0][2] = axis[0] * a.axis[2]; 389 axisdir[0] = axis[0] * dir; 390 ac[0][0] = idMath::Fabs( c[0][0] ); 391 ac[0][1] = idMath::Fabs( c[0][1] ); 392 ac[0][2] = idMath::Fabs( c[0][2] ); 393 394 d = idMath::Fabs( axisdir[0] ); 395 e0 = extents[0]; 396 e1 = a.extents[0] * ac[0][0] + a.extents[1] * ac[0][1] + a.extents[2] * ac[0][2]; 397 if ( d > e0 + e1 ) { 398 return false; 399 } 400 401 // axis C0 + t * A1 402 c[1][0] = axis[1] * a.axis[0]; 403 c[1][1] = axis[1] * a.axis[1]; 404 c[1][2] = axis[1] * a.axis[2]; 405 axisdir[1] = axis[1] * dir; 406 ac[1][0] = idMath::Fabs( c[1][0] ); 407 ac[1][1] = idMath::Fabs( c[1][1] ); 408 ac[1][2] = idMath::Fabs( c[1][2] ); 409 410 d = idMath::Fabs( axisdir[1] ); 411 e0 = extents[1]; 412 e1 = a.extents[0] * ac[1][0] + a.extents[1] * ac[1][1] + a.extents[2] * ac[1][2]; 413 if ( d > e0 + e1 ) { 414 return false; 415 } 416 417 // axis C0 + t * A2 418 c[2][0] = axis[2] * a.axis[0]; 419 c[2][1] = axis[2] * a.axis[1]; 420 c[2][2] = axis[2] * a.axis[2]; 421 axisdir[2] = axis[2] * dir; 422 ac[2][0] = idMath::Fabs( c[2][0] ); 423 ac[2][1] = idMath::Fabs( c[2][1] ); 424 ac[2][2] = idMath::Fabs( c[2][2] ); 425 426 d = idMath::Fabs( axisdir[2] ); 427 e0 = extents[2]; 428 e1 = a.extents[0] * ac[2][0] + a.extents[1] * ac[2][1] + a.extents[2] * ac[2][2]; 429 if ( d > e0 + e1 ) { 430 return false; 431 } 432 433 // axis C0 + t * B0 434 d = idMath::Fabs( a.axis[0] * dir ); 435 e0 = extents[0] * ac[0][0] + extents[1] * ac[1][0] + extents[2] * ac[2][0]; 436 e1 = a.extents[0]; 437 if ( d > e0 + e1 ) { 438 return false; 439 } 440 441 // axis C0 + t * B1 442 d = idMath::Fabs( a.axis[1] * dir ); 443 e0 = extents[0] * ac[0][1] + extents[1] * ac[1][1] + extents[2] * ac[2][1]; 444 e1 = a.extents[1]; 445 if ( d > e0 + e1 ) { 446 return false; 447 } 448 449 // axis C0 + t * B2 450 d = idMath::Fabs( a.axis[2] * dir ); 451 e0 = extents[0] * ac[0][2] + extents[1] * ac[1][2] + extents[2] * ac[2][2]; 452 e1 = a.extents[2]; 453 if ( d > e0 + e1 ) { 454 return false; 455 } 456 457 // axis C0 + t * A0xB0 458 d = idMath::Fabs( axisdir[2] * c[1][0] - axisdir[1] * c[2][0] ); 459 e0 = extents[1] * ac[2][0] + extents[2] * ac[1][0]; 460 e1 = a.extents[1] * ac[0][2] + a.extents[2] * ac[0][1]; 461 if ( d > e0 + e1 ) { 462 return false; 463 } 464 465 // axis C0 + t * A0xB1 466 d = idMath::Fabs( axisdir[2] * c[1][1] - axisdir[1] * c[2][1] ); 467 e0 = extents[1] * ac[2][1] + extents[2] * ac[1][1]; 468 e1 = a.extents[0] * ac[0][2] + a.extents[2] * ac[0][0]; 469 if ( d > e0 + e1 ) { 470 return false; 471 } 472 473 // axis C0 + t * A0xB2 474 d = idMath::Fabs( axisdir[2] * c[1][2] - axisdir[1] * c[2][2] ); 475 e0 = extents[1] * ac[2][2] + extents[2] * ac[1][2]; 476 e1 = a.extents[0] * ac[0][1] + a.extents[1] * ac[0][0]; 477 if ( d > e0 + e1 ) { 478 return false; 479 } 480 481 // axis C0 + t * A1xB0 482 d = idMath::Fabs( axisdir[0] * c[2][0] - axisdir[2] * c[0][0] ); 483 e0 = extents[0] * ac[2][0] + extents[2] * ac[0][0]; 484 e1 = a.extents[1] * ac[1][2] + a.extents[2] * ac[1][1]; 485 if ( d > e0 + e1 ) { 486 return false; 487 } 488 489 // axis C0 + t * A1xB1 490 d = idMath::Fabs( axisdir[0] * c[2][1] - axisdir[2] * c[0][1] ); 491 e0 = extents[0] * ac[2][1] + extents[2] * ac[0][1]; 492 e1 = a.extents[0] * ac[1][2] + a.extents[2] * ac[1][0]; 493 if ( d > e0 + e1 ) { 494 return false; 495 } 496 497 // axis C0 + t * A1xB2 498 d = idMath::Fabs( axisdir[0] * c[2][2] - axisdir[2] * c[0][2] ); 499 e0 = extents[0] * ac[2][2] + extents[2] * ac[0][2]; 500 e1 = a.extents[0] * ac[1][1] + a.extents[1] * ac[1][0]; 501 if ( d > e0 + e1 ) { 502 return false; 503 } 504 505 // axis C0 + t * A2xB0 506 d = idMath::Fabs( axisdir[1] * c[0][0] - axisdir[0] * c[1][0] ); 507 e0 = extents[0] * ac[1][0] + extents[1] * ac[0][0]; 508 e1 = a.extents[1] * ac[2][2] + a.extents[2] * ac[2][1]; 509 if ( d > e0 + e1 ) { 510 return false; 511 } 512 513 // axis C0 + t * A2xB1 514 d = idMath::Fabs( axisdir[1] * c[0][1] - axisdir[0] * c[1][1] ); 515 e0 = extents[0] * ac[1][1] + extents[1] * ac[0][1]; 516 e1 = a.extents[0] * ac[2][2] + a.extents[2] * ac[2][0]; 517 if ( d > e0 + e1 ) { 518 return false; 519 } 520 521 // axis C0 + t * A2xB2 522 d = idMath::Fabs( axisdir[1] * c[0][2] - axisdir[0] * c[1][2] ); 523 e0 = extents[0] * ac[1][2] + extents[1] * ac[0][2]; 524 e1 = a.extents[0] * ac[2][1] + a.extents[1] * ac[2][0]; 525 if ( d > e0 + e1 ) { 526 return false; 527 } 528 return true; 529 } 530 531 /* 532 ============ 533 idBox::LineIntersection 534 535 Returns true if the line intersects the box between the start and end point. 536 ============ 537 */ 538 bool idBox::LineIntersection( const idVec3 &start, const idVec3 &end ) const { 539 float ld[3]; 540 idVec3 lineDir = 0.5f * ( end - start ); 541 idVec3 lineCenter = start + lineDir; 542 idVec3 dir = lineCenter - center; 543 544 ld[0] = idMath::Fabs( lineDir * axis[0] ); 545 if ( idMath::Fabs( dir * axis[0] ) > extents[0] + ld[0] ) { 546 return false; 547 } 548 549 ld[1] = idMath::Fabs( lineDir * axis[1] ); 550 if ( idMath::Fabs( dir * axis[1] ) > extents[1] + ld[1] ) { 551 return false; 552 } 553 554 ld[2] = idMath::Fabs( lineDir * axis[2] ); 555 if ( idMath::Fabs( dir * axis[2] ) > extents[2] + ld[2] ) { 556 return false; 557 } 558 559 idVec3 cross = lineDir.Cross( dir ); 560 561 if ( idMath::Fabs( cross * axis[0] ) > extents[1] * ld[2] + extents[2] * ld[1] ) { 562 return false; 563 } 564 565 if ( idMath::Fabs( cross * axis[1] ) > extents[0] * ld[2] + extents[2] * ld[0] ) { 566 return false; 567 } 568 569 if ( idMath::Fabs( cross * axis[2] ) > extents[0] * ld[1] + extents[1] * ld[0] ) { 570 return false; 571 } 572 573 return true; 574 } 575 576 /* 577 ============ 578 BoxPlaneClip 579 ============ 580 */ 581 static bool BoxPlaneClip( const float denom, const float numer, float &scale0, float &scale1 ) { 582 if ( denom > 0.0f ) { 583 if ( numer > denom * scale1 ) { 584 return false; 585 } 586 if ( numer > denom * scale0 ) { 587 scale0 = numer / denom; 588 } 589 return true; 590 } 591 else if ( denom < 0.0f ) { 592 if ( numer > denom * scale0 ) { 593 return false; 594 } 595 if ( numer > denom * scale1 ) { 596 scale1 = numer / denom; 597 } 598 return true; 599 } 600 else { 601 return ( numer <= 0.0f ); 602 } 603 } 604 605 /* 606 ============ 607 idBox::RayIntersection 608 609 Returns true if the ray intersects the box. 610 The ray can intersect the box in both directions from the start point. 611 If start is inside the box then scale1 < 0 and scale2 > 0. 612 ============ 613 */ 614 bool idBox::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const { 615 idVec3 localStart, localDir; 616 617 localStart = ( start - center ) * axis.Transpose(); 618 localDir = dir * axis.Transpose(); 619 620 scale1 = -idMath::INFINITY; 621 scale2 = idMath::INFINITY; 622 return BoxPlaneClip( localDir.x, -localStart.x - extents[0], scale1, scale2 ) && 623 BoxPlaneClip( -localDir.x, localStart.x - extents[0], scale1, scale2 ) && 624 BoxPlaneClip( localDir.y, -localStart.y - extents[1], scale1, scale2 ) && 625 BoxPlaneClip( -localDir.y, localStart.y - extents[1], scale1, scale2 ) && 626 BoxPlaneClip( localDir.z, -localStart.z - extents[2], scale1, scale2 ) && 627 BoxPlaneClip( -localDir.z, localStart.z - extents[2], scale1, scale2 ); 628 } 629 630 /* 631 ============ 632 idBox::FromPoints 633 634 Tight box for a collection of points. 635 ============ 636 */ 637 void idBox::FromPoints( const idVec3 *points, const int numPoints ) { 638 int i; 639 float invNumPoints, sumXX, sumXY, sumXZ, sumYY, sumYZ, sumZZ; 640 idVec3 dir; 641 idBounds bounds; 642 idMatX eigenVectors; 643 idVecX eigenValues; 644 645 // compute mean of points 646 center = points[0]; 647 for ( i = 1; i < numPoints; i++ ) { 648 center += points[i]; 649 } 650 invNumPoints = 1.0f / numPoints; 651 center *= invNumPoints; 652 653 // compute covariances of points 654 sumXX = 0.0f; sumXY = 0.0f; sumXZ = 0.0f; 655 sumYY = 0.0f; sumYZ = 0.0f; sumZZ = 0.0f; 656 for ( i = 0; i < numPoints; i++ ) { 657 dir = points[i] - center; 658 sumXX += dir.x * dir.x; 659 sumXY += dir.x * dir.y; 660 sumXZ += dir.x * dir.z; 661 sumYY += dir.y * dir.y; 662 sumYZ += dir.y * dir.z; 663 sumZZ += dir.z * dir.z; 664 } 665 sumXX *= invNumPoints; 666 sumXY *= invNumPoints; 667 sumXZ *= invNumPoints; 668 sumYY *= invNumPoints; 669 sumYZ *= invNumPoints; 670 sumZZ *= invNumPoints; 671 672 // compute eigenvectors for covariance matrix 673 eigenValues.SetData( 3, VECX_ALLOCA( 3 ) ); 674 eigenVectors.SetData( 3, 3, MATX_ALLOCA( 3 * 3 ) ); 675 676 eigenVectors[0][0] = sumXX; 677 eigenVectors[0][1] = sumXY; 678 eigenVectors[0][2] = sumXZ; 679 eigenVectors[1][0] = sumXY; 680 eigenVectors[1][1] = sumYY; 681 eigenVectors[1][2] = sumYZ; 682 eigenVectors[2][0] = sumXZ; 683 eigenVectors[2][1] = sumYZ; 684 eigenVectors[2][2] = sumZZ; 685 eigenVectors.Eigen_SolveSymmetric( eigenValues ); 686 eigenVectors.Eigen_SortIncreasing( eigenValues ); 687 688 axis[0][0] = eigenVectors[0][0]; 689 axis[0][1] = eigenVectors[0][1]; 690 axis[0][2] = eigenVectors[0][2]; 691 axis[1][0] = eigenVectors[1][0]; 692 axis[1][1] = eigenVectors[1][1]; 693 axis[1][2] = eigenVectors[1][2]; 694 axis[2][0] = eigenVectors[2][0]; 695 axis[2][1] = eigenVectors[2][1]; 696 axis[2][2] = eigenVectors[2][2]; 697 698 extents[0] = eigenValues[0]; 699 extents[1] = eigenValues[0]; 700 extents[2] = eigenValues[0]; 701 702 // refine by calculating the bounds of the points projected onto the axis and adjusting the center and extents 703 bounds.Clear(); 704 for ( i = 0; i < numPoints; i++ ) { 705 bounds.AddPoint( idVec3( points[i] * axis[0], points[i] * axis[1], points[i] * axis[2] ) ); 706 } 707 center = ( bounds[0] + bounds[1] ) * 0.5f; 708 extents = bounds[1] - center; 709 center *= axis; 710 } 711 712 /* 713 ============ 714 idBox::FromPointTranslation 715 716 Most tight box for the translational movement of the given point. 717 ============ 718 */ 719 void idBox::FromPointTranslation( const idVec3 &point, const idVec3 &translation ) { 720 // FIXME: implement 721 } 722 723 /* 724 ============ 725 idBox::FromBoxTranslation 726 727 Most tight box for the translational movement of the given box. 728 ============ 729 */ 730 void idBox::FromBoxTranslation( const idBox &box, const idVec3 &translation ) { 731 // FIXME: implement 732 } 733 734 /* 735 ============ 736 idBox::FromPointRotation 737 738 Most tight bounds for the rotational movement of the given point. 739 ============ 740 */ 741 void idBox::FromPointRotation( const idVec3 &point, const idRotation &rotation ) { 742 // FIXME: implement 743 } 744 745 /* 746 ============ 747 idBox::FromBoxRotation 748 749 Most tight box for the rotational movement of the given box. 750 ============ 751 */ 752 void idBox::FromBoxRotation( const idBox &box, const idRotation &rotation ) { 753 // FIXME: implement 754 } 755 756 /* 757 ============ 758 idBox::ToPoints 759 ============ 760 */ 761 void idBox::ToPoints( idVec3 points[8] ) const { 762 idMat3 ax; 763 idVec3 temp[4]; 764 765 ax[0] = extents[0] * axis[0]; 766 ax[1] = extents[1] * axis[1]; 767 ax[2] = extents[2] * axis[2]; 768 temp[0] = center - ax[0]; 769 temp[1] = center + ax[0]; 770 temp[2] = ax[1] - ax[2]; 771 temp[3] = ax[1] + ax[2]; 772 points[0] = temp[0] - temp[3]; 773 points[1] = temp[1] - temp[3]; 774 points[2] = temp[1] + temp[2]; 775 points[3] = temp[0] + temp[2]; 776 points[4] = temp[0] - temp[2]; 777 points[5] = temp[1] - temp[2]; 778 points[6] = temp[1] + temp[3]; 779 points[7] = temp[0] + temp[3]; 780 } 781 782 /* 783 ============ 784 idBox::GetProjectionSilhouetteVerts 785 ============ 786 */ 787 int idBox::GetProjectionSilhouetteVerts( const idVec3 &projectionOrigin, idVec3 silVerts[6] ) const { 788 float f; 789 int i, planeBits, *index; 790 idVec3 points[8], dir1, dir2; 791 792 ToPoints( points ); 793 794 dir1 = points[0] - projectionOrigin; 795 dir2 = points[6] - projectionOrigin; 796 f = dir1 * axis[0]; 797 planeBits = IEEE_FLT_SIGNBITNOTSET( f ); 798 f = dir2 * axis[0]; 799 planeBits |= IEEE_FLT_SIGNBITSET( f ) << 1; 800 f = dir1 * axis[1]; 801 planeBits |= IEEE_FLT_SIGNBITNOTSET( f ) << 2; 802 f = dir2 * axis[1]; 803 planeBits |= IEEE_FLT_SIGNBITSET( f ) << 3; 804 f = dir1 * axis[2]; 805 planeBits |= IEEE_FLT_SIGNBITNOTSET( f ) << 4; 806 f = dir2 * axis[2]; 807 planeBits |= IEEE_FLT_SIGNBITSET( f ) << 5; 808 809 index = boxPlaneBitsSilVerts[planeBits]; 810 for ( i = 0; i < index[0]; i++ ) { 811 silVerts[i] = points[index[i+1]]; 812 } 813 814 return index[0]; 815 } 816 817 /* 818 ============ 819 idBox::GetParallelProjectionSilhouetteVerts 820 ============ 821 */ 822 int idBox::GetParallelProjectionSilhouetteVerts( const idVec3 &projectionDir, idVec3 silVerts[6] ) const { 823 float f; 824 int i, planeBits, *index; 825 idVec3 points[8]; 826 827 ToPoints( points ); 828 829 planeBits = 0; 830 f = projectionDir * axis[0]; 831 if ( IEEE_FLT_ISNOTZERO( f ) ) { 832 planeBits = 1 << IEEE_FLT_SIGNBITSET( f ); 833 } 834 f = projectionDir * axis[1]; 835 if ( IEEE_FLT_ISNOTZERO( f ) ) { 836 planeBits |= 4 << IEEE_FLT_SIGNBITSET( f ); 837 } 838 f = projectionDir * axis[2]; 839 if ( IEEE_FLT_ISNOTZERO( f ) ) { 840 planeBits |= 16 << IEEE_FLT_SIGNBITSET( f ); 841 } 842 843 index = boxPlaneBitsSilVerts[planeBits]; 844 for ( i = 0; i < index[0]; i++ ) { 845 silVerts[i] = points[index[i+1]]; 846 } 847 848 return index[0]; 849 }