//=========================================================================== // // 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
//=========================================================================== // find a Quake2 file // returns full path in 'filename' // sets offset and length of the file // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== qboolean FindQuakeFile2( char *basedir, char *gamedir, char *filename, foundfile_t *file ) { int dir, i; //NOTE: 3 is necessary (LCC bug???) char gamedirs[3][MAX_PATH] = {"","",""}; char filedir[MAX_PATH] = ""; // if ( gamedir ) { strncpy( gamedirs[0], gamedir, MAX_PATH ); } strncpy( gamedirs[1], "baseq2", MAX_PATH ); // //find the file in the two game directories for ( dir = 0; dir < 2; dir++ ) { //check if the file is in a directory filedir[0] = 0; if ( basedir && strlen( basedir ) ) { strncpy( filedir, basedir, MAX_PATH ); AppendPathSeperator( filedir, MAX_PATH ); } //end if if ( strlen( gamedirs[dir] ) ) { strncat( filedir, gamedirs[dir], MAX_PATH - strlen( filedir ) ); AppendPathSeperator( filedir, MAX_PATH ); } //end if strncat( filedir, filename, MAX_PATH - strlen( filedir ) ); ConvertPath( filedir ); Log_Write( "accessing %s", filedir ); if ( !access( filedir, 0x04 ) ) { strcpy( file->filename, filedir ); file->length = 0; file->offset = 0; return true; } //end if //check if the file is in a pak?.pak for ( i = 0; i < 10; i++ ) { filedir[0] = 0; if ( basedir && strlen( basedir ) ) { strncpy( filedir, basedir, MAX_PATH ); AppendPathSeperator( filedir, MAX_PATH ); } //end if if ( strlen( gamedirs[dir] ) ) { strncat( filedir, gamedirs[dir], MAX_PATH - strlen( filedir ) ); AppendPathSeperator( filedir, MAX_PATH ); } //end if sprintf( &filedir[strlen( filedir )], "pak%d.pak", i ); if ( !access( filedir, 0x04 ) ) { Log_Write( "searching %s in %s", filename, filedir ); if ( FindFileInPak( filedir, filename, file ) ) { return true; } } //end if } //end for } //end for file->offset = 0; file->length = 0; return false; } //end of the function FindQuakeFile2
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 [-<switch> [-<switch> ...]]\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 <quake3folder> = create AAS files for all BSPs\n" " reach <filter.bsp> = compute reachability & clusters\n" " cluster <filter.aas> = compute clusters\n" " aasopt <filter.aas> = optimize aas file\n" //" tetra <filter.aas> = tetrahedral decomposition\n" " output <output path> = set output path\n" " threads <X> = set number of threads to X\n" " cfg <filename> = use this cfg file\n" " optimize = enable optimization\n" " noverbose = disable verbose output\n" " breadthfirst = breadth first bsp building\n" " nobrushmerge = don't merge brushes\n" " noliquids = don't write liquids to map\n" " freetree = free the bsp tree\n" " nocsg = disables brush chopping\n" " forcesidesvisible = force all sides to be visible\n" " grapplereach = calculate grapple reachabilities\n" /* " glview = output a GL view\n" " draw = enables drawing\n" " noweld = disables weld\n" " noshare = disables sharing\n" " notjunc = disables juncs\n" " nowater = disables water brushes\n" " noprune = disables node prunes\n" " nomerge = disables face merging\n" " nosubdiv = disables subdeviding\n" " nodetail = disables detail brushes\n" " fulldetail = enables full detail\n" " onlyents = only compile entities with bsp\n" " micro <volume>\n" " = sets the micro volume to the given float\n" " leaktest = perform a leak test\n" " verboseentities\n" " = enable entity verbose mode\n" " chop <subdivide_size>\n" " = sets the subdivide size to the given float\n"*/ "\n" ); } //end else Log_Close(); //close the log file return 0; } //end of the function main
//=========================================================================== // // 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
int main (int argc, char **argv) { int i, comp = 0; char outputpath[MAX_PATH] = ""; char filename[MAX_PATH] = "unknown"; quakefile_t *qfiles = NULL, *qf; double start_time; myargc = argc; myargv = argv; start_time = I_FloatTime(); Log_Open("bspc.log"); //open a log file Log_Print(BSPC_NAME" version "BSPC_VERSION", %s %s\n", __DATE__, __TIME__); #ifdef ZTMAUTOARGS calcgrapplereach = true; forcesidesvisible = true; // Currently always required or BSPC fails? #endif 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], "-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 */ 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 #ifdef ZTMAUTOARGS else if (!stricmp(argv[i], "-nograpplereach")) { calcgrapplereach = false; Log_Print("grapplereach = false\n"); } //end else if #endif 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 #ifdef ZTMAUTOARGS else if (!stricmp(argv[i], "-noforcesidesvisible")) { forcesidesvisible = false; Log_Print("forcesidesvisible = false\n"); } //end else if #endif 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], "-capsule")) { capsule_collision = true; Log_Print("capsule_collision = 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 { 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); //calculate the reachabilities and clusters 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)) { Error("error loading aas file %s\n", filename); } //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); } //end else //calculate the reachabilities and clusters 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_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)) { Error("error loading aas file %s\n", filename); } //end if //calculate the clusters AAS_RecalcClusters(); } //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); //calculate the reachabilities and clusters 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)) { 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)) { Error("error loading aas file %s\n", qf->filename); } //end if AAS_ShowTotals(); } //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 [-<switch> [-<switch> ...]]\n" #ifdef _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" //" aasall <quake3folder> = create AAS files for all BSPs\n" " bsp2aas <[pakfilter/]filter.bsp> = convert BSP to AAS\n" " reach <filter.bsp> = compute reachability & clusters\n" " cluster <filter.bsp> = compute clusters\n" " aasopt <filter.aas> = optimize aas file\n" " aasinfo <filter.aas> = show AAS file info\n" " output <output path> = set output path\n" " threads <X> = set number of threads to X\n" " cfg <filename> = use this cfg file\n" " optimize = enable optimization\n" " noverbose = disable verbose output\n" " breadthfirst = breadth first bsp building\n" " nobrushmerge = don't merge brushes\n" " noliquids = don't write liquids to map\n" " freetree = free the bsp tree\n" " nocsg = disables brush chopping\n" #ifdef ZTMAUTOARGS " noforcesidesvisible = don't force all sides to be visible\n" " nograpplereach = don't calculate grapple reachabilities\n" #else " forcesidesvisible = force all sides to be visible\n" " grapplereach = calculate grapple reachabilities\n" #endif /* " noweld = disables weld\n" " noshare = disables sharing\n" " notjunc = disables juncs\n" " nowater = disables water brushes\n" " noprune = disables node prunes\n" " nomerge = disables face merging\n" " nosubdiv = disables subdeviding\n" " nodetail = disables detail brushes\n" " fulldetail = enables full detail\n" " onlyents = only compile entities with bsp\n" " micro <volume>\n" " = sets the micro volume to the given float\n" " leaktest = perform a leak test\n" " verboseentities\n" " = enable entity verbose mode\n" " chop <subdivide_size>\n" " = sets the subdivide size to the given float\n"*/ "\n"); } //end else Log_Print("BSPC run time is %5.0f seconds\n", I_FloatTime() - start_time); Log_Close(); //close the log file return 0; } //end of the function main
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== quakefile_t *FindQuakeFilesWithPakFilter(char *pakfilter, char *filter) { #ifdef _WIN32 WIN32_FIND_DATA filedata; HWND handle; struct _stat statbuf; int done; #else glob_t globbuf; struct stat statbuf; int j; #endif quakefile_t *qfiles, *lastqf, *qf; char pakfile[_MAX_PATH], filename[_MAX_PATH], *str; qfiles = NULL; lastqf = NULL; if (pakfilter && strlen(pakfilter)) { #ifdef _WIN32 handle = FindFirstFile(pakfilter, &filedata); done = (handle == INVALID_HANDLE_VALUE); while(!done) { _splitpath(pakfilter, pakfile, NULL, NULL, NULL); _splitpath(pakfilter, NULL, &pakfile[strlen(pakfile)], NULL, NULL); AppendPathSeperator(pakfile, _MAX_PATH); strcat(pakfile, filedata.cFileName); _stat(pakfile, &statbuf); #else glob(pakfilter, 0, NULL, &globbuf); for (j = 0; j < globbuf.gl_pathc; j++) { strcpy(pakfile, globbuf.gl_pathv[j]); stat(pakfile, &statbuf); #endif //if the file with .pak or .pk3 is a folder if (statbuf.st_mode & S_IFDIR) { strcpy(filename, pakfilter); AppendPathSeperator(filename, _MAX_PATH); strcat(filename, filter); qf = FindQuakeFilesWithPakFilter(NULL, filename); if (lastqf) lastqf->next = qf; else qfiles = qf; lastqf = qf; while(lastqf->next) lastqf = lastqf->next; } //end if else { #ifdef _WIN32 str = StringContains(pakfile, ".pk3", false); #else str = StringContains(pakfile, ".pk3", true); #endif if (str && str == pakfile + strlen(pakfile) - strlen(".pk3")) { qf = FindQuakeFilesInZip(pakfile, filter); } //end if else { qf = NULL; } //end else // if (qf) { if (lastqf) lastqf->next = qf; else qfiles = qf; lastqf = qf; while(lastqf->next) lastqf = lastqf->next; } //end if } //end else // #ifdef _WIN32 //find the next file done = !FindNextFile(handle, &filedata); } //end while #else } //end for globfree(&globbuf); #endif } //end if else { #ifdef _WIN32 handle = FindFirstFile(filter, &filedata); done = (handle == INVALID_HANDLE_VALUE); while(!done) { _splitpath(filter, filename, NULL, NULL, NULL); _splitpath(filter, NULL, &filename[strlen(filename)], NULL, NULL); AppendPathSeperator(filename, _MAX_PATH); strcat(filename, filedata.cFileName); #else glob(filter, 0, NULL, &globbuf); for (j = 0; j < globbuf.gl_pathc; j++) { strcpy(filename, globbuf.gl_pathv[j]); #endif // qf = malloc(sizeof(quakefile_t)); if (!qf) Error("out of memory"); memset(qf, 0, sizeof(quakefile_t)); strcpy(qf->pakfile, ""); strcpy(qf->filename, filename); strcpy(qf->origname, filename); qf->length = 0; qf->type = QuakeFileType(filename); //add the file ot the list qf->next = NULL; if (lastqf) lastqf->next = qf; else qfiles = qf; lastqf = qf; #ifdef _WIN32 //find the next file done = !FindNextFile(handle, &filedata); } //end while #else } //end for globfree(&globbuf); #endif } //end else return qfiles; } //end of the function FindQuakeFilesWithPakFilter