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