PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/utils/qutils/qbsp/qbsp.c

https://gitlab.com/fzwoch/fodquake
C | 1028 lines | 653 code | 184 blank | 191 comment | 135 complexity | d714434ae2dc004589a7532ba2345fea MD5 | raw file
Possible License(s): GPL-2.0
  1. /* Copyright (C) 1996-1997 Id Software, Inc.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. // bsp5.c
  16. #include "bsp5.h"
  17. //
  18. // command line flags
  19. //
  20. qboolean drawflag;
  21. qboolean nofill;
  22. qboolean notjunc;
  23. qboolean noclip;
  24. qboolean onlyents;
  25. qboolean verbose = true;
  26. qboolean allverbose;
  27. qboolean usehulls;
  28. int subdivide_size = 240;
  29. brushset_t *brushset;
  30. int valid;
  31. char bspfilename[1024];
  32. char pointfilename[1024];
  33. char portfilename[1024];
  34. char hullfilename[1024];
  35. char *argv0; // changed after fork();
  36. qboolean worldmodel;
  37. int hullnum;
  38. //===========================================================================
  39. void qprintf (char *fmt, ...)
  40. {
  41. va_list argptr;
  42. if (!verbose)
  43. return;
  44. va_start (argptr, fmt);
  45. vprintf (fmt,argptr);
  46. va_end (argptr);
  47. }
  48. /*
  49. =================
  50. BaseWindingForPlane
  51. =================
  52. */
  53. winding_t *BaseWindingForPlane (plane_t *p)
  54. {
  55. int i, x;
  56. vec_t max, v;
  57. vec3_t org, vright, vup;
  58. winding_t *w;
  59. // find the major axis
  60. max = -BOGUS_RANGE;
  61. x = -1;
  62. for (i=0 ; i<3; i++)
  63. {
  64. v = fabs(p->normal[i]);
  65. if (v > max)
  66. {
  67. x = i;
  68. max = v;
  69. }
  70. }
  71. if (x==-1)
  72. Error ("BaseWindingForPlane: no axis found");
  73. VectorCopy (vec3_origin, vup);
  74. switch (x)
  75. {
  76. case 0:
  77. case 1:
  78. vup[2] = 1;
  79. break;
  80. case 2:
  81. vup[0] = 1;
  82. break;
  83. }
  84. v = DotProduct (vup, p->normal);
  85. VectorMA (vup, -v, p->normal, vup);
  86. VectorNormalize (vup);
  87. VectorScale (p->normal, p->dist, org);
  88. CrossProduct (vup, p->normal, vright);
  89. VectorScale (vup, 8192, vup);
  90. VectorScale (vright, 8192, vright);
  91. // project a really big axis aligned box onto the plane
  92. w = NewWinding (4);
  93. VectorSubtract (org, vright, w->points[0]);
  94. VectorAdd (w->points[0], vup, w->points[0]);
  95. VectorAdd (org, vright, w->points[1]);
  96. VectorAdd (w->points[1], vup, w->points[1]);
  97. VectorAdd (org, vright, w->points[2]);
  98. VectorSubtract (w->points[2], vup, w->points[2]);
  99. VectorSubtract (org, vright, w->points[3]);
  100. VectorSubtract (w->points[3], vup, w->points[3]);
  101. w->numpoints = 4;
  102. return w;
  103. }
  104. /*
  105. ==================
  106. CheckWinding
  107. Check for possible errors
  108. ==================
  109. */
  110. void CheckWinding (winding_t *w)
  111. {
  112. }
  113. /*
  114. ==================
  115. ClipWinding
  116. Clips the winding to the plane, returning the new winding on the positive side
  117. Frees the input winding.
  118. If keepon is true, an exactly on-plane winding will be saved, otherwise
  119. it will be clipped away.
  120. ==================
  121. */
  122. winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
  123. {
  124. vec_t dists[MAX_POINTS_ON_WINDING];
  125. int sides[MAX_POINTS_ON_WINDING];
  126. int counts[3];
  127. vec_t dot;
  128. int i, j;
  129. vec_t *p1, *p2;
  130. vec3_t mid;
  131. winding_t *neww;
  132. int maxpts;
  133. counts[0] = counts[1] = counts[2] = 0;
  134. // determine sides for each point
  135. for (i=0 ; i<in->numpoints ; i++)
  136. {
  137. dot = DotProduct (in->points[i], split->normal);
  138. dot -= split->dist;
  139. dists[i] = dot;
  140. if (dot > ON_EPSILON)
  141. sides[i] = SIDE_FRONT;
  142. else if (dot < -ON_EPSILON)
  143. sides[i] = SIDE_BACK;
  144. else
  145. {
  146. sides[i] = SIDE_ON;
  147. }
  148. counts[sides[i]]++;
  149. }
  150. sides[i] = sides[0];
  151. dists[i] = dists[0];
  152. if (keepon && !counts[0] && !counts[1])
  153. return in;
  154. if (!counts[0])
  155. {
  156. FreeWinding (in);
  157. return NULL;
  158. }
  159. if (!counts[1])
  160. return in;
  161. maxpts = in->numpoints+4; // can't use counts[0]+2 because
  162. // of fp grouping errors
  163. neww = NewWinding (maxpts);
  164. for (i=0 ; i<in->numpoints ; i++)
  165. {
  166. p1 = in->points[i];
  167. if (sides[i] == SIDE_ON)
  168. {
  169. VectorCopy (p1, neww->points[neww->numpoints]);
  170. neww->numpoints++;
  171. continue;
  172. }
  173. if (sides[i] == SIDE_FRONT)
  174. {
  175. VectorCopy (p1, neww->points[neww->numpoints]);
  176. neww->numpoints++;
  177. }
  178. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  179. continue;
  180. // generate a split point
  181. p2 = in->points[(i+1)%in->numpoints];
  182. dot = dists[i] / (dists[i]-dists[i+1]);
  183. for (j=0 ; j<3 ; j++)
  184. { // avoid round off error when possible
  185. if (split->normal[j] == 1)
  186. mid[j] = split->dist;
  187. else if (split->normal[j] == -1)
  188. mid[j] = -split->dist;
  189. else
  190. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  191. }
  192. VectorCopy (mid, neww->points[neww->numpoints]);
  193. neww->numpoints++;
  194. }
  195. if (neww->numpoints > maxpts)
  196. Error ("ClipWinding: points exceeded estimate");
  197. // free the original winding
  198. FreeWinding (in);
  199. return neww;
  200. }
  201. /*
  202. ==================
  203. DivideWinding
  204. Divides a winding by a plane, producing one or two windings. The
  205. original winding is not damaged or freed. If only on one side, the
  206. returned winding will be the input winding. If on both sides, two
  207. new windings will be created.
  208. ==================
  209. */
  210. void DivideWinding (winding_t *in, plane_t *split, winding_t **front, winding_t **back)
  211. {
  212. vec_t dists[MAX_POINTS_ON_WINDING];
  213. int sides[MAX_POINTS_ON_WINDING];
  214. int counts[3];
  215. vec_t dot;
  216. int i, j;
  217. vec_t *p1, *p2;
  218. vec3_t mid;
  219. winding_t *f, *b;
  220. int maxpts;
  221. counts[0] = counts[1] = counts[2] = 0;
  222. // determine sides for each point
  223. for (i=0 ; i<in->numpoints ; i++)
  224. {
  225. dot = DotProduct (in->points[i], split->normal);
  226. dot -= split->dist;
  227. dists[i] = dot;
  228. if (dot > ON_EPSILON)
  229. sides[i] = SIDE_FRONT;
  230. else if (dot < -ON_EPSILON)
  231. sides[i] = SIDE_BACK;
  232. else
  233. {
  234. sides[i] = SIDE_ON;
  235. }
  236. counts[sides[i]]++;
  237. }
  238. sides[i] = sides[0];
  239. dists[i] = dists[0];
  240. *front = *back = NULL;
  241. if (!counts[0])
  242. {
  243. *back = in;
  244. return;
  245. }
  246. if (!counts[1])
  247. {
  248. *front = in;
  249. return;
  250. }
  251. maxpts = in->numpoints+4; // can't use counts[0]+2 because
  252. // of fp grouping errors
  253. *front = f = NewWinding (maxpts);
  254. *back = b = NewWinding (maxpts);
  255. for (i=0 ; i<in->numpoints ; i++)
  256. {
  257. p1 = in->points[i];
  258. if (sides[i] == SIDE_ON)
  259. {
  260. VectorCopy (p1, f->points[f->numpoints]);
  261. f->numpoints++;
  262. VectorCopy (p1, b->points[b->numpoints]);
  263. b->numpoints++;
  264. continue;
  265. }
  266. if (sides[i] == SIDE_FRONT)
  267. {
  268. VectorCopy (p1, f->points[f->numpoints]);
  269. f->numpoints++;
  270. }
  271. if (sides[i] == SIDE_BACK)
  272. {
  273. VectorCopy (p1, b->points[b->numpoints]);
  274. b->numpoints++;
  275. }
  276. if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  277. continue;
  278. // generate a split point
  279. p2 = in->points[(i+1)%in->numpoints];
  280. dot = dists[i] / (dists[i]-dists[i+1]);
  281. for (j=0 ; j<3 ; j++)
  282. { // avoid round off error when possible
  283. if (split->normal[j] == 1)
  284. mid[j] = split->dist;
  285. else if (split->normal[j] == -1)
  286. mid[j] = -split->dist;
  287. else
  288. mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  289. }
  290. VectorCopy (mid, f->points[f->numpoints]);
  291. f->numpoints++;
  292. VectorCopy (mid, b->points[b->numpoints]);
  293. b->numpoints++;
  294. }
  295. if (f->numpoints > maxpts || b->numpoints > maxpts)
  296. Error ("ClipWinding: points exceeded estimate");
  297. }
  298. //===========================================================================
  299. int c_activefaces, c_peakfaces;
  300. int c_activesurfaces, c_peaksurfaces;
  301. int c_activewindings, c_peakwindings;
  302. int c_activeportals, c_peakportals;
  303. void PrintMemory (void)
  304. {
  305. printf ("faces : %6i (%6i)\n", c_activefaces, c_peakfaces);
  306. printf ("surfaces: %6i (%6i)\n", c_activesurfaces, c_peaksurfaces);
  307. printf ("windings: %6i (%6i)\n", c_activewindings, c_peakwindings);
  308. printf ("portals : %6i (%6i)\n", c_activeportals, c_peakportals);
  309. }
  310. /*
  311. ==================
  312. NewWinding
  313. ==================
  314. */
  315. winding_t *NewWinding (int points)
  316. {
  317. winding_t *w;
  318. int size;
  319. if (points > MAX_POINTS_ON_WINDING)
  320. Error ("NewWinding: %i points", points);
  321. c_activewindings++;
  322. if (c_activewindings > c_peakwindings)
  323. c_peakwindings = c_activewindings;
  324. size = (int)((winding_t *)0)->points[points];
  325. w = malloc (size);
  326. memset (w, 0, size);
  327. return w;
  328. }
  329. void FreeWinding (winding_t *w)
  330. {
  331. c_activewindings--;
  332. free (w);
  333. }
  334. /*
  335. ===========
  336. AllocFace
  337. ===========
  338. */
  339. face_t *AllocFace (void)
  340. {
  341. face_t *f;
  342. c_activefaces++;
  343. if (c_activefaces > c_peakfaces)
  344. c_peakfaces = c_activefaces;
  345. f = malloc (sizeof(face_t));
  346. memset (f, 0, sizeof(face_t));
  347. f->planenum = -1;
  348. return f;
  349. }
  350. void FreeFace (face_t *f)
  351. {
  352. c_activefaces--;
  353. // memset (f,0xff,sizeof(face_t));
  354. free (f);
  355. }
  356. /*
  357. ===========
  358. AllocSurface
  359. ===========
  360. */
  361. surface_t *AllocSurface (void)
  362. {
  363. surface_t *s;
  364. s = malloc (sizeof(surface_t));
  365. memset (s, 0, sizeof(surface_t));
  366. c_activesurfaces++;
  367. if (c_activesurfaces > c_peaksurfaces)
  368. c_peaksurfaces = c_activesurfaces;
  369. return s;
  370. }
  371. void FreeSurface (surface_t *s)
  372. {
  373. c_activesurfaces--;
  374. free (s);
  375. }
  376. /*
  377. ===========
  378. AllocPortal
  379. ===========
  380. */
  381. portal_t *AllocPortal (void)
  382. {
  383. portal_t *p;
  384. c_activeportals++;
  385. if (c_activeportals > c_peakportals)
  386. c_peakportals = c_activeportals;
  387. p = malloc (sizeof(portal_t));
  388. memset (p, 0, sizeof(portal_t));
  389. return p;
  390. }
  391. void FreePortal (portal_t *p)
  392. {
  393. c_activeportals--;
  394. free (p);
  395. }
  396. /*
  397. ===========
  398. AllocNode
  399. ===========
  400. */
  401. node_t *AllocNode (void)
  402. {
  403. node_t *n;
  404. n = malloc (sizeof(node_t));
  405. memset (n, 0, sizeof(node_t));
  406. return n;
  407. }
  408. /*
  409. ===========
  410. AllocBrush
  411. ===========
  412. */
  413. brush_t *AllocBrush (void)
  414. {
  415. brush_t *b;
  416. b = malloc (sizeof(brush_t));
  417. memset (b, 0, sizeof(brush_t));
  418. return b;
  419. }
  420. //===========================================================================
  421. /*
  422. ===============
  423. ProcessEntity
  424. ===============
  425. */
  426. void ProcessEntity (int entnum)
  427. {
  428. entity_t *ent;
  429. char mod[80];
  430. surface_t *surfs;
  431. node_t *nodes;
  432. brushset_t *bs;
  433. ent = &entities[entnum];
  434. if (!ent->brushes)
  435. return; // non-bmodel entity
  436. if (entnum > 0)
  437. {
  438. worldmodel = false;
  439. if (entnum == 1)
  440. qprintf ("--- Internal Entities ---\n");
  441. sprintf (mod, "*%i", nummodels);
  442. if (verbose)
  443. PrintEntity (ent);
  444. if (hullnum == 0)
  445. printf ("MODEL: %s\n", mod);
  446. SetKeyValue (ent, "model", mod);
  447. }
  448. else
  449. worldmodel = true;
  450. //
  451. // take the brush_ts and clip off all overlapping and contained faces,
  452. // leaving a perfect skin of the model with no hidden faces
  453. //
  454. bs = Brush_LoadEntity (ent, hullnum);
  455. if (!bs->brushes)
  456. {
  457. PrintEntity (ent);
  458. Error ("Entity with no valid brushes");
  459. }
  460. brushset = bs;
  461. surfs = CSGFaces (bs);
  462. if (hullnum != 0)
  463. {
  464. nodes = SolidBSP (surfs, true);
  465. if (entnum == 0 && !nofill) // assume non-world bmodels are simple
  466. {
  467. PortalizeWorld (nodes);
  468. if (FillOutside (nodes))
  469. {
  470. surfs = GatherNodeFaces (nodes);
  471. nodes = SolidBSP (surfs, false); // make a really good tree
  472. }
  473. FreeAllPortals (nodes);
  474. }
  475. WriteNodePlanes (nodes);
  476. WriteClipNodes (nodes);
  477. BumpModel (hullnum);
  478. }
  479. else
  480. {
  481. //
  482. // SolidBSP generates a node tree
  483. //
  484. // if not the world, make a good tree first
  485. // the world is just going to make a bad tree
  486. // because the outside filling will force a regeneration later
  487. nodes = SolidBSP (surfs, entnum == 0);
  488. //
  489. // build all the portals in the bsp tree
  490. // some portals are solid polygons, and some are paths to other leafs
  491. //
  492. if (entnum == 0 && !nofill) // assume non-world bmodels are simple
  493. {
  494. PortalizeWorld (nodes);
  495. if (FillOutside (nodes))
  496. {
  497. FreeAllPortals (nodes);
  498. // get the remaining faces together into surfaces again
  499. surfs = GatherNodeFaces (nodes);
  500. // merge polygons
  501. MergeAll (surfs);
  502. // make a really good tree
  503. nodes = SolidBSP (surfs, false);
  504. // make the real portals for vis tracing
  505. PortalizeWorld (nodes);
  506. // save portal file for vis tracing
  507. WritePortalfile (nodes);
  508. // fix tjunctions
  509. tjunc (nodes);
  510. }
  511. FreeAllPortals (nodes);
  512. }
  513. WriteNodePlanes (nodes);
  514. MakeFaceEdges (nodes);
  515. WriteDrawNodes (nodes);
  516. }
  517. }
  518. /*
  519. =================
  520. UpdateEntLump
  521. =================
  522. */
  523. void UpdateEntLump (void)
  524. {
  525. int m, entnum;
  526. char mod[80];
  527. m = 1;
  528. for (entnum = 1 ; entnum < num_entities ; entnum++)
  529. {
  530. if (!entities[entnum].brushes)
  531. continue;
  532. sprintf (mod, "*%i", m);
  533. SetKeyValue (&entities[entnum], "model", mod);
  534. m++;
  535. }
  536. printf ("Updating entities lump...\n");
  537. LoadBSPFile (bspfilename);
  538. WriteEntitiesToString();
  539. WriteBSPFile (bspfilename);
  540. }
  541. /*
  542. =================
  543. WriteClipHull
  544. Write the clipping hull out to a text file so the parent process can get it
  545. =================
  546. */
  547. void WriteClipHull (void)
  548. {
  549. FILE *f;
  550. int i;
  551. dplane_t *p;
  552. dclipnode_t *d;
  553. hullfilename[strlen(hullfilename)-1] = '0' + hullnum;
  554. qprintf ("---- WriteClipHull ----\n");
  555. qprintf ("Writing %s\n", hullfilename);
  556. f = fopen (hullfilename, "w");
  557. if (!f)
  558. Error ("Couldn't open %s", hullfilename);
  559. fprintf (f, "%i\n", nummodels);
  560. for (i=0 ; i<nummodels ; i++)
  561. fprintf (f, "%i\n", dmodels[i].headnode[hullnum]);
  562. fprintf (f, "\n%i\n", numclipnodes);
  563. for (i=0 ; i<numclipnodes ; i++)
  564. {
  565. d = &dclipnodes[i];
  566. p = &dplanes[d->planenum];
  567. // the node number is only written out for human readability
  568. fprintf (f, "%5i : %f %f %f %f : %5i %5i\n", i, p->normal[0], p->normal[1], p->normal[2], p->dist, d->children[0], d->children[1]);
  569. }
  570. fclose (f);
  571. }
  572. /*
  573. =================
  574. ReadClipHull
  575. Read the files written out by the child processes
  576. =================
  577. */
  578. void ReadClipHull (int hullnum)
  579. {
  580. FILE *f;
  581. int i, j, n;
  582. int firstclipnode;
  583. dplane_t p;
  584. dclipnode_t *d;
  585. int c1, c2;
  586. float f1, f2, f3, f4;
  587. int junk;
  588. vec3_t norm;
  589. hullfilename[strlen(hullfilename)-1] = '0' + hullnum;
  590. f = fopen (hullfilename, "r");
  591. if (!f)
  592. Error ("Couldn't open %s", hullfilename);
  593. if (fscanf (f,"%i\n", &n) != 1)
  594. Error ("Error parsing %s", hullfilename);
  595. if (n != nummodels)
  596. Error ("ReadClipHull: hull had %i models, base had %i", n, nummodels);
  597. for (i=0 ; i<n ; i++)
  598. {
  599. fscanf (f, "%i\n", &j);
  600. dmodels[i].headnode[hullnum] = numclipnodes + j;
  601. }
  602. fscanf (f,"\n%i\n", &n);
  603. firstclipnode = numclipnodes;
  604. for (i=0 ; i<n ; i++)
  605. {
  606. if (numclipnodes == MAX_MAP_CLIPNODES)
  607. Error ("ReadClipHull: MAX_MAP_CLIPNODES");
  608. d = &dclipnodes[numclipnodes];
  609. numclipnodes++;
  610. if (fscanf (f,"%i : %f %f %f %f : %i %i\n", &junk, &f1, &f2, &f3, &f4, &c1, &c2) != 7)
  611. Error ("Error parsing %s", hullfilename);
  612. p.normal[0] = f1;
  613. p.normal[1] = f2;
  614. p.normal[2] = f3;
  615. p.dist = f4;
  616. norm[0] = f1; norm[1] = f2; norm[2] = f3; // vec_t precision
  617. p.type = PlaneTypeForNormal (norm);
  618. d->children[0] = c1 >= 0 ? c1 + firstclipnode : c1;
  619. d->children[1] = c2 >= 0 ? c2 + firstclipnode : c2;
  620. d->planenum = FindFinalPlane (&p);
  621. }
  622. }
  623. /*
  624. =================
  625. CreateSingleHull
  626. =================
  627. */
  628. void CreateSingleHull (void)
  629. {
  630. int entnum;
  631. // for each entity in the map file that has geometry
  632. for (entnum = 0 ; entnum < num_entities ; entnum++)
  633. {
  634. ProcessEntity (entnum);
  635. if (!allverbose)
  636. verbose = false; // don't print rest of entities
  637. }
  638. if (hullnum)
  639. WriteClipHull ();
  640. }
  641. /*
  642. =================
  643. CreateHulls
  644. =================
  645. */
  646. void CreateHulls (void)
  647. {
  648. // commanded to create a single hull only
  649. if (hullnum)
  650. {
  651. CreateSingleHull ();
  652. exit (0);
  653. }
  654. // commanded to use the allready existing hulls 1 and 2
  655. if (usehulls)
  656. {
  657. CreateSingleHull ();
  658. return;
  659. }
  660. // commanded to ignore the hulls altogether
  661. if (noclip)
  662. {
  663. CreateSingleHull ();
  664. return;
  665. }
  666. // create all the hulls
  667. #ifdef __alpha
  668. printf ("forking hull processes...\n");
  669. // fork a process for each clipping hull
  670. fflush (stdout);
  671. if (!fork ())
  672. {
  673. hullnum = 1;
  674. verbose = false;
  675. drawflag = false;
  676. sprintf (argv0, "HUL%i", hullnum);
  677. }
  678. else if (!fork ())
  679. {
  680. hullnum = 2;
  681. verbose = false;
  682. drawflag = false;
  683. sprintf (argv0, "HUL%i", hullnum);
  684. }
  685. CreateSingleHull ();
  686. if (hullnum)
  687. exit (0);
  688. wait (NULL); // wait for clip hull process to finish
  689. wait (NULL); // wait for clip hull process to finish
  690. #else
  691. // create the hulls sequentially
  692. printf ("building hulls sequentially...\n");
  693. hullnum = 1;
  694. CreateSingleHull ();
  695. nummodels = 0;
  696. numplanes = 0;
  697. numclipnodes = 0;
  698. hullnum = 2;
  699. CreateSingleHull ();
  700. nummodels = 0;
  701. numplanes = 0;
  702. numclipnodes = 0;
  703. hullnum = 0;
  704. CreateSingleHull ();
  705. #endif
  706. }
  707. /*
  708. =================
  709. ProcessFile
  710. =================
  711. */
  712. void ProcessFile (char *sourcebase, char *bspfilename1)
  713. {
  714. // create filenames
  715. strcpy (bspfilename, bspfilename1);
  716. StripExtension (bspfilename);
  717. strcat (bspfilename, ".bsp");
  718. strcpy (hullfilename, bspfilename1);
  719. StripExtension (hullfilename);
  720. strcat (hullfilename, ".h0");
  721. strcpy (portfilename, bspfilename1);
  722. StripExtension (portfilename);
  723. strcat (portfilename, ".prt");
  724. strcpy (pointfilename, bspfilename1);
  725. StripExtension (pointfilename);
  726. strcat (pointfilename, ".pts");
  727. if (!onlyents)
  728. {
  729. remove (bspfilename);
  730. if (!usehulls)
  731. {
  732. hullfilename[strlen(hullfilename)-1] = '1';
  733. remove (hullfilename);
  734. hullfilename[strlen(hullfilename)-1] = '2';
  735. remove (hullfilename);
  736. }
  737. remove (portfilename);
  738. remove (pointfilename);
  739. }
  740. // load brushes and entities
  741. LoadMapFile (sourcebase);
  742. if (onlyents)
  743. {
  744. UpdateEntLump ();
  745. return;
  746. }
  747. // init the tables to be shared by all models
  748. BeginBSPFile ();
  749. // the clipping hulls will be written out to text files by forked processes
  750. CreateHulls ();
  751. ReadClipHull (1);
  752. ReadClipHull (2);
  753. WriteEntitiesToString();
  754. FinishBSPFile ();
  755. }
  756. /*
  757. ==================
  758. main
  759. ==================
  760. */
  761. int main (int argc, char **argv)
  762. {
  763. int i;
  764. double start, end;
  765. char sourcename[1024];
  766. char destname[1024];
  767. // malloc_debug (15);
  768. //
  769. // check command line flags
  770. //
  771. for (i=1 ; i<argc ; i++)
  772. {
  773. if (argv[i][0] != '-')
  774. break;
  775. else if (!strcmp (argv[i],"-draw"))
  776. drawflag = true;
  777. else if (!strcmp (argv[i],"-notjunc"))
  778. notjunc = true;
  779. else if (!strcmp (argv[i],"-nofill"))
  780. nofill = true;
  781. else if (!strcmp (argv[i],"-noclip"))
  782. noclip = true;
  783. else if (!strcmp (argv[i],"-onlyents"))
  784. onlyents = true;
  785. else if (!strcmp (argv[i],"-verbose"))
  786. allverbose = true;
  787. else if (!strcmp (argv[i],"-usehulls"))
  788. usehulls = true; // don't fork -- use the existing files
  789. else if (!strcmp (argv[i],"-hullnum"))
  790. {
  791. hullnum = atoi(argv[i+1]);
  792. i++;
  793. }
  794. else if (!strcmp (argv[i],"-subdivide"))
  795. {
  796. subdivide_size = atoi(argv[i+1]);
  797. i++;
  798. }
  799. else
  800. Error ("qbsp: Unknown option '%s'", argv[i]);
  801. }
  802. if (i != argc - 2 && i != argc - 1)
  803. Error ("usage: qbsp [options] sourcefile [destfile]\noptions: -nojunc -nofill -threads[124] -draw -onlyents -verbose -proj <projectpath>");
  804. //
  805. // let forked processes change name for ps status
  806. //
  807. argv0 = argv[0];
  808. //
  809. // create destination name if not specified
  810. //
  811. strcpy (sourcename, argv[i]);
  812. DefaultExtension (sourcename, ".map");
  813. if (i != argc - 2)
  814. {
  815. strcpy (destname, argv[i]);
  816. StripExtension (destname);
  817. strcat (destname, ".bsp");
  818. printf ("outputfile: %s\n", destname);
  819. }
  820. else
  821. strcpy (destname, argv[i+1]);
  822. //
  823. // do it!
  824. //
  825. start = I_FloatTime ();
  826. ProcessFile (sourcename, destname);
  827. end = I_FloatTime ();
  828. printf ("%5.1f seconds elapsed\n", end-start);
  829. return 0;
  830. }