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

  1. // vis.c
  2.  
  3. #include "vis.h"
  4.  
  5. #define    MAX_THREADS        4
  6.  
  7. int            numportals;
  8. int            portalleafs;
  9.  
  10. portal_t    *portals;
  11. leaf_t        *leafs;
  12.  
  13. int            c_portaltest, c_portalpass, c_portalcheck;
  14.  
  15.  
  16. qboolean        showgetleaf = true;
  17.  
  18. int        leafon;            // the next leaf to be given to a thread to process
  19.  
  20. #ifdef __alpha
  21. pthread_mutex_t    *my_mutex;
  22. #endif
  23.  
  24. byte    *vismap, *vismap_p, *vismap_end;    // past visfile
  25. int        originalvismapsize;
  26.  
  27. byte    *uncompressed;            // [bitbytes*portalleafs]
  28.  
  29. int        bitbytes;                // (portalleafs+63)>>3
  30. int        bitlongs;
  31.  
  32. #ifdef __alpha
  33. int            numthreads = 4;
  34. #else
  35. int            numthreads = 1;
  36. #endif
  37.  
  38. qboolean        fastvis;
  39. qboolean        verbose;
  40. int            testlevel = 2;
  41.  
  42. #if 0
  43. void NormalizePlane (plane_t *dp)
  44. {
  45.     vec_t    ax, ay, az;
  46.     
  47.     if (dp->normal[0] == -1.0)
  48.     {
  49.         dp->normal[0] = 1.0;
  50.         dp->dist = -dp->dist;
  51.         return;
  52.     }
  53.     if (dp->normal[1] == -1.0)
  54.     {
  55.         dp->normal[1] = 1.0;
  56.         dp->dist = -dp->dist;
  57.         return;
  58.     }
  59.     if (dp->normal[2] == -1.0)
  60.     {
  61.         dp->normal[2] = 1.0;
  62.         dp->dist = -dp->dist;
  63.         return;
  64.     }
  65.     
  66.     ax = fabs(dp->normal[0]);
  67.     ay = fabs(dp->normal[1]);
  68.     az = fabs(dp->normal[2]);
  69.     
  70.     if (ax >= ay && ax >= az)
  71.     {
  72.         if (dp->normal[0] < 0)
  73.         {
  74.             VectorSubtract (vec3_origin, dp->normal, dp->normal);
  75.             dp->dist = -dp->dist;
  76.         }
  77.         return;
  78.     }
  79.     
  80.     if (ay >= ax && ay >= az)
  81.     {
  82.         if (dp->normal[1] < 0)
  83.         {
  84.             VectorSubtract (vec3_origin, dp->normal, dp->normal);
  85.             dp->dist = -dp->dist;
  86.         }
  87.         return;
  88.     }
  89.     
  90.     if (dp->normal[2] < 0)
  91.     {
  92.         VectorSubtract (vec3_origin, dp->normal, dp->normal);
  93.         dp->dist = -dp->dist;
  94.     }
  95. }
  96. #endif
  97.  
  98. void PlaneFromWinding (winding_t *w, plane_t *plane)
  99. {
  100.     vec3_t        v1, v2;
  101.  
  102. // calc plane
  103.     VectorSubtract (w->points[2], w->points[1], v1);
  104.     VectorSubtract (w->points[0], w->points[1], v2);
  105.     CrossProduct (v2, v1, plane->normal);
  106.     VectorNormalize (plane->normal);
  107.     plane->dist = DotProduct (w->points[0], plane->normal);
  108. }
  109.  
  110. //=============================================================================
  111.  
  112. /*
  113. ==================
  114. NewWinding
  115. ==================
  116. */
  117. winding_t *NewWinding (int points)
  118. {
  119.     winding_t    *w;
  120.     int            size;
  121.     
  122.     if (points > MAX_POINTS_ON_WINDING)
  123.         Error ("NewWinding: %i points", points);
  124.     
  125.     size = (int)((winding_t *)0)->points[points];
  126.     w = malloc (size);
  127.     memset (w, 0, size);
  128.     
  129.     return w;
  130. }
  131.  
  132.  
  133. void FreeWinding (winding_t *w)
  134. {
  135.     if (!w->original)
  136.         free (w);
  137. }
  138.  
  139.  
  140. void pw(winding_t *w)
  141. {
  142.     int        i;
  143.     for (i=0 ; i<w->numpoints ; i++)
  144.         printf ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]);
  145. }
  146.  
  147. void prl(leaf_t *l)
  148. {
  149.     int            i;
  150.     portal_t    *p;
  151.     plane_t        pl;
  152.     
  153.     for (i=0 ; i<l->numportals ; i++)
  154.     {
  155.         p = l->portals[i];
  156.         pl = p->plane;
  157.         printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]);
  158.     }
  159. }
  160.  
  161. /*
  162. ==================
  163. CopyWinding
  164. ==================
  165. */
  166. winding_t    *CopyWinding (winding_t *w)
  167. {
  168.     int            size;
  169.     winding_t    *c;
  170.     
  171.     size = (int)((winding_t *)0)->points[w->numpoints];
  172.     c = malloc (size);
  173.     memcpy (c, w, size);
  174.     c->original = false;
  175.     return c;
  176. }
  177.  
  178.  
  179. /*
  180. ==================
  181. ClipWinding
  182.  
  183. Clips the winding to the plane, returning the new winding on the positive side
  184. Frees the input winding.
  185. If keepon is true, an exactly on-plane winding will be saved, otherwise
  186. it will be clipped away.
  187. ==================
  188. */
  189. winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
  190. {
  191.     vec_t    dists[MAX_POINTS_ON_WINDING];
  192.     int        sides[MAX_POINTS_ON_WINDING];
  193.     int        counts[3];
  194.     vec_t    dot;
  195.     int        i, j;
  196.     vec_t    *p1, *p2;
  197.     vec3_t    mid;
  198.     winding_t    *neww;
  199.     int        maxpts;
  200.     
  201.     counts[0] = counts[1] = counts[2] = 0;
  202.  
  203. // determine sides for each point
  204.     for (i=0 ; i<in->numpoints ; i++)
  205.     {
  206.         dot = DotProduct (in->points[i], split->normal);
  207.         dot -= split->dist;
  208.         dists[i] = dot;
  209.         if (dot > ON_EPSILON)
  210.             sides[i] = SIDE_FRONT;
  211.         else if (dot < -ON_EPSILON)
  212.             sides[i] = SIDE_BACK;
  213.         else
  214.         {
  215.             sides[i] = SIDE_ON;
  216.         }
  217.         counts[sides[i]]++;
  218.     }
  219.     sides[i] = sides[0];
  220.     dists[i] = dists[0];
  221.     
  222.     if (keepon && !counts[0] && !counts[1])
  223.         return in;
  224.         
  225.     if (!counts[0])
  226.     {
  227.         FreeWinding (in);
  228.         return NULL;
  229.     }
  230.     if (!counts[1])
  231.         return in;
  232.     
  233.     maxpts = in->numpoints+4;    // can't use counts[0]+2 because
  234.                                 // of fp grouping errors
  235.     neww = NewWinding (maxpts);
  236.         
  237.     for (i=0 ; i<in->numpoints ; i++)
  238.     {
  239.         p1 = in->points[i];
  240.         
  241.         if (sides[i] == SIDE_ON)
  242.         {
  243.             VectorCopy (p1, neww->points[neww->numpoints]);
  244.             neww->numpoints++;
  245.             continue;
  246.         }
  247.     
  248.         if (sides[i] == SIDE_FRONT)
  249.         {
  250.             VectorCopy (p1, neww->points[neww->numpoints]);
  251.             neww->numpoints++;
  252.         }
  253.         
  254.         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  255.             continue;
  256.             
  257.     // generate a split point
  258.         p2 = in->points[(i+1)%in->numpoints];
  259.         
  260.         dot = dists[i] / (dists[i]-dists[i+1]);
  261.         for (j=0 ; j<3 ; j++)
  262.         {    // avoid round off error when possible
  263.             if (split->normal[j] == 1)
  264.                 mid[j] = split->dist;
  265.             else if (split->normal[j] == -1)
  266.                 mid[j] = -split->dist;
  267.             else
  268.                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  269.         }
  270.             
  271.         VectorCopy (mid, neww->points[neww->numpoints]);
  272.         neww->numpoints++;
  273.     }
  274.     
  275.     if (neww->numpoints > maxpts)
  276.         Error ("ClipWinding: points exceeded estimate");
  277.         
  278. // free the original winding
  279.     FreeWinding (in);
  280.     
  281.     return neww;
  282. }
  283.  
  284.  
  285. //=============================================================================
  286.  
  287. /*
  288. =============
  289. GetNextPortal
  290.  
  291. Returns the next portal for a thread to work on
  292. Returns the portals from the least complex, so the later ones can reuse
  293. the earlier information.
  294. =============
  295. */
  296. portal_t *GetNextPortal (void)
  297. {
  298.     int        j;
  299.     portal_t    *p, *tp;
  300.     int        min;
  301.     
  302.     LOCK;
  303.  
  304.     min = 99999;
  305.     p = NULL;
  306.     
  307.     for (j=0, tp = portals ; j<numportals*2 ; j++, tp++)
  308.     {
  309.         if (tp->nummightsee < min && tp->status == stat_none)
  310.         {
  311.             min = tp->nummightsee;
  312.             p = tp;
  313.         }
  314.     }
  315.  
  316.     
  317.     if (p)
  318.         p->status = stat_working;
  319.  
  320.     UNLOCK;
  321.  
  322.     return p;
  323. }
  324.  
  325. /*
  326. ==============
  327. LeafThread
  328. ==============
  329. */
  330. #ifdef __alpha
  331. pthread_addr_t LeafThread (pthread_addr_t thread)
  332. #else
  333. void *LeafThread (int thread)
  334. #endif
  335. {
  336.     portal_t    *p;
  337.         
  338. //printf ("Begining LeafThread: %i\n",(int)thread);    
  339.     do
  340.     {
  341.         p = GetNextPortal ();
  342.         if (!p)
  343.             break;
  344.             
  345.         PortalFlow (p);
  346.         
  347.         if (verbose)
  348.             printf ("portal:%4i  mightsee:%4i  cansee:%4i\n", (int)(p - portals), p->nummightsee, p->numcansee);
  349.     } while (1);
  350.  
  351. //printf ("Completed LeafThread: %i\n",(int)thread);    
  352.  
  353.     return NULL;
  354. }
  355.  
  356. /*
  357. ===============
  358. CompressRow
  359.  
  360. ===============
  361. */
  362. int CompressRow (byte *vis, byte *dest)
  363. {
  364.     int        j;
  365.     int        rep;
  366.     int        visrow;
  367.     byte    *dest_p;
  368.     
  369.     dest_p = dest;
  370.     visrow = (portalleafs + 7)>>3;
  371.     
  372.     for (j=0 ; j<visrow ; j++)
  373.     {
  374.         *dest_p++ = vis[j];
  375.         if (vis[j])
  376.             continue;
  377.  
  378.         rep = 1;
  379.         for ( j++; j<visrow ; j++)
  380.             if (vis[j] || rep == 255)
  381.                 break;
  382.             else
  383.                 rep++;
  384.         *dest_p++ = rep;
  385.         j--;
  386.     }
  387.     
  388.     return dest_p - dest;
  389. }
  390.  
  391.  
  392. /*
  393. ===============
  394. LeafFlow
  395.  
  396. Builds the entire visibility list for a leaf
  397. ===============
  398. */
  399. int        totalvis;
  400.  
  401. void LeafFlow (int leafnum)
  402. {
  403.     leaf_t        *leaf;
  404.     byte        *outbuffer;
  405.     byte        compressed[MAX_MAP_LEAFS/8];
  406.     int            i, j;
  407.     int            numvis;
  408.     byte        *dest;
  409.     portal_t    *p;
  410.     
  411. //
  412. // flow through all portals, collecting visible bits
  413. //
  414.     outbuffer = uncompressed + leafnum*bitbytes;
  415.     leaf = &leafs[leafnum];
  416.     for (i=0 ; i<leaf->numportals ; i++)
  417.     {
  418.         p = leaf->portals[i];
  419.         if (p->status != stat_done)
  420.             Error ("portal not done");
  421.         for (j=0 ; j<bitbytes ; j++)
  422.             outbuffer[j] |= p->visbits[j];
  423.     }
  424.  
  425.     if (outbuffer[leafnum>>3] & (1<<(leafnum&7)))
  426.         Error ("Leaf portals saw into leaf");
  427.         
  428.     outbuffer[leafnum>>3] |= (1<<(leafnum&7));
  429.  
  430.     numvis = 0;
  431.     for (i=0 ; i<portalleafs ; i++)
  432.         if (outbuffer[i>>3] & (1<<(i&3)))
  433.             numvis++;
  434.             
  435. //
  436. // compress the bit string
  437. //
  438.     if (verbose)
  439.         printf ("leaf %4i : %4i visible\n", leafnum, numvis);
  440.     totalvis += numvis;
  441.  
  442. #if 0    
  443.     i = (portalleafs+7)>>3;
  444.     memcpy (compressed, outbuffer, i);
  445. #else
  446.     i = CompressRow (outbuffer, compressed);
  447. #endif
  448.  
  449.     dest = vismap_p;
  450.     vismap_p += i;
  451.     
  452.     if (vismap_p > vismap_end)
  453.         Error ("Vismap expansion overflow");
  454.  
  455.     dleafs[leafnum+1].visofs = dest-vismap;    // leaf 0 is a common solid
  456.  
  457.     memcpy (dest, compressed, i);    
  458. }
  459.  
  460.  
  461. /*
  462. ==================
  463. CalcPortalVis
  464. ==================
  465. */
  466. void CalcPortalVis (void)
  467. {
  468.     int        i;
  469.  
  470. // fastvis just uses mightsee for a very loose bound
  471.     if (fastvis)
  472.     {
  473.         for (i=0 ; i<numportals*2 ; i++)
  474.         {
  475.             portals[i].visbits = portals[i].mightsee;
  476.             portals[i].status = stat_done;
  477.         }
  478.         return;
  479.     }
  480.     
  481.     leafon = 0;
  482.     
  483. #ifdef __alpha
  484. {
  485.     pthread_t    work_threads[MAX_THREADS];
  486.     pthread_addr_t    status;
  487.     pthread_attr_t    attrib;
  488.     pthread_mutexattr_t    mattrib;
  489.     int        i;
  490.     
  491.     my_mutex = malloc (sizeof(*my_mutex));
  492.     if (pthread_mutexattr_create (&mattrib) == -1)
  493.         Error ("pthread_mutex_attr_create failed");
  494.     if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
  495.         Error ("pthread_mutexattr_setkind_np failed");
  496.     if (pthread_mutex_init (my_mutex, mattrib) == -1)
  497.         Error ("pthread_mutex_init failed");
  498.  
  499.     if (pthread_attr_create (&attrib) == -1)
  500.         Error ("pthread_attr_create failed");
  501.     if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
  502.         Error ("pthread_attr_setstacksize failed");
  503.     
  504.     for (i=0 ; i<numthreads ; i++)
  505.     {
  506.           if (pthread_create(&work_threads[i], attrib
  507.         , LeafThread, (pthread_addr_t)i) == -1)
  508.             Error ("pthread_create failed");
  509.     }
  510.         
  511.     for (i=0 ; i<numthreads ; i++)
  512.     {
  513.         if (pthread_join (work_threads[i], &status) == -1)
  514.             Error ("pthread_join failed");
  515.     }
  516.  
  517.     if (pthread_mutex_destroy (my_mutex) == -1)
  518.             Error ("pthread_mutex_destroy failed");
  519. }
  520. #else
  521.     LeafThread (0);
  522. #endif
  523.  
  524.     if (verbose)
  525.     {
  526.         printf ("portalcheck: %i  portaltest: %i  portalpass: %i\n",c_portalcheck, c_portaltest, c_portalpass);
  527.         printf ("c_vistest: %i  c_mighttest: %i\n",c_vistest, c_mighttest);
  528.     }
  529.  
  530. }
  531.  
  532.  
  533. /*
  534. ==================
  535. CalcVis
  536. ==================
  537. */
  538. void CalcVis (void)
  539. {
  540.     int        i;
  541.     
  542.     BasePortalVis ();
  543.     
  544.     CalcPortalVis ();
  545.  
  546. //
  547. // assemble the leaf vis lists by oring and compressing the portal lists
  548. //
  549.     for (i=0 ; i<portalleafs ; i++)
  550.         LeafFlow (i);
  551.         
  552.     printf ("average leafs visible: %i\n", totalvis / portalleafs);
  553. }
  554.  
  555. /*
  556. ==============================================================================
  557.  
  558. PASSAGE CALCULATION (not used yet...)
  559.  
  560. ==============================================================================
  561. */
  562.  
  563. int        count_sep;
  564.  
  565. qboolean PlaneCompare (plane_t *p1, plane_t *p2)
  566. {
  567.     int        i;
  568.  
  569.     if ( fabs(p1->dist - p2->dist) > 0.01)
  570.         return false;
  571.  
  572.     for (i=0 ; i<3 ; i++)
  573.         if ( fabs(p1->normal[i] - p2->normal[i] ) > 0.001)
  574.             return false;
  575.  
  576.     return true;                
  577. }
  578.  
  579. sep_t    *Findpassages (winding_t *source, winding_t *pass)
  580. {
  581.     int            i, j, k, l;
  582.     plane_t        plane;
  583.     vec3_t        v1, v2;
  584.     float        d;
  585.     double        length;
  586.     int            counts[3];
  587.     qboolean        fliptest;
  588.     sep_t        *sep, *list;
  589.     
  590.     list = NULL;
  591.  
  592. // check all combinations    
  593.     for (i=0 ; i<source->numpoints ; i++)
  594.     {
  595.         l = (i+1)%source->numpoints;
  596.         VectorSubtract (source->points[l] , source->points[i], v1);
  597.  
  598.     // fing a vertex of pass that makes a plane that puts all of the
  599.     // vertexes of pass on the front side and all of the vertexes of
  600.     // source on the back side
  601.         for (j=0 ; j<pass->numpoints ; j++)
  602.         {
  603.             VectorSubtract (pass->points[j], source->points[i], v2);
  604.  
  605.             plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
  606.             plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
  607.             plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
  608.             
  609.         // if points don't make a valid plane, skip it
  610.  
  611.             length = plane.normal[0] * plane.normal[0]
  612.             + plane.normal[1] * plane.normal[1]
  613.             + plane.normal[2] * plane.normal[2];
  614.             
  615.             if (length < ON_EPSILON)
  616.                 continue;
  617.  
  618.             length = 1/sqrt(length);
  619.             
  620.             plane.normal[0] *= length;
  621.             plane.normal[1] *= length;
  622.             plane.normal[2] *= length;
  623.  
  624.             plane.dist = DotProduct (pass->points[j], plane.normal);
  625.  
  626.         //
  627.         // find out which side of the generated seperating plane has the
  628.         // source portal
  629.         //
  630.             fliptest = false;
  631.             for (k=0 ; k<source->numpoints ; k++)
  632.             {
  633.                 if (k == i || k == l)
  634.                     continue;
  635.                 d = DotProduct (source->points[k], plane.normal) - plane.dist;
  636.                 if (d < -ON_EPSILON)
  637.                 {    // source is on the negative side, so we want all
  638.                     // pass and target on the positive side
  639.                     fliptest = false;
  640.                     break;
  641.                 }
  642.                 else if (d > ON_EPSILON)
  643.                 {    // source is on the positive side, so we want all
  644.                     // pass and target on the negative side
  645.                     fliptest = true;
  646.                     break;
  647.                 }
  648.             }
  649.             if (k == source->numpoints)
  650.                 continue;        // planar with source portal
  651.  
  652.         //
  653.         // flip the normal if the source portal is backwards
  654.         //
  655.             if (fliptest)
  656.             {
  657.                 VectorSubtract (vec3_origin, plane.normal, plane.normal);
  658.                 plane.dist = -plane.dist;
  659.             }
  660.             
  661.         //
  662.         // if all of the pass portal points are now on the positive side,
  663.         // this is the seperating plane
  664.         //
  665.             counts[0] = counts[1] = counts[2] = 0;
  666.             for (k=0 ; k<pass->numpoints ; k++)
  667.             {
  668.                 if (k==j)
  669.                     continue;
  670.                 d = DotProduct (pass->points[k], plane.normal) - plane.dist;
  671.                 if (d < -ON_EPSILON)
  672.                     break;
  673.                 else if (d > ON_EPSILON)
  674.                     counts[0]++;
  675.                 else
  676.                     counts[2]++;
  677.             }
  678.             if (k != pass->numpoints)
  679.                 continue;    // points on negative side, not a seperating plane
  680.                 
  681.             if (!counts[0])
  682.                 continue;    // planar with pass portal
  683.         
  684.         //
  685.         // save this out
  686.         //
  687.             count_sep++;
  688.  
  689.             sep = malloc(sizeof(*sep));
  690.             sep->next = list;
  691.             list = sep;
  692.             sep->plane = plane;
  693.         }
  694.     }
  695.     
  696.     return list;
  697. }
  698.  
  699.  
  700.  
  701. /*
  702. ============
  703. CalcPassages
  704. ============
  705. */
  706. void CalcPassages (void)
  707. {
  708.     int        i, j, k;
  709.     int        count, count2;
  710.     leaf_t    *l;
  711.     portal_t    *p1, *p2;
  712.     sep_t        *sep;
  713.     passage_t        *passages;
  714.  
  715.     printf ("building passages...\n");
  716.  
  717.     count = count2 = 0;
  718.     for (i=0 ; i<portalleafs ; i++)
  719.     {
  720.         l = &leafs[i];
  721.  
  722.         for (j=0 ; j<l->numportals ; j++)
  723.         {
  724.             p1 = l->portals[j];
  725.             for (k=0 ; k<l->numportals ; k++)
  726.             {
  727.                 if (k==j)
  728.                     continue;
  729.                     
  730.                 count++;
  731.                 p2 = l->portals[k];
  732.             
  733.             // definately can't see into a coplanar portal
  734.                 if (PlaneCompare (&p1->plane, &p2->plane) )
  735.                     continue;
  736.                     
  737.                 count2++;
  738.  
  739.                 sep = Findpassages (p1->winding, p2->winding);
  740.                 if (!sep)
  741.                 {
  742. //                    Error ("No seperating planes found in portal pair");
  743.                     count_sep++;
  744.                     sep = malloc(sizeof(*sep));
  745.                     sep->next = NULL;
  746.                     sep->plane = p1->plane;
  747.                 }
  748.                 passages = malloc(sizeof(*passages));
  749.                 passages->planes = sep;
  750.                 passages->from = p1->leaf;
  751.                 passages->to = p2->leaf;
  752.                 passages->next = l->passages;
  753.                 l->passages = passages;
  754.             }
  755.         }
  756.     }
  757.  
  758.     printf ("numpassages: %i (%i)\n", count2, count);
  759.     printf ("total passages: %i\n", count_sep);
  760. }
  761.  
  762. //=============================================================================
  763.  
  764. /*
  765. ============
  766. LoadPortals
  767. ============
  768. */
  769. void LoadPortals (char *name)
  770. {
  771.     int            i, j;
  772.     portal_t    *p;
  773.     leaf_t        *l;
  774.     char        magic[80];
  775.     FILE        *f;
  776.     int            numpoints;
  777.     winding_t    *w;
  778.     int            leafnums[2];
  779.     plane_t        plane;
  780.     
  781.     if (!strcmp(name,"-"))
  782.         f = stdin;
  783.     else
  784.     {
  785.         f = fopen(name, "r");
  786.         if (!f)
  787.         {
  788.             printf ("LoadPortals: couldn't read %s\n",name);
  789.             printf ("No vising performed.\n");
  790.             exit (1);
  791.         }
  792.     }
  793.  
  794.     if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalleafs, &numportals) != 3)
  795.         Error ("LoadPortals: failed to read header");
  796.     if (strcmp(magic,PORTALFILE))
  797.         Error ("LoadPortals: not a portal file");
  798.  
  799.     printf ("%4i portalleafs\n", portalleafs);
  800.     printf ("%4i numportals\n", numportals);
  801.  
  802.     bitbytes = ((portalleafs+63)&~63)>>3;
  803.     bitlongs = bitbytes/sizeof(long);
  804.     
  805. // each file portal is split into two memory portals
  806.     portals = malloc(2*numportals*sizeof(portal_t));
  807.     memset (portals, 0, 2*numportals*sizeof(portal_t));
  808.     
  809.     leafs = malloc(portalleafs*sizeof(leaf_t));
  810.     memset (leafs, 0, portalleafs*sizeof(leaf_t));
  811.  
  812.     originalvismapsize = portalleafs*((portalleafs+7)/8);
  813.  
  814.     vismap = vismap_p = dvisdata;
  815.     vismap_end = vismap + MAX_MAP_VISIBILITY;
  816.         
  817.     for (i=0, p=portals ; i<numportals ; i++)
  818.     {
  819.         if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1])
  820.             != 3)
  821.             Error ("LoadPortals: reading portal %i", i);
  822.         if (numpoints > MAX_POINTS_ON_WINDING)
  823.             Error ("LoadPortals: portal %i has too many points", i);
  824.         if ( (unsigned)leafnums[0] > portalleafs
  825.         || (unsigned)leafnums[1] > portalleafs)
  826.             Error ("LoadPortals: reading portal %i", i);
  827.         
  828.         w = p->winding = NewWinding (numpoints);
  829.         w->original = true;
  830.         w->numpoints = numpoints;
  831.         
  832.         for (j=0 ; j<numpoints ; j++)
  833.         {
  834.             double    v[3];
  835.             int        k;
  836.  
  837.             // scanf into double, then assign to vec_t
  838.             if (fscanf (f, "(%lf %lf %lf ) "
  839.             , &v[0], &v[1], &v[2]) != 3)
  840.                 Error ("LoadPortals: reading portal %i", i);
  841.             for (k=0 ; k<3 ; k++)
  842.                 w->points[j][k] = v[k];
  843.         }
  844.         fscanf (f, "\n");
  845.         
  846.     // calc plane
  847.         PlaneFromWinding (w, &plane);
  848.  
  849.     // create forward portal
  850.         l = &leafs[leafnums[0]];
  851.         if (l->numportals == MAX_PORTALS_ON_LEAF)
  852.             Error ("Leaf with too many portals");
  853.         l->portals[l->numportals] = p;
  854.         l->numportals++;
  855.         
  856.         p->winding = w;
  857.         VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
  858.         p->plane.dist = -plane.dist;
  859.         p->leaf = leafnums[1];
  860.         p++;
  861.         
  862.     // create backwards portal
  863.         l = &leafs[leafnums[1]];
  864.         if (l->numportals == MAX_PORTALS_ON_LEAF)
  865.             Error ("Leaf with too many portals");
  866.         l->portals[l->numportals] = p;
  867.         l->numportals++;
  868.         
  869.         p->winding = w;
  870.         p->plane = plane;
  871.         p->leaf = leafnums[0];
  872.         p++;
  873.  
  874.     }
  875.     
  876.     fclose (f);
  877. }
  878.  
  879.  
  880. /*
  881. ===========
  882. main
  883. ===========
  884. */
  885. int main (int argc, char **argv)
  886. {
  887.     char    portalfile[1024];
  888.     char        source[1024];
  889.     int        i;
  890.     double        start, end;
  891.         
  892.     printf ("---- vis ----\n");
  893.  
  894.     for (i=1 ; i<argc ; i++)
  895.     {
  896.         if (!strcmp(argv[i],"-threads"))
  897.         {
  898.             numthreads = atoi (argv[i+1]);
  899.             i++;
  900.         }
  901.         else if (!strcmp(argv[i], "-fast"))
  902.         {
  903.             printf ("fastvis = true\n");
  904.             fastvis = true;
  905.         }
  906.         else if (!strcmp(argv[i], "-level"))
  907.         {
  908.             testlevel = atoi(argv[i+1]);
  909.             printf ("testlevel = %i\n", testlevel);
  910.             i++;
  911.         }
  912.         else if (!strcmp(argv[i], "-v"))
  913.         {
  914.             printf ("verbose = true\n");
  915.             verbose = true;
  916.         }
  917.         else if (argv[i][0] == '-')
  918.             Error ("Unknown option \"%s\"", argv[i]);
  919.         else
  920.             break;
  921.     }
  922.  
  923.     if (i != argc - 1)
  924.         Error ("usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile");
  925.  
  926.     start = I_FloatTime ();
  927.     
  928.     strcpy (source, argv[i]);
  929.     StripExtension (source);
  930.     DefaultExtension (source, ".bsp");
  931.  
  932.     LoadBSPFile (source);
  933.     
  934.     strcpy (portalfile, argv[i]);
  935.     StripExtension (portalfile);
  936.     strcat (portalfile, ".prt");
  937.     
  938.     LoadPortals (portalfile);
  939.     
  940.     uncompressed = malloc(bitbytes*portalleafs);
  941.     memset (uncompressed, 0, bitbytes*portalleafs);
  942.     
  943. //    CalcPassages ();
  944.  
  945.     CalcVis ();
  946.  
  947.     printf ("c_chains: %i\n",c_chains);
  948.     
  949.     visdatasize = vismap_p - dvisdata;    
  950.     printf ("visdatasize:%i  compressed from %i\n", visdatasize, originalvismapsize);
  951.     
  952.     CalcAmbientSounds ();
  953.  
  954.     WriteBSPFile (source);    
  955.     
  956. //    unlink (portalfile);
  957.  
  958.     end = I_FloatTime ();
  959.     printf ("%5.1f seconds elapsed\n", end-start);
  960.     
  961.     return 0;
  962. }
  963.  
  964.