bspc.c 28 KB

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