]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/brush.cpp
* reactivated WXY_Print function to generate screenshots from the xy window
[xonotic/netradiant.git] / radiant / brush.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 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.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "stdafx.h"
23 #include <assert.h>
24 #include "winding.h"
25 #include <limits.h>
26 #include "filters.h"
27
28 extern MainFrame* g_pParentWnd;
29 extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...);
30
31 // globals
32
33 int g_nBrushId = 0;
34
35 #ifdef ENABLE_GROUPS
36 const char* Brush_Name(brush_t *b)
37 {
38   static char cBuff[1024];
39         b->numberId = g_nBrushId++;
40         if (g_qeglobals.m_bBrushPrimitMode)
41   {
42     sprintf(cBuff, "Brush %i", b->numberId);
43     Brush_SetEpair(b, "Name", cBuff);
44   }
45   return cBuff;
46 }
47 #endif
48
49 brush_t *Brush_Alloc()
50 {
51   brush_t *b = (brush_t*)qmalloc(sizeof(brush_t));
52   return b;
53 }
54 /*
55 void Brush_Free(brush_t *b)
56 {
57   free(b);
58 }
59 */
60 void PrintWinding (winding_t *w)
61 {
62   int i;
63
64   Sys_Printf ("-------------\n");
65   for (i=0 ; i<w->numpoints ; i++)
66     Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
67             , w->points[i][1], w->points[i][2]);
68 }
69
70 void PrintPlane (plane_t *p)
71 {
72   Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n",  p->normal[0],  p->normal[1],
73   p->normal[2],  p->dist);
74 }
75
76 void PrintVector (vec3_t v)
77 {
78   Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n",  v[0],  v[1], v[2]);
79 }
80
81
82 /*
83 =============================================================================
84
85                         TEXTURE COORDINATES
86
87 =============================================================================
88 */
89
90
91 /*
92 ==================
93 textureAxisFromPlane
94 ==================
95 */
96 vec3_t  baseaxis[18] =
97 {
98 {0,0,1}, {1,0,0}, {0,-1,0},                     // floor
99 {0,0,-1}, {1,0,0}, {0,-1,0},            // ceiling
100 {1,0,0}, {0,1,0}, {0,0,-1},                     // west wall
101 {-1,0,0}, {0,1,0}, {0,0,-1},            // east wall
102 {0,1,0}, {1,0,0}, {0,0,-1},                     // south wall
103 {0,-1,0}, {1,0,0}, {0,0,-1}                     // north wall
104 };
105
106 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
107 {
108         int             bestaxis;
109         float   dot,best;
110         int             i;
111
112         best = 0;
113         bestaxis = 0;
114
115         for (i=0 ; i<6 ; i++)
116         {
117                 dot = DotProduct (pln->normal, baseaxis[i*3]);
118     if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best)
119                 {
120                         best = dot;
121                         bestaxis = i;
122                 }
123         }
124
125         VectorCopy (baseaxis[bestaxis*3+1], xv);
126         VectorCopy (baseaxis[bestaxis*3+2], yv);
127 }
128
129
130
131 float   lightaxis[3] = {0.6f, 0.8f, 1.0f};
132 /*
133 ================
134 SetShadeForPlane
135
136 Light different planes differently to
137 improve recognition
138 ================
139 */
140 extern float ShadeForNormal(vec3_t normal);
141
142 float SetShadeForPlane (plane_t *p)
143 {
144         //return ShadeForNormal(p->normal);
145
146
147         int             i;
148         float   f;
149
150         // axial plane
151         for (i=0 ; i<3 ; i++)
152                 if (fabs(p->normal[i]) > 0.9)
153                 {
154                         f = lightaxis[i];
155                         return f;
156                 }
157
158         // between two axial planes
159         for (i=0 ; i<3 ; i++)
160                 if (fabs(p->normal[i]) < 0.1)
161                 {
162                         f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
163                         return f;
164                 }
165
166         // other
167         f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
168         return f;
169
170 }
171
172 vec3_t  vecs[2];
173 float   shift[2];
174
175 /*
176 ================
177 Face_Alloc
178 ================
179 */
180 face_t *Face_Alloc( void )
181 {
182         face_t *f = (face_t*)qmalloc( sizeof( *f ) );
183         return f;
184 }
185
186 /*
187 ================
188 Face_Free
189 ================
190 */
191 void Face_Free( face_t *f )
192 {
193         assert( f != 0 );
194
195         if ( f->face_winding )
196         {
197                 free( f->face_winding );
198                 f->face_winding = 0;
199         }
200         f->texdef.~texdef_t();;
201
202         free( f );
203 }
204
205 /*
206 ================
207 Face_Clone
208 ================
209 */
210 face_t  *Face_Clone (face_t *f)
211 {
212         face_t  *n;
213
214         n = Face_Alloc();
215         n->texdef = f->texdef;
216   n->brushprimit_texdef = f->brushprimit_texdef;
217
218         memcpy (n->planepts, f->planepts, sizeof(n->planepts));
219
220         // all other fields are derived, and will be set by Brush_Build
221   // FIXME: maybe not, for example n->pData!
222         return n;
223 }
224
225 /*
226 ================
227 Face_FullClone
228
229 makes an exact copy of the face
230 ================
231 */
232 face_t  *Face_FullClone (face_t *f)
233 {
234         face_t  *n;
235
236         n = Face_Alloc();
237         n->texdef = f->texdef;
238   n->brushprimit_texdef = f->brushprimit_texdef;
239         memcpy(n->planepts, f->planepts, sizeof(n->planepts));
240         memcpy(&n->plane, &f->plane, sizeof(plane_t));
241         if (f->face_winding)
242                 n->face_winding = Winding_Clone(f->face_winding);
243         else
244                 n->face_winding = NULL;
245         n->pShader = f->pShader;
246         n->pShader->IncRef();
247         n->d_texture = n->pShader->getTexture();
248         return n;
249 }
250
251 void Face_SetShader(face_t *face, const char *name)
252 {
253   if(face->pShader != NULL)
254     face->pShader->DecRef();
255   face->texdef.SetName(name);
256   face->pShader = QERApp_Shader_ForName(name);
257   face->pShader->IncRef();
258   face->d_texture = face->pShader->getTexture();
259   face->texdef.flags = face->pShader->getFlags();
260 }
261
262 void Face_SetShader(face_t *face, IShader *shader)
263 {
264   if(face->pShader != NULL)
265     face->pShader->DecRef();
266   face->texdef.SetName(shader->getName());
267   face->d_texture = shader->getTexture();
268   face->texdef.flags = shader->getFlags();
269   face->pShader = shader;
270   face->pShader->IncRef();
271 }
272
273 /*
274 ================
275 Clamp
276 ================
277 */
278 void Clamp(float& f, int nClamp)
279 {
280   float fFrac = f - static_cast<int>(f);
281   f = static_cast<int>(f) % nClamp;
282   f += fFrac;
283 }
284
285 /*
286 ================
287 Face_MoveTexture
288 ================
289 */
290 void Face_MoveTexture(face_t *f, vec3_t delta)
291 {
292         vec3_t vX, vY;
293
294         if (g_qeglobals.m_bBrushPrimitMode)
295                 ShiftTextureGeometric_BrushPrimit( f, delta );
296         else
297         {
298                 TextureAxisFromPlane(&f->plane, vX, vY);
299
300                 vec3_t vDP, vShift;
301                 vDP[0] = DotProduct(delta, vX);
302                 vDP[1] = DotProduct(delta, vY);
303
304                 double fAngle = f->texdef.rotate  / 180 * Q_PI;
305                 double c = cos(fAngle);
306                 double s = sin(fAngle);
307
308                 vShift[0] = vDP[0] * c - vDP[1] * s;
309                 vShift[1] = vDP[0] * s + vDP[1] * c;
310
311                 if (!f->texdef.scale[0])
312                         f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale;
313                 if (!f->texdef.scale[1])
314                         f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale;
315
316                 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
317                 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
318
319                 // clamp the shifts
320                 Clamp(f->texdef.shift[0], f->d_texture->width);
321                 Clamp(f->texdef.shift[1], f->d_texture->height);
322         }
323 }
324
325 /*
326 ================
327 Face_SetColor
328 ================
329 */
330 /*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/
331 void Face_SetColor (brush_t *b, face_t *f, float fCurveColor)
332 {
333         // set shading for face
334   f->d_shade = SetShadeForPlane (&f->plane);
335         f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade;
336   f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade;
337         f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade;
338 }
339
340 /*
341 ================
342 Face_TextureVectors
343 ================
344 */
345 void Face_TextureVectors (face_t *f, float STfromXYZ[2][4])
346 {
347         vec3_t          pvecs[2];
348         int                     sv, tv;
349         float           ang, sinv, cosv;
350         float           ns, nt;
351         int                     i,j;
352         qtexture_t *q;
353         texdef_t        *td;
354
355 #ifdef _DEBUG
356         // this code is not supposed to be used while in BP mode, warning here can help spot the problem
357         if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert)
358                 Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
359 #endif
360
361         td = &f->texdef;
362         q = f->d_texture;
363
364         memset (STfromXYZ, 0, 8*sizeof(float));
365
366         if (!td->scale[0])
367                 td->scale[0] = g_pGameDescription->mTextureDefaultScale;
368         if (!td->scale[1])
369                 td->scale[1] = g_pGameDescription->mTextureDefaultScale;
370
371         // get natural texture axis
372         TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
373
374         // rotate axis
375         if (td->rotate == 0)
376                 { sinv = 0 ; cosv = 1; }
377         else if (td->rotate == 90)
378                 { sinv = 1 ; cosv = 0; }
379         else if (td->rotate == 180)
380                 { sinv = 0 ; cosv = -1; }
381         else if (td->rotate == 270)
382                 { sinv = -1 ; cosv = 0; }
383         else
384         {
385                 ang = td->rotate / 180 * Q_PI;
386                 sinv = sin(ang);
387                 cosv = cos(ang);
388         }
389
390         if (pvecs[0][0])
391                 sv = 0;
392         else if (pvecs[0][1])
393                 sv = 1;
394         else
395                 sv = 2;
396
397         if (pvecs[1][0])
398                 tv = 0;
399         else if (pvecs[1][1])
400                 tv = 1;
401         else
402                 tv = 2;
403
404         for (i=0 ; i<2 ; i++) {
405                 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
406                 nt = sinv * pvecs[i][sv] +  cosv * pvecs[i][tv];
407                 STfromXYZ[i][sv] = ns;
408                 STfromXYZ[i][tv] = nt;
409         }
410
411         // scale
412         for (i=0 ; i<2 ; i++)
413                 for (j=0 ; j<3 ; j++)
414                         STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
415
416         // shift
417         STfromXYZ[0][3] = td->shift[0];
418         STfromXYZ[1][3] = td->shift[1];
419
420         for (j=0 ; j<4 ; j++) {
421                 STfromXYZ[0][j] /= q->width;
422                 STfromXYZ[1][j] /= q->height;
423         }
424 }
425
426 /*
427 ================
428 Face_MakePlane
429 ================
430 */
431 void Face_MakePlane (face_t *f)
432 {
433         int             j;
434         vec3_t  t1, t2, t3;
435
436         // convert to a vector / dist plane
437         for (j=0 ; j<3 ; j++)
438         {
439                 t1[j] = f->planepts[0][j] - f->planepts[1][j];
440                 t2[j] = f->planepts[2][j] - f->planepts[1][j];
441                 t3[j] = f->planepts[1][j];
442         }
443
444         CrossProduct(t1,t2, f->plane.normal);
445         if (VectorCompare (f->plane.normal, vec3_origin))
446                 Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n");
447         VectorNormalize (f->plane.normal, f->plane.normal);
448         f->plane.dist = DotProduct (t3, f->plane.normal);
449 }
450
451 /*
452 ================
453 EmitTextureCoordinates
454 ================
455 */
456 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
457 {
458         float   STfromXYZ[2][4];
459
460         Face_TextureVectors (f,  STfromXYZ);
461         xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
462         xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
463 }
464
465 //==========================================================================
466
467 /*
468 ================
469 Brush_MakeFacePlanes
470 ================
471 */
472 void Brush_MakeFacePlanes (brush_t *b)
473 {
474         face_t  *f;
475
476         for (f=b->brush_faces ; f ; f=f->next)
477         {
478                 Face_MakePlane (f);
479         }
480 }
481
482 /*
483 ================
484 DrawBrushEntityName
485 ================
486 */
487 void DrawBrushEntityName (brush_t *b)
488 {
489   const char  *name;
490   float a, s, c;
491   vec3_t  mid;
492   int   i;
493
494   if (!b->owner)
495     return;   // during contruction
496
497   if (b->owner == world_entity)
498     return;
499
500   if (b != b->owner->brushes.onext)
501     return; // not key brush
502
503   // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views
504   // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job?
505   // Brush_DrawFacingAngle() works when called, but is not being called.
506   if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))
507   {
508     // draw the angle pointer
509     a = FloatForKey (b->owner, "angle");
510     s = sin (a/180*Q_PI);
511     c = cos (a/180*Q_PI);
512     for (i=0 ; i<3 ; i++)
513       mid[i] = (b->mins[i] + b->maxs[i])*0.5;
514
515     qglBegin (GL_LINE_STRIP);
516     qglVertex3fv (mid);
517     mid[0] += c*8;
518     mid[1] += s*8;
519     mid[2] += s*8;
520     qglVertex3fv (mid);
521     mid[0] -= c*4;
522     mid[1] -= s*4;
523     mid[2] -= s*4;
524     mid[0] -= s*4;
525     mid[1] += c*4;
526     mid[2] += c*4;
527     qglVertex3fv (mid);
528     mid[0] += c*4;
529     mid[1] += s*4;
530     mid[2] += s*4;
531     mid[0] += s*4;
532     mid[1] -= c*4;
533     mid[2] -= c*4;
534     qglVertex3fv (mid);
535     mid[0] -= c*4;
536     mid[1] -= s*4;
537     mid[2] -= s*4;
538     mid[0] += s*4;
539     mid[1] -= c*4;
540     mid[2] -= c*4;
541     qglVertex3fv (mid);
542     qglEnd ();
543   }
544
545   if (g_qeglobals.d_savedinfo.show_names)
546   {
547     name = ValueForKey (b->owner, "classname");
548     qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);
549     gtk_glwidget_print_string(name);
550   }
551 }
552
553 /*
554 =================
555 Brush_MakeFaceWinding
556
557 returns the visible polygon on a face
558 =================
559 */
560 winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)
561 {
562         winding_t       *w;
563         face_t          *clip;
564         plane_t                 plane;
565         qboolean                past;
566
567   // get a poly that covers an effectively infinite area
568         w = Winding_BaseForPlane (&face->plane);
569
570         // chop the poly by all of the other faces
571         past = false;
572         for (clip = b->brush_faces ; clip && w ; clip=clip->next)
573         {
574                 if (clip == face)
575                 {
576                         past = true;
577                         continue;
578                 }
579                 if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
580                         && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
581                 {       // identical plane, use the later one
582                         if (past)
583                         {
584                                 free (w);
585                                 return NULL;
586                         }
587                         continue;
588                 }
589
590                 // flip the plane, because we want to keep the back side
591                 VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
592                 plane.dist = -clip->plane.dist;
593
594                 w = Winding_Clip (w, &plane, false);
595                 if (!w)
596                         return w;
597         }
598
599         if (w->numpoints < 3)
600         {
601                 free(w);
602                 w = NULL;
603         }
604
605         if (!w)
606                 Sys_FPrintf (SYS_WRN, "unused plane\n");
607
608         return w;
609 }
610
611 /*
612 =================
613 Brush_SnapPlanepts
614 =================
615 */
616 void Brush_SnapPlanepts (brush_t *b)
617 {
618         int             i, j;
619         face_t  *f;
620
621   if (g_PrefsDlg.m_bNoClamp)
622     return;
623
624   if (g_qeglobals.d_bSmallGrid)
625   {
626           for (f=b->brush_faces ; f; f=f->next)
627                   for (i=0 ; i<3 ; i++)
628                           for (j=0 ; j<3 ; j++)
629                                 f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize;
630   }
631   else
632   {
633           for (f=b->brush_faces ; f; f=f->next)
634                   for (i=0 ; i<3 ; i++)
635                           for (j=0 ; j<3 ; j++)
636                                   f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
637   }
638 }
639
640 /*
641 ** Brush_Build
642 **
643 ** Builds a brush rendering data and also sets the min/max bounds
644 */
645 // TTimo
646 // added a bConvert flag to convert between old and new brush texture formats
647 // TTimo
648 // brush grouping: update the group treeview if necessary
649 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest)
650 {
651         bool            bLocalConvert;
652
653
654 #ifdef _DEBUG
655         if (!g_qeglobals.m_bBrushPrimitMode && bConvert)
656                 Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
657 #endif
658
659         // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
660         if (bConvert && !g_qeglobals.bNeedConvert)
661         {
662 #ifdef _DEBUG
663     //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes
664     // back and forth in one format or the other .. more when mixing BP / noBP in the same maps.
665 #endif
666                 bLocalConvert = true;
667                 g_qeglobals.bNeedConvert = true;
668         }
669         else
670           bLocalConvert = false;
671
672         /*
673         ** build the windings and generate the bounding box
674         */
675         Brush_BuildWindings(b, bSnap);
676
677   if(b->owner->model.pRender)
678   {
679     const aabb_t *aabb = b->owner->model.pRender->GetAABB();
680     VectorAdd(aabb->origin, aabb->extents, b->maxs);
681     VectorSubtract(aabb->origin, aabb->extents, b->mins);
682   }
683
684         //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH !
685
686         /*
687         ** move the points and edges if in select mode
688         */
689         if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
690                 SetupVertexSelection ();
691
692         if (b->itemOwner == 0) //NULL)
693           Group_AddToProperGroup(b);
694
695         if (bMarkMap)
696         {
697                 Sys_MarkMapModified();
698         }
699
700         if (bLocalConvert)
701                 g_qeglobals.bNeedConvert = false;
702
703         // spog - applying filters to brush during brush_build instead of during redraw
704         if (bFilterTest)
705                 b->bFiltered = FilterBrush( b );
706 }
707
708 /*
709 ==============
710 Brush_SplitBrushByFace
711
712 The incoming brush is NOT freed.
713 The incoming face is NOT left referenced.
714 ==============
715 */
716 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk)
717 {
718         brush_t *b;
719         face_t  *nf;
720         vec3_t  temp;
721
722         b = Brush_Clone (in);
723         nf = Face_Clone (f);
724
725         nf->texdef = b->brush_faces->texdef;
726   if (bCaulk)
727   {
728     nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
729   }
730         nf->next = b->brush_faces;
731         b->brush_faces = nf;
732
733         Brush_Build( b );
734         Brush_RemoveEmptyFaces ( b );
735         if ( !b->brush_faces )
736         {       // completely clipped away
737                 Brush_Free (b);
738                 *back = NULL;
739         }
740         else
741         {
742                 Entity_LinkBrush (in->owner, b);
743                 *back = b;
744         }
745
746         b = Brush_Clone (in);
747         nf = Face_Clone (f);
748         // swap the plane winding
749         VectorCopy (nf->planepts[0], temp);
750         VectorCopy (nf->planepts[1], nf->planepts[0]);
751         VectorCopy (temp, nf->planepts[1]);
752
753         nf->texdef = b->brush_faces->texdef;
754   if (bCaulk)
755   {
756     nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
757   }
758         nf->next = b->brush_faces;
759         b->brush_faces = nf;
760
761         Brush_Build( b );
762         Brush_RemoveEmptyFaces ( b );
763         if ( !b->brush_faces )
764         {       // completely clipped away
765                 Brush_Free (b);
766                 *front = NULL;
767         }
768         else
769         {
770                 Entity_LinkBrush (in->owner, b);
771                 *front = b;
772         }
773 }
774
775 /*
776 =================
777 Brush_BestSplitFace
778
779 returns the best face to split the brush with.
780 return NULL if the brush is convex
781 =================
782 */
783 face_t *Brush_BestSplitFace(brush_t *b)
784 {
785         face_t *face, *f, *bestface;
786         winding_t *front, *back;
787         int splits, tinywindings, value, bestvalue;
788
789         bestvalue = 999999;
790         bestface = NULL;
791         for (face = b->brush_faces; face; face = face->next)
792         {
793                 splits = 0;
794                 tinywindings = 0;
795                 for (f = b->brush_faces; f; f = f->next)
796                 {
797                         if (f == face) continue;
798                         //
799                         Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back);
800
801                         if (!front)
802                         {
803                                 Winding_Free(back);
804                         }
805                         else if (!back)
806                         {
807                                 Winding_Free(front);
808                         }
809                         else
810                         {
811                                 splits++;
812                                 if (Winding_IsTiny(front)) tinywindings++;
813                                 if (Winding_IsTiny(back)) tinywindings++;
814                         }
815                 }
816                 if (splits)
817                 {
818                         value = splits + 50 * tinywindings;
819                         if (value < bestvalue)
820                         {
821                                 bestvalue = value;
822                                 bestface = face;
823                         }
824                 }
825         }
826         return bestface;
827 }
828
829 /*
830 =================
831 Brush_MakeConvexBrushes
832
833 MrE FIXME: this doesn't work because the old
834                    Brush_SplitBrushByFace is used
835 Turns the brush into a minimal number of convex brushes.
836 If the input brush is convex then it will be returned.
837 Otherwise the input brush will be freed.
838 NOTE: the input brush should have windings for the faces.
839 =================
840 */
841 brush_t *Brush_MakeConvexBrushes(brush_t *b)
842 {
843         brush_t *front, *back, *end;
844         face_t *face;
845
846         b->next = NULL;
847         face = Brush_BestSplitFace(b);
848         if (!face) return b;
849         Brush_SplitBrushByFace(b, face, &front, &back);
850         //this should never happen
851         if (!front && !back) return b;
852         Brush_Free(b);
853         if (!front)
854                 return Brush_MakeConvexBrushes(back);
855         b = Brush_MakeConvexBrushes(front);
856         if (back)
857         {
858                 for (end = b; end->next; end = end->next);
859                 end->next = Brush_MakeConvexBrushes(back);
860         }
861         return b;
862 }
863
864 /*
865 =================
866 Brush_Convex
867 =================
868 */
869 int Brush_Convex(brush_t *b)
870 {
871         face_t *face1, *face2;
872
873         for (face1 = b->brush_faces; face1; face1 = face1->next)
874         {
875                 if (!face1->face_winding) continue;
876                 for (face2 = b->brush_faces; face2; face2 = face2->next)
877                 {
878                         if (face1 == face2) continue;
879                         if (!face2->face_winding) continue;
880                         if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
881                                                                                 face1->plane.normal, face2->plane.normal,
882                                                                                 face1->plane.dist, face2->plane.dist))
883                         {
884                                 return false;
885                         }
886                 }
887         }
888         return true;
889 }
890
891 /*
892 =================
893 Brush_MoveVertexes
894
895 - The input brush must be convex
896 - The input brush must have face windings.
897 - The output brush will be convex.
898 - Returns true if the WHOLE vertex movement is performed.
899 =================
900 */
901
902 // define this to debug the vertex editing mode
903 #ifdef _DEBUG
904 //#define DBG_VERT
905 #endif
906
907 #define MAX_MOVE_FACES          64
908
909 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
910 {
911         face_t *f, *face, *newface, *lastface, *nextface;
912         face_t *movefaces[MAX_MOVE_FACES];
913         int movefacepoints[MAX_MOVE_FACES];
914         winding_t *w, tmpw;
915         vec3_t start, mid;
916         plane_t plane;
917         int i, j, k, nummovefaces, result, done;
918         float dot, front, back, frac, smallestfrac;
919
920 #ifdef DBG_VERT
921   Sys_Printf("Bursh_MoveVertex: %p vertex: %g %g %g delta: %g %g %g end: %g %g %g snap: %s\n", b, vertex[0], vertex[1], vertex[2], delta[0], delta[1], delta[2], end[0], end[1], end[2], bSnap ? "true" : "false" );
922 #endif
923
924         result = true;
925         //
926         tmpw.numpoints = 3;
927         tmpw.maxpoints = 3;
928         VectorCopy(vertex, start);
929         VectorAdd(vertex, delta, end);
930         //snap or not?
931         if (bSnap)
932                 for (i = 0; i < 3; i++)
933                         end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize;
934         //
935         VectorCopy(end, mid);
936         //if the start and end are the same
937         if (Point_Equal(start, end, 0.3f)) return false;
938         //the end point may not be the same as another vertex
939         for (face = b->brush_faces; face; face = face->next)
940         {
941                 w = face->face_winding;
942                 if (!w) continue;
943                 for (i = 0; i < w->numpoints; i++)
944                 {
945                         if (Point_Equal(w->points[i], end, 0.3f))
946                         {
947                                 VectorCopy(vertex, end);
948                                 return false;
949                         }
950                 }
951         }
952         //
953         done = false;
954         while(!done)
955         {
956                 //chop off triangles from all brush faces that use the to be moved vertex
957                 //store pointers to these chopped off triangles in movefaces[]
958                 nummovefaces = 0;
959                 for (face = b->brush_faces; face; face = face->next)
960                 {
961                         w = face->face_winding;
962                         if (!w) continue;
963                         for (i = 0; i < w->numpoints; i++)
964                         {
965                                 if (Point_Equal(w->points[i], start, 0.2f))
966                                 {
967                                         if (face->face_winding->numpoints <= 3)
968                                         {
969                                                 movefacepoints[nummovefaces] = i;
970                                                 movefaces[nummovefaces++] = face;
971                                                 break;
972                                         }
973                                         dot = DotProduct(end, face->plane.normal) - face->plane.dist;
974                                         //if the end point is in front of the face plane
975                                         if (dot > 0.1)
976                                         {
977                                           //fanout triangle subdivision
978                                           for (k = i; k < i + w->numpoints-3; k++)
979                                           {
980                                             VectorCopy(w->points[i], tmpw.points[0]);
981                                             VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
982                                             VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
983                                             //
984                                             newface = Face_Clone(face);
985                                             //get the original
986                                             for (f = face; f->original; f = f->original) ;
987                                             newface->original = f;
988                                             //store the new winding
989                                             if (newface->face_winding) Winding_Free(newface->face_winding);
990                                             newface->face_winding = Winding_Clone(&tmpw);
991                                             //get the texture information
992                                             newface->pShader = face->pShader;
993                                             newface->d_texture = face->d_texture;
994
995                                             //add the face to the brush
996                                             newface->next = b->brush_faces;
997                                             b->brush_faces = newface;
998                                             //add this new triangle to the move faces
999                                             movefacepoints[nummovefaces] = 0;
1000                                             movefaces[nummovefaces++] = newface;
1001                                           }
1002                                           //give the original face a new winding
1003                                           VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
1004                                           VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
1005                                           VectorCopy(w->points[i], tmpw.points[2]);
1006                                           Winding_Free(face->face_winding);
1007                                           face->face_winding = Winding_Clone(&tmpw);
1008                                           //add the original face to the move faces
1009                                           movefacepoints[nummovefaces] = 2;
1010                                           movefaces[nummovefaces++] = face;
1011                                         }
1012                                         else
1013                                         {
1014                                                 //chop a triangle off the face
1015                                                 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
1016                                                 VectorCopy(w->points[i], tmpw.points[1]);
1017                                                 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
1018                                                 //remove the point from the face winding
1019                                                 Winding_RemovePoint(w, i);
1020                                                 //get texture crap right
1021                                                 Face_SetColor(b, face, 1.0);
1022                                                 for (j = 0; j < w->numpoints; j++)
1023                                                         EmitTextureCoordinates(w->points[j], face->d_texture, face);
1024                                                 //make a triangle face
1025                                                 newface = Face_Clone(face);
1026                                                 //get the original
1027                                                 for (f = face; f->original; f = f->original) ;
1028                                                 newface->original = f;
1029                                                 //store the new winding
1030                                                 if (newface->face_winding) Winding_Free(newface->face_winding);
1031                                                 newface->face_winding = Winding_Clone(&tmpw);
1032                                                 //get the texture
1033                                                 newface->pShader = face->pShader;
1034                                                 newface->d_texture = newface->pShader->getTexture();
1035 //                                              newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name );
1036                                                 //add the face to the brush
1037                                                 newface->next = b->brush_faces;
1038                                                 b->brush_faces = newface;
1039                                                 //
1040                                                 movefacepoints[nummovefaces] = 1;
1041                                                 movefaces[nummovefaces++] = newface;
1042                                         }
1043                                         break;
1044                                 }
1045                         }
1046                 }
1047                 //now movefaces contains pointers to triangle faces that
1048                 //contain the to be moved vertex
1049                 //
1050                 done = true;
1051                 VectorCopy(end, mid);
1052                 smallestfrac = 1;
1053                 for (face = b->brush_faces; face; face = face->next)
1054                 {
1055                         //check if there is a move face that has this face as the original
1056                         for (i = 0; i < nummovefaces; i++)
1057                         {
1058                                 if (movefaces[i]->original == face) break;
1059                         }
1060                         if (i >= nummovefaces) continue;
1061                         //check if the original is not a move face itself
1062                         for (j = 0; j < nummovefaces; j++)
1063                         {
1064                                 if (face == movefaces[j]) break;
1065                         }
1066                         //if the original is not a move face itself
1067                         if (j >= nummovefaces)
1068                         {
1069                                 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t));
1070                         }
1071                         else
1072                         {
1073                                 k = movefacepoints[j];
1074                                 w = movefaces[j]->face_winding;
1075                                 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]);
1076                                 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]);
1077                                 //
1078                                 k = movefacepoints[i];
1079                                 w = movefaces[i]->face_winding;
1080                                 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]);
1081                                 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
1082                                 {
1083                                         VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]);
1084                                         if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
1085                                                 //this should never happen otherwise the face merge did a crappy job a previous pass
1086                                                 continue;
1087                                 }
1088                         }
1089                         //now we've got the plane to check agains
1090                         front = DotProduct(start, plane.normal) - plane.dist;
1091                         back = DotProduct(end, plane.normal) - plane.dist;
1092                         //if the whole move is at one side of the plane
1093                         if (front < 0.01 && back < 0.01) continue;
1094                         if (front > -0.01 && back > -0.01) continue;
1095                         //if there's no movement orthogonal to this plane at all
1096                         if (fabs(front-back) < 0.001) continue;
1097                         //ok first only move till the plane is hit
1098                         frac = front/(front-back);
1099                         if (frac < smallestfrac)
1100                         {
1101                                 mid[0] = start[0] + (end[0] - start[0]) * frac;
1102                                 mid[1] = start[1] + (end[1] - start[1]) * frac;
1103                                 mid[2] = start[2] + (end[2] - start[2]) * frac;
1104                                 smallestfrac = frac;
1105                         }
1106                         //
1107                         done = false;
1108                 }
1109
1110                 //move the vertex
1111                 for (i = 0; i < nummovefaces; i++)
1112                 {
1113                         //move vertex to end position
1114                         VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]);
1115                         //create new face plane
1116                         for (j = 0; j < 3; j++)
1117                         {
1118                                 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
1119                         }
1120                         Face_MakePlane(movefaces[i]);
1121                         if (VectorLength(movefaces[i]->plane.normal) < 0.1)
1122                                 result = false;
1123                 }
1124                 //if the brush is no longer convex
1125                 if (!result || !Brush_Convex(b))
1126                 {
1127                         for (i = 0; i < nummovefaces; i++)
1128                         {
1129                                 //move the vertex back to the initial position
1130                                 VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]);
1131                                 //create new face plane
1132                                 for (j = 0; j < 3; j++)
1133                                 {
1134                                         VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
1135                                 }
1136                                 Face_MakePlane(movefaces[i]);
1137                         }
1138                         result = false;
1139                         VectorCopy(start, end);
1140                         done = true;
1141                 }
1142                 else
1143                 {
1144                         VectorCopy(mid, start);
1145                 }
1146                 //get texture crap right
1147                 for (i = 0; i < nummovefaces; i++)
1148                 {
1149                         Face_SetColor(b, movefaces[i], 1.0);
1150                         for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
1151                                 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
1152                 }
1153
1154                 //now try to merge faces with their original faces
1155                 lastface = NULL;
1156                 for (face = b->brush_faces; face; face = nextface)
1157                 {
1158                         nextface = face->next;
1159                         if (!face->original)
1160                         {
1161                                 lastface = face;
1162                                 continue;
1163                         }
1164                         if (!Plane_Equal(&face->plane, &face->original->plane, false))
1165                         {
1166                                 lastface = face;
1167                                 continue;
1168                         }
1169                         w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
1170                         if (!w)
1171                         {
1172                                 lastface = face;
1173                                 continue;
1174                         }
1175                         Winding_Free(face->original->face_winding);
1176                         face->original->face_winding = w;
1177                         //get texture crap right
1178                         Face_SetColor(b, face->original, 1.0);
1179                         for (j = 0; j < face->original->face_winding->numpoints; j++)
1180                                 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
1181                         //remove the face that was merged with the original
1182                         if (lastface) lastface->next = face->next;
1183                         else b->brush_faces = face->next;
1184                         Face_Free(face);
1185                 }
1186         }
1187         return result;
1188 }
1189
1190 /*
1191 =================
1192 Brush_InsertVertexBetween
1193 =================
1194 */
1195 int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2)
1196 {
1197         face_t *face;
1198         winding_t *w, *neww;
1199         vec3_t point;
1200         int i, insert;
1201
1202         if (Point_Equal(p1, p2, 0.4f))
1203                 return false;
1204         VectorAdd(p1, p2, point);
1205         VectorScale(point, 0.5f, point);
1206         insert = false;
1207         //the end point may not be the same as another vertex
1208         for (face = b->brush_faces; face; face = face->next)
1209         {
1210                 w = face->face_winding;
1211                 if (!w) continue;
1212                 neww = NULL;
1213                 for (i = 0; i < w->numpoints; i++)
1214                 {
1215                         if (!Point_Equal(w->points[i], p1, 0.1f))
1216                                 continue;
1217                         if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f))
1218                         {
1219                                 neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints);
1220                                 break;
1221                         }
1222                         else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f))
1223                         {
1224                                 neww = Winding_InsertPoint(w, point, i);
1225                                 break;
1226                         }
1227                 }
1228                 if (neww)
1229                 {
1230                         Winding_Free(face->face_winding);
1231                         face->face_winding = neww;
1232                         insert = true;
1233                 }
1234         }
1235         return insert;
1236 }
1237
1238
1239 /*
1240 =================
1241 Brush_ResetFaceOriginals
1242 =================
1243 */
1244 void Brush_ResetFaceOriginals(brush_t *b)
1245 {
1246         face_t *face;
1247
1248         for (face = b->brush_faces; face; face = face->next)
1249         {
1250                 face->original = NULL;
1251         }
1252 }
1253
1254 #ifdef ENABLE_GROUPS
1255 /*
1256 ==============
1257 Brush_SetEpair
1258 sets an epair for the given brush
1259 ==============
1260 */
1261 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)
1262 {
1263         if (g_qeglobals.m_bBrushPrimitMode)
1264         {
1265     if (b->patchBrush)
1266     {
1267       Patch_SetEpair(b->pPatch, pKey, pValue);
1268     }
1269     else
1270     {
1271                   SetKeyValue(b->epairs, pKey, pValue);
1272     }
1273         }
1274         else
1275         {
1276                 Sys_Printf("Can only set key/values in Brush primitive mode\n");
1277         }
1278 }
1279
1280 /*
1281 =================
1282 Brush_GetKeyValue
1283 =================
1284 */
1285 const char* Brush_GetKeyValue(brush_t *b, const char *pKey)
1286 {
1287         if (g_qeglobals.m_bBrushPrimitMode)
1288         {
1289     if (b->patchBrush)
1290     {
1291       return Patch_GetKeyValue(b->pPatch, pKey);
1292     }
1293     else
1294     {
1295                   return ValueForKey(b->epairs, pKey);
1296     }
1297         }
1298         else
1299         {
1300                 Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n");
1301         }
1302   return "";
1303 }
1304 #endif
1305 /*
1306 =================
1307 CheckName
1308 temporary stuff, detect potential problems when saving the texture name
1309 =================
1310 */
1311 void CheckName( face_t *fa, char *pname )
1312 {
1313   if (!strlen(fa->texdef.GetName()))
1314         {
1315 #ifdef _DEBUG
1316                 Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n");
1317 #endif
1318                 fa->texdef.SetName(SHADER_NOT_FOUND);
1319                 strcpy(pname, SHADER_NOT_FOUND);
1320                 return;
1321         }
1322
1323         // some people manage to get long filename textures (with spaces) in their maps
1324         if (strchr( fa->texdef.GetName(), ' ' ))
1325         {
1326                 char Msg1[1024];
1327
1328     sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", fa->texdef.GetName() );
1329
1330                 Sys_Printf("%s\n", Msg1 );
1331                 gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );
1332                 strcpy( pname, SHADER_NOT_FOUND );
1333                 return;
1334         }
1335
1336   //++timo FIXME: bug #103494 detection attempt
1337   // TODO: clean this detection part when bug will have disappeared
1338         if (fa->texdef.GetName()[0] == '(')
1339   {
1340                 const char *text = "Bug #103494 detected, dropping texture. Please report to timo@qeradiant.com if you have a way to reproduce!\nNOTE: this message may popup several times .. once for each buggy face detected.";
1341                 Sys_Printf("%s\n", text);
1342                 gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK );
1343                 // need to cleanup this dead face name or we may loop endlessly
1344                 fa->texdef.SetName(SHADER_NOT_FOUND);
1345                 strcpy( pname, SHADER_NOT_FOUND );
1346                 return;
1347         }
1348         strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/"
1349 }
1350
1351 /*
1352 =============
1353 Brush_Create
1354
1355 Create non-textured blocks for entities
1356 The brush is NOT linked to any list
1357 =============
1358 */
1359 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
1360 {
1361         int             i, j;
1362         vec3_t  pts[4][2];
1363         face_t  *f;
1364         brush_t *b;
1365
1366 #if DBG_BP
1367         // brush primitive mode : convert texdef to brushprimit_texdef ?
1368         // most of the time texdef is empty
1369         if (g_qeglobals.m_bBrushPrimitMode)
1370         {
1371                 // check texdef is empty .. if there are cases it's not we need to write some conversion code
1372                 if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0)
1373                         Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n");
1374         }
1375 #endif
1376
1377         for (i=0 ; i<3 ; i++)
1378         {
1379                 if (maxs[i] < mins[i])
1380                         Error ("Brush_InitSolid: backwards");
1381         }
1382
1383         b = Brush_Alloc();
1384
1385         pts[0][0][0] = mins[0];
1386         pts[0][0][1] = mins[1];
1387
1388         pts[1][0][0] = mins[0];
1389         pts[1][0][1] = maxs[1];
1390
1391         pts[2][0][0] = maxs[0];
1392         pts[2][0][1] = maxs[1];
1393
1394         pts[3][0][0] = maxs[0];
1395         pts[3][0][1] = mins[1];
1396
1397         for (i=0 ; i<4 ; i++)
1398         {
1399                 pts[i][0][2] = mins[2];
1400                 pts[i][1][0] = pts[i][0][0];
1401                 pts[i][1][1] = pts[i][0][1];
1402                 pts[i][1][2] = maxs[2];
1403         }
1404
1405         for (i=0 ; i<4 ; i++)
1406         {
1407                 f = Face_Alloc();
1408                 f->texdef = *texdef;
1409                 f->texdef.flags &= ~SURF_KEEP;
1410                 f->texdef.contents &= ~CONTENTS_KEEP;
1411                 f->next = b->brush_faces;
1412                 b->brush_faces = f;
1413                 j = (i+1)%4;
1414
1415                 VectorCopy (pts[j][1], f->planepts[0]);
1416                 VectorCopy (pts[i][1], f->planepts[1]);
1417                 VectorCopy (pts[i][0], f->planepts[2]);
1418         }
1419
1420         f = Face_Alloc();
1421         f->texdef = *texdef;
1422         f->texdef.flags &= ~SURF_KEEP;
1423         f->texdef.contents &= ~CONTENTS_KEEP;
1424         f->next = b->brush_faces;
1425         b->brush_faces = f;
1426
1427         VectorCopy (pts[0][1], f->planepts[0]);
1428         VectorCopy (pts[1][1], f->planepts[1]);
1429         VectorCopy (pts[2][1], f->planepts[2]);
1430
1431         f = Face_Alloc();
1432         f->texdef = *texdef;
1433         f->texdef.flags &= ~SURF_KEEP;
1434         f->texdef.contents &= ~CONTENTS_KEEP;
1435         f->next = b->brush_faces;
1436         b->brush_faces = f;
1437
1438         VectorCopy (pts[2][0], f->planepts[0]);
1439         VectorCopy (pts[1][0], f->planepts[1]);
1440         VectorCopy (pts[0][0], f->planepts[2]);
1441
1442         return b;
1443 }
1444
1445 /*
1446 =============
1447 Brush_CreatePyramid
1448
1449 Create non-textured pyramid for light entities
1450 The brush is NOT linked to any list
1451 =============
1452 */
1453 brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef)
1454 {
1455   int i;
1456
1457         //++timo handle new brush primitive ? return here ??
1458         return Brush_Create(mins, maxs, texdef);
1459
1460         for (i=0 ; i<3 ; i++)
1461                 if (maxs[i] < mins[i])
1462                         Error ("Brush_InitSolid: backwards");
1463
1464         brush_t* b = Brush_Alloc();
1465
1466         vec3_t corners[4];
1467
1468         float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2)));
1469
1470         corners[0][0] = mins[0];
1471         corners[0][1] = mins[1];
1472         corners[0][2] = fMid;
1473
1474         corners[1][0] = mins[0];
1475         corners[1][1] = maxs[1];
1476         corners[1][2] = fMid;
1477
1478         corners[2][0] = maxs[0];
1479         corners[2][1] = maxs[1];
1480         corners[2][2] = fMid;
1481
1482         corners[3][0] = maxs[0];
1483         corners[3][1] = mins[1];
1484         corners[3][2] = fMid;
1485
1486         vec3_t top, bottom;
1487
1488         top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2));
1489         top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2));
1490         top[2] = Rad_rint(maxs[2]);
1491
1492         VectorCopy(top, bottom);
1493         bottom[2] = mins[2];
1494
1495         // sides
1496         for (i = 0; i < 4; i++)
1497         {
1498                 face_t* f = Face_Alloc();
1499                 f->texdef = *texdef;
1500                 f->texdef.flags &= ~SURF_KEEP;
1501                 f->texdef.contents &= ~CONTENTS_KEEP;
1502                 f->next = b->brush_faces;
1503                 b->brush_faces = f;
1504                 int j = (i+1)%4;
1505
1506                 VectorCopy (top, f->planepts[0]);
1507                 VectorCopy (corners[i], f->planepts[1]);
1508                 VectorCopy(corners[j], f->planepts[2]);
1509
1510                 f = Face_Alloc();
1511                 f->texdef = *texdef;
1512                 f->texdef.flags &= ~SURF_KEEP;
1513                 f->texdef.contents &= ~CONTENTS_KEEP;
1514                 f->next = b->brush_faces;
1515                 b->brush_faces = f;
1516
1517                 VectorCopy (bottom, f->planepts[2]);
1518                 VectorCopy (corners[i], f->planepts[1]);
1519                 VectorCopy(corners[j], f->planepts[0]);
1520         }
1521
1522         return b;
1523 }
1524
1525
1526
1527
1528 /*
1529 =============
1530 Brush_MakeSided
1531
1532 Makes the current brush have the given number of 2d sides
1533 =============
1534 */
1535 void Brush_MakeSided (int sides)
1536 {
1537         int             i, axis = 0;
1538         vec3_t  mins, maxs;
1539         brush_t *b;
1540         texdef_t        *texdef;
1541         face_t  *f;
1542         vec3_t  mid;
1543         float   width;
1544         float   sv, cv;
1545
1546         if (sides < 3)
1547         {
1548                 Sys_Status ("Bad sides number", 0);
1549                 return;
1550         }
1551
1552         if (sides >= MAX_POINTS_ON_WINDING-4)
1553         {
1554                 Sys_Printf("too many sides.\n");
1555                 return;
1556         }
1557
1558         if (!QE_SingleBrush ())
1559         {
1560                 Sys_Status ("Must have a single brush selected", 0 );
1561                 return;
1562         }
1563
1564         b = selected_brushes.next;
1565         VectorCopy (b->mins, mins);
1566         VectorCopy (b->maxs, maxs);
1567         texdef = &g_qeglobals.d_texturewin.texdef;
1568
1569         Brush_Free (b);
1570
1571         if (g_pParentWnd->ActiveXY())
1572         {
1573                 switch(g_pParentWnd->ActiveXY()->GetViewType())
1574                 {
1575                         case XY: axis = 2; break;
1576                         case XZ: axis = 1; break;
1577                         case YZ: axis = 0; break;
1578                 }
1579         }
1580         else
1581         {
1582                 axis = 2;
1583         }
1584
1585         // find center of brush
1586         width = 8;
1587         for (i = 0; i < 3; i++)
1588         {
1589                 mid[i] = (maxs[i] + mins[i]) * 0.5;
1590                 if (i == axis) continue;
1591                 if ((maxs[i] - mins[i]) * 0.5 > width)
1592                         width = (maxs[i] - mins[i]) * 0.5;
1593         }
1594
1595         b = Brush_Alloc();
1596
1597         // create top face
1598         f = Face_Alloc();
1599         f->texdef = *texdef;
1600         f->next = b->brush_faces;
1601         b->brush_faces = f;
1602
1603         f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis];
1604         f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis];
1605         f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis];
1606
1607         // create bottom face
1608         f = Face_Alloc();
1609         f->texdef = *texdef;
1610         f->next = b->brush_faces;
1611         b->brush_faces = f;
1612
1613         f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis];
1614         f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis];
1615         f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis];
1616
1617         for (i=0 ; i<sides ; i++)
1618         {
1619                 f = Face_Alloc();
1620                 f->texdef = *texdef;
1621                 f->next = b->brush_faces;
1622                 b->brush_faces = f;
1623
1624                 sv = sin (i*3.14159265*2/sides);
1625                 cv = cos (i*3.14159265*2/sides);
1626
1627                 f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5);
1628                 f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5);
1629                 f->planepts[0][axis] = mins[axis];
1630
1631                 f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3];
1632                 f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3];
1633                 f->planepts[1][axis] = maxs[axis];
1634
1635                 f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5);
1636                 f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5);
1637                 f->planepts[2][axis] = maxs[axis];
1638         }
1639
1640         Brush_AddToList (b, &selected_brushes);
1641
1642         Entity_LinkBrush (world_entity, b);
1643
1644         Brush_Build( b );
1645
1646         Sys_UpdateWindows (W_ALL);
1647 }
1648
1649
1650
1651 /*
1652 =============
1653 Brush_Free
1654
1655 Frees the brush with all of its faces and display list.
1656 Unlinks the brush from whichever chain it is in.
1657 Decrements the owner entity's brushcount.
1658 Removes owner entity if this was the last brush
1659 unless owner is the world.
1660 Removes from groups
1661 =============
1662 */
1663 void Brush_Free (brush_t *b, bool bRemoveNode)
1664 {
1665         face_t  *f, *next;
1666         epair_t *ep, *enext;
1667
1668         // remove from group
1669         if (bRemoveNode)
1670                 Group_RemoveBrush(b);
1671
1672         // free the patch if it's there
1673         if (b->patchBrush)
1674         {
1675                 Patch_Delete(b->pPatch);
1676         }
1677
1678         // free faces
1679         for (f=b->brush_faces ; f ; f=next)
1680         {
1681                 next = f->next;
1682                 Face_Free( f );
1683         }
1684
1685         // TTimo : free brush epairs
1686         for (ep = b->epairs ; ep ; ep=enext )
1687         {
1688                 enext = ep->next;
1689                 free (ep->key);
1690                 free (ep->value);
1691                 free (ep);
1692         }
1693
1694         // unlink from active/selected list
1695         if (b->next)
1696                 Brush_RemoveFromList (b);
1697
1698         // unlink from entity list
1699         if (b->onext)
1700                 Entity_UnlinkBrush (b);
1701
1702         free (b);
1703 }
1704
1705 /*
1706 =============
1707 Face_MemorySize
1708 =============
1709 */
1710 int Face_MemorySize(face_t *f )
1711 {
1712   int size = 0;
1713
1714   if (f->face_winding)
1715   {
1716 //    size += _msize(f->face_winding);
1717     size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int);
1718   }
1719 //  size += _msize(f);
1720   size += sizeof(face_t);
1721   return size;
1722 }
1723
1724 /*
1725 =============
1726 Brush_MemorySize
1727 =============
1728 */
1729 int Brush_MemorySize(brush_t *b)
1730 {
1731         face_t  *f;
1732         epair_t *ep;
1733         int size = 0;
1734
1735         //
1736         if (b->patchBrush)
1737         {
1738                 size += Patch_MemorySize(b->pPatch);
1739         }
1740         //
1741         for (f = b->brush_faces; f; f = f->next)
1742         {
1743                 size += Face_MemorySize(f);
1744         }
1745         //
1746         for (ep = b->epairs; ep; ep = ep->next )
1747         {
1748 //              size += _msize(ep->key);
1749     size += strlen(ep->key);
1750 //              size += _msize(ep->value);
1751     size += strlen(ep->value);
1752 //              size += _msize(ep);
1753     size += sizeof(epair_t);
1754         }
1755 //      size += _msize(b);
1756   size += sizeof(brush_t);
1757         return size;
1758 }
1759
1760
1761 /*
1762 ============
1763 Brush_Clone
1764
1765 Does NOT add the new brush to any lists
1766 ============
1767 */
1768 brush_t *Brush_Clone (brush_t *b)
1769 {
1770         brush_t *n = NULL;
1771         face_t  *f, *nf;
1772
1773         if (b->patchBrush)
1774         {
1775                 patchMesh_t *p = Patch_Duplicate(b->pPatch);
1776                 Brush_RemoveFromList(p->pSymbiot);
1777                 Entity_UnlinkBrush(p->pSymbiot);
1778                 n = p->pSymbiot;
1779         }
1780         else
1781         {
1782         n = Brush_Alloc();
1783           n->numberId = g_nBrushId++;
1784                 n->owner = b->owner;
1785                 for (f=b->brush_faces ; f ; f=f->next)
1786                 {
1787                         nf = Face_Clone( f );
1788                         nf->next = n->brush_faces;
1789                         n->brush_faces = nf;
1790                 }
1791         }
1792
1793         return n;
1794 }
1795
1796 /*
1797 ============
1798 Brush_Clone
1799
1800 Does NOT add the new brush to any lists
1801 ============
1802 */
1803 brush_t *Brush_FullClone(brush_t *b)
1804 {
1805         brush_t *n = NULL;
1806         face_t *f, *nf, *f2, *nf2;
1807         int j;
1808
1809         if (b->patchBrush)
1810         {
1811                 patchMesh_t *p = Patch_Duplicate(b->pPatch);
1812                 Brush_RemoveFromList(p->pSymbiot);
1813                 Entity_UnlinkBrush(p->pSymbiot);
1814                 n = p->pSymbiot;
1815                 n->owner = b->owner;
1816                 Brush_Build(n);
1817         }
1818         else
1819         {
1820         n = Brush_Alloc();
1821         n->numberId = g_nBrushId++;
1822                 n->owner = b->owner;
1823                 VectorCopy(b->mins, n->mins);
1824                 VectorCopy(b->maxs, n->maxs);
1825                 //
1826                 for (f = b->brush_faces; f; f = f->next)
1827                 {
1828                         if (f->original) continue;
1829                         nf = Face_FullClone(f);
1830                         nf->next = n->brush_faces;
1831                         n->brush_faces = nf;
1832                         //copy all faces that have the original set to this face
1833                         for (f2 = b->brush_faces; f2; f2 = f2->next)
1834                         {
1835                                 if (f2->original == f)
1836                                 {
1837                                         nf2 = Face_FullClone(f2);
1838                                         nf2->next = n->brush_faces;
1839                                         n->brush_faces = nf2;
1840                                         //set original
1841                                         nf2->original = nf;
1842                                 }
1843                         }
1844                 }
1845                 for (nf = n->brush_faces; nf; nf = nf->next)
1846                 {
1847                         Face_SetColor(n, nf, 1.0);
1848                         if (nf->face_winding)
1849       {
1850         if (g_qeglobals.m_bBrushPrimitMode)
1851                         EmitBrushPrimitTextureCoordinates(nf,nf->face_winding);
1852         else
1853         {
1854                                   for (j = 0; j < nf->face_winding->numpoints; j++)
1855                                         EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf);
1856         }
1857       }
1858                 }
1859   }
1860         return n;
1861 }
1862
1863  // FIXME - spog - finish this later..
1864  /*
1865 bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3)
1866 {
1867         int i;
1868         vec3_t v1, v2, normal[3];
1869         float d;
1870
1871         //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]);
1872         //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]);
1873         //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]);
1874         //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]);
1875
1876         // test ray against triangle
1877         // get triangle plane normal
1878         //VectorSubtract(p1, p2, v1);
1879         //VectorSubtract(p1, p3, v2);
1880         //CrossProduct(v1, v2, v1);
1881         // check normal against direction
1882         //if (DotProduct(dir, v1) >= 0)
1883         //{
1884                 // generate cone normals
1885                 VectorSubtract(origin, p1, v1);
1886                 VectorSubtract(origin, p2, v2);
1887                 CrossProduct(v1, v2, normal[0]);
1888                 VectorSubtract(origin, p2, v1);
1889                 VectorSubtract(origin, p3, v2);
1890                 CrossProduct(v1, v2, normal[1]);
1891                 VectorSubtract(origin, p3, v1);
1892                 VectorSubtract(origin, p1, v2);
1893                 CrossProduct(v1, v2, normal[2]);
1894         //}
1895         //else
1896         //{
1897                 // flip normals if triangle faces away
1898         //      Sys_Printf("flipped\n");
1899         //      VectorSubtract(origin, p1, v1);
1900         //      VectorSubtract(origin, p3, v2);
1901         //      CrossProduct(v1, v2, normal[0]);
1902         //      VectorSubtract(origin, p3, v1);
1903         //      VectorSubtract(origin, p2, v2);
1904         //      CrossProduct(v1, v2, normal[1]);
1905         //      VectorSubtract(origin, p2, v1);
1906         //      VectorSubtract(origin, p1, v2);
1907         //      CrossProduct(v1, v2, normal[2]);
1908         //}
1909
1910         for (i=0; i<3; i++)
1911         {
1912                 VectorNormalize(normal[i]);
1913                 //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]);
1914                 //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]);
1915                 d = DotProduct(dir, normal[i]);
1916                 //Sys_Printf("dotproduct: %f\n",d);
1917                 if (d < 0)
1918                         return false;
1919         }
1920         return true;
1921 }
1922 */
1923
1924 /*
1925 extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,
1926                  float vert0[3], float vert1[3], float vert2[3],
1927                  double *t, double *u, double *v);
1928
1929 bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v)
1930 {
1931   bool bIntersect = false;
1932   float tBest = FLT_MAX;
1933   int i, j;
1934   vec3_t xyz[3];
1935   vec3_t vRay[2];
1936
1937   float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set
1938
1939   VectorSubtract (origin, b->owner->origin, vRay[0]);
1940   VectorCopy (dir, vRay[1]);
1941
1942   if (angle > 0)
1943   {
1944     int i;
1945     float s, c;
1946     float x, y;
1947
1948     s = sin (-angle/180*Q_PI);
1949     c = cos (-angle/180*Q_PI);
1950
1951     for (i=0; i<2; i++)
1952     {
1953       x = vRay[i][0];
1954       y = vRay[i][1];
1955       vRay[i][0] = (x * c) - (y * s);
1956       vRay[i][1] = (x * s) + (y * c);
1957     }
1958   }
1959
1960   entitymodel *model = b->owner->md3Class->model;
1961
1962   while (model != NULL)
1963   {
1964     for (i = 0; i < model->nTriCount; i++)
1965     {
1966       for (j = 0; j < 3; j++)
1967         VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]);
1968
1969       if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v))
1970       {
1971         bIntersect = true;
1972         if (*t < tBest)
1973           tBest = *t;
1974       }
1975     }
1976     model = model->pNext;
1977   }
1978   if (bIntersect)
1979   {
1980     *t = tBest;
1981     return true;
1982   }
1983   else
1984   {
1985     *t = 0;
1986     return false;
1987   }
1988 }
1989 */
1990
1991 /*
1992 ==============
1993 Brush_Ray
1994
1995 Itersects a ray with a brush
1996 Returns the face hit and the distance along the ray the intersection occured at
1997 Returns NULL and 0 if not hit at all
1998 ==============
1999 */
2000 extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v);
2001 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags)
2002 {
2003         face_t  *f, *firstface = NULL;
2004         vec3_t  p1, p2;
2005         float   frac, d1, d2;
2006         int             i;
2007
2008         if (b->owner->eclass->fixedsize
2009     && b->owner->model.pSelect
2010     && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))
2011     && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)
2012         {
2013     ray_t ray_local;
2014     vec_t dist_local = FLT_MAX;
2015     ray_construct_for_vec3(&ray_local, origin, dir);
2016                 if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local))
2017     {
2018       *dist = dist_local;
2019       return b->brush_faces;
2020     }
2021     else
2022     {
2023       *dist = 0.0f;
2024       return NULL;
2025     }
2026         }
2027
2028   VectorCopy (origin, p1);
2029         for (i=0 ; i<3 ; i++)
2030                 p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord;
2031
2032         for (f=b->brush_faces ; f ; f=f->next)
2033         {
2034                 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2035                 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2036                 if (d1 >= 0 && d2 >= 0)
2037                 {
2038                         *dist = 0;
2039                         return NULL;    // ray is on front side of face
2040                 }
2041                 if (d1 <=0 && d2 <= 0)
2042                         continue;
2043                 // clip the ray to the plane
2044                 frac = d1 / (d1 - d2);
2045                 if (d1 > 0)
2046                 {
2047                         firstface = f;
2048                         for (i=0 ; i<3 ; i++)
2049                                 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
2050                 }
2051                 else
2052                 {
2053                         for (i=0 ; i<3 ; i++)
2054                                 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
2055                 }
2056         }
2057
2058         // find distance p1 is along dir
2059         VectorSubtract (p1, origin, p1);
2060         d1 = DotProduct (p1, dir);
2061
2062         *dist = d1;
2063
2064         // new test stuff for patches
2065         if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush)
2066         {
2067     double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are
2068                 if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v))
2069                 {
2070                         *dist = 0;
2071                         return NULL;
2072                 }
2073     else
2074     {
2075       *dist = (float)t;
2076       //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);
2077     }
2078         }
2079
2080   // IMPORTANT NOTE:
2081   // modifications to the discarding code here should be matched in the selection code
2082   // see Brush_Draw
2083
2084   // do some last minute filtering
2085   if (firstface && nFlags & SF_CAMERA)
2086   {
2087     if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
2088     {
2089       if (strstr(firstface->texdef.GetName(), "caulk"))
2090       {
2091         *dist = 0;
2092         return NULL;
2093       }
2094     }
2095     if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
2096     {
2097       if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster"))
2098       {
2099         *dist = 0;
2100         return NULL;
2101       }
2102     }
2103     if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
2104     {
2105       if (strstr(firstface->texdef.GetName(), "clip"))
2106       {
2107         *dist = 0;
2108         return NULL;
2109       }
2110     }
2111   }
2112
2113         return firstface;
2114 }
2115
2116 //PGM
2117 face_t *Brush_Point (vec3_t origin, brush_t *b)
2118 {
2119         face_t  *f;
2120         float   d1;
2121
2122         for (f=b->brush_faces ; f ; f=f->next)
2123         {
2124                 d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;
2125                 if (d1 > 0)
2126                 {
2127                         return NULL;    // point is on front side of face
2128                 }
2129         }
2130
2131         return b->brush_faces;
2132 }
2133 //PGM
2134
2135
2136 void    Brush_AddToList (brush_t *b, brush_t *blist)
2137 {
2138         if (b->next || b->prev)
2139                 Error ("Brush_AddToList: already linked");
2140
2141         if (blist == &selected_brushes || blist == &active_brushes)
2142         {
2143                 if (b->patchBrush && blist == &selected_brushes)
2144                 {
2145                         Patch_Select(b->pPatch);
2146                 }
2147         }
2148         b->next = blist->next;
2149         blist->next->prev = b;
2150         blist->next = b;
2151         b->prev = blist;
2152
2153         // TTimo messaging
2154         DispatchRadiantMsg( RADIANT_SELECTION );
2155 }
2156
2157 void    Brush_RemoveFromList (brush_t *b)
2158 {
2159         if (!b->next || !b->prev)
2160                 Error ("Brush_RemoveFromList: not linked");
2161
2162         if (b->patchBrush)
2163         {
2164                 Patch_Deselect(b->pPatch);
2165         }
2166         b->next->prev = b->prev;
2167         b->prev->next = b->next;
2168         b->next = b->prev = NULL;
2169 }
2170
2171 /*
2172 ===============
2173 SetFaceTexdef
2174
2175 Doesn't set the curve flags
2176
2177 NOTE : ( TTimo )
2178         never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2179         use Texture_ForName() to find the right shader
2180         FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2181
2182 TTimo: surface plugin, added an IPluginTexdef* parameter
2183                 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2184                 if NULL, ask for a default
2185
2186  TTimo - shader code cleanup
2187    added IShader* parameter
2188   ===============
2189 */
2190 void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2191         int             oldFlags;
2192         int             oldContents;
2193         face_t  *tf;
2194
2195         oldFlags = f->texdef.flags;
2196         oldContents = f->texdef.contents;
2197         if (g_qeglobals.m_bBrushPrimitMode)
2198         {
2199                 f->texdef = *texdef;
2200                 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2201         }
2202         else
2203                 if (bFitScale)
2204                 {
2205                         f->texdef = *texdef;
2206                         // fit the scaling of the texture on the actual plane
2207                         vec3_t p1,p2,p3; // absolute coordinates
2208                         // compute absolute coordinates
2209                         ComputeAbsolute(f,p1,p2,p3);
2210                         // compute the scale
2211                         vec3_t vx,vy;
2212                         VectorSubtract(p2,p1,vx);
2213                         VectorNormalize(vx, vx);
2214                         VectorSubtract(p3,p1,vy);
2215                         VectorNormalize(vy, vy);
2216                         // assign scale
2217                         VectorScale(vx,texdef->scale[0],vx);
2218                         VectorScale(vy,texdef->scale[1],vy);
2219                         VectorAdd(p1,vx,p2);
2220                         VectorAdd(p1,vy,p3);
2221                         // compute back shift scale rot
2222                         AbsoluteToLocal(f->plane,f,p1,p2,p3);
2223                 }
2224                 else
2225                         f->texdef = *texdef;
2226         f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2227         f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2228
2229         // if this is a curve face, set all other curve faces to the same texdef
2230         if (f->texdef.flags & SURF_CURVE)
2231         {
2232                 for (tf = b->brush_faces ; tf ; tf = tf->next)
2233                 {
2234                         if (tf->texdef.flags & SURF_CURVE)
2235                                 tf->texdef = f->texdef;
2236                 }
2237         }
2238 }
2239
2240 /*
2241 ===============
2242 SetFaceTexdef
2243
2244 Doesn't set the curve flags
2245
2246 NOTE : ( TTimo )
2247         never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2248         use Texture_ForName() to find the right shader
2249         FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2250
2251  TTimo: surface plugin, added an IPluginTexdef* parameter
2252                 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2253                 if NULL, ask for a default
2254 ===============
2255 */
2256 void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2257         int             oldFlags;
2258         int             oldContents;
2259
2260         oldFlags = f->texdef.flags;
2261         oldContents = f->texdef.contents;
2262
2263   if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build
2264     Face_SetShader(f, texdef->GetName());
2265
2266         if (g_qeglobals.m_bBrushPrimitMode)
2267         {
2268                 f->texdef = *texdef;
2269                 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2270         }
2271         else
2272   {
2273                 if (bFitScale)
2274                 {
2275                         f->texdef = *texdef;
2276                         // fit the scaling of the texture on the actual plane
2277                         vec3_t p1,p2,p3; // absolute coordinates
2278                         // compute absolute coordinates
2279                         ComputeAbsolute(f,p1,p2,p3);
2280                         // compute the scale
2281                         vec3_t vx,vy;
2282                         VectorSubtract(p2,p1,vx);
2283                         VectorNormalize(vx, vx);
2284                         VectorSubtract(p3,p1,vy);
2285                         VectorNormalize(vy, vy);
2286                         // assign scale
2287                         VectorScale(vx,texdef->scale[0],vx);
2288                         VectorScale(vy,texdef->scale[1],vy);
2289                         VectorAdd(p1,vx,p2);
2290                         VectorAdd(p1,vy,p3);
2291                         // compute back shift scale rot
2292                         AbsoluteToLocal(f->plane,f,p1,p2,p3);
2293                 }
2294                 else
2295     {
2296                         f->texdef = *texdef;
2297     }
2298   }
2299         f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2300         f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2301 }
2302
2303 #ifdef _DEBUG
2304 void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2305 {
2306         for (face_t* f = b->brush_faces ; f ; f = f->next)
2307                 SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef);
2308         Brush_Build( b );
2309         if (b->patchBrush)
2310         {
2311                 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2312                 b->bFiltered = FilterBrush( b );
2313         }
2314 }
2315 #endif
2316
2317 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2318 {
2319         for (face_t* f = b->brush_faces ; f ; f = f->next)
2320                 SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef);
2321         Brush_Build( b );
2322         if (b->patchBrush)
2323         {
2324                 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2325                 b->bFiltered = FilterBrush( b );
2326         }
2327 }
2328
2329
2330 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
2331 {
2332         float   d1, d2, fr;
2333         int             i;
2334         float   *v;
2335
2336         d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2337         d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2338
2339         if (d1 >= 0 && d2 >= 0)
2340                 return false;           // totally outside
2341         if (d1 <= 0 && d2 <= 0)
2342                 return true;            // totally inside
2343
2344         fr = d1 / (d1 - d2);
2345
2346         if (d1 > 0)
2347                 v = p1;
2348         else
2349                 v = p2;
2350
2351         for (i=0 ; i<3 ; i++)
2352                 v[i] = p1[i] + fr*(p2[i] - p1[i]);
2353
2354         return true;
2355 }
2356
2357
2358 int AddPlanept (float *f)
2359 {
2360         int             i;
2361
2362         for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
2363                 if (g_qeglobals.d_move_points[i] == f)
2364                         return 0;
2365         g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2366         return 1;
2367 }
2368
2369 /*
2370 ==============
2371 Brush_SelectFaceForDragging
2372
2373 Adds the faces planepts to move_points, and
2374 rotates and adds the planepts of adjacent face if shear is set
2375 ==============
2376 */
2377 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
2378 {
2379         int             i;
2380         face_t  *f2;
2381         winding_t       *w;
2382         float   d;
2383         brush_t *b2;
2384         int             c;
2385
2386         if (b->owner->eclass->fixedsize)
2387                 return;
2388
2389         c = 0;
2390         for (i=0 ; i<3 ; i++)
2391                 c += AddPlanept (f->planepts[i]);
2392         if (c == 0)
2393                 return;         // already completely added
2394
2395         // select all points on this plane in all brushes the selection
2396         for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
2397         {
2398                 if (b2 == b)
2399                         continue;
2400                 for (f2=b2->brush_faces ; f2 ; f2=f2->next)
2401                 {
2402                         for (i=0 ; i<3 ; i++)
2403                                 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
2404                                 -f->plane.dist) > ON_EPSILON)
2405                                         break;
2406                         if (i==3)
2407                         {       // move this face as well
2408                                 Brush_SelectFaceForDragging (b2, f2, shear);
2409                                 break;
2410                         }
2411                 }
2412         }
2413
2414
2415         // if shearing, take all the planes adjacent to
2416         // selected faces and rotate their points so the
2417         // edge clipped by a selcted face has two of the points
2418         if (!shear)
2419                 return;
2420
2421         for (f2=b->brush_faces ; f2 ; f2=f2->next)
2422         {
2423                 if (f2 == f)
2424                         continue;
2425                 w = Brush_MakeFaceWinding (b, f2);
2426                 if (!w)
2427                         continue;
2428
2429                 // any points on f will become new control points
2430                 for (i=0 ; i<w->numpoints ; i++)
2431                 {
2432                         d = DotProduct (w->points[i], f->plane.normal)
2433                                 - f->plane.dist;
2434                         if (d > -ON_EPSILON && d < ON_EPSILON)
2435                                 break;
2436                 }
2437
2438                 //
2439                 // if none of the points were on the plane,
2440                 // leave it alone
2441                 //
2442                 if (i != w->numpoints)
2443                 {
2444                         if (i == 0)
2445                         {       // see if the first clockwise point was the
2446                                 // last point on the winding
2447                                 d = DotProduct (w->points[w->numpoints-1]
2448                                         , f->plane.normal) - f->plane.dist;
2449                                 if (d > -ON_EPSILON && d < ON_EPSILON)
2450                                         i = w->numpoints - 1;
2451                         }
2452
2453                         AddPlanept (f2->planepts[0]);
2454
2455                         VectorCopy (w->points[i], f2->planepts[0]);
2456                         if (++i == w->numpoints)
2457                                 i = 0;
2458
2459                         // see if the next point is also on the plane
2460                         d = DotProduct (w->points[i]
2461                                 , f->plane.normal) - f->plane.dist;
2462                         if (d > -ON_EPSILON && d < ON_EPSILON)
2463                                 AddPlanept (f2->planepts[1]);
2464
2465                         VectorCopy (w->points[i], f2->planepts[1]);
2466                         if (++i == w->numpoints)
2467                                 i = 0;
2468
2469                         // the third point is never on the plane
2470
2471                         VectorCopy (w->points[i], f2->planepts[2]);
2472                 }
2473
2474                 free(w);
2475         }
2476 }
2477
2478 /*
2479 ==============
2480 Brush_SideSelect
2481
2482 The mouse click did not hit the brush, so grab one or more side
2483 planes for dragging
2484 ==============
2485 */
2486 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
2487                                            , qboolean shear)
2488 {
2489         face_t  *f, *f2;
2490         vec3_t  p1, p2;
2491
2492         for (f=b->brush_faces ; f ; f=f->next)
2493         {
2494                 VectorCopy (origin, p1);
2495                 VectorMA (origin, 2*g_MaxWorldCoord, dir, p2);
2496
2497                 for (f2=b->brush_faces ; f2 ; f2=f2->next)
2498                 {
2499                         if (f2 == f)
2500                                 continue;
2501                         ClipLineToFace (p1, p2, f2);
2502                 }
2503
2504                 if (f2)
2505                         continue;
2506
2507                 if (VectorCompare (p1, origin))
2508                         continue;
2509                 if (ClipLineToFace (p1, p2, f))
2510                         continue;
2511
2512                 Brush_SelectFaceForDragging (b, f, shear);
2513         }
2514 }
2515
2516 bool g_bBuildWindingsNoTexBuild = false;
2517
2518 void Brush_SetBuildWindingsNoTexBuild(bool bBuild)
2519 {
2520   g_bBuildWindingsNoTexBuild = bBuild;
2521 }
2522
2523 // TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary
2524 //    saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases
2525 //    ie when we want to update a shader
2526 //    default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild
2527 void Brush_BuildWindings( brush_t *b, bool bSnap )
2528 {
2529         winding_t *w;
2530         face_t    *face;
2531         vec_t      v;
2532
2533         if (bSnap)
2534                 Brush_SnapPlanepts( b );
2535
2536         // clear the mins/maxs bounds
2537         b->mins[0] = b->mins[1] = b->mins[2] = 99999;
2538         b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
2539
2540         Brush_MakeFacePlanes (b);
2541
2542         face = b->brush_faces;
2543
2544         float fCurveColor = 1.0;
2545
2546         for ( ; face ; face=face->next)
2547         {
2548                 int i, j;
2549                 free(face->face_winding);
2550                 w = face->face_winding = Brush_MakeFaceWinding (b, face);
2551
2552     if (!g_bBuildWindingsNoTexBuild || !face->d_texture)
2553     {
2554 #ifdef _DEBUG
2555       // if there's no d_texture, then we expect pShader to be empty
2556       if (!face->d_texture && face->pShader)
2557         Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n");
2558 #endif
2559       if ((!face->d_texture && !face->pShader) || !face->pShader)
2560       {
2561         // NOTE TTimo
2562         // patch 84 for bug 253 doesn't dec ref the potential face->pShader
2563         // add a debug check to make sure this is actually not necessary
2564 #ifdef _DEBUG
2565         if (face->pShader)
2566         {
2567           Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n");
2568         }
2569 #endif
2570         face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );
2571         face->pShader->IncRef();
2572         face->d_texture = face->pShader->getTexture();
2573       }
2574     }
2575
2576                 if (!w)
2577                         continue;
2578
2579                 for (i=0 ; i<w->numpoints ; i++)
2580                 {
2581                         // add to bounding box
2582                         for (j=0 ; j<3 ; j++)
2583                         {
2584                                 v = w->points[i][j];
2585                                 if (v > b->maxs[j])
2586                                         b->maxs[j] = v;
2587                                 if (v < b->mins[j])
2588                                         b->mins[j] = v;
2589                         }
2590                 }
2591                 Face_SetColor (b, face, fCurveColor);
2592
2593                 fCurveColor -= .10f;
2594                 if (fCurveColor <= 0)
2595                         fCurveColor = 1.0f;
2596
2597                 // computing ST coordinates for the windings
2598                 if (g_qeglobals.m_bBrushPrimitMode)
2599                 {
2600                         if (g_qeglobals.bNeedConvert)
2601                         {
2602                                 // we have parsed old brushes format and need conversion
2603                                 // convert old brush texture representation to new format
2604                                 FaceToBrushPrimitFace(face);
2605 #ifdef _DEBUG
2606                                 // use old texture coordinates code to check against
2607                             for (i=0 ; i<w->numpoints ; i++)
2608                                         EmitTextureCoordinates( w->points[i], face->d_texture, face);
2609 #endif
2610                         }
2611                         // use new texture representation to compute texture coordinates
2612                         // in debug mode we will check against old code and warn if there are differences
2613                         EmitBrushPrimitTextureCoordinates(face,w);
2614                 }
2615                 else
2616                 {
2617       if (g_qeglobals.bNeedConvert)
2618       {
2619         BrushPrimitFaceToFace(face);
2620 /*
2621         // we have parsed brush primitives and need conversion back to standard format
2622         // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
2623                                 // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
2624                                 // I tried various tweaks, no luck .. seems shifting is lost
2625         brushprimit_texdef_t aux;
2626         ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
2627         TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
2628                                 face->texdef.scale[0]/=2.0;
2629                                 face->texdef.scale[1]/=2.0;
2630 */
2631       }
2632                     for (i=0 ; i<w->numpoints ; i++)
2633                                 EmitTextureCoordinates( w->points[i], face->d_texture, face);
2634                 }
2635         }
2636 }
2637
2638 /*
2639 ==================
2640 Brush_RemoveEmptyFaces
2641
2642 Frees any overconstraining faces
2643 ==================
2644 */
2645 void Brush_RemoveEmptyFaces ( brush_t *b )
2646 {
2647         face_t  *f, *next;
2648
2649         f = b->brush_faces;
2650         b->brush_faces = NULL;
2651
2652         for ( ; f ; f=next)
2653         {
2654                 next = f->next;
2655                 if (!f->face_winding)
2656                         Face_Free (f);
2657                 else
2658                 {
2659                         f->next = b->brush_faces;
2660                         b->brush_faces = f;
2661                 }
2662
2663         }
2664 }
2665
2666 void Brush_SnapToGrid(brush_t *pb)
2667 {
2668         face_t *f;
2669         vec3_t temp;
2670         vec3_t diff[2];
2671         int mult[3];
2672         int i, j, n;
2673         // TTimo: some brushes are "special" and should not be snapped
2674         // specially fixed-size entity ones
2675         if (pb->owner->eclass->fixedsize)
2676         {
2677                 // save current origin
2678                 VectorCopy (pb->owner->origin, temp);
2679                 // snap the origin
2680                 VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize);
2681                 // return if amount is zero
2682                 if (VectorCompare (pb->owner->origin, temp))
2683                         return;
2684                 // transform brush faces same amount
2685                 VectorSubtract (pb->owner->origin, temp, temp);
2686                 for (f = pb->brush_faces; f; f = f->next)
2687                 {
2688                         for (i=0 ; i<3 ; i++)
2689                                 VectorAdd (f->planepts[i], temp, f->planepts[i]);
2690                 }
2691         }
2692         else
2693         {
2694                 for (f = pb->brush_faces ; f; f = f->next)
2695                 {
2696                         for (j=0; j<2; j++)
2697                         {
2698                                 // spog - move planepts apart just far enough to avoid snapping two together
2699                                 VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]);
2700                                 for (i=0; i<3; i++)
2701                                 {
2702                                         if (diff[j][i] == 0.0f)
2703                                                 mult[i] = 2; // next value up from 1
2704                                         else  // multiplier = gridsize / component difference, rounded up
2705                                                 mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i]));
2706                                 }
2707
2708                                 if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1
2709                                 {
2710                                         n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2;
2711                                         for (i=0; i<3; i++)
2712                                                 diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component
2713                                 }
2714                                 VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]);
2715                         }
2716
2717                         for (i=0; i<3; i++)
2718                                 VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize);
2719
2720                 }
2721         }
2722         Brush_Build(pb,true,true,false,false); // don't filter
2723 }
2724
2725 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)
2726 {
2727         for (face_t* f=b->brush_faces ; f ; f=f->next)
2728         {
2729                 for (int i=0 ; i<3 ; i++)
2730                 {
2731                         VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]);
2732                 }
2733         }
2734         if (bBuild)
2735         {
2736                 Brush_Build(b,false,false,false,false); // don't filter
2737         }
2738 }
2739
2740 void Brush_Center(brush_t *b, vec3_t vNewCenter)
2741 {
2742   vec3_t vMid;
2743   // get center of the brush
2744   for (int j = 0; j < 3; j++)
2745   {
2746     vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5);
2747   }
2748   // calc distance between centers
2749   VectorSubtract(vNewCenter, vMid, vMid);
2750   Brush_Move(b, vMid, true);
2751
2752 }
2753
2754 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)
2755 {
2756   face_t *f;
2757   texdef_t texdef;
2758   int i;
2759   short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
2760
2761   for (i=0 ; i<3 ; i++)
2762                 if (vMax[i] < vMin[i])
2763                         Error ("Brush_Resize: invalid input");
2764
2765   if(b->brush_faces != NULL)
2766     texdef = b->brush_faces->texdef;
2767   else
2768     texdef = g_qeglobals.d_texturewin.texdef;
2769
2770   while (b->brush_faces != NULL)
2771   {
2772     f = b->brush_faces->next;
2773     Face_Free(b->brush_faces);
2774     b->brush_faces = f;
2775   }
2776
2777   for(i=0; i<3; i++)
2778   {
2779     f = b->brush_faces;
2780     b->brush_faces = Face_Alloc();
2781     b->brush_faces->next = f;
2782     f = b->brush_faces;
2783     f->texdef = texdef;
2784     VectorCopy(vMax, f->planepts[0]);
2785     VectorCopy(vMax, f->planepts[1]);
2786     VectorCopy(vMax, f->planepts[2]);
2787     f->planepts[2][box[i][0]] = vMin[box[i][0]];
2788     f->planepts[1][box[i][1]] = vMin[box[i][1]];
2789   }
2790   for(i=0; i<3; i++)
2791   {
2792     f = b->brush_faces;
2793     b->brush_faces = Face_Alloc();
2794     b->brush_faces->next = f;
2795     f = b->brush_faces;
2796     f->texdef = texdef;
2797     VectorCopy(vMin, f->planepts[0]);
2798     VectorCopy(vMin, f->planepts[1]);
2799     VectorCopy(vMin, f->planepts[2]);
2800     f->planepts[1][box[i][0]] = vMax[box[i][0]];
2801     f->planepts[2][box[i][1]] = vMax[box[i][1]];
2802   }
2803 }
2804
2805 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)
2806 {
2807         int                     angleVal;
2808         vec3_t          angles;
2809
2810         angleVal = IntForKey(e, "angle");
2811         if (angleVal == -1)                             // up
2812         {
2813                 VectorSet(angles, 270, 0, 0);
2814         }
2815         else if(angleVal == -2)         // down
2816         {
2817                 VectorSet(angles, 90, 0, 0);
2818         }
2819         else
2820         {
2821                 VectorSet(angles, 0, angleVal, 0);
2822         }
2823
2824         AngleVectors(angles, forward, right, up);
2825 }
2826
2827 void Brush_DrawFacingAngle (brush_t *b, entity_t *e)
2828 {
2829         vec3_t  forward, right, up;
2830         vec3_t  endpoint, tip1, tip2;
2831         vec3_t  start;
2832         float   dist;
2833
2834         VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
2835         VectorScale(start, 0.5, start);
2836         dist = (b->maxs[0] - start[0]) * 2.5;
2837
2838         FacingVectors (e, forward, right, up);
2839         VectorMA (start, dist, forward, endpoint);
2840
2841         dist = (b->maxs[0] - start[0]) * 0.5;
2842         VectorMA (endpoint, -dist, forward, tip1);
2843         VectorMA (tip1, -dist, up, tip1);
2844         VectorMA (tip1, 2*dist, up, tip2);
2845
2846         qglColor4f (1, 1, 1, 1);
2847         qglLineWidth (4);
2848         qglBegin (GL_LINES);
2849         qglVertex3fv (start);
2850         qglVertex3fv (endpoint);
2851         qglVertex3fv (endpoint);
2852         qglVertex3fv (tip1);
2853         qglVertex3fv (endpoint);
2854         qglVertex3fv (tip2);
2855         qglEnd ();
2856         qglLineWidth (1);
2857 }
2858
2859 void Brush_FaceDraw(face_t *face, int nGLState)
2860 {
2861         const winding_t *w = face->face_winding;
2862   if (w == NULL) return;
2863   if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting)
2864                 qglNormal3fv(face->plane.normal);
2865   /*
2866         if (mode & DRAW_GL_TEXTURE_2D)
2867                 qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);
2868         qglVertexPointer(3, GL_FLOAT, 5, w->points);
2869
2870         if (mode & DRAW_GL_FILL)
2871                 qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);
2872         else
2873                 qglDrawArrays(GL_POLYGON, 0, w->numpoints);
2874   */
2875
2876   if (nGLState & DRAW_GL_FILL)
2877     qglBegin(GL_TRIANGLE_FAN);
2878   else
2879     qglBegin(GL_POLYGON);
2880
2881         for (int i=0 ; i<w->numpoints ; i++)
2882         {
2883                 if (nGLState & DRAW_GL_TEXTURE_2D)
2884                         qglTexCoord2fv( &w->points[i][3] );
2885                 qglVertex3fv(w->points[i]);
2886         }
2887         qglEnd();
2888 }
2889
2890 #define Q2_SURF_TRANS33   0x00000010
2891 #define Q2_SURF_TRANS66   0x00000020
2892
2893 void Brush_Draw(brush_t *b)
2894 {
2895         face_t                  *face;
2896         int                             order;
2897         qtexture_t              *prev = 0;
2898         winding_t *w;
2899
2900         int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;
2901   int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;
2902
2903         GLfloat material[4], identity[4];
2904         VectorSet(identity, 0.8f, 0.8f, 0.8f);
2905         IShader *pShader;
2906         qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
2907         qglDisableClientState(GL_NORMAL_ARRAY);
2908
2909   // guarantee the texture will be set first
2910   bool bTrans;
2911         float transVal;
2912         prev = NULL;
2913         for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
2914         {
2915                 w = face->face_winding;
2916                 if (!w)
2917                 {
2918                         continue;               // freed face
2919                 }
2920
2921                 bTrans = (face->pShader->getFlags() & QER_TRANS);
2922                 transVal = face->pShader->getTrans();
2923                 // try to read the texture def surface flags to get trans
2924                 if (!bTrans) {
2925                         if (face->texdef.flags & Q2_SURF_TRANS33) {
2926                                 bTrans = true;
2927                                 transVal = 0.33;
2928                         } else if (face->texdef.flags & Q2_SURF_TRANS66) {
2929                                 bTrans = true;
2930                                 transVal = 0.66;
2931                         }
2932                 }
2933
2934           if (bTrans && !(nGLState & DRAW_GL_BLEND))
2935       continue;
2936     if (!bTrans && nGLState & DRAW_GL_BLEND)
2937       continue;
2938
2939                 // IMPORTANT NOTE:
2940                 // modifications to the discarding code here should be matched in the selection code
2941                 // see Brush_Ray
2942
2943                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
2944                 {
2945                         if (strstr(face->texdef.GetName(), "caulk"))
2946                                 continue;
2947                 }
2948
2949                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
2950                 {
2951                         if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster"))
2952                                 continue;
2953                 }
2954
2955                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
2956                 {
2957                         if (strstr(face->texdef.GetName(), "clip"))
2958                                 continue;
2959     }
2960
2961     if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(')
2962     {
2963       prev = NULL;
2964       qglDisable(GL_TEXTURE_2D);
2965     }
2966     else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)
2967     {
2968       // set the texture for this face
2969       prev = face->d_texture;
2970       qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
2971     }
2972
2973     if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting)
2974     {
2975       if (!b->owner->eclass->fixedsize)
2976         material[3] = transVal;
2977       else
2978         material[3] = 1;
2979       VectorCopy(face->d_color, material);
2980
2981                         if (nGLState & DRAW_GL_TEXTURE_2D)
2982         qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]);
2983                         else
2984         qglColor4fv(material);
2985     }
2986     else if (!b->owner->eclass->fixedsize)
2987                 {
2988                         pShader = face->pShader;
2989                         VectorCopy(pShader->getTexture()->color, material);
2990                         material[3] = identity[3] = transVal;
2991
2992                         if (nGLState & DRAW_GL_TEXTURE_2D)
2993         qglColor4fv(identity);
2994                         else
2995         qglColor4fv(material);
2996                 }
2997
2998                 // draw the polygon
2999
3000                 Brush_FaceDraw(face, nGLState);
3001         }
3002         qglPopClientAttrib();
3003 }
3004
3005 void Face_Draw( face_t *f )
3006 {
3007         int i;
3008
3009         if ( f->face_winding == 0 )
3010                 return;
3011         qglBegin(GL_POLYGON);
3012         for ( i = 0 ; i < f->face_winding->numpoints; i++)
3013                 qglVertex3fv( f->face_winding->points[i] );
3014         qglEnd();
3015 }
3016
3017 entity_t *FindEntity(const char *pszKey, const char *pszValue)
3018 {
3019         entity_t *pe;
3020
3021         pe = entities.next;
3022
3023         for (; pe != NULL && pe != &entities ; pe = pe->next)
3024         {
3025                 if (!strcmp(ValueForKey(pe, pszKey), pszValue))
3026                         return pe;
3027         }
3028
3029         return NULL;
3030 }
3031
3032 void Brush_DrawXY(brush_t *b, int nViewType)
3033 {
3034         face_t *face;
3035         int     order;
3036         winding_t *w;
3037         int        i;
3038
3039   if (b->patchBrush)
3040   {
3041     Patch_DrawXY(b->pPatch);
3042     if (!g_bPatchShowBounds)
3043       return;
3044   }
3045
3046   if (b->owner->eclass->fixedsize)
3047   {
3048     if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))
3049     {
3050 #if 1 // requires vertex arrays enabled
3051       DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType);
3052 #else
3053       vec3_t vCorners[4];
3054       float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
3055
3056       vCorners[0][0] = b->mins[0];
3057       vCorners[0][1] = b->mins[1];
3058       vCorners[0][2] = fMid;
3059
3060       vCorners[1][0] = b->mins[0];
3061       vCorners[1][1] = b->maxs[1];
3062       vCorners[1][2] = fMid;
3063
3064       vCorners[2][0] = b->maxs[0];
3065       vCorners[2][1] = b->maxs[1];
3066       vCorners[2][2] = fMid;
3067
3068       vCorners[3][0] = b->maxs[0];
3069       vCorners[3][1] = b->mins[1];
3070       vCorners[3][2] = fMid;
3071
3072       vec3_t vTop, vBottom;
3073
3074       vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
3075       vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
3076       vTop[2] = b->maxs[2];
3077
3078       VectorCopy(vTop, vBottom);
3079       vBottom[2] = b->mins[2];
3080
3081       qglBegin(GL_LINES);
3082       qglVertex3fv(vTop);
3083       qglVertex3fv(vCorners[0]);
3084       qglVertex3fv(vTop);
3085       qglVertex3fv(vCorners[1]);
3086       qglVertex3fv(vTop);
3087       qglVertex3fv(vCorners[2]);
3088       qglVertex3fv(vTop);
3089       qglVertex3fv(vCorners[3]);
3090       qglEnd();
3091
3092       qglBegin(GL_LINES);
3093       qglVertex3fv(vBottom);
3094       qglVertex3fv(vCorners[0]);
3095       qglVertex3fv(vBottom);
3096       qglVertex3fv(vCorners[1]);
3097       qglVertex3fv(vBottom);
3098       qglVertex3fv(vCorners[2]);
3099       qglVertex3fv(vBottom);
3100       qglVertex3fv(vCorners[3]);
3101       qglEnd();
3102
3103       qglBegin(GL_LINE_LOOP);
3104       qglVertex3fv(vCorners[0]);
3105       qglVertex3fv(vCorners[1]);
3106       qglVertex3fv(vCorners[2]);
3107       qglVertex3fv(vCorners[3]);
3108       qglEnd();
3109 #endif
3110       DrawBrushEntityName (b);
3111       return;
3112     }
3113     else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)))
3114     {
3115       qglPushAttrib(GL_CURRENT_BIT); // save brush colour
3116       qglColor3fv(b->owner->eclass->color);
3117       if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX )
3118         b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY);
3119       aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
3120       qglPopAttrib();
3121       return;
3122     }
3123     //}
3124   }
3125
3126         for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
3127         {
3128                 // moved so check occurs earlier
3129                 w = face->face_winding;
3130                 if (!w)
3131                         continue;
3132                 // only draw polygons facing in a direction we care about
3133     if (nViewType == XY)
3134     {
3135                   if (face->plane.normal[2] <= 0)
3136                           continue;
3137     }
3138     else
3139     {
3140       if (nViewType == XZ)
3141       {
3142         if (face->plane.normal[1] >= 0) // stop axes being mirrored
3143           continue;
3144       }
3145       else
3146       {
3147         if (face->plane.normal[0] <= 0)
3148           continue;
3149       }
3150     }
3151
3152                 // draw the polygon
3153                 qglBegin(GL_LINE_LOOP);
3154     for (i=0 ; i<w->numpoints ; i++)
3155                   qglVertex3fv(w->points[i]);
3156                 qglEnd();
3157         }
3158
3159         DrawBrushEntityName (b);
3160
3161 }
3162
3163 /*
3164 ============
3165 Brush_Move
3166 ============
3167 */
3168 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)
3169 {
3170   int i;
3171   face_t *f;
3172
3173   for (f=b->brush_faces ; f ; f=f->next)
3174     for (i=0 ; i<3 ; i++)
3175       VectorAdd (f->planepts[i], move, f->planepts[i]);
3176
3177   if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize)
3178   {
3179     for (f=b->brush_faces ; f ; f=f->next)
3180     {
3181       vec3_t vTemp;
3182       VectorCopy(move, vTemp);
3183       Face_MoveTexture(f, vTemp);
3184     }
3185   }
3186
3187   Brush_Build( b, bSnap,true,false,false); // don't filter
3188
3189
3190   if (b->patchBrush)
3191   {
3192     //Patch_Move(b->nPatchID, move);
3193     Patch_Move(b->pPatch, move);
3194   }
3195
3196
3197   // PGM - keep the origin vector up to date on fixed size entities.
3198   if(b->owner->eclass->fixedsize)
3199   {
3200     char text[64];
3201     VectorAdd(b->owner->origin, move, b->owner->origin);
3202     sprintf (text, "%i %i %i",
3203       (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
3204     SetKeyValue(b->owner, "origin", text);
3205           //VectorAdd(b->maxs, b->mins, b->owner->origin);
3206           //VectorScale(b->owner->origin, 0.5, b->owner->origin);
3207   }
3208 }
3209
3210
3211
3212 void Brush_Print(brush_t* b)
3213 {
3214   int nFace = 0;
3215   for (face_t* f = b->brush_faces ; f ; f=f->next)
3216   {
3217     Sys_Printf("Face %i\n", nFace++);
3218     Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
3219     Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
3220     Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
3221   }
3222  }
3223
3224
3225
3226 /*
3227 =============
3228 Brush_MakeSided
3229
3230 Makes the current brushhave the given number of 2d sides and turns it into a cone
3231 =============
3232 */
3233 void Brush_MakeSidedCone(int sides)
3234 {
3235         int             i;
3236         vec3_t  mins, maxs;
3237         brush_t *b;
3238         texdef_t        *texdef;
3239         face_t  *f;
3240         vec3_t  mid;
3241         float   width;
3242         float   sv, cv;
3243
3244         if (sides < 3 || sides > 32)
3245         {
3246                 Sys_Status ("Bad sides number", 0);
3247                 return;
3248         }
3249
3250         if (!QE_SingleBrush ())
3251         {
3252                 Sys_Status ("Must have a single brush selected", 0 );
3253                 return;
3254         }
3255
3256         b = selected_brushes.next;
3257         VectorCopy (b->mins, mins);
3258         VectorCopy (b->maxs, maxs);
3259         texdef = &g_qeglobals.d_texturewin.texdef;
3260
3261         Brush_Free (b);
3262
3263         // find center of brush
3264         width = 8;
3265         for (i=0 ; i<2 ; i++)
3266         {
3267                 mid[i] = (maxs[i] + mins[i])*0.5;
3268                 if (maxs[i] - mins[i] > width)
3269                         width = maxs[i] - mins[i];
3270         }
3271         width /= 2;
3272
3273         b = Brush_Alloc();
3274
3275         // create bottom face
3276         f = Face_Alloc();
3277         f->texdef = *texdef;
3278         f->next = b->brush_faces;
3279         b->brush_faces = f;
3280
3281         f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
3282         f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
3283         f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
3284
3285         for (i=0 ; i<sides ; i++)
3286         {
3287                 f = Face_Alloc();
3288                 f->texdef = *texdef;
3289                 f->next = b->brush_faces;
3290                 b->brush_faces = f;
3291
3292                 sv = sin (i*3.14159265*2/sides);
3293                 cv = cos (i*3.14159265*2/sides);
3294
3295
3296                 f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
3297                 f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
3298                 f->planepts[0][2] = mins[2];
3299
3300                 f->planepts[1][0] = mid[0];
3301                 f->planepts[1][1] = mid[1];
3302                 f->planepts[1][2] = maxs[2];
3303
3304                 f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);
3305                 f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);
3306                 f->planepts[2][2] = maxs[2];
3307
3308         }
3309
3310         Brush_AddToList (b, &selected_brushes);
3311
3312         Entity_LinkBrush (world_entity, b);
3313
3314         Brush_Build( b );
3315
3316         Sys_UpdateWindows (W_ALL);
3317 }
3318
3319 /*
3320 =============
3321 Brush_MakeSided
3322
3323 Makes the current brushhave the given number of 2d sides and turns it into a sphere
3324 =============
3325
3326 */
3327 void Brush_MakeSidedSphere(int sides)
3328 {
3329         int             i,j;
3330         vec3_t  mins, maxs;
3331         brush_t *b;
3332         texdef_t        *texdef;
3333         face_t  *f;
3334         vec3_t  mid;
3335
3336         if (sides < 4 || sides > 32)
3337         {
3338                 Sys_Status ("Bad sides number", 0);
3339                 return;
3340         }
3341
3342         if (!QE_SingleBrush ())
3343         {
3344                 Sys_Status ("Must have a single brush selected", 0 );
3345                 return;
3346         }
3347
3348         b = selected_brushes.next;
3349         VectorCopy (b->mins, mins);
3350         VectorCopy (b->maxs, maxs);
3351         texdef = &g_qeglobals.d_texturewin.texdef;
3352
3353         Brush_Free (b);
3354
3355         // find center of brush
3356         float radius = 8;
3357         for (i=0 ; i<2 ; i++)
3358         {
3359                 mid[i] = (maxs[i] + mins[i])*0.5;
3360                 if (maxs[i] - mins[i] > radius)
3361                         radius = maxs[i] - mins[i];
3362         }
3363         radius /= 2;
3364
3365         b = Brush_Alloc();
3366
3367         float dt = float(2 * Q_PI / sides);
3368         float dp = float(Q_PI / sides);
3369   float t,p;
3370         for(i=0; i <= sides-1; i++)
3371   {
3372                 for(j=0;j <= sides-2; j++)
3373                 {
3374                         t = i * dt;
3375                         p = float(j * dp - Q_PI / 2);
3376
3377       f = Face_Alloc();
3378             f->texdef = *texdef;
3379             f->next = b->brush_faces;
3380             b->brush_faces = f;
3381
3382       VectorPolar(f->planepts[0], radius, t, p);
3383       VectorPolar(f->planepts[1], radius, t, p + dp);
3384       VectorPolar(f->planepts[2], radius, t + dt, p + dp);
3385
3386       for (int k = 0; k < 3; k++)
3387         VectorAdd(f->planepts[k], mid, f->planepts[k]);
3388                 }
3389   }
3390
3391   p = float((sides - 1) * dp - Q_PI / 2);
3392         for(i = 0; i <= sides-1; i++)
3393         {
3394                 t = i * dt;
3395
3396     f = Face_Alloc();
3397           f->texdef = *texdef;
3398           f->next = b->brush_faces;
3399           b->brush_faces = f;
3400
3401     VectorPolar(f->planepts[0], radius, t, p);
3402     VectorPolar(f->planepts[1], radius, t + dt, p + dp);
3403     VectorPolar(f->planepts[2], radius, t + dt, p);
3404
3405     for (int k = 0; k < 3; k++)
3406       VectorAdd(f->planepts[k], mid, f->planepts[k]);
3407         }
3408
3409         Brush_AddToList (b, &selected_brushes);
3410
3411         Entity_LinkBrush (world_entity, b);
3412
3413         Brush_Build( b );
3414
3415         Sys_UpdateWindows (W_ALL);
3416 }
3417
3418 void Face_FitTexture( face_t * face, int nHeight, int nWidth )
3419 {
3420   winding_t *w;
3421   vec3_t   mins,maxs;
3422   int i;
3423   float width, height, temp;
3424   float rot_width, rot_height;
3425   float cosv,sinv,ang;
3426   float min_t, min_s, max_t, max_s;
3427   float s,t;
3428   vec3_t        vecs[2];
3429   vec3_t   coords[4];
3430   texdef_t      *td;
3431
3432   if (nHeight < 1)
3433     nHeight = 1;
3434   if (nWidth < 1)
3435     nWidth = 1;
3436
3437   ClearBounds (mins, maxs);
3438
3439   w = face->face_winding;
3440   if (!w)
3441   {
3442     return;
3443   }
3444   for (i=0 ; i<w->numpoints ; i++)
3445   {
3446     AddPointToBounds( w->points[i], mins, maxs );
3447   }
3448
3449   if (g_qeglobals.m_bBrushPrimitMode)
3450     Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth );
3451   else
3452   {
3453
3454     td = &face->texdef;
3455     //
3456     // get the current angle
3457     //
3458     ang = td->rotate / 180 * Q_PI;
3459     sinv = sin(ang);
3460     cosv = cos(ang);
3461
3462     // get natural texture axis
3463     TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]);
3464
3465     min_s = DotProduct( mins, vecs[0] );
3466     min_t = DotProduct( mins, vecs[1] );
3467     max_s = DotProduct( maxs, vecs[0] );
3468     max_t = DotProduct( maxs, vecs[1] );
3469     width = max_s - min_s;
3470     height = max_t - min_t;
3471     coords[0][0] = min_s;
3472     coords[0][1] = min_t;
3473     coords[1][0] = max_s;
3474     coords[1][1] = min_t;
3475     coords[2][0] = min_s;
3476     coords[2][1] = max_t;
3477     coords[3][0] = max_s;
3478     coords[3][1] = max_t;
3479     min_s = min_t = 99999;
3480     max_s = max_t = -99999;
3481     for (i=0; i<4; i++)
3482     {
3483       s = cosv * coords[i][0] - sinv * coords[i][1];
3484       t = sinv * coords[i][0] + cosv * coords[i][1];
3485       if (i&1)
3486       {
3487         if (s > max_s)
3488         {
3489           max_s = s;
3490         }
3491       }
3492       else
3493       {
3494         if (s < min_s)
3495         {
3496           min_s = s;
3497         }
3498         if (i<2)
3499         {
3500           if (t < min_t)
3501           {
3502             min_t = t;
3503           }
3504         }
3505         else
3506         {
3507           if (t > max_t)
3508           {
3509             max_t = t;
3510           }
3511         }
3512       }
3513     }
3514     rot_width =  (max_s - min_s);
3515     rot_height = (max_t - min_t);
3516     td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth)));
3517     td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight)));
3518
3519     td->shift[0] = min_s/td->scale[0];
3520     temp = (int)(td->shift[0] / (face->d_texture->width*nWidth));
3521     temp = (temp+1)*face->d_texture->width*nWidth;
3522     td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth);
3523
3524     td->shift[1] = min_t/td->scale[1];
3525     temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
3526     temp = (temp+1)*(face->d_texture->height*nHeight);
3527     td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
3528
3529     td->shift[1] = min_t/td->scale[1];
3530     temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
3531     temp = (temp+1)*(face->d_texture->height*nHeight);
3532     td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
3533
3534   }
3535 }
3536
3537 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth )
3538 {
3539         face_t *face;
3540
3541         for (face = b->brush_faces ; face ; face=face->next)
3542   {
3543     Face_FitTexture( face, nHeight, nWidth );
3544   }
3545 }
3546
3547 void aabb_draw(const aabb_t *aabb, int mode)
3548 {
3549   vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } };
3550   vec3_t points[8];
3551         vec3_t vMin, vMax;
3552   VectorSubtract(aabb->origin, aabb->extents, vMin);
3553   VectorAdd(aabb->origin, aabb->extents, vMax);
3554   VectorSet(points[0], vMin[0], vMax[1], vMax[2]);
3555   VectorSet(points[1], vMax[0], vMax[1], vMax[2]);
3556   VectorSet(points[2], vMax[0], vMin[1], vMax[2]);
3557   VectorSet(points[3], vMin[0], vMin[1], vMax[2]);
3558   VectorSet(points[4], vMin[0], vMax[1], vMin[2]);
3559   VectorSet(points[5], vMax[0], vMax[1], vMin[2]);
3560   VectorSet(points[6], vMax[0], vMin[1], vMin[2]);
3561   VectorSet(points[7], vMin[0], vMin[1], vMin[2]);
3562
3563   qglBegin(GL_QUADS);
3564
3565   qglNormal3fv(normals[0]);
3566   qglVertex3fv(points[2]);
3567   qglVertex3fv(points[1]);
3568   qglVertex3fv(points[5]);
3569   qglVertex3fv(points[6]);
3570
3571   qglNormal3fv(normals[1]);
3572   qglVertex3fv(points[1]);
3573   qglVertex3fv(points[0]);
3574   qglVertex3fv(points[4]);
3575   qglVertex3fv(points[5]);
3576
3577   qglNormal3fv(normals[2]);
3578   qglVertex3fv(points[0]);
3579   qglVertex3fv(points[1]);
3580   qglVertex3fv(points[2]);
3581   qglVertex3fv(points[3]);
3582
3583   qglNormal3fv(normals[3]);
3584   qglVertex3fv(points[3]);
3585   qglVertex3fv(points[7]);
3586   qglVertex3fv(points[4]);
3587   qglVertex3fv(points[0]);
3588
3589   qglNormal3fv(normals[4]);
3590   qglVertex3fv(points[3]);
3591   qglVertex3fv(points[2]);
3592   qglVertex3fv(points[6]);
3593   qglVertex3fv(points[7]);
3594
3595   qglNormal3fv(normals[5]);
3596   qglVertex3fv(points[7]);
3597   qglVertex3fv(points[6]);
3598   qglVertex3fv(points[5]);
3599   qglVertex3fv(points[4]);
3600
3601   qglEnd();
3602
3603 /*
3604
3605
3606   vec3_t Coords[8];
3607
3608         vec3_t vMin, vMax;
3609   VectorSubtract(aabb->origin, aabb->extents, vMin);
3610   VectorAdd(aabb->origin, aabb->extents, vMax);
3611   VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]);
3612   VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]);
3613   VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]);
3614   VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]);
3615   VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]);
3616   VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]);
3617   VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]);
3618   VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]);
3619
3620         vec3_t Normals[8] = { {-1, 0, 0 },
3621                                                                                         { 0, 0, 0 },
3622                                                                                         { 0, 0, 0 },
3623                                                                                         { 0, 0, 1 },
3624                                                                                         { 0, 0,-1 },
3625                                                                                         { 0, 1, 0 },
3626                                                                                         { 1, 0, 0 },
3627                                                                                         { 0,-1, 0 } };
3628
3629         unsigned short Indices[24] = { 2, 1, 5, 6,
3630                                                                                                                                  1, 0, 4, 5,
3631                                                                                                                                  0, 1, 2, 3,
3632                                                                                                                                  3, 7, 4, 0,
3633                                                                                                                                  3, 2, 6, 7,
3634                                                                                                                                  7, 6, 5, 4 };
3635
3636   qglVertexPointer(3, GL_FLOAT, 0, Coords);         // filling the arrays
3637   qglNormalPointer(GL_FLOAT, 0, Normals);
3638
3639   //glLockArraysEXT(0, count);                // extension GL_EXT_compiled_vertex_array
3640
3641   qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices);
3642
3643   //glUnlockArraysEXT;                        // extension GL_EXT_compiled_vertex_array
3644 */
3645 }
3646
3647 qboolean IsBrushSelected(brush_t* bSel)
3648 {
3649         for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)
3650   {
3651     if (b == bSel)
3652       return true;
3653   }
3654   return false;
3655 }
3656
3657