home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / sharewar / quake106 / utils / qbsp / brush.c next >
C/C++ Source or Header  |  1996-09-12  |  17KB  |  871 lines

  1. // brush.c
  2.  
  3. #include "bsp5.h"
  4.  
  5. int            numbrushplanes;
  6. plane_t        planes[MAX_MAP_PLANES];
  7.  
  8. int            numbrushfaces;
  9. mface_t        faces[128];        // beveled clipping hull can generate many extra
  10.  
  11.  
  12. /*
  13. =================
  14. CheckFace
  15.  
  16. Note: this will not catch 0 area polygons
  17. =================
  18. */
  19. void CheckFace (face_t *f)
  20. {
  21.     int        i, j;
  22.     vec_t    *p1, *p2;
  23.     vec_t    d, edgedist;
  24.     vec3_t    dir, edgenormal, facenormal;
  25.     
  26.     if (f->numpoints < 3)
  27.         Error ("CheckFace: %i points",f->numpoints);
  28.         
  29.     VectorCopy (planes[f->planenum].normal, facenormal);
  30.     if (f->planeside)
  31.     {
  32.         VectorSubtract (vec3_origin, facenormal, facenormal);
  33.     }
  34.     
  35.     for (i=0 ; i<f->numpoints ; i++)
  36.     {
  37.         p1 = f->pts[i];
  38.  
  39.         for (j=0 ; j<3 ; j++)
  40.             if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
  41.                 Error ("CheckFace: BUGUS_RANGE: %f",p1[j]);
  42.  
  43.         j = i+1 == f->numpoints ? 0 : i+1;
  44.         
  45.     // check the point is on the face plane
  46.         d = DotProduct (p1, planes[f->planenum].normal) - planes[f->planenum].dist;
  47.         if (d < -ON_EPSILON || d > ON_EPSILON)
  48.             Error ("CheckFace: point off plane");
  49.     
  50.     // check the edge isn't degenerate
  51.         p2 = f->pts[j];
  52.         VectorSubtract (p2, p1, dir);
  53.         
  54.         if (VectorLength (dir) < ON_EPSILON)
  55.             Error ("CheckFace: degenerate edge");
  56.             
  57.         CrossProduct (facenormal, dir, edgenormal);
  58.         VectorNormalize (edgenormal);
  59.         edgedist = DotProduct (p1, edgenormal);
  60.         edgedist += ON_EPSILON;
  61.         
  62.     // all other points must be on front side
  63.         for (j=0 ; j<f->numpoints ; j++)
  64.         {
  65.             if (j == i)
  66.                 continue;
  67.             d = DotProduct (f->pts[j], edgenormal);
  68.             if (d > edgedist)
  69.                 Error ("CheckFace: non-convex");
  70.         }
  71.     }
  72. }
  73.  
  74.  
  75. //===========================================================================
  76.  
  77. /*
  78. =================
  79. ClearBounds
  80. =================
  81. */
  82. void ClearBounds (brushset_t *bs)
  83. {
  84.     int        i, j;
  85.     
  86.     for (j=0 ; j<NUM_HULLS ; j++)
  87.         for (i=0 ; i<3 ; i++)
  88.         {
  89.             bs->mins[i] = 99999;
  90.             bs->maxs[i] = -99999;
  91.         }
  92. }
  93.  
  94. /*
  95. =================
  96. AddToBounds
  97. =================
  98. */
  99. void AddToBounds (brushset_t *bs, vec3_t v)
  100. {
  101.     int        i;
  102.     
  103.     for (i=0 ; i<3 ; i++)
  104.     {
  105.         if (v[i] < bs->mins[i])
  106.             bs->mins[i] = v[i];
  107.         if (v[i] > bs->maxs[i])
  108.             bs->maxs[i] = v[i];
  109.     }
  110. }
  111.  
  112. //===========================================================================
  113.  
  114. int    PlaneTypeForNormal (vec3_t normal)
  115. {
  116.     float    ax, ay, az;
  117.     
  118. // NOTE: should these have an epsilon around 1.0?        
  119.     if (normal[0] == 1.0)
  120.         return PLANE_X;
  121.     if (normal[1] == 1.0)
  122.         return PLANE_Y;
  123.     if (normal[2] == 1.0)
  124.         return PLANE_Z;
  125.     if (normal[0] == -1.0 ||
  126.         normal[1] == -1.0 ||
  127.         normal[2] == -1.0)
  128.         Error ("PlaneTypeForNormal: not a canonical vector");
  129.         
  130.     ax = fabs(normal[0]);
  131.     ay = fabs(normal[1]);
  132.     az = fabs(normal[2]);
  133.     
  134.     if (ax >= ay && ax >= az)
  135.         return PLANE_ANYX;
  136.     if (ay >= ax && ay >= az)
  137.         return PLANE_ANYY;
  138.     return PLANE_ANYZ;
  139. }
  140.  
  141. #define    DISTEPSILON        0.01
  142. #define    ANGLEEPSILON    0.00001
  143.  
  144. void NormalizePlane (plane_t *dp)
  145. {
  146.     vec_t    ax, ay, az;
  147.     
  148.     if (dp->normal[0] == -1.0)
  149.     {
  150.         dp->normal[0] = 1.0;
  151.         dp->dist = -dp->dist;
  152.     }
  153.     if (dp->normal[1] == -1.0)
  154.     {
  155.         dp->normal[1] = 1.0;
  156.         dp->dist = -dp->dist;
  157.     }
  158.     if (dp->normal[2] == -1.0)
  159.     {
  160.         dp->normal[2] = 1.0;
  161.         dp->dist = -dp->dist;
  162.     }
  163.  
  164.     if (dp->normal[0] == 1.0)
  165.     {
  166.         dp->type = PLANE_X;
  167.         return;
  168.     }
  169.     if (dp->normal[1] == 1.0)
  170.     {
  171.         dp->type = PLANE_Y;
  172.         return;
  173.     }
  174.     if (dp->normal[2] == 1.0)
  175.     {
  176.         dp->type = PLANE_Z;
  177.         return;
  178.     }
  179.  
  180.     ax = fabs(dp->normal[0]);
  181.     ay = fabs(dp->normal[1]);
  182.     az = fabs(dp->normal[2]);
  183.  
  184.     if (ax >= ay && ax >= az)
  185.         dp->type = PLANE_ANYX;
  186.     else if (ay >= ax && ay >= az)
  187.         dp->type = PLANE_ANYY;
  188.     else
  189.         dp->type = PLANE_ANYZ;
  190.     if (dp->normal[dp->type-PLANE_ANYX] < 0)
  191.     {
  192.         VectorSubtract (vec3_origin, dp->normal, dp->normal);
  193.         dp->dist = -dp->dist;
  194.     }
  195.  
  196. }
  197.  
  198. /*
  199. ===============
  200. FindPlane
  201.  
  202. Returns a global plane number and the side that will be the front
  203. ===============
  204. */
  205. int    FindPlane (plane_t *dplane, int *side)
  206. {
  207.     int            i;
  208.     plane_t        *dp, pl;
  209.     vec_t        dot;
  210.         
  211.     dot = VectorLength(dplane->normal);
  212.     if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON)
  213.         Error ("FindPlane: normalization error");
  214.     
  215.     pl = *dplane;
  216.     NormalizePlane (&pl);
  217.     if (DotProduct(pl.normal, dplane->normal) > 0)
  218.         *side = 0;
  219.     else
  220.         *side = 1;
  221.  
  222.     dp = planes;    
  223.     for (i=0 ; i<numbrushplanes;i++, dp++)
  224.     {
  225.         dot = DotProduct (dp->normal, pl.normal);
  226.         if (dot > 1.0 - ANGLEEPSILON 
  227.         && fabs(dp->dist - pl.dist) < DISTEPSILON )
  228.         {    // regular match
  229.             return i;        
  230.         }
  231.     }
  232.  
  233.     if (numbrushplanes == MAX_MAP_PLANES)
  234.         Error ("numbrushplanes == MAX_MAP_PLANES");
  235.  
  236.     planes[numbrushplanes] = pl;
  237.  
  238.     numbrushplanes++;
  239.  
  240.     return numbrushplanes-1;
  241. }
  242.  
  243.  
  244. /*
  245. ===============
  246. FindPlane_old
  247.  
  248. Returns a global plane number and the side that will be the front
  249. ===============
  250. */
  251. int    FindPlane_old (plane_t *dplane, int *side)
  252. {
  253.     int            i;
  254.     plane_t        *dp;
  255.     vec_t        dot, ax, ay, az;
  256.         
  257.     dot = VectorLength(dplane->normal);
  258.     if (dot < 1.0 - ANGLEEPSILON || dot > 1.0 + ANGLEEPSILON)
  259.         Error ("FindPlane: normalization error");
  260.     
  261.     dp = planes;
  262.     
  263.     for (i=0 ; i<numbrushplanes;i++, dp++)
  264.     {
  265.         dot = DotProduct (dplane->normal, dp->normal);
  266.         if (dot > 1.0 - ANGLEEPSILON 
  267.         && fabs(dplane->dist - dp->dist) < DISTEPSILON )
  268.         {    // regular match
  269.             *side = 0;
  270.             return i;        
  271.         }
  272.         if (dot < -1.0+ANGLEEPSILON
  273.         && fabs(dplane->dist + dp->dist) < DISTEPSILON )
  274.         {    // inverse of vector
  275.             *side = 1;
  276.             return i;
  277.         }
  278.     }
  279.     
  280. // allocate a new plane, flipping normal to a consistant direction
  281. // if needed
  282.     *dp = *dplane;
  283.     
  284.     if (numbrushplanes == MAX_MAP_PLANES)
  285.         Error ("numbrushplanes == MAX_MAP_PLANES");
  286.     numbrushplanes++;
  287.     
  288.     *side = 0;
  289.  
  290. // NOTE: should these have an epsilon around 1.0?        
  291.     if (dplane->normal[0] == 1.0)
  292.         dp->type = PLANE_X;
  293.     else if (dplane->normal[1] == 1.0)
  294.         dp->type = PLANE_Y;
  295.     else if (dplane->normal[2] == 1.0)
  296.         dp->type = PLANE_Z;
  297.     else if (dplane->normal[0] == -1.0)
  298.     {
  299.         dp->type = PLANE_X;
  300.         dp->normal[0] = 1.0;
  301.         dp->dist = -dp->dist;
  302.         *side = 1;
  303.     }
  304.     else if (dplane->normal[1] == -1.0)
  305.     {
  306.         dp->type = PLANE_Y;
  307.         dp->normal[1] = 1.0;
  308.         dp->dist = -dp->dist;
  309.         *side = 1;
  310.     }
  311.     else if (dplane->normal[2] == -1.0)
  312.     {
  313.         dp->type = PLANE_Z;
  314.         dp->normal[2] = 1.0;
  315.         dp->dist = -dp->dist;
  316.         *side = 1;
  317.     }
  318.     else
  319.     {
  320.         ax = fabs(dplane->normal[0]);
  321.         ay = fabs(dplane->normal[1]);
  322.         az = fabs(dplane->normal[2]);
  323.         
  324.         if (ax >= ay && ax >= az)
  325.             dp->type = PLANE_ANYX;
  326.         else if (ay >= ax && ay >= az)
  327.             dp->type = PLANE_ANYY;
  328.         else
  329.             dp->type = PLANE_ANYZ;
  330.         if (dplane->normal[dp->type-PLANE_ANYX] < 0)
  331.         {
  332.             VectorSubtract (vec3_origin, dp->normal, dp->normal);
  333.             dp->dist = -dp->dist;
  334.             *side = 1;
  335.         }
  336.     }
  337.         
  338.     return i;
  339. }
  340.  
  341.  
  342.  
  343. /*
  344. =============================================================================
  345.  
  346.             TURN BRUSHES INTO GROUPS OF FACES
  347.  
  348. =============================================================================
  349. */
  350.  
  351. vec3_t        brush_mins, brush_maxs;
  352. face_t        *brush_faces;
  353.  
  354. /*
  355. =================
  356. CreateBrushFaces
  357. =================
  358. */
  359. #define    ZERO_EPSILON    0.001
  360. void CreateBrushFaces (void)
  361. {
  362.     int                i,j, k;
  363.     vec_t            r;
  364.     face_t            *f;
  365.     winding_t        *w;
  366.     plane_t            plane;
  367.     mface_t            *mf;
  368.     
  369.     brush_mins[0] = brush_mins[1] = brush_mins[2] = 99999;
  370.     brush_maxs[0] = brush_maxs[1] = brush_maxs[2] = -99999;
  371.  
  372.     brush_faces = NULL;
  373.     
  374.     for (i=0 ; i<numbrushfaces ; i++)
  375.     {
  376.         mf = &faces[i];
  377.         
  378.         w = BaseWindingForPlane (&mf->plane);
  379.  
  380.         for (j=0 ; j<numbrushfaces && w ; j++)
  381.         {
  382.             if (j == i)
  383.                 continue;
  384.         // flip the plane, because we want to keep the back side
  385.             VectorSubtract (vec3_origin,faces[j].plane.normal, plane.normal);
  386.             plane.dist = -faces[j].plane.dist;
  387.             
  388.             w = ClipWinding (w, &plane, false);
  389.         }
  390.         
  391.         if (!w)
  392.             continue;    // overcontrained plane
  393.             
  394.     // this face is a keeper
  395.         f = AllocFace ();
  396.         f->numpoints = w->numpoints;
  397.         if (f->numpoints > MAXEDGES)
  398.             Error ("f->numpoints > MAXEDGES");
  399.     
  400.         for (j=0 ; j<w->numpoints ; j++)
  401.         {
  402.             for (k=0 ; k<3 ; k++)
  403.             {
  404.                 r = Q_rint (w->points[j][k]);
  405.                 if ( fabs(w->points[j][k] - r) < ZERO_EPSILON)
  406.                     f->pts[j][k] = r;
  407.                 else
  408.                     f->pts[j][k] = w->points[j][k];
  409.                     
  410.                 if (f->pts[j][k] < brush_mins[k])
  411.                     brush_mins[k] = f->pts[j][k];
  412.                 if (f->pts[j][k] > brush_maxs[k])
  413.                     brush_maxs[k] = f->pts[j][k];                
  414.             }
  415.             
  416.         }
  417.         FreeWinding (w);
  418.         f->texturenum = mf->texinfo;
  419.         f->planenum = FindPlane (&mf->plane, &f->planeside);
  420.         f->next = brush_faces;
  421.         brush_faces = f;
  422.         CheckFace (f);
  423.     }    
  424. }
  425.  
  426.  
  427.  
  428. /*
  429. ==============================================================================
  430.  
  431. BEVELED CLIPPING HULL GENERATION
  432.  
  433. This is done by brute force, and could easily get a lot faster if anyone cares.
  434. ==============================================================================
  435. */
  436.  
  437. vec3_t    hull_size[3][2] = {
  438. { {0, 0, 0}, {0, 0, 0} },
  439. { {-16,-16,-32}, {16,16,24} },
  440. { {-32,-32,-64}, {32,32,24} }
  441.  
  442. };
  443.  
  444. #define    MAX_HULL_POINTS    32
  445. #define    MAX_HULL_EDGES    64
  446.  
  447. int        num_hull_points;
  448. vec3_t    hull_points[MAX_HULL_POINTS];
  449. vec3_t    hull_corners[MAX_HULL_POINTS*8];
  450. int        num_hull_edges;
  451. int        hull_edges[MAX_HULL_EDGES][2];
  452.  
  453. /*
  454. ============
  455. AddBrushPlane
  456. =============
  457. */
  458. void AddBrushPlane (plane_t *plane)
  459. {
  460.     int        i;
  461.     plane_t    *pl;
  462.     float    l;
  463.     
  464.     if (numbrushfaces == MAX_FACES)
  465.         Error ("AddBrushPlane: numbrushfaces == MAX_FACES");
  466.     l = VectorLength (plane->normal);
  467.     if (l < 0.999 || l > 1.001)
  468.         Error ("AddBrushPlane: bad normal");
  469.     
  470.     for (i=0 ; i<numbrushfaces ; i++)
  471.     {
  472.         pl = &faces[i].plane;
  473.         if (VectorCompare (pl->normal, plane->normal)
  474.         && fabs(pl->dist - plane->dist) < ON_EPSILON )
  475.             return;
  476.     }
  477.     faces[i].plane = *plane;
  478.     faces[i].texinfo = faces[0].texinfo;
  479.     numbrushfaces++;
  480. }
  481.  
  482.  
  483. /*
  484. ============
  485. TestAddPlane
  486.  
  487. Adds the given plane to the brush description if all of the original brush
  488. vertexes can be put on the front side
  489. =============
  490. */
  491. void TestAddPlane (plane_t *plane)
  492. {
  493.     int        i, c;
  494.     vec_t    d;
  495.     vec_t    *corner;
  496.     plane_t    flip;
  497.     vec3_t    inv;
  498.     int        counts[3];
  499.     plane_t    *pl;
  500.     
  501. // see if the plane has allready been added
  502.     for (i=0 ; i<numbrushfaces ; i++)
  503.     {
  504.         pl = &faces[i].plane;
  505.         if (VectorCompare (plane->normal, pl->normal) && fabs(plane->dist - pl->dist) < ON_EPSILON)
  506.             return;
  507.         VectorSubtract (vec3_origin, plane->normal, inv);
  508.         if (VectorCompare (inv, pl->normal) && fabs(plane->dist + pl->dist) < ON_EPSILON)
  509.             return;
  510.     }
  511.     
  512. // check all the corner points
  513.     counts[0] = counts[1] = counts[2] = 0;
  514.     c = num_hull_points * 8;
  515.     
  516.     corner = hull_corners[0];
  517.     for (i=0 ; i<c ; i++, corner += 3)
  518.     {
  519.         d = DotProduct (corner, plane->normal) - plane->dist;
  520.         if (d < -ON_EPSILON)
  521.         {
  522.             if (counts[0])
  523.                 return;
  524.             counts[1]++;
  525.         }
  526.         else if (d > ON_EPSILON)
  527.         {
  528.             if (counts[1])
  529.                 return;
  530.             counts[0]++;
  531.         }
  532.         else
  533.             counts[2]++;
  534.     }
  535.     
  536. // the plane is a seperator
  537.  
  538.     if (counts[0])
  539.     {
  540.         VectorSubtract (vec3_origin, plane->normal, flip.normal);
  541.         flip.dist = -plane->dist;
  542.         plane = &flip;
  543.     }
  544.     
  545.     AddBrushPlane (plane);
  546. }
  547.  
  548. /*
  549. ============
  550. AddHullPoint
  551.  
  552. Doesn't add if duplicated
  553. =============
  554. */
  555. int AddHullPoint (vec3_t p, int hullnum)
  556. {
  557.     int        i;
  558.     vec_t    *c;
  559.     int        x,y,z;
  560.     
  561.     for (i=0 ; i<num_hull_points ; i++)
  562.         if (VectorCompare (p, hull_points[i]))
  563.             return i;
  564.             
  565.     VectorCopy (p, hull_points[num_hull_points]);
  566.     
  567.     c = hull_corners[i*8];
  568.     
  569.     for (x=0 ; x<2 ; x++)
  570.         for (y=0 ; y<2 ; y++)
  571.             for (z=0; z<2 ; z++)
  572.             {
  573.                 c[0] = p[0] + hull_size[hullnum][x][0];
  574.                 c[1] = p[1] + hull_size[hullnum][y][1];
  575.                 c[2] = p[2] + hull_size[hullnum][z][2];
  576.                 c += 3;
  577.             }
  578.     
  579.     if (num_hull_points == MAX_HULL_POINTS)
  580.         Error ("MAX_HULL_POINTS");
  581.  
  582.     num_hull_points++;
  583.     
  584.     return i;
  585. }
  586.  
  587.  
  588. /*
  589. ============
  590. AddHullEdge
  591.  
  592. Creates all of the hull planes around the given edge, if not done allready
  593. =============
  594. */
  595. void AddHullEdge (vec3_t p1, vec3_t p2, int hullnum)
  596. {
  597.     int        pt1, pt2;
  598.     int        i;
  599.     int        a, b, c, d, e;
  600.     vec3_t    edgevec, planeorg, planevec;
  601.     plane_t    plane;
  602.     vec_t    l;
  603.     
  604.     pt1 = AddHullPoint (p1, hullnum);
  605.     pt2 = AddHullPoint (p2, hullnum);
  606.     
  607.     for (i=0 ; i<num_hull_edges ; i++)
  608.         if ( (hull_edges[i][0] == pt1 && hull_edges[i][1] == pt2)
  609.         || (hull_edges[i][0] == pt2 && hull_edges[i][1] == pt1) )
  610.             return;    // allread added
  611.         
  612.     if (num_hull_edges == MAX_HULL_EDGES)
  613.         Error ("MAX_HULL_EDGES");
  614.  
  615.     hull_edges[i][0] = pt1;
  616.     hull_edges[i][1] = pt2;
  617.     num_hull_edges++;
  618.         
  619.     VectorSubtract (p1, p2, edgevec);
  620.     VectorNormalize (edgevec);
  621.     
  622.     for (a=0 ; a<3 ; a++)
  623.     {
  624.         b = (a+1)%3;
  625.         c = (a+2)%3;
  626.         for (d=0 ; d<=1 ; d++)
  627.             for (e=0 ; e<=1 ; e++)
  628.             {
  629.                 VectorCopy (p1, planeorg);
  630.                 planeorg[b] += hull_size[hullnum][d][b];
  631.                 planeorg[c] += hull_size[hullnum][e][c];
  632.                 
  633.                 VectorCopy (vec3_origin, planevec);
  634.                 planevec[a] = 1;
  635.                 
  636.                 CrossProduct (planevec, edgevec, plane.normal);
  637.                 l = VectorLength (plane.normal);
  638.                 if (l < 1-ANGLEEPSILON || l > 1+ANGLEEPSILON)
  639.                     continue;
  640.                 plane.dist = DotProduct (planeorg, plane.normal);                
  641.                 TestAddPlane (&plane);
  642.             }
  643.     }
  644.     
  645.  
  646. }        
  647.  
  648. /*
  649. ============
  650. ExpandBrush
  651. =============
  652. */
  653. void ExpandBrush (int hullnum)
  654. {
  655.     int        i, x, s;
  656.     vec3_t    corner;
  657.     face_t    *f;
  658.     plane_t    plane, *p;
  659.  
  660.     num_hull_points = 0;
  661.     num_hull_edges = 0;
  662.  
  663. // create all the hull points
  664.     for (f=brush_faces ; f ; f=f->next)
  665.         for (i=0 ; i<f->numpoints ; i++)
  666.             AddHullPoint (f->pts[i], hullnum);
  667.  
  668. // expand all of the planes
  669.     for (i=0 ; i<numbrushfaces ; i++)
  670.     {
  671.         p = &faces[i].plane;
  672.         VectorCopy (vec3_origin, corner);
  673.         for (x=0 ; x<3 ; x++)
  674.         {
  675.             if (p->normal[x] > 0)
  676.                 corner[x] = hull_size[hullnum][1][x];
  677.             else if (p->normal[x] < 0)
  678.                 corner[x] = hull_size[hullnum][0][x];
  679.         }
  680.         p->dist += DotProduct (corner, p->normal);        
  681.     }
  682.  
  683. // add any axis planes not contained in the brush to bevel off corners
  684.     for (x=0 ; x<3 ; x++)
  685.         for (s=-1 ; s<=1 ; s+=2)
  686.         {
  687.         // add the plane
  688.             VectorCopy (vec3_origin, plane.normal);
  689.             plane.normal[x] = s;
  690.             if (s == -1)
  691.                 plane.dist = -brush_mins[x] + -hull_size[hullnum][0][x];
  692.             else
  693.                 plane.dist = brush_maxs[x] + hull_size[hullnum][1][x];
  694.             AddBrushPlane (&plane);
  695.         }
  696.  
  697. // add all of the edge bevels
  698.     for (f=brush_faces ; f ; f=f->next)
  699.         for (i=0 ; i<f->numpoints ; i++)
  700.             AddHullEdge (f->pts[i], f->pts[(i+1)%f->numpoints], hullnum);
  701. }
  702.  
  703. //============================================================================
  704.  
  705.  
  706. /*
  707. ===============
  708. LoadBrush
  709.  
  710. Converts a mapbrush to a bsp brush
  711. ===============
  712. */
  713. brush_t *LoadBrush (mbrush_t *mb, int hullnum)
  714. {
  715.     brush_t        *b;
  716.     int            contents;
  717.     char        *name;
  718.     mface_t        *f;
  719.  
  720. //
  721. // check texture name for attributes
  722. //    
  723.     name = miptex[texinfo[mb->faces->texinfo].miptex];
  724.  
  725.     if (!Q_strcasecmp(name, "clip") && hullnum == 0)
  726.         return NULL;        // "clip" brushes don't show up in the draw hull
  727.     
  728.     if (name[0] == '*' && worldmodel)        // entities never use water merging
  729.     {
  730.         if (!Q_strncasecmp(name+1,"lava",4))
  731.             contents = CONTENTS_LAVA;
  732.         else if (!Q_strncasecmp(name+1,"slime",5))
  733.             contents = CONTENTS_SLIME;
  734.         else            
  735.             contents = CONTENTS_WATER;
  736.     }
  737.     else if (!Q_strncasecmp (name, "sky",3) && worldmodel && hullnum == 0)
  738.         contents = CONTENTS_SKY;
  739.     else
  740.         contents = CONTENTS_SOLID;
  741.  
  742.     if (hullnum && contents != CONTENTS_SOLID && contents != CONTENTS_SKY)
  743.         return NULL;        // water brushes don't show up in clipping hulls
  744.  
  745. // no seperate textures on clip hull
  746.  
  747. //
  748. // create the faces
  749. //
  750.     brush_faces = NULL;
  751.     
  752.     numbrushfaces = 0;
  753.     for (f=mb->faces ; f ; f=f->next)
  754.     {
  755.         faces[numbrushfaces] = *f;
  756.         if (hullnum)
  757.             faces[numbrushfaces].texinfo = 0;
  758.         numbrushfaces++;
  759.     }
  760.         
  761.     CreateBrushFaces ();
  762.     
  763.     if (!brush_faces)
  764.     {
  765.         printf ("WARNING: couldn't create brush faces\n");
  766.         return NULL;
  767.     }
  768.  
  769.     if (hullnum)
  770.     {
  771.         ExpandBrush (hullnum);
  772.         CreateBrushFaces ();
  773.     }
  774.     
  775. //
  776. // create the brush
  777. //
  778.     b = AllocBrush ();
  779.     
  780.     b->contents = contents;
  781.     b->faces = brush_faces;
  782.     VectorCopy (brush_mins, b->mins);
  783.     VectorCopy (brush_maxs, b->maxs);
  784.  
  785.     return b;
  786. }
  787.  
  788. //=============================================================================
  789.  
  790.  
  791. /*
  792. ============
  793. Brush_DrawAll
  794.  
  795. ============
  796. */
  797. void Brush_DrawAll (brushset_t *bs)
  798. {
  799.     brush_t    *b;
  800.     face_t    *f;
  801.  
  802.     for (b=bs->brushes ; b ; b=b->next)
  803.         for (f=b->faces ; f ; f=f->next)
  804.             Draw_DrawFace (f);    
  805. }
  806.  
  807.  
  808. /*
  809. ============
  810. Brush_LoadEntity
  811. ============
  812. */
  813. brushset_t *Brush_LoadEntity (entity_t *ent, int hullnum)
  814. {
  815.     brush_t        *b, *next, *water, *other;
  816.     mbrush_t    *mbr;
  817.     int            numbrushes;
  818.     brushset_t    *bset;
  819.         
  820.     bset = malloc (sizeof(brushset_t));
  821.     memset (bset, 0, sizeof(brushset_t));
  822.     ClearBounds (bset);
  823.  
  824.     numbrushes = 0;
  825.     other = water = NULL;
  826.  
  827.     qprintf ("--- Brush_LoadEntity ---\n");
  828.  
  829.     for (mbr = ent->brushes ; mbr ; mbr=mbr->next)
  830.     {
  831.         b = LoadBrush (mbr, hullnum);
  832.         if (!b)
  833.             continue;
  834.         
  835.         numbrushes++;
  836.  
  837.         if (b->contents != CONTENTS_SOLID)
  838.         {
  839.             b->next = water;
  840.             water = b;
  841.         }
  842.         else
  843.         {
  844.             b->next = other;
  845.             other = b;
  846.         }
  847.     
  848.         AddToBounds (bset, b->mins);
  849.         AddToBounds (bset, b->maxs);
  850.     }
  851.  
  852. // add all of the water textures at the start
  853.     for (b=water ; b ; b=next)
  854.     {
  855.         next = b->next;
  856.         b->next = other;
  857.         other = b;
  858.     }
  859.  
  860.     bset->brushes = other;
  861.  
  862.     brushset = bset;
  863.     Brush_DrawAll (bset);
  864.     
  865.     qprintf ("%i brushes read\n",numbrushes);
  866.     
  867.     return bset;
  868. }
  869.  
  870.  
  871.