AASFile_sample.cpp (15518B)
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 32 33 #include "AASFile.h" 34 #include "AASFile_local.h" 35 36 37 //=============================================================== 38 // 39 // Environment Sampling 40 // 41 //=============================================================== 42 43 /* 44 ================ 45 idAASFileLocal::EdgeCenter 46 ================ 47 */ 48 idVec3 idAASFileLocal::EdgeCenter( int edgeNum ) const { 49 const aasEdge_t *edge; 50 edge = &edges[edgeNum]; 51 return ( vertices[edge->vertexNum[0]] + vertices[edge->vertexNum[1]] ) * 0.5f; 52 } 53 54 /* 55 ================ 56 idAASFileLocal::FaceCenter 57 ================ 58 */ 59 idVec3 idAASFileLocal::FaceCenter( int faceNum ) const { 60 int i, edgeNum; 61 const aasFace_t *face; 62 const aasEdge_t *edge; 63 idVec3 center; 64 65 center = vec3_origin; 66 67 face = &faces[faceNum]; 68 if ( face->numEdges > 0 ) { 69 for ( i = 0; i < face->numEdges; i++ ) { 70 edgeNum = edgeIndex[ face->firstEdge + i ]; 71 edge = &edges[ abs( edgeNum ) ]; 72 center += vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ]; 73 } 74 center /= face->numEdges; 75 } 76 return center; 77 } 78 79 /* 80 ================ 81 idAASFileLocal::AreaCenter 82 ================ 83 */ 84 idVec3 idAASFileLocal::AreaCenter( int areaNum ) const { 85 int i, faceNum; 86 const aasArea_t *area; 87 idVec3 center; 88 89 center = vec3_origin; 90 91 area = &areas[areaNum]; 92 if ( area->numFaces > 0 ) { 93 for ( i = 0; i < area->numFaces; i++ ) { 94 faceNum = faceIndex[area->firstFace + i]; 95 center += FaceCenter( abs(faceNum) ); 96 } 97 center /= area->numFaces; 98 } 99 return center; 100 } 101 102 /* 103 ============ 104 idAASFileLocal::AreaReachableGoal 105 ============ 106 */ 107 idVec3 idAASFileLocal::AreaReachableGoal( int areaNum ) const { 108 int i, faceNum, numFaces; 109 const aasArea_t *area; 110 idVec3 center; 111 idVec3 start, end; 112 aasTrace_t trace; 113 114 area = &areas[areaNum]; 115 116 if ( !(area->flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) || (area->flags & AREA_LIQUID) ) { 117 return AreaCenter( areaNum ); 118 } 119 120 center = vec3_origin; 121 122 numFaces = 0; 123 for ( i = 0; i < area->numFaces; i++ ) { 124 faceNum = faceIndex[area->firstFace + i]; 125 if ( !(faces[abs(faceNum)].flags & FACE_FLOOR) ) { 126 continue; 127 } 128 center += FaceCenter( abs(faceNum) ); 129 numFaces++; 130 } 131 if ( numFaces > 0 ) { 132 center /= numFaces; 133 } 134 center[2] += 1.0f; 135 end = center; 136 end[2] -= 1024; 137 Trace( trace, center, end ); 138 139 return trace.endpos; 140 } 141 142 /* 143 ================ 144 idAASFileLocal::EdgeBounds 145 ================ 146 */ 147 idBounds idAASFileLocal::EdgeBounds( int edgeNum ) const { 148 const aasEdge_t *edge; 149 idBounds bounds; 150 151 edge = &edges[ abs( edgeNum ) ]; 152 bounds[0] = bounds[1] = vertices[ edge->vertexNum[0] ]; 153 bounds += vertices[ edge->vertexNum[1] ]; 154 return bounds; 155 } 156 157 /* 158 ================ 159 idAASFileLocal::FaceBounds 160 ================ 161 */ 162 idBounds idAASFileLocal::FaceBounds( int faceNum ) const { 163 int i, edgeNum; 164 const aasFace_t *face; 165 const aasEdge_t *edge; 166 idBounds bounds; 167 168 face = &faces[faceNum]; 169 bounds.Clear(); 170 171 for ( i = 0; i < face->numEdges; i++ ) { 172 edgeNum = edgeIndex[ face->firstEdge + i ]; 173 edge = &edges[ abs( edgeNum ) ]; 174 bounds.AddPoint( vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ] ); 175 } 176 return bounds; 177 } 178 179 /* 180 ================ 181 idAASFileLocal::AreaBounds 182 ================ 183 */ 184 idBounds idAASFileLocal::AreaBounds( int areaNum ) const { 185 int i, faceNum; 186 const aasArea_t *area; 187 idBounds bounds; 188 189 area = &areas[areaNum]; 190 bounds.Clear(); 191 192 for ( i = 0; i < area->numFaces; i++ ) { 193 faceNum = faceIndex[area->firstFace + i]; 194 bounds += FaceBounds( abs(faceNum) ); 195 } 196 return bounds; 197 } 198 199 /* 200 ============ 201 idAASFileLocal::PointAreaNum 202 ============ 203 */ 204 int idAASFileLocal::PointAreaNum( const idVec3 &origin ) const { 205 int nodeNum; 206 const aasNode_t *node; 207 208 nodeNum = 1; 209 do { 210 node = &nodes[nodeNum]; 211 if ( planeList[node->planeNum].Side( origin ) == PLANESIDE_BACK ) { 212 nodeNum = node->children[1]; 213 } 214 else { 215 nodeNum = node->children[0]; 216 } 217 if ( nodeNum < 0 ) { 218 return -nodeNum; 219 } 220 } while( nodeNum ); 221 222 return 0; 223 } 224 225 /* 226 ============ 227 idAASFileLocal::PointReachableAreaNum 228 ============ 229 */ 230 int idAASFileLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const { 231 int areaList[32], areaNum, i; 232 idVec3 start, end, pointList[32]; 233 aasTrace_t trace; 234 idBounds bounds; 235 float frac; 236 237 start = origin; 238 239 trace.areas = areaList; 240 trace.points = pointList; 241 trace.maxAreas = sizeof( areaList ) / sizeof( int ); 242 trace.getOutOfSolid = true; 243 244 areaNum = PointAreaNum( start ); 245 if ( areaNum ) { 246 if ( ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) { 247 return areaNum; 248 } 249 } 250 else { 251 // trace up 252 end = start; 253 end[2] += 32.0f; 254 Trace( trace, start, end ); 255 if ( trace.numAreas >= 1 ) { 256 if ( ( areas[0].flags & areaFlags ) && ( ( areas[0].travelFlags & excludeTravelFlags ) == 0 ) ) { 257 return areaList[0]; 258 } 259 start = pointList[0]; 260 start[2] += 1.0f; 261 } 262 } 263 264 // trace down 265 end = start; 266 end[2] -= 32.0f; 267 Trace( trace, start, end ); 268 if ( trace.lastAreaNum ) { 269 if ( ( areas[trace.lastAreaNum].flags & areaFlags ) && ( ( areas[trace.lastAreaNum].travelFlags & excludeTravelFlags ) == 0 ) ) { 270 return trace.lastAreaNum; 271 } 272 start = trace.endpos; 273 } 274 275 // expand bounds until an area is found 276 for ( i = 1; i <= 12; i++ ) { 277 frac = i * ( 1.0f / 12.0f ); 278 bounds[0] = origin + searchBounds[0] * frac; 279 bounds[1] = origin + searchBounds[1] * frac; 280 areaNum = BoundsReachableAreaNum( bounds, areaFlags, excludeTravelFlags ); 281 if ( areaNum && ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) { 282 return areaNum; 283 } 284 } 285 return 0; 286 } 287 288 /* 289 ============ 290 idAASFileLocal::BoundsReachableAreaNum_r 291 ============ 292 */ 293 int idAASFileLocal::BoundsReachableAreaNum_r( int nodeNum, const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const { 294 int res; 295 const aasNode_t *node; 296 297 while( nodeNum ) { 298 if ( nodeNum < 0 ) { 299 if ( ( areas[-nodeNum].flags & areaFlags ) && ( ( areas[-nodeNum].travelFlags & excludeTravelFlags ) == 0 ) ) { 300 return -nodeNum; 301 } 302 return 0; 303 } 304 node = &nodes[nodeNum]; 305 res = bounds.PlaneSide( planeList[node->planeNum] ); 306 if ( res == PLANESIDE_BACK ) { 307 nodeNum = node->children[1]; 308 } 309 else if ( res == PLANESIDE_FRONT ) { 310 nodeNum = node->children[0]; 311 } 312 else { 313 nodeNum = BoundsReachableAreaNum_r( node->children[1], bounds, areaFlags, excludeTravelFlags ); 314 if ( nodeNum ) { 315 return nodeNum; 316 } 317 nodeNum = node->children[0]; 318 } 319 } 320 321 return 0; 322 } 323 324 /* 325 ============ 326 idAASFileLocal::BoundsReachableAreaNum 327 ============ 328 */ 329 int idAASFileLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const { 330 331 return BoundsReachableAreaNum_r( 1, bounds, areaFlags, excludeTravelFlags ); 332 } 333 334 /* 335 ============ 336 idAASFileLocal::PushPointIntoAreaNum 337 ============ 338 */ 339 void idAASFileLocal::PushPointIntoAreaNum( int areaNum, idVec3 &point ) const { 340 int i, faceNum; 341 const aasArea_t *area; 342 const aasFace_t *face; 343 344 area = &areas[areaNum]; 345 346 // push the point to the right side of all area face planes 347 for ( i = 0; i < area->numFaces; i++ ) { 348 faceNum = faceIndex[area->firstFace + i]; 349 face = &faces[abs( faceNum )]; 350 351 const idPlane &plane = planeList[face->planeNum ^ INT32_SIGNBITSET( faceNum )]; 352 float dist = plane.Distance( point ); 353 354 // project the point onto the face plane if it is on the wrong side 355 if ( dist < 0.0f ) { 356 point -= dist * plane.Normal(); 357 } 358 } 359 } 360 361 /* 362 ============ 363 idAASFileLocal::Trace 364 ============ 365 */ 366 #define TRACEPLANE_EPSILON 0.125f 367 368 typedef struct aasTraceStack_s 369 { 370 idVec3 start; 371 idVec3 end; 372 int planeNum; 373 int nodeNum; 374 } aasTraceStack_t; 375 376 bool idAASFileLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const { 377 int side, nodeNum, tmpPlaneNum; 378 double front, back, frac; 379 idVec3 cur_start, cur_end, cur_mid, v1, v2; 380 aasTraceStack_t tracestack[MAX_AAS_TREE_DEPTH]; 381 aasTraceStack_t *tstack_p; 382 const aasNode_t *node; 383 const idPlane *plane; 384 385 trace.numAreas = 0; 386 trace.lastAreaNum = 0; 387 trace.blockingAreaNum = 0; 388 389 tstack_p = tracestack; 390 tstack_p->start = start; 391 tstack_p->end = end; 392 tstack_p->planeNum = 0; 393 tstack_p->nodeNum = 1; //start with the root of the tree 394 tstack_p++; 395 396 while( 1 ) { 397 398 tstack_p--; 399 // if the trace stack is empty 400 if ( tstack_p < tracestack ) { 401 if ( !trace.lastAreaNum ) { 402 // completely in solid 403 trace.fraction = 0.0f; 404 trace.endpos = start; 405 } 406 else { 407 // nothing was hit 408 trace.fraction = 1.0f; 409 trace.endpos = end; 410 } 411 trace.planeNum = 0; 412 return false; 413 } 414 415 // number of the current node to test the line against 416 nodeNum = tstack_p->nodeNum; 417 418 // if it is an area 419 if ( nodeNum < 0) { 420 // if can't enter the area 421 if ( ( areas[-nodeNum].flags & trace.flags ) || ( areas[-nodeNum].travelFlags & trace.travelFlags ) ) { 422 if ( !trace.lastAreaNum ) { 423 trace.fraction = 0.0f; 424 v1 = vec3_origin; 425 } else { 426 v1 = end - start; 427 v2 = tstack_p->start - start; 428 trace.fraction = v2.Length() / v1.Length(); 429 } 430 trace.endpos = tstack_p->start; 431 trace.blockingAreaNum = -nodeNum; 432 trace.planeNum = tstack_p->planeNum; 433 // always take the plane with normal facing towards the trace start 434 plane = &planeList[trace.planeNum]; 435 if ( v1 * plane->Normal() > 0.0f ) { 436 trace.planeNum ^= 1; 437 } 438 return true; 439 } 440 trace.lastAreaNum = -nodeNum; 441 if ( trace.numAreas < trace.maxAreas ) { 442 if ( trace.areas ) { 443 trace.areas[trace.numAreas] = -nodeNum; 444 } 445 if ( trace.points ) { 446 trace.points[trace.numAreas] = tstack_p->start; 447 } 448 trace.numAreas++; 449 } 450 continue; 451 } 452 453 // if it is a solid leaf 454 if ( !nodeNum ) { 455 if ( !trace.lastAreaNum ) { 456 trace.fraction = 0.0f; 457 v1 = vec3_origin; 458 } else { 459 v1 = end - start; 460 v2 = tstack_p->start - start; 461 trace.fraction = v2.Length() / v1.Length(); 462 } 463 trace.endpos = tstack_p->start; 464 trace.blockingAreaNum = 0; // hit solid leaf 465 trace.planeNum = tstack_p->planeNum; 466 // always take the plane with normal facing towards the trace start 467 plane = &planeList[trace.planeNum]; 468 if ( v1 * plane->Normal() > 0.0f ) { 469 trace.planeNum ^= 1; 470 } 471 if ( !trace.lastAreaNum && trace.getOutOfSolid ) { 472 continue; 473 } 474 else { 475 return true; 476 } 477 } 478 479 // the node to test against 480 node = &nodes[nodeNum]; 481 // start point of current line to test against node 482 cur_start = tstack_p->start; 483 // end point of the current line to test against node 484 cur_end = tstack_p->end; 485 // the current node plane 486 plane = &planeList[node->planeNum]; 487 488 front = plane->Distance( cur_start ); 489 back = plane->Distance( cur_end ); 490 491 // if the whole to be traced line is totally at the front of this node 492 // only go down the tree with the front child 493 if ( front >= -ON_EPSILON && back >= -ON_EPSILON ) { 494 // keep the current start and end point on the stack and go down the tree with the front child 495 tstack_p->nodeNum = node->children[0]; 496 tstack_p++; 497 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) { 498 common->Error("idAASFileLocal::Trace: stack overflow\n" ); 499 return false; 500 } 501 } 502 // if the whole to be traced line is totally at the back of this node 503 // only go down the tree with the back child 504 else if ( front < ON_EPSILON && back < ON_EPSILON ) { 505 // keep the current start and end point on the stack and go down the tree with the back child 506 tstack_p->nodeNum = node->children[1]; 507 tstack_p++; 508 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) { 509 common->Error("idAASFileLocal::Trace: stack overflow\n" ); 510 return false; 511 } 512 } 513 // go down the tree both at the front and back of the node 514 else { 515 tmpPlaneNum = tstack_p->planeNum; 516 // calculate the hit point with the node plane 517 // put the cross point TRACEPLANE_EPSILON on the near side 518 if (front < 0) { 519 frac = (front + TRACEPLANE_EPSILON) / ( front - back ); 520 } 521 else { 522 frac = (front - TRACEPLANE_EPSILON) / ( front - back ); 523 } 524 525 if (frac < 0) { 526 frac = 0.001f; //0 527 } 528 else if (frac > 1) { 529 frac = 0.999f; //1 530 } 531 532 cur_mid = cur_start + ( cur_end - cur_start ) * frac; 533 534 // side the front part of the line is on 535 side = front < 0; 536 537 // first put the end part of the line on the stack (back side) 538 tstack_p->start = cur_mid; 539 tstack_p->planeNum = node->planeNum; 540 tstack_p->nodeNum = node->children[!side]; 541 tstack_p++; 542 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) { 543 common->Error("idAASFileLocal::Trace: stack overflow\n" ); 544 return false; 545 } 546 // now put the part near the start of the line on the stack so we will 547 // continue with that part first. 548 tstack_p->start = cur_start; 549 tstack_p->end = cur_mid; 550 tstack_p->planeNum = tmpPlaneNum; 551 tstack_p->nodeNum = node->children[side]; 552 tstack_p++; 553 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) { 554 common->Error("idAASFileLocal::Trace: stack overflow\n" ); 555 return false; 556 } 557 } 558 } 559 return false; 560 } 561 562 /* 563 ============ 564 idAASLocal::AreaContentsTravelFlags 565 ============ 566 */ 567 int idAASFileLocal::AreaContentsTravelFlags( int areaNum ) const { 568 if ( areas[areaNum].contents & AREACONTENTS_WATER ) { 569 return TFL_WATER; 570 } 571 return TFL_AIR; 572 } 573 574 /* 575 ============ 576 idAASFileLocal::MaxTreeDepth_r 577 ============ 578 */ 579 void idAASFileLocal::MaxTreeDepth_r( int nodeNum, int &depth, int &maxDepth ) const { 580 const aasNode_t *node; 581 582 if ( nodeNum <= 0 ) { 583 return; 584 } 585 586 depth++; 587 if ( depth > maxDepth ) { 588 maxDepth = depth; 589 } 590 591 node = &nodes[nodeNum]; 592 MaxTreeDepth_r( node->children[0], depth, maxDepth ); 593 MaxTreeDepth_r( node->children[1], depth, maxDepth ); 594 595 depth--; 596 } 597 598 /* 599 ============ 600 idAASFileLocal::MaxTreeDepth 601 ============ 602 */ 603 int idAASFileLocal::MaxTreeDepth() const { 604 int depth, maxDepth; 605 606 depth = maxDepth = 0; 607 MaxTreeDepth_r( 1, depth, maxDepth ); 608 return maxDepth; 609 }