mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-12-02 17:22:32 +00:00
0d27bfe7b9
Apart from some minor stuff, this changes the signature of some methods of Parser and Token classes and of the (unused) Random2 class. That no problem though, because the calling code uses normal ints anyway.
1318 lines
33 KiB
C++
1318 lines
33 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "sys/platform.h"
|
|
#include "framework/FileSystem.h"
|
|
#include "framework/DeclEntityDef.h"
|
|
|
|
#include "tools/compilers/aas/AASFile_local.h"
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idReachability
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
Reachability_Write
|
|
================
|
|
*/
|
|
bool Reachability_Write( idFile *fp, idReachability *reach ) {
|
|
fp->WriteFloatString( "\t\t%d %d (%f %f %f) (%f %f %f) %d %d",
|
|
(int) reach->travelType, (int) reach->toAreaNum, reach->start.x, reach->start.y, reach->start.z,
|
|
reach->end.x, reach->end.y, reach->end.z, reach->edgeNum, (int) reach->travelTime );
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
Reachability_Read
|
|
================
|
|
*/
|
|
bool Reachability_Read( idLexer &src, idReachability *reach ) {
|
|
reach->travelType = src.ParseInt();
|
|
reach->toAreaNum = src.ParseInt();
|
|
src.Parse1DMatrix( 3, reach->start.ToFloatPtr() );
|
|
src.Parse1DMatrix( 3, reach->end.ToFloatPtr() );
|
|
reach->edgeNum = src.ParseInt();
|
|
reach->travelTime = src.ParseInt();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idReachability::CopyBase
|
|
================
|
|
*/
|
|
void idReachability::CopyBase( idReachability &reach ) {
|
|
travelType = reach.travelType;
|
|
toAreaNum = reach.toAreaNum;
|
|
start = reach.start;
|
|
end = reach.end;
|
|
edgeNum = reach.edgeNum;
|
|
travelTime = reach.travelTime;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idReachability_Special
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
Reachability_Special_Write
|
|
================
|
|
*/
|
|
bool Reachability_Special_Write( idFile *fp, idReachability_Special *reach ) {
|
|
int i;
|
|
const idKeyValue *keyValue;
|
|
|
|
fp->WriteFloatString( "\n\t\t{\n" );
|
|
for ( i = 0; i < reach->dict.GetNumKeyVals(); i++ ) {
|
|
keyValue = reach->dict.GetKeyVal( i );
|
|
fp->WriteFloatString( "\t\t\t\"%s\" \"%s\"\n", keyValue->GetKey().c_str(), keyValue->GetValue().c_str() );
|
|
}
|
|
fp->WriteFloatString( "\t\t}\n" );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
Reachability_Special_Read
|
|
================
|
|
*/
|
|
bool Reachability_Special_Read( idLexer &src, idReachability_Special *reach ) {
|
|
idToken key, value;
|
|
|
|
src.ExpectTokenString( "{" );
|
|
while( src.ReadToken( &key ) ) {
|
|
if ( key == "}" ) {
|
|
return true;
|
|
}
|
|
src.ExpectTokenType( TT_STRING, 0, &value );
|
|
reach->dict.Set( key, value );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idAASSettings
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
============
|
|
idAASSettings::idAASSettings
|
|
============
|
|
*/
|
|
idAASSettings::idAASSettings( void ) {
|
|
numBoundingBoxes = 1;
|
|
boundingBoxes[0] = idBounds( idVec3( -16, -16, 0 ), idVec3( 16, 16, 72 ) );
|
|
usePatches = false;
|
|
writeBrushMap = false;
|
|
playerFlood = false;
|
|
noOptimize = false;
|
|
allowSwimReachabilities = false;
|
|
allowFlyReachabilities = false;
|
|
fileExtension = "aas48";
|
|
// physics settings
|
|
gravity = idVec3( 0, 0, -1066 );
|
|
gravityDir = gravity;
|
|
gravityValue = gravityDir.Normalize();
|
|
invGravityDir = -gravityDir;
|
|
maxStepHeight = 14.0f;
|
|
maxBarrierHeight = 32.0f;
|
|
maxWaterJumpHeight = 20.0f;
|
|
maxFallHeight = 64.0f;
|
|
minFloorCos = 0.7f;
|
|
// fixed travel times
|
|
tt_barrierJump = 100;
|
|
tt_startCrouching = 100;
|
|
tt_waterJump = 100;
|
|
tt_startWalkOffLedge = 100;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::ParseBool
|
|
============
|
|
*/
|
|
bool idAASSettings::ParseBool( idLexer &src, bool &b ) {
|
|
if ( !src.ExpectTokenString( "=" ) ) {
|
|
return false;
|
|
}
|
|
b = src.ParseBool();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::ParseInt
|
|
============
|
|
*/
|
|
bool idAASSettings::ParseInt( idLexer &src, int &i ) {
|
|
if ( !src.ExpectTokenString( "=" ) ) {
|
|
return false;
|
|
}
|
|
i = src.ParseInt();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::ParseFloat
|
|
============
|
|
*/
|
|
bool idAASSettings::ParseFloat( idLexer &src, float &f ) {
|
|
if ( !src.ExpectTokenString( "=" ) ) {
|
|
return false;
|
|
}
|
|
f = src.ParseFloat();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::ParseVector
|
|
============
|
|
*/
|
|
bool idAASSettings::ParseVector( idLexer &src, idVec3 &vec ) {
|
|
if ( !src.ExpectTokenString( "=" ) ) {
|
|
return false;
|
|
}
|
|
return ( src.Parse1DMatrix( 3, vec.ToFloatPtr() ) != 0 );
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::ParseBBoxes
|
|
============
|
|
*/
|
|
bool idAASSettings::ParseBBoxes( idLexer &src ) {
|
|
idToken token;
|
|
idBounds bounds;
|
|
|
|
numBoundingBoxes = 0;
|
|
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
while( src.ReadToken( &token ) ) {
|
|
if ( token == "}" ) {
|
|
return true;
|
|
}
|
|
src.UnreadToken( &token );
|
|
src.Parse1DMatrix( 3, bounds[0].ToFloatPtr() );
|
|
if ( !src.ExpectTokenString( "-" ) ) {
|
|
return false;
|
|
}
|
|
src.Parse1DMatrix( 3, bounds[1].ToFloatPtr() );
|
|
|
|
boundingBoxes[numBoundingBoxes++] = bounds;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::FromParser
|
|
============
|
|
*/
|
|
bool idAASSettings::FromParser( idLexer &src ) {
|
|
idToken token;
|
|
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
|
|
// parse the file
|
|
while ( 1 ) {
|
|
if ( !src.ReadToken( &token ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( token == "}" ) {
|
|
break;
|
|
}
|
|
|
|
if ( token == "bboxes" ) {
|
|
if ( !ParseBBoxes( src ) ) { return false; }
|
|
}
|
|
else if ( token == "usePatches" ) {
|
|
if ( !ParseBool( src, usePatches ) ) { return false; }
|
|
}
|
|
else if ( token == "writeBrushMap" ) {
|
|
if ( !ParseBool( src, writeBrushMap ) ) { return false; }
|
|
}
|
|
else if ( token == "playerFlood" ) {
|
|
if ( !ParseBool( src, playerFlood ) ) { return false; }
|
|
}
|
|
else if ( token == "allowSwimReachabilities" ) {
|
|
if ( !ParseBool( src, allowSwimReachabilities ) ) { return false; }
|
|
}
|
|
else if ( token == "allowFlyReachabilities" ) {
|
|
if ( !ParseBool( src, allowFlyReachabilities ) ) { return false; }
|
|
}
|
|
else if ( token == "fileExtension" ) {
|
|
src.ExpectTokenString( "=" );
|
|
src.ExpectTokenType( TT_STRING, 0, &token );
|
|
fileExtension = token;
|
|
}
|
|
else if ( token == "gravity" ) {
|
|
ParseVector( src, gravity );
|
|
gravityDir = gravity;
|
|
gravityValue = gravityDir.Normalize();
|
|
invGravityDir = -gravityDir;
|
|
}
|
|
else if ( token == "maxStepHeight" ) {
|
|
if ( !ParseFloat( src, maxStepHeight ) ) { return false; }
|
|
}
|
|
else if ( token == "maxBarrierHeight" ) {
|
|
if ( !ParseFloat( src, maxBarrierHeight ) ) { return false; }
|
|
}
|
|
else if ( token == "maxWaterJumpHeight" ) {
|
|
if ( !ParseFloat( src, maxWaterJumpHeight ) ) { return false; }
|
|
}
|
|
else if ( token == "maxFallHeight" ) {
|
|
if ( !ParseFloat( src, maxFallHeight ) ) { return false; }
|
|
}
|
|
else if ( token == "minFloorCos" ) {
|
|
if ( !ParseFloat( src, minFloorCos ) ) { return false; }
|
|
}
|
|
else if ( token == "tt_barrierJump" ) {
|
|
if ( !ParseInt( src, tt_barrierJump ) ) { return false; }
|
|
}
|
|
else if ( token == "tt_startCrouching" ) {
|
|
if ( !ParseInt( src, tt_startCrouching ) ) { return false; }
|
|
}
|
|
else if ( token == "tt_waterJump" ) {
|
|
if ( !ParseInt( src, tt_waterJump ) ) { return false; }
|
|
}
|
|
else if ( token == "tt_startWalkOffLedge" ) {
|
|
if ( !ParseInt( src, tt_startWalkOffLedge ) ) { return false; }
|
|
}
|
|
else {
|
|
src.Error( "invalid token '%s'", token.c_str() );
|
|
}
|
|
}
|
|
|
|
if ( numBoundingBoxes <= 0 ) {
|
|
src.Error( "no valid bounding box" );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::FromFile
|
|
============
|
|
*/
|
|
bool idAASSettings::FromFile( const idStr &fileName ) {
|
|
idLexer src( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
|
|
idStr name;
|
|
|
|
name = fileName;
|
|
|
|
common->Printf( "loading %s\n", name.c_str() );
|
|
|
|
if ( !src.LoadFile( name ) ) {
|
|
common->Error( "WARNING: couldn't load %s\n", name.c_str() );
|
|
return false;
|
|
}
|
|
|
|
if ( !src.ExpectTokenString( "settings" ) ) {
|
|
common->Error( "%s is not a settings file", name.c_str() );
|
|
return false;
|
|
}
|
|
|
|
if ( !FromParser( src ) ) {
|
|
common->Error( "failed to parse %s", name.c_str() );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::FromDict
|
|
============
|
|
*/
|
|
bool idAASSettings::FromDict( const char *name, const idDict *dict ) {
|
|
idBounds bounds;
|
|
|
|
if ( !dict->GetVector( "mins", "0 0 0", bounds[ 0 ] ) ) {
|
|
common->Error( "Missing 'mins' in entityDef '%s'", name );
|
|
}
|
|
if ( !dict->GetVector( "maxs", "0 0 0", bounds[ 1 ] ) ) {
|
|
common->Error( "Missing 'maxs' in entityDef '%s'", name );
|
|
}
|
|
|
|
numBoundingBoxes = 1;
|
|
boundingBoxes[0] = bounds;
|
|
|
|
if ( !dict->GetBool( "usePatches", "0", usePatches ) ) {
|
|
common->Error( "Missing 'usePatches' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetBool( "writeBrushMap", "0", writeBrushMap ) ) {
|
|
common->Error( "Missing 'writeBrushMap' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetBool( "playerFlood", "0", playerFlood ) ) {
|
|
common->Error( "Missing 'playerFlood' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetBool( "allowSwimReachabilities", "0", allowSwimReachabilities ) ) {
|
|
common->Error( "Missing 'allowSwimReachabilities' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetBool( "allowFlyReachabilities", "0", allowFlyReachabilities ) ) {
|
|
common->Error( "Missing 'allowFlyReachabilities' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetString( "fileExtension", "", fileExtension ) ) {
|
|
common->Error( "Missing 'fileExtension' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetVector( "gravity", "0 0 -1066", gravity ) ) {
|
|
common->Error( "Missing 'gravity' in entityDef '%s'", name );
|
|
}
|
|
gravityDir = gravity;
|
|
gravityValue = gravityDir.Normalize();
|
|
invGravityDir = -gravityDir;
|
|
|
|
if ( !dict->GetFloat( "maxStepHeight", "0", maxStepHeight ) ) {
|
|
common->Error( "Missing 'maxStepHeight' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetFloat( "maxBarrierHeight", "0", maxBarrierHeight ) ) {
|
|
common->Error( "Missing 'maxBarrierHeight' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetFloat( "maxWaterJumpHeight", "0", maxWaterJumpHeight ) ) {
|
|
common->Error( "Missing 'maxWaterJumpHeight' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetFloat( "maxFallHeight", "0", maxFallHeight ) ) {
|
|
common->Error( "Missing 'maxFallHeight' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetFloat( "minFloorCos", "0", minFloorCos ) ) {
|
|
common->Error( "Missing 'minFloorCos' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetInt( "tt_barrierJump", "0", tt_barrierJump ) ) {
|
|
common->Error( "Missing 'tt_barrierJump' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetInt( "tt_startCrouching", "0", tt_startCrouching ) ) {
|
|
common->Error( "Missing 'tt_startCrouching' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetInt( "tt_waterJump", "0", tt_waterJump ) ) {
|
|
common->Error( "Missing 'tt_waterJump' in entityDef '%s'", name );
|
|
}
|
|
|
|
if ( !dict->GetInt( "tt_startWalkOffLedge", "0", tt_startWalkOffLedge ) ) {
|
|
common->Error( "Missing 'tt_startWalkOffLedge' in entityDef '%s'", name );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
idAASSettings::WriteToFile
|
|
============
|
|
*/
|
|
bool idAASSettings::WriteToFile( idFile *fp ) const {
|
|
int i;
|
|
|
|
fp->WriteFloatString( "{\n" );
|
|
fp->WriteFloatString( "\tbboxes\n\t{\n" );
|
|
for ( i = 0; i < numBoundingBoxes; i++ ) {
|
|
fp->WriteFloatString( "\t\t(%f %f %f)-(%f %f %f)\n", boundingBoxes[i][0].x, boundingBoxes[i][0].y,
|
|
boundingBoxes[i][0].z, boundingBoxes[i][1].x, boundingBoxes[i][1].y, boundingBoxes[i][1].z );
|
|
}
|
|
fp->WriteFloatString( "\t}\n" );
|
|
fp->WriteFloatString( "\tusePatches = %d\n", usePatches );
|
|
fp->WriteFloatString( "\twriteBrushMap = %d\n", writeBrushMap );
|
|
fp->WriteFloatString( "\tplayerFlood = %d\n", playerFlood );
|
|
fp->WriteFloatString( "\tallowSwimReachabilities = %d\n", allowSwimReachabilities );
|
|
fp->WriteFloatString( "\tallowFlyReachabilities = %d\n", allowFlyReachabilities );
|
|
fp->WriteFloatString( "\tfileExtension = \"%s\"\n", fileExtension.c_str() );
|
|
fp->WriteFloatString( "\tgravity = (%f %f %f)\n", gravity.x, gravity.y, gravity.z );
|
|
fp->WriteFloatString( "\tmaxStepHeight = %f\n", maxStepHeight );
|
|
fp->WriteFloatString( "\tmaxBarrierHeight = %f\n", maxBarrierHeight );
|
|
fp->WriteFloatString( "\tmaxWaterJumpHeight = %f\n", maxWaterJumpHeight );
|
|
fp->WriteFloatString( "\tmaxFallHeight = %f\n", maxFallHeight );
|
|
fp->WriteFloatString( "\tminFloorCos = %f\n", minFloorCos );
|
|
fp->WriteFloatString( "\ttt_barrierJump = %d\n", tt_barrierJump );
|
|
fp->WriteFloatString( "\ttt_startCrouching = %d\n", tt_startCrouching );
|
|
fp->WriteFloatString( "\ttt_waterJump = %d\n", tt_waterJump );
|
|
fp->WriteFloatString( "\ttt_startWalkOffLedge = %d\n", tt_startWalkOffLedge );
|
|
fp->WriteFloatString( "}\n" );
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::ValidForBounds
|
|
============
|
|
*/
|
|
bool idAASSettings::ValidForBounds( const idBounds &bounds ) const {
|
|
int i;
|
|
|
|
for ( i = 0; i < 3; i++ ) {
|
|
if ( bounds[0][i] < boundingBoxes[0][0][i] ) {
|
|
return false;
|
|
}
|
|
if ( bounds[1][i] > boundingBoxes[0][1][i] ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============
|
|
idAASSettings::ValidEntity
|
|
============
|
|
*/
|
|
bool idAASSettings::ValidEntity( const char *classname ) const {
|
|
idStr use_aas;
|
|
idVec3 size;
|
|
idBounds bounds;
|
|
|
|
if ( playerFlood ) {
|
|
if ( !strcmp( classname, "info_player_start" ) || !strcmp( classname , "info_player_deathmatch" ) || !strcmp( classname, "func_teleporter" ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
const idDeclEntityDef *decl = static_cast<const idDeclEntityDef *>( declManager->FindType( DECL_ENTITYDEF, classname, false ) );
|
|
if ( decl && decl->dict.GetString( "use_aas", NULL, use_aas ) && !fileExtension.Icmp( use_aas ) ) {
|
|
if ( decl->dict.GetVector( "mins", NULL, bounds[0] ) ) {
|
|
decl->dict.GetVector( "maxs", NULL, bounds[1] );
|
|
} else if ( decl->dict.GetVector( "size", NULL, size ) ) {
|
|
bounds[ 0 ].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
|
|
bounds[ 1 ].Set( size.x * 0.5f, size.y * 0.5f, size.z );
|
|
}
|
|
|
|
if ( !ValidForBounds( bounds ) ) {
|
|
common->Error( "%s cannot use %s\n", classname, fileExtension.c_str() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idAASFileLocal
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#define AAS_LIST_GRANULARITY 1024
|
|
#define AAS_INDEX_GRANULARITY 4096
|
|
#define AAS_PLANE_GRANULARITY 4096
|
|
#define AAS_VERTEX_GRANULARITY 4096
|
|
#define AAS_EDGE_GRANULARITY 4096
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::idAASFileLocal
|
|
================
|
|
*/
|
|
idAASFileLocal::idAASFileLocal( void ) {
|
|
planeList.SetGranularity( AAS_PLANE_GRANULARITY );
|
|
vertices.SetGranularity( AAS_VERTEX_GRANULARITY );
|
|
edges.SetGranularity( AAS_EDGE_GRANULARITY );
|
|
edgeIndex.SetGranularity( AAS_INDEX_GRANULARITY );
|
|
faces.SetGranularity( AAS_LIST_GRANULARITY );
|
|
faceIndex.SetGranularity( AAS_INDEX_GRANULARITY );
|
|
areas.SetGranularity( AAS_LIST_GRANULARITY );
|
|
nodes.SetGranularity( AAS_LIST_GRANULARITY );
|
|
portals.SetGranularity( AAS_LIST_GRANULARITY );
|
|
portalIndex.SetGranularity( AAS_INDEX_GRANULARITY );
|
|
clusters.SetGranularity( AAS_LIST_GRANULARITY );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::~idAASFileLocal
|
|
================
|
|
*/
|
|
idAASFileLocal::~idAASFileLocal( void ) {
|
|
int i;
|
|
idReachability *reach, *next;
|
|
|
|
for ( i = 0; i < areas.Num(); i++ ) {
|
|
for ( reach = areas[i].reach; reach; reach = next ) {
|
|
next = reach->next;
|
|
delete reach;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::Clear
|
|
================
|
|
*/
|
|
void idAASFileLocal::Clear( void ) {
|
|
planeList.Clear();
|
|
vertices.Clear();
|
|
edges.Clear();
|
|
edgeIndex.Clear();
|
|
faces.Clear();
|
|
faceIndex.Clear();
|
|
areas.Clear();
|
|
nodes.Clear();
|
|
portals.Clear();
|
|
portalIndex.Clear();
|
|
clusters.Clear();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::Write
|
|
================
|
|
*/
|
|
bool idAASFileLocal::Write( const idStr &fileName, unsigned int mapFileCRC ) {
|
|
int i, num;
|
|
idFile *aasFile;
|
|
idReachability *reach;
|
|
|
|
common->Printf( "[Write AAS]\n" );
|
|
common->Printf( "writing %s\n", fileName.c_str() );
|
|
|
|
name = fileName;
|
|
crc = mapFileCRC;
|
|
|
|
aasFile = fileSystem->OpenFileWrite( fileName, "fs_devpath" );
|
|
if ( !aasFile ) {
|
|
common->Error( "Error opening %s", fileName.c_str() );
|
|
return false;
|
|
}
|
|
|
|
aasFile->WriteFloatString( "%s \"%s\"\n\n", AAS_FILEID, AAS_FILEVERSION );
|
|
aasFile->WriteFloatString( "%u\n\n", mapFileCRC );
|
|
|
|
// write out the settings
|
|
aasFile->WriteFloatString( "settings\n" );
|
|
settings.WriteToFile( aasFile );
|
|
|
|
// write out planes
|
|
aasFile->WriteFloatString( "planes %d {\n", planeList.Num() );
|
|
for ( i = 0; i < planeList.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %f %f %f %f )\n", i,
|
|
planeList[i].Normal().x, planeList[i].Normal().y, planeList[i].Normal().z, planeList[i].Dist() );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out vertices
|
|
aasFile->WriteFloatString( "vertices %d {\n", vertices.Num() );
|
|
for ( i = 0; i < vertices.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %f %f %f )\n", i, vertices[i].x, vertices[i].y, vertices[i].z );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out edges
|
|
aasFile->WriteFloatString( "edges %d {\n", edges.Num() );
|
|
for ( i = 0; i < edges.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d %d )\n", i, edges[i].vertexNum[0], edges[i].vertexNum[1] );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out edgeIndex
|
|
aasFile->WriteFloatString( "edgeIndex %d {\n", edgeIndex.Num() );
|
|
for ( i = 0; i < edgeIndex.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d )\n", i, edgeIndex[i] );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out faces
|
|
aasFile->WriteFloatString( "faces %d {\n", faces.Num() );
|
|
for ( i = 0; i < faces.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d %d )\n", i, faces[i].planeNum, faces[i].flags,
|
|
faces[i].areas[0], faces[i].areas[1], faces[i].firstEdge, faces[i].numEdges );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out faceIndex
|
|
aasFile->WriteFloatString( "faceIndex %d {\n", faceIndex.Num() );
|
|
for ( i = 0; i < faceIndex.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d )\n", i, faceIndex[i] );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out areas
|
|
aasFile->WriteFloatString( "areas %d {\n", areas.Num() );
|
|
for ( i = 0; i < areas.Num(); i++ ) {
|
|
for ( num = 0, reach = areas[i].reach; reach; reach = reach->next ) {
|
|
num++;
|
|
}
|
|
aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d %d ) %d {\n", i, areas[i].flags, areas[i].contents,
|
|
areas[i].firstFace, areas[i].numFaces, areas[i].cluster, areas[i].clusterAreaNum, num );
|
|
for ( reach = areas[i].reach; reach; reach = reach->next ) {
|
|
Reachability_Write( aasFile, reach );
|
|
switch( reach->travelType ) {
|
|
case TFL_SPECIAL:
|
|
Reachability_Special_Write( aasFile, static_cast<idReachability_Special *>(reach) );
|
|
break;
|
|
}
|
|
aasFile->WriteFloatString( "\n" );
|
|
}
|
|
aasFile->WriteFloatString( "\t}\n" );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out nodes
|
|
aasFile->WriteFloatString( "nodes %d {\n", nodes.Num() );
|
|
for ( i = 0; i < nodes.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d %d %d )\n", i, nodes[i].planeNum, nodes[i].children[0], nodes[i].children[1] );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out portals
|
|
aasFile->WriteFloatString( "portals %d {\n", portals.Num() );
|
|
for ( i = 0; i < portals.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d %d %d %d %d )\n", i, portals[i].areaNum, portals[i].clusters[0],
|
|
portals[i].clusters[1], portals[i].clusterAreaNum[0], portals[i].clusterAreaNum[1] );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out portalIndex
|
|
aasFile->WriteFloatString( "portalIndex %d {\n", portalIndex.Num() );
|
|
for ( i = 0; i < portalIndex.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d )\n", i, portalIndex[i] );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// write out clusters
|
|
aasFile->WriteFloatString( "clusters %d {\n", clusters.Num() );
|
|
for ( i = 0; i < clusters.Num(); i++ ) {
|
|
aasFile->WriteFloatString( "\t%d ( %d %d %d %d )\n", i, clusters[i].numAreas, clusters[i].numReachableAreas,
|
|
clusters[i].firstPortal, clusters[i].numPortals );
|
|
}
|
|
aasFile->WriteFloatString( "}\n" );
|
|
|
|
// close file
|
|
fileSystem->CloseFile( aasFile );
|
|
|
|
common->Printf( "done.\n" );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseIndex
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseIndex( idLexer &src, idList<aasIndex_t> &indexes ) {
|
|
int numIndexes, i;
|
|
aasIndex_t index;
|
|
|
|
numIndexes = src.ParseInt();
|
|
indexes.Resize( numIndexes );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numIndexes; i++ ) {
|
|
src.ParseInt();
|
|
src.ExpectTokenString( "(" );
|
|
index = src.ParseInt();
|
|
src.ExpectTokenString( ")" );
|
|
indexes.Append( index );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParsePlanes
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParsePlanes( idLexer &src ) {
|
|
int numPlanes, i;
|
|
idPlane plane;
|
|
idVec4 vec;
|
|
|
|
numPlanes = src.ParseInt();
|
|
planeList.Resize( numPlanes );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numPlanes; i++ ) {
|
|
src.ParseInt();
|
|
if ( !src.Parse1DMatrix( 4, vec.ToFloatPtr() ) ) {
|
|
return false;
|
|
}
|
|
plane.SetNormal( vec.ToVec3() );
|
|
plane.SetDist( vec[3] );
|
|
planeList.Append( plane );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseVertices
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseVertices( idLexer &src ) {
|
|
int numVertices, i;
|
|
idVec3 vec;
|
|
|
|
numVertices = src.ParseInt();
|
|
vertices.Resize( numVertices );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numVertices; i++ ) {
|
|
src.ParseInt();
|
|
if ( !src.Parse1DMatrix( 3, vec.ToFloatPtr() ) ) {
|
|
return false;
|
|
}
|
|
vertices.Append( vec );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseEdges
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseEdges( idLexer &src ) {
|
|
int numEdges, i;
|
|
aasEdge_t edge;
|
|
|
|
numEdges = src.ParseInt();
|
|
edges.Resize( numEdges );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numEdges; i++ ) {
|
|
src.ParseInt();
|
|
src.ExpectTokenString( "(" );
|
|
edge.vertexNum[0] = src.ParseInt();
|
|
edge.vertexNum[1] = src.ParseInt();
|
|
src.ExpectTokenString( ")" );
|
|
edges.Append( edge );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseFaces
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseFaces( idLexer &src ) {
|
|
int numFaces, i;
|
|
aasFace_t face;
|
|
|
|
numFaces = src.ParseInt();
|
|
faces.Resize( numFaces );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numFaces; i++ ) {
|
|
src.ParseInt();
|
|
src.ExpectTokenString( "(" );
|
|
face.planeNum = src.ParseInt();
|
|
face.flags = src.ParseInt();
|
|
face.areas[0] = src.ParseInt();
|
|
face.areas[1] = src.ParseInt();
|
|
face.firstEdge = src.ParseInt();
|
|
face.numEdges = src.ParseInt();
|
|
src.ExpectTokenString( ")" );
|
|
faces.Append( face );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseReachabilities
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseReachabilities( idLexer &src, int areaNum ) {
|
|
int num, j;
|
|
aasArea_t *area;
|
|
idReachability reach, *newReach;
|
|
idReachability_Special *special;
|
|
|
|
area = &areas[areaNum];
|
|
|
|
num = src.ParseInt();
|
|
src.ExpectTokenString( "{" );
|
|
area->reach = NULL;
|
|
area->rev_reach = NULL;
|
|
area->travelFlags = AreaContentsTravelFlags( areaNum );
|
|
for ( j = 0; j < num; j++ ) {
|
|
Reachability_Read( src, &reach );
|
|
switch( reach.travelType ) {
|
|
case TFL_SPECIAL:
|
|
newReach = special = new idReachability_Special();
|
|
Reachability_Special_Read( src, special );
|
|
break;
|
|
default:
|
|
newReach = new idReachability();
|
|
break;
|
|
}
|
|
newReach->CopyBase( reach );
|
|
newReach->fromAreaNum = areaNum;
|
|
newReach->next = area->reach;
|
|
area->reach = newReach;
|
|
}
|
|
src.ExpectTokenString( "}" );
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::LinkReversedReachability
|
|
================
|
|
*/
|
|
void idAASFileLocal::LinkReversedReachability( void ) {
|
|
int i;
|
|
idReachability *reach;
|
|
|
|
// link reversed reachabilities
|
|
for ( i = 0; i < areas.Num(); i++ ) {
|
|
for ( reach = areas[i].reach; reach; reach = reach->next ) {
|
|
reach->rev_next = areas[reach->toAreaNum].rev_reach;
|
|
areas[reach->toAreaNum].rev_reach = reach;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseAreas
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseAreas( idLexer &src ) {
|
|
int numAreas, i;
|
|
aasArea_t area;
|
|
|
|
numAreas = src.ParseInt();
|
|
areas.Resize( numAreas );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numAreas; i++ ) {
|
|
src.ParseInt();
|
|
src.ExpectTokenString( "(" );
|
|
area.flags = src.ParseInt();
|
|
area.contents = src.ParseInt();
|
|
area.firstFace = src.ParseInt();
|
|
area.numFaces = src.ParseInt();
|
|
area.cluster = src.ParseInt();
|
|
area.clusterAreaNum = src.ParseInt();
|
|
area.reach = NULL;
|
|
area.rev_reach = NULL;
|
|
area.bounds.Zero();
|
|
area.center.Zero();
|
|
area.travelFlags = 0;
|
|
src.ExpectTokenString( ")" );
|
|
areas.Append( area );
|
|
ParseReachabilities( src, i );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
|
|
LinkReversedReachability();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseNodes
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseNodes( idLexer &src ) {
|
|
int numNodes, i;
|
|
aasNode_t node;
|
|
|
|
numNodes = src.ParseInt();
|
|
nodes.Resize( numNodes );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numNodes; i++ ) {
|
|
src.ParseInt();
|
|
src.ExpectTokenString( "(" );
|
|
node.planeNum = src.ParseInt();
|
|
node.children[0] = src.ParseInt();
|
|
node.children[1] = src.ParseInt();
|
|
src.ExpectTokenString( ")" );
|
|
nodes.Append( node );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParsePortals
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParsePortals( idLexer &src ) {
|
|
int numPortals, i;
|
|
aasPortal_t portal;
|
|
|
|
numPortals = src.ParseInt();
|
|
portals.Resize( numPortals );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numPortals; i++ ) {
|
|
src.ParseInt();
|
|
src.ExpectTokenString( "(" );
|
|
portal.areaNum = src.ParseInt();
|
|
portal.clusters[0] = src.ParseInt();
|
|
portal.clusters[1] = src.ParseInt();
|
|
portal.clusterAreaNum[0] = src.ParseInt();
|
|
portal.clusterAreaNum[1] = src.ParseInt();
|
|
src.ExpectTokenString( ")" );
|
|
portals.Append( portal );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ParseClusters
|
|
================
|
|
*/
|
|
bool idAASFileLocal::ParseClusters( idLexer &src ) {
|
|
int numClusters, i;
|
|
aasCluster_t cluster;
|
|
|
|
numClusters = src.ParseInt();
|
|
clusters.Resize( numClusters );
|
|
if ( !src.ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
for ( i = 0; i < numClusters; i++ ) {
|
|
src.ParseInt();
|
|
src.ExpectTokenString( "(" );
|
|
cluster.numAreas = src.ParseInt();
|
|
cluster.numReachableAreas = src.ParseInt();
|
|
cluster.firstPortal = src.ParseInt();
|
|
cluster.numPortals = src.ParseInt();
|
|
src.ExpectTokenString( ")" );
|
|
clusters.Append( cluster );
|
|
}
|
|
if ( !src.ExpectTokenString( "}" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::FinishAreas
|
|
================
|
|
*/
|
|
void idAASFileLocal::FinishAreas( void ) {
|
|
int i;
|
|
|
|
for ( i = 0; i < areas.Num(); i++ ) {
|
|
areas[i].center = AreaReachableGoal( i );
|
|
areas[i].bounds = AreaBounds( i );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::Load
|
|
================
|
|
*/
|
|
bool idAASFileLocal::Load( const idStr &fileName, unsigned int mapFileCRC ) {
|
|
idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWPATHNAMES );
|
|
idToken token;
|
|
int depth;
|
|
unsigned int c;
|
|
|
|
name = fileName;
|
|
crc = mapFileCRC;
|
|
|
|
common->Printf( "[Load AAS]\n" );
|
|
common->Printf( "loading %s\n", name.c_str() );
|
|
|
|
if ( !src.LoadFile( name ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !src.ExpectTokenString( AAS_FILEID ) ) {
|
|
common->Warning( "Not an AAS file: '%s'", name.c_str() );
|
|
return false;
|
|
}
|
|
|
|
if ( !src.ReadToken( &token ) || token != AAS_FILEVERSION ) {
|
|
common->Warning( "AAS file '%s' has version %s instead of %s", name.c_str(), token.c_str(), AAS_FILEVERSION );
|
|
return false;
|
|
}
|
|
|
|
if ( !src.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
|
|
common->Warning( "AAS file '%s' has no map file CRC", name.c_str() );
|
|
return false;
|
|
}
|
|
|
|
c = token.GetUnsignedIntValue();
|
|
if ( mapFileCRC && c != mapFileCRC ) {
|
|
common->Warning( "AAS file '%s' is out of date", name.c_str() );
|
|
return false;
|
|
}
|
|
|
|
// clear the file in memory
|
|
Clear();
|
|
|
|
// parse the file
|
|
while ( 1 ) {
|
|
if ( !src.ReadToken( &token ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( token == "settings" ) {
|
|
if ( !settings.FromParser( src ) ) { return false; }
|
|
}
|
|
else if ( token == "planes" ) {
|
|
if ( !ParsePlanes( src ) ) { return false; }
|
|
}
|
|
else if ( token == "vertices" ) {
|
|
if ( !ParseVertices( src ) ) { return false; }
|
|
}
|
|
else if ( token == "edges" ) {
|
|
if ( !ParseEdges( src ) ) { return false; }
|
|
}
|
|
else if ( token == "edgeIndex" ) {
|
|
if ( !ParseIndex( src, edgeIndex ) ) { return false; }
|
|
}
|
|
else if ( token == "faces" ) {
|
|
if ( !ParseFaces( src ) ) { return false; }
|
|
}
|
|
else if ( token == "faceIndex" ) {
|
|
if ( !ParseIndex( src, faceIndex ) ) { return false; }
|
|
}
|
|
else if ( token == "areas" ) {
|
|
if ( !ParseAreas( src ) ) { return false; }
|
|
}
|
|
else if ( token == "nodes" ) {
|
|
if ( !ParseNodes( src ) ) { return false; }
|
|
}
|
|
else if ( token == "portals" ) {
|
|
if ( !ParsePortals( src ) ) { return false; }
|
|
}
|
|
else if ( token == "portalIndex" ) {
|
|
if ( !ParseIndex( src, portalIndex ) ) { return false; }
|
|
}
|
|
else if ( token == "clusters" ) {
|
|
if ( !ParseClusters( src ) ) { return false; }
|
|
}
|
|
else {
|
|
src.Error( "idAASFileLocal::Load: bad token \"%s\"", token.c_str() );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
FinishAreas();
|
|
|
|
depth = MaxTreeDepth();
|
|
if ( depth > MAX_AAS_TREE_DEPTH ) {
|
|
src.Error( "idAASFileLocal::Load: tree depth = %d", depth );
|
|
}
|
|
|
|
common->Printf( "done.\n" );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::MemorySize
|
|
================
|
|
*/
|
|
int idAASFileLocal::MemorySize( void ) const {
|
|
int size;
|
|
|
|
size = planeList.Size();
|
|
size += vertices.Size();
|
|
size += edges.Size();
|
|
size += edgeIndex.Size();
|
|
size += faces.Size();
|
|
size += faceIndex.Size();
|
|
size += areas.Size();
|
|
size += nodes.Size();
|
|
size += portals.Size();
|
|
size += portalIndex.Size();
|
|
size += clusters.Size();
|
|
size += sizeof( idReachability_Walk ) * NumReachabilities();
|
|
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::PrintInfo
|
|
================
|
|
*/
|
|
void idAASFileLocal::PrintInfo( void ) const {
|
|
common->Printf( "%6d KB file size\n", MemorySize() >> 10 );
|
|
common->Printf( "%6d areas\n", areas.Num() );
|
|
common->Printf( "%6d max tree depth\n", MaxTreeDepth() );
|
|
ReportRoutingEfficiency();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::NumReachabilities
|
|
================
|
|
*/
|
|
int idAASFileLocal::NumReachabilities( void ) const {
|
|
int i, num;
|
|
idReachability *reach;
|
|
|
|
num = 0;
|
|
for ( i = 0; i < areas.Num(); i++ ) {
|
|
for ( reach = areas[i].reach; reach; reach = reach->next ) {
|
|
num++;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::ReportRoutingEfficiency
|
|
================
|
|
*/
|
|
void idAASFileLocal::ReportRoutingEfficiency( void ) const {
|
|
int numReachableAreas, total, i, n;
|
|
|
|
numReachableAreas = 0;
|
|
total = 0;
|
|
for ( i = 0; i < clusters.Num(); i++ ) {
|
|
n = clusters[i].numReachableAreas;
|
|
numReachableAreas += n;
|
|
total += n * n;
|
|
}
|
|
total += numReachableAreas * portals.Num();
|
|
|
|
common->Printf( "%6d reachable areas\n", numReachableAreas );
|
|
common->Printf( "%6d reachabilities\n", NumReachabilities() );
|
|
common->Printf( "%6d KB max routing cache\n", ( total * 3 ) >> 10 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::DeleteReachabilities
|
|
================
|
|
*/
|
|
void idAASFileLocal::DeleteReachabilities( void ) {
|
|
int i;
|
|
idReachability *reach, *nextReach;
|
|
|
|
for ( i = 0; i < areas.Num(); i++ ) {
|
|
for ( reach = areas[i].reach; reach; reach = nextReach ) {
|
|
nextReach = reach->next;
|
|
delete reach;
|
|
}
|
|
areas[i].reach = NULL;
|
|
areas[i].rev_reach = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idAASFileLocal::DeleteClusters
|
|
================
|
|
*/
|
|
void idAASFileLocal::DeleteClusters( void ) {
|
|
aasPortal_t portal;
|
|
aasCluster_t cluster;
|
|
|
|
portals.Clear();
|
|
portalIndex.Clear();
|
|
clusters.Clear();
|
|
|
|
// first portal is a dummy
|
|
memset( &portal, 0, sizeof( portal ) );
|
|
portals.Append( portal );
|
|
|
|
// first cluster is a dummy
|
|
memset( &cluster, 0, sizeof( cluster ) );
|
|
clusters.Append( cluster );
|
|
}
|