home *** CD-ROM | disk | FTP | other *** search
/ Superpower (Alt) / SUPERPOWER.iso / q / source / setbrush.m < prev    next >
Encoding:
Text File  |  1996-08-08  |  35.3 KB  |  2,035 lines

  1. #import "qedefs.h"
  2.  
  3. @implementation SetBrush
  4.  
  5. /*
  6. ==================
  7. textureAxisFromPlane
  8. ==================
  9. */
  10. #if 1
  11. vec3_t    baseaxis[18] =
  12. {
  13. {0,0,1}, {1,0,0}, {0,-1,0},            // floor
  14. {0,0,-1}, {1,0,0}, {0,-1,0},        // ceiling
  15. {1,0,0}, {0,1,0}, {0,0,-1},            // west wall
  16. {-1,0,0}, {0,1,0}, {0,0,-1},        // east wall
  17. {0,1,0}, {1,0,0}, {0,0,-1},            // south wall
  18. {0,-1,0}, {1,0,0}, {0,0,-1}            // north wall
  19. };
  20. #else
  21. vec3_t    baseaxis[18] =
  22. {
  23. {0,0,1}, {1,0,0}, {0,-1,0},            // floor
  24. {0,0,-1}, {1,0,0}, {0,1,0},            // ceiling
  25. {1,0,0}, {0,1,0}, {0,0,-1},            // west wall
  26. {-1,0,0}, {0,-1,0}, {0,0,-1},        // east wall
  27. {0,1,0}, {-1,0,0}, {0,0,-1},        // south wall
  28. {0,-1,0}, {1,0,0}, {0,0,-1}            // north wall
  29. };
  30. #endif
  31.  
  32.  
  33. float TextureAxisFromPlane(plane_t *pln, float *xv, float *yv)
  34. {
  35.     int        bestaxis;
  36.     float    dot,best;
  37.     int        i;
  38.     
  39.     best = 0;
  40.     bestaxis = 0;
  41.     
  42.     for (i=0 ; i<6 ; i++)
  43.     {
  44.         dot = DotProduct (pln->normal, baseaxis[i*3]);
  45.         if (dot > best)
  46.         {
  47.             best = dot;
  48.             bestaxis = i;
  49.         }
  50.     }
  51.     
  52.     VectorCopy (baseaxis[bestaxis*3+1], xv);
  53.     VectorCopy (baseaxis[bestaxis*3+2], yv);
  54.     
  55.     return lightaxis[bestaxis>>1];
  56. }
  57.  
  58. #define    BOGUS_RANGE    18000
  59.  
  60. /*
  61. =================
  62. CheckFace
  63.  
  64. Note: this will not catch 0 area polygons
  65. =================
  66. */
  67. void CheckFace (face_t *f)
  68. {
  69.     int        i, j;
  70.     float    *p1, *p2;
  71.     float    d, edgedist;
  72.     vec3_t    dir, edgenormal;
  73.     winding_t    *w;
  74.     
  75.     w = f->w;
  76.     if (!w)
  77.         Error ("CheckFace: no winding");
  78.         
  79.     if (w->numpoints < 3)
  80.         Error ("CheckFace: %i points",w->numpoints);
  81.     
  82.     for (i=0 ; i<w->numpoints ; i++)
  83.     {
  84.         p1 = w->points[i];
  85.  
  86.         for (j=0 ; j<3 ; j++)
  87.             if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE)
  88.                 Error ("CheckFace: BUGUS_RANGE: %f",p1[j]);
  89.  
  90.         j = i+1 == w->numpoints ? 0 : i+1;
  91.         
  92.     // check the point is on the face plane
  93.         d = DotProduct (p1, f->plane.normal) - f->plane.dist;
  94.         if (d < -ON_EPSILON || d > ON_EPSILON)
  95.             Error ("CheckFace: point off plane");
  96.     
  97.     // check the edge isn't degenerate
  98.         p2 = w->points[j];
  99.         VectorSubtract (p2, p1, dir);
  100.         
  101.         if (VectorLength (dir) < ON_EPSILON)
  102.             Error ("CheckFace: degenerate edge");
  103.             
  104.         CrossProduct (f->plane.normal, dir, edgenormal);
  105.         VectorNormalize (edgenormal);
  106.         edgedist = DotProduct (p1, edgenormal);
  107.         edgedist += ON_EPSILON;
  108.         
  109.     // all other points must be on front side
  110.         for (j=0 ; j<w->numpoints ; j++)
  111.         {
  112.             if (j == i)
  113.                 continue;
  114.             d = DotProduct (w->points[j], edgenormal);
  115.             if (d > edgedist)
  116.                 Error ("CheckFace: non-convex");
  117.         }
  118.     }
  119. }
  120.  
  121.  
  122. /*
  123. =============================================================================
  124.  
  125.             TURN PLANES INTO GROUPS OF FACES
  126.  
  127. =============================================================================
  128. */
  129.  
  130.  
  131. /*
  132. ==================
  133. NewWinding
  134. ==================
  135. */
  136. winding_t *NewWinding (int points)
  137. {
  138.     winding_t    *w;
  139.     int            size;
  140.     
  141.     if (points > MAX_POINTS_ON_WINDING)
  142.         Error ("NewWinding: %i points", points);
  143.     
  144.     size = (int)((winding_t *)0)->points[points];
  145.     w = malloc (size);
  146.     memset (w, 0, size);
  147.     
  148.     return w;
  149. }
  150.  
  151.  
  152. /*
  153. ==================
  154. CopyWinding
  155. ==================
  156. */
  157. winding_t    *CopyWinding (winding_t *w)
  158. {
  159.     int            size;
  160.     winding_t    *c;
  161.     
  162.     size = (int)((winding_t *)0)->points[w->numpoints];
  163.     c = malloc (size);
  164.     memcpy (c, w, size);
  165.     return c;
  166. }
  167.  
  168.  
  169. /*
  170. ==================
  171. ClipWinding
  172.  
  173. Clips the winding to the plane, returning the new winding on the positive side
  174. Frees the input winding.
  175. ==================
  176. */
  177. winding_t *ClipWinding (winding_t *in, plane_t *split)
  178. {
  179.     float    dists[MAX_POINTS_ON_WINDING];
  180.     int        sides[MAX_POINTS_ON_WINDING];
  181.     int        counts[3];
  182.     float    dot;
  183.     int        i, j;
  184.     float    *p1, *p2, *mid;
  185.     winding_t    *neww;
  186.     int        maxpts;
  187.     
  188.     counts[0] = counts[1] = counts[2] = 0;
  189.  
  190. // determine sides for each point
  191.     for (i=0 ; i<in->numpoints ; i++)
  192.     {
  193.         dot = DotProduct (in->points[i], split->normal);
  194.         dot -= split->dist;
  195.         dists[i] = dot;
  196.         if (dot > ON_EPSILON)
  197.             sides[i] = SIDE_FRONT;
  198.         else if (dot < -ON_EPSILON)
  199.             sides[i] = SIDE_BACK;
  200.         else
  201.         {
  202.             sides[i] = SIDE_ON;
  203.         }
  204.         counts[sides[i]]++;
  205.     }
  206.     sides[i] = sides[0];
  207.     dists[i] = dists[0];
  208.     
  209.     if (!counts[0] && !counts[1])
  210.         return in;
  211.         
  212.     if (!counts[0])
  213.     {
  214.         free (in);
  215.         return NULL;
  216.     }
  217.     if (!counts[1])
  218.         return in;
  219.     
  220.     maxpts = in->numpoints+4;    // can't use counts[0]+2 because
  221.                                 // of fp grouping errors
  222.     neww = NewWinding (maxpts);
  223.         
  224.     for (i=0 ; i<in->numpoints ; i++)
  225.     {
  226.         p1 = in->points[i];
  227.         
  228.         mid = neww->points[neww->numpoints];
  229.  
  230.         if (sides[i] == SIDE_FRONT || sides[i] == SIDE_ON)
  231.         {
  232.             VectorCopy (p1, mid);
  233.             mid[3] = p1[3];
  234.             mid[4] = p1[4];
  235.             neww->numpoints++;
  236.             if (sides[i] == SIDE_ON)
  237.                 continue;
  238.             mid = neww->points[neww->numpoints];
  239.         }
  240.         
  241.         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
  242.             continue;
  243.             
  244.     // generate a split point
  245.         if (i == in->numpoints - 1)
  246.             p2 = in->points[0];
  247.         else
  248.             p2 = p1 + 5;
  249.         
  250.         neww->numpoints++;
  251.         
  252.         dot = dists[i] / (dists[i]-dists[i+1]);
  253.         for (j=0 ; j<3 ; j++)
  254.         {    // avoid round off error when possible
  255.             if (split->normal[j] == 1)
  256.                 mid[j] = split->dist;
  257.             else if (split->normal[j] == -1)
  258.                 mid[j] = -split->dist;
  259.             mid[j] = p1[j] + dot*(p2[j]-p1[j]);
  260.         }
  261.         mid[3] = p1[3] + dot*(p2[3]-p1[3]);
  262.         mid[4] = p1[4] + dot*(p2[4]-p1[4]);
  263.     }
  264.  
  265.     if (neww->numpoints > maxpts)
  266.         Error ("ClipWinding: points exceeded estimate");
  267.  
  268. // free the original winding
  269.     free (in);
  270.     
  271.     return neww;
  272. }
  273.  
  274. /*
  275. =================
  276. BasePolyForPlane
  277.  
  278. There has GOT to be a better way of doing this...
  279. =================
  280. */
  281. winding_t *BasePolyForPlane (face_t *f)
  282. {
  283.     int        i, x;
  284.     float    max, v;
  285.     vec3_t    org, vright, vup;
  286.     vec3_t    xaxis, yaxis;
  287.     winding_t    *w;
  288.     texturedef_t    *td;
  289.     plane_t        *p;
  290.     float    ang, sinv, cosv;
  291.     float    s, t, ns, nt;
  292.  
  293.     p = &f->plane;
  294.     
  295. // find the major axis
  296.  
  297.     max = -BOGUS_RANGE;
  298.     x = -1;
  299.     for (i=0 ; i<3; i++)
  300.     {
  301.         v = fabs(p->normal[i]);
  302.         if (v > max)
  303.         {
  304.             x = i;
  305.             max = v;
  306.         }
  307.     }
  308.     if (x==-1)
  309.         Error ("BasePolyForPlane: no axis found");
  310.         
  311.     VectorCopy (vec3_origin, vup);    
  312.     switch (x)
  313.     {
  314.     case 0:
  315.     case 1:
  316.         vup[2] = 1;
  317.         break;        
  318.     case 2:
  319.         vup[0] = 1;
  320.         break;        
  321.     }
  322.  
  323.     v = DotProduct (vup, p->normal);
  324.     VectorMA (vup, -v, p->normal, vup);
  325.     VectorNormalize (vup);
  326.         
  327.     VectorScale (p->normal, p->dist, org);
  328.     
  329.     CrossProduct (vup, p->normal, vright);
  330.     
  331.     VectorScale (vup, 8192, vup);
  332.     VectorScale (vright, 8192, vright);
  333.  
  334. // project a really big    axis aligned box onto the plane
  335.     w = NewWinding (4);
  336.     w->numpoints = 4;
  337.     
  338.     VectorSubtract (org, vright, w->points[0]);
  339.     VectorAdd (w->points[0], vup, w->points[0]);
  340.     
  341.     VectorAdd (org, vright, w->points[1]);
  342.     VectorAdd (w->points[1], vup, w->points[1]);
  343.     
  344.     VectorAdd (org, vright, w->points[2]);
  345.     VectorSubtract (w->points[2], vup, w->points[2]);
  346.     
  347.     VectorSubtract (org, vright, w->points[3]);
  348.     VectorSubtract (w->points[3], vup, w->points[3]);
  349.     
  350. // set texture values
  351.     f->light = TextureAxisFromPlane(&f->plane, xaxis, yaxis);
  352.     td = &f->texture;
  353.     
  354. // rotate axis
  355.     ang = td->rotate / 180 * M_PI;
  356.     sinv = sin(ang);
  357.     cosv = cos(ang);
  358.     
  359.     if (!td->scale[0])
  360.         td->scale[0] = 1;
  361.     if (!td->scale[1])
  362.         td->scale[1] = 1;
  363.  
  364.     for (i=0 ; i<4 ; i++)
  365.     {
  366.         s = DotProduct (w->points[i], xaxis);
  367.         t = DotProduct (w->points[i], yaxis);
  368.  
  369.         ns = cosv * s - sinv * t;
  370.         nt = sinv * s +  cosv * t;
  371.  
  372.         w->points[i][3] = ns/td->scale[0] + td->shift[0];
  373.         w->points[i][4] = nt/td->scale[1] + td->shift[1];
  374.     }
  375.     
  376.     return w;    
  377. }
  378.  
  379. /*
  380. ===========
  381. calcWindings
  382.  
  383. recalc the faces and mins / maxs from the planes
  384. If a face has a NULL winding, it is an overconstraining plane and
  385. can be removed.
  386. ===========
  387. */
  388. - calcWindings
  389. {
  390.     int                i,j, k;
  391.     float            v;
  392.     face_t            *f;
  393.     winding_t        *w;
  394.     plane_t            plane;
  395.     vec3_t            t1, t2, t3;
  396.     BOOL            useplane[MAX_FACES];
  397.     
  398.     bmins[0] = bmins[1] = bmins[2] = 99999;
  399.     bmaxs[0] = bmaxs[1] = bmaxs[2] = -99999;
  400.     invalid = NO;
  401.     
  402.     [self freeWindings];
  403.     
  404.     for (i=0 ; i<MAX_FACES ; i++)
  405.     {
  406.         f = &faces[i];
  407.         
  408.     // calc a plane from the points
  409.         for (j=0 ; j<3 ; j++)
  410.         {
  411.             t1[j] = f->planepts[0][j] - f->planepts[1][j];
  412.             t2[j] = f->planepts[2][j] - f->planepts[1][j];
  413.             t3[j] = f->planepts[1][j];
  414.         }
  415.         
  416.         CrossProduct(t1,t2, f->plane.normal);
  417.         if (VectorCompare (f->plane.normal, vec3_origin))
  418.         {
  419.             useplane[i] = NO;
  420.             break;
  421.         }
  422.         VectorNormalize (f->plane.normal);
  423.         f->plane.dist = DotProduct (t3, f->plane.normal);
  424.         
  425.     // if the plane duplicates another plane, ignore it
  426.     // (assume it is a brush being edited that will be fixed)
  427.         useplane[i] = YES;
  428.         for (j=0 ; j< i ; j++)
  429.         {
  430.             if ( f->plane.normal[0] == faces[j].plane.normal[0]
  431.             && f->plane.normal[1] == faces[j].plane.normal[1]
  432.             && f->plane.normal[2] == faces[j].plane.normal[2]
  433.             && f->plane.dist == faces[j].plane.dist )
  434.             {
  435.                 useplane[i] = NO;
  436.                 break;
  437.             }
  438.         }
  439.     
  440.     }
  441.     
  442.     for (i=0 ; i<numfaces ; i++)
  443.     {
  444.         if (!useplane[i])
  445.             continue;            // duplicate plane
  446.             
  447.         f = &faces[i];
  448.  
  449.         w = BasePolyForPlane (f);
  450.         for (j=0 ; j<numfaces && w ; j++)
  451.         {
  452.             if (j == i)
  453.                 continue;
  454.  
  455.         // flip the plane, because we want to keep the back side
  456.             VectorSubtract (vec3_origin, faces[j].plane.normal, plane.normal);
  457.             plane.dist = -faces[j].plane.dist;
  458.             
  459.             w = ClipWinding (w, &plane);
  460.         }
  461.         f->w = w;
  462.         if (w)
  463.         {
  464.             CheckFace (f);
  465.             for (j=0 ; j<w->numpoints ; j++)
  466.             {
  467.                 for (k=0 ; k<3 ; k++)
  468.                 {
  469.                     v = w->points[j][k];
  470.                     if (fabs(v - rint(v)) < FP_EPSILON)
  471.                         v = w->points[j][k] = rint(v);
  472.                     if (v < bmins[k])
  473.                         bmins[k] = v;
  474.                     if (v > bmaxs[k])
  475.                         bmaxs[k] = v;
  476.                 }
  477.             }
  478.         }
  479.     }    
  480.  
  481.     if (bmins[0] == 99999)
  482.     {
  483.         invalid = YES;
  484.         VectorCopy (vec3_origin, bmins);
  485.         VectorCopy (vec3_origin, bmaxs);
  486.         return nil;
  487.     }
  488.     
  489.     return self;
  490. }
  491.  
  492. //============================================================================
  493.  
  494. /*
  495. ===========
  496. initOwner:::
  497. ===========
  498. */
  499. - initOwner: own mins:(float *)mins maxs:(float *)maxs texture:(texturedef_t *)tex
  500. {
  501.     [super    init];
  502.  
  503.     parent = own;
  504.     
  505.     [self setTexturedef: tex];
  506.     [self setMins: mins maxs: maxs];
  507.     return self;
  508. }
  509.  
  510. - setMins:(float *)mins maxs:(float *)maxs
  511. {
  512.     int        i, j;
  513.     vec3_t    pts[4][2];
  514.     
  515.     for (i=0 ; i<3 ; i++)
  516.     {
  517.         if (maxs[i] - mins[i] <= 0)
  518.         {
  519.             VectorCopy (mins, bmins);
  520.             VectorCopy (maxs, bmaxs);
  521.             invalid = YES;
  522.             numfaces = 0;
  523.             return self;
  524.         } 
  525.     }
  526.     
  527.     pts[0][0][0] = mins[0];
  528.     pts[0][0][1] = mins[1];
  529.     
  530.     pts[1][0][0] = mins[0];
  531.     pts[1][0][1] = maxs[1];
  532.     
  533.     pts[2][0][0] = maxs[0];
  534.     pts[2][0][1] = maxs[1];
  535.     
  536.     pts[3][0][0] = maxs[0];
  537.     pts[3][0][1] = mins[1];
  538.     
  539.     for (i=0 ; i<4 ; i++)
  540.     {
  541.         pts[i][0][2] = mins[2];
  542.         pts[i][1][0] = pts[i][0][0];
  543.         pts[i][1][1] = pts[i][0][1];
  544.         pts[i][1][2] = maxs[2];
  545.     }
  546.     
  547.     numfaces = 6;
  548.     for (i=0 ; i<4 ; i++)
  549.     {
  550.         j = (i+1)%4;
  551.         faces[i].planepts[0][0] = pts[j][1][0];
  552.         faces[i].planepts[0][1] = pts[j][1][1];
  553.         faces[i].planepts[0][2] = pts[j][1][2];
  554.         
  555.         faces[i].planepts[1][0] = pts[i][1][0];
  556.         faces[i].planepts[1][1] = pts[i][1][1];
  557.         faces[i].planepts[1][2] = pts[i][1][2];
  558.         
  559.         faces[i].planepts[2][0] = pts[i][0][0];
  560.         faces[i].planepts[2][1] = pts[i][0][1];
  561.         faces[i].planepts[2][2] = pts[i][0][2];
  562.     }
  563.     
  564.     faces[4].planepts[0][0] = pts[0][1][0];
  565.     faces[4].planepts[0][1] = pts[0][1][1];
  566.     faces[4].planepts[0][2] = pts[0][1][2];
  567.  
  568.     faces[4].planepts[1][0] = pts[1][1][0];
  569.     faces[4].planepts[1][1] = pts[1][1][1];
  570.     faces[4].planepts[1][2] = pts[1][1][2];
  571.  
  572.     faces[4].planepts[2][0] = pts[2][1][0];
  573.     faces[4].planepts[2][1] = pts[2][1][1];
  574.     faces[4].planepts[2][2] = pts[2][1][2];
  575.     
  576.  
  577.     faces[5].planepts[0][0] = pts[2][0][0];
  578.     faces[5].planepts[0][1] = pts[2][0][1];
  579.     faces[5].planepts[0][2] = pts[2][0][2];
  580.  
  581.     faces[5].planepts[1][0] = pts[1][0][0];
  582.     faces[5].planepts[1][1] = pts[1][0][1];
  583.     faces[5].planepts[1][2] = pts[1][0][2];
  584.  
  585.     faces[5].planepts[2][0] = pts[0][0][0];
  586.     faces[5].planepts[2][1] = pts[0][0][1];
  587.     faces[5].planepts[2][2] = pts[0][0][2];
  588.     
  589.  
  590.     [self calcWindings];
  591.     return self;
  592. }
  593.  
  594. - parent
  595. {
  596.     return parent;
  597. }
  598.  
  599. - setParent: (id)p
  600. {
  601.     parent = p;
  602.     return self;
  603. }
  604.  
  605. - setEntityColor: (vec3_t)color
  606. {
  607.     VectorCopy (color, entitycolor);
  608.     return self;
  609. }
  610.  
  611. - freeWindings
  612. {
  613.     int        i;
  614.     
  615.     for (i=0 ; i<MAX_FACES ; i++)
  616.         if (faces[i].w)
  617.         {
  618.             free (faces[i].w);
  619.             faces[i].w = NULL;
  620.         }
  621.     return self;
  622. }
  623.  
  624. - copyFromZone:(NXZone *)zone
  625. {
  626.     id    new;
  627.     
  628.     [self freeWindings];
  629.     new = [super copyFromZone: zone];
  630.     
  631.     [self calcWindings];
  632.     [new calcWindings];
  633.     
  634.     return new;
  635. }
  636.  
  637. - free
  638. {
  639.     [self freeWindings];
  640.     return [super free];
  641. }
  642.  
  643. /*
  644. ===========
  645. initOwner: fromTokens
  646. ===========
  647. */
  648. int        numsb;
  649. - initFromTokens: own
  650. {
  651.     face_t    *f;
  652.     int        i,j;
  653.  
  654.     [self init];
  655.     
  656.     parent = own;
  657.     
  658.     f = faces;
  659.     numfaces = 0;
  660.     do
  661.     {
  662.         if (!GetToken (true))
  663.             break;
  664.         if (!strcmp (token, "}") )
  665.             break;
  666.             
  667.         for (i=0 ; i<3 ; i++)
  668.         {
  669.             if (i != 0)
  670.                 GetToken (true);
  671.             if (strcmp (token, "(") )
  672.                 Error ("parsing map file");
  673.             
  674.             for (j=0 ; j<3 ; j++)
  675.             {
  676.                 GetToken (false);
  677.                 f->planepts[i][j] = atoi(token);
  678.             }
  679.             
  680.             GetToken (false);
  681.             if (strcmp (token, ")") )
  682.                 Error ("parsing map file");
  683.         }
  684.  
  685.         GetToken (false);
  686.         strcpy (f->texture.texture, token);
  687.         GetToken (false);
  688.         f->texture.shift[0] = atof(token);
  689.         GetToken (false);
  690.         f->texture.shift[1] = atof(token);
  691.         GetToken (false);
  692.         f->texture.rotate = atof(token);
  693.         GetToken (false);
  694.         f->texture.scale[0] = atof(token);
  695.         GetToken (false);
  696.         f->texture.scale[1] = atof(token);
  697.         
  698. #if 0
  699.         flags = atoi(token);
  700.         
  701.         flags &= 7;
  702.  
  703.         f->texture.rotate = 0;
  704.         f->texture.scale[0] = 1;
  705.         f->texture.scale[1] = 1;
  706.  
  707. #define    TEX_FLIPAXIS    1
  708. #define    TEX_FLIPS        2
  709. #define    TEX_FLIPT        4
  710.  
  711.         if (flags & TEX_FLIPAXIS)
  712.         {
  713.             f->texture.rotate = 90;
  714.             if ( !(flags & TEX_FLIPT) )
  715.                 f->texture.scale[0] = -1;
  716.             if (flags & TEX_FLIPS)
  717.                 f->texture.scale[1] = -1;
  718.         }
  719.         else
  720.         {
  721.             if (flags & TEX_FLIPS)
  722.                 f->texture.scale[0] = -1;
  723.             if (flags & TEX_FLIPT)
  724.                 f->texture.scale[1] = -1;
  725.         }        
  726. #endif        
  727.         f++;
  728.         numfaces++;
  729.     } while (1);
  730.     
  731.     numsb++;
  732.  
  733.     [self calcWindings];
  734.  
  735.     return self;
  736. }
  737.  
  738. /*
  739. ===========
  740. writeToFILE
  741. ===========
  742. */
  743. - writeToFILE: (FILE *)f region: (BOOL)reg
  744. {
  745.     int        i,j;
  746.     face_t    *fa;
  747.     texturedef_t    *td;
  748.     
  749.  
  750.     if (reg && regioned)
  751.         return self;
  752.  
  753.     fprintf (f, "{\n");
  754.     for (i=0 ; i<numfaces ; i++)
  755.     {
  756.         fa = &faces[i];
  757.         for (j=0 ; j<3 ; j++)
  758.             fprintf (f,"( %d %d %d ) ", (int)fa->planepts[j][0], (int)fa->planepts[j][1], (int)fa->planepts[j][2]);
  759.         td = &fa->texture;
  760.         fprintf (f,"%s %d %d %d %f %f\n", td->texture, (int)td->shift[0], (int)td->shift[1], (int)td->rotate, td->scale[0], td->scale[1]);
  761.     }
  762.     fprintf (f, "}\n");
  763.     
  764.     return self;
  765. }
  766.  
  767.  
  768.  
  769. /*
  770. ==============================================================================
  771.  
  772. INTERACTION
  773.  
  774. ==============================================================================
  775. */
  776.  
  777. - getMins: (vec3_t)mins maxs: (vec3_t)maxs
  778. {
  779.     VectorCopy (bmins, mins);
  780.     VectorCopy (bmaxs, maxs);
  781.     return self;
  782. }
  783.  
  784.  
  785. - (BOOL)selected
  786. {
  787.     return selected;
  788. }
  789.  
  790. - setSelected: (BOOL)s
  791. {
  792.     selected = s;
  793.     return self;
  794. }
  795.  
  796. - (BOOL)regioned
  797. {
  798.     return regioned;
  799. }
  800.  
  801. - setRegioned: (BOOL)s
  802. {
  803.     regioned = s;
  804.     return self;
  805. }
  806.  
  807.  
  808. /*
  809. ===========
  810. setTexturedef
  811. ===========
  812. */
  813. - setTexturedef: (texturedef_t *)tex
  814. {
  815.     int        i;
  816.     
  817.     for (i=0 ; i<MAX_FACES ; i++)
  818.     {
  819.         faces[i].texture = *tex;
  820.         faces[i].qtexture = NULL;    // recache next render
  821.     }
  822.     
  823.     [self calcWindings];    // in case texture coords changed
  824.     return self;
  825. }
  826.  
  827. - setTexturedef: (texturedef_t *)tex forFace:(int)f
  828. {
  829.     if ( (unsigned)f > numfaces)
  830.         Error ("setTexturedef:forFace: bad face number %i",f);
  831.         
  832.     faces[f].texture = *tex;
  833.     faces[f].qtexture = NULL;    // recache next render
  834.  
  835.     [self calcWindings];    // in case texture coords changed
  836.     return self;
  837. }
  838.  
  839. /*
  840. ===========
  841. texturedef
  842. ===========
  843. */
  844. - (texturedef_t *)texturedef
  845. {
  846.     return &faces[0].texture;
  847. }
  848.  
  849. - (texturedef_t *)texturedefForFace: (int)f
  850. {
  851.     return &faces[f].texture;
  852. }
  853.  
  854.  
  855. /*
  856. ===========
  857. removeIfInvalid
  858.  
  859. So created veneers don't stay around
  860. ===========
  861. */
  862. - removeIfInvalid
  863. {
  864.     int        i, j;
  865.     
  866.     for (i=0 ; i<numfaces ; i++)
  867.     {
  868.         if (faces[i].w)
  869.             continue;
  870.         for (j=i+1 ; j<numfaces ; j++)
  871.             faces[j-1] = faces[j];
  872.         i--;
  873.         numfaces--;
  874.     }
  875.     for ( ; i<MAX_FACES ; i++)
  876.         faces[i].w = NULL;
  877.             
  878.     if (numfaces<4)
  879.     {
  880.         invalid = YES;
  881.         [self remove];
  882.         return nil;
  883.     }
  884.     return self;
  885. }
  886.  
  887. /*
  888. ===========
  889. containsPoint
  890.  
  891. ===========
  892. */
  893. - (BOOL)containsPoint: (vec3_t)pt
  894. {
  895.     int        i;
  896.     
  897.     for (i=0 ; i<numfaces ; i++)
  898.         if (DotProduct (faces[i].plane.normal, pt) >= faces[i].plane.dist)
  899.             return NO;
  900.     return YES;            
  901. }
  902.  
  903. /*
  904. ===========
  905. clipRay
  906.  
  907. ===========
  908. */
  909. - clipRay: (vec3_t)p1 : (vec3_t) p2 
  910.     :(vec3_t)frontpoint : (int *)f_face
  911.     :(vec3_t)backpoint : (int *)b_face
  912. {
  913.     int        frontface, backface;
  914.     int        i, j;
  915.     face_t    *f;
  916.     float    d1, d2, m;
  917.     float    *start;
  918.     
  919.     start = p1;
  920.  
  921.     frontface = -2;
  922.     backface = -2;
  923.     
  924.     f = faces;
  925.     for (i=0 ; i<numfaces ; i++, f++)
  926.     {
  927.         if (!f->w)
  928.             continue;    // clipped off plane
  929.         d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
  930.         d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
  931.         if (d1 >= 0 && d2 >= 0)
  932.         {    // the entire ray is in front of the polytope
  933.             *f_face = -1;
  934.             *b_face = -1;
  935.             return self;
  936.         }
  937.         if (d1 > 0 && d2 < 0)
  938.         {    // new front plane
  939.             frontface = i;
  940.             m = d1 / (d1-d2);
  941.             for (j=0 ; j<3 ; j++)
  942.                 frontpoint[j] = p1[j] + m*(p2[j]-p1[j]);
  943.             p1 = frontpoint;
  944.         }
  945.         if (d1 < 0 && d2 > 0)
  946.         {    // new back plane
  947.             backface = i;
  948.             m = d1 / (d1-d2);
  949.             for (j=0 ; j<3 ; j++)
  950.                 backpoint[j] = p1[j] + m*(p2[j]-p1[j]);
  951.             p2 = backpoint;
  952.         }
  953.     }
  954.     
  955.     *f_face = frontface;
  956.     *b_face = backface;
  957.         
  958.     return self;
  959. }
  960.  
  961.  
  962. /*
  963. ===========
  964. hitByRay
  965.  
  966. ===========
  967. */
  968. - hitByRay: (vec3_t)p1 : (vec3_t) p2 : (float *)time : (int *)face
  969. {
  970.     vec3_t    frontpoint, backpoint, dir;
  971.     int        frontface, backface;
  972.     
  973.     if (regioned)
  974.     {
  975.         *time = -1;
  976.         *face = -1;
  977.         return self;
  978.     }
  979.     
  980.     [self clipRay: p1 : p2 : frontpoint: &frontface : backpoint : &backface];
  981.     
  982.     if (frontface == -2 && backface == -2)
  983.     {    // entire ray is inside the brush, select first face
  984.         *time = 0;
  985.         *face = 0;
  986.         return self;
  987.     }
  988.     
  989.     
  990.     if (frontface < 0)
  991.     {    // ray started inside the polytope, don't select it
  992.         *time = -1;
  993.         *face = -1;
  994.         return self;
  995.     }
  996.     
  997.     VectorSubtract (p2, p1, dir);
  998.     VectorNormalize (dir);
  999.     VectorSubtract (frontpoint, p1, frontpoint);
  1000.     *time = DotProduct (frontpoint, dir);
  1001.  
  1002.     if (*time < 0)
  1003.         Error ("hitByRay: negative t");
  1004.  
  1005.     *face = frontface;
  1006.         
  1007.     return self;
  1008. }
  1009.  
  1010.  
  1011. /*
  1012. ==============================================================================
  1013.  
  1014. DRAWING ROUTINES
  1015.  
  1016. ==============================================================================
  1017. */
  1018.  
  1019. BOOL    fakebrush;
  1020.  
  1021. - drawConnections
  1022. {
  1023.     id    obj;
  1024.     int    c, i;
  1025.     vec3_t    dest, origin;
  1026.     vec3_t    mid;
  1027.     vec3_t    forward, right;
  1028.     char    *targname;    
  1029.     vec3_t    min, max, temp;
  1030.     char    targ[64];
  1031.     
  1032.     strcpy (targ, [parent valueForQKey: "target"]);
  1033.  
  1034.     if (!targ || !targ[0])
  1035.         return self;
  1036.     
  1037.     origin[0] = (bmins[0] + bmaxs[0]) /2;
  1038.     origin[1] = (bmins[1] + bmaxs[1]) /2;
  1039.     
  1040.     c = [map_i count];
  1041.     for (i=0 ; i<c ; i++)
  1042.     {
  1043.         obj = [map_i objectAt: i];
  1044.         targname = [obj valueForQKey: "targetname"];
  1045.         if (strcmp (targ, targname))
  1046.             continue;
  1047.             
  1048.         [[obj objectAt:0] getMins: min  maxs: max];
  1049.         dest[0] = (min[0] + max[0]) /2;
  1050.         dest[1] = (min[1] + max[1]) /2;
  1051.         
  1052.         XYmoveto (origin);
  1053.         XYlineto (dest);
  1054.         
  1055.         forward[0] = dest[0] - origin[0];
  1056.         forward[1] = dest[1] - origin[1];
  1057.         forward[2] = 0;
  1058.         
  1059.         if (!forward[0] && !forward[1])
  1060.             continue;
  1061.                 
  1062.         VectorNormalize (forward);
  1063.         forward[0] = 8*forward[0];
  1064.         forward[1] = 8*forward[1];
  1065.         right[0] = forward[1];
  1066.         right[1] = -forward[0];
  1067.  
  1068.         mid[0] = (dest[0] + origin[0])/2;
  1069.         mid[1] = (dest[1] + origin[1])/2;
  1070.         
  1071.         temp[0] = mid[0] + right[0] - forward[0];
  1072.         temp[1] = mid[1] + right[1] - forward[1];
  1073.         XYmoveto (temp);
  1074.         XYlineto (mid);
  1075.         temp[0] = mid[0] - right[0] - forward[0];
  1076.         temp[1] = mid[1] - right[1] - forward[1];
  1077.         XYlineto (temp);
  1078.         
  1079.     }
  1080.     
  1081.     return self;
  1082. }
  1083.  
  1084. - (BOOL)fakeBrush: (SEL)call
  1085. {
  1086.     id        copy;
  1087.     face_t    face;
  1088.  
  1089.     if (!selected || fakebrush)
  1090.         return NO;
  1091.         
  1092.     if (![clipper_i getFace: &face])
  1093.         return NO;
  1094.         
  1095.     fakebrush = YES;
  1096.     copy = [self copy];
  1097.     copy = [copy addFace: &face];
  1098.     if (copy)
  1099.     {
  1100.         [copy perform:call];
  1101.         [copy free];
  1102.     }
  1103.     fakebrush = NO;
  1104.     return YES;
  1105. }
  1106.  
  1107. /*
  1108. ===========
  1109. XYDrawSelf
  1110. ===========
  1111. */
  1112. - XYDrawSelf
  1113. {
  1114.     int        i, j;
  1115.     winding_t    *w;
  1116.     vec3_t    mid, end, s1, s2;
  1117.     char    *val;
  1118.     float    ang;
  1119.     id        worldent, currentent;
  1120.     BOOL    keybrush;
  1121.  
  1122.     if ([self fakeBrush: @selector(XYDrawSelf)])
  1123.         return self;
  1124.     
  1125.     [xyview_i addToScrollRange: bmins[0] : bmins[1]];
  1126.     [xyview_i addToScrollRange: bmaxs[0] : bmaxs[1]];
  1127.  
  1128.     worldent = [map_i objectAt: 0];
  1129.     currentent = [map_i currentEntity];
  1130.     
  1131.     if (parent != worldent && self == [parent objectAt: 0])
  1132.         keybrush = YES;
  1133.     else
  1134.         keybrush = NO;
  1135.  
  1136.     if (parent != worldent && worldent == currentent)
  1137.         linecolor (entitycolor[0], entitycolor[1], entitycolor[2]);
  1138.     else if (selected)
  1139.         linecolor (1,0,0);            // selected
  1140.     else if (parent == currentent)
  1141.         linecolor (0,0,0);            // unselected, but in same entity
  1142.     else
  1143.         linecolor (0,0.5,0);        // other entity green
  1144.  
  1145.     if (keybrush)
  1146.         [self drawConnections];    // target line
  1147.  
  1148.     if (!selected &&
  1149.     ( bmaxs[0] < xy_draw_rect.origin.x
  1150.     || bmaxs[1] < xy_draw_rect.origin.y
  1151.     || bmins[0] > xy_draw_rect.origin.x + xy_draw_rect.size.width
  1152.     || bmins[1] > xy_draw_rect.origin.y + xy_draw_rect.size.height) )
  1153.         return self;    // off view, don't bother
  1154.  
  1155.     for (i=0 ; i<numfaces ; i++)
  1156.     {
  1157.         w = faces[i].w;
  1158.         if (!w)
  1159.             continue;
  1160.         if (DotProduct (faces[i].plane.normal,xy_viewnormal) > -VECTOR_EPSILON)
  1161.             continue;
  1162.         
  1163.         XYmoveto (w->points[w->numpoints-1]);
  1164.         for (j=0 ; j<w->numpoints ; j++)
  1165.             XYlineto (w->points[j]);
  1166.     }
  1167.     
  1168.     if (keybrush)
  1169.     {
  1170. // angle arrow
  1171.         val = [parent valueForQKey: "angle"];
  1172.         if (val && val[0])
  1173.         {
  1174.             ang = atof(val) * M_PI / 180;
  1175.             if (ang > 0)    // negative values are up/down flags
  1176.             {
  1177.                 mid[0] = (bmins[0]+bmaxs[0])/2;
  1178.                 mid[1] = (bmins[1]+bmaxs[1])/2;
  1179.     
  1180.                 end[0] = mid[0] + 16*cos(ang);
  1181.                 end[1] = mid[1] + 16*sin(ang);
  1182.                 
  1183.                 s1[0] = mid[0] + 12*cos(ang+0.4);
  1184.                 s1[1] = mid[1] + 12*sin(ang+0.4);
  1185.                 
  1186.                 s2[0] = mid[0] + 12*cos(ang-0.4);
  1187.                 s2[1] = mid[1] + 12*sin(ang-0.4);
  1188.                 
  1189.                 XYmoveto ( mid);
  1190.                 XYlineto ( end );
  1191.                 XYmoveto ( s1);
  1192.                 XYlineto ( end );
  1193.                 XYlineto ( s2 );
  1194.             }
  1195.         }
  1196.     }
  1197.     
  1198.     return self;
  1199. }
  1200.  
  1201. /*
  1202. ===========
  1203. ZDrawSelf
  1204. ===========
  1205. */
  1206. - ZDrawSelf
  1207. {
  1208.     int            i;
  1209.     vec3_t        p1, p2;
  1210.     vec3_t        frontpoint, backpoint;
  1211.     int            frontface, backface;
  1212.     qtexture_t    *q;
  1213.     
  1214.     if ([self fakeBrush: @selector(ZDrawSelf)])
  1215.         return self;
  1216.  
  1217.     [zview_i addToHeightRange: bmins[2]];
  1218.     [zview_i addToHeightRange: bmaxs[2]];
  1219.     
  1220.     if (selected)
  1221.     {        
  1222.         PSmoveto (1, bmaxs[2]);
  1223.         PSlineto (23, bmaxs[2]);
  1224.         PSlineto (23, bmins[2]);
  1225.         PSlineto (1, bmins[2]);
  1226.         PSlineto (1, bmaxs[2]);
  1227.         PSsetrgbcolor (1,0,0);
  1228.         PSstroke ();
  1229.     }
  1230.  
  1231.     [zview_i getPoint: (NXPoint *)p1];
  1232.     
  1233.     for (i=0 ; i<2 ; i++)
  1234.         if (bmins[i] >= p1[i] || bmaxs[i] <= p1[i])
  1235.             return self;
  1236.     
  1237.     p1[2] = 4096;
  1238.     p2[0] = p1[0];
  1239.     p2[1] = p1[1];
  1240.     p2[2] = -4096;
  1241.  
  1242.     [self clipRay: p1 : p2 : frontpoint: &frontface : backpoint : &backface];
  1243.  
  1244.     if (frontface == -1 || backface == -1)
  1245.         return self;
  1246.         
  1247.     q = TEX_ForName (faces[frontface].texture.texture);
  1248.     
  1249.     PSmoveto (-8, frontpoint[2]);
  1250.     PSlineto (8, frontpoint[2]);
  1251.     PSlineto (8, backpoint[2]);
  1252.     PSlineto (-8, backpoint[2]);
  1253.     PSlineto (-8, frontpoint[2]);
  1254.     
  1255.     PSsetrgbcolor (q->flatcolor.chan[0]/255.0
  1256.             , q->flatcolor.chan[1]/255.0
  1257.             , q->flatcolor.chan[2]/255.0);
  1258.     PSfill ();
  1259.  
  1260.     PSmoveto (-12, frontpoint[2]);
  1261.     PSlineto (12, frontpoint[2]);
  1262.     PSlineto (12, backpoint[2]);
  1263.     PSlineto (-12, backpoint[2]);
  1264.     PSlineto (-12, frontpoint[2]);
  1265.     
  1266.     PSsetrgbcolor (0,0,0);
  1267.     PSstroke ();
  1268.             
  1269.     return self;
  1270. }
  1271.  
  1272. /*
  1273. ===========
  1274. CameraDrawSelf
  1275. ===========
  1276. */
  1277. - CameraDrawSelf
  1278. {
  1279.     int        i, j;
  1280.     winding_t    *w;
  1281.     id        worldent, currentent;
  1282.     
  1283.     if ([self fakeBrush: @selector(CameraDrawSelf)])
  1284.         return self;
  1285.     
  1286.     worldent = [map_i objectAt: 0];
  1287.     currentent = [map_i currentEntity];
  1288.  
  1289.     if (parent != worldent && worldent == currentent)
  1290.         linecolor (entitycolor[0], entitycolor[1], entitycolor[2]);
  1291.     else if (selected)
  1292.         linecolor (1,0,0);
  1293.     else if (parent == [map_i currentEntity])
  1294.         linecolor (0,0,0);
  1295.     else
  1296.         linecolor (0,0.5,0);
  1297.  
  1298.     for (i=0 ; i<numfaces ; i++)
  1299.     {
  1300.         w = faces[i].w;
  1301.         if (!w)
  1302.             continue;
  1303.         CameraMoveto (w->points[w->numpoints-1]);
  1304.         for (j=0 ; j<w->numpoints ; j++)
  1305.             CameraLineto (w->points[j]);
  1306.     }
  1307.     return self;
  1308. }
  1309.  
  1310.  
  1311. /*
  1312. ===========
  1313. XYRenderSelf
  1314. ===========
  1315. */
  1316. - XYRenderSelf
  1317. {
  1318.     int        i;
  1319.     
  1320.     if ([self fakeBrush: @selector(XYRenderSelf)])
  1321.         return self;
  1322.     
  1323.     for (i=0 ; i<numfaces ; i++)
  1324.         REN_DrawXYFace (&faces[i]);
  1325.         
  1326.     return self;
  1327. }
  1328.  
  1329. /*
  1330. ===========
  1331. CameraRenderSelf
  1332. ===========
  1333. */
  1334. - CameraRenderSelf
  1335. {
  1336.     int        i;
  1337.     BOOL    olddraw;
  1338.     extern qtexture_t badtex;
  1339.     pixel32_t    p;
  1340.  
  1341.     if ([self fakeBrush: @selector(CameraRenderSelf)])
  1342.         return self;
  1343. // hack to draw entity boxes as single flat color
  1344.     if ( ![parent modifiable] )
  1345.     {
  1346.         olddraw = r_drawflat;
  1347.         r_drawflat = YES;
  1348.  
  1349.         p = badtex.flatcolor;
  1350.  
  1351.         badtex.flatcolor.chan[0] = entitycolor[0]*255;
  1352.         badtex.flatcolor.chan[1] = entitycolor[1]*255;
  1353.         badtex.flatcolor.chan[2] = entitycolor[2]*255;
  1354.  
  1355.         for (i=0 ; i<numfaces ; i++)
  1356.             REN_DrawCameraFace (&faces[i]);
  1357.  
  1358.         badtex.flatcolor = p;
  1359.         r_drawflat = olddraw;
  1360.     }
  1361.     else
  1362.     {
  1363.         for (i=0 ; i<numfaces ; i++)
  1364.             REN_DrawCameraFace (&faces[i]);
  1365.     }
  1366.             
  1367.     return self;
  1368. }
  1369.  
  1370. /*
  1371. ==============================================================================
  1372.  
  1373. SINGLE BRUSH ACTIONS
  1374.  
  1375. ==============================================================================
  1376. */
  1377.  
  1378. face_t    *dragface, *dragface2;
  1379.  
  1380. int        numcontrolpoints;
  1381. float    *controlpoints[MAX_FACES*3];
  1382.  
  1383. - (BOOL)checkModifiable
  1384. {
  1385. //    int        i;
  1386.  
  1387.     if ( [parent modifiable] )
  1388.         return YES;
  1389.         
  1390. // don't stretch spawned entities, move all points
  1391. #if 0
  1392.     numcontrolpoints = numfaces*3;
  1393.     
  1394.     for (i=0 ; i<numcontrolpoints ; i++)
  1395.         controlpoints[i] = faces[i/3].planepts[i%3];
  1396. #endif    
  1397.     return NO;
  1398. }
  1399.  
  1400. - getZdragface: (vec3_t)dragpoint
  1401. {
  1402.     int        i, j;
  1403.     float    d;
  1404.     
  1405.  
  1406.     if (![self checkModifiable])
  1407.         return self;
  1408.  
  1409.     numcontrolpoints = 0;    
  1410.  
  1411.     for (i=0 ; i<numfaces ; i++)
  1412.     {
  1413.         if (!faces[i].w)
  1414.             continue;
  1415.         if (faces[i].plane.normal[2] == 1)
  1416.             d = dragpoint[2] - faces[i].plane.dist;
  1417.         else if (faces[i].plane.normal[2] == -1)
  1418.             d = -faces[i].plane.dist - dragpoint[2];
  1419.         else
  1420.             continue;
  1421.                     
  1422.         if (d <= 0)
  1423.             continue;
  1424.         
  1425.         for (j=0 ; j<3 ; j++)
  1426.         {
  1427.             controlpoints[numcontrolpoints] = faces[i].planepts[j];
  1428.             numcontrolpoints++;
  1429.         }
  1430.     }
  1431.     
  1432.     return self;
  1433. }
  1434.  
  1435. - getXYdragface: (vec3_t)dragpoint
  1436. {
  1437.     int        i,j;
  1438.     float    d;
  1439.  
  1440.     numcontrolpoints = 0;    
  1441.  
  1442.     if (![self checkModifiable])
  1443.         return self;
  1444.         
  1445.     for (i=0 ; i<numfaces ; i++)
  1446.     {
  1447.         if (!faces[i].w)
  1448.             continue;
  1449.         if (faces[i].plane.normal[2])
  1450.             continue;
  1451.  
  1452.         d = DotProduct(faces[i].plane.normal, dragpoint) - faces[i].plane.dist;
  1453.         if (d <= 0)
  1454.             continue;
  1455.  
  1456.         for (j=0 ; j<3 ; j++)
  1457.         {
  1458.             controlpoints[numcontrolpoints] = faces[i].planepts[j];
  1459.             numcontrolpoints++;
  1460.         }
  1461.     }
  1462.     
  1463.     return self;
  1464. }
  1465.  
  1466. - getXYShearPoints: (vec3_t)dragpoint
  1467. {
  1468.     int        i,j, k;
  1469.     int        facectl;
  1470.     float    d;
  1471.     int        numdragplanes;
  1472.     BOOL    dragplane[MAX_FACES];
  1473.     winding_t    *w;
  1474.     face_t        *f;
  1475.     BOOL    onplane[MAX_POINTS_ON_WINDING];
  1476.     
  1477.  
  1478.     if (![self checkModifiable])
  1479.         return self;
  1480.  
  1481.     numcontrolpoints = 0;
  1482.     numdragplanes = 0;
  1483.     for (i=0 ; i<numfaces ; i++)
  1484.     {
  1485.         dragplane[i] = NO;
  1486.         if (!faces[i].w)
  1487.             continue;
  1488. //        if (faces[i].plane.normal[2])
  1489. //            continue;
  1490.  
  1491.         d = DotProduct(faces[i].plane.normal, dragpoint) - faces[i].plane.dist;
  1492.         if (d <= -ON_EPSILON)
  1493.             continue;
  1494.  
  1495.         dragplane[i] = YES;
  1496.         numdragplanes++;
  1497.     }
  1498.     
  1499. // find faces that just share an edge with a drag plane
  1500.     for (i=0 ; i<numfaces ; i++)
  1501.     {
  1502.         f = &faces[i];
  1503.         w = f->w;
  1504.         if (!w)
  1505.             continue;
  1506.         if (dragplane[i] && numdragplanes == 1)
  1507.         {
  1508.             for (j=0 ; j<3 ; j++)
  1509.             {
  1510.                 controlpoints[numcontrolpoints] = faces[i].planepts[j];
  1511.                 numcontrolpoints++;
  1512.             }
  1513.             continue;
  1514.         }
  1515.         if (!dragplane[i] && numdragplanes > 1)
  1516.             continue;
  1517.             
  1518.         facectl = 0;
  1519.         for (j=0 ; j<w->numpoints ; j++)
  1520.         {
  1521.             onplane[j] = NO;
  1522.             for (k=0 ; k<numfaces ; k++)
  1523.             {
  1524.                 if (!dragplane[k])
  1525.                     continue;
  1526.                 if (k == i)
  1527.                     continue;
  1528.                 d = DotProduct (w->points[j], faces[k].plane.normal)
  1529.                     - faces[k].plane.dist;
  1530.                 if (fabs(d) > ON_EPSILON)
  1531.                     continue;
  1532.                 onplane[j] = YES;
  1533.                 facectl++;
  1534.                 break;        
  1535.             }
  1536.         }
  1537.         if (facectl == 0)
  1538.             continue;
  1539.             
  1540.     // find one or two static points to go with the controlpoints
  1541.     // and change the plane points
  1542.         k = 0;
  1543.         for (j=0 ; j<w->numpoints ; j++)
  1544.         {
  1545.             if (!onplane[j])
  1546.                 continue;
  1547.             if (facectl >= 2 && !onplane[(j+1)%w->numpoints])
  1548.                 continue;
  1549.             if (facectl == 3 && !onplane[(j+2)%w->numpoints])
  1550.                 continue;
  1551.  
  1552.             VectorCopy (w->points[j], f->planepts[k]);
  1553.             controlpoints[numcontrolpoints] = f->planepts[k];
  1554.             numcontrolpoints++;
  1555.             k++;
  1556.  
  1557.             if (facectl >= 2)
  1558.             {
  1559.                 VectorCopy (w->points[(j+1)%w->numpoints], f->planepts[k]);
  1560.                 controlpoints[numcontrolpoints] = f->planepts[k];
  1561.                 numcontrolpoints++;
  1562.                 k++;
  1563.             }
  1564.             if (facectl == 3)
  1565.             {
  1566.                 VectorCopy (w->points[(j+2)%w->numpoints], f->planepts[k]);
  1567.                 controlpoints[numcontrolpoints] = f->planepts[k];
  1568.                 numcontrolpoints++;
  1569.                 k++;
  1570.             }
  1571.             break;
  1572.         }
  1573.     
  1574.         for ( ; j<w->numpoints && k != 3 ; j++)
  1575.             if (!onplane[j])
  1576.             {
  1577.                 VectorCopy (w->points[j], f->planepts[k]);
  1578.                 k++;
  1579.             }
  1580.             
  1581.         for (j=0 ; j<w->numpoints && k != 3 ; j++)
  1582.             if (!onplane[j])
  1583.             {
  1584.                 VectorCopy (w->points[j], f->planepts[k]);
  1585.                 k++;
  1586.             }
  1587.             
  1588.         if (k != 3)
  1589.         {
  1590. //            Error ("getXYShearPoints: didn't get three points on plane");
  1591.             numcontrolpoints = 0;
  1592.             return self;
  1593.         }
  1594.             
  1595.         for (j=0 ; j<3 ; j++)
  1596.             for (k=0 ; k<3 ; k++)
  1597.                 f->planepts[j][k] = rint(f->planepts[j][k]);
  1598.     }
  1599.         
  1600.     return self;
  1601. }
  1602.  
  1603. /*
  1604. ==============================================================================
  1605.  
  1606. MULTIPLE BRUSH ACTIONS
  1607.  
  1608. ==============================================================================
  1609. */
  1610.  
  1611. vec3_t    region_min, region_max;
  1612.  
  1613. /*
  1614. ===========
  1615. newRegion
  1616.  
  1617. Set the regioned flag based on if the object is containted in region_min/max
  1618. ===========
  1619. */
  1620. - newRegion
  1621. {
  1622.     int        i;
  1623.     char    *name;
  1624.     
  1625. // filter away entities
  1626.     if (parent != [map_i objectAt: 0])
  1627.     {
  1628.         if (filter_entities)
  1629.         {
  1630.             regioned = YES;
  1631.             return self;
  1632.         }
  1633.     
  1634.         name = [parent valueForQKey: "classname"];
  1635.             
  1636.         if ( (filter_light && !strncmp(name,"light",5) )
  1637.         || (filter_path && !strncmp(name,"path",4) ) )
  1638.         {
  1639.             regioned = YES;
  1640.             return self;
  1641.         }
  1642.     }
  1643.     else if (filter_world)
  1644.     {
  1645.         regioned = YES;
  1646.         return self;
  1647.     }
  1648.     
  1649.     if (filter_clip_brushes && !strcasecmp(faces[0].texture.texture, "clip"))
  1650.     {
  1651.         regioned = YES;
  1652.         return self;
  1653.     }
  1654.         
  1655.     if (filter_water_brushes && faces[0].texture.texture[0] == '*')
  1656.     {
  1657.         regioned = YES;
  1658.         return self;
  1659.     }
  1660.         
  1661.     for (i=0 ; i<3 ; i++)
  1662.     {
  1663.         if (region_min[i] >= bmaxs[i] || region_max[i] <= bmins[i])
  1664.         {
  1665.             if (selected)
  1666.                 [self deselect];
  1667.             regioned = YES;
  1668.             return self;
  1669.         }
  1670.     }
  1671.     
  1672.     regioned = NO;
  1673.     return self;
  1674. }
  1675.  
  1676. vec3_t    select_min, select_max;
  1677. - selectPartial
  1678. {
  1679.     int        i;
  1680.     for (i=0 ; i<3 ; i++)
  1681.         if (select_min[i] >= bmaxs[i] || select_max[i] <= bmins[i])
  1682.             return self;
  1683.     selected = YES;
  1684.     return self;
  1685. }
  1686.  
  1687. - selectComplete
  1688. {
  1689.     int        i;
  1690.     for (i=0 ; i<3 ; i++)
  1691.         if (select_min[i] > bmins[i] || select_max[i] < bmaxs[i])
  1692.             return self;
  1693.     selected = YES;
  1694.     return self;
  1695. }
  1696.  
  1697.  
  1698. - regionPartial
  1699. {
  1700.     int        i;
  1701.     for (i=0 ; i<3 ; i++)
  1702.         if (select_min[i] >= bmaxs[i] || select_max[i] <= bmins[i])
  1703.             return self;
  1704.     selected = YES;
  1705.     return self;
  1706. }
  1707.  
  1708. - regionComplete
  1709. {
  1710.     int        i;
  1711.     for (i=0 ; i<3 ; i++)
  1712.         if (select_min[i] > bmins[i] || select_max[i] < bmaxs[i])
  1713.             return self;
  1714.     selected = YES;
  1715.     return self;
  1716. }
  1717.  
  1718.  
  1719. id    sb_newowner;
  1720. - moveToEntity
  1721. {
  1722.     id        eclass;
  1723.     float    *c;
  1724.     
  1725.     [parent removeObject: self];
  1726.     parent = sb_newowner;
  1727.     
  1728. // hack to allow them to be copied to another map
  1729.     if ( [parent respondsTo:@selector(valueForQKey:)])
  1730.     {
  1731.         eclass = [entity_classes_i classForName: [parent valueForQKey: "classname"]];
  1732.         c = [eclass drawColor];
  1733.         [self setEntityColor: c];
  1734.     }
  1735.     
  1736.     [parent addObject: self];
  1737.     return self;
  1738. }
  1739.  
  1740. vec3_t    sb_translate;
  1741.  
  1742. - translate
  1743. {
  1744.     int        i, j;
  1745.     
  1746. // move the planes
  1747.     for (i=0; i<numfaces ; i++)
  1748.         for (j=0 ; j<3 ; j++)
  1749.         {
  1750.             VectorAdd (faces[i].planepts[j], sb_translate, faces[i].planepts[j]);
  1751.         }
  1752.  
  1753.     [self calcWindings];
  1754.     
  1755.     return self;
  1756. }
  1757.  
  1758. vec3_t    sb_mins, sb_maxs;
  1759. - addToBBox
  1760. {
  1761.     int            k;
  1762.     
  1763.     if (numfaces < 4)
  1764.         return self;
  1765.  
  1766.     for (k=0 ; k<3 ; k++)
  1767.     {
  1768.         if (bmins[k] < sb_mins[k])
  1769.             sb_mins[k] = bmins[k];
  1770.         if (bmaxs[k] > sb_maxs[k])
  1771.             sb_maxs[k] = bmaxs[k];
  1772.     }
  1773.  
  1774.     return self;
  1775. }
  1776.  
  1777. - flushTextures
  1778. {    // call when texture palette changes
  1779.     int        i;
  1780.     
  1781.     for (i=0 ; i<MAX_FACES ; i++)
  1782.         faces[i].qtexture = NULL;
  1783.     
  1784.     [self calcWindings];
  1785.  
  1786.     return self;
  1787. }
  1788.  
  1789. - select
  1790. {
  1791.     [map_i setCurrentEntity: parent];
  1792.     selected = YES;
  1793.     return self;
  1794. }
  1795.  
  1796. - deselect
  1797. {
  1798.     selected = NO;
  1799.  
  1800. // the last selected brush determines 
  1801.     if (invalid)
  1802.         printf ("WARNING: deselected invalid brush\n");
  1803.     [map_i setCurrentMinZ: bmins[2]];
  1804.     [map_i setCurrentMaxZ: bmaxs[2]];
  1805.     
  1806.     return self;
  1807. }
  1808.  
  1809. - remove
  1810. {
  1811. // the last selected brush determines 
  1812.     if (!invalid)
  1813.     {
  1814.         [map_i setCurrentMinZ: bmins[2]];
  1815.         [map_i setCurrentMaxZ: bmaxs[2]];
  1816.     }
  1817.  
  1818.     [parent removeObject: self];
  1819.     [self free];
  1820.  
  1821.     return nil;
  1822. }
  1823.  
  1824.  
  1825. vec3_t    sel_x, sel_y, sel_z;
  1826. vec3_t    sel_org;
  1827. - transform
  1828. {
  1829.     int        i,j;
  1830.     vec3_t    old;
  1831.     float    *p;
  1832.     
  1833.     for (i=0 ; i<numfaces ; i++)
  1834.         for (j=0 ; j<3 ; j++)
  1835.         {
  1836.             p = faces[i].planepts[j];
  1837.             VectorCopy (p, old);
  1838.             VectorSubtract (old, sel_org, old);
  1839.             p[0] = DotProduct (old, sel_x);
  1840.             p[1] = DotProduct (old, sel_y);
  1841.             p[2] = DotProduct (old, sel_z);
  1842.             VectorAdd (p, sel_org, p);
  1843.         }
  1844.         
  1845.     [self calcWindings];
  1846.  
  1847.     return self;
  1848. }
  1849.  
  1850. - flipNormals    // used after an inside-out transform (flip x/y/z)
  1851. {
  1852.     int        i;
  1853.     vec3_t    temp;
  1854.     
  1855.     for (i=0 ; i<numfaces ; i++)
  1856.     {
  1857.         VectorCopy (faces[i].planepts[0], temp);
  1858.         VectorCopy (faces[i].planepts[2], faces[i].planepts[0]);
  1859.         VectorCopy (temp, faces[i].planepts[2]);
  1860.     }
  1861.     [self calcWindings];
  1862.     return self;
  1863. }
  1864.  
  1865. - carveByClipper
  1866. {
  1867.     face_t face;
  1868.     
  1869.     if (![clipper_i getFace: &face])
  1870.         return self;
  1871.         
  1872.     [self addFace: &face];
  1873.     
  1874.     return self;
  1875. }
  1876.  
  1877.  
  1878. - takeCurrentTexture
  1879. {
  1880.     texturedef_t    td;
  1881.     
  1882.     [texturepalette_i getTextureDef: &td];
  1883.     [self setTexturedef: &td];
  1884.     
  1885.     return self;
  1886. }
  1887.  
  1888.  
  1889. float    sb_floor_dir, sb_floor_dist;
  1890. - feetToFloor
  1891. {
  1892.     float    oldz;
  1893.     vec3_t    p1, p2;
  1894.     int        frontface, backface;
  1895.     vec3_t    frontpoint, backpoint;
  1896.     float    dist;
  1897.     
  1898.     [cameraview_i getOrigin: p1];
  1899.     VectorCopy (p1, p2);
  1900.     oldz = p1[2] - 48;
  1901.     
  1902.     p1[2] = 4096;
  1903.     p2[2] = -4096;
  1904.  
  1905.     [self clipRay: p1 : p2 : frontpoint : &frontface : backpoint : &backface];
  1906.     if (frontface == -1)
  1907.         return self;
  1908.  
  1909.     dist = frontpoint[2] - oldz;
  1910.     
  1911.     if (sb_floor_dir == 1)
  1912.     {
  1913.         if (dist > 0 && dist < sb_floor_dist)
  1914.             sb_floor_dist = dist;    
  1915.     }
  1916.     else
  1917.     {
  1918.         if (dist < 0 && dist > sb_floor_dist)
  1919.             sb_floor_dist = dist;    
  1920.     }
  1921.     return self;
  1922. }
  1923.  
  1924.  
  1925. /*
  1926. ===============================================================================
  1927.  
  1928. BRUSH SUBTRACTION
  1929.  
  1930. ===============================================================================
  1931. */
  1932.  
  1933. vec3_t    carvemin, carvemax;
  1934. int        numcarvefaces;
  1935. face_t    *carvefaces;
  1936. id        carve_in, carve_out;
  1937.  
  1938. // returns the new brush formed after the addition of the given plane
  1939. // nil is returned if it faced all of the original setbrush
  1940. - addFace: (face_t *)f
  1941. {
  1942.     if (numfaces == MAX_FACES)
  1943.         Error ("addFace: numfaces == MAX_FACES");
  1944.         
  1945.     faces[numfaces] = *f;
  1946.     faces[numfaces].texture = faces[0].texture;
  1947.     faces[numfaces].qtexture = NULL;
  1948.     faces[numfaces].w = NULL;
  1949.     numfaces++;
  1950.     [self calcWindings];
  1951.     
  1952. // remove any degenerate faces
  1953.     return [self removeIfInvalid];
  1954. }
  1955.  
  1956. - clipByFace: (face_t *)fa front:(id *)f back:(id *)b
  1957. {
  1958.     id        front, back;
  1959.     face_t    fb;
  1960.     vec3_t    temp;
  1961.     
  1962.     fb = *fa;
  1963.     VectorCopy (fb.planepts[0], temp);
  1964.     VectorCopy (fb.planepts[2], fb.planepts[0]);
  1965.     VectorCopy (temp, fb.planepts[2]);
  1966.     
  1967.     front = [self copy];
  1968.     back = [self copy];
  1969.  
  1970.     *b = [back addFace: fa];
  1971.     *f = [front addFace: &fb];
  1972.     
  1973.     return self;
  1974. }
  1975.  
  1976. - carve
  1977. {
  1978.     int        i;
  1979.     id        front, back;
  1980.         
  1981. #if 0
  1982.     if ( (i = NXMallocCheck()) )
  1983.         Error ("MallocCheck failure");
  1984. #endif
  1985.         
  1986. // check bboxes
  1987.     for (i=0 ; i<3 ; i++)
  1988.         if (bmins[i] >= carvemax[i] || bmaxs[i] <= carvemin[i])
  1989.         {
  1990.             [carve_out addObject: self];
  1991.             return self;
  1992.         }
  1993.  
  1994. // carve by the planes
  1995.     back = self;
  1996.     for (i=0 ; i<numcarvefaces ; i++)
  1997.     {
  1998.         [back clipByFace: &carvefaces[i] front:&front back:&back];
  1999.         if (front)
  2000.             [carve_out addObject: front];
  2001.         if (!back)
  2002.             return nil;        // nothing completely inside
  2003.     }
  2004.     
  2005.     [carve_in addObject: back];
  2006.     return self;
  2007. }
  2008.  
  2009. /*
  2010. ==================
  2011. setCarveVars
  2012. ==================
  2013. */
  2014. - setCarveVars
  2015. {
  2016.     VectorCopy (bmins, carvemin);
  2017.     VectorCopy (bmaxs, carvemax);
  2018.     numcarvefaces = numfaces;
  2019.     carvefaces = faces;
  2020.     
  2021.     return self;
  2022. }
  2023.  
  2024. - (int) getNumBrushFaces
  2025. {
  2026.     return numfaces;
  2027. }
  2028.  
  2029. - (face_t *) getBrushFace: (int)which
  2030. {
  2031.     return &faces[which];
  2032. }
  2033.  
  2034. @end
  2035.