Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

bspc.c (28389B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 #if defined(WIN32) || defined(_WIN32)
     24 #include <direct.h>
     25 #include <windows.h>
     26 #include <sys/types.h>
     27 #include <sys/stat.h>
     28 #else
     29 #include <unistd.h>
     30 #include <glob.h>
     31 #include <sys/stat.h>
     32 #include <unistd.h>
     33 #endif
     34 #include "qbsp.h"
     35 #include "l_mem.h"
     36 #include "../botlib/aasfile.h"
     37 #include "../botlib/be_aas_cluster.h"
     38 #include "../botlib/be_aas_optimize.h"
     39 #include "aas_create.h"
     40 #include "aas_store.h"
     41 #include "aas_file.h"
     42 #include "aas_cfg.h"
     43 #include "be_aas_bspc.h"
     44 
     45 extern	int use_nodequeue;		//brushbsp.c
     46 extern	int calcgrapplereach;	//be_aas_reach.c
     47 
     48 float			subdivide_size = 240;
     49 char			source[1024];
     50 char			name[1024];
     51 vec_t			microvolume = 1.0;
     52 char			outbase[32];
     53 int				entity_num;
     54 aas_settings_t	aassettings;
     55 
     56 qboolean	noprune;			//don't prune nodes (bspc.c)
     57 qboolean	glview;				//create a gl view
     58 qboolean	nodetail;			//don't use detail brushes (map.c)
     59 qboolean	fulldetail;			//use but don't mark detail brushes (map.c)
     60 qboolean	onlyents;			//only process the entities (bspc.c)
     61 qboolean	nomerge;			//don't merge bsp node faces (faces.c)
     62 qboolean	nowater;			//don't use the water brushes (map.c)
     63 qboolean	nocsg;				//don't carve intersecting brushes (bspc.c)
     64 qboolean	noweld;				//use unique face vertexes (faces.c)
     65 qboolean	noshare;			//don't share bsp edges (faces.c)
     66 qboolean	nosubdiv;			//don't subdivide bsp node faces (faces.c)
     67 qboolean	notjunc;			//don't create tjunctions (edge melting) (faces.c)
     68 qboolean	optimize;			//enable optimisation
     69 qboolean	leaktest;			//perform a leak test
     70 qboolean	verboseentities;
     71 qboolean	freetree;			//free the bsp tree when not needed anymore
     72 qboolean	create_aas;			//create an .AAS file
     73 qboolean	nobrushmerge;		//don't merge brushes
     74 qboolean	lessbrushes;		//create less brushes instead of correct texture placement
     75 qboolean	cancelconversion;	//true if the conversion is being cancelled
     76 qboolean	noliquids;			//no liquids when writing map file
     77 qboolean	forcesidesvisible;	//force all brush sides to be visible when loaded from bsp
     78 qboolean	capsule_collision = 0;
     79 
     80 /*
     81 //===========================================================================
     82 //
     83 // Parameter:			-
     84 // Returns:				-
     85 // Changes Globals:		-
     86 //===========================================================================
     87 void ProcessWorldModel (void)
     88 {
     89 	entity_t	*e;
     90 	tree_t *tree;
     91 	qboolean	leaked;
     92 	int brush_start, brush_end;
     93 
     94 	e = &entities[entity_num];
     95 
     96 	brush_start = e->firstbrush;
     97 	brush_end = brush_start + e->numbrushes;
     98 	leaked = false;
     99 
    100 	//process the whole world in one time
    101 	tree = ProcessWorldBrushes(brush_start, brush_end);
    102 	//create the bsp tree portals
    103 	MakeTreePortals(tree);
    104 	//mark all leafs that can be reached by entities
    105 	if (FloodEntities(tree))
    106 	{
    107 		FillOutside(tree->headnode);
    108 	} //end if
    109 	else
    110 	{
    111 		Log_Print("**** leaked ****\n");
    112 		leaked = true;
    113 		LeakFile(tree);
    114 		if (leaktest)
    115 		{
    116 			Log_Print("--- MAP LEAKED ---\n");
    117 			exit(0);
    118 		} //end if
    119 	} //end else
    120 
    121 	MarkVisibleSides (tree, brush_start, brush_end);
    122 
    123 	FloodAreas (tree);
    124 
    125 #ifndef ME
    126 	if (glview) WriteGLView(tree, source);
    127 #endif
    128 	MakeFaces(tree->headnode);
    129 	FixTjuncs(tree->headnode);
    130 
    131 	//NOTE: Never prune the nodes because the portals
    132 	//		are screwed when prunning is done and as
    133 	//		a result portal writing will crash
    134 	//if (!noprune) PruneNodes(tree->headnode);
    135 
    136 	WriteBSP(tree->headnode);
    137 
    138 	if (!leaked) WritePortalFile(tree);
    139 
    140 	Tree_Free(tree);
    141 } //end of the function ProcessWorldModel
    142 //===========================================================================
    143 //
    144 // Parameter:			-
    145 // Returns:				-
    146 // Changes Globals:		-
    147 //===========================================================================
    148 void ProcessSubModel (void)
    149 {
    150 	entity_t	*e;
    151 	int start, end;
    152 	tree_t *tree;
    153 	bspbrush_t *list;
    154 	vec3_t mins, maxs;
    155 
    156 	e = &entities[entity_num];
    157 
    158 	start = e->firstbrush;
    159 	end = start + e->numbrushes;
    160 
    161 	mins[0] = mins[1] = mins[2] = -4096;
    162 	maxs[0] = maxs[1] = maxs[2] = 4096;
    163 	list = MakeBspBrushList(start, end, mins, maxs);
    164 	if (!nocsg) list = ChopBrushes (list);
    165 	tree = BrushBSP (list, mins, maxs);
    166 	MakeTreePortals (tree);
    167 	MarkVisibleSides (tree, start, end);
    168 	MakeFaces (tree->headnode);
    169 	FixTjuncs (tree->headnode);
    170 	WriteBSP (tree->headnode);
    171 	Tree_Free(tree);
    172 } //end of the function ProcessSubModel
    173 //===========================================================================
    174 //
    175 // Parameter:			-
    176 // Returns:				-
    177 // Changes Globals:		-
    178 //===========================================================================
    179 void ProcessModels (void)
    180 {
    181 	BeginBSPFile();
    182 
    183 	for (entity_num = 0; entity_num < num_entities; entity_num++)
    184 	{
    185 		if (!entities[entity_num].numbrushes)
    186 			continue;
    187 
    188 		Log_Print("############### model %i ###############\n", nummodels);
    189 		BeginModel();
    190 		if (entity_num == 0) ProcessWorldModel();
    191 		else ProcessSubModel();
    192 		EndModel();
    193 
    194 		if (!verboseentities)
    195 			verbose = false;	// don't bother printing submodels
    196 	} //end for
    197 	EndBSPFile();
    198 } //end of the function ProcessModels
    199 //===========================================================================
    200 //
    201 // Parameter:			-
    202 // Returns:				-
    203 // Changes Globals:		-
    204 //===========================================================================
    205 void Win_Map2Bsp(char *bspfilename)
    206 {
    207 	double start, end;
    208 	char path[1024];
    209 
    210 	start = I_FloatTime();
    211 
    212 	ThreadSetDefault();
    213 	//yeah sure Carmack
    214 	//numthreads = 1;		// multiple threads aren't helping...
    215 
    216 	strcpy(source, ExpandArg(bspfilename));
    217 	StripExtension(source);
    218 
    219 	//delete portal and line files
    220 	sprintf(path, "%s.prt", source);
    221 	remove(path);
    222 	sprintf(path, "%s.lin", source);
    223 	remove(path);
    224 
    225 	strcpy(name, ExpandArg(bspfilename));	
    226 	DefaultExtension(name, ".map");	// might be .reg
    227 
    228 	Q2_AllocMaxBSP();
    229 	//
    230 	SetModelNumbers();
    231 	SetLightStyles();
    232 	ProcessModels();
    233 	//write the BSP
    234 	Q2_WriteBSPFile(bspfilename);
    235 
    236 	Q2_FreeMaxBSP();
    237 
    238 	end = I_FloatTime();
    239 	Log_Print("%5.0f seconds elapsed\n", end-start);
    240 } //end of the function Win_Map2Bsp
    241 //===========================================================================
    242 //
    243 // Parameter:			-
    244 // Returns:				-
    245 // Changes Globals:		-
    246 //===========================================================================
    247 void Map2Bsp(char *mapfilename, char *outputfilename)
    248 {
    249 	double start, end;
    250 	char path[1024];
    251 
    252 	start = I_FloatTime ();
    253 
    254 	ThreadSetDefault ();
    255 	//yeah sure Carmack
    256 	//numthreads = 1;		//multiple threads aren't helping...
    257 	//SetQdirFromPath(bspfilename);
    258 
    259 	strcpy(source, ExpandArg(mapfilename));
    260 	StripExtension(source);
    261 
    262 	// delete portal and line files
    263 	sprintf(path, "%s.prt", source);
    264 	remove(path);
    265 	sprintf(path, "%s.lin", source);
    266 	remove(path);
    267 
    268 	strcpy(name, ExpandArg(mapfilename));
    269 	DefaultExtension(name, ".map");	// might be .reg
    270 
    271 	//
    272 	// if onlyents, just grab the entites and resave
    273 	//
    274 	if (onlyents)
    275 	{
    276 		char out[1024];
    277 
    278 		Q2_AllocMaxBSP();
    279 		sprintf (out, "%s.bsp", source);
    280 		Q2_LoadBSPFile(out, 0, 0);
    281 		num_entities = 0;
    282 
    283 		Q2_LoadMapFile(name);
    284 		SetModelNumbers();
    285 		SetLightStyles();
    286 
    287 		Q2_UnparseEntities();
    288 
    289 		Q2_WriteBSPFile(out);
    290 		//
    291 		Q2_FreeMaxBSP();
    292 	} //end if
    293 	else
    294 	{
    295 		//
    296 		// start from scratch
    297 		//
    298 		Q2_AllocMaxBSP();
    299 		//load the map
    300 		Q2_LoadMapFile(name);
    301 		//create the .bsp file
    302 		SetModelNumbers();
    303 		SetLightStyles();
    304 		ProcessModels();
    305 		//write the BSP
    306 		Q2_WriteBSPFile(outputfilename);
    307 		//
    308 		Q2_FreeMaxBSP();
    309 	} //end else
    310 
    311 	end = I_FloatTime();
    312 	Log_Print("%5.0f seconds elapsed\n", end-start);
    313 } //end of the function Map2Bsp
    314 */
    315 //===========================================================================
    316 //
    317 // Parameter:			-
    318 // Returns:				-
    319 // Changes Globals:		-
    320 //===========================================================================
    321 void AASOuputFile(quakefile_t *qf, char *outputpath, char *filename)
    322 {
    323 	char ext[MAX_PATH];
    324 
    325 	//
    326 	if (strlen(outputpath))
    327 	{
    328 		strcpy(filename, outputpath);
    329 		//append the bsp file base
    330 		AppendPathSeperator(filename, MAX_PATH);
    331 		ExtractFileBase(qf->origname, &filename[strlen(filename)]);
    332 		//append .aas
    333 		strcat(filename, ".aas");
    334 		return;
    335 	} //end if
    336 	//
    337 	ExtractFileExtension(qf->filename, ext);
    338 	if (!stricmp(ext, "pk3") || !stricmp(ext, "pak") || !stricmp(ext, "sin"))
    339 	{
    340 		strcpy(filename, qf->filename);
    341 		while(strlen(filename) &&
    342 				filename[strlen(filename)-1] != '\\' &&
    343 				filename[strlen(filename)-1] != '/')
    344 		{
    345 			filename[strlen(filename)-1] = '\0';
    346 		} //end while
    347 		strcat(filename, "maps");
    348 		if (access(filename, 0x04)) CreatePath(filename);
    349 		//append the bsp file base
    350 		AppendPathSeperator(filename, MAX_PATH);
    351 		ExtractFileBase(qf->origname, &filename[strlen(filename)]);
    352 		//append .aas
    353 		strcat(filename, ".aas");
    354 	} //end if
    355 	else
    356 	{
    357 		strcpy(filename, qf->filename);
    358 		while(strlen(filename) &&
    359 				filename[strlen(filename)-1] != '.')
    360 		{
    361 			filename[strlen(filename)-1] = '\0';
    362 		} //end while
    363 		strcat(filename, "aas");
    364 	} //end else
    365 } //end of the function AASOutputFile
    366 //===========================================================================
    367 //
    368 // Parameter:			-
    369 // Returns:				-
    370 // Changes Globals:		-
    371 //===========================================================================
    372 void CreateAASFilesForAllBSPFiles(char *quakepath)
    373 {
    374 #if defined(WIN32)|defined(_WIN32)
    375 	WIN32_FIND_DATA filedata;
    376 	HWND handle;
    377 	struct _stat statbuf;
    378 #else
    379 	glob_t globbuf;
    380 	struct stat statbuf;
    381 	int j;
    382 #endif
    383 	int done;
    384 	char filter[_MAX_PATH], bspfilter[_MAX_PATH], aasfilter[_MAX_PATH];
    385 	char aasfile[_MAX_PATH], buf[_MAX_PATH], foldername[_MAX_PATH];
    386 	quakefile_t *qf, *qf2, *files, *bspfiles, *aasfiles;
    387 
    388 	strcpy(filter, quakepath);
    389 	AppendPathSeperator(filter, sizeof(filter));
    390 	strcat(filter, "*");
    391 
    392 #if defined(WIN32)|defined(_WIN32)
    393 	handle = FindFirstFile(filter, &filedata);
    394 	done = (handle == INVALID_HANDLE_VALUE);
    395 	while(!done)
    396 	{
    397 		_splitpath(filter, foldername, NULL, NULL, NULL);
    398 		_splitpath(filter, NULL, &foldername[strlen(foldername)], NULL, NULL);
    399 		AppendPathSeperator(foldername, _MAX_PATH);
    400 		strcat(foldername, filedata.cFileName);
    401 		_stat(foldername, &statbuf);
    402 #else
    403 	glob(filter, 0, NULL, &globbuf);
    404 	for (j = 0; j < globbuf.gl_pathc; j++)
    405 	{
    406 		strcpy(foldername, globbuf.gl_pathv[j]);
    407 		stat(foldername, &statbuf);
    408 #endif
    409 		//if it is a folder
    410 		if (statbuf.st_mode & S_IFDIR)
    411 		{
    412 			//
    413 			AppendPathSeperator(foldername, sizeof(foldername));
    414 			//get all the bsp files
    415 			strcpy(bspfilter, foldername);
    416 			strcat(bspfilter, "maps/*.bsp");
    417 			files = FindQuakeFiles(bspfilter);
    418 			strcpy(bspfilter, foldername);
    419 			strcat(bspfilter, "*.pk3/maps/*.bsp");
    420 			bspfiles = FindQuakeFiles(bspfilter);
    421 			for (qf = bspfiles; qf; qf = qf->next) if (!qf->next) break;
    422 			if (qf) qf->next = files;
    423 			else bspfiles = files;
    424 			//get all the aas files
    425 			strcpy(aasfilter, foldername);
    426 			strcat(aasfilter, "maps/*.aas");
    427 			files = FindQuakeFiles(aasfilter);
    428 			strcpy(aasfilter, foldername);
    429 			strcat(aasfilter, "*.pk3/maps/*.aas");
    430 			aasfiles = FindQuakeFiles(aasfilter);
    431 			for (qf = aasfiles; qf; qf = qf->next) if (!qf->next) break;
    432 			if (qf) qf->next = files;
    433 			else aasfiles = files;
    434 			//
    435 			for (qf = bspfiles; qf; qf = qf->next)
    436 			{
    437 				sprintf(aasfile, "%s/%s", qf->pakfile, qf->origname);
    438 				Log_Print("found %s\n", aasfile);
    439 				strcpy(&aasfile[strlen(aasfile)-strlen(".bsp")], ".aas");
    440 				for (qf2 = aasfiles; qf2; qf2 = qf2->next)
    441 				{
    442 					sprintf(buf, "%s/%s", qf2->pakfile, qf2->origname);
    443 					if (!stricmp(aasfile, buf))
    444 					{
    445 						Log_Print("found %s\n", buf);
    446 						break;
    447 					} //end if
    448 				} //end for
    449 			} //end for
    450 		} //end if
    451 #if defined(WIN32)|defined(_WIN32)
    452 		//find the next file
    453 		done = !FindNextFile(handle, &filedata);
    454 	} //end while
    455 #else
    456 	} //end for
    457 	globfree(&globbuf);
    458 #endif
    459 } //end of the function CreateAASFilesForAllBSPFiles
    460 //===========================================================================
    461 //
    462 // Parameter:			-
    463 // Returns:				-
    464 // Changes Globals:		-
    465 //===========================================================================
    466 quakefile_t *GetArgumentFiles(int argc, char *argv[], int *i, char *ext)
    467 {
    468 	quakefile_t *qfiles, *lastqf, *qf;
    469 	int j;
    470 	char buf[1024];
    471 
    472 	qfiles = NULL;
    473 	lastqf = NULL;
    474 	for (; (*i)+1 < argc && argv[(*i)+1][0] != '-'; (*i)++)
    475 	{
    476 		strcpy(buf, argv[(*i)+1]);
    477 		for (j = strlen(buf)-1; j >= strlen(buf)-4; j--)
    478 			if (buf[j] == '.') break;
    479 		if (j >= strlen(buf)-4)
    480 			strcpy(&buf[j+1], ext);
    481 		qf = FindQuakeFiles(buf);
    482 		if (!qf) continue;
    483 		if (lastqf) lastqf->next = qf;
    484 		else qfiles = qf;
    485 		lastqf = qf;
    486 		while(lastqf->next) lastqf = lastqf->next;
    487 	} //end for
    488 	return qfiles;
    489 } //end of the function GetArgumentFiles
    490 //===========================================================================
    491 //
    492 // Parameter:			-
    493 // Returns:				-
    494 // Changes Globals:		-
    495 //===========================================================================
    496 
    497 #define COMP_BSP2MAP		1
    498 #define COMP_BSP2AAS		2
    499 #define COMP_REACH			3
    500 #define COMP_CLUSTER		4
    501 #define COMP_AASOPTIMIZE	5
    502 #define COMP_AASINFO		6
    503 
    504 int main (int argc, char **argv)
    505 {
    506 	int i, comp = 0;
    507 	char outputpath[MAX_PATH] = "";
    508 	char filename[MAX_PATH] = "unknown";
    509 	quakefile_t *qfiles, *qf;
    510 	double start_time;
    511 
    512 	myargc = argc;
    513 	myargv = argv;
    514 
    515 	start_time = I_FloatTime();
    516 
    517 	Log_Open("bspc.log");		//open a log file
    518 	Log_Print("BSPC version "BSPC_VERSION", %s %s\n", __DATE__, __TIME__);
    519 
    520 	DefaultCfg();
    521 	for (i = 1; i < argc; i++)
    522 	{
    523 		if (!stricmp(argv[i],"-threads"))
    524 		{
    525 			if (i + 1 >= argc) {i = 0; break;}
    526 			numthreads = atoi(argv[++i]);
    527 			Log_Print("threads = %d\n", numthreads);
    528 		} //end if
    529 		else if (!stricmp(argv[i], "-noverbose"))
    530 		{
    531 			Log_Print("verbose = false\n");
    532 			verbose = false;
    533 		} //end else if
    534 		else if (!stricmp(argv[i], "-nocsg"))
    535 		{
    536 			Log_Print("nocsg = true\n");
    537 			nocsg = true;
    538 		} //end else if
    539 		else if (!stricmp(argv[i], "-optimize"))
    540 		{
    541 			Log_Print("optimize = true\n");
    542 			optimize = true;
    543 		} //end else if
    544 		/*
    545 		else if (!stricmp(argv[i],"-glview"))
    546 		{
    547 			glview = true;
    548 		} //end else if
    549 		else if (!stricmp(argv[i], "-draw"))
    550 		{
    551 			Log_Print("drawflag = true\n");
    552 			drawflag = true;
    553 		} //end else if
    554 		else if (!stricmp(argv[i], "-noweld"))
    555 		{
    556 			Log_Print("noweld = true\n");
    557 			noweld = true;
    558 		} //end else if
    559 		else if (!stricmp(argv[i], "-noshare"))
    560 		{
    561 			Log_Print("noshare = true\n");
    562 			noshare = true;
    563 		} //end else if
    564 		else if (!stricmp(argv[i], "-notjunc"))
    565 		{
    566 			Log_Print("notjunc = true\n");
    567 			notjunc = true;
    568 		} //end else if
    569 		else if (!stricmp(argv[i], "-nowater"))
    570 		{
    571 			Log_Print("nowater = true\n");
    572 			nowater = true;
    573 		} //end else if
    574 		else if (!stricmp(argv[i], "-noprune"))
    575 		{
    576 			Log_Print("noprune = true\n");
    577 			noprune = true;
    578 		} //end else if
    579 		else if (!stricmp(argv[i], "-nomerge"))
    580 		{
    581 			Log_Print("nomerge = true\n");
    582 			nomerge = true;
    583 		} //end else if
    584 		else if (!stricmp(argv[i], "-nosubdiv"))
    585 		{
    586 			Log_Print("nosubdiv = true\n");
    587 			nosubdiv = true;
    588 		} //end else if
    589 		else if (!stricmp(argv[i], "-nodetail"))
    590 		{
    591 			Log_Print("nodetail = true\n");
    592 			nodetail = true;
    593 		} //end else if
    594 		else if (!stricmp(argv[i], "-fulldetail"))
    595 		{
    596 			Log_Print("fulldetail = true\n");
    597 			fulldetail = true;
    598 		} //end else if
    599 		else if (!stricmp(argv[i], "-onlyents"))
    600 		{
    601 			Log_Print("onlyents = true\n");
    602 			onlyents = true;
    603 		} //end else if
    604 		else if (!stricmp(argv[i], "-micro"))
    605 		{
    606 			if (i + 1 >= argc) {i = 0; break;}
    607 			microvolume = atof(argv[++i]);
    608 			Log_Print("microvolume = %f\n", microvolume);
    609 		} //end else if
    610 		else if (!stricmp(argv[i], "-leaktest"))
    611 		{
    612 			Log_Print("leaktest = true\n");
    613 			leaktest = true;
    614 		} //end else if
    615 		else if (!stricmp(argv[i], "-verboseentities"))
    616 		{
    617 			Log_Print("verboseentities = true\n");
    618 			verboseentities = true;
    619 		} //end else if
    620 		else if (!stricmp(argv[i], "-chop"))
    621 		{
    622 			if (i + 1 >= argc) {i = 0; break;}
    623 			subdivide_size = atof(argv[++i]);
    624 			Log_Print("subdivide_size = %f\n", subdivide_size);
    625 		} //end else if
    626 		else if (!stricmp (argv[i], "-tmpout"))
    627 		{
    628 			strcpy (outbase, "/tmp");
    629 			Log_Print("temp output\n");
    630 		} //end else if
    631 		*/
    632 #ifdef ME
    633 		else if (!stricmp(argv[i], "-freetree"))
    634 		{
    635 			freetree = true;
    636 			Log_Print("freetree = true\n");
    637 		} //end else if
    638 		else if (!stricmp(argv[i], "-grapplereach"))
    639 		{
    640 			calcgrapplereach = true;
    641 			Log_Print("grapplereach = true\n");
    642 		} //end else if
    643 		else if (!stricmp(argv[i], "-nobrushmerge"))
    644 		{
    645 			nobrushmerge = true;
    646 			Log_Print("nobrushmerge = true\n");
    647 		} //end else if
    648 		else if (!stricmp(argv[i], "-noliquids"))
    649 		{
    650 			noliquids = true;
    651 			Log_Print("noliquids = true\n");
    652 		} //end else if
    653 		else if (!stricmp(argv[i], "-forcesidesvisible"))
    654 		{
    655 			forcesidesvisible = true;
    656 			Log_Print("forcesidesvisible = true\n");
    657 		} //end else if
    658 		else if (!stricmp(argv[i], "-output"))
    659 		{
    660 			if (i + 1 >= argc) {i = 0; break;}
    661 			if (access(argv[i+1], 0x04)) Warning("the folder %s does not exist", argv[i+1]);
    662 			strcpy(outputpath, argv[++i]);
    663 		} //end else if
    664 		else if (!stricmp(argv[i], "-breadthfirst"))
    665 		{
    666 			use_nodequeue = true;
    667 			Log_Print("breadthfirst = true\n");
    668 		} //end else if
    669 		else if (!stricmp(argv[i], "-capsule"))
    670 		{
    671 			capsule_collision = true;
    672 			Log_Print("capsule_collision = true\n");
    673 		} //end else if
    674 		else if (!stricmp(argv[i], "-cfg"))
    675 		{
    676 			if (i + 1 >= argc) {i = 0; break;}
    677 			if (!LoadCfgFile(argv[++i]))
    678 				exit(0);
    679 		} //end else if
    680 		else if (!stricmp(argv[i], "-bsp2map"))
    681 		{
    682 			if (i + 1 >= argc) {i = 0; break;}
    683 			comp = COMP_BSP2MAP;
    684 			qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
    685 		} //end else if
    686 		else if (!stricmp(argv[i], "-bsp2aas"))
    687 		{
    688 			if (i + 1 >= argc) {i = 0; break;}
    689 			comp = COMP_BSP2AAS;
    690 			qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
    691 		} //end else if
    692 		else if (!stricmp(argv[i], "-aasall"))
    693 		{
    694 			if (i + 1 >= argc) {i = 0; break;}
    695 			CreateAASFilesForAllBSPFiles(argv[++i]);
    696 		} //end else if
    697 		else if (!stricmp(argv[i], "-reach"))
    698 		{
    699 			if (i + 1 >= argc) {i = 0; break;}
    700 			comp = COMP_REACH;
    701 			qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
    702 		} //end else if
    703 		else if (!stricmp(argv[i], "-cluster"))
    704 		{
    705 			if (i + 1 >= argc) {i = 0; break;}
    706 			comp = COMP_CLUSTER;
    707 			qfiles = GetArgumentFiles(argc, argv, &i, "bsp");
    708 		} //end else if
    709 		else if (!stricmp(argv[i], "-aasinfo"))
    710 		{
    711 			if (i + 1 >= argc) {i = 0; break;}
    712 			comp = COMP_AASINFO;
    713 			qfiles = GetArgumentFiles(argc, argv, &i, "aas");
    714 		} //end else if
    715 		else if (!stricmp(argv[i], "-aasopt"))
    716 		{
    717 			if (i + 1 >= argc) {i = 0; break;}
    718 			comp = COMP_AASOPTIMIZE;
    719 			qfiles = GetArgumentFiles(argc, argv, &i, "aas");
    720 		} //end else if
    721 #endif //ME
    722 		else
    723 		{
    724 			Log_Print("unknown parameter %s\n", argv[i]);
    725 			break;
    726 		} //end else
    727 	} //end for
    728 
    729 	//if there are parameters and there's no mismatch in one of the parameters
    730 	if (argc > 1 && i == argc)
    731 	{
    732 		switch(comp)
    733 		{
    734 			case COMP_BSP2MAP:
    735 			{
    736 				if (!qfiles) Log_Print("no files found\n");
    737 				for (qf = qfiles; qf; qf = qf->next)
    738 				{
    739 					//copy the output path
    740 					strcpy(filename, outputpath);
    741 					//append the bsp file base
    742 					AppendPathSeperator(filename, MAX_PATH);
    743 					ExtractFileBase(qf->origname, &filename[strlen(filename)]);
    744 					//append .map
    745 					strcat(filename, ".map");
    746 					//
    747 					Log_Print("bsp2map: %s to %s\n", qf->origname, filename);
    748 					if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
    749 					//
    750 					LoadMapFromBSP(qf);
    751 					//write the map file
    752 					WriteMapFile(filename);
    753 				} //end for
    754 				break;
    755 			} //end case
    756 			case COMP_BSP2AAS:
    757 			{
    758 				if (!qfiles) Log_Print("no files found\n");
    759 				for (qf = qfiles; qf; qf = qf->next)
    760 				{
    761 					AASOuputFile(qf, outputpath, filename);
    762 					//
    763 					Log_Print("bsp2aas: %s to %s\n", qf->origname, filename);
    764 					if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
    765 					//set before map loading
    766 					create_aas = 1;
    767 					LoadMapFromBSP(qf);
    768 					//create the AAS file
    769 					AAS_Create(filename);
    770 					//if it's a Quake3 map calculate the reachabilities and clusters
    771 					if (loadedmaptype == MAPTYPE_QUAKE3) AAS_CalcReachAndClusters(qf);
    772 					//
    773 					if (optimize) AAS_Optimize();
    774 					//
    775 					//write out the stored AAS file
    776 					if (!AAS_WriteAASFile(filename))
    777 					{
    778 						Error("error writing %s\n", filename);
    779 					} //end if
    780 					//deallocate memory
    781 					AAS_FreeMaxAAS();
    782 				} //end for
    783 				break;
    784 			} //end case
    785 			case COMP_REACH:
    786 			{
    787 				if (!qfiles) Log_Print("no files found\n");
    788 				for (qf = qfiles; qf; qf = qf->next)
    789 				{
    790 					AASOuputFile(qf, outputpath, filename);
    791 					//
    792 					Log_Print("reach: %s to %s\n", qf->origname, filename);
    793 					if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
    794 					//if the AAS file exists in the output directory
    795 					if (!access(filename, 0x04))
    796 					{
    797 						if (!AAS_LoadAASFile(filename, 0, 0))
    798 						{
    799 							Error("error loading aas file %s\n", filename);
    800 						} //end if
    801 						//assume it's a Quake3 BSP file
    802 						loadedmaptype = MAPTYPE_QUAKE3;
    803 					} //end if
    804 					else
    805 					{
    806 						Warning("AAS file %s not found in output folder\n", filename);
    807 						Log_Print("creating %s...\n", filename);
    808 						//set before map loading
    809 						create_aas = 1;
    810 						LoadMapFromBSP(qf);
    811 						//create the AAS file
    812 						AAS_Create(filename);
    813 					} //end else
    814 					//if it's a Quake3 map calculate the reachabilities and clusters
    815 					if (loadedmaptype == MAPTYPE_QUAKE3)
    816 					{
    817 						AAS_CalcReachAndClusters(qf);
    818 					} //end if
    819 					//
    820 					if (optimize) AAS_Optimize();
    821 					//write out the stored AAS file
    822 					if (!AAS_WriteAASFile(filename))
    823 					{
    824 						Error("error writing %s\n", filename);
    825 					} //end if
    826 					//deallocate memory
    827 					AAS_FreeMaxAAS();
    828 				} //end for
    829 				break;
    830 			} //end case
    831 			case COMP_CLUSTER:
    832 			{
    833 				if (!qfiles) Log_Print("no files found\n");
    834 				for (qf = qfiles; qf; qf = qf->next)
    835 				{
    836 					AASOuputFile(qf, outputpath, filename);
    837 					//
    838 					Log_Print("cluster: %s to %s\n", qf->origname, filename);
    839 					if (qf->type != QFILETYPE_BSP) Warning("%s is probably not a BSP file\n", qf->origname);
    840 					//if the AAS file exists in the output directory
    841 					if (!access(filename, 0x04))
    842 					{
    843 						if (!AAS_LoadAASFile(filename, 0, 0))
    844 						{
    845 							Error("error loading aas file %s\n", filename);
    846 						} //end if
    847 						//assume it's a Quake3 BSP file
    848 						loadedmaptype = MAPTYPE_QUAKE3;
    849 						//if it's a Quake3 map calculate the clusters
    850 						if (loadedmaptype == MAPTYPE_QUAKE3)
    851 						{
    852 							aasworld.numclusters = 0;
    853 							AAS_InitBotImport();
    854 							AAS_InitClustering();
    855 						} //end if
    856 					} //end if
    857 					else
    858 					{
    859 						Warning("AAS file %s not found in output folder\n", filename);
    860 						Log_Print("creating %s...\n", filename);
    861 						//set before map loading
    862 						create_aas = 1;
    863 						LoadMapFromBSP(qf);
    864 						//create the AAS file
    865 						AAS_Create(filename);
    866 						//if it's a Quake3 map calculate the reachabilities and clusters
    867 						if (loadedmaptype == MAPTYPE_QUAKE3) AAS_CalcReachAndClusters(qf);
    868 					} //end else
    869 					//
    870 					if (optimize) AAS_Optimize();
    871 					//write out the stored AAS file
    872 					if (!AAS_WriteAASFile(filename))
    873 					{
    874 						Error("error writing %s\n", filename);
    875 					} //end if
    876 					//deallocate memory
    877 					AAS_FreeMaxAAS();
    878 				} //end for
    879 				break;
    880 			} //end case
    881 			case COMP_AASOPTIMIZE:
    882 			{
    883 				if (!qfiles) Log_Print("no files found\n");
    884 				for (qf = qfiles; qf; qf = qf->next)
    885 				{
    886 					AASOuputFile(qf, outputpath, filename);
    887 					//
    888 					Log_Print("optimizing: %s to %s\n", qf->origname, filename);
    889 					if (qf->type != QFILETYPE_AAS) Warning("%s is probably not a AAS file\n", qf->origname);
    890 					//
    891 					AAS_InitBotImport();
    892 					//
    893 					if (!AAS_LoadAASFile(qf->filename, qf->offset, qf->length))
    894 					{
    895 						Error("error loading aas file %s\n", qf->filename);
    896 					} //end if
    897 					AAS_Optimize();
    898 					//write out the stored AAS file
    899 					if (!AAS_WriteAASFile(filename))
    900 					{
    901 						Error("error writing %s\n", filename);
    902 					} //end if
    903 					//deallocate memory
    904 					AAS_FreeMaxAAS();
    905 				} //end for
    906 				break;
    907 			} //end case
    908 			case COMP_AASINFO:
    909 			{
    910 				if (!qfiles) Log_Print("no files found\n");
    911 				for (qf = qfiles; qf; qf = qf->next)
    912 				{
    913 					AASOuputFile(qf, outputpath, filename);
    914 					//
    915 					Log_Print("aas info for: %s\n", filename);
    916 					if (qf->type != QFILETYPE_AAS) Warning("%s is probably not a AAS file\n", qf->origname);
    917 					//
    918 					AAS_InitBotImport();
    919 					//
    920 					if (!AAS_LoadAASFile(qf->filename, qf->offset, qf->length))
    921 					{
    922 						Error("error loading aas file %s\n", qf->filename);
    923 					} //end if
    924 					AAS_ShowTotals();
    925 				} //end for
    926 			} //end case
    927 			default:
    928 			{
    929 				Log_Print("don't know what to do\n");
    930 				break;
    931 			} //end default
    932 		} //end switch
    933 	} //end if
    934 	else
    935 	{
    936 		Log_Print("Usage:   bspc [-<switch> [-<switch> ...]]\n"
    937 #if defined(WIN32) || defined(_WIN32)
    938 			"Example 1: bspc -bsp2aas d:\\quake3\\baseq3\\maps\\mymap?.bsp\n"
    939 			"Example 2: bspc -bsp2aas d:\\quake3\\baseq3\\pak0.pk3\\maps/q3dm*.bsp\n"
    940 #else
    941 			"Example 1: bspc -bsp2aas /quake3/baseq3/maps/mymap?.bsp\n"
    942 			"Example 2: bspc -bsp2aas /quake3/baseq3/pak0.pk3/maps/q3dm*.bsp\n"
    943 #endif
    944 			"\n"
    945 			"Switches:\n"
    946 			//"   bsp2map  <[pakfilter/]filter.bsp>    = convert BSP to MAP\n"
    947 			//"   aasall   <quake3folder>              = create AAS files for all BSPs\n"
    948 			"   bsp2aas  <[pakfilter/]filter.bsp>    = convert BSP to AAS\n"
    949 			"   reach    <filter.bsp>                = compute reachability & clusters\n"
    950 			"   cluster  <filter.aas>                = compute clusters\n"
    951 			"   aasopt   <filter.aas>                = optimize aas file\n"
    952 			"   aasinfo  <filter.aas>                = show AAS file info\n"
    953 			"   output   <output path>               = set output path\n"
    954 			"   threads  <X>                         = set number of threads to X\n"
    955 			"   cfg      <filename>                  = use this cfg file\n"
    956 			"   optimize                             = enable optimization\n"
    957 			"   noverbose                            = disable verbose output\n"
    958 			"   breadthfirst                         = breadth first bsp building\n"
    959 			"   nobrushmerge                         = don't merge brushes\n"
    960 			"   noliquids                            = don't write liquids to map\n"
    961 			"   freetree                             = free the bsp tree\n"
    962 			"   nocsg                                = disables brush chopping\n"
    963 			"   forcesidesvisible                    = force all sides to be visible\n"
    964 			"   grapplereach                         = calculate grapple reachabilities\n"
    965 
    966 /*			"   glview     = output a GL view\n"
    967 			"   draw       = enables drawing\n"
    968 			"   noweld     = disables weld\n"
    969 			"   noshare    = disables sharing\n"
    970 			"   notjunc    = disables juncs\n"
    971 			"   nowater    = disables water brushes\n"
    972 			"   noprune    = disables node prunes\n"
    973 			"   nomerge    = disables face merging\n"
    974 			"   nosubdiv   = disables subdeviding\n"
    975 			"   nodetail   = disables detail brushes\n"
    976 			"   fulldetail = enables full detail\n"
    977 			"   onlyents   = only compile entities with bsp\n"
    978 			"   micro <volume>\n"
    979 			"              = sets the micro volume to the given float\n"
    980 			"   leaktest   = perform a leak test\n"
    981 			"   verboseentities\n"
    982 			"              = enable entity verbose mode\n"
    983 			"   chop <subdivide_size>\n"
    984 			"              = sets the subdivide size to the given float\n"*/
    985 			"\n");
    986 	} //end else
    987 	Log_Print("BSPC run time is %5.0f seconds\n", I_FloatTime() - start_time);
    988 	Log_Close();						//close the log file
    989 	return 0;
    990 } //end of the function main
    991