/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).
RTCW MP 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.
RTCW MP 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 RTCW MP Source Code. If not, see .
In addition, the RTCW MP 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 RTCW MP 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.
===========================================================================
*/
//===========================================================================
//
// Name: BSP tool
// Function:
// Programmer: id Software & Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
// Notes: Microsoft Visual C++ optimizations:
// "global optimization" or "full optimization" results
// in micro brushes??
//===========================================================================
#if defined( WIN32 ) || defined( _WIN32 )
#include
#include
#include
#include
#else
#include
#include
#include
#include
#endif
#include "qbsp.h"
#include "l_mem.h"
//#include "l_qfiles.h"
#include "..\botlib\aasfile.h"
#include "..\botlib\be_aas_cluster.h"
#include "..\botlib\be_aas_optimize.h"
#include "aas_create.h"
#include "aas_store.h"
#include "aas_file.h"
#include "aas_cfg.h"
#include "be_aas_bspc.h"
#define BSPC_VERSION "2.1c"
extern int use_nodequeue; //brushbsp.c
extern int calcgrapplereach; //be_aas_reach.c
float subdivide_size = 240;
char source[1024];
char name[1024];
vec_t microvolume = 1.0;
char outbase[32];
int entity_num;
aas_settings_t aassettings;
qboolean noprune; //don't prune nodes (bspc.c)
qboolean glview; //create a gl view
qboolean nodetail; //don't use detail brushes (map.c)
qboolean fulldetail; //use but don't mark detail brushes (map.c)
qboolean onlyents; //only process the entities (bspc.c)
qboolean nomerge; //don't merge bsp node faces (faces.c)
qboolean nowater; //don't use the water brushes (map.c)
qboolean nocsg; //don't carve intersecting brushes (bspc.c)
qboolean noweld; //use unique face vertexes (faces.c)
qboolean noshare; //don't share bsp edges (faces.c)
qboolean nosubdiv; //don't subdivide bsp node faces (faces.c)
qboolean notjunc; //don't create tjunctions (edge melting) (faces.c)
qboolean optimize; //enable optimisation
qboolean leaktest; //perform a leak test
qboolean verboseentities;
qboolean freetree; //free the bsp tree when not needed anymore
qboolean create_aas; //create an .AAS file
qboolean nobrushmerge; //don't merge brushes
qboolean lessbrushes; //create less brushes instead of correct texture placement
qboolean cancelconversion; //true if the conversion is being cancelled
qboolean noliquids; //no liquids when writing map file
qboolean forcesidesvisible; //force all brush sides to be visible when loaded from bsp
// qboolean capsule_collision = true; //use capsule collision
qboolean capsule_collision = false; // capsule collision// Ridah, allow to specify an extension for multiple AAS files per map
char aas_extension[64];
// done.
float VectorDistance( vec3_t v1, vec3_t v2 ) {
vec3_t dir;
VectorSubtract( v2, v1, dir );
return VectorLength( dir );
}
/*
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void ProcessWorldModel (void)
{
entity_t *e;
tree_t *tree;
qboolean leaked;
int brush_start, brush_end;
e = &entities[entity_num];
brush_start = e->firstbrush;
brush_end = brush_start + e->numbrushes;
leaked = false;
//process the whole world in one time
tree = ProcessWorldBrushes(brush_start, brush_end);
//create the bsp tree portals
MakeTreePortals(tree);
//mark all leafs that can be reached by entities
if (FloodEntities(tree))
{
FillOutside(tree->headnode);
} //end if
else
{
Log_Print("**** leaked ****\n");
leaked = true;
LeakFile(tree);
if (leaktest)
{
Log_Print("--- MAP LEAKED ---\n");
exit(0);
} //end if
} //end else
MarkVisibleSides (tree, brush_start, brush_end);
FloodAreas (tree);
#ifndef ME
if (glview) WriteGLView(tree, source);
#endif
MakeFaces(tree->headnode);
FixTjuncs(tree->headnode);
//NOTE: Never prune the nodes because the portals
// are screwed when prunning is done and as
// a result portal writing will crash
//if (!noprune) PruneNodes(tree->headnode);
WriteBSP(tree->headnode);
if (!leaked) WritePortalFile(tree);
Tree_Free(tree);
} //end of the function ProcessWorldModel
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void ProcessSubModel (void)
{
entity_t *e;
int start, end;
tree_t *tree;
bspbrush_t *list;
vec3_t mins, maxs;
e = &entities[entity_num];
start = e->firstbrush;
end = start + e->numbrushes;
mins[0] = mins[1] = mins[2] = -4096;
maxs[0] = maxs[1] = maxs[2] = 4096;
list = MakeBspBrushList(start, end, mins, maxs);
if (!nocsg) list = ChopBrushes (list);
tree = BrushBSP (list, mins, maxs);
MakeTreePortals (tree);
MarkVisibleSides (tree, start, end);
MakeFaces (tree->headnode);
FixTjuncs (tree->headnode);
WriteBSP (tree->headnode);
Tree_Free (tree);
} //end of the function ProcessSubModel
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void ProcessModels (void)
{
BeginBSPFile();
for (entity_num = 0; entity_num < num_entities; entity_num++)
{
if (!entities[entity_num].numbrushes)
continue;
Log_Print("############### model %i ###############\n", nummodels);
BeginModel();
if (entity_num == 0) ProcessWorldModel();
else ProcessSubModel();
EndModel();
if (!verboseentities)
verbose = false; // don't bother printing submodels
} //end for
EndBSPFile();
} //end of the function ProcessModels
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Win_Map2Bsp(char *bspfilename)
{
double start, end;
char path[1024];
start = I_FloatTime();
ThreadSetDefault();
//yeah sure Carmack
//numthreads = 1; // multiple threads aren't helping...
strcpy(source, ExpandArg(bspfilename));
StripExtension(source);
//delete portal and line files
sprintf(path, "%s.prt", source);
remove(path);
sprintf(path, "%s.lin", source);
remove(path);
strcpy(name, ExpandArg(bspfilename));
DefaultExtension(name, ".map"); // might be .reg
Q2_AllocMaxBSP();
//
SetModelNumbers();
SetLightStyles();
ProcessModels();
//write the BSP
Q2_WriteBSPFile(bspfilename);
Q2_FreeMaxBSP();
end = I_FloatTime();
Log_Print("%5.0f seconds elapsed\n", end-start);
} //end of the function Win_Map2Bsp
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Map2Bsp(char *mapfilename, char *outputfilename)
{
double start, end;
char path[1024];
start = I_FloatTime ();
ThreadSetDefault ();
//yeah sure Carmack
//numthreads = 1; //multiple threads aren't helping...
//SetQdirFromPath(bspfilename);
strcpy(source, ExpandArg(mapfilename));
StripExtension(source);
// delete portal and line files
sprintf(path, "%s.prt", source);
remove(path);
sprintf(path, "%s.lin", source);
remove(path);
strcpy(name, ExpandArg(mapfilename));
DefaultExtension(name, ".map"); // might be .reg
//
// if onlyents, just grab the entites and resave
//
if (onlyents)
{
char out[1024];
Q2_AllocMaxBSP();
sprintf (out, "%s.bsp", source);
Q2_LoadBSPFile(out, 0, 0);
num_entities = 0;
Q2_LoadMapFile(name);
SetModelNumbers();
SetLightStyles();
Q2_UnparseEntities();
Q2_WriteBSPFile(out);
//
Q2_FreeMaxBSP();
} //end if
else
{
//
// start from scratch
//
Q2_AllocMaxBSP();
//load the map
Q2_LoadMapFile(name);
//create the .bsp file
SetModelNumbers();
SetLightStyles();
ProcessModels();
//write the BSP
Q2_WriteBSPFile(outputfilename);
//
Q2_FreeMaxBSP();
} //end else
end = I_FloatTime();
Log_Print("%5.0f seconds elapsed\n", end-start);
} //end of the function Map2Bsp
*/
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AASOuputFile( quakefile_t *qf, char *outputpath, char *filename ) {
char ext[MAX_PATH];
//
if ( strlen( outputpath ) ) {
strcpy( filename, outputpath );
//append the bsp file base
AppendPathSeperator( filename, MAX_PATH );
ExtractFileBase( qf->origname, &filename[strlen( filename )] );
// Ridah, add extension
strcat( filename, aas_extension );
// done.
//append .aas
strcat( filename, ".aas" );
return;
} //end if
//
ExtractFileExtension( qf->filename, ext );
if ( !stricmp( ext, "pk3" ) || !stricmp( ext, "pak" ) || !stricmp( ext, "sin" ) ) {
strcpy( filename, qf->filename );
while ( strlen( filename ) &&
filename[strlen( filename ) - 1] != '\\' &&
filename[strlen( filename ) - 1] != '/' )
{
filename[strlen( filename ) - 1] = '\0';
} //end while
strcat( filename, "maps" );
if ( access( filename, 0x04 ) ) {
CreatePath( filename );
}
//append the bsp file base
AppendPathSeperator( filename, MAX_PATH );
ExtractFileBase( qf->origname, &filename[strlen( filename )] );
// Ridah, add extension
strcat( filename, aas_extension );
// done.
//append .aas
strcat( filename, ".aas" );
} //end if
else
{
strcpy( filename, qf->filename );
while ( strlen( filename ) &&
filename[strlen( filename ) - 1] != '.' )
{
filename[strlen( filename ) - 1] = '\0';
} //end while
// Ridah, add extension
strcat( filename, aas_extension );
// done.
strcat( filename, "aas" );
} //end else
} //end of the function AASOutputFile
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void CreateAASFilesForAllBSPFiles( char *quakepath ) {
#if defined( WIN32 ) | defined( _WIN32 )
WIN32_FIND_DATA filedata;
HWND handle;
struct _stat statbuf;
#else
glob_t globbuf;
struct stat statbuf;
int j;
#endif
int done;
char filter[_MAX_PATH], bspfilter[_MAX_PATH], aasfilter[_MAX_PATH];
char aasfile[_MAX_PATH], buf[_MAX_PATH], foldername[_MAX_PATH];
quakefile_t *qf, *qf2, *files, *bspfiles, *aasfiles;
strcpy( filter, quakepath );
AppendPathSeperator( filter, sizeof( filter ) );
strcat( filter, "*" );
#if defined( WIN32 ) | defined( _WIN32 )
handle = FindFirstFile( filter, &filedata );
done = ( handle == INVALID_HANDLE_VALUE );
while ( !done )
{
_splitpath( filter, foldername, NULL, NULL, NULL );
_splitpath( filter, NULL, &foldername[strlen( foldername )], NULL, NULL );
AppendPathSeperator( foldername, _MAX_PATH );
strcat( foldername, filedata.cFileName );
_stat( foldername, &statbuf );
#else
glob( filter, 0, NULL, &globbuf );
for ( j = 0; j < globbuf.gl_pathc; j++ )
{
strcpy( foldername, globbuf.gl_pathv[j] );
stat( foldername, &statbuf );
#endif
//if it is a folder
if ( statbuf.st_mode & S_IFDIR ) {
//
AppendPathSeperator( foldername, sizeof( foldername ) );
//get all the bsp files
strcpy( bspfilter, foldername );
strcat( bspfilter, "maps/*.bsp" );
files = FindQuakeFiles( bspfilter );
strcpy( bspfilter, foldername );
strcat( bspfilter, "*.pk3/maps/*.bsp" );
bspfiles = FindQuakeFiles( bspfilter );
for ( qf = bspfiles; qf; qf = qf->next ) if ( !qf->next ) {
break;
}
if ( qf ) {
qf->next = files;
} else { bspfiles = files;}
//get all the aas files
strcpy( aasfilter, foldername );
strcat( aasfilter, "maps/*.aas" );
files = FindQuakeFiles( aasfilter );
strcpy( aasfilter, foldername );
strcat( aasfilter, "*.pk3/maps/*.aas" );
aasfiles = FindQuakeFiles( aasfilter );
for ( qf = aasfiles; qf; qf = qf->next ) if ( !qf->next ) {
break;
}
if ( qf ) {
qf->next = files;
} else { aasfiles = files;}
//
for ( qf = bspfiles; qf; qf = qf->next )
{
sprintf( aasfile, "%s/%s", qf->pakfile, qf->origname );
Log_Print( "found %s\n", aasfile );
strcpy( &aasfile[strlen( aasfile ) - strlen( ".bsp" )], ".aas" );
for ( qf2 = aasfiles; qf2; qf2 = qf2->next )
{
sprintf( buf, "%s/%s", qf2->pakfile, qf2->origname );
if ( !stricmp( aasfile, buf ) ) {
Log_Print( "found %s\n", buf );
break;
} //end if
} //end for
} //end for
} //end if
#if defined( WIN32 ) | defined( _WIN32 )
//find the next file
done = !FindNextFile( handle, &filedata );
} //end while
#else
} //end for
globfree( &globbuf );
#endif
} //end of the function CreateAASFilesForAllBSPFiles
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
quakefile_t *GetArgumentFiles( int argc, char *argv[], int *i, char *ext ) {
quakefile_t *qfiles, *lastqf, *qf;
int j;
char buf[1024];
qfiles = NULL;
lastqf = NULL;
for (; ( *i ) + 1 < argc && argv[( *i ) + 1][0] != '-'; ( *i )++ )
{
strcpy( buf, argv[( *i ) + 1] );
for ( j = strlen( buf ) - 1; j >= strlen( buf ) - 4; j-- )
if ( buf[j] == '.' ) {
break;
}
if ( j >= strlen( buf ) - 4 ) {
strcpy( &buf[j + 1], ext );
}
qf = FindQuakeFiles( buf );
if ( !qf ) {
continue;
}
if ( lastqf ) {
lastqf->next = qf;
} else { qfiles = qf;}
lastqf = qf;
while ( lastqf->next ) lastqf = lastqf->next;
} //end for
return qfiles;
} //end of the function GetArgumentFiles
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
#define COMP_BSP2MAP 1
#define COMP_BSP2AAS 2
#define COMP_REACH 3
#define COMP_CLUSTER 4
#define COMP_AASOPTIMIZE 5
#define COMP_AASINFO 6
#define COMP_TETRA 7
int main( int argc, char **argv ) {
int i, comp = 0;
char outputpath[MAX_PATH] = "";
char filename[MAX_PATH] = "unknown";
quakefile_t *qfiles, *qf;
// Ridah, allow to specify an extension for multiple AAS files per map
int has_ext = 0;
// done.
// Ridah, set the world pointer up for reachabilities
aasworld = aasworlds;
AAS_SetWorldPointer( &( *aasworld ) );
// done.
myargc = argc;
myargv = argv;
Log_Open( "bspc.log" ); //open a log file
Log_Print( "BSPC version " BSPC_VERSION ", %s %s by Mr Elusive\n", __DATE__, __TIME__ );
DefaultCfg();
for ( i = 1; i < argc; i++ )
{
if ( !stricmp( argv[i],"-threads" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
numthreads = atoi( argv[++i] );
Log_Print( "threads = %d\n", numthreads );
} //end if
else if ( !stricmp( argv[i], "-noverbose" ) ) {
Log_Print( "verbose = false\n" );
verbose = false;
} //end else if
else if ( !stricmp( argv[i], "-nocsg" ) ) {
Log_Print( "nocsg = true\n" );
nocsg = true;
} //end else if
else if ( !stricmp( argv[i], "-optimize" ) ) {
Log_Print( "optimize = true\n" );
optimize = true;
} //end else if
/*
else if (!stricmp(argv[i],"-glview"))
{
glview = true;
} //end else if
else if (!stricmp(argv[i], "-draw"))
{
Log_Print("drawflag = true\n");
drawflag = true;
} //end else if
else if (!stricmp(argv[i], "-noweld"))
{
Log_Print("noweld = true\n");
noweld = true;
} //end else if
else if (!stricmp(argv[i], "-noshare"))
{
Log_Print("noshare = true\n");
noshare = true;
} //end else if
else if (!stricmp(argv[i], "-notjunc"))
{
Log_Print("notjunc = true\n");
notjunc = true;
} //end else if
else if (!stricmp(argv[i], "-nowater"))
{
Log_Print("nowater = true\n");
nowater = true;
} //end else if
else if (!stricmp(argv[i], "-noprune"))
{
Log_Print("noprune = true\n");
noprune = true;
} //end else if
else if (!stricmp(argv[i], "-nomerge"))
{
Log_Print("nomerge = true\n");
nomerge = true;
} //end else if
else if (!stricmp(argv[i], "-nosubdiv"))
{
Log_Print("nosubdiv = true\n");
nosubdiv = true;
} //end else if
else if (!stricmp(argv[i], "-nodetail"))
{
Log_Print("nodetail = true\n");
nodetail = true;
} //end else if
else if (!stricmp(argv[i], "-fulldetail"))
{
Log_Print("fulldetail = true\n");
fulldetail = true;
} //end else if
else if (!stricmp(argv[i], "-onlyents"))
{
Log_Print("onlyents = true\n");
onlyents = true;
} //end else if
else if (!stricmp(argv[i], "-micro"))
{
if (i + 1 >= argc) {i = 0; break;}
microvolume = atof(argv[++i]);
Log_Print("microvolume = %f\n", microvolume);
} //end else if
else if (!stricmp(argv[i], "-leaktest"))
{
Log_Print("leaktest = true\n");
leaktest = true;
} //end else if
else if (!stricmp(argv[i], "-verboseentities"))
{
Log_Print("verboseentities = true\n");
verboseentities = true;
} //end else if
else if (!stricmp(argv[i], "-chop"))
{
if (i + 1 >= argc) {i = 0; break;}
subdivide_size = atof(argv[++i]);
Log_Print("subdivide_size = %f\n", subdivide_size);
} //end else if
else if (!stricmp (argv[i], "-tmpout"))
{
strcpy (outbase, "/tmp");
Log_Print("temp output\n");
} //end else if
*/
#ifdef ME
else if ( !stricmp( argv[i], "-freetree" ) ) {
freetree = true;
Log_Print( "freetree = true\n" );
} //end else if
else if ( !stricmp( argv[i], "-grapplereach" ) ) {
calcgrapplereach = true;
Log_Print( "grapplereach = true\n" );
} //end else if
else if ( !stricmp( argv[i], "-nobrushmerge" ) ) {
nobrushmerge = true;
Log_Print( "nobrushmerge = true\n" );
} //end else if
else if ( !stricmp( argv[i], "-noliquids" ) ) {
noliquids = true;
Log_Print( "noliquids = true\n" );
} //end else if
else if ( !stricmp( argv[i], "-forcesidesvisible" ) ) {
forcesidesvisible = true;
Log_Print( "forcesidesvisible = true\n" );
} //end else if
else if ( !stricmp( argv[i], "-output" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
if ( access( argv[i + 1], 0x04 ) ) {
Warning( "the folder %s does not exist", argv[i + 1] );
}
strcpy( outputpath, argv[++i] );
} //end else if
else if ( !stricmp( argv[i], "-breadthfirst" ) ) {
use_nodequeue = true;
Log_Print( "breadthfirst = true\n" );
} //end else if
else if ( !stricmp( argv[i], "-cfg" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
if ( !LoadCfgFile( argv[++i] ) ) {
exit( 0 );
}
} //end else if
else if ( !stricmp( argv[i], "-bsp2map" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
comp = COMP_BSP2MAP;
qfiles = GetArgumentFiles( argc, argv, &i, "bsp" );
} //end else if
else if ( !stricmp( argv[i], "-bsp2aas" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
comp = COMP_BSP2AAS;
qfiles = GetArgumentFiles( argc, argv, &i, "bsp" );
} //end else if
else if ( !stricmp( argv[i], "-aasall" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
CreateAASFilesForAllBSPFiles( argv[++i] );
} //end else if
else if ( !stricmp( argv[i], "-reach" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
comp = COMP_REACH;
qfiles = GetArgumentFiles( argc, argv, &i, "bsp" );
} //end else if
else if ( !stricmp( argv[i], "-cluster" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
comp = COMP_CLUSTER;
qfiles = GetArgumentFiles( argc, argv, &i, "bsp" );
} //end else if
else if ( !stricmp( argv[i], "-aasinfo" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
comp = COMP_AASINFO;
qfiles = GetArgumentFiles( argc, argv, &i, "aas" );
} //end else if
else if ( !stricmp( argv[i], "-aasopt" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
comp = COMP_AASOPTIMIZE;
qfiles = GetArgumentFiles( argc, argv, &i, "aas" );
} //end else if
else if ( !stricmp( argv[i], "-tetra" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
comp = COMP_TETRA;
qfiles = GetArgumentFiles( argc, argv, &i, "aas" );
} //end else if
// Ridah, allow to specify an extension for multiple AAS files per map
else if ( !stricmp( argv[i], "-ext" ) ) {
if ( i + 1 >= argc ) {
i = 0; break;
}
strcpy( aas_extension, argv[++i] );
has_ext = 1;
} //end else if
// done.
#endif //ME
else
{
Log_Print( "unknown parameter %s\n", argv[i] );
break;
} //end else
} //end for
//if there are parameters and there's no mismatch in one of the parameters
if ( argc > 1 && i == argc ) {
switch ( comp )
{
case COMP_BSP2MAP:
{
if ( !qfiles ) {
Log_Print( "no files found\n" );
}
for ( qf = qfiles; qf; qf = qf->next )
{
//copy the output path
strcpy( filename, outputpath );
//append the bsp file base
AppendPathSeperator( filename, MAX_PATH );
ExtractFileBase( qf->origname, &filename[strlen( filename )] );
//append .map
strcat( filename, ".map" );
//
Log_Print( "bsp2map: %s to %s\n", qf->origname, filename );
if ( qf->type != QFILETYPE_BSP ) {
Warning( "%s is probably not a BSP file\n", qf->origname );
}
//
LoadMapFromBSP( qf );
//write the map file
WriteMapFile( filename );
} //end for
break;
} //end case
case COMP_BSP2AAS:
{
if ( !qfiles ) {
Log_Print( "no files found\n" );
}
for ( qf = qfiles; qf; qf = qf->next )
{
AASOuputFile( qf, outputpath, filename );
//
Log_Print( "bsp2aas: %s to %s\n", qf->origname, filename );
if ( qf->type != QFILETYPE_BSP ) {
Warning( "%s is probably not a BSP file\n", qf->origname );
}
//set before map loading
create_aas = 1;
LoadMapFromBSP( qf );
//create the AAS file
AAS_Create( filename );
//if it's a Quake3 map calculate the reachabilities and clusters
if ( loadedmaptype == MAPTYPE_QUAKE3 ) {
AAS_CalcReachAndClusters( qf );
}
//
if ( optimize ) {
AAS_Optimize();
}
//
//write out the stored AAS file
if ( !AAS_WriteAASFile( filename ) ) {
Error( "error writing %s\n", filename );
} //end if
//deallocate memory
AAS_FreeMaxAAS();
} //end for
break;
} //end case
case COMP_REACH:
{
if ( !qfiles ) {
Log_Print( "no files found\n" );
}
for ( qf = qfiles; qf; qf = qf->next )
{
AASOuputFile( qf, outputpath, filename );
//
Log_Print( "reach: %s to %s\n", qf->origname, filename );
if ( qf->type != QFILETYPE_BSP ) {
Warning( "%s is probably not a BSP file\n", qf->origname );
}
//if the AAS file exists in the output directory
if ( !access( filename, 0x04 ) ) {
if ( !AAS_LoadAASFile( filename, 0, 0 ) ) {
Error( "error loading aas file %s\n", filename );
} //end if
//assume it's a Quake3 BSP file
loadedmaptype = MAPTYPE_QUAKE3;
} //end if
else
{
Warning( "AAS file %s not found in output folder\n", filename );
Log_Print( "creating %s...\n", filename );
//set before map loading
create_aas = 1;
LoadMapFromBSP( qf );
//create the AAS file
AAS_Create( filename );
} //end else
//if it's a Quake3 map calculate the reachabilities and clusters
if ( loadedmaptype == MAPTYPE_QUAKE3 ) {
AAS_CalcReachAndClusters( qf );
} //end if
//
if ( optimize ) {
AAS_Optimize();
}
//write out the stored AAS file
if ( !AAS_WriteAASFile( filename ) ) {
Error( "error writing %s\n", filename );
} //end if
//deallocate memory
AAS_FreeMaxAAS();
} //end for
break;
} //end case
case COMP_CLUSTER:
{
if ( !qfiles ) {
Log_Print( "no files found\n" );
}
for ( qf = qfiles; qf; qf = qf->next )
{
AASOuputFile( qf, outputpath, filename );
//
Log_Print( "cluster: %s to %s\n", qf->origname, filename );
if ( qf->type != QFILETYPE_BSP ) {
Warning( "%s is probably not a BSP file\n", qf->origname );
}
//if the AAS file exists in the output directory
if ( !access( filename, 0x04 ) ) {
if ( !AAS_LoadAASFile( filename, 0, 0 ) ) {
Error( "error loading aas file %s\n", filename );
} //end if
//assume it's a Quake3 BSP file
loadedmaptype = MAPTYPE_QUAKE3;
//if it's a Quake3 map calculate the clusters
if ( loadedmaptype == MAPTYPE_QUAKE3 ) {
( *aasworld ).numclusters = 0;
AAS_InitBotImport();
AAS_InitClustering();
} //end if
} //end if
else
{
Warning( "AAS file %s not found in output folder\n", filename );
Log_Print( "creating %s...\n", filename );
//set before map loading
create_aas = 1;
LoadMapFromBSP( qf );
//create the AAS file
AAS_Create( filename );
//if it's a Quake3 map calculate the reachabilities and clusters
if ( loadedmaptype == MAPTYPE_QUAKE3 ) {
AAS_CalcReachAndClusters( qf );
}
} //end else
//
if ( optimize ) {
AAS_Optimize();
}
//write out the stored AAS file
if ( !AAS_WriteAASFile( filename ) ) {
Error( "error writing %s\n", filename );
} //end if
//deallocate memory
AAS_FreeMaxAAS();
} //end for
break;
} //end case
case COMP_AASOPTIMIZE:
{
if ( !qfiles ) {
Log_Print( "no files found\n" );
}
for ( qf = qfiles; qf; qf = qf->next )
{
AASOuputFile( qf, outputpath, filename );
//
Log_Print( "optimizing: %s to %s\n", qf->origname, filename );
if ( qf->type != QFILETYPE_AAS ) {
Warning( "%s is probably not a AAS file\n", qf->origname );
}
//
AAS_InitBotImport();
//
if ( !AAS_LoadAASFile( qf->filename, qf->offset, qf->length ) ) {
Error( "error loading aas file %s\n", qf->filename );
} //end if
AAS_Optimize();
//write out the stored AAS file
if ( !AAS_WriteAASFile( filename ) ) {
Error( "error writing %s\n", filename );
} //end if
//deallocate memory
AAS_FreeMaxAAS();
} //end for
break;
} //end case
case COMP_AASINFO:
{
if ( !qfiles ) {
Log_Print( "no files found\n" );
}
for ( qf = qfiles; qf; qf = qf->next )
{
AASOuputFile( qf, outputpath, filename );
//
Log_Print( "aas info for: %s\n", filename );
if ( qf->type != QFILETYPE_AAS ) {
Warning( "%s is probably not a AAS file\n", qf->origname );
}
//
AAS_InitBotImport();
//
if ( !AAS_LoadAASFile( qf->filename, qf->offset, qf->length ) ) {
Error( "error loading aas file %s\n", qf->filename );
} //end if
AAS_ShowTotals();
} //end for
} //end case
case COMP_TETRA:
{
if ( !qfiles ) {
Log_Print( "no files found\n" );
}
for ( qf = qfiles; qf; qf = qf->next )
{
//TH_AASToTetrahedrons(qf->filename);
} //end for
break;
} //end case
default:
{
Log_Print( "don't know what to do\n" );
break;
} //end default
} //end switch
} //end if
else
{
Log_Print( "Usage: bspc [- [- ...]]\n"
#if defined( WIN32 ) || defined( _WIN32 )
"Example 1: bspc -bsp2aas d:\\quake3\\baseq3\\maps\\mymap?.bsp\n"
"Example 2: bspc -bsp2aas d:\\quake3\\baseq3\\pak0.pk3\\maps/q3dm*.bsp\n"
#else
"Example 1: bspc -bsp2aas /quake3/baseq3/maps/mymap?.bsp\n"
"Example 2: bspc -bsp2aas /quake3/baseq3/pak0.pk3/maps/q3dm*.bsp\n"
#endif
"\n"
"Switches:\n"
//" bsp2map <[pakfilter/]filter.bsp> = convert BSP to MAP\n"
" bsp2aas <[pakfilter/]filter.bsp> = convert BSP to AAS\n"
//" aasall = create AAS files for all BSPs\n"
" reach = compute reachability & clusters\n"
" cluster = compute clusters\n"
" aasopt = optimize aas file\n"
//" tetra = tetrahedral decomposition\n"
" output