qbsp3.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1997-2006 Id Software, Inc.
  4. This file is part of Quake 2 Tools source code.
  5. Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "qbsp.h"
  19. extern float subdivide_size;
  20. char source[1024];
  21. char name[1024];
  22. vec_t microvolume = 1.0;
  23. qboolean noprune;
  24. qboolean glview;
  25. qboolean nodetail;
  26. qboolean fulldetail;
  27. qboolean onlyents;
  28. qboolean nomerge;
  29. qboolean nowater;
  30. qboolean nofill;
  31. qboolean nocsg;
  32. qboolean noweld;
  33. qboolean noshare;
  34. qboolean nosubdiv;
  35. qboolean notjunc;
  36. qboolean noopt;
  37. qboolean leaktest;
  38. qboolean verboseentities;
  39. char outbase[32];
  40. int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
  41. int entity_num;
  42. node_t *block_nodes[10][10];
  43. /*
  44. ============
  45. BlockTree
  46. ============
  47. */
  48. node_t *BlockTree (int xl, int yl, int xh, int yh)
  49. {
  50. node_t *node;
  51. vec3_t normal;
  52. float dist;
  53. int mid;
  54. if (xl == xh && yl == yh)
  55. {
  56. node = block_nodes[xl+5][yl+5];
  57. if (!node)
  58. { // return an empty leaf
  59. node = AllocNode ();
  60. node->planenum = PLANENUM_LEAF;
  61. node->contents = 0; //CONTENTS_SOLID;
  62. return node;
  63. }
  64. return node;
  65. }
  66. // create a seperator along the largest axis
  67. node = AllocNode ();
  68. if (xh - xl > yh - yl)
  69. { // split x axis
  70. mid = xl + (xh-xl)/2 + 1;
  71. normal[0] = 1;
  72. normal[1] = 0;
  73. normal[2] = 0;
  74. dist = mid*1024;
  75. node->planenum = FindFloatPlane (normal, dist);
  76. node->children[0] = BlockTree ( mid, yl, xh, yh);
  77. node->children[1] = BlockTree ( xl, yl, mid-1, yh);
  78. }
  79. else
  80. {
  81. mid = yl + (yh-yl)/2 + 1;
  82. normal[0] = 0;
  83. normal[1] = 1;
  84. normal[2] = 0;
  85. dist = mid*1024;
  86. node->planenum = FindFloatPlane (normal, dist);
  87. node->children[0] = BlockTree ( xl, mid, xh, yh);
  88. node->children[1] = BlockTree ( xl, yl, xh, mid-1);
  89. }
  90. return node;
  91. }
  92. /*
  93. ============
  94. ProcessBlock_Thread
  95. ============
  96. */
  97. int brush_start, brush_end;
  98. void ProcessBlock_Thread (int blocknum)
  99. {
  100. int xblock, yblock;
  101. vec3_t mins, maxs;
  102. bspbrush_t *brushes;
  103. tree_t *tree;
  104. node_t *node;
  105. yblock = block_yl + blocknum / (block_xh-block_xl+1);
  106. xblock = block_xl + blocknum % (block_xh-block_xl+1);
  107. qprintf ("############### block %2i,%2i ###############\n", xblock, yblock);
  108. mins[0] = xblock*1024;
  109. mins[1] = yblock*1024;
  110. mins[2] = -4096;
  111. maxs[0] = (xblock+1)*1024;
  112. maxs[1] = (yblock+1)*1024;
  113. maxs[2] = 4096;
  114. // the makelist and chopbrushes could be cached between the passes...
  115. brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
  116. if (!brushes)
  117. {
  118. node = AllocNode ();
  119. node->planenum = PLANENUM_LEAF;
  120. node->contents = CONTENTS_SOLID;
  121. block_nodes[xblock+5][yblock+5] = node;
  122. return;
  123. }
  124. if (!nocsg)
  125. brushes = ChopBrushes (brushes);
  126. tree = BrushBSP (brushes, mins, maxs);
  127. block_nodes[xblock+5][yblock+5] = tree->headnode;
  128. }
  129. /*
  130. ============
  131. ProcessWorldModel
  132. ============
  133. */
  134. void ProcessWorldModel (void)
  135. {
  136. entity_t *e;
  137. tree_t *tree;
  138. qboolean leaked;
  139. qboolean optimize;
  140. e = &entities[entity_num];
  141. brush_start = e->firstbrush;
  142. brush_end = brush_start + e->numbrushes;
  143. leaked = false;
  144. //
  145. // perform per-block operations
  146. //
  147. if (block_xh * 1024 > map_maxs[0])
  148. block_xh = floor(map_maxs[0]/1024.0);
  149. if ( (block_xl+1) * 1024 < map_mins[0])
  150. block_xl = floor(map_mins[0]/1024.0);
  151. if (block_yh * 1024 > map_maxs[1])
  152. block_yh = floor(map_maxs[1]/1024.0);
  153. if ( (block_yl+1) * 1024 < map_mins[1])
  154. block_yl = floor(map_mins[1]/1024.0);
  155. if (block_xl <-4)
  156. block_xl = -4;
  157. if (block_yl <-4)
  158. block_yl = -4;
  159. if (block_xh > 3)
  160. block_xh = 3;
  161. if (block_yh > 3)
  162. block_yh = 3;
  163. for (optimize = false ; optimize <= true ; optimize++)
  164. {
  165. qprintf ("--------------------------------------------\n");
  166. RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
  167. !verbose, ProcessBlock_Thread);
  168. //
  169. // build the division tree
  170. // oversizing the blocks guarantees that all the boundaries
  171. // will also get nodes.
  172. //
  173. qprintf ("--------------------------------------------\n");
  174. tree = AllocTree ();
  175. tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
  176. tree->mins[0] = (block_xl)*1024;
  177. tree->mins[1] = (block_yl)*1024;
  178. tree->mins[2] = map_mins[2] - 8;
  179. tree->maxs[0] = (block_xh+1)*1024;
  180. tree->maxs[1] = (block_yh+1)*1024;
  181. tree->maxs[2] = map_maxs[2] + 8;
  182. //
  183. // perform the global operations
  184. //
  185. MakeTreePortals (tree);
  186. if (FloodEntities (tree))
  187. FillOutside (tree->headnode);
  188. else
  189. {
  190. printf ("**** leaked ****\n");
  191. leaked = true;
  192. LeakFile (tree);
  193. if (leaktest)
  194. {
  195. printf ("--- MAP LEAKED ---\n");
  196. exit (0);
  197. }
  198. }
  199. MarkVisibleSides (tree, brush_start, brush_end);
  200. if (noopt || leaked)
  201. break;
  202. if (!optimize)
  203. {
  204. FreeTree (tree);
  205. }
  206. }
  207. FloodAreas (tree);
  208. if (glview)
  209. WriteGLView (tree, source);
  210. MakeFaces (tree->headnode);
  211. FixTjuncs (tree->headnode);
  212. if (!noprune)
  213. PruneNodes (tree->headnode);
  214. WriteBSP (tree->headnode);
  215. if (!leaked)
  216. WritePortalFile (tree);
  217. FreeTree (tree);
  218. }
  219. /*
  220. ============
  221. ProcessSubModel
  222. ============
  223. */
  224. void ProcessSubModel (void)
  225. {
  226. entity_t *e;
  227. int start, end;
  228. tree_t *tree;
  229. bspbrush_t *list;
  230. vec3_t mins, maxs;
  231. e = &entities[entity_num];
  232. start = e->firstbrush;
  233. end = start + e->numbrushes;
  234. mins[0] = mins[1] = mins[2] = -4096;
  235. maxs[0] = maxs[1] = maxs[2] = 4096;
  236. list = MakeBspBrushList (start, end, mins, maxs);
  237. if (!nocsg)
  238. list = ChopBrushes (list);
  239. tree = BrushBSP (list, mins, maxs);
  240. MakeTreePortals (tree);
  241. MarkVisibleSides (tree, start, end);
  242. MakeFaces (tree->headnode);
  243. FixTjuncs (tree->headnode);
  244. WriteBSP (tree->headnode);
  245. FreeTree (tree);
  246. }
  247. /*
  248. ============
  249. ProcessModels
  250. ============
  251. */
  252. void ProcessModels (void)
  253. {
  254. BeginBSPFile ();
  255. for (entity_num=0 ; entity_num< num_entities ; entity_num++)
  256. {
  257. if (!entities[entity_num].numbrushes)
  258. continue;
  259. qprintf ("############### model %i ###############\n", nummodels);
  260. BeginModel ();
  261. if (entity_num == 0)
  262. ProcessWorldModel ();
  263. else
  264. ProcessSubModel ();
  265. EndModel ();
  266. if (!verboseentities)
  267. verbose = false; // don't bother printing submodels
  268. }
  269. EndBSPFile ();
  270. }
  271. /*
  272. ============
  273. main
  274. ============
  275. */
  276. int main (int argc, char **argv)
  277. {
  278. int i;
  279. double start, end;
  280. char path[1024];
  281. printf ("---- qbsp3 ----\n");
  282. for (i=1 ; i<argc ; i++)
  283. {
  284. if (!strcmp(argv[i],"-threads"))
  285. {
  286. numthreads = atoi (argv[i+1]);
  287. i++;
  288. }
  289. else if (!strcmp(argv[i],"-glview"))
  290. {
  291. glview = true;
  292. }
  293. else if (!strcmp(argv[i], "-v"))
  294. {
  295. printf ("verbose = true\n");
  296. verbose = true;
  297. }
  298. else if (!strcmp(argv[i], "-draw"))
  299. {
  300. printf ("drawflag = true\n");
  301. drawflag = true;
  302. }
  303. else if (!strcmp(argv[i], "-noweld"))
  304. {
  305. printf ("noweld = true\n");
  306. noweld = true;
  307. }
  308. else if (!strcmp(argv[i], "-nocsg"))
  309. {
  310. printf ("nocsg = true\n");
  311. nocsg = true;
  312. }
  313. else if (!strcmp(argv[i], "-noshare"))
  314. {
  315. printf ("noshare = true\n");
  316. noshare = true;
  317. }
  318. else if (!strcmp(argv[i], "-notjunc"))
  319. {
  320. printf ("notjunc = true\n");
  321. notjunc = true;
  322. }
  323. else if (!strcmp(argv[i], "-nowater"))
  324. {
  325. printf ("nowater = true\n");
  326. nowater = true;
  327. }
  328. else if (!strcmp(argv[i], "-noopt"))
  329. {
  330. printf ("noopt = true\n");
  331. noopt = true;
  332. }
  333. else if (!strcmp(argv[i], "-noprune"))
  334. {
  335. printf ("noprune = true\n");
  336. noprune = true;
  337. }
  338. else if (!strcmp(argv[i], "-nofill"))
  339. {
  340. printf ("nofill = true\n");
  341. nofill = true;
  342. }
  343. else if (!strcmp(argv[i], "-nomerge"))
  344. {
  345. printf ("nomerge = true\n");
  346. nomerge = true;
  347. }
  348. else if (!strcmp(argv[i], "-nosubdiv"))
  349. {
  350. printf ("nosubdiv = true\n");
  351. nosubdiv = true;
  352. }
  353. else if (!strcmp(argv[i], "-nodetail"))
  354. {
  355. printf ("nodetail = true\n");
  356. nodetail = true;
  357. }
  358. else if (!strcmp(argv[i], "-fulldetail"))
  359. {
  360. printf ("fulldetail = true\n");
  361. fulldetail = true;
  362. }
  363. else if (!strcmp(argv[i], "-onlyents"))
  364. {
  365. printf ("onlyents = true\n");
  366. onlyents = true;
  367. }
  368. else if (!strcmp(argv[i], "-micro"))
  369. {
  370. microvolume = atof(argv[i+1]);
  371. printf ("microvolume = %f\n", microvolume);
  372. i++;
  373. }
  374. else if (!strcmp(argv[i], "-leaktest"))
  375. {
  376. printf ("leaktest = true\n");
  377. leaktest = true;
  378. }
  379. else if (!strcmp(argv[i], "-verboseentities"))
  380. {
  381. printf ("verboseentities = true\n");
  382. verboseentities = true;
  383. }
  384. else if (!strcmp(argv[i], "-chop"))
  385. {
  386. subdivide_size = atof(argv[i+1]);
  387. printf ("subdivide_size = %f\n", subdivide_size);
  388. i++;
  389. }
  390. else if (!strcmp(argv[i], "-block"))
  391. {
  392. block_xl = block_xh = atoi(argv[i+1]);
  393. block_yl = block_yh = atoi(argv[i+2]);
  394. printf ("block: %i,%i\n", block_xl, block_yl);
  395. i+=2;
  396. }
  397. else if (!strcmp(argv[i], "-blocks"))
  398. {
  399. block_xl = atoi(argv[i+1]);
  400. block_yl = atoi(argv[i+2]);
  401. block_xh = atoi(argv[i+3]);
  402. block_yh = atoi(argv[i+4]);
  403. printf ("blocks: %i,%i to %i,%i\n",
  404. block_xl, block_yl, block_xh, block_yh);
  405. i+=4;
  406. }
  407. else if (!strcmp (argv[i],"-tmpout"))
  408. {
  409. strcpy (outbase, "/tmp");
  410. }
  411. else if (argv[i][0] == '-')
  412. Error ("Unknown option \"%s\"", argv[i]);
  413. else
  414. break;
  415. }
  416. if (i != argc - 1)
  417. Error ("usage: qbsp3 [options] mapfile");
  418. start = I_FloatTime ();
  419. ThreadSetDefault ();
  420. numthreads = 1; // multiple threads aren't helping...
  421. SetQdirFromPath (argv[i]);
  422. strcpy (source, ExpandArg (argv[i]));
  423. StripExtension (source);
  424. // delete portal and line files
  425. sprintf (path, "%s.prt", source);
  426. remove (path);
  427. sprintf (path, "%s.lin", source);
  428. remove (path);
  429. strcpy (name, ExpandArg (argv[i]));
  430. DefaultExtension (name, ".map"); // might be .reg
  431. //
  432. // if onlyents, just grab the entites and resave
  433. //
  434. if (onlyents)
  435. {
  436. char out[1024];
  437. sprintf (out, "%s.bsp", source);
  438. LoadBSPFile (out);
  439. num_entities = 0;
  440. LoadMapFile (name);
  441. SetModelNumbers ();
  442. SetLightStyles ();
  443. UnparseEntities ();
  444. WriteBSPFile (out);
  445. }
  446. else
  447. {
  448. //
  449. // start from scratch
  450. //
  451. LoadMapFile (name);
  452. SetModelNumbers ();
  453. SetLightStyles ();
  454. ProcessModels ();
  455. }
  456. end = I_FloatTime ();
  457. printf ("%5.0f seconds elapsed\n", end-start);
  458. return 0;
  459. }