DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 &centerOfMass, 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 }