2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
5 This file is part of Quake 2 Tools source code.
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
26 #define MAX_POINTS_ON_WINDING 64
28 face_t *Face_Alloc( void );
29 void Face_Free( face_t *f );
31 winding_t *NewWinding (int points);
32 void FreeWinding (winding_t *w);
33 winding_t *Winding_Clone( winding_t *w );
34 winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon);
36 void PrintWinding (winding_t *w)
40 printf ("-------------\n");
41 for (i=0 ; i<w->numpoints ; i++)
42 printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
43 , w->points[i][1], w->points[i][2]);
46 void PrintPlane (plane_t *p)
48 printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1],
49 p->normal[2], p->dist);
52 void PrintVector (vec3_t v)
54 printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]);
58 face_t *Face_Clone (face_t *f)
63 n->texdef = f->texdef;
64 memcpy (n->planepts, f->planepts, sizeof(n->planepts));
66 // all other fields are derived, and will be set by Brush_Build
70 //============================================================================
72 #define BOGUS_RANGE 18000
80 winding_t *NewWinding (int points)
85 if (points > MAX_POINTS_ON_WINDING)
86 Error ("NewWinding: %i points", points);
88 size = (int)((winding_t *)0)->points[points];
91 w->maxpoints = points;
97 void FreeWinding (winding_t *w)
108 winding_t *Winding_Clone(winding_t *w)
113 size = (int)((winding_t *)0)->points[w->numpoints];
124 Clips the winding to the plane, returning the new winding on the positive side
125 Frees the input winding.
126 If keepon is true, an exactly on-plane winding will be saved, otherwise
127 it will be clipped away.
130 winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon)
132 vec_t dists[MAX_POINTS_ON_WINDING];
133 int sides[MAX_POINTS_ON_WINDING];
142 counts[0] = counts[1] = counts[2] = 0;
144 // determine sides for each point
145 for (i=0 ; i<in->numpoints ; i++)
147 dot = DotProduct (in->points[i], split->normal);
150 if (dot > ON_EPSILON)
151 sides[i] = SIDE_FRONT;
152 else if (dot < -ON_EPSILON)
153 sides[i] = SIDE_BACK;
163 if (keepon && !counts[0] && !counts[1])
174 maxpts = in->numpoints+4; // can't use counts[0]+2 because
175 // of fp grouping errors
176 neww = NewWinding (maxpts);
178 for (i=0 ; i<in->numpoints ; i++)
182 if (sides[i] == SIDE_ON)
184 VectorCopy (p1, neww->points[neww->numpoints]);
189 if (sides[i] == SIDE_FRONT)
191 VectorCopy (p1, neww->points[neww->numpoints]);
195 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
198 // generate a split point
199 p2 = in->points[(i+1)%in->numpoints];
201 dot = dists[i] / (dists[i]-dists[i+1]);
202 for (j=0 ; j<3 ; j++)
203 { // avoid round off error when possible
204 if (split->normal[j] == 1)
205 mid[j] = split->dist;
206 else if (split->normal[j] == -1)
207 mid[j] = -split->dist;
209 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
212 VectorCopy (mid, neww->points[neww->numpoints]);
216 if (neww->numpoints > maxpts)
217 Error ("ClipWinding: points exceeded estimate");
219 // free the original winding
228 =============================================================================
232 =============================================================================
241 vec3_t baseaxis[18] =
243 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
244 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
245 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
246 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
247 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
248 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
251 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
260 for (i=0 ; i<6 ; i++)
262 dot = DotProduct (pln->normal, baseaxis[i*3]);
270 VectorCopy (baseaxis[bestaxis*3+1], xv);
271 VectorCopy (baseaxis[bestaxis*3+2], yv);
275 float lightaxis[3] = {0.6, 0.8, 1.0};
280 Light different planes differently to
284 float SetShadeForPlane (plane_t *p)
290 for (i=0 ; i<3 ; i++)
291 if (fabs(p->normal[i]) > 0.9)
297 // between two axial planes
298 for (i=0 ; i<3 ; i++)
299 if (fabs(p->normal[i]) < 0.1)
301 f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
306 f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
318 void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q)
322 float ang, sinv, cosv;
327 // get natural texture axis
328 TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
330 // set shading for face
331 shade = SetShadeForPlane (&f->plane);
332 if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize)
336 f->d_color[2] = shade;
340 f->d_color[0] = shade*q->color[0];
341 f->d_color[1] = shade*q->color[1];
342 f->d_color[2] = shade*q->color[2];
345 if (camera.draw_mode != cd_texture)
348 if (!f->texdef.scale[0])
349 f->texdef.scale[0] = 1;
350 if (!f->texdef.scale[1])
351 f->texdef.scale[1] = 1;
355 if (f->texdef.rotate == 0)
356 { sinv = 0 ; cosv = 1; }
357 else if (f->texdef.rotate == 90)
358 { sinv = 1 ; cosv = 0; }
359 else if (f->texdef.rotate == 180)
360 { sinv = 0 ; cosv = -1; }
361 else if (f->texdef.rotate == 270)
362 { sinv = -1 ; cosv = 0; }
365 ang = f->texdef.rotate / 180 * Q_PI;
372 else if (pvecs[0][1])
379 else if (pvecs[1][1])
384 for (i=0 ; i<2 ; i++)
386 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
387 nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
392 for (i=0 ; i<2 ; i++)
393 for (j=0 ; j<3 ; j++)
394 vecs[i][j] = vecs[i][j] / f->texdef.scale[i];
398 void _EmitTextureCoordinates (vec3_t v, qtexture_t *q)
402 s = DotProduct (v, vecs[0]);
403 t = DotProduct (v, vecs[1]);
414 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
417 float ang, sinv, cosv;
421 // get natural texture axis
422 TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]);
426 ang = td->rotate / 180 * Q_PI;
435 s = DotProduct(xyzst, vecs[0]);
436 t = DotProduct(xyzst, vecs[1]);
438 ns = cosv * s - sinv * t;
439 nt = sinv * s + cosv * t;
441 s = ns/td->scale[0] + td->shift[0];
442 t = nt/td->scale[1] + td->shift[1];
444 // gl scales everything from 0 to 1
452 //==========================================================================
460 winding_t *BasePolyForPlane (plane_t *p)
464 vec3_t org, vright, vup;
467 // find the major axis
473 v = fabs(p->normal[i]);
481 Error ("BasePolyForPlane: no axis found");
483 VectorCopy (vec3_origin, vup);
496 v = DotProduct (vup, p->normal);
497 VectorMA (vup, -v, p->normal, vup);
498 VectorNormalize (vup);
500 VectorScale (p->normal, p->dist, org);
502 CrossProduct (vup, p->normal, vright);
504 VectorScale (vup, 8192, vup);
505 VectorScale (vright, 8192, vright);
507 // project a really big axis aligned box onto the plane
510 VectorSubtract (org, vright, w->points[0]);
511 VectorAdd (w->points[0], vup, w->points[0]);
513 VectorAdd (org, vright, w->points[1]);
514 VectorAdd (w->points[1], vup, w->points[1]);
516 VectorAdd (org, vright, w->points[2]);
517 VectorSubtract (w->points[2], vup, w->points[2]);
519 VectorSubtract (org, vright, w->points[3]);
520 VectorSubtract (w->points[3], vup, w->points[3]);
527 void Brush_MakeFacePlanes (brush_t *b)
533 for (f=b->brush_faces ; f ; f=f->next)
535 // convert to a vector / dist plane
536 for (j=0 ; j<3 ; j++)
538 t1[j] = f->planepts[0][j] - f->planepts[1][j];
539 t2[j] = f->planepts[2][j] - f->planepts[1][j];
540 t3[j] = f->planepts[1][j];
543 CrossProduct(t1,t2, f->plane.normal);
544 if (VectorCompare (f->plane.normal, vec3_origin))
545 printf ("WARNING: brush plane with no normal\n");
546 VectorNormalize (f->plane.normal);
547 f->plane.dist = DotProduct (t3, f->plane.normal);
551 void DrawBrushEntityName (brush_t *b)
559 return; // during contruction
561 if (b->owner == world_entity)
564 if (b != b->owner->brushes.onext)
565 return; // not key brush
567 // draw the angle pointer
568 a = FloatForKey (b->owner, "angle");
571 s = sin (a/180*Q_PI);
572 c = cos (a/180*Q_PI);
573 for (i=0 ; i<3 ; i++)
574 mid[i] = (b->mins[i] + b->maxs[i])*0.5;
576 glBegin (GL_LINE_STRIP);
599 if (!g_qeglobals.d_savedinfo.show_names)
602 name = ValueForKey (b->owner, "classname");
603 glRasterPos2f (b->mins[0]+4, b->mins[1]+4);
604 glCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
611 returns the visible polygon on a face
614 winding_t *MakeFaceWinding (brush_t *b, face_t *face)
621 // get a poly that covers an effectively infinite area
622 w = BasePolyForPlane (&face->plane);
624 // chop the poly by all of the other faces
626 for (clip = b->brush_faces ; clip && w ; clip=clip->next)
633 if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
634 && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
635 { // identical plane, use the later one
644 // flip the plane, because we want to keep the back side
645 VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
646 plane.dist = -clip->plane.dist;
648 w = ClipWinding (w, &plane, false);
653 if (w->numpoints < 3)
660 printf ("unused plane\n");
666 void Brush_SnapPlanepts (brush_t *b)
671 for (f=b->brush_faces ; f; f=f->next)
672 for (i=0 ; i<3 ; i++)
673 for (j=0 ; j<3 ; j++)
674 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
680 ** Builds a brush rendering data and also sets the min/max bounds
682 #define ZERO_EPSILON 0.001
683 void Brush_Build( brush_t *b )
692 modified = true; // mark the map as changed
693 sprintf (title, "%s *", currentmap);
695 QE_ConvertDOSToUnixName( title, title );
696 Sys_SetTitle (title);
700 ** build the windings and generate the bounding box
702 Brush_BuildWindings( b );
705 ** move the points and edges if in select mode
707 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
708 SetupVertexSelection ();
715 The brush is NOT linked to any list
718 brush_t *Brush_Parse (void)
724 g_qeglobals.d_parsed_brushes++;
725 b = qmalloc(sizeof(brush_t));
729 if (!GetToken (true))
731 if (!strcmp (token, "}") )
736 // add the brush to the end of the chain, so
737 // loading and saving a map doesn't reverse the order
748 for (scan=b->brush_faces ; scan->next ; scan=scan->next)
753 // read the three point plane definition
754 for (i=0 ; i<3 ; i++)
758 if (strcmp (token, "(") )
759 Error ("parsing brush");
761 for (j=0 ; j<3 ; j++)
764 f->planepts[i][j] = atoi(token);
768 if (strcmp (token, ")") )
769 Error ("parsing brush");
773 // read the texturedef
775 strcpy(f->texdef.name, token);
777 f->texdef.shift[0] = atoi(token);
779 f->texdef.shift[1] = atoi(token);
781 f->texdef.rotate = atoi(token);
783 f->texdef.scale[0] = atof(token);
785 f->texdef.scale[1] = atof(token);
787 // the flags and value field aren't necessarily present
788 f->d_texture = Texture_ForName( f->texdef.name );
789 f->texdef.flags = f->d_texture->flags;
790 f->texdef.value = f->d_texture->value;
791 f->texdef.contents = f->d_texture->contents;
793 if (TokenAvailable ())
796 f->texdef.contents = atoi(token);
798 f->texdef.flags = atoi(token);
800 f->texdef.value = atoi(token);
812 void Brush_Write (brush_t *b, FILE *f)
819 for (fa=b->brush_faces ; fa ; fa=fa->next)
821 for (i=0 ; i<3 ; i++)
822 fprintf (f, "( %i %i %i ) ", (int)fa->planepts[i][0]
823 , (int)fa->planepts[i][1], (int)fa->planepts[i][2]);
825 pname = fa->texdef.name;
829 fprintf (f, "%s %i %i %i ", pname,
830 (int)fa->texdef.shift[0], (int)fa->texdef.shift[1],
831 (int)fa->texdef.rotate);
833 if (fa->texdef.scale[0] == (int)fa->texdef.scale[0])
834 fprintf (f, "%i ", (int)fa->texdef.scale[0]);
836 fprintf (f, "%f ", (float)fa->texdef.scale[0]);
837 if (fa->texdef.scale[1] == (int)fa->texdef.scale[1])
838 fprintf (f, "%i", (int)fa->texdef.scale[1]);
840 fprintf (f, "%f", (float)fa->texdef.scale[1]);
842 // only output flags and value if not default
843 if (fa->texdef.value != fa->d_texture->value
844 || fa->texdef.flags != fa->d_texture->flags
845 || fa->texdef.contents != fa->d_texture->contents)
847 fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
860 Create non-textured blocks for entities
861 The brush is NOT linked to any list
864 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
871 for (i=0 ; i<3 ; i++)
872 if (maxs[i] < mins[i])
873 Error ("Brush_InitSolid: backwards");
875 b = qmalloc (sizeof(brush_t));
877 pts[0][0][0] = mins[0];
878 pts[0][0][1] = mins[1];
880 pts[1][0][0] = mins[0];
881 pts[1][0][1] = maxs[1];
883 pts[2][0][0] = maxs[0];
884 pts[2][0][1] = maxs[1];
886 pts[3][0][0] = maxs[0];
887 pts[3][0][1] = mins[1];
889 for (i=0 ; i<4 ; i++)
891 pts[i][0][2] = mins[2];
892 pts[i][1][0] = pts[i][0][0];
893 pts[i][1][1] = pts[i][0][1];
894 pts[i][1][2] = maxs[2];
897 for (i=0 ; i<4 ; i++)
901 f->next = b->brush_faces;
905 VectorCopy (pts[j][1], f->planepts[0]);
906 VectorCopy (pts[i][1], f->planepts[1]);
907 VectorCopy (pts[i][0], f->planepts[2]);
912 f->next = b->brush_faces;
915 VectorCopy (pts[0][1], f->planepts[0]);
916 VectorCopy (pts[1][1], f->planepts[1]);
917 VectorCopy (pts[2][1], f->planepts[2]);
921 f->next = b->brush_faces;
924 VectorCopy (pts[2][0], f->planepts[0]);
925 VectorCopy (pts[1][0], f->planepts[1]);
926 VectorCopy (pts[0][0], f->planepts[2]);
936 Makes the current brushhave the given number of 2d sides
939 void Brush_MakeSided (int sides)
952 Sys_Status ("Bad sides number", 0);
956 if (!QE_SingleBrush ())
958 Sys_Status ("Must have a single brush selected", 0 );
962 b = selected_brushes.next;
963 VectorCopy (b->mins, mins);
964 VectorCopy (b->maxs, maxs);
965 texdef = &g_qeglobals.d_texturewin.texdef;
969 // find center of brush
971 for (i=0 ; i<2 ; i++)
973 mid[i] = (maxs[i] + mins[i])*0.5;
974 if (maxs[i] - mins[i] > width)
975 width = maxs[i] - mins[i];
979 b = qmalloc (sizeof(brush_t));
984 f->next = b->brush_faces;
987 f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2];
988 f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2];
989 f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2];
991 // create bottom face
994 f->next = b->brush_faces;
997 f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
998 f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
999 f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
1001 for (i=0 ; i<sides ; i++)
1004 f->texdef = *texdef;
1005 f->next = b->brush_faces;
1008 sv = sin (i*3.14159265*2/sides);
1009 cv = cos (i*3.14159265*2/sides);
1011 f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
1012 f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
1013 f->planepts[0][2] = mins[2];
1015 f->planepts[1][0] = f->planepts[0][0];
1016 f->planepts[1][1] = f->planepts[0][1];
1017 f->planepts[1][2] = maxs[2];
1019 f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5);
1020 f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5);
1021 f->planepts[2][2] = maxs[2];
1025 Brush_AddToList (b, &selected_brushes);
1027 Entity_LinkBrush (world_entity, b);
1031 Sys_UpdateWindows (W_ALL);
1039 Frees the brush with all of its faces and display list.
1040 Unlinks the brush from whichever chain it is in.
1041 Decrements the owner entity's brushcount.
1042 Removes owner entity if this was the last brush
1043 unless owner is the world.
1046 void Brush_Free (brush_t *b)
1051 for (f=b->brush_faces ; f ; f=next)
1058 for ( i = 0; i < b->d_numwindings; i++ )
1060 if ( b->d_windings[i] )
1062 FreeWinding( b->d_windings[i] );
1063 b->d_windings[i] = 0;
1068 // unlink from active/selected list
1070 Brush_RemoveFromList (b);
1072 // unlink from entity list
1074 Entity_UnlinkBrush (b);
1084 void Brush_Move (brush_t *b, vec3_t move)
1089 for (f=b->brush_faces ; f ; f=f->next)
1090 for (i=0 ; i<3 ; i++)
1091 VectorAdd (f->planepts[i], move, f->planepts[i]);
1099 Does NOT add the new brush to any lists
1102 brush_t *Brush_Clone (brush_t *b)
1107 n = qmalloc(sizeof(brush_t));
1108 n->owner = b->owner;
1109 for (f=b->brush_faces ; f ; f=f->next)
1111 nf = Face_Clone( f );
1112 nf->next = n->brush_faces;
1113 n->brush_faces = nf;
1122 Itersects a ray with a brush
1123 Returns the face hit and the distance along the ray the intersection occured at
1124 Returns NULL and 0 if not hit at all
1127 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist)
1129 face_t *f, *firstface;
1134 VectorCopy (origin, p1);
1135 for (i=0 ; i<3 ; i++)
1136 p2[i] = p1[i] + dir[i]*16384;
1138 for (f=b->brush_faces ; f ; f=f->next)
1140 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
1141 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
1142 if (d1 >= 0 && d2 >= 0)
1145 return NULL; // ray is on front side of face
1147 if (d1 <=0 && d2 <= 0)
1149 // clip the ray to the plane
1150 frac = d1 / (d1 - d2);
1154 for (i=0 ; i<3 ; i++)
1155 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
1159 for (i=0 ; i<3 ; i++)
1160 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
1164 // find distance p1 is along dir
1165 VectorSubtract (p1, origin, p1);
1166 d1 = DotProduct (p1, dir);
1173 void Brush_AddToList (brush_t *b, brush_t *list)
1175 if (b->next || b->prev)
1176 Error ("Brush_RemoveFromList: allready linked");
1177 b->next = list->next;
1178 list->next->prev = b;
1183 void Brush_RemoveFromList (brush_t *b)
1185 if (!b->next || !b->prev)
1186 Error ("Brush_RemoveFromList: not linked");
1187 b->next->prev = b->prev;
1188 b->prev->next = b->next;
1189 b->next = b->prev = NULL;
1192 void Brush_SetTexture (brush_t *b, texdef_t *texdef)
1196 for (f=b->brush_faces ; f ; f=f->next)
1197 f->texdef = *texdef;
1202 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
1208 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
1209 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
1211 if (d1 >= 0 && d2 >= 0)
1212 return false; // totally outside
1213 if (d1 <= 0 && d2 <= 0)
1214 return true; // totally inside
1216 fr = d1 / (d1 - d2);
1223 for (i=0 ; i<3 ; i++)
1224 v[i] = p1[i] + fr*(p2[i] - p1[i]);
1230 int AddPlanept (float *f)
1234 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
1235 if (g_qeglobals.d_move_points[i] == f)
1237 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
1243 Brush_SelectFaceForDragging
1245 Adds the faces planepts to move_points, and
1246 rotates and adds the planepts of adjacent face if shear is set
1249 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
1258 if (b->owner->eclass->fixedsize)
1262 for (i=0 ; i<3 ; i++)
1263 c += AddPlanept (f->planepts[i]);
1265 return; // allready completely added
1267 // select all points on this plane in all brushes the selection
1268 for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
1272 for (f2=b2->brush_faces ; f2 ; f2=f2->next)
1274 for (i=0 ; i<3 ; i++)
1275 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
1276 -f->plane.dist) > ON_EPSILON)
1279 { // move this face as well
1280 Brush_SelectFaceForDragging (b2, f2, shear);
1287 // if shearing, take all the planes adjacent to
1288 // selected faces and rotate their points so the
1289 // edge clipped by a selcted face has two of the points
1293 for (f2=b->brush_faces ; f2 ; f2=f2->next)
1297 w = MakeFaceWinding (b, f2);
1301 // any points on f will become new control points
1302 for (i=0 ; i<w->numpoints ; i++)
1304 d = DotProduct (w->points[i], f->plane.normal)
1306 if (d > -ON_EPSILON && d < ON_EPSILON)
1311 // if none of the points were on the plane,
1314 if (i != w->numpoints)
1317 { // see if the first clockwise point was the
1318 // last point on the winding
1319 d = DotProduct (w->points[w->numpoints-1]
1320 , f->plane.normal) - f->plane.dist;
1321 if (d > -ON_EPSILON && d < ON_EPSILON)
1322 i = w->numpoints - 1;
1325 AddPlanept (f2->planepts[0]);
1327 VectorCopy (w->points[i], f2->planepts[0]);
1328 if (++i == w->numpoints)
1331 // see if the next point is also on the plane
1332 d = DotProduct (w->points[i]
1333 , f->plane.normal) - f->plane.dist;
1334 if (d > -ON_EPSILON && d < ON_EPSILON)
1335 AddPlanept (f2->planepts[1]);
1337 VectorCopy (w->points[i], f2->planepts[1]);
1338 if (++i == w->numpoints)
1341 // the third point is never on the plane
1343 VectorCopy (w->points[i], f2->planepts[2]);
1354 The mouse click did not hit the brush, so grab one or more side
1358 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
1364 for (f=b->brush_faces ; f ; f=f->next)
1366 VectorCopy (origin, p1);
1367 VectorMA (origin, 16384, dir, p2);
1369 for (f2=b->brush_faces ; f2 ; f2=f2->next)
1373 ClipLineToFace (p1, p2, f2);
1379 if (VectorCompare (p1, origin))
1381 if (ClipLineToFace (p1, p2, f))
1384 Brush_SelectFaceForDragging (b, f, shear);
1390 void Brush_BuildWindings( brush_t *b )
1396 Brush_SnapPlanepts( b );
1398 // clear the mins/maxs bounds
1399 b->mins[0] = b->mins[1] = b->mins[2] = 99999;
1400 b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
1402 Brush_MakeFacePlanes (b);
1404 face = b->brush_faces;
1406 for ( ; face ; face=face->next)
1410 w = face->face_winding = MakeFaceWinding (b, face);
1411 face->d_texture = Texture_ForName( face->texdef.name );
1418 for (i=0 ; i<w->numpoints ; i++)
1420 // add to bounding box
1421 for (j=0 ; j<3 ; j++)
1423 v = w->points[i][j];
1430 // setup s and t vectors, and set color
1431 BeginTexturingFace( b, face, face->d_texture);
1434 for (i=0 ; i<w->numpoints ; i++)
1436 EmitTextureCoordinates( w->points[i], face->d_texture, face);
1443 Brush_RemoveEmptyFaces
1445 Frees any overconstraining faces
1448 void Brush_RemoveEmptyFaces ( brush_t *b )
1453 b->brush_faces = NULL;
1458 if (!f->face_winding)
1462 f->next = b->brush_faces;
1469 void Brush_Draw( brush_t *b )
1473 qtexture_t *prev = 0;
1476 if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
1477 glDisable (GL_TEXTURE_2D);
1479 // guarantee the texture will be set first
1481 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
1483 w = face->face_winding;
1485 continue; // freed face
1487 if ( face->d_texture != prev && camera.draw_mode == cd_texture)
1489 // set the texture for this face
1490 prev = face->d_texture;
1491 glBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
1494 glColor3fv( face->d_color );
1497 glBegin(GL_POLYGON);
1498 for (i=0 ; i<w->numpoints ; i++)
1500 if (camera.draw_mode == cd_texture)
1501 glTexCoord2fv( &w->points[i][3] );
1502 glVertex3fv(w->points[i]);
1507 if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture)
1508 glEnable (GL_TEXTURE_2D);
1510 glBindTexture( GL_TEXTURE_2D, 0 );
1513 void Face_Draw( face_t *f )
1517 if ( f->face_winding == 0 )
1519 glBegin( GL_POLYGON );
1520 for ( i = 0 ; i < f->face_winding->numpoints; i++)
1521 glVertex3fv( f->face_winding->points[i] );
1525 void Brush_DrawXY( brush_t *b )
1532 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
1534 // only draw up facing polygons
1535 if (face->plane.normal[2] <= 0)
1538 w = face->face_winding;
1543 glBegin(GL_LINE_LOOP);
1544 for (i=0 ; i<w->numpoints ; i++)
1545 glVertex3fv(w->points[i]);
1549 // optionally add a text label
1550 if ( g_qeglobals.d_savedinfo.show_names )
1551 DrawBrushEntityName (b);
1554 face_t *Face_Alloc( void )
1556 face_t *f = qmalloc( sizeof( *f ) );
1561 void Face_Free( face_t *f )
1565 if ( f->face_winding )
1566 free( f->face_winding ), f->face_winding = 0;