2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 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.
14 Doom 3 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.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
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.
26 ===========================================================================
29 #include "../../../idlib/precompiled.h"
33 #include "AASFile_local.h"
37 ===============================================================================
41 ===============================================================================
49 bool Reachability_Write( idFile *fp, idReachability *reach ) {
50 fp->WriteFloatString( "\t\t%d %d (%f %f %f) (%f %f %f) %d %d",
51 (int) reach->travelType, (int) reach->toAreaNum, reach->start.x, reach->start.y, reach->start.z,
52 reach->end.x, reach->end.y, reach->end.z, reach->edgeNum, (int) reach->travelTime );
61 bool Reachability_Read( idLexer &src, idReachability *reach ) {
62 reach->travelType = src.ParseInt();
63 reach->toAreaNum = src.ParseInt();
64 src.Parse1DMatrix( 3, reach->start.ToFloatPtr() );
65 src.Parse1DMatrix( 3, reach->end.ToFloatPtr() );
66 reach->edgeNum = src.ParseInt();
67 reach->travelTime = src.ParseInt();
73 idReachability::CopyBase
76 void idReachability::CopyBase( idReachability &reach ) {
77 travelType = reach.travelType;
78 toAreaNum = reach.toAreaNum;
81 edgeNum = reach.edgeNum;
82 travelTime = reach.travelTime;
87 ===============================================================================
89 idReachability_Special
91 ===============================================================================
96 Reachability_Special_Write
99 bool Reachability_Special_Write( idFile *fp, idReachability_Special *reach ) {
101 const idKeyValue *keyValue;
103 fp->WriteFloatString( "\n\t\t{\n" );
104 for ( i = 0; i < reach->dict.GetNumKeyVals(); i++ ) {
105 keyValue = reach->dict.GetKeyVal( i );
106 fp->WriteFloatString( "\t\t\t\"%s\" \"%s\"\n", keyValue->GetKey().c_str(), keyValue->GetValue().c_str() );
108 fp->WriteFloatString( "\t\t}\n" );
115 Reachability_Special_Read
118 bool Reachability_Special_Read( idLexer &src, idReachability_Special *reach ) {
121 src.ExpectTokenString( "{" );
122 while( src.ReadToken( &key ) ) {
126 src.ExpectTokenType( TT_STRING, 0, &value );
127 reach->dict.Set( key, value );
133 ===============================================================================
137 ===============================================================================
142 idAASSettings::idAASSettings
145 idAASSettings::idAASSettings( void ) {
146 numBoundingBoxes = 1;
147 boundingBoxes[0] = idBounds( idVec3( -16, -16, 0 ), idVec3( 16, 16, 72 ) );
149 writeBrushMap = false;
152 allowSwimReachabilities = false;
153 allowFlyReachabilities = false;
154 fileExtension = "aas48";
156 gravity = idVec3( 0, 0, -1066 );
157 gravityDir = gravity;
158 gravityValue = gravityDir.Normalize();
159 invGravityDir = -gravityDir;
160 maxStepHeight = 14.0f;
161 maxBarrierHeight = 32.0f;
162 maxWaterJumpHeight = 20.0f;
163 maxFallHeight = 64.0f;
165 // fixed travel times
166 tt_barrierJump = 100;
167 tt_startCrouching = 100;
169 tt_startWalkOffLedge = 100;
174 idAASSettings::ParseBool
177 bool idAASSettings::ParseBool( idLexer &src, bool &b ) {
178 if ( !src.ExpectTokenString( "=" ) ) {
187 idAASSettings::ParseInt
190 bool idAASSettings::ParseInt( idLexer &src, int &i ) {
191 if ( !src.ExpectTokenString( "=" ) ) {
200 idAASSettings::ParseFloat
203 bool idAASSettings::ParseFloat( idLexer &src, float &f ) {
204 if ( !src.ExpectTokenString( "=" ) ) {
207 f = src.ParseFloat();
213 idAASSettings::ParseVector
216 bool idAASSettings::ParseVector( idLexer &src, idVec3 &vec ) {
217 if ( !src.ExpectTokenString( "=" ) ) {
220 return ( src.Parse1DMatrix( 3, vec.ToFloatPtr() ) != 0 );
225 idAASSettings::ParseBBoxes
228 bool idAASSettings::ParseBBoxes( idLexer &src ) {
232 numBoundingBoxes = 0;
234 if ( !src.ExpectTokenString( "{" ) ) {
237 while( src.ReadToken( &token ) ) {
238 if ( token == "}" ) {
241 src.UnreadToken( &token );
242 src.Parse1DMatrix( 3, bounds[0].ToFloatPtr() );
243 if ( !src.ExpectTokenString( "-" ) ) {
246 src.Parse1DMatrix( 3, bounds[1].ToFloatPtr() );
248 boundingBoxes[numBoundingBoxes++] = bounds;
255 idAASSettings::FromParser
258 bool idAASSettings::FromParser( idLexer &src ) {
261 if ( !src.ExpectTokenString( "{" ) ) {
267 if ( !src.ReadToken( &token ) ) {
271 if ( token == "}" ) {
275 if ( token == "bboxes" ) {
276 if ( !ParseBBoxes( src ) ) { return false; }
278 else if ( token == "usePatches" ) {
279 if ( !ParseBool( src, usePatches ) ) { return false; }
281 else if ( token == "writeBrushMap" ) {
282 if ( !ParseBool( src, writeBrushMap ) ) { return false; }
284 else if ( token == "playerFlood" ) {
285 if ( !ParseBool( src, playerFlood ) ) { return false; }
287 else if ( token == "allowSwimReachabilities" ) {
288 if ( !ParseBool( src, allowSwimReachabilities ) ) { return false; }
290 else if ( token == "allowFlyReachabilities" ) {
291 if ( !ParseBool( src, allowFlyReachabilities ) ) { return false; }
293 else if ( token == "fileExtension" ) {
294 src.ExpectTokenString( "=" );
295 src.ExpectTokenType( TT_STRING, 0, &token );
296 fileExtension = token;
298 else if ( token == "gravity" ) {
299 ParseVector( src, gravity );
300 gravityDir = gravity;
301 gravityValue = gravityDir.Normalize();
302 invGravityDir = -gravityDir;
304 else if ( token == "maxStepHeight" ) {
305 if ( !ParseFloat( src, maxStepHeight ) ) { return false; }
307 else if ( token == "maxBarrierHeight" ) {
308 if ( !ParseFloat( src, maxBarrierHeight ) ) { return false; }
310 else if ( token == "maxWaterJumpHeight" ) {
311 if ( !ParseFloat( src, maxWaterJumpHeight ) ) { return false; }
313 else if ( token == "maxFallHeight" ) {
314 if ( !ParseFloat( src, maxFallHeight ) ) { return false; }
316 else if ( token == "minFloorCos" ) {
317 if ( !ParseFloat( src, minFloorCos ) ) { return false; }
319 else if ( token == "tt_barrierJump" ) {
320 if ( !ParseInt( src, tt_barrierJump ) ) { return false; }
322 else if ( token == "tt_startCrouching" ) {
323 if ( !ParseInt( src, tt_startCrouching ) ) { return false; }
325 else if ( token == "tt_waterJump" ) {
326 if ( !ParseInt( src, tt_waterJump ) ) { return false; }
328 else if ( token == "tt_startWalkOffLedge" ) {
329 if ( !ParseInt( src, tt_startWalkOffLedge ) ) { return false; }
332 src.Error( "invalid token '%s'", token.c_str() );
336 if ( numBoundingBoxes <= 0 ) {
337 src.Error( "no valid bounding box" );
345 idAASSettings::FromFile
348 bool idAASSettings::FromFile( const idStr &fileName ) {
349 idLexer src( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
354 common->Printf( "loading %s\n", name.c_str() );
356 if ( !src.LoadFile( name ) ) {
357 common->Error( "WARNING: couldn't load %s\n", name.c_str() );
361 if ( !src.ExpectTokenString( "settings" ) ) {
362 common->Error( "%s is not a settings file", name.c_str() );
366 if ( !FromParser( src ) ) {
367 common->Error( "failed to parse %s", name.c_str() );
376 idAASSettings::FromDict
379 bool idAASSettings::FromDict( const char *name, const idDict *dict ) {
382 if ( !dict->GetVector( "mins", "0 0 0", bounds[ 0 ] ) ) {
383 common->Error( "Missing 'mins' in entityDef '%s'", name );
385 if ( !dict->GetVector( "maxs", "0 0 0", bounds[ 1 ] ) ) {
386 common->Error( "Missing 'maxs' in entityDef '%s'", name );
389 numBoundingBoxes = 1;
390 boundingBoxes[0] = bounds;
392 if ( !dict->GetBool( "usePatches", "0", usePatches ) ) {
393 common->Error( "Missing 'usePatches' in entityDef '%s'", name );
396 if ( !dict->GetBool( "writeBrushMap", "0", writeBrushMap ) ) {
397 common->Error( "Missing 'writeBrushMap' in entityDef '%s'", name );
400 if ( !dict->GetBool( "playerFlood", "0", playerFlood ) ) {
401 common->Error( "Missing 'playerFlood' in entityDef '%s'", name );
404 if ( !dict->GetBool( "allowSwimReachabilities", "0", allowSwimReachabilities ) ) {
405 common->Error( "Missing 'allowSwimReachabilities' in entityDef '%s'", name );
408 if ( !dict->GetBool( "allowFlyReachabilities", "0", allowFlyReachabilities ) ) {
409 common->Error( "Missing 'allowFlyReachabilities' in entityDef '%s'", name );
412 if ( !dict->GetString( "fileExtension", "", fileExtension ) ) {
413 common->Error( "Missing 'fileExtension' in entityDef '%s'", name );
416 if ( !dict->GetVector( "gravity", "0 0 -1066", gravity ) ) {
417 common->Error( "Missing 'gravity' in entityDef '%s'", name );
419 gravityDir = gravity;
420 gravityValue = gravityDir.Normalize();
421 invGravityDir = -gravityDir;
423 if ( !dict->GetFloat( "maxStepHeight", "0", maxStepHeight ) ) {
424 common->Error( "Missing 'maxStepHeight' in entityDef '%s'", name );
427 if ( !dict->GetFloat( "maxBarrierHeight", "0", maxBarrierHeight ) ) {
428 common->Error( "Missing 'maxBarrierHeight' in entityDef '%s'", name );
431 if ( !dict->GetFloat( "maxWaterJumpHeight", "0", maxWaterJumpHeight ) ) {
432 common->Error( "Missing 'maxWaterJumpHeight' in entityDef '%s'", name );
435 if ( !dict->GetFloat( "maxFallHeight", "0", maxFallHeight ) ) {
436 common->Error( "Missing 'maxFallHeight' in entityDef '%s'", name );
439 if ( !dict->GetFloat( "minFloorCos", "0", minFloorCos ) ) {
440 common->Error( "Missing 'minFloorCos' in entityDef '%s'", name );
443 if ( !dict->GetInt( "tt_barrierJump", "0", tt_barrierJump ) ) {
444 common->Error( "Missing 'tt_barrierJump' in entityDef '%s'", name );
447 if ( !dict->GetInt( "tt_startCrouching", "0", tt_startCrouching ) ) {
448 common->Error( "Missing 'tt_startCrouching' in entityDef '%s'", name );
451 if ( !dict->GetInt( "tt_waterJump", "0", tt_waterJump ) ) {
452 common->Error( "Missing 'tt_waterJump' in entityDef '%s'", name );
455 if ( !dict->GetInt( "tt_startWalkOffLedge", "0", tt_startWalkOffLedge ) ) {
456 common->Error( "Missing 'tt_startWalkOffLedge' in entityDef '%s'", name );
465 idAASSettings::WriteToFile
468 bool idAASSettings::WriteToFile( idFile *fp ) const {
471 fp->WriteFloatString( "{\n" );
472 fp->WriteFloatString( "\tbboxes\n\t{\n" );
473 for ( i = 0; i < numBoundingBoxes; i++ ) {
474 fp->WriteFloatString( "\t\t(%f %f %f)-(%f %f %f)\n", boundingBoxes[i][0].x, boundingBoxes[i][0].y,
475 boundingBoxes[i][0].z, boundingBoxes[i][1].x, boundingBoxes[i][1].y, boundingBoxes[i][1].z );
477 fp->WriteFloatString( "\t}\n" );
478 fp->WriteFloatString( "\tusePatches = %d\n", usePatches );
479 fp->WriteFloatString( "\twriteBrushMap = %d\n", writeBrushMap );
480 fp->WriteFloatString( "\tplayerFlood = %d\n", playerFlood );
481 fp->WriteFloatString( "\tallowSwimReachabilities = %d\n", allowSwimReachabilities );
482 fp->WriteFloatString( "\tallowFlyReachabilities = %d\n", allowFlyReachabilities );
483 fp->WriteFloatString( "\tfileExtension = \"%s\"\n", fileExtension.c_str() );
484 fp->WriteFloatString( "\tgravity = (%f %f %f)\n", gravity.x, gravity.y, gravity.z );
485 fp->WriteFloatString( "\tmaxStepHeight = %f\n", maxStepHeight );
486 fp->WriteFloatString( "\tmaxBarrierHeight = %f\n", maxBarrierHeight );
487 fp->WriteFloatString( "\tmaxWaterJumpHeight = %f\n", maxWaterJumpHeight );
488 fp->WriteFloatString( "\tmaxFallHeight = %f\n", maxFallHeight );
489 fp->WriteFloatString( "\tminFloorCos = %f\n", minFloorCos );
490 fp->WriteFloatString( "\ttt_barrierJump = %d\n", tt_barrierJump );
491 fp->WriteFloatString( "\ttt_startCrouching = %d\n", tt_startCrouching );
492 fp->WriteFloatString( "\ttt_waterJump = %d\n", tt_waterJump );
493 fp->WriteFloatString( "\ttt_startWalkOffLedge = %d\n", tt_startWalkOffLedge );
494 fp->WriteFloatString( "}\n" );
500 idAASSettings::ValidForBounds
503 bool idAASSettings::ValidForBounds( const idBounds &bounds ) const {
506 for ( i = 0; i < 3; i++ ) {
507 if ( bounds[0][i] < boundingBoxes[0][0][i] ) {
510 if ( bounds[1][i] > boundingBoxes[0][1][i] ) {
519 idAASSettings::ValidEntity
522 bool idAASSettings::ValidEntity( const char *classname ) const {
528 if ( !strcmp( classname, "info_player_start" ) || !strcmp( classname , "info_player_deathmatch" ) || !strcmp( classname, "func_teleporter" ) ) {
533 const idDeclEntityDef *decl = static_cast<const idDeclEntityDef *>( declManager->FindType( DECL_ENTITYDEF, classname, false ) );
534 if ( decl && decl->dict.GetString( "use_aas", NULL, use_aas ) && !fileExtension.Icmp( use_aas ) ) {
535 if ( decl->dict.GetVector( "mins", NULL, bounds[0] ) ) {
536 decl->dict.GetVector( "maxs", NULL, bounds[1] );
537 } else if ( decl->dict.GetVector( "size", NULL, size ) ) {
538 bounds[ 0 ].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
539 bounds[ 1 ].Set( size.x * 0.5f, size.y * 0.5f, size.z );
542 if ( !ValidForBounds( bounds ) ) {
543 common->Error( "%s cannot use %s\n", classname, fileExtension.c_str() );
554 ===============================================================================
558 ===============================================================================
561 #define AAS_LIST_GRANULARITY 1024
562 #define AAS_INDEX_GRANULARITY 4096
563 #define AAS_PLANE_GRANULARITY 4096
564 #define AAS_VERTEX_GRANULARITY 4096
565 #define AAS_EDGE_GRANULARITY 4096
569 idAASFileLocal::idAASFileLocal
572 idAASFileLocal::idAASFileLocal( void ) {
573 planeList.SetGranularity( AAS_PLANE_GRANULARITY );
574 vertices.SetGranularity( AAS_VERTEX_GRANULARITY );
575 edges.SetGranularity( AAS_EDGE_GRANULARITY );
576 edgeIndex.SetGranularity( AAS_INDEX_GRANULARITY );
577 faces.SetGranularity( AAS_LIST_GRANULARITY );
578 faceIndex.SetGranularity( AAS_INDEX_GRANULARITY );
579 areas.SetGranularity( AAS_LIST_GRANULARITY );
580 nodes.SetGranularity( AAS_LIST_GRANULARITY );
581 portals.SetGranularity( AAS_LIST_GRANULARITY );
582 portalIndex.SetGranularity( AAS_INDEX_GRANULARITY );
583 clusters.SetGranularity( AAS_LIST_GRANULARITY );
588 idAASFileLocal::~idAASFileLocal
591 idAASFileLocal::~idAASFileLocal( void ) {
593 idReachability *reach, *next;
595 for ( i = 0; i < areas.Num(); i++ ) {
596 for ( reach = areas[i].reach; reach; reach = next ) {
605 idAASFileLocal::Clear
608 void idAASFileLocal::Clear( void ) {
624 idAASFileLocal::Write
627 bool idAASFileLocal::Write( const idStr &fileName, unsigned int mapFileCRC ) {
630 idReachability *reach;
632 common->Printf( "[Write AAS]\n" );
633 common->Printf( "writing %s\n", fileName.c_str() );
638 aasFile = fileSystem->OpenFileWrite( fileName, "fs_devpath" );
640 common->Error( "Error opening %s", fileName.c_str() );
644 aasFile->WriteFloatString( "%s \"%s\"\n\n", AAS_FILEID, AAS_FILEVERSION );
645 aasFile->WriteFloatString( "%u\n\n", mapFileCRC );
647 // write out the settings
648 aasFile->WriteFloatString( "settings\n" );
649 settings.WriteToFile( aasFile );
652 aasFile->WriteFloatString( "planes %d {\n", planeList.Num() );
653 for ( i = 0; i < planeList.Num(); i++ ) {
654 aasFile->WriteFloatString( "\t%d ( %f %f %f %f )\n", i,
655 planeList[i].Normal().x, planeList[i].Normal().y, planeList[i].Normal().z, planeList[i].Dist() );
657 aasFile->WriteFloatString( "}\n" );
659 // write out vertices
660 aasFile->WriteFloatString( "vertices %d {\n", vertices.Num() );
661 for ( i = 0; i < vertices.Num(); i++ ) {
662 aasFile->WriteFloatString( "\t%d ( %f %f %f )\n", i, vertices[i].x, vertices[i].y, vertices[i].z );
664 aasFile->WriteFloatString( "}\n" );
667 aasFile->WriteFloatString( "edges %d {\n", edges.Num() );
668 for ( i = 0; i < edges.Num(); i++ ) {
669 aasFile->WriteFloatString( "\t%d ( %d %d )\n", i, edges[i].vertexNum[0], edges[i].vertexNum[1] );
671 aasFile->WriteFloatString( "}\n" );
673 // write out edgeIndex
674 aasFile->WriteFloatString( "edgeIndex %d {\n", edgeIndex.Num() );
675 for ( i = 0; i < edgeIndex.Num(); i++ ) {
676 aasFile->WriteFloatString( "\t%d ( %d )\n", i, edgeIndex[i] );
678 aasFile->WriteFloatString( "}\n" );
681 aasFile->WriteFloatString( "faces %d {\n", faces.Num() );
682 for ( i = 0; i < faces.Num(); i++ ) {
683 aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d %d )\n", i, faces[i].planeNum, faces[i].flags,
684 faces[i].areas[0], faces[i].areas[1], faces[i].firstEdge, faces[i].numEdges );
686 aasFile->WriteFloatString( "}\n" );
688 // write out faceIndex
689 aasFile->WriteFloatString( "faceIndex %d {\n", faceIndex.Num() );
690 for ( i = 0; i < faceIndex.Num(); i++ ) {
691 aasFile->WriteFloatString( "\t%d ( %d )\n", i, faceIndex[i] );
693 aasFile->WriteFloatString( "}\n" );
696 aasFile->WriteFloatString( "areas %d {\n", areas.Num() );
697 for ( i = 0; i < areas.Num(); i++ ) {
698 for ( num = 0, reach = areas[i].reach; reach; reach = reach->next ) {
701 aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d %d ) %d {\n", i, areas[i].flags, areas[i].contents,
702 areas[i].firstFace, areas[i].numFaces, areas[i].cluster, areas[i].clusterAreaNum, num );
703 for ( reach = areas[i].reach; reach; reach = reach->next ) {
704 Reachability_Write( aasFile, reach );
705 switch( reach->travelType ) {
707 Reachability_Special_Write( aasFile, static_cast<idReachability_Special *>(reach) );
710 aasFile->WriteFloatString( "\n" );
712 aasFile->WriteFloatString( "\t}\n" );
714 aasFile->WriteFloatString( "}\n" );
717 aasFile->WriteFloatString( "nodes %d {\n", nodes.Num() );
718 for ( i = 0; i < nodes.Num(); i++ ) {
719 aasFile->WriteFloatString( "\t%d ( %d %d %d )\n", i, nodes[i].planeNum, nodes[i].children[0], nodes[i].children[1] );
721 aasFile->WriteFloatString( "}\n" );
724 aasFile->WriteFloatString( "portals %d {\n", portals.Num() );
725 for ( i = 0; i < portals.Num(); i++ ) {
726 aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d )\n", i, portals[i].areaNum, portals[i].clusters[0],
727 portals[i].clusters[1], portals[i].clusterAreaNum[0], portals[i].clusterAreaNum[1] );
729 aasFile->WriteFloatString( "}\n" );
731 // write out portalIndex
732 aasFile->WriteFloatString( "portalIndex %d {\n", portalIndex.Num() );
733 for ( i = 0; i < portalIndex.Num(); i++ ) {
734 aasFile->WriteFloatString( "\t%d ( %d )\n", i, portalIndex[i] );
736 aasFile->WriteFloatString( "}\n" );
738 // write out clusters
739 aasFile->WriteFloatString( "clusters %d {\n", clusters.Num() );
740 for ( i = 0; i < clusters.Num(); i++ ) {
741 aasFile->WriteFloatString( "\t%d ( %d %d %d %d )\n", i, clusters[i].numAreas, clusters[i].numReachableAreas,
742 clusters[i].firstPortal, clusters[i].numPortals );
744 aasFile->WriteFloatString( "}\n" );
747 fileSystem->CloseFile( aasFile );
749 common->Printf( "done.\n" );
756 idAASFileLocal::ParseIndex
759 bool idAASFileLocal::ParseIndex( idLexer &src, idList<aasIndex_t> &indexes ) {
763 numIndexes = src.ParseInt();
764 indexes.Resize( numIndexes );
765 if ( !src.ExpectTokenString( "{" ) ) {
768 for ( i = 0; i < numIndexes; i++ ) {
770 src.ExpectTokenString( "(" );
771 index = src.ParseInt();
772 src.ExpectTokenString( ")" );
773 indexes.Append( index );
775 if ( !src.ExpectTokenString( "}" ) ) {
783 idAASFileLocal::ParsePlanes
786 bool idAASFileLocal::ParsePlanes( idLexer &src ) {
791 numPlanes = src.ParseInt();
792 planeList.Resize( numPlanes );
793 if ( !src.ExpectTokenString( "{" ) ) {
796 for ( i = 0; i < numPlanes; i++ ) {
798 if ( !src.Parse1DMatrix( 4, vec.ToFloatPtr() ) ) {
801 plane.SetNormal( vec.ToVec3() );
802 plane.SetDist( vec[3] );
803 planeList.Append( plane );
805 if ( !src.ExpectTokenString( "}" ) ) {
813 idAASFileLocal::ParseVertices
816 bool idAASFileLocal::ParseVertices( idLexer &src ) {
820 numVertices = src.ParseInt();
821 vertices.Resize( numVertices );
822 if ( !src.ExpectTokenString( "{" ) ) {
825 for ( i = 0; i < numVertices; i++ ) {
827 if ( !src.Parse1DMatrix( 3, vec.ToFloatPtr() ) ) {
830 vertices.Append( vec );
832 if ( !src.ExpectTokenString( "}" ) ) {
840 idAASFileLocal::ParseEdges
843 bool idAASFileLocal::ParseEdges( idLexer &src ) {
847 numEdges = src.ParseInt();
848 edges.Resize( numEdges );
849 if ( !src.ExpectTokenString( "{" ) ) {
852 for ( i = 0; i < numEdges; i++ ) {
854 src.ExpectTokenString( "(" );
855 edge.vertexNum[0] = src.ParseInt();
856 edge.vertexNum[1] = src.ParseInt();
857 src.ExpectTokenString( ")" );
858 edges.Append( edge );
860 if ( !src.ExpectTokenString( "}" ) ) {
868 idAASFileLocal::ParseFaces
871 bool idAASFileLocal::ParseFaces( idLexer &src ) {
875 numFaces = src.ParseInt();
876 faces.Resize( numFaces );
877 if ( !src.ExpectTokenString( "{" ) ) {
880 for ( i = 0; i < numFaces; i++ ) {
882 src.ExpectTokenString( "(" );
883 face.planeNum = src.ParseInt();
884 face.flags = src.ParseInt();
885 face.areas[0] = src.ParseInt();
886 face.areas[1] = src.ParseInt();
887 face.firstEdge = src.ParseInt();
888 face.numEdges = src.ParseInt();
889 src.ExpectTokenString( ")" );
890 faces.Append( face );
892 if ( !src.ExpectTokenString( "}" ) ) {
900 idAASFileLocal::ParseReachabilities
903 bool idAASFileLocal::ParseReachabilities( idLexer &src, int areaNum ) {
906 idReachability reach, *newReach;
907 idReachability_Special *special;
909 area = &areas[areaNum];
911 num = src.ParseInt();
912 src.ExpectTokenString( "{" );
914 area->rev_reach = NULL;
915 area->travelFlags = AreaContentsTravelFlags( areaNum );
916 for ( j = 0; j < num; j++ ) {
917 Reachability_Read( src, &reach );
918 switch( reach.travelType ) {
920 newReach = special = new idReachability_Special();
921 Reachability_Special_Read( src, special );
924 newReach = new idReachability();
927 newReach->CopyBase( reach );
928 newReach->fromAreaNum = areaNum;
929 newReach->next = area->reach;
930 area->reach = newReach;
932 src.ExpectTokenString( "}" );
938 idAASFileLocal::LinkReversedReachability
941 void idAASFileLocal::LinkReversedReachability( void ) {
943 idReachability *reach;
945 // link reversed reachabilities
946 for ( i = 0; i < areas.Num(); i++ ) {
947 for ( reach = areas[i].reach; reach; reach = reach->next ) {
948 reach->rev_next = areas[reach->toAreaNum].rev_reach;
949 areas[reach->toAreaNum].rev_reach = reach;
956 idAASFileLocal::ParseAreas
959 bool idAASFileLocal::ParseAreas( idLexer &src ) {
963 numAreas = src.ParseInt();
964 areas.Resize( numAreas );
965 if ( !src.ExpectTokenString( "{" ) ) {
968 for ( i = 0; i < numAreas; i++ ) {
970 src.ExpectTokenString( "(" );
971 area.flags = src.ParseInt();
972 area.contents = src.ParseInt();
973 area.firstFace = src.ParseInt();
974 area.numFaces = src.ParseInt();
975 area.cluster = src.ParseInt();
976 area.clusterAreaNum = src.ParseInt();
977 src.ExpectTokenString( ")" );
978 areas.Append( area );
979 ParseReachabilities( src, i );
981 if ( !src.ExpectTokenString( "}" ) ) {
985 LinkReversedReachability();
992 idAASFileLocal::ParseNodes
995 bool idAASFileLocal::ParseNodes( idLexer &src ) {
999 numNodes = src.ParseInt();
1000 nodes.Resize( numNodes );
1001 if ( !src.ExpectTokenString( "{" ) ) {
1004 for ( i = 0; i < numNodes; i++ ) {
1006 src.ExpectTokenString( "(" );
1007 node.planeNum = src.ParseInt();
1008 node.children[0] = src.ParseInt();
1009 node.children[1] = src.ParseInt();
1010 src.ExpectTokenString( ")" );
1011 nodes.Append( node );
1013 if ( !src.ExpectTokenString( "}" ) ) {
1021 idAASFileLocal::ParsePortals
1024 bool idAASFileLocal::ParsePortals( idLexer &src ) {
1028 numPortals = src.ParseInt();
1029 portals.Resize( numPortals );
1030 if ( !src.ExpectTokenString( "{" ) ) {
1033 for ( i = 0; i < numPortals; i++ ) {
1035 src.ExpectTokenString( "(" );
1036 portal.areaNum = src.ParseInt();
1037 portal.clusters[0] = src.ParseInt();
1038 portal.clusters[1] = src.ParseInt();
1039 portal.clusterAreaNum[0] = src.ParseInt();
1040 portal.clusterAreaNum[1] = src.ParseInt();
1041 src.ExpectTokenString( ")" );
1042 portals.Append( portal );
1044 if ( !src.ExpectTokenString( "}" ) ) {
1052 idAASFileLocal::ParseClusters
1055 bool idAASFileLocal::ParseClusters( idLexer &src ) {
1057 aasCluster_t cluster;
1059 numClusters = src.ParseInt();
1060 clusters.Resize( numClusters );
1061 if ( !src.ExpectTokenString( "{" ) ) {
1064 for ( i = 0; i < numClusters; i++ ) {
1066 src.ExpectTokenString( "(" );
1067 cluster.numAreas = src.ParseInt();
1068 cluster.numReachableAreas = src.ParseInt();
1069 cluster.firstPortal = src.ParseInt();
1070 cluster.numPortals = src.ParseInt();
1071 src.ExpectTokenString( ")" );
1072 clusters.Append( cluster );
1074 if ( !src.ExpectTokenString( "}" ) ) {
1082 idAASFileLocal::FinishAreas
1085 void idAASFileLocal::FinishAreas( void ) {
1088 for ( i = 0; i < areas.Num(); i++ ) {
1089 areas[i].center = AreaReachableGoal( i );
1090 areas[i].bounds = AreaBounds( i );
1096 idAASFileLocal::Load
1099 bool idAASFileLocal::Load( const idStr &fileName, unsigned int mapFileCRC ) {
1100 idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES );
1108 common->Printf( "[Load AAS]\n" );
1109 common->Printf( "loading %s\n", name.c_str() );
1111 if ( !src.LoadFile( name ) ) {
1115 if ( !src.ExpectTokenString( AAS_FILEID ) ) {
1116 common->Warning( "Not an AAS file: '%s'", name.c_str() );
1120 if ( !src.ReadToken( &token ) || token != AAS_FILEVERSION ) {
1121 common->Warning( "AAS file '%s' has version %s instead of %s", name.c_str(), token.c_str(), AAS_FILEVERSION );
1125 if ( !src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
1126 common->Warning( "AAS file '%s' has no map file CRC", name.c_str() );
1130 c = token.GetUnsignedLongValue();
1131 if ( mapFileCRC && c != mapFileCRC ) {
1132 common->Warning( "AAS file '%s' is out of date", name.c_str() );
1136 // clear the file in memory
1141 if ( !src.ReadToken( &token ) ) {
1145 if ( token == "settings" ) {
1146 if ( !settings.FromParser( src ) ) { return false; }
1148 else if ( token == "planes" ) {
1149 if ( !ParsePlanes( src ) ) { return false; }
1151 else if ( token == "vertices" ) {
1152 if ( !ParseVertices( src ) ) { return false; }
1154 else if ( token == "edges" ) {
1155 if ( !ParseEdges( src ) ) { return false; }
1157 else if ( token == "edgeIndex" ) {
1158 if ( !ParseIndex( src, edgeIndex ) ) { return false; }
1160 else if ( token == "faces" ) {
1161 if ( !ParseFaces( src ) ) { return false; }
1163 else if ( token == "faceIndex" ) {
1164 if ( !ParseIndex( src, faceIndex ) ) { return false; }
1166 else if ( token == "areas" ) {
1167 if ( !ParseAreas( src ) ) { return false; }
1169 else if ( token == "nodes" ) {
1170 if ( !ParseNodes( src ) ) { return false; }
1172 else if ( token == "portals" ) {
1173 if ( !ParsePortals( src ) ) { return false; }
1175 else if ( token == "portalIndex" ) {
1176 if ( !ParseIndex( src, portalIndex ) ) { return false; }
1178 else if ( token == "clusters" ) {
1179 if ( !ParseClusters( src ) ) { return false; }
1182 src.Error( "idAASFileLocal::Load: bad token \"%s\"", token.c_str() );
1189 depth = MaxTreeDepth();
1190 if ( depth > MAX_AAS_TREE_DEPTH ) {
1191 src.Error( "idAASFileLocal::Load: tree depth = %d", depth );
1194 common->Printf( "done.\n" );
1201 idAASFileLocal::MemorySize
1204 int idAASFileLocal::MemorySize( void ) const {
1207 size = planeList.Size();
1208 size += vertices.Size();
1209 size += edges.Size();
1210 size += edgeIndex.Size();
1211 size += faces.Size();
1212 size += faceIndex.Size();
1213 size += areas.Size();
1214 size += nodes.Size();
1215 size += portals.Size();
1216 size += portalIndex.Size();
1217 size += clusters.Size();
1218 size += sizeof( idReachability_Walk ) * NumReachabilities();
1225 idAASFileLocal::PrintInfo
1228 void idAASFileLocal::PrintInfo( void ) const {
1229 common->Printf( "%6d KB file size\n", MemorySize() >> 10 );
1230 common->Printf( "%6d areas\n", areas.Num() );
1231 common->Printf( "%6d max tree depth\n", MaxTreeDepth() );
1232 ReportRoutingEfficiency();
1237 idAASFileLocal::NumReachabilities
1240 int idAASFileLocal::NumReachabilities( void ) const {
1242 idReachability *reach;
1245 for ( i = 0; i < areas.Num(); i++ ) {
1246 for ( reach = areas[i].reach; reach; reach = reach->next ) {
1255 idAASFileLocal::ReportRoutingEfficiency
1258 void idAASFileLocal::ReportRoutingEfficiency( void ) const {
1259 int numReachableAreas, total, i, n;
1261 numReachableAreas = 0;
1263 for ( i = 0; i < clusters.Num(); i++ ) {
1264 n = clusters[i].numReachableAreas;
1265 numReachableAreas += n;
1268 total += numReachableAreas * portals.Num();
1270 common->Printf( "%6d reachable areas\n", numReachableAreas );
1271 common->Printf( "%6d reachabilities\n", NumReachabilities() );
1272 common->Printf( "%6d KB max routing cache\n", ( total * 3 ) >> 10 );
1277 idAASFileLocal::DeleteReachabilities
1280 void idAASFileLocal::DeleteReachabilities( void ) {
1282 idReachability *reach, *nextReach;
1284 for ( i = 0; i < areas.Num(); i++ ) {
1285 for ( reach = areas[i].reach; reach; reach = nextReach ) {
1286 nextReach = reach->next;
1289 areas[i].reach = NULL;
1290 areas[i].rev_reach = NULL;
1296 idAASFileLocal::DeleteClusters
1299 void idAASFileLocal::DeleteClusters( void ) {
1301 aasCluster_t cluster;
1304 portalIndex.Clear();
1307 // first portal is a dummy
1308 memset( &portal, 0, sizeof( portal ) );
1309 portals.Append( portal );
1311 // first cluster is a dummy
1312 memset( &cluster, 0, sizeof( portal ) );
1313 clusters.Append( cluster );