AASFile.cpp (33890B)
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 40 idReachability 41 42 =============================================================================== 43 */ 44 45 /* 46 ================ 47 Reachability_Write 48 ================ 49 */ 50 bool Reachability_Write( idFile *fp, idReachability *reach ) { 51 fp->WriteFloatString( "\t\t%d %d (%f %f %f) (%f %f %f) %d %d", 52 (int) reach->travelType, (int) reach->toAreaNum, reach->start.x, reach->start.y, reach->start.z, 53 reach->end.x, reach->end.y, reach->end.z, reach->edgeNum, (int) reach->travelTime ); 54 return true; 55 } 56 57 /* 58 ================ 59 Reachability_Read 60 ================ 61 */ 62 bool Reachability_Read( idLexer &src, idReachability *reach ) { 63 reach->travelType = src.ParseInt(); 64 reach->toAreaNum = src.ParseInt(); 65 src.Parse1DMatrix( 3, reach->start.ToFloatPtr() ); 66 src.Parse1DMatrix( 3, reach->end.ToFloatPtr() ); 67 reach->edgeNum = src.ParseInt(); 68 reach->travelTime = src.ParseInt(); 69 return true; 70 } 71 72 /* 73 ================ 74 idReachability::CopyBase 75 ================ 76 */ 77 void idReachability::CopyBase( idReachability &reach ) { 78 travelType = reach.travelType; 79 toAreaNum = reach.toAreaNum; 80 start = reach.start; 81 end = reach.end; 82 edgeNum = reach.edgeNum; 83 travelTime = reach.travelTime; 84 } 85 86 87 /* 88 =============================================================================== 89 90 idReachability_Special 91 92 =============================================================================== 93 */ 94 95 /* 96 ================ 97 Reachability_Special_Write 98 ================ 99 */ 100 bool Reachability_Special_Write( idFile *fp, idReachability_Special *reach ) { 101 int i; 102 const idKeyValue *keyValue; 103 104 fp->WriteFloatString( "\n\t\t{\n" ); 105 for ( i = 0; i < reach->dict.GetNumKeyVals(); i++ ) { 106 keyValue = reach->dict.GetKeyVal( i ); 107 fp->WriteFloatString( "\t\t\t\"%s\" \"%s\"\n", keyValue->GetKey().c_str(), keyValue->GetValue().c_str() ); 108 } 109 fp->WriteFloatString( "\t\t}\n" ); 110 111 return true; 112 } 113 114 /* 115 ================ 116 Reachability_Special_Read 117 ================ 118 */ 119 bool Reachability_Special_Read( idLexer &src, idReachability_Special *reach ) { 120 idToken key, value; 121 122 src.ExpectTokenString( "{" ); 123 while( src.ReadToken( &key ) ) { 124 if ( key == "}" ) { 125 return true; 126 } 127 src.ExpectTokenType( TT_STRING, 0, &value ); 128 reach->dict.Set( key, value ); 129 } 130 return false; 131 } 132 133 /* 134 =============================================================================== 135 136 idAASSettings 137 138 =============================================================================== 139 */ 140 141 /* 142 ============ 143 idAASSettings::idAASSettings 144 ============ 145 */ 146 idAASSettings::idAASSettings() { 147 numBoundingBoxes = 1; 148 boundingBoxes[0] = idBounds( idVec3( -16, -16, 0 ), idVec3( 16, 16, 72 ) ); 149 usePatches = false; 150 writeBrushMap = false; 151 playerFlood = false; 152 noOptimize = false; 153 allowSwimReachabilities = false; 154 allowFlyReachabilities = false; 155 fileExtension = "aas48"; 156 // physics settings 157 gravity = idVec3( 0, 0, -1066 ); 158 gravityDir = gravity; 159 gravityValue = gravityDir.Normalize(); 160 invGravityDir = -gravityDir; 161 maxStepHeight = 14.0f; 162 maxBarrierHeight = 32.0f; 163 maxWaterJumpHeight = 20.0f; 164 maxFallHeight = 64.0f; 165 minFloorCos = 0.7f; 166 // fixed travel times 167 tt_barrierJump = 100; 168 tt_startCrouching = 100; 169 tt_waterJump = 100; 170 tt_startWalkOffLedge = 100; 171 } 172 173 /* 174 ============ 175 idAASSettings::ParseBool 176 ============ 177 */ 178 bool idAASSettings::ParseBool( idLexer &src, bool &b ) { 179 if ( !src.ExpectTokenString( "=" ) ) { 180 return false; 181 } 182 b = src.ParseBool(); 183 return true; 184 } 185 186 /* 187 ============ 188 idAASSettings::ParseInt 189 ============ 190 */ 191 bool idAASSettings::ParseInt( idLexer &src, int &i ) { 192 if ( !src.ExpectTokenString( "=" ) ) { 193 return false; 194 } 195 i = src.ParseInt(); 196 return true; 197 } 198 199 /* 200 ============ 201 idAASSettings::ParseFloat 202 ============ 203 */ 204 bool idAASSettings::ParseFloat( idLexer &src, float &f ) { 205 if ( !src.ExpectTokenString( "=" ) ) { 206 return false; 207 } 208 f = src.ParseFloat(); 209 return true; 210 } 211 212 /* 213 ============ 214 idAASSettings::ParseVector 215 ============ 216 */ 217 bool idAASSettings::ParseVector( idLexer &src, idVec3 &vec ) { 218 if ( !src.ExpectTokenString( "=" ) ) { 219 return false; 220 } 221 return ( src.Parse1DMatrix( 3, vec.ToFloatPtr() ) != 0 ); 222 } 223 224 /* 225 ============ 226 idAASSettings::ParseBBoxes 227 ============ 228 */ 229 bool idAASSettings::ParseBBoxes( idLexer &src ) { 230 idToken token; 231 idBounds bounds; 232 233 numBoundingBoxes = 0; 234 235 if ( !src.ExpectTokenString( "{" ) ) { 236 return false; 237 } 238 while( src.ReadToken( &token ) ) { 239 if ( token == "}" ) { 240 return true; 241 } 242 src.UnreadToken( &token ); 243 src.Parse1DMatrix( 3, bounds[0].ToFloatPtr() ); 244 if ( !src.ExpectTokenString( "-" ) ) { 245 return false; 246 } 247 src.Parse1DMatrix( 3, bounds[1].ToFloatPtr() ); 248 249 boundingBoxes[numBoundingBoxes++] = bounds; 250 } 251 return false; 252 } 253 254 /* 255 ============ 256 idAASSettings::FromParser 257 ============ 258 */ 259 bool idAASSettings::FromParser( idLexer &src ) { 260 idToken token; 261 262 if ( !src.ExpectTokenString( "{" ) ) { 263 return false; 264 } 265 266 // parse the file 267 while ( 1 ) { 268 if ( !src.ReadToken( &token ) ) { 269 break; 270 } 271 272 if ( token == "}" ) { 273 break; 274 } 275 276 if ( token == "bboxes" ) { 277 if ( !ParseBBoxes( src ) ) { return false; } 278 } 279 else if ( token == "usePatches" ) { 280 if ( !ParseBool( src, usePatches ) ) { return false; } 281 } 282 else if ( token == "writeBrushMap" ) { 283 if ( !ParseBool( src, writeBrushMap ) ) { return false; } 284 } 285 else if ( token == "playerFlood" ) { 286 if ( !ParseBool( src, playerFlood ) ) { return false; } 287 } 288 else if ( token == "allowSwimReachabilities" ) { 289 if ( !ParseBool( src, allowSwimReachabilities ) ) { return false; } 290 } 291 else if ( token == "allowFlyReachabilities" ) { 292 if ( !ParseBool( src, allowFlyReachabilities ) ) { return false; } 293 } 294 else if ( token == "fileExtension" ) { 295 src.ExpectTokenString( "=" ); 296 src.ExpectTokenType( TT_STRING, 0, &token ); 297 fileExtension = token; 298 } 299 else if ( token == "gravity" ) { 300 ParseVector( src, gravity ); 301 gravityDir = gravity; 302 gravityValue = gravityDir.Normalize(); 303 invGravityDir = -gravityDir; 304 } 305 else if ( token == "maxStepHeight" ) { 306 if ( !ParseFloat( src, maxStepHeight ) ) { return false; } 307 } 308 else if ( token == "maxBarrierHeight" ) { 309 if ( !ParseFloat( src, maxBarrierHeight ) ) { return false; } 310 } 311 else if ( token == "maxWaterJumpHeight" ) { 312 if ( !ParseFloat( src, maxWaterJumpHeight ) ) { return false; } 313 } 314 else if ( token == "maxFallHeight" ) { 315 if ( !ParseFloat( src, maxFallHeight ) ) { return false; } 316 } 317 else if ( token == "minFloorCos" ) { 318 if ( !ParseFloat( src, minFloorCos ) ) { return false; } 319 } 320 else if ( token == "tt_barrierJump" ) { 321 if ( !ParseInt( src, tt_barrierJump ) ) { return false; } 322 } 323 else if ( token == "tt_startCrouching" ) { 324 if ( !ParseInt( src, tt_startCrouching ) ) { return false; } 325 } 326 else if ( token == "tt_waterJump" ) { 327 if ( !ParseInt( src, tt_waterJump ) ) { return false; } 328 } 329 else if ( token == "tt_startWalkOffLedge" ) { 330 if ( !ParseInt( src, tt_startWalkOffLedge ) ) { return false; } 331 } 332 else { 333 src.Error( "invalid token '%s'", token.c_str() ); 334 } 335 } 336 337 if ( numBoundingBoxes <= 0 ) { 338 src.Error( "no valid bounding box" ); 339 } 340 341 return true; 342 } 343 344 /* 345 ============ 346 idAASSettings::FromFile 347 ============ 348 */ 349 bool idAASSettings::FromFile( const idStr &fileName ) { 350 idLexer src( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT ); 351 idStr name; 352 353 name = fileName; 354 355 common->Printf( "loading %s\n", name.c_str() ); 356 357 if ( !src.LoadFile( name ) ) { 358 common->Error( "WARNING: couldn't load %s\n", name.c_str() ); 359 return false; 360 } 361 362 if ( !src.ExpectTokenString( "settings" ) ) { 363 common->Error( "%s is not a settings file", name.c_str() ); 364 return false; 365 } 366 367 if ( !FromParser( src ) ) { 368 common->Error( "failed to parse %s", name.c_str() ); 369 return false; 370 } 371 372 return true; 373 } 374 375 /* 376 ============ 377 idAASSettings::FromDict 378 ============ 379 */ 380 bool idAASSettings::FromDict( const char *name, const idDict *dict ) { 381 idBounds bounds; 382 383 if ( !dict->GetVector( "mins", "0 0 0", bounds[ 0 ] ) ) { 384 common->Error( "Missing 'mins' in entityDef '%s'", name ); 385 } 386 if ( !dict->GetVector( "maxs", "0 0 0", bounds[ 1 ] ) ) { 387 common->Error( "Missing 'maxs' in entityDef '%s'", name ); 388 } 389 390 numBoundingBoxes = 1; 391 boundingBoxes[0] = bounds; 392 393 if ( !dict->GetBool( "usePatches", "0", usePatches ) ) { 394 common->Error( "Missing 'usePatches' in entityDef '%s'", name ); 395 } 396 397 if ( !dict->GetBool( "writeBrushMap", "0", writeBrushMap ) ) { 398 common->Error( "Missing 'writeBrushMap' in entityDef '%s'", name ); 399 } 400 401 if ( !dict->GetBool( "playerFlood", "0", playerFlood ) ) { 402 common->Error( "Missing 'playerFlood' in entityDef '%s'", name ); 403 } 404 405 if ( !dict->GetBool( "allowSwimReachabilities", "0", allowSwimReachabilities ) ) { 406 common->Error( "Missing 'allowSwimReachabilities' in entityDef '%s'", name ); 407 } 408 409 if ( !dict->GetBool( "allowFlyReachabilities", "0", allowFlyReachabilities ) ) { 410 common->Error( "Missing 'allowFlyReachabilities' in entityDef '%s'", name ); 411 } 412 413 if ( !dict->GetString( "fileExtension", "", fileExtension ) ) { 414 common->Error( "Missing 'fileExtension' in entityDef '%s'", name ); 415 } 416 417 if ( !dict->GetVector( "gravity", "0 0 -1066", gravity ) ) { 418 common->Error( "Missing 'gravity' in entityDef '%s'", name ); 419 } 420 gravityDir = gravity; 421 gravityValue = gravityDir.Normalize(); 422 invGravityDir = -gravityDir; 423 424 if ( !dict->GetFloat( "maxStepHeight", "0", maxStepHeight ) ) { 425 common->Error( "Missing 'maxStepHeight' in entityDef '%s'", name ); 426 } 427 428 if ( !dict->GetFloat( "maxBarrierHeight", "0", maxBarrierHeight ) ) { 429 common->Error( "Missing 'maxBarrierHeight' in entityDef '%s'", name ); 430 } 431 432 if ( !dict->GetFloat( "maxWaterJumpHeight", "0", maxWaterJumpHeight ) ) { 433 common->Error( "Missing 'maxWaterJumpHeight' in entityDef '%s'", name ); 434 } 435 436 if ( !dict->GetFloat( "maxFallHeight", "0", maxFallHeight ) ) { 437 common->Error( "Missing 'maxFallHeight' in entityDef '%s'", name ); 438 } 439 440 if ( !dict->GetFloat( "minFloorCos", "0", minFloorCos ) ) { 441 common->Error( "Missing 'minFloorCos' in entityDef '%s'", name ); 442 } 443 444 if ( !dict->GetInt( "tt_barrierJump", "0", tt_barrierJump ) ) { 445 common->Error( "Missing 'tt_barrierJump' in entityDef '%s'", name ); 446 } 447 448 if ( !dict->GetInt( "tt_startCrouching", "0", tt_startCrouching ) ) { 449 common->Error( "Missing 'tt_startCrouching' in entityDef '%s'", name ); 450 } 451 452 if ( !dict->GetInt( "tt_waterJump", "0", tt_waterJump ) ) { 453 common->Error( "Missing 'tt_waterJump' in entityDef '%s'", name ); 454 } 455 456 if ( !dict->GetInt( "tt_startWalkOffLedge", "0", tt_startWalkOffLedge ) ) { 457 common->Error( "Missing 'tt_startWalkOffLedge' in entityDef '%s'", name ); 458 } 459 460 return true; 461 } 462 463 464 /* 465 ============ 466 idAASSettings::WriteToFile 467 ============ 468 */ 469 bool idAASSettings::WriteToFile( idFile *fp ) const { 470 int i; 471 472 fp->WriteFloatString( "{\n" ); 473 fp->WriteFloatString( "\tbboxes\n\t{\n" ); 474 for ( i = 0; i < numBoundingBoxes; i++ ) { 475 fp->WriteFloatString( "\t\t(%f %f %f)-(%f %f %f)\n", boundingBoxes[i][0].x, boundingBoxes[i][0].y, 476 boundingBoxes[i][0].z, boundingBoxes[i][1].x, boundingBoxes[i][1].y, boundingBoxes[i][1].z ); 477 } 478 fp->WriteFloatString( "\t}\n" ); 479 fp->WriteFloatString( "\tusePatches = %d\n", usePatches ); 480 fp->WriteFloatString( "\twriteBrushMap = %d\n", writeBrushMap ); 481 fp->WriteFloatString( "\tplayerFlood = %d\n", playerFlood ); 482 fp->WriteFloatString( "\tallowSwimReachabilities = %d\n", allowSwimReachabilities ); 483 fp->WriteFloatString( "\tallowFlyReachabilities = %d\n", allowFlyReachabilities ); 484 fp->WriteFloatString( "\tfileExtension = \"%s\"\n", fileExtension.c_str() ); 485 fp->WriteFloatString( "\tgravity = (%f %f %f)\n", gravity.x, gravity.y, gravity.z ); 486 fp->WriteFloatString( "\tmaxStepHeight = %f\n", maxStepHeight ); 487 fp->WriteFloatString( "\tmaxBarrierHeight = %f\n", maxBarrierHeight ); 488 fp->WriteFloatString( "\tmaxWaterJumpHeight = %f\n", maxWaterJumpHeight ); 489 fp->WriteFloatString( "\tmaxFallHeight = %f\n", maxFallHeight ); 490 fp->WriteFloatString( "\tminFloorCos = %f\n", minFloorCos ); 491 fp->WriteFloatString( "\ttt_barrierJump = %d\n", tt_barrierJump ); 492 fp->WriteFloatString( "\ttt_startCrouching = %d\n", tt_startCrouching ); 493 fp->WriteFloatString( "\ttt_waterJump = %d\n", tt_waterJump ); 494 fp->WriteFloatString( "\ttt_startWalkOffLedge = %d\n", tt_startWalkOffLedge ); 495 fp->WriteFloatString( "}\n" ); 496 return true; 497 } 498 499 /* 500 ============ 501 idAASSettings::ValidForBounds 502 ============ 503 */ 504 bool idAASSettings::ValidForBounds( const idBounds &bounds ) const { 505 int i; 506 507 for ( i = 0; i < 3; i++ ) { 508 if ( bounds[0][i] < boundingBoxes[0][0][i] ) { 509 return false; 510 } 511 if ( bounds[1][i] > boundingBoxes[0][1][i] ) { 512 return false; 513 } 514 } 515 return true; 516 } 517 518 /* 519 ============ 520 idAASSettings::ValidEntity 521 ============ 522 */ 523 bool idAASSettings::ValidEntity( const char *classname ) const { 524 idStr use_aas; 525 idVec3 size; 526 idBounds bounds; 527 528 if ( playerFlood ) { 529 if ( !strcmp( classname, "info_player_start" ) || !strcmp( classname , "info_player_deathmatch" ) || !strcmp( classname, "func_teleporter" ) ) { 530 return true; 531 } 532 } 533 534 const idDeclEntityDef *decl = static_cast<const idDeclEntityDef *>( declManager->FindType( DECL_ENTITYDEF, classname, false ) ); 535 if ( ( decl != NULL ) && decl->dict.GetString( "use_aas", NULL, use_aas ) && !fileExtension.Icmp( use_aas ) ) { 536 if ( decl->dict.GetVector( "mins", NULL, bounds[0] ) ) { 537 decl->dict.GetVector( "maxs", NULL, bounds[1] ); 538 } else if ( decl->dict.GetVector( "size", NULL, size ) ) { 539 bounds[ 0 ].Set( size.x * -0.5f, size.y * -0.5f, 0.0f ); 540 bounds[ 1 ].Set( size.x * 0.5f, size.y * 0.5f, size.z ); 541 } 542 543 if ( !ValidForBounds( bounds ) ) { 544 common->Error( "%s cannot use %s\n", classname, fileExtension.c_str() ); 545 } 546 547 return true; 548 } 549 550 return false; 551 } 552 553 554 /* 555 =============================================================================== 556 557 idAASFileLocal 558 559 =============================================================================== 560 */ 561 562 #define AAS_LIST_GRANULARITY 1024 563 #define AAS_INDEX_GRANULARITY 4096 564 #define AAS_PLANE_GRANULARITY 4096 565 #define AAS_VERTEX_GRANULARITY 4096 566 #define AAS_EDGE_GRANULARITY 4096 567 568 /* 569 ================ 570 idAASFileLocal::idAASFileLocal 571 ================ 572 */ 573 idAASFileLocal::idAASFileLocal() { 574 planeList.SetGranularity( AAS_PLANE_GRANULARITY ); 575 vertices.SetGranularity( AAS_VERTEX_GRANULARITY ); 576 edges.SetGranularity( AAS_EDGE_GRANULARITY ); 577 edgeIndex.SetGranularity( AAS_INDEX_GRANULARITY ); 578 faces.SetGranularity( AAS_LIST_GRANULARITY ); 579 faceIndex.SetGranularity( AAS_INDEX_GRANULARITY ); 580 areas.SetGranularity( AAS_LIST_GRANULARITY ); 581 nodes.SetGranularity( AAS_LIST_GRANULARITY ); 582 portals.SetGranularity( AAS_LIST_GRANULARITY ); 583 portalIndex.SetGranularity( AAS_INDEX_GRANULARITY ); 584 clusters.SetGranularity( AAS_LIST_GRANULARITY ); 585 } 586 587 /* 588 ================ 589 idAASFileLocal::~idAASFileLocal 590 ================ 591 */ 592 idAASFileLocal::~idAASFileLocal() { 593 int i; 594 idReachability *reach, *next; 595 596 for ( i = 0; i < areas.Num(); i++ ) { 597 for ( reach = areas[i].reach; reach; reach = next ) { 598 next = reach->next; 599 delete reach; 600 } 601 } 602 } 603 604 /* 605 ================ 606 idAASFileLocal::Clear 607 ================ 608 */ 609 void idAASFileLocal::Clear() { 610 planeList.Clear(); 611 vertices.Clear(); 612 edges.Clear(); 613 edgeIndex.Clear(); 614 faces.Clear(); 615 faceIndex.Clear(); 616 areas.Clear(); 617 nodes.Clear(); 618 portals.Clear(); 619 portalIndex.Clear(); 620 clusters.Clear(); 621 } 622 623 /* 624 ================ 625 idAASFileLocal::Write 626 ================ 627 */ 628 bool idAASFileLocal::Write( const idStr &fileName, unsigned int mapFileCRC ) { 629 int i, num; 630 idFile *aasFile; 631 idReachability *reach; 632 633 common->Printf( "[Write AAS]\n" ); 634 common->Printf( "writing %s\n", fileName.c_str() ); 635 636 name = fileName; 637 crc = mapFileCRC; 638 639 aasFile = fileSystem->OpenFileWrite( fileName, "fs_basepath" ); 640 if ( !aasFile ) { 641 common->Error( "Error opening %s", fileName.c_str() ); 642 return false; 643 } 644 645 aasFile->WriteFloatString( "%s \"%s\"\n\n", AAS_FILEID, AAS_FILEVERSION ); 646 aasFile->WriteFloatString( "%u\n\n", mapFileCRC ); 647 648 // write out the settings 649 aasFile->WriteFloatString( "settings\n" ); 650 settings.WriteToFile( aasFile ); 651 652 // write out planes 653 aasFile->WriteFloatString( "planes %d {\n", planeList.Num() ); 654 for ( i = 0; i < planeList.Num(); i++ ) { 655 aasFile->WriteFloatString( "\t%d ( %f %f %f %f )\n", i, 656 planeList[i].Normal().x, planeList[i].Normal().y, planeList[i].Normal().z, planeList[i].Dist() ); 657 } 658 aasFile->WriteFloatString( "}\n" ); 659 660 // write out vertices 661 aasFile->WriteFloatString( "vertices %d {\n", vertices.Num() ); 662 for ( i = 0; i < vertices.Num(); i++ ) { 663 aasFile->WriteFloatString( "\t%d ( %f %f %f )\n", i, vertices[i].x, vertices[i].y, vertices[i].z ); 664 } 665 aasFile->WriteFloatString( "}\n" ); 666 667 // write out edges 668 aasFile->WriteFloatString( "edges %d {\n", edges.Num() ); 669 for ( i = 0; i < edges.Num(); i++ ) { 670 aasFile->WriteFloatString( "\t%d ( %d %d )\n", i, edges[i].vertexNum[0], edges[i].vertexNum[1] ); 671 } 672 aasFile->WriteFloatString( "}\n" ); 673 674 // write out edgeIndex 675 aasFile->WriteFloatString( "edgeIndex %d {\n", edgeIndex.Num() ); 676 for ( i = 0; i < edgeIndex.Num(); i++ ) { 677 aasFile->WriteFloatString( "\t%d ( %d )\n", i, edgeIndex[i] ); 678 } 679 aasFile->WriteFloatString( "}\n" ); 680 681 // write out faces 682 aasFile->WriteFloatString( "faces %d {\n", faces.Num() ); 683 for ( i = 0; i < faces.Num(); i++ ) { 684 aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d %d )\n", i, faces[i].planeNum, faces[i].flags, 685 faces[i].areas[0], faces[i].areas[1], faces[i].firstEdge, faces[i].numEdges ); 686 } 687 aasFile->WriteFloatString( "}\n" ); 688 689 // write out faceIndex 690 aasFile->WriteFloatString( "faceIndex %d {\n", faceIndex.Num() ); 691 for ( i = 0; i < faceIndex.Num(); i++ ) { 692 aasFile->WriteFloatString( "\t%d ( %d )\n", i, faceIndex[i] ); 693 } 694 aasFile->WriteFloatString( "}\n" ); 695 696 // write out areas 697 aasFile->WriteFloatString( "areas %d {\n", areas.Num() ); 698 for ( i = 0; i < areas.Num(); i++ ) { 699 for ( num = 0, reach = areas[i].reach; reach; reach = reach->next ) { 700 num++; 701 } 702 aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d %d ) %d {\n", i, areas[i].flags, areas[i].contents, 703 areas[i].firstFace, areas[i].numFaces, areas[i].cluster, areas[i].clusterAreaNum, num ); 704 for ( reach = areas[i].reach; reach; reach = reach->next ) { 705 Reachability_Write( aasFile, reach ); 706 switch( reach->travelType ) { 707 case TFL_SPECIAL: 708 Reachability_Special_Write( aasFile, static_cast<idReachability_Special *>(reach) ); 709 break; 710 } 711 aasFile->WriteFloatString( "\n" ); 712 } 713 aasFile->WriteFloatString( "\t}\n" ); 714 } 715 aasFile->WriteFloatString( "}\n" ); 716 717 // write out nodes 718 aasFile->WriteFloatString( "nodes %d {\n", nodes.Num() ); 719 for ( i = 0; i < nodes.Num(); i++ ) { 720 aasFile->WriteFloatString( "\t%d ( %d %d %d )\n", i, nodes[i].planeNum, nodes[i].children[0], nodes[i].children[1] ); 721 } 722 aasFile->WriteFloatString( "}\n" ); 723 724 // write out portals 725 aasFile->WriteFloatString( "portals %d {\n", portals.Num() ); 726 for ( i = 0; i < portals.Num(); i++ ) { 727 aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d )\n", i, portals[i].areaNum, portals[i].clusters[0], 728 portals[i].clusters[1], portals[i].clusterAreaNum[0], portals[i].clusterAreaNum[1] ); 729 } 730 aasFile->WriteFloatString( "}\n" ); 731 732 // write out portalIndex 733 aasFile->WriteFloatString( "portalIndex %d {\n", portalIndex.Num() ); 734 for ( i = 0; i < portalIndex.Num(); i++ ) { 735 aasFile->WriteFloatString( "\t%d ( %d )\n", i, portalIndex[i] ); 736 } 737 aasFile->WriteFloatString( "}\n" ); 738 739 // write out clusters 740 aasFile->WriteFloatString( "clusters %d {\n", clusters.Num() ); 741 for ( i = 0; i < clusters.Num(); i++ ) { 742 aasFile->WriteFloatString( "\t%d ( %d %d %d %d )\n", i, clusters[i].numAreas, clusters[i].numReachableAreas, 743 clusters[i].firstPortal, clusters[i].numPortals ); 744 } 745 aasFile->WriteFloatString( "}\n" ); 746 747 // close file 748 fileSystem->CloseFile( aasFile ); 749 750 common->Printf( "done.\n" ); 751 752 return true; 753 } 754 755 /* 756 ================ 757 idAASFileLocal::ParseIndex 758 ================ 759 */ 760 bool idAASFileLocal::ParseIndex( idLexer &src, idList<aasIndex_t> &indexes ) { 761 int numIndexes, i; 762 aasIndex_t index; 763 764 numIndexes = src.ParseInt(); 765 indexes.Resize( numIndexes ); 766 if ( !src.ExpectTokenString( "{" ) ) { 767 return false; 768 } 769 for ( i = 0; i < numIndexes; i++ ) { 770 src.ParseInt(); 771 src.ExpectTokenString( "(" ); 772 index = src.ParseInt(); 773 src.ExpectTokenString( ")" ); 774 indexes.Append( index ); 775 } 776 if ( !src.ExpectTokenString( "}" ) ) { 777 return false; 778 } 779 return true; 780 } 781 782 /* 783 ================ 784 idAASFileLocal::ParsePlanes 785 ================ 786 */ 787 bool idAASFileLocal::ParsePlanes( idLexer &src ) { 788 int numPlanes, i; 789 idPlane plane; 790 idVec4 vec; 791 792 numPlanes = src.ParseInt(); 793 planeList.Resize( numPlanes ); 794 if ( !src.ExpectTokenString( "{" ) ) { 795 return false; 796 } 797 for ( i = 0; i < numPlanes; i++ ) { 798 src.ParseInt(); 799 if ( !src.Parse1DMatrix( 4, vec.ToFloatPtr() ) ) { 800 return false; 801 } 802 plane.SetNormal( vec.ToVec3() ); 803 plane.SetDist( vec[3] ); 804 planeList.Append( plane ); 805 } 806 if ( !src.ExpectTokenString( "}" ) ) { 807 return false; 808 } 809 return true; 810 } 811 812 /* 813 ================ 814 idAASFileLocal::ParseVertices 815 ================ 816 */ 817 bool idAASFileLocal::ParseVertices( idLexer &src ) { 818 int numVertices, i; 819 idVec3 vec; 820 821 numVertices = src.ParseInt(); 822 vertices.Resize( numVertices ); 823 if ( !src.ExpectTokenString( "{" ) ) { 824 return false; 825 } 826 for ( i = 0; i < numVertices; i++ ) { 827 src.ParseInt(); 828 if ( !src.Parse1DMatrix( 3, vec.ToFloatPtr() ) ) { 829 return false; 830 } 831 vertices.Append( vec ); 832 } 833 if ( !src.ExpectTokenString( "}" ) ) { 834 return false; 835 } 836 return true; 837 } 838 839 /* 840 ================ 841 idAASFileLocal::ParseEdges 842 ================ 843 */ 844 bool idAASFileLocal::ParseEdges( idLexer &src ) { 845 int numEdges, i; 846 aasEdge_t edge; 847 848 numEdges = src.ParseInt(); 849 edges.Resize( numEdges ); 850 if ( !src.ExpectTokenString( "{" ) ) { 851 return false; 852 } 853 for ( i = 0; i < numEdges; i++ ) { 854 src.ParseInt(); 855 src.ExpectTokenString( "(" ); 856 edge.vertexNum[0] = src.ParseInt(); 857 edge.vertexNum[1] = src.ParseInt(); 858 src.ExpectTokenString( ")" ); 859 edges.Append( edge ); 860 } 861 if ( !src.ExpectTokenString( "}" ) ) { 862 return false; 863 } 864 return true; 865 } 866 867 /* 868 ================ 869 idAASFileLocal::ParseFaces 870 ================ 871 */ 872 bool idAASFileLocal::ParseFaces( idLexer &src ) { 873 int numFaces, i; 874 aasFace_t face; 875 876 numFaces = src.ParseInt(); 877 faces.Resize( numFaces ); 878 if ( !src.ExpectTokenString( "{" ) ) { 879 return false; 880 } 881 for ( i = 0; i < numFaces; i++ ) { 882 src.ParseInt(); 883 src.ExpectTokenString( "(" ); 884 face.planeNum = src.ParseInt(); 885 face.flags = src.ParseInt(); 886 face.areas[0] = src.ParseInt(); 887 face.areas[1] = src.ParseInt(); 888 face.firstEdge = src.ParseInt(); 889 face.numEdges = src.ParseInt(); 890 src.ExpectTokenString( ")" ); 891 faces.Append( face ); 892 } 893 if ( !src.ExpectTokenString( "}" ) ) { 894 return false; 895 } 896 return true; 897 } 898 899 /* 900 ================ 901 idAASFileLocal::ParseReachabilities 902 ================ 903 */ 904 bool idAASFileLocal::ParseReachabilities( idLexer &src, int areaNum ) { 905 int num, j; 906 aasArea_t *area; 907 idReachability reach, *newReach; 908 idReachability_Special *special; 909 910 area = &areas[areaNum]; 911 912 num = src.ParseInt(); 913 src.ExpectTokenString( "{" ); 914 area->reach = NULL; 915 area->rev_reach = NULL; 916 area->travelFlags = AreaContentsTravelFlags( areaNum ); 917 for ( j = 0; j < num; j++ ) { 918 Reachability_Read( src, &reach ); 919 switch( reach.travelType ) { 920 case TFL_SPECIAL: 921 newReach = special = new (TAG_AAS) idReachability_Special(); 922 Reachability_Special_Read( src, special ); 923 break; 924 default: 925 newReach = new (TAG_AAS) idReachability(); 926 break; 927 } 928 newReach->CopyBase( reach ); 929 newReach->fromAreaNum = areaNum; 930 newReach->next = area->reach; 931 area->reach = newReach; 932 } 933 src.ExpectTokenString( "}" ); 934 return true; 935 } 936 937 /* 938 ================ 939 idAASFileLocal::LinkReversedReachability 940 ================ 941 */ 942 void idAASFileLocal::LinkReversedReachability() { 943 int i; 944 idReachability *reach; 945 946 // link reversed reachabilities 947 for ( i = 0; i < areas.Num(); i++ ) { 948 for ( reach = areas[i].reach; reach; reach = reach->next ) { 949 reach->rev_next = areas[reach->toAreaNum].rev_reach; 950 areas[reach->toAreaNum].rev_reach = reach; 951 } 952 } 953 } 954 955 /* 956 ================ 957 idAASFileLocal::ParseAreas 958 ================ 959 */ 960 bool idAASFileLocal::ParseAreas( idLexer &src ) { 961 int numAreas, i; 962 aasArea_t area; 963 964 numAreas = src.ParseInt(); 965 areas.Resize( numAreas ); 966 if ( !src.ExpectTokenString( "{" ) ) { 967 return false; 968 } 969 for ( i = 0; i < numAreas; i++ ) { 970 src.ParseInt(); 971 src.ExpectTokenString( "(" ); 972 area.flags = src.ParseInt(); 973 area.contents = src.ParseInt(); 974 area.firstFace = src.ParseInt(); 975 area.numFaces = src.ParseInt(); 976 area.cluster = src.ParseInt(); 977 area.clusterAreaNum = src.ParseInt(); 978 src.ExpectTokenString( ")" ); 979 areas.Append( area ); 980 ParseReachabilities( src, i ); 981 } 982 if ( !src.ExpectTokenString( "}" ) ) { 983 return false; 984 } 985 986 LinkReversedReachability(); 987 988 return true; 989 } 990 991 /* 992 ================ 993 idAASFileLocal::ParseNodes 994 ================ 995 */ 996 bool idAASFileLocal::ParseNodes( idLexer &src ) { 997 int numNodes, i; 998 aasNode_t node; 999 1000 numNodes = src.ParseInt(); 1001 nodes.Resize( numNodes ); 1002 if ( !src.ExpectTokenString( "{" ) ) { 1003 return false; 1004 } 1005 for ( i = 0; i < numNodes; i++ ) { 1006 src.ParseInt(); 1007 src.ExpectTokenString( "(" ); 1008 node.planeNum = src.ParseInt(); 1009 node.children[0] = src.ParseInt(); 1010 node.children[1] = src.ParseInt(); 1011 src.ExpectTokenString( ")" ); 1012 nodes.Append( node ); 1013 } 1014 if ( !src.ExpectTokenString( "}" ) ) { 1015 return false; 1016 } 1017 return true; 1018 } 1019 1020 /* 1021 ================ 1022 idAASFileLocal::ParsePortals 1023 ================ 1024 */ 1025 bool idAASFileLocal::ParsePortals( idLexer &src ) { 1026 int numPortals, i; 1027 aasPortal_t portal; 1028 1029 numPortals = src.ParseInt(); 1030 portals.Resize( numPortals ); 1031 if ( !src.ExpectTokenString( "{" ) ) { 1032 return false; 1033 } 1034 for ( i = 0; i < numPortals; i++ ) { 1035 src.ParseInt(); 1036 src.ExpectTokenString( "(" ); 1037 portal.areaNum = src.ParseInt(); 1038 portal.clusters[0] = src.ParseInt(); 1039 portal.clusters[1] = src.ParseInt(); 1040 portal.clusterAreaNum[0] = src.ParseInt(); 1041 portal.clusterAreaNum[1] = src.ParseInt(); 1042 src.ExpectTokenString( ")" ); 1043 portals.Append( portal ); 1044 } 1045 if ( !src.ExpectTokenString( "}" ) ) { 1046 return false; 1047 } 1048 return true; 1049 } 1050 1051 /* 1052 ================ 1053 idAASFileLocal::ParseClusters 1054 ================ 1055 */ 1056 bool idAASFileLocal::ParseClusters( idLexer &src ) { 1057 int numClusters, i; 1058 aasCluster_t cluster; 1059 1060 numClusters = src.ParseInt(); 1061 clusters.Resize( numClusters ); 1062 if ( !src.ExpectTokenString( "{" ) ) { 1063 return false; 1064 } 1065 for ( i = 0; i < numClusters; i++ ) { 1066 src.ParseInt(); 1067 src.ExpectTokenString( "(" ); 1068 cluster.numAreas = src.ParseInt(); 1069 cluster.numReachableAreas = src.ParseInt(); 1070 cluster.firstPortal = src.ParseInt(); 1071 cluster.numPortals = src.ParseInt(); 1072 src.ExpectTokenString( ")" ); 1073 clusters.Append( cluster ); 1074 } 1075 if ( !src.ExpectTokenString( "}" ) ) { 1076 return false; 1077 } 1078 return true; 1079 } 1080 1081 /* 1082 ================ 1083 idAASFileLocal::FinishAreas 1084 ================ 1085 */ 1086 void idAASFileLocal::FinishAreas() { 1087 int i; 1088 1089 for ( i = 0; i < areas.Num(); i++ ) { 1090 areas[i].center = AreaReachableGoal( i ); 1091 areas[i].bounds = AreaBounds( i ); 1092 } 1093 } 1094 1095 /* 1096 ================ 1097 idAASFileLocal::Load 1098 ================ 1099 */ 1100 bool idAASFileLocal::Load( const idStr &fileName, unsigned int mapFileCRC ) { 1101 idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES ); 1102 idToken token; 1103 int depth; 1104 unsigned int c; 1105 1106 name = fileName; 1107 crc = mapFileCRC; 1108 1109 common->Printf( "[Load AAS]\n" ); 1110 common->Printf( "loading %s\n", name.c_str() ); 1111 1112 if ( !src.LoadFile( name ) ) { 1113 return false; 1114 } 1115 1116 if ( !src.ExpectTokenString( AAS_FILEID ) ) { 1117 common->Warning( "Not an AAS file: '%s'", name.c_str() ); 1118 return false; 1119 } 1120 1121 if ( !src.ReadToken( &token ) || token != AAS_FILEVERSION ) { 1122 common->Warning( "AAS file '%s' has version %s instead of %s", name.c_str(), token.c_str(), AAS_FILEVERSION ); 1123 return false; 1124 } 1125 1126 if ( !src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) { 1127 common->Warning( "AAS file '%s' has no map file CRC", name.c_str() ); 1128 return false; 1129 } 1130 1131 c = token.GetUnsignedLongValue(); 1132 if ( mapFileCRC && c != mapFileCRC ) { 1133 common->Warning( "AAS file '%s' is out of date", name.c_str() ); 1134 return false; 1135 } 1136 1137 // clear the file in memory 1138 Clear(); 1139 1140 // parse the file 1141 while ( 1 ) { 1142 if ( !src.ReadToken( &token ) ) { 1143 break; 1144 } 1145 1146 if ( token == "settings" ) { 1147 if ( !settings.FromParser( src ) ) { return false; } 1148 } 1149 else if ( token == "planes" ) { 1150 if ( !ParsePlanes( src ) ) { return false; } 1151 } 1152 else if ( token == "vertices" ) { 1153 if ( !ParseVertices( src ) ) { return false; } 1154 } 1155 else if ( token == "edges" ) { 1156 if ( !ParseEdges( src ) ) { return false; } 1157 } 1158 else if ( token == "edgeIndex" ) { 1159 if ( !ParseIndex( src, edgeIndex ) ) { return false; } 1160 } 1161 else if ( token == "faces" ) { 1162 if ( !ParseFaces( src ) ) { return false; } 1163 } 1164 else if ( token == "faceIndex" ) { 1165 if ( !ParseIndex( src, faceIndex ) ) { return false; } 1166 } 1167 else if ( token == "areas" ) { 1168 if ( !ParseAreas( src ) ) { return false; } 1169 } 1170 else if ( token == "nodes" ) { 1171 if ( !ParseNodes( src ) ) { return false; } 1172 } 1173 else if ( token == "portals" ) { 1174 if ( !ParsePortals( src ) ) { return false; } 1175 } 1176 else if ( token == "portalIndex" ) { 1177 if ( !ParseIndex( src, portalIndex ) ) { return false; } 1178 } 1179 else if ( token == "clusters" ) { 1180 if ( !ParseClusters( src ) ) { return false; } 1181 } 1182 else { 1183 src.Error( "idAASFileLocal::Load: bad token \"%s\"", token.c_str() ); 1184 return false; 1185 } 1186 } 1187 1188 FinishAreas(); 1189 1190 depth = MaxTreeDepth(); 1191 if ( depth > MAX_AAS_TREE_DEPTH ) { 1192 src.Error( "idAASFileLocal::Load: tree depth = %d", depth ); 1193 } 1194 1195 common->UpdateLevelLoadPacifier(); 1196 1197 common->Printf( "done.\n" ); 1198 1199 return true; 1200 } 1201 1202 /* 1203 ================ 1204 idAASFileLocal::MemorySize 1205 ================ 1206 */ 1207 int idAASFileLocal::MemorySize() const { 1208 int size; 1209 1210 size = planeList.Size(); 1211 size += vertices.Size(); 1212 size += edges.Size(); 1213 size += edgeIndex.Size(); 1214 size += faces.Size(); 1215 size += faceIndex.Size(); 1216 size += areas.Size(); 1217 size += nodes.Size(); 1218 size += portals.Size(); 1219 size += portalIndex.Size(); 1220 size += clusters.Size(); 1221 size += sizeof( idReachability_Walk ) * NumReachabilities(); 1222 1223 return size; 1224 } 1225 1226 /* 1227 ================ 1228 idAASFileLocal::PrintInfo 1229 ================ 1230 */ 1231 void idAASFileLocal::PrintInfo() const { 1232 common->Printf( "%6d KB file size\n", MemorySize() >> 10 ); 1233 common->Printf( "%6d areas\n", areas.Num() ); 1234 common->Printf( "%6d max tree depth\n", MaxTreeDepth() ); 1235 ReportRoutingEfficiency(); 1236 } 1237 1238 /* 1239 ================ 1240 idAASFileLocal::NumReachabilities 1241 ================ 1242 */ 1243 int idAASFileLocal::NumReachabilities() const { 1244 int i, num; 1245 idReachability *reach; 1246 1247 num = 0; 1248 for ( i = 0; i < areas.Num(); i++ ) { 1249 for ( reach = areas[i].reach; reach; reach = reach->next ) { 1250 num++; 1251 } 1252 } 1253 return num; 1254 } 1255 1256 /* 1257 ================ 1258 idAASFileLocal::ReportRoutingEfficiency 1259 ================ 1260 */ 1261 void idAASFileLocal::ReportRoutingEfficiency() const { 1262 int numReachableAreas, total, i, n; 1263 1264 numReachableAreas = 0; 1265 total = 0; 1266 for ( i = 0; i < clusters.Num(); i++ ) { 1267 n = clusters[i].numReachableAreas; 1268 numReachableAreas += n; 1269 total += n * n; 1270 } 1271 total += numReachableAreas * portals.Num(); 1272 1273 common->Printf( "%6d reachable areas\n", numReachableAreas ); 1274 common->Printf( "%6d reachabilities\n", NumReachabilities() ); 1275 common->Printf( "%6d KB max routing cache\n", ( total * 3 ) >> 10 ); 1276 } 1277 1278 /* 1279 ================ 1280 idAASFileLocal::DeleteReachabilities 1281 ================ 1282 */ 1283 void idAASFileLocal::DeleteReachabilities() { 1284 int i; 1285 idReachability *reach, *nextReach; 1286 1287 for ( i = 0; i < areas.Num(); i++ ) { 1288 for ( reach = areas[i].reach; reach; reach = nextReach ) { 1289 nextReach = reach->next; 1290 delete reach; 1291 } 1292 areas[i].reach = NULL; 1293 areas[i].rev_reach = NULL; 1294 } 1295 } 1296 1297 /* 1298 ================ 1299 idAASFileLocal::DeleteClusters 1300 ================ 1301 */ 1302 void idAASFileLocal::DeleteClusters() { 1303 aasPortal_t portal; 1304 aasCluster_t cluster; 1305 1306 portals.Clear(); 1307 portalIndex.Clear(); 1308 clusters.Clear(); 1309 1310 // first portal is a dummy 1311 memset( &portal, 0, sizeof( portal ) ); 1312 portals.Append( portal ); 1313 1314 // first cluster is a dummy 1315 memset( &cluster, 0, sizeof( cluster ) ); 1316 clusters.Append( cluster ); 1317 }