TraceModel.cpp (40446B)
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 "../../idlib/precompiled.h" 31 #include "TraceModel.h" 32 33 /* 34 ============ 35 idTraceModel::SetupBox 36 ============ 37 */ 38 void idTraceModel::SetupBox( const idBounds &boxBounds ) { 39 int i; 40 41 if ( type != TRM_BOX ) { 42 InitBox(); 43 } 44 // offset to center 45 offset = ( boxBounds[0] + boxBounds[1] ) * 0.5f; 46 // set box vertices 47 for ( i = 0; i < 8; i++ ) { 48 verts[i][0] = boxBounds[(i^(i>>1))&1][0]; 49 verts[i][1] = boxBounds[(i>>1)&1][1]; 50 verts[i][2] = boxBounds[(i>>2)&1][2]; 51 } 52 // set polygon plane distances 53 polys[0].dist = -boxBounds[0][2]; 54 polys[1].dist = boxBounds[1][2]; 55 polys[2].dist = -boxBounds[0][1]; 56 polys[3].dist = boxBounds[1][0]; 57 polys[4].dist = boxBounds[1][1]; 58 polys[5].dist = -boxBounds[0][0]; 59 // set polygon bounds 60 for ( i = 0; i < 6; i++ ) { 61 polys[i].bounds = boxBounds; 62 } 63 polys[0].bounds[1][2] = boxBounds[0][2]; 64 polys[1].bounds[0][2] = boxBounds[1][2]; 65 polys[2].bounds[1][1] = boxBounds[0][1]; 66 polys[3].bounds[0][0] = boxBounds[1][0]; 67 polys[4].bounds[0][1] = boxBounds[1][1]; 68 polys[5].bounds[1][0] = boxBounds[0][0]; 69 70 bounds = boxBounds; 71 } 72 73 /* 74 ============ 75 idTraceModel::SetupBox 76 77 The origin is placed at the center of the cube. 78 ============ 79 */ 80 void idTraceModel::SetupBox( const float size ) { 81 idBounds boxBounds; 82 float halfSize; 83 84 halfSize = size * 0.5f; 85 boxBounds[0].Set( -halfSize, -halfSize, -halfSize ); 86 boxBounds[1].Set( halfSize, halfSize, halfSize ); 87 SetupBox( boxBounds ); 88 } 89 90 /* 91 ============ 92 idTraceModel::InitBox 93 94 Initialize size independent box. 95 ============ 96 */ 97 void idTraceModel::InitBox() { 98 int i; 99 100 type = TRM_BOX; 101 numVerts = 8; 102 numEdges = 12; 103 numPolys = 6; 104 105 // set box edges 106 for ( i = 0; i < 4; i++ ) { 107 edges[ i + 1 ].v[0] = i; 108 edges[ i + 1 ].v[1] = (i + 1) & 3; 109 edges[ i + 5 ].v[0] = 4 + i; 110 edges[ i + 5 ].v[1] = 4 + ((i + 1) & 3); 111 edges[ i + 9 ].v[0] = i; 112 edges[ i + 9 ].v[1] = 4 + i; 113 } 114 115 // all edges of a polygon go counter clockwise 116 polys[0].numEdges = 4; 117 polys[0].edges[0] = -4; 118 polys[0].edges[1] = -3; 119 polys[0].edges[2] = -2; 120 polys[0].edges[3] = -1; 121 polys[0].normal.Set( 0.0f, 0.0f, -1.0f ); 122 123 polys[1].numEdges = 4; 124 polys[1].edges[0] = 5; 125 polys[1].edges[1] = 6; 126 polys[1].edges[2] = 7; 127 polys[1].edges[3] = 8; 128 polys[1].normal.Set( 0.0f, 0.0f, 1.0f ); 129 130 polys[2].numEdges = 4; 131 polys[2].edges[0] = 1; 132 polys[2].edges[1] = 10; 133 polys[2].edges[2] = -5; 134 polys[2].edges[3] = -9; 135 polys[2].normal.Set( 0.0f, -1.0f, 0.0f ); 136 137 polys[3].numEdges = 4; 138 polys[3].edges[0] = 2; 139 polys[3].edges[1] = 11; 140 polys[3].edges[2] = -6; 141 polys[3].edges[3] = -10; 142 polys[3].normal.Set( 1.0f, 0.0f, 0.0f ); 143 144 polys[4].numEdges = 4; 145 polys[4].edges[0] = 3; 146 polys[4].edges[1] = 12; 147 polys[4].edges[2] = -7; 148 polys[4].edges[3] = -11; 149 polys[4].normal.Set( 0.0f, 1.0f, 0.0f ); 150 151 polys[5].numEdges = 4; 152 polys[5].edges[0] = 4; 153 polys[5].edges[1] = 9; 154 polys[5].edges[2] = -8; 155 polys[5].edges[3] = -12; 156 polys[5].normal.Set( -1.0f, 0.0f, 0.0f ); 157 158 // convex model 159 isConvex = true; 160 161 GenerateEdgeNormals(); 162 } 163 164 /* 165 ============ 166 idTraceModel::SetupOctahedron 167 ============ 168 */ 169 void idTraceModel::SetupOctahedron( const idBounds &octBounds ) { 170 int i, e0, e1, v0, v1, v2; 171 idVec3 v; 172 173 if ( type != TRM_OCTAHEDRON ) { 174 InitOctahedron(); 175 } 176 177 offset = ( octBounds[0] + octBounds[1] ) * 0.5f; 178 v[0] = octBounds[1][0] - offset[0]; 179 v[1] = octBounds[1][1] - offset[1]; 180 v[2] = octBounds[1][2] - offset[2]; 181 182 // set vertices 183 verts[0].Set( offset.x + v[0], offset.y, offset.z ); 184 verts[1].Set( offset.x - v[0], offset.y, offset.z ); 185 verts[2].Set( offset.x, offset.y + v[1], offset.z ); 186 verts[3].Set( offset.x, offset.y - v[1], offset.z ); 187 verts[4].Set( offset.x, offset.y, offset.z + v[2] ); 188 verts[5].Set( offset.x, offset.y, offset.z - v[2] ); 189 190 // set polygons 191 for ( i = 0; i < numPolys; i++ ) { 192 e0 = polys[i].edges[0]; 193 e1 = polys[i].edges[1]; 194 v0 = edges[abs(e0)].v[INT32_SIGNBITSET(e0)]; 195 v1 = edges[abs(e0)].v[INT32_SIGNBITNOTSET(e0)]; 196 v2 = edges[abs(e1)].v[INT32_SIGNBITNOTSET(e1)]; 197 // polygon plane 198 polys[i].normal = ( verts[v1] - verts[v0] ).Cross( verts[v2] - verts[v0] ); 199 polys[i].normal.Normalize(); 200 polys[i].dist = polys[i].normal * verts[v0]; 201 // polygon bounds 202 polys[i].bounds[0] = polys[i].bounds[1] = verts[v0]; 203 polys[i].bounds.AddPoint( verts[v1] ); 204 polys[i].bounds.AddPoint( verts[v2] ); 205 } 206 207 // trm bounds 208 bounds = octBounds; 209 210 GenerateEdgeNormals(); 211 } 212 213 /* 214 ============ 215 idTraceModel::SetupOctahedron 216 217 The origin is placed at the center of the octahedron. 218 ============ 219 */ 220 void idTraceModel::SetupOctahedron( const float size ) { 221 idBounds octBounds; 222 float halfSize; 223 224 halfSize = size * 0.5f; 225 octBounds[0].Set( -halfSize, -halfSize, -halfSize ); 226 octBounds[1].Set( halfSize, halfSize, halfSize ); 227 SetupOctahedron( octBounds ); 228 } 229 230 /* 231 ============ 232 idTraceModel::InitOctahedron 233 234 Initialize size independent octahedron. 235 ============ 236 */ 237 void idTraceModel::InitOctahedron() { 238 239 type = TRM_OCTAHEDRON; 240 numVerts = 6; 241 numEdges = 12; 242 numPolys = 8; 243 244 // set edges 245 edges[ 1].v[0] = 4; edges[ 1].v[1] = 0; 246 edges[ 2].v[0] = 0; edges[ 2].v[1] = 2; 247 edges[ 3].v[0] = 2; edges[ 3].v[1] = 4; 248 edges[ 4].v[0] = 2; edges[ 4].v[1] = 1; 249 edges[ 5].v[0] = 1; edges[ 5].v[1] = 4; 250 edges[ 6].v[0] = 1; edges[ 6].v[1] = 3; 251 edges[ 7].v[0] = 3; edges[ 7].v[1] = 4; 252 edges[ 8].v[0] = 3; edges[ 8].v[1] = 0; 253 edges[ 9].v[0] = 5; edges[ 9].v[1] = 2; 254 edges[10].v[0] = 0; edges[10].v[1] = 5; 255 edges[11].v[0] = 5; edges[11].v[1] = 1; 256 edges[12].v[0] = 5; edges[12].v[1] = 3; 257 258 // all edges of a polygon go counter clockwise 259 polys[0].numEdges = 3; 260 polys[0].edges[0] = 1; 261 polys[0].edges[1] = 2; 262 polys[0].edges[2] = 3; 263 264 polys[1].numEdges = 3; 265 polys[1].edges[0] = -3; 266 polys[1].edges[1] = 4; 267 polys[1].edges[2] = 5; 268 269 polys[2].numEdges = 3; 270 polys[2].edges[0] = -5; 271 polys[2].edges[1] = 6; 272 polys[2].edges[2] = 7; 273 274 polys[3].numEdges = 3; 275 polys[3].edges[0] = -7; 276 polys[3].edges[1] = 8; 277 polys[3].edges[2] = -1; 278 279 polys[4].numEdges = 3; 280 polys[4].edges[0] = 9; 281 polys[4].edges[1] = -2; 282 polys[4].edges[2] = 10; 283 284 polys[5].numEdges = 3; 285 polys[5].edges[0] = 11; 286 polys[5].edges[1] = -4; 287 polys[5].edges[2] = -9; 288 289 polys[6].numEdges = 3; 290 polys[6].edges[0] = 12; 291 polys[6].edges[1] = -6; 292 polys[6].edges[2] = -11; 293 294 polys[7].numEdges = 3; 295 polys[7].edges[0] = -10; 296 polys[7].edges[1] = -8; 297 polys[7].edges[2] = -12; 298 299 // convex model 300 isConvex = true; 301 } 302 303 /* 304 ============ 305 idTraceModel::SetupDodecahedron 306 ============ 307 */ 308 void idTraceModel::SetupDodecahedron( const idBounds &dodBounds ) { 309 int i, e0, e1, e2, e3, v0, v1, v2, v3, v4; 310 float s, d; 311 idVec3 a, b, c; 312 313 if ( type != TRM_DODECAHEDRON ) { 314 InitDodecahedron(); 315 } 316 317 a[0] = a[1] = a[2] = 0.5773502691896257f; // 1.0f / ( 3.0f ) ^ 0.5f; 318 b[0] = b[1] = b[2] = 0.3568220897730899f; // ( ( 3.0f - ( 5.0f ) ^ 0.5f ) / 6.0f ) ^ 0.5f; 319 c[0] = c[1] = c[2] = 0.9341723589627156f; // ( ( 3.0f + ( 5.0f ) ^ 0.5f ) / 6.0f ) ^ 0.5f; 320 d = 0.5f / c[0]; 321 s = ( dodBounds[1][0] - dodBounds[0][0] ) * d; 322 a[0] *= s; 323 b[0] *= s; 324 c[0] *= s; 325 s = ( dodBounds[1][1] - dodBounds[0][1] ) * d; 326 a[1] *= s; 327 b[1] *= s; 328 c[1] *= s; 329 s = ( dodBounds[1][2] - dodBounds[0][2] ) * d; 330 a[2] *= s; 331 b[2] *= s; 332 c[2] *= s; 333 334 offset = ( dodBounds[0] + dodBounds[1] ) * 0.5f; 335 336 // set vertices 337 verts[ 0].Set( offset.x + a[0], offset.y + a[1], offset.z + a[2] ); 338 verts[ 1].Set( offset.x + a[0], offset.y + a[1], offset.z - a[2] ); 339 verts[ 2].Set( offset.x + a[0], offset.y - a[1], offset.z + a[2] ); 340 verts[ 3].Set( offset.x + a[0], offset.y - a[1], offset.z - a[2] ); 341 verts[ 4].Set( offset.x - a[0], offset.y + a[1], offset.z + a[2] ); 342 verts[ 5].Set( offset.x - a[0], offset.y + a[1], offset.z - a[2] ); 343 verts[ 6].Set( offset.x - a[0], offset.y - a[1], offset.z + a[2] ); 344 verts[ 7].Set( offset.x - a[0], offset.y - a[1], offset.z - a[2] ); 345 verts[ 8].Set( offset.x + b[0], offset.y + c[1], offset.z ); 346 verts[ 9].Set( offset.x - b[0], offset.y + c[1], offset.z ); 347 verts[10].Set( offset.x + b[0], offset.y - c[1], offset.z ); 348 verts[11].Set( offset.x - b[0], offset.y - c[1], offset.z ); 349 verts[12].Set( offset.x + c[0], offset.y , offset.z + b[2] ); 350 verts[13].Set( offset.x + c[0], offset.y , offset.z - b[2] ); 351 verts[14].Set( offset.x - c[0], offset.y , offset.z + b[2] ); 352 verts[15].Set( offset.x - c[0], offset.y , offset.z - b[2] ); 353 verts[16].Set( offset.x , offset.y + b[1], offset.z + c[2] ); 354 verts[17].Set( offset.x , offset.y - b[1], offset.z + c[2] ); 355 verts[18].Set( offset.x , offset.y + b[1], offset.z - c[2] ); 356 verts[19].Set( offset.x , offset.y - b[1], offset.z - c[2] ); 357 358 // set polygons 359 for ( i = 0; i < numPolys; i++ ) { 360 e0 = polys[i].edges[0]; 361 e1 = polys[i].edges[1]; 362 e2 = polys[i].edges[2]; 363 e3 = polys[i].edges[3]; 364 v0 = edges[abs(e0)].v[INT32_SIGNBITSET(e0)]; 365 v1 = edges[abs(e0)].v[INT32_SIGNBITNOTSET(e0)]; 366 v2 = edges[abs(e1)].v[INT32_SIGNBITNOTSET(e1)]; 367 v3 = edges[abs(e2)].v[INT32_SIGNBITNOTSET(e2)]; 368 v4 = edges[abs(e3)].v[INT32_SIGNBITNOTSET(e3)]; 369 // polygon plane 370 polys[i].normal = ( verts[v1] - verts[v0] ).Cross( verts[v2] - verts[v0] ); 371 polys[i].normal.Normalize(); 372 polys[i].dist = polys[i].normal * verts[v0]; 373 // polygon bounds 374 polys[i].bounds[0] = polys[i].bounds[1] = verts[v0]; 375 polys[i].bounds.AddPoint( verts[v1] ); 376 polys[i].bounds.AddPoint( verts[v2] ); 377 polys[i].bounds.AddPoint( verts[v3] ); 378 polys[i].bounds.AddPoint( verts[v4] ); 379 } 380 381 // trm bounds 382 bounds = dodBounds; 383 384 GenerateEdgeNormals(); 385 } 386 387 /* 388 ============ 389 idTraceModel::SetupDodecahedron 390 391 The origin is placed at the center of the octahedron. 392 ============ 393 */ 394 void idTraceModel::SetupDodecahedron( const float size ) { 395 idBounds dodBounds; 396 float halfSize; 397 398 halfSize = size * 0.5f; 399 dodBounds[0].Set( -halfSize, -halfSize, -halfSize ); 400 dodBounds[1].Set( halfSize, halfSize, halfSize ); 401 SetupDodecahedron( dodBounds ); 402 } 403 404 /* 405 ============ 406 idTraceModel::InitDodecahedron 407 408 Initialize size independent dodecahedron. 409 ============ 410 */ 411 void idTraceModel::InitDodecahedron() { 412 413 type = TRM_DODECAHEDRON; 414 numVerts = 20; 415 numEdges = 30; 416 numPolys = 12; 417 418 // set edges 419 edges[ 1].v[0] = 0; edges[ 1].v[1] = 8; 420 edges[ 2].v[0] = 8; edges[ 2].v[1] = 9; 421 edges[ 3].v[0] = 9; edges[ 3].v[1] = 4; 422 edges[ 4].v[0] = 4; edges[ 4].v[1] = 16; 423 edges[ 5].v[0] = 16; edges[ 5].v[1] = 0; 424 edges[ 6].v[0] = 16; edges[ 6].v[1] = 17; 425 edges[ 7].v[0] = 17; edges[ 7].v[1] = 2; 426 edges[ 8].v[0] = 2; edges[ 8].v[1] = 12; 427 edges[ 9].v[0] = 12; edges[ 9].v[1] = 0; 428 edges[10].v[0] = 2; edges[10].v[1] = 10; 429 edges[11].v[0] = 10; edges[11].v[1] = 3; 430 edges[12].v[0] = 3; edges[12].v[1] = 13; 431 edges[13].v[0] = 13; edges[13].v[1] = 12; 432 edges[14].v[0] = 9; edges[14].v[1] = 5; 433 edges[15].v[0] = 5; edges[15].v[1] = 15; 434 edges[16].v[0] = 15; edges[16].v[1] = 14; 435 edges[17].v[0] = 14; edges[17].v[1] = 4; 436 edges[18].v[0] = 3; edges[18].v[1] = 19; 437 edges[19].v[0] = 19; edges[19].v[1] = 18; 438 edges[20].v[0] = 18; edges[20].v[1] = 1; 439 edges[21].v[0] = 1; edges[21].v[1] = 13; 440 edges[22].v[0] = 7; edges[22].v[1] = 11; 441 edges[23].v[0] = 11; edges[23].v[1] = 6; 442 edges[24].v[0] = 6; edges[24].v[1] = 14; 443 edges[25].v[0] = 15; edges[25].v[1] = 7; 444 edges[26].v[0] = 1; edges[26].v[1] = 8; 445 edges[27].v[0] = 18; edges[27].v[1] = 5; 446 edges[28].v[0] = 6; edges[28].v[1] = 17; 447 edges[29].v[0] = 11; edges[29].v[1] = 10; 448 edges[30].v[0] = 19; edges[30].v[1] = 7; 449 450 // all edges of a polygon go counter clockwise 451 polys[0].numEdges = 5; 452 polys[0].edges[0] = 1; 453 polys[0].edges[1] = 2; 454 polys[0].edges[2] = 3; 455 polys[0].edges[3] = 4; 456 polys[0].edges[4] = 5; 457 458 polys[1].numEdges = 5; 459 polys[1].edges[0] = -5; 460 polys[1].edges[1] = 6; 461 polys[1].edges[2] = 7; 462 polys[1].edges[3] = 8; 463 polys[1].edges[4] = 9; 464 465 polys[2].numEdges = 5; 466 polys[2].edges[0] = -8; 467 polys[2].edges[1] = 10; 468 polys[2].edges[2] = 11; 469 polys[2].edges[3] = 12; 470 polys[2].edges[4] = 13; 471 472 polys[3].numEdges = 5; 473 polys[3].edges[0] = 14; 474 polys[3].edges[1] = 15; 475 polys[3].edges[2] = 16; 476 polys[3].edges[3] = 17; 477 polys[3].edges[4] = -3; 478 479 polys[4].numEdges = 5; 480 polys[4].edges[0] = 18; 481 polys[4].edges[1] = 19; 482 polys[4].edges[2] = 20; 483 polys[4].edges[3] = 21; 484 polys[4].edges[4] = -12; 485 486 polys[5].numEdges = 5; 487 polys[5].edges[0] = 22; 488 polys[5].edges[1] = 23; 489 polys[5].edges[2] = 24; 490 polys[5].edges[3] = -16; 491 polys[5].edges[4] = 25; 492 493 polys[6].numEdges = 5; 494 polys[6].edges[0] = -9; 495 polys[6].edges[1] = -13; 496 polys[6].edges[2] = -21; 497 polys[6].edges[3] = 26; 498 polys[6].edges[4] = -1; 499 500 polys[7].numEdges = 5; 501 polys[7].edges[0] = -26; 502 polys[7].edges[1] = -20; 503 polys[7].edges[2] = 27; 504 polys[7].edges[3] = -14; 505 polys[7].edges[4] = -2; 506 507 polys[8].numEdges = 5; 508 polys[8].edges[0] = -4; 509 polys[8].edges[1] = -17; 510 polys[8].edges[2] = -24; 511 polys[8].edges[3] = 28; 512 polys[8].edges[4] = -6; 513 514 polys[9].numEdges = 5; 515 polys[9].edges[0] = -23; 516 polys[9].edges[1] = 29; 517 polys[9].edges[2] = -10; 518 polys[9].edges[3] = -7; 519 polys[9].edges[4] = -28; 520 521 polys[10].numEdges = 5; 522 polys[10].edges[0] = -25; 523 polys[10].edges[1] = -15; 524 polys[10].edges[2] = -27; 525 polys[10].edges[3] = -19; 526 polys[10].edges[4] = 30; 527 528 polys[11].numEdges = 5; 529 polys[11].edges[0] = -30; 530 polys[11].edges[1] = -18; 531 polys[11].edges[2] = -11; 532 polys[11].edges[3] = -29; 533 polys[11].edges[4] = -22; 534 535 // convex model 536 isConvex = true; 537 } 538 539 /* 540 ============ 541 idTraceModel::SetupCylinder 542 ============ 543 */ 544 void idTraceModel::SetupCylinder( const idBounds &cylBounds, const int numSides ) { 545 int i, n, ii, n2; 546 float angle; 547 idVec3 halfSize; 548 549 n = numSides; 550 if ( n < 3 ) { 551 n = 3; 552 } 553 if ( n * 2 > MAX_TRACEMODEL_VERTS ) { 554 idLib::common->Printf( "WARNING: idTraceModel::SetupCylinder: too many vertices\n" ); 555 n = MAX_TRACEMODEL_VERTS / 2; 556 } 557 if ( n * 3 > MAX_TRACEMODEL_EDGES ) { 558 idLib::common->Printf( "WARNING: idTraceModel::SetupCylinder: too many sides\n" ); 559 n = MAX_TRACEMODEL_EDGES / 3; 560 } 561 if ( n + 2 > MAX_TRACEMODEL_POLYS ) { 562 idLib::common->Printf( "WARNING: idTraceModel::SetupCylinder: too many polygons\n" ); 563 n = MAX_TRACEMODEL_POLYS - 2; 564 } 565 566 type = TRM_CYLINDER; 567 numVerts = n * 2; 568 numEdges = n * 3; 569 numPolys = n + 2; 570 offset = ( cylBounds[0] + cylBounds[1] ) * 0.5f; 571 halfSize = cylBounds[1] - offset; 572 for ( i = 0; i < n; i++ ) { 573 // verts 574 angle = idMath::TWO_PI * i / n; 575 verts[i].x = cos( angle ) * halfSize.x + offset.x; 576 verts[i].y = sin( angle ) * halfSize.y + offset.y; 577 verts[i].z = -halfSize.z + offset.z; 578 verts[n+i].x = verts[i].x; 579 verts[n+i].y = verts[i].y; 580 verts[n+i].z = halfSize.z + offset.z; 581 // edges 582 ii = i + 1; 583 n2 = n << 1; 584 edges[ii].v[0] = i; 585 edges[ii].v[1] = ii % n; 586 edges[n+ii].v[0] = edges[ii].v[0] + n; 587 edges[n+ii].v[1] = edges[ii].v[1] + n; 588 edges[n2+ii].v[0] = i; 589 edges[n2+ii].v[1] = n + i; 590 // vertical polygon edges 591 polys[i].numEdges = 4; 592 polys[i].edges[0] = ii; 593 polys[i].edges[1] = n2 + (ii % n) + 1; 594 polys[i].edges[2] = -(n + ii); 595 polys[i].edges[3] = -(n2 + ii); 596 // bottom and top polygon edges 597 polys[n].edges[i] = -(n - i); 598 polys[n+1].edges[i] = n + ii; 599 } 600 // bottom and top polygon numEdges 601 polys[n].numEdges = n; 602 polys[n+1].numEdges = n; 603 // polygons 604 for ( i = 0; i < n; i++ ) { 605 // vertical polygon plane 606 polys[i].normal = (verts[(i+1)%n] - verts[i]).Cross( verts[n+i] - verts[i] ); 607 polys[i].normal.Normalize(); 608 polys[i].dist = polys[i].normal * verts[i]; 609 // vertical polygon bounds 610 polys[i].bounds.Clear(); 611 polys[i].bounds.AddPoint( verts[i] ); 612 polys[i].bounds.AddPoint( verts[(i+1)%n] ); 613 polys[i].bounds[0][2] = -halfSize.z + offset.z; 614 polys[i].bounds[1][2] = halfSize.z + offset.z; 615 } 616 // bottom and top polygon plane 617 polys[n].normal.Set( 0.0f, 0.0f, -1.0f ); 618 polys[n].dist = -cylBounds[0][2]; 619 polys[n+1].normal.Set( 0.0f, 0.0f, 1.0f ); 620 polys[n+1].dist = cylBounds[1][2]; 621 // trm bounds 622 bounds = cylBounds; 623 // bottom and top polygon bounds 624 polys[n].bounds = bounds; 625 polys[n].bounds[1][2] = bounds[0][2]; 626 polys[n+1].bounds = bounds; 627 polys[n+1].bounds[0][2] = bounds[1][2]; 628 // convex model 629 isConvex = true; 630 631 GenerateEdgeNormals(); 632 } 633 634 /* 635 ============ 636 idTraceModel::SetupCylinder 637 638 The origin is placed at the center of the cylinder. 639 ============ 640 */ 641 void idTraceModel::SetupCylinder( const float height, const float width, const int numSides ) { 642 idBounds cylBounds; 643 float halfHeight, halfWidth; 644 645 halfHeight = height * 0.5f; 646 halfWidth = width * 0.5f; 647 cylBounds[0].Set( -halfWidth, -halfWidth, -halfHeight ); 648 cylBounds[1].Set( halfWidth, halfWidth, halfHeight ); 649 SetupCylinder( cylBounds, numSides ); 650 } 651 652 /* 653 ============ 654 idTraceModel::SetupCone 655 ============ 656 */ 657 void idTraceModel::SetupCone( const idBounds &coneBounds, const int numSides ) { 658 int i, n, ii; 659 float angle; 660 idVec3 halfSize; 661 662 n = numSides; 663 if ( n < 2 ) { 664 n = 3; 665 } 666 if ( n + 1 > MAX_TRACEMODEL_VERTS ) { 667 idLib::common->Printf( "WARNING: idTraceModel::SetupCone: too many vertices\n" ); 668 n = MAX_TRACEMODEL_VERTS - 1; 669 } 670 if ( n * 2 > MAX_TRACEMODEL_EDGES ) { 671 idLib::common->Printf( "WARNING: idTraceModel::SetupCone: too many edges\n" ); 672 n = MAX_TRACEMODEL_EDGES / 2; 673 } 674 if ( n + 1 > MAX_TRACEMODEL_POLYS ) { 675 idLib::common->Printf( "WARNING: idTraceModel::SetupCone: too many polygons\n" ); 676 n = MAX_TRACEMODEL_POLYS - 1; 677 } 678 679 type = TRM_CONE; 680 numVerts = n + 1; 681 numEdges = n * 2; 682 numPolys = n + 1; 683 offset = ( coneBounds[0] + coneBounds[1] ) * 0.5f; 684 halfSize = coneBounds[1] - offset; 685 verts[n].Set( 0.0f, 0.0f, halfSize.z + offset.z ); 686 for ( i = 0; i < n; i++ ) { 687 // verts 688 angle = idMath::TWO_PI * i / n; 689 verts[i].x = cos( angle ) * halfSize.x + offset.x; 690 verts[i].y = sin( angle ) * halfSize.y + offset.y; 691 verts[i].z = -halfSize.z + offset.z; 692 // edges 693 ii = i + 1; 694 edges[ii].v[0] = i; 695 edges[ii].v[1] = ii % n; 696 edges[n+ii].v[0] = i; 697 edges[n+ii].v[1] = n; 698 // vertical polygon edges 699 polys[i].numEdges = 3; 700 polys[i].edges[0] = ii; 701 polys[i].edges[1] = n + (ii % n) + 1; 702 polys[i].edges[2] = -(n + ii); 703 // bottom polygon edges 704 polys[n].edges[i] = -(n - i); 705 } 706 // bottom polygon numEdges 707 polys[n].numEdges = n; 708 709 // polygons 710 for ( i = 0; i < n; i++ ) { 711 // polygon plane 712 polys[i].normal = (verts[(i+1)%n] - verts[i]).Cross( verts[n] - verts[i] ); 713 polys[i].normal.Normalize(); 714 polys[i].dist = polys[i].normal * verts[i]; 715 // polygon bounds 716 polys[i].bounds.Clear(); 717 polys[i].bounds.AddPoint( verts[i] ); 718 polys[i].bounds.AddPoint( verts[(i+1)%n] ); 719 polys[i].bounds.AddPoint( verts[n] ); 720 } 721 // bottom polygon plane 722 polys[n].normal.Set( 0.0f, 0.0f, -1.0f ); 723 polys[n].dist = -coneBounds[0][2]; 724 // trm bounds 725 bounds = coneBounds; 726 // bottom polygon bounds 727 polys[n].bounds = bounds; 728 polys[n].bounds[1][2] = bounds[0][2]; 729 // convex model 730 isConvex = true; 731 732 GenerateEdgeNormals(); 733 } 734 735 /* 736 ============ 737 idTraceModel::SetupCone 738 739 The origin is placed at the apex of the cone. 740 ============ 741 */ 742 void idTraceModel::SetupCone( const float height, const float width, const int numSides ) { 743 idBounds coneBounds; 744 float halfWidth; 745 746 halfWidth = width * 0.5f; 747 coneBounds[0].Set( -halfWidth, -halfWidth, -height ); 748 coneBounds[1].Set( halfWidth, halfWidth, 0.0f ); 749 SetupCone( coneBounds, numSides ); 750 } 751 752 /* 753 ============ 754 idTraceModel::SetupBone 755 756 The origin is placed at the center of the bone. 757 ============ 758 */ 759 void idTraceModel::SetupBone( const float length, const float width ) { 760 int i, j, edgeNum; 761 float halfLength = length * 0.5f; 762 763 if ( type != TRM_BONE ) { 764 InitBone(); 765 } 766 // offset to center 767 offset.Set( 0.0f, 0.0f, 0.0f ); 768 // set vertices 769 verts[0].Set( 0.0f, 0.0f, -halfLength ); 770 verts[1].Set( 0.0f, width * -0.5f, 0.0f ); 771 verts[2].Set( width * 0.5f, width * 0.25f, 0.0f ); 772 verts[3].Set( width * -0.5f, width * 0.25f, 0.0f ); 773 verts[4].Set( 0.0f, 0.0f, halfLength ); 774 // set bounds 775 bounds[0].Set( width * -0.5f, width * -0.5f, -halfLength ); 776 bounds[1].Set( width * 0.5f, width * 0.25f, halfLength ); 777 // poly plane normals 778 polys[0].normal = ( verts[2] - verts[0] ).Cross( verts[1] - verts[0] ); 779 polys[0].normal.Normalize(); 780 polys[2].normal.Set( -polys[0].normal[0], polys[0].normal[1], polys[0].normal[2] ); 781 polys[3].normal.Set( polys[0].normal[0], polys[0].normal[1], -polys[0].normal[2] ); 782 polys[5].normal.Set( -polys[0].normal[0], polys[0].normal[1], -polys[0].normal[2] ); 783 polys[1].normal = (verts[3] - verts[0]).Cross(verts[2] - verts[0]); 784 polys[1].normal.Normalize(); 785 polys[4].normal.Set( polys[1].normal[0], polys[1].normal[1], -polys[1].normal[2] ); 786 // poly plane distances 787 for ( i = 0; i < 6; i++ ) { 788 polys[i].dist = polys[i].normal * verts[ edges[ abs(polys[i].edges[0]) ].v[0] ]; 789 polys[i].bounds.Clear(); 790 for ( j = 0; j < 3; j++ ) { 791 edgeNum = polys[i].edges[ j ]; 792 polys[i].bounds.AddPoint( verts[ edges[abs(edgeNum)].v[edgeNum < 0] ] ); 793 } 794 } 795 796 GenerateEdgeNormals(); 797 } 798 799 /* 800 ============ 801 idTraceModel::InitBone 802 803 Initialize size independent bone. 804 ============ 805 */ 806 void idTraceModel::InitBone() { 807 int i; 808 809 type = TRM_BONE; 810 numVerts = 5; 811 numEdges = 9; 812 numPolys = 6; 813 814 // set bone edges 815 for ( i = 0; i < 3; i++ ) { 816 edges[ i + 1 ].v[0] = 0; 817 edges[ i + 1 ].v[1] = i + 1; 818 edges[ i + 4 ].v[0] = 1 + i; 819 edges[ i + 4 ].v[1] = 1 + ((i + 1) % 3); 820 edges[ i + 7 ].v[0] = i + 1; 821 edges[ i + 7 ].v[1] = 4; 822 } 823 824 // all edges of a polygon go counter clockwise 825 polys[0].numEdges = 3; 826 polys[0].edges[0] = 2; 827 polys[0].edges[1] = -4; 828 polys[0].edges[2] = -1; 829 830 polys[1].numEdges = 3; 831 polys[1].edges[0] = 3; 832 polys[1].edges[1] = -5; 833 polys[1].edges[2] = -2; 834 835 polys[2].numEdges = 3; 836 polys[2].edges[0] = 1; 837 polys[2].edges[1] = -6; 838 polys[2].edges[2] = -3; 839 840 polys[3].numEdges = 3; 841 polys[3].edges[0] = 4; 842 polys[3].edges[1] = 8; 843 polys[3].edges[2] = -7; 844 845 polys[4].numEdges = 3; 846 polys[4].edges[0] = 5; 847 polys[4].edges[1] = 9; 848 polys[4].edges[2] = -8; 849 850 polys[5].numEdges = 3; 851 polys[5].edges[0] = 6; 852 polys[5].edges[1] = 7; 853 polys[5].edges[2] = -9; 854 855 // convex model 856 isConvex = true; 857 } 858 859 /* 860 ============ 861 idTraceModel::SetupPolygon 862 ============ 863 */ 864 void idTraceModel::SetupPolygon( const idVec3 *v, const int count ) { 865 int i, j; 866 idVec3 mid; 867 868 type = TRM_POLYGON; 869 numVerts = count; 870 // times three because we need to be able to turn the polygon into a volume 871 if ( numVerts * 3 > MAX_TRACEMODEL_EDGES ) { 872 idLib::common->Printf( "WARNING: idTraceModel::SetupPolygon: too many vertices\n" ); 873 numVerts = MAX_TRACEMODEL_EDGES / 3; 874 } 875 876 numEdges = numVerts; 877 numPolys = 2; 878 // set polygon planes 879 polys[0].numEdges = numEdges; 880 polys[0].normal = ( v[1] - v[0] ).Cross( v[2] - v[0] ); 881 polys[0].normal.Normalize(); 882 polys[0].dist = polys[0].normal * v[0]; 883 polys[1].numEdges = numEdges; 884 polys[1].normal = -polys[0].normal; 885 polys[1].dist = -polys[0].dist; 886 // setup verts, edges and polygons 887 polys[0].bounds.Clear(); 888 mid = vec3_origin; 889 for ( i = 0, j = 1; i < numVerts; i++, j++ ) { 890 if ( j >= numVerts ) { 891 j = 0; 892 } 893 verts[i] = v[i]; 894 edges[i+1].v[0] = i; 895 edges[i+1].v[1] = j; 896 edges[i+1].normal = polys[0].normal.Cross( v[i] - v[j] ); 897 edges[i+1].normal.Normalize(); 898 polys[0].edges[i] = i + 1; 899 polys[1].edges[i] = -(numVerts - i); 900 polys[0].bounds.AddPoint( verts[i] ); 901 mid += v[i]; 902 } 903 polys[1].bounds = polys[0].bounds; 904 // offset to center 905 offset = mid * (1.0f / numVerts); 906 // total bounds 907 bounds = polys[0].bounds; 908 // considered non convex because the model has no volume 909 isConvex = false; 910 } 911 912 /* 913 ============ 914 idTraceModel::SetupPolygon 915 ============ 916 */ 917 void idTraceModel::SetupPolygon( const idWinding &w ) { 918 int i; 919 idVec3 *verts; 920 921 verts = (idVec3 *) _alloca16( w.GetNumPoints() * sizeof( idVec3 ) ); 922 for ( i = 0; i < w.GetNumPoints(); i++ ) { 923 verts[i] = w[i].ToVec3(); 924 } 925 SetupPolygon( verts, w.GetNumPoints() ); 926 } 927 928 /* 929 ============ 930 idTraceModel::VolumeFromPolygon 931 ============ 932 */ 933 void idTraceModel::VolumeFromPolygon( idTraceModel &trm, float thickness ) const { 934 int i; 935 936 trm = *this; 937 trm.type = TRM_POLYGONVOLUME; 938 trm.numVerts = numVerts * 2; 939 trm.numEdges = numEdges * 3; 940 trm.numPolys = numEdges + 2; 941 for ( i = 0; i < numEdges; i++ ) { 942 trm.verts[ numVerts + i ] = verts[i] - thickness * polys[0].normal; 943 trm.edges[ numEdges + i + 1 ].v[0] = numVerts + i; 944 trm.edges[ numEdges + i + 1 ].v[1] = numVerts + (i+1) % numVerts; 945 trm.edges[ numEdges * 2 + i + 1 ].v[0] = i; 946 trm.edges[ numEdges * 2 + i + 1 ].v[1] = numVerts + i; 947 trm.polys[1].edges[i] = -(numEdges + i + 1); 948 trm.polys[2+i].numEdges = 4; 949 trm.polys[2+i].edges[0] = -(i + 1); 950 trm.polys[2+i].edges[1] = numEdges*2 + i + 1; 951 trm.polys[2+i].edges[2] = numEdges + i + 1; 952 trm.polys[2+i].edges[3] = -(numEdges*2 + (i+1) % numEdges + 1); 953 trm.polys[2+i].normal = (verts[(i + 1) % numVerts] - verts[i]).Cross( polys[0].normal ); 954 trm.polys[2+i].normal.Normalize(); 955 trm.polys[2+i].dist = trm.polys[2+i].normal * verts[i]; 956 } 957 trm.polys[1].dist = trm.polys[1].normal * trm.verts[ numEdges ]; 958 959 trm.GenerateEdgeNormals(); 960 } 961 962 /* 963 ============ 964 idTraceModel::GenerateEdgeNormals 965 ============ 966 */ 967 #define SHARP_EDGE_DOT -0.7f 968 969 int idTraceModel::GenerateEdgeNormals() { 970 int i, j, edgeNum, numSharpEdges; 971 float dot; 972 idVec3 dir; 973 traceModelPoly_t *poly; 974 traceModelEdge_t *edge; 975 976 for ( i = 0; i <= numEdges; i++ ) { 977 edges[i].normal.Zero(); 978 } 979 980 numSharpEdges = 0; 981 for ( i = 0; i < numPolys; i++ ) { 982 poly = polys + i; 983 for ( j = 0; j < poly->numEdges; j++ ) { 984 edgeNum = poly->edges[j]; 985 edge = edges + abs( edgeNum ); 986 if ( edge->normal[0] == 0.0f && edge->normal[1] == 0.0f && edge->normal[2] == 0.0f ) { 987 edge->normal = poly->normal; 988 } 989 else { 990 dot = edge->normal * poly->normal; 991 // if the two planes make a very sharp edge 992 if ( dot < SHARP_EDGE_DOT ) { 993 // max length normal pointing outside both polygons 994 dir = verts[ edge->v[edgeNum > 0]] - verts[ edge->v[edgeNum < 0]]; 995 edge->normal = edge->normal.Cross( dir ) + poly->normal.Cross( -dir ); 996 edge->normal *= ( 0.5f / ( 0.5f + 0.5f * SHARP_EDGE_DOT ) ) / edge->normal.Length(); 997 numSharpEdges++; 998 } 999 else { 1000 edge->normal = ( 0.5f / ( 0.5f + 0.5f * dot ) ) * ( edge->normal + poly->normal ); 1001 } 1002 } 1003 } 1004 } 1005 return numSharpEdges; 1006 } 1007 1008 /* 1009 ============ 1010 idTraceModel::Translate 1011 ============ 1012 */ 1013 void idTraceModel::Translate( const idVec3 &translation ) { 1014 int i; 1015 1016 for ( i = 0; i < numVerts; i++ ) { 1017 verts[i] += translation; 1018 } 1019 for ( i = 0; i < numPolys; i++ ) { 1020 polys[i].dist += polys[i].normal * translation; 1021 polys[i].bounds[0] += translation; 1022 polys[i].bounds[1] += translation; 1023 } 1024 offset += translation; 1025 bounds[0] += translation; 1026 bounds[1] += translation; 1027 } 1028 1029 /* 1030 ============ 1031 idTraceModel::Rotate 1032 ============ 1033 */ 1034 void idTraceModel::Rotate( const idMat3 &rotation ) { 1035 int i, j, edgeNum; 1036 1037 for ( i = 0; i < numVerts; i++ ) { 1038 verts[i] *= rotation; 1039 } 1040 1041 bounds.Clear(); 1042 for ( i = 0; i < numPolys; i++ ) { 1043 polys[i].normal *= rotation; 1044 polys[i].bounds.Clear(); 1045 edgeNum = 0; 1046 for ( j = 0; j < polys[i].numEdges; j++ ) { 1047 edgeNum = polys[i].edges[j]; 1048 polys[i].bounds.AddPoint( verts[edges[abs(edgeNum)].v[INT32_SIGNBITSET(edgeNum)]] ); 1049 } 1050 polys[i].dist = polys[i].normal * verts[edges[abs(edgeNum)].v[INT32_SIGNBITSET(edgeNum)]]; 1051 bounds += polys[i].bounds; 1052 } 1053 1054 GenerateEdgeNormals(); 1055 } 1056 1057 /* 1058 ============ 1059 idTraceModel::Shrink 1060 ============ 1061 */ 1062 void idTraceModel::Shrink( const float m ) { 1063 int i, j, edgeNum; 1064 traceModelEdge_t *edge; 1065 idVec3 dir; 1066 1067 if ( type == TRM_POLYGON ) { 1068 for ( i = 0; i < numEdges; i++ ) { 1069 edgeNum = polys[0].edges[i]; 1070 edge = &edges[abs(edgeNum)]; 1071 dir = verts[ edge->v[ INT32_SIGNBITSET(edgeNum) ] ] - verts[ edge->v[ INT32_SIGNBITNOTSET(edgeNum) ] ]; 1072 if ( dir.Normalize() < 2.0f * m ) { 1073 continue; 1074 } 1075 dir *= m; 1076 verts[ edge->v[ 0 ] ] -= dir; 1077 verts[ edge->v[ 1 ] ] += dir; 1078 } 1079 return; 1080 } 1081 1082 for ( i = 0; i < numPolys; i++ ) { 1083 polys[i].dist -= m; 1084 1085 for ( j = 0; j < polys[i].numEdges; j++ ) { 1086 edgeNum = polys[i].edges[j]; 1087 edge = &edges[abs(edgeNum)]; 1088 verts[ edge->v[ INT32_SIGNBITSET(edgeNum) ] ] -= polys[i].normal * m; 1089 } 1090 } 1091 } 1092 1093 /* 1094 ============ 1095 idTraceModel::Compare 1096 ============ 1097 */ 1098 bool idTraceModel::Compare( const idTraceModel &trm ) const { 1099 int i; 1100 1101 if ( type != trm.type || numVerts != trm.numVerts || 1102 numEdges != trm.numEdges || numPolys != trm.numPolys ) { 1103 return false; 1104 } 1105 if ( bounds != trm.bounds || offset != trm.offset ) { 1106 return false; 1107 } 1108 1109 switch( type ) { 1110 case TRM_INVALID: 1111 case TRM_BOX: 1112 case TRM_OCTAHEDRON: 1113 case TRM_DODECAHEDRON: 1114 case TRM_CYLINDER: 1115 case TRM_CONE: 1116 break; 1117 case TRM_BONE: 1118 case TRM_POLYGON: 1119 case TRM_POLYGONVOLUME: 1120 case TRM_CUSTOM: 1121 for ( i = 0; i < trm.numVerts; i++ ) { 1122 if ( verts[i] != trm.verts[i] ) { 1123 return false; 1124 } 1125 } 1126 break; 1127 } 1128 return true; 1129 } 1130 1131 /* 1132 ============ 1133 idTraceModel::GetPolygonArea 1134 ============ 1135 */ 1136 float idTraceModel::GetPolygonArea( int polyNum ) const { 1137 int i; 1138 idVec3 base, v1, v2, cross; 1139 float total; 1140 const traceModelPoly_t *poly; 1141 1142 if ( polyNum < 0 || polyNum >= numPolys ) { 1143 return 0.0f; 1144 } 1145 poly = &polys[polyNum]; 1146 total = 0.0f; 1147 base = verts[ edges[ abs(poly->edges[0]) ].v[ INT32_SIGNBITSET( poly->edges[0] ) ] ]; 1148 for ( i = 0; i < poly->numEdges; i++ ) { 1149 v1 = verts[ edges[ abs(poly->edges[i]) ].v[ INT32_SIGNBITSET( poly->edges[i] ) ] ] - base; 1150 v2 = verts[ edges[ abs(poly->edges[i]) ].v[ INT32_SIGNBITNOTSET( poly->edges[i] ) ] ] - base; 1151 cross = v1.Cross( v2 ); 1152 total += cross.Length(); 1153 } 1154 return total * 0.5f; 1155 } 1156 1157 /* 1158 ============ 1159 idTraceModel::GetOrderedSilhouetteEdges 1160 ============ 1161 */ 1162 int idTraceModel::GetOrderedSilhouetteEdges( const int edgeIsSilEdge[MAX_TRACEMODEL_EDGES+1], int silEdges[MAX_TRACEMODEL_EDGES] ) const { 1163 int i, j, edgeNum, numSilEdges, nextSilVert; 1164 int unsortedSilEdges[MAX_TRACEMODEL_EDGES]; 1165 1166 numSilEdges = 0; 1167 for ( i = 1; i <= numEdges; i++ ) { 1168 if ( edgeIsSilEdge[i] ) { 1169 unsortedSilEdges[numSilEdges++] = i; 1170 } 1171 } 1172 1173 silEdges[0] = unsortedSilEdges[0]; 1174 unsortedSilEdges[0] = -1; 1175 nextSilVert = edges[silEdges[0]].v[0]; 1176 for ( i = 1; i < numSilEdges; i++ ) { 1177 for ( j = 1; j < numSilEdges; j++ ) { 1178 edgeNum = unsortedSilEdges[j]; 1179 if ( edgeNum >= 0 ) { 1180 if ( edges[edgeNum].v[0] == nextSilVert ) { 1181 nextSilVert = edges[edgeNum].v[1]; 1182 silEdges[i] = edgeNum; 1183 break; 1184 } 1185 if ( edges[edgeNum].v[1] == nextSilVert ) { 1186 nextSilVert = edges[edgeNum].v[0]; 1187 silEdges[i] = -edgeNum; 1188 break; 1189 } 1190 } 1191 } 1192 if ( j >= numSilEdges ) { 1193 silEdges[i] = 1; // shouldn't happen 1194 } 1195 unsortedSilEdges[j] = -1; 1196 } 1197 return numSilEdges; 1198 } 1199 1200 /* 1201 ============ 1202 idTraceModel::GetProjectionSilhouetteEdges 1203 ============ 1204 */ 1205 int idTraceModel::GetProjectionSilhouetteEdges( const idVec3 &projectionOrigin, int silEdges[MAX_TRACEMODEL_EDGES] ) const { 1206 int i, j, edgeNum; 1207 int edgeIsSilEdge[MAX_TRACEMODEL_EDGES+1]; 1208 const traceModelPoly_t *poly; 1209 idVec3 dir; 1210 1211 memset( edgeIsSilEdge, 0, sizeof( edgeIsSilEdge ) ); 1212 1213 for ( i = 0; i < numPolys; i++ ) { 1214 poly = &polys[i]; 1215 edgeNum = poly->edges[0]; 1216 dir = verts[ edges[abs(edgeNum)].v[ INT32_SIGNBITSET(edgeNum) ] ] - projectionOrigin; 1217 if ( dir * poly->normal < 0.0f ) { 1218 for ( j = 0; j < poly->numEdges; j++ ) { 1219 edgeNum = poly->edges[j]; 1220 edgeIsSilEdge[abs(edgeNum)] ^= 1; 1221 } 1222 } 1223 } 1224 1225 return GetOrderedSilhouetteEdges( edgeIsSilEdge, silEdges ); 1226 } 1227 1228 /* 1229 ============ 1230 idTraceModel::GetParallelProjectionSilhouetteEdges 1231 ============ 1232 */ 1233 int idTraceModel::GetParallelProjectionSilhouetteEdges( const idVec3 &projectionDir, int silEdges[MAX_TRACEMODEL_EDGES] ) const { 1234 int i, j, edgeNum; 1235 int edgeIsSilEdge[MAX_TRACEMODEL_EDGES+1]; 1236 const traceModelPoly_t *poly; 1237 1238 memset( edgeIsSilEdge, 0, sizeof( edgeIsSilEdge ) ); 1239 1240 for ( i = 0; i < numPolys; i++ ) { 1241 poly = &polys[i]; 1242 if ( projectionDir * poly->normal < 0.0f ) { 1243 for ( j = 0; j < poly->numEdges; j++ ) { 1244 edgeNum = poly->edges[j]; 1245 edgeIsSilEdge[abs(edgeNum)] ^= 1; 1246 } 1247 } 1248 } 1249 1250 return GetOrderedSilhouetteEdges( edgeIsSilEdge, silEdges ); 1251 } 1252 1253 1254 /* 1255 1256 credits to Brian Mirtich for his paper "Fast and Accurate Computation of Polyhedral Mass Properties" 1257 1258 */ 1259 1260 typedef struct projectionIntegrals_s { 1261 float P1; 1262 float Pa, Pb; 1263 float Paa, Pab, Pbb; 1264 float Paaa, Paab, Pabb, Pbbb; 1265 } projectionIntegrals_t; 1266 1267 /* 1268 ============ 1269 idTraceModel::ProjectionIntegrals 1270 ============ 1271 */ 1272 void idTraceModel::ProjectionIntegrals( int polyNum, int a, int b, struct projectionIntegrals_s &integrals ) const { 1273 const traceModelPoly_t *poly; 1274 int i, edgeNum; 1275 idVec3 v1, v2; 1276 float a0, a1, da; 1277 float b0, b1, db; 1278 float a0_2, a0_3, a0_4, b0_2, b0_3, b0_4; 1279 float a1_2, a1_3, b1_2, b1_3; 1280 float C1, Ca, Caa, Caaa, Cb, Cbb, Cbbb; 1281 float Cab, Kab, Caab, Kaab, Cabb, Kabb; 1282 1283 memset(&integrals, 0, sizeof(projectionIntegrals_t)); 1284 poly = &polys[polyNum]; 1285 for ( i = 0; i < poly->numEdges; i++ ) { 1286 edgeNum = poly->edges[i]; 1287 v1 = verts[ edges[ abs(edgeNum) ].v[ edgeNum < 0 ] ]; 1288 v2 = verts[ edges[ abs(edgeNum) ].v[ edgeNum > 0 ] ]; 1289 a0 = v1[a]; 1290 b0 = v1[b]; 1291 a1 = v2[a]; 1292 b1 = v2[b]; 1293 da = a1 - a0; 1294 db = b1 - b0; 1295 a0_2 = a0 * a0; 1296 a0_3 = a0_2 * a0; 1297 a0_4 = a0_3 * a0; 1298 b0_2 = b0 * b0; 1299 b0_3 = b0_2 * b0; 1300 b0_4 = b0_3 * b0; 1301 a1_2 = a1 * a1; 1302 a1_3 = a1_2 * a1; 1303 b1_2 = b1 * b1; 1304 b1_3 = b1_2 * b1; 1305 1306 C1 = a1 + a0; 1307 Ca = a1 * C1 + a0_2; 1308 Caa = a1 * Ca + a0_3; 1309 Caaa = a1 * Caa + a0_4; 1310 Cb = b1 * (b1 + b0) + b0_2; 1311 Cbb = b1 * Cb + b0_3; 1312 Cbbb = b1 * Cbb + b0_4; 1313 Cab = 3 * a1_2 + 2 * a1 * a0 + a0_2; 1314 Kab = a1_2 + 2 * a1 * a0 + 3 * a0_2; 1315 Caab = a0 * Cab + 4 * a1_3; 1316 Kaab = a1 * Kab + 4 * a0_3; 1317 Cabb = 4 * b1_3 + 3 * b1_2 * b0 + 2 * b1 * b0_2 + b0_3; 1318 Kabb = b1_3 + 2 * b1_2 * b0 + 3 * b1 * b0_2 + 4 * b0_3; 1319 1320 integrals.P1 += db * C1; 1321 integrals.Pa += db * Ca; 1322 integrals.Paa += db * Caa; 1323 integrals.Paaa += db * Caaa; 1324 integrals.Pb += da * Cb; 1325 integrals.Pbb += da * Cbb; 1326 integrals.Pbbb += da * Cbbb; 1327 integrals.Pab += db * (b1 * Cab + b0 * Kab); 1328 integrals.Paab += db * (b1 * Caab + b0 * Kaab); 1329 integrals.Pabb += da * (a1 * Cabb + a0 * Kabb); 1330 } 1331 1332 integrals.P1 *= (1.0f / 2.0f); 1333 integrals.Pa *= (1.0f / 6.0f); 1334 integrals.Paa *= (1.0f / 12.0f); 1335 integrals.Paaa *= (1.0f / 20.0f); 1336 integrals.Pb *= (1.0f / -6.0f); 1337 integrals.Pbb *= (1.0f / -12.0f); 1338 integrals.Pbbb *= (1.0f / -20.0f); 1339 integrals.Pab *= (1.0f / 24.0f); 1340 integrals.Paab *= (1.0f / 60.0f); 1341 integrals.Pabb *= (1.0f / -60.0f); 1342 } 1343 1344 typedef struct polygonIntegrals_s { 1345 float Fa, Fb, Fc; 1346 float Faa, Fbb, Fcc; 1347 float Faaa, Fbbb, Fccc; 1348 float Faab, Fbbc, Fcca; 1349 } polygonIntegrals_t; 1350 1351 /* 1352 ============ 1353 idTraceModel::PolygonIntegrals 1354 ============ 1355 */ 1356 void idTraceModel::PolygonIntegrals( int polyNum, int a, int b, int c, struct polygonIntegrals_s &integrals ) const { 1357 projectionIntegrals_t pi; 1358 idVec3 n; 1359 float w; 1360 float k1, k2, k3, k4; 1361 1362 ProjectionIntegrals( polyNum, a, b, pi ); 1363 1364 n = polys[polyNum].normal; 1365 w = -polys[polyNum].dist; 1366 k1 = 1 / n[c]; 1367 k2 = k1 * k1; 1368 k3 = k2 * k1; 1369 k4 = k3 * k1; 1370 1371 integrals.Fa = k1 * pi.Pa; 1372 integrals.Fb = k1 * pi.Pb; 1373 integrals.Fc = -k2 * (n[a] * pi.Pa + n[b] * pi.Pb + w * pi.P1); 1374 1375 integrals.Faa = k1 * pi.Paa; 1376 integrals.Fbb = k1 * pi.Pbb; 1377 integrals.Fcc = k3 * (Square(n[a]) * pi.Paa + 2 * n[a] * n[b] * pi.Pab + Square(n[b]) * pi.Pbb 1378 + w * (2 * (n[a] * pi.Pa + n[b] * pi.Pb) + w * pi.P1)); 1379 1380 integrals.Faaa = k1 * pi.Paaa; 1381 integrals.Fbbb = k1 * pi.Pbbb; 1382 integrals.Fccc = -k4 * (Cube(n[a]) * pi.Paaa + 3 * Square(n[a]) * n[b] * pi.Paab 1383 + 3 * n[a] * Square(n[b]) * pi.Pabb + Cube(n[b]) * pi.Pbbb 1384 + 3 * w * (Square(n[a]) * pi.Paa + 2 * n[a] * n[b] * pi.Pab + Square(n[b]) * pi.Pbb) 1385 + w * w * (3 * (n[a] * pi.Pa + n[b] * pi.Pb) + w * pi.P1)); 1386 1387 integrals.Faab = k1 * pi.Paab; 1388 integrals.Fbbc = -k2 * (n[a] * pi.Pabb + n[b] * pi.Pbbb + w * pi.Pbb); 1389 integrals.Fcca = k3 * (Square(n[a]) * pi.Paaa + 2 * n[a] * n[b] * pi.Paab + Square(n[b]) * pi.Pabb 1390 + w * (2 * (n[a] * pi.Paa + n[b] * pi.Pab) + w * pi.Pa)); 1391 } 1392 1393 typedef struct volumeIntegrals_s { 1394 float T0; 1395 idVec3 T1; 1396 idVec3 T2; 1397 idVec3 TP; 1398 } volumeIntegrals_t; 1399 1400 /* 1401 ============ 1402 idTraceModel::VolumeIntegrals 1403 ============ 1404 */ 1405 void idTraceModel::VolumeIntegrals( struct volumeIntegrals_s &integrals ) const { 1406 const traceModelPoly_t *poly; 1407 polygonIntegrals_t pi; 1408 int i, a, b, c; 1409 float nx, ny, nz; 1410 1411 memset( &integrals, 0, sizeof(volumeIntegrals_t) ); 1412 for ( i = 0; i < numPolys; i++ ) { 1413 poly = &polys[i]; 1414 1415 nx = idMath::Fabs( poly->normal[0] ); 1416 ny = idMath::Fabs( poly->normal[1] ); 1417 nz = idMath::Fabs( poly->normal[2] ); 1418 if ( nx > ny && nx > nz ) { 1419 c = 0; 1420 } 1421 else { 1422 c = (ny > nz) ? 1 : 2; 1423 } 1424 a = (c + 1) % 3; 1425 b = (a + 1) % 3; 1426 1427 PolygonIntegrals( i, a, b, c, pi ); 1428 1429 integrals.T0 += poly->normal[0] * ((a == 0) ? pi.Fa : ((b == 0) ? pi.Fb : pi.Fc)); 1430 1431 integrals.T1[a] += poly->normal[a] * pi.Faa; 1432 integrals.T1[b] += poly->normal[b] * pi.Fbb; 1433 integrals.T1[c] += poly->normal[c] * pi.Fcc; 1434 integrals.T2[a] += poly->normal[a] * pi.Faaa; 1435 integrals.T2[b] += poly->normal[b] * pi.Fbbb; 1436 integrals.T2[c] += poly->normal[c] * pi.Fccc; 1437 integrals.TP[a] += poly->normal[a] * pi.Faab; 1438 integrals.TP[b] += poly->normal[b] * pi.Fbbc; 1439 integrals.TP[c] += poly->normal[c] * pi.Fcca; 1440 } 1441 1442 integrals.T1 *= 0.5f; 1443 integrals.T2 *= (1.0f / 3.0f); 1444 integrals.TP *= 0.5f; 1445 } 1446 1447 /* 1448 ============ 1449 idTraceModel::GetMassProperties 1450 ============ 1451 */ 1452 void idTraceModel::GetMassProperties( const float density, float &mass, idVec3 ¢erOfMass, idMat3 &inertiaTensor ) const { 1453 volumeIntegrals_t integrals; 1454 1455 // if polygon trace model 1456 if ( type == TRM_POLYGON ) { 1457 idTraceModel trm; 1458 1459 VolumeFromPolygon( trm, 1.0f ); 1460 trm.GetMassProperties( density, mass, centerOfMass, inertiaTensor ); 1461 return; 1462 } 1463 1464 VolumeIntegrals( integrals ); 1465 1466 // if no volume 1467 if ( integrals.T0 == 0.0f ) { 1468 mass = 1.0f; 1469 centerOfMass.Zero(); 1470 inertiaTensor.Identity(); 1471 return; 1472 } 1473 1474 // mass of model 1475 mass = density * integrals.T0; 1476 // center of mass 1477 centerOfMass = integrals.T1 / integrals.T0; 1478 // compute inertia tensor 1479 inertiaTensor[0][0] = density * (integrals.T2[1] + integrals.T2[2]); 1480 inertiaTensor[1][1] = density * (integrals.T2[2] + integrals.T2[0]); 1481 inertiaTensor[2][2] = density * (integrals.T2[0] + integrals.T2[1]); 1482 inertiaTensor[0][1] = inertiaTensor[1][0] = - density * integrals.TP[0]; 1483 inertiaTensor[1][2] = inertiaTensor[2][1] = - density * integrals.TP[1]; 1484 inertiaTensor[2][0] = inertiaTensor[0][2] = - density * integrals.TP[2]; 1485 // translate inertia tensor to center of mass 1486 inertiaTensor[0][0] -= mass * (centerOfMass[1]*centerOfMass[1] + centerOfMass[2]*centerOfMass[2]); 1487 inertiaTensor[1][1] -= mass * (centerOfMass[2]*centerOfMass[2] + centerOfMass[0]*centerOfMass[0]); 1488 inertiaTensor[2][2] -= mass * (centerOfMass[0]*centerOfMass[0] + centerOfMass[1]*centerOfMass[1]); 1489 inertiaTensor[0][1] = inertiaTensor[1][0] += mass * centerOfMass[0] * centerOfMass[1]; 1490 inertiaTensor[1][2] = inertiaTensor[2][1] += mass * centerOfMass[1] * centerOfMass[2]; 1491 inertiaTensor[2][0] = inertiaTensor[0][2] += mass * centerOfMass[2] * centerOfMass[0]; 1492 }