home *** CD-ROM | disk | FTP | other *** search
/ Dream 57 / Amiga_Dream_57.iso / Amiga / Programmation / c / QuakeC / qtools0.2-src.lha / src / libqbuild / brush.c next >
Encoding:
C/C++ Source or Header  |  1998-07-15  |  20.6 KB  |  910 lines

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