home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / sharewar / quake106 / utils / qbsp / qbsp.c < prev    next >
C/C++ Source or Header  |  1996-09-12  |  19KB  |  1,031 lines

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