]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/EditorBrush.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / radiant / EditorBrush.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "qe3.h"
33 #include <GL/glu.h>
34
35 #include "../../renderer/tr_local.h"
36 #include "../../renderer/model_local.h" // for idRenderModelMD5
37
38 void    Brush_UpdateLightPoints(brush_t *b, const idVec3 &offset);
39 void Brush_DrawCurve( brush_t *b, bool bSelected, bool cam );
40
41 // globals
42 int             g_nBrushId = 0;
43 bool    g_bShowLightVolumes = false;
44 bool    g_bShowLightTextures = false;
45
46 void GLCircle(float x, float y, float z, float r);
47
48 const int POINTS_PER_KNOT = 50;
49
50 /*
51 ================
52 DrawRenderModel
53 ================
54 */
55 void DrawRenderModel( idRenderModel *model, idVec3 &origin, idMat3 &axis, bool cameraView ) {
56         for ( int i = 0; i < model->NumSurfaces(); i++ ) {
57                 const modelSurface_t *surf = model->Surface( i );
58                 const idMaterial *material = surf->shader;
59
60                 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
61
62                 if ( cameraView && (nDrawMode == cd_texture || nDrawMode == cd_light) ) {
63                         material->GetEditorImage()->Bind();
64                 }
65
66                 qglBegin( GL_TRIANGLES );
67
68                 const srfTriangles_t    *tri = surf->geometry;
69                 for ( int j = 0; j < tri->numIndexes; j += 3 ) {
70                         for ( int k = 0; k < 3; k++ ) {
71                                 int             index = tri->indexes[j + k];
72                                 idVec3  v;
73
74                                 v = tri->verts[index].xyz * axis + origin;
75                                 qglTexCoord2f( tri->verts[index].st.x, tri->verts[index].st.y );
76                                 qglVertex3fv( v.ToFloatPtr() );
77                         }
78                 }
79
80                 qglEnd();
81         }
82 }
83
84 /*
85 ================
86 SnapVectorToGrid
87 ================
88 */
89 void SnapVectorToGrid(idVec3 &v) {
90         v.x = floor(v.x / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
91         v.y = floor(v.y / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
92         v.z = floor(v.z / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
93 }
94
95 /*
96 ================
97 Brush_Name
98 ================
99 */
100 const char *Brush_Name( brush_t *b ) {
101         static char cBuff[1024];
102
103         b->numberId = g_nBrushId++;
104         if (g_qeglobals.m_bBrushPrimitMode) {
105                 sprintf(cBuff, "Brush %i", b->numberId);
106                 Brush_SetEpair(b, "Name", cBuff);
107         }
108
109         return cBuff;
110 }
111
112 /*
113 ================
114 Brush_Alloc
115 ================
116 */
117 brush_t *Brush_Alloc( void ) {
118         brush_t *b = new brush_t;
119         b->prev = b->next = NULL;
120         b->oprev = b->onext = NULL;
121         b->owner = NULL;
122         b->mins.Zero();
123         b->maxs.Zero();
124
125         b->lightCenter.Zero();
126         b->lightRight.Zero();
127         b->lightTarget.Zero();
128         b->lightUp.Zero();
129         b->lightRadius.Zero();
130         b->lightOffset.Zero();
131         b->lightColor.Zero();
132         b->lightStart.Zero();
133         b->lightEnd.Zero();
134         b->pointLight = false;
135         b->startEnd = false;
136         b->lightTexture = 0;
137         b->trackLightOrigin = false;
138
139         b->entityModel = false;
140         b->brush_faces = NULL;
141         b->hiddenBrush = false;
142         b->pPatch = NULL;
143         b->pUndoOwner = NULL;
144         b->undoId = 0;
145         b->redoId = 0;
146         b->ownerId = 0;
147         b->numberId = 0;
148         b->itemOwner = 0;
149         b->bModelFailed = false;
150         b->modelHandle = NULL;
151         b->forceVisibile = false;
152         b->forceWireFrame = false;
153         return b;
154 }
155
156 /*
157 ================
158 TextureAxisFromPlane
159 ================
160 */
161 idVec3  baseaxis[18] = {
162         idVec3(0, 0, 1),
163         idVec3(1, 0, 0),
164         idVec3(0, -1, 0),
165
166         // floor
167         idVec3(0, 0, -1),
168         idVec3(1, 0, 0),
169         idVec3(0, -1, 0),
170
171         // ceiling
172         idVec3(1, 0, 0),
173         idVec3(0, 1, 0),
174         idVec3(0, 0, -1),
175
176         // west wall
177         idVec3(-1, 0, 0),
178         idVec3(0, 1, 0),
179         idVec3(0, 0, -1),
180
181         // east wall
182         idVec3(0, 1, 0),
183         idVec3(1, 0, 0),
184         idVec3(0, 0, -1),
185
186         // south wall
187         idVec3(0, -1, 0),
188         idVec3(1, 0, 0),
189         idVec3(0, 0, -1)        // north wall
190 };
191
192 void TextureAxisFromPlane( const idPlane &pln, idVec3 &xv, idVec3 &yv) {
193         int             bestaxis;
194         float   dot, best;
195         int             i;
196
197         best = 0;
198         bestaxis = 0;
199
200         for (i = 0; i < 6; i++) {
201                 dot = DotProduct(pln, baseaxis[i * 3]);
202                 if (dot > best) {
203                         best = dot;
204                         bestaxis = i;
205                 }
206         }
207
208         VectorCopy(baseaxis[bestaxis * 3 + 1], xv);
209         VectorCopy(baseaxis[bestaxis * 3 + 2], yv);
210 }
211
212 /*
213 ================
214 ShadeForNormal
215
216   Light different planes differently to improve recognition
217 ================
218 */
219 float   lightaxis[3] = { 0.6f, 0.8f, 1.0f };
220
221 float ShadeForNormal(idVec3 normal) {
222         int             i;
223         float   f;
224
225         // axial plane
226         for (i = 0; i < 3; i++) {
227                 if ( idMath::Fabs(normal[i]) > 0.9f ) {
228                         f = lightaxis[i];
229                         return f;
230                 }
231         }
232
233         // between two axial planes
234         for (i = 0; i < 3; i++) {
235                 if ( idMath::Fabs(normal[i]) < 0.1f ) {
236                         f = (lightaxis[(i + 1) % 3] + lightaxis[(i + 2) % 3]) / 2;
237                         return f;
238                 }
239         }
240
241         // other
242         f = (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
243         return f;
244 }
245
246 /*
247 ================
248 Face_Alloc
249 ================
250 */
251 face_t *Face_Alloc(void) {
252         brushprimit_texdef_t    bp;
253
254         face_t *f = (face_t *) Mem_ClearedAlloc(sizeof(*f));
255
256         bp.coords[0][0] = 0.0f;
257         bp.coords[1][1] = 0.0f;
258         f->brushprimit_texdef = bp;
259         f->dirty = true;
260         return f;
261 }
262
263 /*
264 ================
265 Face_Free
266 ================
267 */
268 void Face_Free(face_t *f) {
269         assert(f != 0);
270
271         if (f->face_winding) {
272                 delete f->face_winding;
273         }
274
275         f->texdef.~texdef_t();
276
277         Mem_Free(f);
278 }
279
280 /*
281 ================
282 Face_Clone
283 ================
284 */
285 face_t *Face_Clone(face_t *f) {
286         face_t  *n;
287
288         n = Face_Alloc();
289         n->texdef = f->texdef;
290         n->brushprimit_texdef = f->brushprimit_texdef;
291
292         memcpy(n->planepts, f->planepts, sizeof(n->planepts));
293         n->plane = f->plane;
294         n->originalPlane = f->originalPlane;
295         n->dirty = f->dirty;
296
297         // all other fields are derived, and will be set by Brush_Build
298         return n;
299 }
300
301 /*
302 ================
303 Face_FullClone
304
305   Used by Undo.
306   Makes an exact copy of the face.
307 ================
308 */
309 face_t *Face_FullClone(face_t *f) {
310         face_t  *n;
311
312         n = Face_Alloc();
313         n->texdef = f->texdef;
314         n->brushprimit_texdef = f->brushprimit_texdef;
315         memcpy(n->planepts, f->planepts, sizeof(n->planepts));
316         n->plane = f->plane;
317         n->originalPlane = f->originalPlane;
318         n->dirty = f->dirty;
319         if (f->face_winding) {
320                 n->face_winding = f->face_winding->Copy();
321         }
322         else {
323                 n->face_winding = NULL;
324         }
325
326         n->d_texture = Texture_ForName(n->texdef.name);
327         return n;
328 }
329
330 /*
331 ================
332 Clamp
333 ================
334 */
335 void Clamp(float &f, int nClamp) {
336         float   fFrac = f - static_cast<int>(f);
337         f = static_cast<int>(f) % nClamp;
338         f += fFrac;
339 }
340
341 /*
342 ================
343 Face_MoveTexture
344 ================
345 */
346 void Face_MoveTexture(face_t *f, idVec3 delta) {
347         idVec3  vX, vY;
348
349         /*
350          * #ifdef _DEBUG if (g_PrefsDlg.m_bBrushPrimitMode) common->Printf("Warning :
351          * Face_MoveTexture not done in brush primitive mode\n"); #endif
352          */
353         if (g_qeglobals.m_bBrushPrimitMode) {
354                 Face_MoveTexture_BrushPrimit(f, delta);
355         }
356         else {
357                 TextureAxisFromPlane( f->plane, vX, vY );
358
359                 idVec3  vDP, vShift;
360                 vDP[0] = DotProduct(delta, vX);
361                 vDP[1] = DotProduct(delta, vY);
362
363                 double  fAngle = DEG2RAD( f->texdef.rotate );
364                 double  c = cos(fAngle);
365                 double  s = sin(fAngle);
366
367                 vShift[0] = vDP[0] * c - vDP[1] * s;
368                 vShift[1] = vDP[0] * s + vDP[1] * c;
369
370                 if (!f->texdef.scale[0]) {
371                         f->texdef.scale[0] = 1;
372                 }
373
374                 if (!f->texdef.scale[1]) {
375                         f->texdef.scale[1] = 1;
376                 }
377
378                 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
379                 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
380
381                 // clamp the shifts
382                 Clamp(f->texdef.shift[0], f->d_texture->GetEditorImage()->uploadWidth);
383                 Clamp(f->texdef.shift[1], f->d_texture->GetEditorImage()->uploadHeight);
384         }
385 }
386
387 /*
388 ================
389 Face_SetColor
390 ================
391 */
392 void Face_SetColor(brush_t *b, face_t *f, float fCurveColor) {
393         float           shade;
394         const idMaterial        *q;
395
396         q = f->d_texture;
397
398         // set shading for face
399         shade = ShadeForNormal( f->plane.Normal() );
400         if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture && (b->owner && !b->owner->eclass->fixedsize)) {
401                 // if (b->curveBrush) shade = fCurveColor;
402                 f->d_color[0] = f->d_color[1] = f->d_color[2] = shade;
403         }
404         else if ( f && b && b->owner ) {
405                 f->d_color[0] = shade * b->owner->eclass->color.x;
406                 f->d_color[1] = shade * b->owner->eclass->color.y;
407                 f->d_color[2] = shade * b->owner->eclass->color.z;
408         }
409 }
410
411 /*
412 ================
413 Face_TextureVectors
414
415   NOTE: this is never to get called while in brush primitives mode
416 ================
417 */
418 void Face_TextureVectors(face_t *f, float STfromXYZ[2][4]) {
419         idVec3          pvecs[2];
420         int                     sv, tv;
421         float           ang, sinv, cosv;
422         float           ns, nt;
423         int                     i, j;
424         const idMaterial        *q;
425         texdef_t        *td;
426
427 #ifdef _DEBUG
428
429         //
430         // ++timo when playing with patches, this sometimes get called and the Warning is
431         // displayed find some way out ..
432         //
433         if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) {
434                 common->Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
435         }
436 #endif
437         td = &f->texdef;
438         q = f->d_texture;
439
440         memset(STfromXYZ, 0, 8 * sizeof (float));
441
442         if (!td->scale[0]) {
443                 td->scale[0] = (g_PrefsDlg.m_bHiColorTextures) ? 2 : 1;
444         }
445
446         if (!td->scale[1]) {
447                 td->scale[1] = (g_PrefsDlg.m_bHiColorTextures) ? 2 : 1;
448         }
449
450         // get natural texture axis
451         TextureAxisFromPlane( f->plane, pvecs[0], pvecs[1]);
452
453         // rotate axis
454         if (td->rotate == 0) {
455                 sinv = 0;
456                 cosv = 1;
457         }
458         else if (td->rotate == 90) {
459                 sinv = 1;
460                 cosv = 0;
461         }
462         else if (td->rotate == 180) {
463                 sinv = 0;
464                 cosv = -1;
465         }
466         else if (td->rotate == 270) {
467                 sinv = -1;
468                 cosv = 0;
469         }
470         else {
471                 ang = DEG2RAD( td->rotate );
472                 sinv = sin(ang);
473                 cosv = cos(ang);
474         }
475
476         if (pvecs[0][0]) {
477                 sv = 0;
478         }
479         else if (pvecs[0][1]) {
480                 sv = 1;
481         }
482         else {
483                 sv = 2;
484         }
485
486         if (pvecs[1][0]) {
487                 tv = 0;
488         }
489         else if (pvecs[1][1]) {
490                 tv = 1;
491         }
492         else {
493                 tv = 2;
494         }
495
496         for (i = 0; i < 2; i++) {
497                 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
498                 nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
499                 STfromXYZ[i][sv] = ns;
500                 STfromXYZ[i][tv] = nt;
501         }
502
503         // scale
504         for (i = 0; i < 2; i++) {
505                 for (j = 0; j < 3; j++) {
506                         STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
507                 }
508         }
509
510         // shift
511         STfromXYZ[0][3] = td->shift[0];
512         STfromXYZ[1][3] = td->shift[1];
513
514         for (j = 0; j < 4; j++) {
515                 STfromXYZ[0][j] /= q->GetEditorImage()->uploadWidth;
516                 STfromXYZ[1][j] /= q->GetEditorImage()->uploadHeight;
517         }
518 }
519
520 /*
521 ================
522 Face_MakePlane
523 ================
524 */
525 void Face_MakePlane(face_t *f) {
526         int             j;
527         idVec3  t1, t2, t3;
528
529         idPlane oldPlane = f->plane;
530
531         // convert to a vector / dist plane
532         for (j = 0; j < 3; j++) {
533                 t1[j] = f->planepts[0][j] - f->planepts[1][j];
534                 t2[j] = f->planepts[2][j] - f->planepts[1][j];
535                 t3[j] = f->planepts[1][j];
536         }
537
538         f->plane = t1.Cross( t2 );
539         //if ( f->plane.Compare( vec3_origin ) ) {
540         //      printf("WARNING: brush plane with no normal\n");
541         //}
542
543         f->plane.Normalize(false);
544         f->plane[3] = - (t3 * f->plane.Normal());
545
546         if ( !f->dirty && !f->plane.Compare( oldPlane, 0.01f ) ) {
547                 f->dirty = true;
548         }
549 }
550
551 /*
552 ================
553 EmitTextureCoordinates
554 ================
555 */
556 void EmitTextureCoordinates(idVec5 &xyzst, const idMaterial *q, face_t *f, bool force) {
557         float   STfromXYZ[2][4];
558
559         if (g_qeglobals.m_bBrushPrimitMode && !force) {
560                 EmitBrushPrimitTextureCoordinates(f, f->face_winding);
561         }
562         else {
563                 Face_TextureVectors(f, STfromXYZ);
564                 xyzst[3] = DotProduct(xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
565                 xyzst[4] = DotProduct(xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
566         }
567 }
568
569 /*
570 ================
571 Brush_MakeFacePlanes
572 ================
573 */
574 void Brush_MakeFacePlanes(brush_t *b) {
575         face_t  *f;
576
577         for (f = b->brush_faces; f; f = f->next) {
578                 Face_MakePlane(f);
579         }
580 }
581
582 /*
583 ================
584 DrawBrushEntityName
585 ================
586 */
587 void DrawBrushEntityName(brush_t *b) {
588         const char      *name;
589
590         // float a, s, c; vec3_t mid; int i;
591         if (!b->owner) {
592                 return; // during contruction
593         }
594
595         if (b->owner == world_entity) {
596                 return;
597         }
598
599         if (b != b->owner->brushes.onext) {
600                 return; // not key brush
601         }
602
603         if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES)) {
604                 // draw the angle pointer
605                 float a = FloatForKey(b->owner, "angle");
606                 if (a) {
607                         float s = sin( DEG2RAD( a ) );
608                         float c = cos( DEG2RAD( a ) );
609
610                         idVec3 mid = (b->mins + b->maxs) / 2.0f;
611
612                         qglBegin(GL_LINE_STRIP);
613                         qglVertex3fv(mid.ToFloatPtr());
614                         mid[0] += c * 8;
615                         mid[1] += s * 8;
616                         mid[2] += s * 8;
617                         qglVertex3fv(mid.ToFloatPtr());
618                         mid[0] -= c * 4;
619                         mid[1] -= s * 4;
620                         mid[2] -= s * 4;
621                         mid[0] -= s * 4;
622                         mid[1] += c * 4;
623                         mid[2] += c * 4;
624                         qglVertex3fv(mid.ToFloatPtr());
625                         mid[0] += c * 4;
626                         mid[1] += s * 4;
627                         mid[2] += s * 4;
628                         mid[0] += s * 4;
629                         mid[1] -= c * 4;
630                         mid[2] -= c * 4;
631                         qglVertex3fv(mid.ToFloatPtr());
632                         mid[0] -= c * 4;
633                         mid[1] -= s * 4;
634                         mid[2] -= s * 4;
635                         mid[0] += s * 4;
636                         mid[1] -= c * 4;
637                         mid[2] -= c * 4;
638                         qglVertex3fv(mid.ToFloatPtr());
639                         qglEnd();
640                 }
641         }
642
643         int viewType = g_pParentWnd->ActiveXY()->GetViewType();
644         float scale = g_pParentWnd->ActiveXY()->Scale();
645
646         if (g_qeglobals.d_savedinfo.show_names && scale >= 1.0f) {
647                 name = ValueForKey(b->owner, "name");
648                 int nameLen = strlen(name);
649                 if ( nameLen == 0 ) {
650                         name = ValueForKey(b->owner, "classname");
651                         nameLen = strlen(name);
652                 }
653                 if ( nameLen > 0 ) {
654                         idVec3 origin = b->owner->origin;
655
656                         float halfWidth = ( (nameLen / 2) *  (7.0f / scale) );
657                         float halfHeight = 4.0f / scale;
658
659                         switch (viewType) {
660                         case XY:
661                                 origin.x -= halfWidth;
662                                 origin.y += halfHeight;
663                                 break;
664                         case XZ:
665                                 origin.x -= halfWidth;
666                                 origin.z += halfHeight;
667                                 break;
668                         case YZ:
669                                 origin.y -= halfWidth;
670                                 origin.z += halfHeight;
671                                 break;
672                         }
673                         qglRasterPos3fv( origin.ToFloatPtr() );
674                         qglCallLists(nameLen, GL_UNSIGNED_BYTE, name);
675                 }
676         }
677 }
678
679 /*
680 ================
681 Brush_MakeFaceWinding
682
683   returns the visible winding
684 ================
685 */
686 idWinding *Brush_MakeFaceWinding(brush_t *b, face_t *face, bool keepOnPlaneWinding) {
687         idWinding       *w;
688         face_t          *clip;
689         idPlane         plane;
690         bool            past;
691
692         // get a poly that covers an effectively infinite area
693         w = new idWinding( face->plane );
694
695         // chop the poly by all of the other faces
696         past = false;
697         for (clip = b->brush_faces; clip && w; clip = clip->next) {
698                 if (clip == face) {
699                         past = true;
700                         continue;
701                 }
702
703                 if ( DotProduct(face->plane, clip->plane) > 0.999f &&
704                                 idMath::Fabs(face->plane[3] - clip->plane[3]) < 0.01f ) { // identical plane, use the later one
705                         if (past) {
706                                 delete w;
707                                 common->Printf("Unable to create face winding on brush\n");
708                                 return NULL;
709                         }
710                         continue;
711                 }
712
713                 // flip the plane, because we want to keep the back side
714                 VectorSubtract(vec3_origin, clip->plane, plane );
715                 plane[3] = -clip->plane[3];
716
717                 w = w->Clip( plane, ON_EPSILON, keepOnPlaneWinding );
718                 if ( !w ) {
719                         return w;
720                 }
721         }
722
723         if ( w->GetNumPoints() < 3) {
724                 delete w;
725                 w = NULL;
726         }
727
728         if (!w) {
729                 Sys_Status("Unable to create face winding on brush\n");
730         } 
731         return w;
732 }
733
734 /*
735 ================
736 Brush_Build
737
738   Builds a brush rendering data and also sets the min/max bounds
739   TTimo added a bConvert flag to convert between old and new brush texture formats
740   TTimo brush grouping: update the group treeview if necessary
741 ================
742 */
743 void Brush_Build(brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool updateLights) {
744         bool bLocalConvert = false;
745
746 #ifdef _DEBUG
747         if (!g_qeglobals.m_bBrushPrimitMode && bConvert) {
748                 common->Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
749         }
750 #endif
751         //
752         // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need
753         // convert for this brush only
754         //
755         if (bConvert && !g_qeglobals.bNeedConvert) {
756                 bLocalConvert = true;
757                 g_qeglobals.bNeedConvert = true;
758         }
759
760         /* build the windings and generate the bounding box */
761         Brush_BuildWindings(b, bSnap, EntityHasModel(b->owner) || b->pPatch, updateLights);
762
763         /* move the points and edges if in select mode */
764         if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) {
765                 SetupVertexSelection();
766         }
767
768         if (bMarkMap) {
769                 Sys_MarkMapModified();
770                 g_pParentWnd->GetCamera()->MarkWorldDirty();
771         }
772
773         if (bLocalConvert) {
774                 g_qeglobals.bNeedConvert = false;
775         }
776 }
777
778 /*
779 ================
780 Brush_SplitBrushByFace
781
782   The incoming brush is NOT freed. The incoming face is NOT left referenced.
783 ================
784 */
785 void Brush_SplitBrushByFace(brush_t *in, face_t *f, brush_t **front, brush_t **back) {
786         brush_t *b;
787         face_t  *nf;
788         idVec3  temp;
789
790         b = Brush_Clone(in);
791         nf = Face_Clone(f);
792
793         nf->texdef = b->brush_faces->texdef;
794         nf->brushprimit_texdef = b->brush_faces->brushprimit_texdef;
795         nf->next = b->brush_faces;
796         b->brush_faces = nf;
797
798         Brush_Build(b);
799         Brush_RemoveEmptyFaces(b);
800         if (!b->brush_faces) {  // completely clipped away
801                 Brush_Free(b);
802                 *back = NULL;
803         }
804         else {
805                 Entity_LinkBrush(in->owner, b);
806                 *back = b;
807         }
808
809         b = Brush_Clone(in);
810         nf = Face_Clone(f);
811
812         // swap the plane winding
813         VectorCopy(nf->planepts[0], temp);
814         VectorCopy(nf->planepts[1], nf->planepts[0]);
815         VectorCopy(temp, nf->planepts[1]);
816
817         nf->texdef = b->brush_faces->texdef;
818         nf->brushprimit_texdef = b->brush_faces->brushprimit_texdef;
819         nf->next = b->brush_faces;
820         b->brush_faces = nf;
821
822         Brush_Build(b);
823         Brush_RemoveEmptyFaces(b);
824         if (!b->brush_faces) {  // completely clipped away
825                 Brush_Free(b);
826                 *front = NULL;
827         }
828         else {
829                 Entity_LinkBrush(in->owner, b);
830                 *front = b;
831         }
832 }
833
834 /*
835 ================
836 Brush_BestSplitFace
837
838   returns the best face to split the brush with. return NULL if the brush is convex
839 ================
840 */
841 face_t *Brush_BestSplitFace(brush_t *b) {
842         face_t          *face, *f, *bestface;
843         idWinding       *front, *back;
844         int                     splits, tinywindings, value, bestvalue;
845
846         bestvalue = 999999;
847         bestface = NULL;
848         for ( face = b->brush_faces; face; face = face->next ) {
849                 splits = 0;
850                 tinywindings = 0;
851                 for ( f = b->brush_faces; f; f = f->next ) {
852                         if ( f == face ) {
853                                 continue;
854                         }
855
856                         f->face_winding->Split( face->plane, 0.1f, &front, &back );
857
858                         if ( !front ) {
859                                 delete back;
860                         }
861                         else if ( !back ) {
862                                 delete front;
863                         }
864                         else {
865                                 splits++;
866                                 if ( front->IsTiny() ) {
867                                         tinywindings++;
868                                 }
869
870                                 if ( back->IsTiny() ) {
871                                         tinywindings++;
872                                 }
873                                 delete front;
874                                 delete back;
875                         }
876                 }
877
878                 if ( splits ) {
879                         value = splits + 50 * tinywindings;
880                         if ( value < bestvalue ) {
881                                 bestvalue = value;
882                                 bestface = face;
883                         }
884                 }
885         }
886
887         return bestface;
888 }
889
890 /*
891 ================
892 Brush_MakeConvexBrushes
893
894   MrE FIXME: this doesn't work because the old Brush_SplitBrushByFace is used
895   Turns the brush into a minimal number of convex brushes.
896   If the input brush is convex then it will be returned. Otherwise the input
897   brush will be freed.
898   NOTE: the input brush should have windings for the faces.
899 ================
900 */
901 brush_t *Brush_MakeConvexBrushes(brush_t *b) {
902         brush_t *front, *back, *end;
903         face_t  *face;
904
905         b->next = NULL;
906         face = Brush_BestSplitFace(b);
907         if (!face) {
908                 return b;
909         }
910
911         Brush_SplitBrushByFace(b, face, &front, &back);
912
913         // this should never happen
914         if (!front && !back) {
915                 return b;
916         }
917
918         Brush_Free(b);
919         if (!front) {
920                 return Brush_MakeConvexBrushes(back);
921         }
922
923         b = Brush_MakeConvexBrushes(front);
924         if (back) {
925                 for (end = b; end->next; end = end->next);
926                 end->next = Brush_MakeConvexBrushes(back);
927         }
928
929         return b;
930 }
931
932 /*
933 ================
934 Brush_Convex
935
936   returns true if the brush is convex
937 ================
938 */
939 int Brush_Convex(brush_t *b) {
940         face_t  *face1, *face2;
941
942         for (face1 = b->brush_faces; face1; face1 = face1->next) {
943                 if (!face1->face_winding) {
944                         continue;
945                 }
946
947                 for (face2 = b->brush_faces; face2; face2 = face2->next) {
948                         if (face1 == face2) {
949                                 continue;
950                         }
951
952                         if (!face2->face_winding) {
953                                 continue;
954                         }
955
956                         if ( face1->face_winding->PlanesConcave( *face2->face_winding,
957                                         face1->plane.Normal(), face2->plane.Normal(), -face1->plane[3], -face2->plane[3] ) ) {
958                                 return false;
959                         }
960                 }
961         }
962
963         return true;
964 }
965
966 /*
967 ================
968 Brush_MoveVertexes
969
970   The input brush must be convex.
971   The input brush must have face windings.
972   The output brush will be convex.
973   Returns true if the WHOLE vertex movement is performed.
974 ================
975 */
976 #define MAX_MOVE_FACES  64
977 #define TINY_EPSILON    0.0325f
978
979 int Brush_MoveVertex(brush_t *b, const idVec3 &vertex, const idVec3 &delta, idVec3 &end, bool bSnap) {
980         face_t          *f, *face, *newface, *lastface, *nextface;
981         face_t          *movefaces[MAX_MOVE_FACES];
982         int                     movefacepoints[MAX_MOVE_FACES];
983         idWinding       *w, tmpw(3);
984         idVec3          start, mid;
985         idPlane         plane;
986         int                     i, j, k, nummovefaces, result, done;
987         float           dot, front, back, frac, smallestfrac;
988
989         result = true;
990         tmpw.SetNumPoints( 3 );
991         VectorCopy(vertex, start);
992         VectorAdd(vertex, delta, end);
993
994         // snap or not?
995         //
996         if (bSnap) {
997                 for (i = 0; i < 3; i++) {
998                         end[i] = floor( end[i] / 0.125f + 0.5f ) * 0.125f;
999                 }
1000         }
1001
1002         VectorCopy(end, mid);
1003
1004         // if the start and end are the same
1005         if ( start.Compare( end, TINY_EPSILON ) ) {
1006                 return false;
1007         }
1008
1009         // the end point may not be the same as another vertex
1010         for ( face = b->brush_faces; face; face = face->next ) {
1011                 w = face->face_winding;
1012                 if (!w) {
1013                         continue;
1014                 }
1015
1016                 for (i = 0; i < w->GetNumPoints(); i++) {
1017                         if ( end.Compare( (*w)[i].ToVec3(), TINY_EPSILON ) ) {
1018                                 VectorCopy(vertex, end);
1019                                 return false;
1020                         }
1021                 }
1022         }
1023
1024         done = false;
1025         while (!done) {
1026                 //
1027                 // chop off triangles from all brush faces that use the to be moved vertex store
1028                 // pointers to these chopped off triangles in movefaces[]
1029                 //
1030                 nummovefaces = 0;
1031                 for (face = b->brush_faces; face; face = face->next) {
1032                         w = face->face_winding;
1033                         if (!w) {
1034                                 continue;
1035                         }
1036
1037                         for (i = 0; i < w->GetNumPoints(); i++) {
1038                                 if ( start.Compare( (*w)[i].ToVec3(), TINY_EPSILON ) ) {
1039                                         if (face->face_winding->GetNumPoints() <= 3) {
1040                                                 movefacepoints[nummovefaces] = i;
1041                                                 movefaces[nummovefaces++] = face;
1042                                                 break;
1043                                         }
1044
1045                                         dot = DotProduct(end, face->plane) + face->plane[3];
1046
1047                                         // if the end point is in front of the face plane
1048                                         //if ( dot > 0.1f ) {
1049                                         if ( dot > TINY_EPSILON ) {
1050                                                 // fanout triangle subdivision
1051                                                 for (k = i; k < i + w->GetNumPoints() - 3; k++) {
1052                                                         VectorCopy((*w)[i], tmpw[0]);
1053                                                         VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[1]);
1054                                                         VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[2]);
1055                                                         newface = Face_Clone(face);
1056
1057                                                         // get the original
1058                                                         for (f = face; f->original; f = f->original) {};
1059
1060                                                         newface->original = f;
1061
1062                                                         // store the new winding
1063                                                         if (newface->face_winding) {
1064                                                                 delete newface->face_winding;
1065                                                         }
1066
1067                                                         newface->face_winding = tmpw.Copy();
1068
1069                                                         // get the texture
1070                                                         newface->d_texture = Texture_ForName(newface->texdef.name);
1071
1072                                                         // add the face to the brush
1073                                                         newface->next = b->brush_faces;
1074                                                         b->brush_faces = newface;
1075
1076                                                         // add this new triangle to the move faces
1077                                                         movefacepoints[nummovefaces] = 0;
1078                                                         movefaces[nummovefaces++] = newface;
1079                                                 }
1080
1081                                                 // give the original face a new winding
1082                                                 VectorCopy((*w)[(i - 2 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[0]);
1083                                                 VectorCopy((*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[1]);
1084                                                 VectorCopy((*w)[i], tmpw[2]);
1085                                                 delete face->face_winding;
1086                                                 face->face_winding = tmpw.Copy();
1087
1088                                                 // add the original face to the move faces
1089                                                 movefacepoints[nummovefaces] = 2;
1090                                                 movefaces[nummovefaces++] = face;
1091                                         }
1092                                         else {
1093                                                 // chop a triangle off the face
1094                                                 VectorCopy((*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[0]);
1095                                                 VectorCopy((*w)[i], tmpw[1]);
1096                                                 VectorCopy((*w)[(i + 1) % w->GetNumPoints()], tmpw[2]);
1097
1098                                                 // remove the point from the face winding
1099                                                 w->RemovePoint( i );
1100
1101                                                 // get texture crap right
1102                                                 Face_SetColor(b, face, 1.0);
1103                                                 for (j = 0; j < w->GetNumPoints(); j++) {
1104                                                         EmitTextureCoordinates( (*w)[j], face->d_texture, face );
1105                                                 }
1106
1107                                                 // make a triangle face
1108                                                 newface = Face_Clone(face);
1109
1110                                                 // get the original
1111                                                 for (f = face; f->original; f = f->original) {};
1112
1113                                                 newface->original = f;
1114
1115                                                 // store the new winding
1116                                                 if (newface->face_winding) {
1117                                                         delete newface->face_winding;
1118                                                 }
1119
1120                                                 newface->face_winding = tmpw.Copy();
1121
1122                                                 // get the texture
1123                                                 newface->d_texture = Texture_ForName(newface->texdef.name);
1124
1125                                                 // add the face to the brush
1126                                                 newface->next = b->brush_faces;
1127                                                 b->brush_faces = newface;
1128                                                 movefacepoints[nummovefaces] = 1;
1129                                                 movefaces[nummovefaces++] = newface;
1130                                         }
1131                                         break;
1132                                 }
1133                         }
1134                 }
1135
1136                 //
1137                 // now movefaces contains pointers to triangle faces that contain the to be moved
1138                 // vertex
1139                 //
1140                 done = true;
1141                 VectorCopy(end, mid);
1142                 smallestfrac = 1;
1143                 for (face = b->brush_faces; face; face = face->next) {
1144                         // check if there is a move face that has this face as the original
1145                         for (i = 0; i < nummovefaces; i++) {
1146                                 if (movefaces[i]->original == face) {
1147                                         break;
1148                                 }
1149                         }
1150
1151                         if (i >= nummovefaces) {
1152                                 continue;
1153                         }
1154
1155                         // check if the original is not a move face itself
1156                         for (j = 0; j < nummovefaces; j++) {
1157                                 if (face == movefaces[j]) {
1158                                         break;
1159                                 }
1160                         }
1161
1162                         // if the original is not a move face itself
1163                         if (j >= nummovefaces) {
1164                                 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane));
1165                         }
1166                         else {
1167                                 k = movefacepoints[j];
1168                                 w = movefaces[j]->face_winding;
1169                                 VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[0]);
1170                                 VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[1]);
1171
1172                                 k = movefacepoints[i];
1173                                 w = movefaces[i]->face_winding;
1174                                 VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[2]);
1175
1176                                 if ( !plane.FromPoints( tmpw[0].ToVec3(), tmpw[1].ToVec3(), tmpw[2].ToVec3(), false ) ) {
1177                                         VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[2]);
1178                                         if ( !plane.FromPoints( tmpw[0].ToVec3(), tmpw[1].ToVec3(), tmpw[2].ToVec3() ), false ) {
1179                                                 // this should never happen otherwise the face merge did
1180                                                 // a crappy job a previous pass
1181                                                 continue;
1182                                         }
1183                                 }
1184                                 plane[0] = -plane[0];
1185                                 plane[1] = -plane[1];
1186                                 plane[2] = -plane[2];
1187                                 plane[3] = -plane[3];
1188                         }
1189
1190                         // now we've got the plane to check against
1191                         front = DotProduct(start, plane) + plane[3];
1192                         back = DotProduct(end, plane) + plane[3];
1193
1194                         // if the whole move is at one side of the plane
1195                         if (front < TINY_EPSILON && back < TINY_EPSILON) {
1196                                 continue;
1197                         }
1198
1199                         if (front > -TINY_EPSILON && back > -TINY_EPSILON) {
1200                                 continue;
1201                         }
1202
1203                         // if there's no movement orthogonal to this plane at all
1204                         if ( idMath::Fabs(front - back) < 0.001f ) {
1205                                 continue;
1206                         }
1207
1208                         // ok first only move till the plane is hit
1209                         frac = front / (front - back);
1210                         if (frac < smallestfrac) {
1211                                 mid[0] = start[0] + (end[0] - start[0]) * frac;
1212                                 mid[1] = start[1] + (end[1] - start[1]) * frac;
1213                                 mid[2] = start[2] + (end[2] - start[2]) * frac;
1214                                 smallestfrac = frac;
1215                         }
1216
1217                         done = false;
1218                 }
1219
1220                 // move the vertex
1221                 for (i = 0; i < nummovefaces; i++) {
1222                         // move vertex to end position
1223                         VectorCopy( mid, (*movefaces[i]->face_winding)[movefacepoints[i]] );
1224
1225                         // create new face plane
1226                         for (j = 0; j < 3; j++) {
1227                                 VectorCopy( (*movefaces[i]->face_winding)[j], movefaces[i]->planepts[j] );
1228                         }
1229
1230                         Face_MakePlane( movefaces[i] );
1231                         if ( movefaces[i]->plane.Normal().Length() < TINY_EPSILON ) {
1232                                 result = false;
1233                         }
1234                 }
1235
1236                 // if the brush is no longer convex
1237                 if (!result || !Brush_Convex(b)) {
1238                         for (i = 0; i < nummovefaces; i++) {
1239                                 // move the vertex back to the initial position
1240                                 VectorCopy( start, (*movefaces[i]->face_winding)[movefacepoints[i]] );
1241
1242                                 // create new face plane
1243                                 for (j = 0; j < 3; j++) {
1244                                         VectorCopy( (*movefaces[i]->face_winding)[j], movefaces[i]->planepts[j] );
1245                                 }
1246
1247                                 Face_MakePlane(movefaces[i]);
1248                         }
1249
1250                         result = false;
1251                         VectorCopy(start, end);
1252                         done = true;
1253                 }
1254                 else {
1255                         VectorCopy(mid, start);
1256                 }
1257
1258                 // get texture crap right
1259                 for (i = 0; i < nummovefaces; i++) {
1260                         Face_SetColor( b, movefaces[i], 1.0f );
1261                         for (j = 0; j < movefaces[i]->face_winding->GetNumPoints(); j++) {
1262                                 EmitTextureCoordinates( (*movefaces[i]->face_winding)[j], movefaces[i]->d_texture, movefaces[i] );
1263                         }
1264                 }
1265
1266                 // now try to merge faces with their original faces
1267                 lastface = NULL;
1268                 for (face = b->brush_faces; face; face = nextface) {
1269                         nextface = face->next;
1270                         if (!face->original) {
1271                                 lastface = face;
1272                                 continue;
1273                         }
1274
1275                         if ( !face->plane.Compare( face->original->plane, 0.0001f ) ) {
1276                                 lastface = face;
1277                                 continue;
1278                         }
1279
1280                         w = face->face_winding->TryMerge( *face->original->face_winding, face->plane.Normal(), true );
1281                         if (!w) {
1282                                 lastface = face;
1283                                 continue;
1284                         }
1285
1286                         delete face->original->face_winding;
1287                         face->original->face_winding = w;
1288
1289                         // get texture crap right
1290                         Face_SetColor( b, face->original, 1.0f );
1291                         for (j = 0; j < face->original->face_winding->GetNumPoints(); j++) {
1292                                 EmitTextureCoordinates( (*face->original->face_winding)[j], face->original->d_texture, face->original);
1293                         }
1294
1295                         // remove the face that was merged with the original
1296                         if (lastface) {
1297                                 lastface->next = face->next;
1298                         }
1299                         else {
1300                                 b->brush_faces = face->next;
1301                         }
1302
1303                         Face_Free(face);
1304                 }
1305         }
1306
1307         return result;
1308 }
1309
1310 /*
1311 ================
1312 Brush_InsertVertexBetween
1313
1314   Adds a vertex to the brush windings between the given two points.
1315 ================
1316 */
1317 int Brush_InsertVertexBetween(brush_t *b, idVec3 p1, idVec3 p2) {
1318         face_t          *face;
1319         idWinding       *w, *neww;
1320         idVec3          point;
1321         int                     i, insert;
1322
1323         if ( p1.Compare( p2, TINY_EPSILON ) ) {
1324                 return false;
1325         }
1326
1327         VectorAdd( p1, p2, point );
1328         VectorScale( point, 0.5f, point );
1329         insert = false;
1330
1331         // the end point may not be the same as another vertex
1332         for (face = b->brush_faces; face; face = face->next) {
1333                 w = face->face_winding;
1334                 if (!w) {
1335                         continue;
1336                 }
1337
1338                 neww = NULL;
1339                 for (i = 0; i < w->GetNumPoints(); i++) {
1340                         if (! p1.Compare((*w)[i].ToVec3(), TINY_EPSILON)) {
1341                                 continue;
1342                         }
1343
1344                         if ( p2.Compare( (*w)[(i + 1) % w->GetNumPoints()].ToVec3(), TINY_EPSILON ) ) {
1345                                 neww = new idWinding( *w );
1346                                 neww->InsertPoint( point, (i + 1) % w->GetNumPoints() );
1347                                 break;
1348                         }
1349                         else if ( p2.Compare( (*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()].ToVec3(), TINY_EPSILON ) ) {
1350                                 neww = new idWinding( *w );
1351                                 neww->InsertPoint( point, i );
1352                                 break;
1353                         }
1354                 }
1355
1356                 if (neww) {
1357                         delete face->face_winding;
1358                         face->face_winding = neww;
1359                         insert = true;
1360                 }
1361         }
1362
1363         return insert;
1364 }
1365
1366 /*
1367 ================
1368 Brush_ResetFaceOriginals
1369
1370   reset points to original faces to NULL
1371 ================
1372 */
1373 void Brush_ResetFaceOriginals(brush_t *b) {
1374         face_t  *face;
1375
1376         for (face = b->brush_faces; face; face = face->next) {
1377                 face->original = NULL;
1378         }
1379 }
1380
1381 /*
1382 ================
1383 Brush_Parse
1384
1385   The brush is NOT linked to any list
1386   FIXME: when using old brush primitives, the test loop for "Brush" and "patchDef2" "patchDef3"
1387   run before each face parsing. It works, but it's a performance hit
1388 ================
1389 */
1390 brush_t *Brush_Parse(idVec3 origin) {
1391         brush_t *b;
1392         face_t  *f;
1393         int             i, j;
1394         idVec3  useOrigin = origin;
1395
1396         g_qeglobals.d_parsed_brushes++;
1397         b = Brush_Alloc();
1398         do {
1399                 if (!GetToken(true)) {
1400                         break;
1401                 }
1402
1403                 if (!strcmp(token, "}")) {
1404                         break;
1405                 }
1406
1407                 // handle "Brush" primitive
1408                 if ( idStr::Icmp(token, "brushDef") == 0 || idStr::Icmp(token, "brushDef2") == 0 || idStr::Icmp(token, "brushDef3") == 0 ) {
1409                         // Timo parsing new brush format
1410                         g_qeglobals.bPrimitBrushes = true;
1411
1412                         // check the map is not mixing the two kinds of brushes
1413                         if (g_qeglobals.m_bBrushPrimitMode) {
1414                                 if (g_qeglobals.bOldBrushes) {
1415                                         common->Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
1416                                 }
1417                         }
1418                         else {
1419                                 // ++Timo write new brush primitive -> old conversion code for Q3->Q2 conversions ?
1420                                 common->Printf("Warning : conversion code from brush primitive not done ( Brush_Parse )\n");
1421                         }
1422
1423                         bool    newFormat = false;
1424                         if ( idStr::Icmp(token, "brushDef2") == 0 ) {
1425                                 newFormat = true;
1426
1427                                 // useOrigin.Zero();
1428                         }
1429                         else if ( idStr::Icmp(token, "brushDef3") == 0 ) {
1430                                 newFormat = true;
1431                         }
1432
1433
1434                         BrushPrimit_Parse(b, newFormat, useOrigin);
1435
1436                         if (newFormat) {
1437                                 //Brush_BuildWindings(b, true, true, false, false);
1438                         }
1439                         
1440                         if (b == NULL) {
1441                                 Warning("parsing brush primitive");
1442                                 return NULL;
1443                         }
1444                         else {
1445                                 continue;
1446                         }
1447                 }
1448
1449                 if ( idStr::Icmp(token, "patchDef2") == 0 || idStr::Icmp(token, "patchDef3") == 0 ) {
1450                         Brush_Free(b);
1451
1452                         // double string compare but will go away soon
1453                         b = Patch_Parse( idStr::Icmp(token, "patchDef2") == 0 );
1454                         if (b == NULL) {
1455                                 Warning("parsing patch/brush");
1456                                 return NULL;
1457                         }
1458                         else {
1459                                 continue;
1460                         }
1461
1462                         // handle inline patch
1463                 }
1464                 else {
1465                         // Timo parsing old brush format
1466                         g_qeglobals.bOldBrushes = true;
1467                         if (g_qeglobals.m_bBrushPrimitMode) {
1468                                 // check the map is not mixing the two kinds of brushes
1469                                 if (g_qeglobals.bPrimitBrushes) {
1470                                         common->Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
1471                                 }
1472
1473                                 // set the "need" conversion flag
1474                                 g_qeglobals.bNeedConvert = true;
1475                         }
1476
1477                         f = Face_Alloc();
1478
1479                         //
1480                         // add the brush to the end of the chain, so loading and saving a map doesn't
1481                         // reverse the order
1482                         //
1483                         f->next = NULL;
1484                         if (!b->brush_faces) {
1485                                 b->brush_faces = f;
1486                         }
1487                         else {
1488                                 face_t  *scan;
1489                                 for (scan = b->brush_faces; scan->next; scan = scan->next)
1490                                         ;
1491                                 scan->next = f;
1492                         }
1493
1494                         // read the three point plane definition
1495                         for (i = 0; i < 3; i++) {
1496                                 if (i != 0) {
1497                                         GetToken(true);
1498                                 }
1499
1500                                 if (strcmp(token, "(")) {
1501                                         Warning("parsing brush");
1502                                         return NULL;
1503                                 }
1504
1505                                 for (j = 0; j < 3; j++) {
1506                                         GetToken(false);
1507                                         f->planepts[i][j] = atof(token);
1508                                 }
1509
1510                                 GetToken(false);
1511                                 if (strcmp(token, ")")) {
1512                                         Warning("parsing brush");
1513                                         return NULL;
1514                                 }
1515                         }
1516                 }
1517
1518                 // read the texturedef
1519                 GetToken(false);
1520                 f->texdef.SetName(token);
1521                 if (token[0] == '(') {
1522                         int i = 32;
1523                 }
1524
1525                 GetToken(false);
1526                 f->texdef.shift[0] = atoi(token);
1527                 GetToken(false);
1528                 f->texdef.shift[1] = atoi(token);
1529                 GetToken(false);
1530                 f->texdef.rotate = atoi(token);
1531                 GetToken(false);
1532                 f->texdef.scale[0] = atof(token);
1533                 GetToken(false);
1534                 f->texdef.scale[1] = atof(token);
1535
1536                 // the flags and value field aren't necessarily present
1537                 f->d_texture = Texture_ForName(f->texdef.name);
1538
1539                 //
1540                 // FIXME: idMaterial f->texdef.flags = f->d_texture->flags; f->texdef.value =
1541                 // f->d_texture->value; f->texdef.contents = f->d_texture->contents;
1542                 //
1543                 if (TokenAvailable()) {
1544                         GetToken(false);
1545                         GetToken(false);
1546                         GetToken(false);
1547                         f->texdef.value = atoi(token);
1548                 }
1549         } while (1);
1550
1551         return b;
1552 }
1553
1554 /*
1555 ================
1556 QERApp_MapPrintf_FILE
1557
1558   callback for surface properties plugin must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
1559   carefully initialize !
1560 ================
1561 */
1562 FILE    *g_File;
1563
1564 void WINAPI QERApp_MapPrintf_FILE(char *text, ...) {
1565         va_list argptr;
1566         char    buf[32768];
1567
1568         va_start(argptr, text);
1569         vsprintf(buf, text, argptr);
1570         va_end(argptr);
1571
1572         fprintf(g_File, buf);
1573 }
1574
1575 /*
1576 ================
1577 Brush_SetEpair
1578
1579   sets an epair for the given brush
1580 ================
1581 */
1582 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) {
1583         if (g_qeglobals.m_bBrushPrimitMode) {
1584                 if (b->pPatch) {
1585                         Patch_SetEpair(b->pPatch, pKey, pValue);
1586                 }
1587                 else {
1588                         b->epairs.Set(pKey, pValue);
1589                 }
1590         }
1591         else {
1592                 Sys_Status("Can only set key/values in Brush primitive mode\n");
1593         }
1594 }
1595
1596 /*
1597 ================
1598 Brush_GetKeyValue
1599 ================
1600 */
1601 const char *Brush_GetKeyValue(brush_t *b, const char *pKey) {
1602         if (g_qeglobals.m_bBrushPrimitMode) {
1603                 if (b->pPatch) {
1604                         return Patch_GetKeyValue(b->pPatch, pKey);
1605                 }
1606                 else {
1607                         return b->epairs.GetString(pKey);
1608                 }
1609         }
1610         else {
1611                 Sys_Status("Can only set brush/patch key/values in Brush primitive mode\n");
1612         }
1613
1614         return "";
1615 }
1616
1617 /*
1618 ================
1619 Brush_Write
1620
1621         save all brushes as Brush primitive format
1622 ================
1623 */
1624 void Brush_Write(brush_t *b, FILE *f, const idVec3 &origin, bool newFormat) {
1625         face_t  *fa;
1626         char    *pname;
1627         int             i;
1628
1629         if (b->pPatch) {
1630                 Patch_Write(b->pPatch, f);
1631                 return;
1632         }
1633
1634         if (g_qeglobals.m_bBrushPrimitMode) {
1635                 // save brush primitive format
1636                 if (newFormat) {
1637                         WriteFileString(f, "{\nbrushDef3\n{\n");
1638                 }
1639                 else {
1640                         WriteFileString(f, "{\nbrushDef\n{\n");
1641                 }
1642
1643                 // brush epairs
1644                 int count = b->epairs.GetNumKeyVals();
1645                 for (int j = 0; j < count; j++) {
1646                         WriteFileString(f, "\"%s\" \"%s\"\n", b->epairs.GetKeyVal(j)->GetKey().c_str(), b->epairs.GetKeyVal(j)->GetValue().c_str());
1647                 }
1648
1649                 for (fa = b->brush_faces; fa; fa = fa->next) {
1650                         // save planepts
1651                         if (newFormat) {
1652                                 idPlane plane;
1653
1654                                 if (fa->dirty) {
1655                                         fa->planepts[0] -= origin;
1656                                         fa->planepts[1] -= origin;
1657                                         fa->planepts[2] -= origin;
1658                                         plane.FromPoints( fa->planepts[0], fa->planepts[1], fa->planepts[2], false );
1659                                         fa->planepts[0] += origin;
1660                                         fa->planepts[1] += origin;
1661                                         fa->planepts[2] += origin;
1662                                 } else {
1663                                         plane = fa->originalPlane;
1664                                 }
1665
1666                                 WriteFileString(f, " ( ");
1667                                 for (i = 0; i < 4; i++) {
1668                                         if (plane[i] == (int)plane[i]) {
1669                                                 WriteFileString(f, "%i ", (int)plane[i]);
1670                                         }
1671                                         else {
1672                                                 WriteFileString(f, "%f ", plane[i]);
1673                                         }
1674                                 }
1675
1676                                 WriteFileString(f, ") ");
1677                         }
1678                         else {
1679                                 for (i = 0; i < 3; i++) {
1680                                         WriteFileString(f, "( ");
1681                                         for (int j = 0; j < 3; j++) {
1682                                                 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1683                                                         WriteFileString(f, "%i ", static_cast<int>(fa->planepts[i][j]));
1684                                                 }
1685                                                 else {
1686                                                         WriteFileString(f, "%f ", fa->planepts[i][j]);
1687                                                 }
1688                                         }
1689
1690                                         WriteFileString(f, ") ");
1691                                 }
1692                         }
1693
1694                         // save texture coordinates
1695                         WriteFileString(f, "( ( ");
1696                         for (i = 0; i < 3; i++) {
1697                                 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) {
1698                                         WriteFileString(f, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
1699                                 }
1700                                 else {
1701                                         WriteFileString(f, "%f ", fa->brushprimit_texdef.coords[0][i]);
1702                                 }
1703                         }
1704
1705                         WriteFileString(f, ") ( ");
1706                         for (i = 0; i < 3; i++) {
1707                                 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) {
1708                                         WriteFileString(f, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
1709                                 }
1710                                 else {
1711                                         WriteFileString(f, "%f ", fa->brushprimit_texdef.coords[1][i]);
1712                                 }
1713                         }
1714
1715                         WriteFileString(f, ") ) ");
1716
1717                         char    *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "notexture";
1718                         WriteFileString(f, "\"%s\" ", pName);
1719                         WriteFileString(f, "%i %i %i\n", 0, 0, 0);
1720                 }
1721
1722                 WriteFileString(f, "}\n}\n");
1723         }
1724         else {
1725                 WriteFileString(f, "{\n");
1726                 for (fa = b->brush_faces; fa; fa = fa->next) {
1727                         for (i = 0; i < 3; i++) {
1728                                 WriteFileString(f, "( ");
1729                                 for (int j = 0; j < 3; j++) {
1730                                         if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1731                                                 WriteFileString(f, "%i ", static_cast<int>(fa->planepts[i][j]));
1732                                         }
1733                                         else {
1734                                                 WriteFileString(f, "%f ", fa->planepts[i][j]);
1735                                         }
1736                                 }
1737
1738                                 WriteFileString(f, ") ");
1739                         }
1740
1741                         pname = fa->texdef.name;
1742                         if (pname[0] == 0) {
1743                                 pname = "unnamed";
1744                         }
1745
1746                         WriteFileString
1747                         (
1748                                 f,
1749                                 "%s %i %i %i ",
1750                                 pname,
1751                                 (int)fa->texdef.shift[0],
1752                                 (int)fa->texdef.shift[1],
1753                                 (int)fa->texdef.rotate
1754                         );
1755
1756                         if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) {
1757                                 WriteFileString(f, "%i ", (int)fa->texdef.scale[0]);
1758                         }
1759                         else {
1760                                 WriteFileString(f, "%f ", (float)fa->texdef.scale[0]);
1761                         }
1762
1763                         if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) {
1764                                 WriteFileString(f, "%i", (int)fa->texdef.scale[1]);
1765                         }
1766                         else {
1767                                 WriteFileString(f, "%f", (float)fa->texdef.scale[1]);
1768                         }
1769
1770                         WriteFileString(f, " %i %i %i",0, 0, 0);
1771
1772                         WriteFileString(f, "\n");
1773                 }
1774
1775                 WriteFileString(f, "}\n");
1776         }
1777 }
1778
1779 /*
1780 ================
1781 QERApp_MapPrintf_MEMFILE
1782
1783   callback for surface properties plugin must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
1784   carefully initialize !
1785 ================
1786 */
1787 CMemFile        *g_pMemFile;
1788
1789 void WINAPI QERApp_MapPrintf_MEMFILE(char *text, ...) {
1790         va_list argptr;
1791         char    buf[32768];
1792
1793         va_start(argptr, text);
1794         vsprintf(buf, text, argptr);
1795         va_end(argptr);
1796
1797         MemFile_fprintf(g_pMemFile, buf);
1798 }
1799
1800 /*
1801 ================
1802 Brush_Write
1803
1804   save all brushes as Brush primitive format to a CMemFile*
1805 ================
1806 */
1807 void Brush_Write(brush_t *b, CMemFile *pMemFile, const idVec3 &origin, bool newFormat) {
1808         face_t  *fa;
1809         char    *pname;
1810         int             i;
1811
1812         if (b->pPatch) {
1813                 Patch_Write(b->pPatch, pMemFile);
1814                 return;
1815         }
1816
1817         if (g_qeglobals.m_bBrushPrimitMode) {
1818                 // brush primitive format
1819                 if (newFormat) {
1820                         MemFile_fprintf(pMemFile, "{\nBrushDef2\n{\n");
1821                 }
1822                 else {
1823                         MemFile_fprintf(pMemFile, "{\nBrushDef\n{\n");
1824                 }
1825
1826                 // brush epairs
1827                 // brush epairs
1828                 int count = b->epairs.GetNumKeyVals();
1829                 for (int j = 0; j < count; j++) {
1830                         MemFile_fprintf(pMemFile, "\"%s\" \"%s\"\n", b->epairs.GetKeyVal(j)->GetKey().c_str(), b->epairs.GetKeyVal(j)->GetValue().c_str());
1831                 }
1832
1833                 for (fa = b->brush_faces; fa; fa = fa->next) {
1834                         if (newFormat) {
1835                                 // save planepts
1836                                 idPlane plane;
1837
1838                                 if (fa->dirty) {
1839                                         fa->planepts[0] -= origin;
1840                                         fa->planepts[1] -= origin;
1841                                         fa->planepts[2] -= origin;
1842                                         plane.FromPoints( fa->planepts[0], fa->planepts[1], fa->planepts[2], false );
1843                                         fa->planepts[0] += origin;
1844                                         fa->planepts[1] += origin;
1845                                         fa->planepts[2] += origin;
1846                                 } else {
1847                                         plane = fa->originalPlane;
1848                                 }
1849
1850                                 MemFile_fprintf(pMemFile, " ( ");
1851                                 for (i = 0; i < 4; i++) {
1852                                         if (plane[i] == (int)plane[i]) {
1853                                                 MemFile_fprintf(pMemFile, "%i ", (int)plane[i]);
1854                                         }
1855                                         else {
1856                                                 MemFile_fprintf(pMemFile, "%f ", plane[i]);
1857                                         }
1858                                 }
1859
1860                                 MemFile_fprintf(pMemFile, ") ");
1861                         }
1862                         else {
1863                                 for (i = 0; i < 3; i++) {
1864                                         MemFile_fprintf(pMemFile, "( ");
1865                                         for (int j = 0; j < 3; j++) {
1866                                                 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1867                                                         MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
1868                                                 }
1869                                                 else {
1870                                                         MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
1871                                                 }
1872                                         }
1873
1874                                         MemFile_fprintf(pMemFile, ") ");
1875                                 }
1876                         }
1877
1878                         // save texture coordinates
1879                         MemFile_fprintf(pMemFile, "( ( ");
1880                         for (i = 0; i < 3; i++) {
1881                                 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) {
1882                                         MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
1883                                 }
1884                                 else {
1885                                         MemFile_fprintf(pMemFile, "%f ", fa->brushprimit_texdef.coords[0][i]);
1886                                 }
1887                         }
1888
1889                         MemFile_fprintf(pMemFile, ") ( ");
1890                         for (i = 0; i < 3; i++) {
1891                                 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) {
1892                                         MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
1893                                 }
1894                                 else {
1895                                         MemFile_fprintf(pMemFile, "%f ", fa->brushprimit_texdef.coords[1][i]);
1896                                 }
1897                         }
1898
1899                         MemFile_fprintf(pMemFile, ") ) ");
1900
1901                         // save texture attribs
1902                         char    *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "unnamed";
1903                         MemFile_fprintf(pMemFile, "\"%s\" ", pName);
1904                         MemFile_fprintf(pMemFile, "%i %i %i\n", 0, 0, 0);
1905                 }
1906
1907                 MemFile_fprintf(pMemFile, "}\n}\n");
1908         }
1909         else {
1910                 // old brushes format also handle surface properties plugin
1911                 MemFile_fprintf(pMemFile, "{\n");
1912                 for (fa = b->brush_faces; fa; fa = fa->next) {
1913                         for (i = 0; i < 3; i++) {
1914                                 MemFile_fprintf(pMemFile, "( ");
1915                                 for (int j = 0; j < 3; j++) {
1916                                         if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1917                                                 MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
1918                                         }
1919                                         else {
1920                                                 MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
1921                                         }
1922                                 }
1923
1924                                 MemFile_fprintf(pMemFile, ") ");
1925                         }
1926
1927                         pname = fa->texdef.name;
1928                         if (pname[0] == 0) {
1929                                 pname = "unnamed";
1930                         }
1931
1932                         MemFile_fprintf
1933                         (
1934                                 pMemFile,
1935                                 "%s %i %i %i ",
1936                                 pname,
1937                                 (int)fa->texdef.shift[0],
1938                                 (int)fa->texdef.shift[1],
1939                                 (int)fa->texdef.rotate
1940                         );
1941
1942                         if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) {
1943                                 MemFile_fprintf(pMemFile, "%i ", (int)fa->texdef.scale[0]);
1944                         }
1945                         else {
1946                                 MemFile_fprintf(pMemFile, "%f ", (float)fa->texdef.scale[0]);
1947                         }
1948
1949                         if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) {
1950                                 MemFile_fprintf(pMemFile, "%i", (int)fa->texdef.scale[1]);
1951                         }
1952                         else {
1953                                 MemFile_fprintf(pMemFile, "%f", (float)fa->texdef.scale[1]);
1954                         }
1955
1956                         MemFile_fprintf(pMemFile, " %i %i %i", 0, 0, 0);
1957
1958                         MemFile_fprintf(pMemFile, "\n");
1959                 }
1960
1961                 MemFile_fprintf(pMemFile, "}\n");
1962         }
1963 }
1964
1965 /*
1966 ================
1967 Brush_Create
1968
1969   Create non-textured blocks for entities The brush is NOT linked to any list
1970 ================
1971 */
1972 brush_t *Brush_Create(idVec3 mins, idVec3 maxs, texdef_t *texdef) {
1973         int             i, j;
1974         idVec3  pts[4][2];
1975         face_t  *f;
1976         brush_t *b;
1977
1978         //
1979         // brush primitive mode : convert texdef to brushprimit_texdef ? most of the time
1980         // texdef is empty
1981         //
1982         for (i = 0; i < 3; i++) {
1983                 if (maxs[i] < mins[i]) {
1984                         Error("Brush_InitSolid: backwards");
1985                 }
1986         }
1987
1988         b = Brush_Alloc();
1989
1990         pts[0][0][0] = mins[0];
1991         pts[0][0][1] = mins[1];
1992
1993         pts[1][0][0] = mins[0];
1994         pts[1][0][1] = maxs[1];
1995
1996         pts[2][0][0] = maxs[0];
1997         pts[2][0][1] = maxs[1];
1998
1999         pts[3][0][0] = maxs[0];
2000         pts[3][0][1] = mins[1];
2001
2002         for (i = 0; i < 4; i++) {
2003                 pts[i][0][2] = mins[2];
2004                 pts[i][1][0] = pts[i][0][0];
2005                 pts[i][1][1] = pts[i][0][1];
2006                 pts[i][1][2] = maxs[2];
2007         }
2008
2009         for (i = 0; i < 4; i++) {
2010                 f = Face_Alloc();
2011                 f->texdef = *texdef;
2012                 f->next = b->brush_faces;
2013                 b->brush_faces = f;
2014                 j = (i + 1) % 4;
2015
2016                 VectorCopy(pts[j][1], f->planepts[0]);
2017                 VectorCopy(pts[i][1], f->planepts[1]);
2018                 VectorCopy(pts[i][0], f->planepts[2]);
2019         }
2020
2021         f = Face_Alloc();
2022         f->texdef = *texdef;
2023         f->next = b->brush_faces;
2024         b->brush_faces = f;
2025
2026         VectorCopy(pts[0][1], f->planepts[0]);
2027         VectorCopy(pts[1][1], f->planepts[1]);
2028         VectorCopy(pts[2][1], f->planepts[2]);
2029
2030         f = Face_Alloc();
2031         f->texdef = *texdef;
2032         f->next = b->brush_faces;
2033         b->brush_faces = f;
2034
2035         VectorCopy(pts[2][0], f->planepts[0]);
2036         VectorCopy(pts[1][0], f->planepts[1]);
2037         VectorCopy(pts[0][0], f->planepts[2]);
2038
2039         return b;
2040 }
2041
2042 /*
2043 =============
2044 Brush_Scale
2045 =============
2046 */
2047 void Brush_Scale(brush_t* b) {
2048         for ( face_t *f = b->brush_faces; f; f = f->next ) {
2049                 for ( int i = 0; i < 3; i++ ) {
2050                         VectorScale( f->planepts[i], g_qeglobals.d_gridsize, f->planepts[i] );
2051                 }
2052         }
2053 }
2054
2055 /*
2056 ================
2057 Brush_CreatePyramid
2058
2059   Create non-textured pyramid for light entities The brush is NOT linked to any list
2060 ================
2061 */
2062 brush_t *Brush_CreatePyramid(idVec3 mins, idVec3 maxs, texdef_t *texdef) {
2063         // ++timo handle new brush primitive ? return here ??
2064         return Brush_Create(mins, maxs, texdef);
2065
2066         int i;
2067         for (i = 0; i < 3; i++) {
2068                 if (maxs[i] < mins[i]) {
2069                         Error("Brush_InitSolid: backwards");
2070                 }
2071         }
2072
2073         brush_t *b = Brush_Alloc();
2074
2075         idVec3  corners[4];
2076
2077         float   fMid = idMath::Rint(mins[2] + (idMath::Rint((maxs[2] - mins[2]) / 2)));
2078
2079         corners[0][0] = mins[0];
2080         corners[0][1] = mins[1];
2081         corners[0][2] = fMid;
2082
2083         corners[1][0] = mins[0];
2084         corners[1][1] = maxs[1];
2085         corners[1][2] = fMid;
2086
2087         corners[2][0] = maxs[0];
2088         corners[2][1] = maxs[1];
2089         corners[2][2] = fMid;
2090
2091         corners[3][0] = maxs[0];
2092         corners[3][1] = mins[1];
2093         corners[3][2] = fMid;
2094
2095         idVec3  top, bottom;
2096
2097         top[0] = idMath::Rint(mins[0] + ((maxs[0] - mins[0]) / 2));
2098         top[1] = idMath::Rint(mins[1] + ((maxs[1] - mins[1]) / 2));
2099         top[2] = idMath::Rint(maxs[2]);
2100
2101         VectorCopy(top, bottom);
2102         bottom[2] = mins[2];
2103
2104         // sides
2105         for (i = 0; i < 4; i++) {
2106                 face_t  *f = Face_Alloc();
2107                 f->texdef = *texdef;
2108                 f->next = b->brush_faces;
2109                 b->brush_faces = f;
2110
2111                 int j = (i + 1) % 4;
2112
2113                 VectorCopy(top, f->planepts[0]);
2114                 VectorCopy(corners[i], f->planepts[1]);
2115                 VectorCopy(corners[j], f->planepts[2]);
2116
2117                 f = Face_Alloc();
2118                 f->texdef = *texdef;
2119                 f->next = b->brush_faces;
2120                 b->brush_faces = f;
2121
2122                 VectorCopy(bottom, f->planepts[2]);
2123                 VectorCopy(corners[i], f->planepts[1]);
2124                 VectorCopy(corners[j], f->planepts[0]);
2125         }
2126
2127         return b;
2128 }
2129
2130 /*
2131 ================
2132 Brush_MakeSided
2133
2134   Makes the current brush have the given number of 2d sides
2135 ================
2136 */
2137 void Brush_MakeSided(int sides) {
2138         int                     i, axis;
2139         idVec3          mins, maxs;
2140         brush_t         *b;
2141         texdef_t        *texdef;
2142         face_t          *f;
2143         idVec3          mid;
2144         float           width;
2145         float           sv, cv;
2146
2147         if (sides < 3) {
2148                 Sys_Status("Bad sides number", 0);
2149                 return;
2150         }
2151
2152         if (sides >= MAX_POINTS_ON_WINDING - 4) {
2153                 Sys_Status("too many sides.\n");
2154                 return;
2155         }
2156
2157         if (!QE_SingleBrush()) {
2158                 Sys_Status("Must have a single brush selected", 0);
2159                 return;
2160         }
2161
2162         b = selected_brushes.next;
2163         VectorCopy(b->mins, mins);
2164         VectorCopy(b->maxs, maxs);
2165         texdef = &g_qeglobals.d_texturewin.texdef;
2166
2167         Brush_Free(b);
2168
2169         if (g_pParentWnd->ActiveXY()) {
2170                 switch (g_pParentWnd->ActiveXY()->GetViewType())
2171                 {
2172                         case XY:
2173                                 axis = 2;
2174                                 break;
2175                         case XZ:
2176                                 axis = 1;
2177                                 break;
2178                         case YZ:
2179                                 axis = 0;
2180                                 break;
2181                 }
2182         }
2183         else {
2184                 axis = 2;
2185         }
2186
2187         // find center of brush
2188         width = 8;
2189         for (i = 0; i < 3; i++) {
2190                 mid[i] = (maxs[i] + mins[i]) * 0.5f;
2191                 if (i == axis) {
2192                         continue;
2193                 }
2194
2195                 if ((maxs[i] - mins[i]) * 0.5f > width) {
2196                         width = (maxs[i] - mins[i]) * 0.5f;
2197                 }
2198         }
2199
2200         b = Brush_Alloc();
2201
2202         // create top face
2203         f = Face_Alloc();
2204         f->texdef = *texdef;
2205         f->next = b->brush_faces;
2206         b->brush_faces = f;
2207
2208         f->planepts[2][(axis + 1) % 3] = mins[(axis + 1) % 3];
2209         f->planepts[2][(axis + 2) % 3] = mins[(axis + 2) % 3];
2210         f->planepts[2][axis] = maxs[axis];
2211         f->planepts[1][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2212         f->planepts[1][(axis + 2) % 3] = mins[(axis + 2) % 3];
2213         f->planepts[1][axis] = maxs[axis];
2214         f->planepts[0][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2215         f->planepts[0][(axis + 2) % 3] = maxs[(axis + 2) % 3];
2216         f->planepts[0][axis] = maxs[axis];
2217
2218         // create bottom face
2219         f = Face_Alloc();
2220         f->texdef = *texdef;
2221         f->next = b->brush_faces;
2222         b->brush_faces = f;
2223
2224         f->planepts[0][(axis + 1) % 3] = mins[(axis + 1) % 3];
2225         f->planepts[0][(axis + 2) % 3] = mins[(axis + 2) % 3];
2226         f->planepts[0][axis] = mins[axis];
2227         f->planepts[1][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2228         f->planepts[1][(axis + 2) % 3] = mins[(axis + 2) % 3];
2229         f->planepts[1][axis] = mins[axis];
2230         f->planepts[2][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2231         f->planepts[2][(axis + 2) % 3] = maxs[(axis + 2) % 3];
2232         f->planepts[2][axis] = mins[axis];
2233
2234         for (i = 0; i < sides; i++) {
2235                 f = Face_Alloc();
2236                 f->texdef = *texdef;
2237                 f->next = b->brush_faces;
2238                 b->brush_faces = f;
2239
2240                 sv = sin(i * 3.14159265 * 2 / sides);
2241                 cv = cos(i * 3.14159265 * 2 / sides);
2242
2243                 f->planepts[0][(axis + 1) % 3] = floor(mid[(axis + 1) % 3] + width * cv + 0.5f);
2244                 f->planepts[0][(axis + 2) % 3] = floor(mid[(axis + 2) % 3] + width * sv + 0.5f);
2245                 f->planepts[0][axis] = mins[axis];
2246
2247                 f->planepts[1][(axis + 1) % 3] = f->planepts[0][(axis + 1) % 3];
2248                 f->planepts[1][(axis + 2) % 3] = f->planepts[0][(axis + 2) % 3];
2249                 f->planepts[1][axis] = maxs[axis];
2250
2251                 f->planepts[2][(axis + 1) % 3] = floor(f->planepts[0][(axis + 1) % 3] - width * sv + 0.5f);
2252                 f->planepts[2][(axis + 2) % 3] = floor(f->planepts[0][(axis + 2) % 3] + width * cv + 0.5f);
2253                 f->planepts[2][axis] = maxs[axis];
2254         }
2255
2256         Brush_AddToList(b, &selected_brushes);
2257
2258         Entity_LinkBrush(world_entity, b);
2259
2260         Brush_Build(b);
2261
2262         Sys_UpdateWindows(W_ALL);
2263 }
2264
2265 /*
2266 ================
2267 Brush_Free
2268
2269   Frees the brush with all of its faces and display list.
2270   Unlinks the brush from whichever chain it is in.
2271   Decrements the owner entity's brushcount.
2272   Removes owner entity if this was the last brush unless owner is the world.
2273   Removes from groups
2274
2275   set bRemoveNode to false to avoid trying to delete the item in group view tree control
2276 ================
2277 */
2278 void Brush_Free(brush_t *b, bool bRemoveNode) {
2279         face_t  *f, *next;
2280
2281         // free the patch if it's there
2282         if ( b->pPatch ) {
2283                 Patch_Delete(b->pPatch);
2284         }
2285
2286         // free faces
2287         for ( f = b->brush_faces; f; f = next ) {
2288                 next = f->next;
2289                 Face_Free(f);
2290         }
2291
2292         b->epairs.Clear();
2293
2294         // unlink from active/selected list
2295         if ( b->next ) {
2296                 Brush_RemoveFromList(b);
2297         }
2298
2299         // unlink from entity list
2300         if ( b->onext ) {
2301                 Entity_UnlinkBrush(b);
2302         }
2303
2304         delete b;
2305 }
2306
2307 /*
2308 ================
2309 Face_MemorySize
2310
2311   returns the size in memory of the face
2312 ================
2313 */
2314 int Face_MemorySize(face_t *f) {
2315         int size = 0;
2316
2317         if ( f->face_winding ) {
2318                 size += sizeof( idWinding ) + f->face_winding->GetNumPoints() * sizeof( (f->face_winding)[0] );
2319         }
2320         size += sizeof( face_t );
2321         return size;
2322 }
2323
2324 /*
2325 ================
2326 Brush_MemorySize
2327
2328   returns the size in memory of the brush
2329 ================
2330 */
2331 int Brush_MemorySize( brush_t *b ) {
2332         face_t  *f;
2333         int             size = 0;
2334         if ( b->pPatch ) {
2335                 size += Patch_MemorySize( b->pPatch );
2336         }
2337
2338         for ( f = b->brush_faces; f; f = f->next ) {
2339                 size += Face_MemorySize(f);
2340         }
2341
2342         size += sizeof( brush_t ) + b->epairs.Size();
2343         return size;
2344 }
2345
2346 /*
2347 ================
2348 Brush_Clone
2349
2350   does not add the brush to any lists
2351 ================
2352 */
2353 brush_t *Brush_Clone(brush_t *b) {
2354         brush_t *n = NULL;
2355         face_t  *f, *nf;
2356
2357         if (b->pPatch) {
2358                 patchMesh_t *p = Patch_Duplicate(b->pPatch);
2359                 Brush_RemoveFromList(p->pSymbiot);
2360                 Entity_UnlinkBrush(p->pSymbiot);
2361                 n = p->pSymbiot;
2362         }
2363         else {
2364                 n = Brush_Alloc();
2365                 n->numberId = g_nBrushId++;
2366                 n->owner = b->owner;
2367                 n->lightColor = b->lightColor;
2368                 n->lightEnd = b->lightEnd;
2369                 n->lightOffset = b->lightOffset;
2370                 n->lightRadius = b->lightRadius;
2371                 n->lightRight = b->lightRight;
2372                 n->lightStart = b->lightStart;
2373                 n->lightTarget = b->lightTarget;
2374                 n->lightCenter = b->lightCenter;
2375                 n->lightTexture = b->lightTexture;
2376                 n->lightUp = b->lightUp;
2377                 n->modelHandle = b->modelHandle;
2378                 n->pointLight = b->pointLight;
2379                 for (f = b->brush_faces; f; f = f->next) {
2380                         nf = Face_Clone(f);
2381                         nf->next = n->brush_faces;
2382                         n->brush_faces = nf;
2383                 }
2384         }
2385
2386         return n;
2387 }
2388
2389 /*
2390 ================
2391 Brush_FullClone
2392
2393   Used by Undo.
2394   Makes an exact copy of the brush.
2395   Does NOT add the new brush to any lists.
2396 ================
2397 */
2398 brush_t *Brush_FullClone(brush_t *b) {
2399         brush_t *n = NULL;
2400         face_t  *f, *nf, *f2, *nf2;
2401         int             j;
2402
2403         if (b->pPatch) {
2404                 patchMesh_t *p = Patch_Duplicate(b->pPatch);
2405                 Brush_RemoveFromList(p->pSymbiot);
2406                 Entity_UnlinkBrush(p->pSymbiot);
2407                 n = p->pSymbiot;
2408                 n->owner = b->owner;
2409                 Brush_Build(n);
2410         }
2411         else {
2412                 n = Brush_Alloc();
2413                 n->numberId = g_nBrushId++;
2414                 n->owner = b->owner;
2415                 n->lightColor = b->lightColor;
2416                 n->lightEnd = b->lightEnd;
2417                 n->lightOffset = b->lightOffset;
2418                 n->lightRadius = b->lightRadius;
2419                 n->lightRight = b->lightRight;
2420                 n->lightStart = b->lightStart;
2421                 n->lightTarget = b->lightTarget;
2422                 n->lightCenter = b->lightCenter;
2423                 n->lightTexture = b->lightTexture;
2424                 n->lightUp = b->lightUp;
2425                 n->modelHandle = b->modelHandle;
2426                 n->pointLight = b->pointLight;
2427                 VectorCopy(b->mins, n->mins);
2428                 VectorCopy(b->maxs, n->maxs);
2429                 for (f = b->brush_faces; f; f = f->next) {
2430                         if (f->original) {
2431                                 continue;
2432                         }
2433
2434                         nf = Face_FullClone(f);
2435                         nf->next = n->brush_faces;
2436                         n->brush_faces = nf;
2437
2438                         // copy all faces that have the original set to this face
2439                         for (f2 = b->brush_faces; f2; f2 = f2->next) {
2440                                 if (f2->original == f) {
2441                                         nf2 = Face_FullClone(f2);
2442                                         nf2->next = n->brush_faces;
2443                                         n->brush_faces = nf2;
2444
2445                                         // set original
2446                                         nf2->original = nf;
2447                                 }
2448                         }
2449                 }
2450
2451                 for (nf = n->brush_faces; nf; nf = nf->next) {
2452                         Face_SetColor( n, nf, 1.0f );
2453                         if (nf->face_winding) {
2454                                 if (g_qeglobals.m_bBrushPrimitMode) {
2455                                         EmitBrushPrimitTextureCoordinates(nf, nf->face_winding);
2456                                 }
2457                                 else {
2458                                         for (j = 0; j < nf->face_winding->GetNumPoints(); j++) {
2459                                                 EmitTextureCoordinates( (*nf->face_winding)[j], nf->d_texture, nf );
2460                                         }
2461                                 }
2462                         }
2463                 }
2464         }
2465
2466         return n;
2467 }
2468
2469 extern bool GetMatrixForKey(entity_t *ent, const char *key, idMat3 &mat);
2470 extern bool Patch_Intersect(patchMesh_t *pm, idVec3 origin, idVec3 direction , float &scale);
2471 extern bool RayIntersectsTri
2472                         (
2473                                 const idVec3    &origin,
2474                                 const idVec3    &direction,
2475                                 const idVec3    &vert0,
2476                                 const idVec3    &vert1,
2477                                 const idVec3    &vert2,
2478                 float           &scale
2479                         );
2480
2481
2482 /*
2483 ================
2484 RotateVector
2485 ================
2486 */
2487 void RotateVector(idVec3 &v, idVec3 origin, float a, float c, float s) {
2488         float   x = v[0];
2489         float   y = v[1];
2490         if (a) {
2491                 float x2 = (((x - origin[0]) * c) - ((y - origin[1]) * s)) + origin[0];
2492                 float y2 = (((x - origin[0]) * s) + ((y - origin[1]) * c)) + origin[1];
2493                 x = x2;
2494                 y = y2;
2495         }
2496         v[0] = x;
2497         v[1] = y;
2498 }
2499 /*
2500 ================
2501 Brush_ModelIntersect
2502 ================
2503 */
2504
2505 bool Brush_ModelIntersect(brush_t *b, idVec3 origin, idVec3 dir,float &scale) {
2506         idRenderModel *model = b->modelHandle;
2507         idRenderModel *md5;
2508    
2509     if ( !model )
2510         model = b->owner->eclass->entityModel;
2511
2512     scale = 0;
2513         if (model) {
2514                 if ( model->IsDynamicModel() != DM_STATIC ) {
2515                         if ( dynamic_cast<idRenderModelMD5 *>( model ) ) {
2516                                 // take care of animated models
2517                                 md5 = b->owner->eclass->entityModel;
2518
2519                                 const char *classname = ValueForKey( b->owner, "classname" );
2520                                 if (stricmp(classname, "func_static") == 0) {
2521                                         classname = ValueForKey(b->owner, "animclass");
2522                                 }
2523                                 const char *anim = ValueForKey( b->owner, "anim" );
2524                                 int frame = IntForKey( b->owner, "frame" ) + 1;
2525                                 if ( frame < 1 ) {
2526                                         frame = 1;
2527                                 }
2528                                 if ( !anim || !anim[ 0 ] ) {
2529                                         anim = "idle";
2530                                 }
2531                                 model = gameEdit->ANIM_CreateMeshForAnim( md5, classname, anim, frame, false );
2532                                 if ( !model ) {
2533                                         model = renderModelManager->DefaultModel();
2534                                 }
2535                         }
2536                 }
2537
2538                 bool matrix = false;
2539                 idMat3 mat;
2540                 float a, s, c;
2541                 if (GetMatrixForKey(b->owner, "rotation", mat)) {
2542                         matrix = true;
2543                 } else {
2544                         a = FloatForKey(b->owner, "angle");
2545                         if (a) {
2546                                 s = sin( DEG2RAD( a ) );
2547                                 c = cos( DEG2RAD( a ) );
2548                         }
2549                         else {
2550                                 s = c = 0;
2551                         }
2552                 }
2553
2554                 for (int i = 0; i < model->NumSurfaces() ; i++) {
2555                         const modelSurface_t    *surf = model->Surface( i );
2556                         srfTriangles_t  *tri = surf->geometry;
2557                         for (int j = 0; j < tri->numIndexes; j += 3) {
2558                                 idVec3  v1, v2, v3;
2559                                 v1 = tri->verts[tri->indexes[j]].xyz;
2560                                 v2 = tri->verts[tri->indexes[j + 1]].xyz;
2561                                 v3 = tri->verts[tri->indexes[j + 2]].xyz;
2562
2563                                 if (matrix) {
2564                                         v1 *= b->owner->rotation;
2565                                         v1 += b->owner->origin;
2566                                         v2 *= b->owner->rotation;
2567                                         v2 += b->owner->origin;
2568                                         v3 *= b->owner->rotation;
2569                                         v3 += b->owner->origin;
2570                                 } else {
2571                                         v1 += b->owner->origin;
2572                                         v2 += b->owner->origin;
2573                                         v3 += b->owner->origin;
2574                                         RotateVector(v1, b->owner->origin, a, c, s);
2575                                         RotateVector(v2, b->owner->origin, a, c, s);
2576                                         RotateVector(v3, b->owner->origin, a, c, s);
2577                                 }
2578
2579                                 if (RayIntersectsTri(origin, dir, v1, v2, v3,scale)) {
2580                                         return true;
2581                                 }
2582                         }
2583                 }
2584         }
2585
2586         return false;
2587 }
2588
2589 face_t *Brush_Ray(idVec3 origin, idVec3 dir, brush_t *b, float *dist, bool testPrimitive) {
2590         face_t  *f, *firstface = NULL;
2591         idVec3  p1, p2;
2592         float   frac, d1, d2;
2593         int             i;
2594     float scale = HUGE_DISTANCE * 2;
2595         VectorCopy(origin, p1);
2596         for (i = 0; i < 3; i++) {
2597                 p2[i] = p1[i] + dir[i] * HUGE_DISTANCE * 2;
2598         }
2599
2600         for (f = b->brush_faces; f; f = f->next) {
2601                 d1 = DotProduct(p1, f->plane) + f->plane[3];
2602                 d2 = DotProduct(p2, f->plane) + f->plane[3];
2603                 if (d1 >= 0 && d2 >= 0) {
2604                         *dist = 0;
2605                         return NULL;    // ray is on front side of face
2606                 }
2607
2608                 if (d1 <= 0 && d2 <= 0) {
2609                         continue;
2610                 }
2611
2612                 // clip the ray to the plane
2613                 frac = d1 / (d1 - d2);
2614                 if (d1 > 0) {
2615                         firstface = f;
2616                         for (i = 0; i < 3; i++) {
2617                                 p1[i] = p1[i] + frac * (p2[i] - p1[i]);
2618                         }
2619                 }
2620                 else {
2621                         for (i = 0; i < 3; i++) {
2622                                 p2[i] = p1[i] + frac * (p2[i] - p1[i]);
2623                         }
2624                 }
2625         }
2626
2627         // find distance p1 is along dir
2628         VectorSubtract(p1, origin, p1);
2629         d1 = DotProduct(p1, dir);
2630
2631         if (testPrimitive && !g_PrefsDlg.m_selectByBoundingBrush) {
2632                 if (b->pPatch) {
2633                         if (!Patch_Intersect(b->pPatch, origin, dir, scale)) {
2634                                 *dist = 0;
2635                                 return NULL;
2636                         }
2637                 }
2638                 else if ( b->modelHandle != NULL && dynamic_cast<idRenderModelPrt*>( b->modelHandle ) == NULL && dynamic_cast< idRenderModelLiquid*> ( b->modelHandle ) == NULL ) {
2639                         if (!Brush_ModelIntersect(b, origin, dir, scale)) {
2640                                 *dist = 0;
2641                                 return NULL;
2642                         }
2643                 }
2644         }
2645
2646         *dist = d1;
2647         return firstface;
2648 }
2649
2650 /*
2651 ================
2652 Brush_Point
2653 ================
2654 */
2655 face_t *Brush_Point(idVec3 origin, brush_t *b) {
2656         face_t  *f;
2657         float   d1;
2658
2659         for (f = b->brush_faces; f; f = f->next) {
2660                 d1 = DotProduct(origin, f->plane) + f->plane[3];
2661                 if (d1 > 0) {
2662                         return NULL;    // point is on front side of face
2663                 }
2664         }
2665
2666         return b->brush_faces;
2667 }
2668
2669 /*
2670 ================
2671 Brush_AddToList
2672 ================
2673 */
2674 void Brush_AddToList(brush_t *b, brush_t *list) {
2675         if (b->next || b->prev) {
2676                 Error("Brush_AddToList: allready linked");
2677         }
2678
2679         if (list == &selected_brushes || list == &active_brushes) {
2680                 if (b->pPatch && list == &selected_brushes) {
2681                         Patch_Select(b->pPatch);
2682                 }
2683         }
2684
2685         b->list = list;
2686         b->next = list->next;
2687         list->next->prev = b;
2688         list->next = b;
2689         b->prev = list;
2690
2691 }
2692
2693 /*
2694 ================
2695 Brush_RemoveFromList
2696 ================
2697 */
2698 void Brush_RemoveFromList(brush_t *b) {
2699         if (!b->next || !b->prev) {
2700                 Error("Brush_RemoveFromList: not linked");
2701         }
2702
2703         if (b->pPatch) {
2704                 Patch_Deselect(b->pPatch);
2705
2706                 // Patch_Deselect(b->nPatchID);
2707         }
2708
2709         b->list = NULL;
2710         b->next->prev = b->prev;
2711         b->prev->next = b->next;
2712         b->next = b->prev = NULL;
2713 }
2714
2715 /*
2716 ================
2717 SetFaceTexdef
2718
2719   Doesn't set the curve flags.
2720   NOTE: never trust f->d_texture here, f->texdef and f->d_texture are out of sync when
2721   called by Brush_SetTexture use Texture_ForName() to find the right shader
2722   FIXME: send the right shader ( qtexture_t * ) in the parameters ?
2723   TTimo: surface plugin, added an IPluginTexdef* parameter if not NULL,
2724   get ->Copy() of it into the face ( and remember to hook ) if NULL, ask for a default
2725 ================
2726 */
2727 void SetFaceTexdef( brush_t *b, face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale ) {
2728
2729         if (g_qeglobals.m_bBrushPrimitMode) {
2730                 f->texdef = *texdef;
2731                 ConvertTexMatWithQTexture(brushprimit_texdef, NULL, &f->brushprimit_texdef, Texture_ForName(f->texdef.name));
2732         }
2733         else if (bFitScale) {
2734                 f->texdef = *texdef;
2735
2736                 // fit the scaling of the texture on the actual plane
2737                 idVec3  p1, p2, p3; // absolute coordinates
2738
2739                 // compute absolute coordinates
2740                 ComputeAbsolute(f, p1, p2, p3);
2741
2742                 // compute the scale
2743                 idVec3  vx, vy;
2744                 VectorSubtract(p2, p1, vx);
2745                 vx.Normalize();
2746                 VectorSubtract(p3, p1, vy);
2747                 vy.Normalize();
2748
2749                 // assign scale
2750                 VectorScale(vx, texdef->scale[0], vx);
2751                 VectorScale(vy, texdef->scale[1], vy);
2752                 VectorAdd(p1, vx, p2);
2753                 VectorAdd(p1, vy, p3);
2754
2755                 // compute back shift scale rot
2756                 AbsoluteToLocal(f->plane, f, p1, p2, p3);
2757         }
2758         else {
2759                 f->texdef = *texdef;
2760         }
2761
2762 }
2763
2764 /*
2765 ================
2766 Brush_SetTexture
2767 ================
2768 */
2769 void Brush_SetTexture(brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale) {
2770         if (b->pPatch) {
2771                 Patch_SetTexture(b->pPatch, texdef);
2772         }
2773         else {
2774                 for (face_t * f = b->brush_faces; f; f = f->next) {
2775                         SetFaceTexdef(b, f, texdef, brushprimit_texdef, bFitScale);
2776                 }
2777
2778                 Brush_Build(b);
2779         }
2780 }
2781
2782 /*
2783 ====================
2784 Brush_SetTextureName
2785 ====================
2786 */
2787 void Brush_SetTextureName(brush_t *b, const char *name) {
2788         if (b->pPatch) {
2789                 Patch_SetTextureName(b->pPatch, name);
2790         }
2791         else {
2792                 for (face_t * f = b->brush_faces; f; f = f->next) {
2793                         f->texdef.SetName(name);
2794                 }
2795                 Brush_Build(b);
2796         }
2797 }
2798
2799 /*
2800 ================
2801 ClipLineToFace
2802 ================
2803 */
2804 bool ClipLineToFace(idVec3 &p1, idVec3 &p2, face_t *f) {
2805         float   d1, d2, fr;
2806         int             i;
2807         float   *v;
2808
2809         d1 = DotProduct(p1, f->plane) + f->plane[3];
2810         d2 = DotProduct(p2, f->plane) + f->plane[3];
2811
2812         if (d1 >= 0 && d2 >= 0) {
2813                 return false;   // totally outside
2814         }
2815
2816         if (d1 <= 0 && d2 <= 0) {
2817                 return true;    // totally inside
2818         }
2819
2820         fr = d1 / (d1 - d2);
2821
2822         if (d1 > 0) {
2823                 v = p1.ToFloatPtr();
2824         }
2825         else {
2826                 v = p2.ToFloatPtr();
2827         }
2828
2829         for (i = 0; i < 3; i++) {
2830                 v[i] = p1[i] + fr * (p2[i] - p1[i]);
2831         }
2832
2833         return true;
2834 }
2835
2836 /*
2837 ================
2838 AddPlanept
2839 ================
2840 */
2841 int AddPlanept(idVec3 *f) {
2842         int i;
2843
2844         for (i = 0; i < g_qeglobals.d_num_move_points; i++) {
2845                 if (g_qeglobals.d_move_points[i] == f) {
2846                         return 0;
2847                 }
2848         }
2849
2850         if (g_qeglobals.d_num_move_points < MAX_MOVE_POINTS) {
2851                 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2852         } else {
2853                 Sys_Status("Trying to move too many points\n");
2854                 return 0;
2855         }
2856
2857         return 1;
2858 }
2859
2860 /*
2861 ================
2862 AddMovePlane
2863 ================
2864 */
2865 void AddMovePlane( idPlane *p ) {
2866
2867         for (int i = 0; i < g_qeglobals.d_num_move_planes; i++) {
2868                 if (g_qeglobals.d_move_planes[i] == p) {
2869                         return;
2870                 }
2871         }
2872
2873         if (g_qeglobals.d_num_move_planes < MAX_MOVE_PLANES) {
2874                 g_qeglobals.d_move_planes[g_qeglobals.d_num_move_planes++] = p;
2875         } else {
2876                 Sys_Status("Trying to move too many planes\n");
2877         }
2878
2879 }
2880
2881 /*
2882 ================
2883 Brush_SelectFaceForDragging
2884
2885   Adds the faces planepts to move_points, and rotates and adds the planepts of adjacent face if shear is set
2886 ================
2887 */
2888 void Brush_SelectFaceForDragging(brush_t *b, face_t *f, bool shear) {
2889         int                     i;
2890         face_t          *f2;
2891         idWinding       *w;
2892         float           d;
2893         brush_t         *b2;
2894         int                     c;
2895
2896         if (b->owner->eclass->fixedsize || EntityHasModel(b->owner)) {
2897                 return;
2898         }
2899
2900         c = 0;
2901         for (i = 0; i < 3; i++) {
2902                 c += AddPlanept(&f->planepts[i]);
2903         }
2904
2905         //AddMovePlane(&f->plane);
2906
2907         if (c == 0) {
2908                 return;                         // allready completely added
2909         }
2910
2911         // select all points on this plane in all brushes the selection
2912         for (b2 = selected_brushes.next; b2 != &selected_brushes; b2 = b2->next) {
2913                 if (b2 == b) {
2914                         continue;
2915                 }
2916
2917                 for (f2 = b2->brush_faces; f2; f2 = f2->next) {
2918                         for (i = 0; i < 3; i++) {
2919                                 if (idMath::Fabs(DotProduct(f2->planepts[i], f->plane) + f->plane[3]) > ON_EPSILON) {
2920                                         break;
2921                                 }
2922                         }
2923
2924                         if (i == 3) {   // move this face as well
2925                                 Brush_SelectFaceForDragging(b2, f2, shear);
2926                                 break;
2927                         }
2928                 }
2929         }
2930
2931         //
2932         // if shearing, take all the planes adjacent to selected faces and rotate their
2933         // points so the edge clipped by a selcted face has two of the points
2934         //
2935         if (!shear) {
2936                 return;
2937         }
2938
2939         for (f2 = b->brush_faces; f2; f2 = f2->next) {
2940                 if (f2 == f) {
2941                         continue;
2942                 }
2943
2944                 w = Brush_MakeFaceWinding(b, f2, false);
2945                 if (!w) {
2946                         continue;
2947                 }
2948
2949                 // any points on f will become new control points
2950                 for (i = 0; i < w->GetNumPoints(); i++) {
2951                         d = DotProduct( (*w)[i], f->plane ) + f->plane[3];
2952                         if (d > -ON_EPSILON && d < ON_EPSILON) {
2953                                 break;
2954                         }
2955                 }
2956
2957                 // if none of the points were on the plane, leave it alone
2958                 if (i != w->GetNumPoints()) {
2959                         if (i == 0) {   // see if the first clockwise point was the
2960                                                         ///
2961                                                         ///  last point on the winding
2962                                 d = DotProduct( (*w)[w->GetNumPoints() - 1], f->plane ) + f->plane[3];
2963                                 if (d > -ON_EPSILON && d < ON_EPSILON) {
2964                                         i = w->GetNumPoints() - 1;
2965                                 }
2966                         }
2967
2968                         AddPlanept(&f2->planepts[0]);
2969                         //AddMovePlane(&f2->plane);
2970
2971                         VectorCopy((*w)[i], f2->planepts[0]);
2972                         if (++i == w->GetNumPoints()) {
2973                                 i = 0;
2974                         }
2975
2976                         // see if the next point is also on the plane
2977                         d = DotProduct( (*w)[i], f->plane ) + f->plane[3];
2978                         if (d > -ON_EPSILON && d < ON_EPSILON) {
2979                                 AddPlanept(&f2->planepts[1]);
2980                         }
2981
2982                         VectorCopy( (*w)[i], f2->planepts[1] );
2983                         if (++i == w->GetNumPoints()) {
2984                                 i = 0;
2985                         }
2986
2987                         // the third point is never on the plane
2988                         VectorCopy( (*w)[i], f2->planepts[2] );
2989                 }
2990
2991                 delete w;
2992         }
2993 }
2994
2995 /*
2996 ================
2997 Brush_SideSelect
2998
2999   The mouse click did not hit the brush, so grab one or more side planes for dragging.
3000 ================
3001 */
3002 void Brush_SideSelect(brush_t *b, idVec3 origin, idVec3 dir, bool shear) {
3003         face_t  *f, *f2;
3004         idVec3  p1, p2;
3005
3006         if (g_moveOnly) {
3007                 return;
3008         }
3009
3010         // if (b->pPatch) return; Patch_SideSelect(b->nPatchID, origin, dir);
3011         for (f = b->brush_faces; f; f = f->next) {
3012                 VectorCopy(origin, p1);
3013                 VectorMA(origin, MAX_WORLD_SIZE, dir, p2);
3014
3015                 for (f2 = b->brush_faces; f2; f2 = f2->next) {
3016                         if (f2 == f) {
3017                                 continue;
3018                         }
3019
3020                         ClipLineToFace(p1, p2, f2);
3021                 }
3022
3023                 if (f2) {
3024                         continue;
3025                 }
3026
3027                 if ( p1.Compare( origin ) ) {
3028                         continue;
3029                 }
3030
3031                 if (ClipLineToFace(p1, p2, f)) {
3032                         continue;
3033                 }
3034
3035                 Brush_SelectFaceForDragging(b, f, shear);
3036         }
3037 }
3038
3039 extern void UpdateSelectablePoint(brush_t *b, idVec3 v, int type);
3040 extern void     AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority);
3041 extern void     ClearSelectablePoints(brush_t *b);
3042
3043 /*
3044 ================
3045 Brush_TransformedPoint
3046 ================
3047 */
3048 extern void VectorSnapGrid(idVec3 &v);
3049
3050 idMat3 Brush_RotationMatrix(brush_t *b) {
3051         idMat3 mat;
3052         mat.Identity();
3053         if (!GetMatrixForKey(b->owner, "light_rotation", mat)) {
3054                 GetMatrixForKey(b->owner, "rotation", mat);
3055         }
3056         return mat;
3057 }
3058
3059 idVec3 Brush_TransformedPoint(brush_t *b, const idVec3 &in) {
3060         idVec3 out = in;
3061         out -= b->owner->origin;
3062         out *= Brush_RotationMatrix(b);
3063         out += b->owner->origin;
3064         return out;
3065 }
3066 /*
3067 ================
3068 Brush_UpdateLightPoints
3069 ================
3070 */
3071 void Brush_UpdateLightPoints(brush_t *b, const idVec3 &offset) {
3072
3073         if (!(b->owner->eclass->nShowFlags & ECLASS_LIGHT)) {
3074                 if (b->modelHandle) {
3075                         g_bScreenUpdates = false;
3076                         g_pParentWnd->GetCamera()->BuildEntityRenderState(b->owner, true);
3077                         g_bScreenUpdates = true;
3078                 }
3079                 return;
3080         }
3081
3082         if (b->entityModel) {
3083                 return;
3084         }
3085
3086         idVec3  vCenter;
3087         idVec3 *origin = (b->trackLightOrigin) ? &b->owner->lightOrigin : &b->owner->origin;
3088
3089         if (!GetVectorForKey(b->owner, "_color", b->lightColor)) {
3090                 b->lightColor[0] = b->lightColor[1] = b->lightColor[2] = 1;
3091         }
3092
3093         const char      *str = ValueForKey(b->owner, "texture");
3094         b->lightTexture = -1;
3095         if (str && strlen(str) > 0) {
3096                 const idMaterial        *q = Texture_LoadLight(str);
3097                 if (q) {
3098                         b->lightTexture = q->GetEditorImage()->texnum;
3099                 }
3100         }
3101
3102         str = ValueForKey(b->owner, "light_right");
3103         if (str && *str) {
3104                 idVec3  vRight, vUp, vTarget, vTemp;
3105
3106                 if (GetVectorForKey(b->owner, "light_start", b->lightStart)) {
3107                         b->startEnd = true;
3108                         if (!GetVectorForKey(b->owner, "light_end", b->lightEnd)) {
3109                                 GetVectorForKey(b->owner, "light_target", b->lightEnd);
3110                         }
3111
3112
3113                         VectorAdd(b->lightEnd, *origin, b->lightEnd);
3114                         VectorAdd(b->lightStart, *origin, b->lightStart);
3115                         VectorAdd(b->lightStart, offset, b->lightStart);
3116                 }
3117                 else {
3118                         b->startEnd = false;
3119                 }
3120
3121                 GetVectorForKey(b->owner, "light_right", vRight);
3122                 GetVectorForKey(b->owner, "light_up", vUp);
3123                 GetVectorForKey(b->owner, "light_target", vTarget);
3124                 if (offset.x || offset.y || offset.z) {
3125                         CString str;
3126                         VectorAdd(vTarget, offset, vTarget);
3127                         SetKeyVec3(b->owner, "light_target", vTarget);
3128                 }
3129
3130                 VectorAdd(vTarget, *origin, b->lightTarget);
3131                 VectorAdd(b->lightTarget, vRight, b->lightRight);
3132                 VectorAdd(b->lightTarget, vUp, b->lightUp);
3133
3134                 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightUp), LIGHT_UP);
3135                 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightRight), LIGHT_RIGHT);
3136                 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightTarget), LIGHT_TARGET);
3137                 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightStart), LIGHT_START);
3138                 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightEnd), LIGHT_END);
3139                 b->pointLight = false;
3140         }
3141         else {
3142                 b->pointLight = true;
3143
3144                 if (GetVectorForKey(b->owner, "light_center", vCenter)) {
3145
3146                         if (offset.x || offset.y || offset.z) {
3147                                 CString str;
3148                                 VectorAdd(vCenter, offset, vCenter);
3149                                 SetKeyVec3(b->owner, "light_center", vCenter);
3150                         }
3151
3152                         VectorAdd(vCenter, *origin, b->lightCenter);
3153                         UpdateSelectablePoint(b, b->lightCenter, LIGHT_CENTER);
3154                 }
3155
3156                 if (!GetVectorForKey(b->owner, "light_radius", b->lightRadius)) {
3157                         float   f = FloatForKey(b->owner, "light");
3158                         if (f == 0) {
3159                                 f = 300;
3160                         }
3161
3162                         b->lightRadius[0] = b->lightRadius[1] = b->lightRadius[2] = f;
3163                 }
3164                 else {
3165                 }
3166         }
3167
3168         g_bScreenUpdates = false;
3169         g_pParentWnd->GetCamera()->BuildEntityRenderState(b->owner, true);
3170         g_bScreenUpdates = true;
3171
3172 }
3173
3174 /*
3175 ================
3176 Brush_BuildWindings
3177 ================
3178 */
3179 void Brush_BuildWindings(brush_t *b, bool bSnap, bool keepOnPlaneWinding, bool updateLights, bool makeFacePlanes) {
3180         idWinding       *w;
3181         face_t          *face;
3182         float           v;
3183
3184         // clear the mins/maxs bounds
3185         b->mins[0] = b->mins[1] = b->mins[2] = 999999;
3186         b->maxs[0] = b->maxs[1] = b->maxs[2] = -999999;
3187
3188         if (makeFacePlanes) {
3189                 Brush_MakeFacePlanes(b);
3190         }
3191
3192         face = b->brush_faces;
3193
3194         float   fCurveColor = 1.0f;
3195
3196         for (; face; face = face->next) {
3197                 int i, j;
3198                 delete face->face_winding;
3199                 w = face->face_winding = Brush_MakeFaceWinding(b, face, keepOnPlaneWinding);
3200                 face->d_texture = Texture_ForName(face->texdef.name);
3201
3202                 if (!w) {
3203                         continue;
3204                 }
3205
3206                 for (i = 0; i < w->GetNumPoints(); i++) {
3207                         // add to bounding box
3208                         for (j = 0; j < 3; j++) {
3209                                 v = (*w)[i][j];
3210                                 if (v > b->maxs[j]) {
3211                                         b->maxs[j] = v;
3212                                 }
3213
3214                                 if (v < b->mins[j]) {
3215                                         b->mins[j] = v;
3216                                 }
3217                         }
3218                 }
3219
3220                 // setup s and t vectors, and set color if (!g_PrefsDlg.m_bGLLighting) {
3221                 if (makeFacePlanes) {
3222                         Face_SetColor(b, face, fCurveColor);
3223
3224                 // }
3225                         fCurveColor -= 0.1f;
3226                         if ( fCurveColor <= 0.0f ) {
3227                                 fCurveColor = 1.0f;
3228                         }
3229
3230                         // computing ST coordinates for the windings
3231                         if (g_qeglobals.m_bBrushPrimitMode) {
3232                                 if (g_qeglobals.bNeedConvert) {
3233                                         //
3234                                         // we have parsed old brushes format and need conversion convert old brush texture
3235                                         // representation to new format
3236                                         //
3237                                         FaceToBrushPrimitFace(face);
3238         #ifdef _DEBUG
3239                                         // use old texture coordinates code to check against
3240                                         for (i = 0; i < w->GetNumPoints(); i++) {
3241                                                 EmitTextureCoordinates((*w)[i], face->d_texture, face);
3242                                         }
3243         #endif
3244                                 }
3245
3246                                 //
3247                                 // use new texture representation to compute texture coordinates in debug mode we
3248                                 // will check against old code and warn if there are differences
3249                                 //
3250                                 EmitBrushPrimitTextureCoordinates(face, w);
3251                         }
3252                         else {
3253                                 for (i = 0; i < w->GetNumPoints(); i++) {
3254                                         EmitTextureCoordinates((*w)[i], face->d_texture, face);
3255                                 }
3256                         }
3257                 }
3258
3259         }
3260
3261         if (updateLights) {
3262                 idVec3 offset;
3263                 offset.Zero();
3264                 Brush_UpdateLightPoints(b, offset);
3265         }
3266 }
3267
3268 /*
3269 ================
3270 Brush_RemoveEmptyFaces
3271
3272   Frees any overconstraining faces
3273 ================
3274 */
3275 void Brush_RemoveEmptyFaces(brush_t *b) {
3276         face_t  *f, *next;
3277
3278         f = b->brush_faces;
3279         b->brush_faces = NULL;
3280
3281         for (; f; f = next) {
3282                 next = f->next;
3283                 if (!f->face_winding) {
3284                         Face_Free(f);
3285                 }
3286                 else {
3287                         f->next = b->brush_faces;
3288                         b->brush_faces = f;
3289                 }
3290         }
3291 }
3292
3293 /*
3294 ================
3295 Brush_SnapToGrid
3296 ================
3297 */
3298 void Brush_SnapToGrid(brush_t *pb) {
3299         int i;
3300         for (face_t * f = pb->brush_faces; f; f = f->next) {
3301                 idWinding *w = f->face_winding;
3302
3303                 if (!w) {
3304                         continue;       // freed face
3305                 }
3306
3307                 for (i = 0; i < w->GetNumPoints(); i++) {
3308                         SnapVectorToGrid( (*w)[i].ToVec3() );
3309                 }
3310
3311                 for (i = 0; i < 3; i++) {
3312                         f->planepts[i].x = (*w)[i].x;
3313                         f->planepts[i].y = (*w)[i].y;
3314                         f->planepts[i].z = (*w)[i].z;
3315                 }
3316         }
3317         idVec3 v;
3318         idStr str;
3319         if (GetVectorForKey(pb->owner, "origin", v)) {
3320                 SnapVectorToGrid(pb->owner->origin);
3321                 sprintf(str, "%i %i %i", (int)pb->owner->origin.x, (int)pb->owner->origin.y, (int)pb->owner->origin.z);
3322                 SetKeyValue(pb->owner, "origin", str);
3323         }
3324
3325         if (pb->owner->eclass->nShowFlags & ECLASS_LIGHT) {
3326                 if (GetVectorForKey(pb->owner, "light_right", v)) {
3327                         // projected
3328                         SnapVectorToGrid(v);
3329                         pb->lightRight = v;
3330                         SetKeyVec3(pb->owner, "light_right", v);
3331                         GetVectorForKey(pb->owner, "light_up", v);
3332                         SnapVectorToGrid(v);
3333                         pb->lightUp = v;
3334                         SetKeyVec3(pb->owner, "light_up", v);
3335                         GetVectorForKey(pb->owner, "light_target", v);
3336                         SnapVectorToGrid(v);
3337                         pb->lightTarget = v;
3338                         SetKeyVec3(pb->owner, "light_target", v);
3339                         if (GetVectorForKey(pb->owner, "light_start", v)) {
3340                                 SnapVectorToGrid(v);
3341                                 pb->lightStart = v;
3342                                 SetKeyVec3(pb->owner, "light_start", v);
3343                                 GetVectorForKey(pb->owner, "light_end", v);
3344                                 SnapVectorToGrid(v);
3345                                 pb->lightEnd = v;
3346                                 SetKeyVec3(pb->owner, "light_end", v);
3347                         }
3348                 } else {
3349                         // point
3350                         if (GetVectorForKey(pb->owner, "light_center", v)) {
3351                                 SnapVectorToGrid(v);
3352                                 SetKeyVec3(pb->owner, "light_center", v);
3353                         }
3354                 }
3355         }
3356
3357         if ( pb->owner->curve ) {
3358                 int c = pb->owner->curve->GetNumValues();
3359                 for ( i = 0; i < c; i++ ) {
3360                         v = pb->owner->curve->GetValue( i );
3361                         SnapVectorToGrid( v );
3362                         pb->owner->curve->SetValue( i, v );
3363                 }
3364         }
3365
3366         Brush_Build(pb);
3367 }
3368
3369 /*
3370 ================
3371 Brush_Rotate
3372 ================
3373 */
3374 void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild) {
3375         for (face_t * f = b->brush_faces; f; f = f->next) {
3376                 for (int i = 0; i < 3; i++) {
3377                         f->planepts[i] -= origin;
3378                         f->planepts[i] *= matrix;
3379                         f->planepts[i] += origin;
3380                 }
3381         }
3382
3383         if (bBuild) {
3384                 Brush_Build(b, false, false);
3385         }
3386 }
3387
3388 extern void VectorRotate3Origin( const idVec3 &vIn, const idVec3 &vRotation, const idVec3 &vOrigin, idVec3 &out );
3389
3390 /*
3391 ================
3392 Brush_Rotate
3393 ================
3394 */
3395 void Brush_Rotate(brush_t *b, idVec3 vAngle, idVec3 vOrigin, bool bBuild) {
3396         for (face_t * f = b->brush_faces; f; f = f->next) {
3397                 for (int i = 0; i < 3; i++) {
3398                         VectorRotate3Origin(f->planepts[i], vAngle, vOrigin, f->planepts[i]);
3399                 }
3400         }
3401
3402         if (bBuild) {
3403                 Brush_Build(b, false, false);
3404         }
3405 }
3406
3407 /*
3408 ================
3409 Brush_Center
3410 ================
3411 */
3412 void Brush_Center(brush_t *b, idVec3 vNewCenter) {
3413         idVec3  vMid;
3414
3415         // get center of the brush
3416         for (int j = 0; j < 3; j++) {
3417                 vMid[j] = b->mins[j] + abs((b->maxs[j] - b->mins[j]) * 0.5f);
3418         }
3419
3420         // calc distance between centers
3421         VectorSubtract(vNewCenter, vMid, vMid);
3422         Brush_Move(b, vMid, true);
3423 }
3424
3425 /*
3426 ================
3427 Brush_Resize
3428
3429   the brush must be a true axial box
3430 ================
3431 */
3432 void Brush_Resize( brush_t *b, idVec3 vMin, idVec3 vMax ) {
3433         int i, j;
3434         face_t *f;
3435
3436         assert( vMin[0] < vMax[0] && vMin[1] < vMax[1] && vMin[2] < vMax[2] );
3437
3438         Brush_MakeFacePlanes( b );
3439
3440         for( f = b->brush_faces; f; f = f->next ) {
3441                 for ( i = 0; i < 3; i++ ) {
3442                         if ( f->plane.Normal()[i] >= 0.999f ) {
3443                                 for ( j = 0; j < 3; j++ ) {
3444                                         f->planepts[j][i] = vMax[i];
3445                                 }
3446                                 break;
3447                         }
3448                         if ( f->plane.Normal()[i] <= -0.999f ) {
3449                                 for ( j = 0; j < 3; j++ ) {
3450                                         f->planepts[j][i] = vMin[i];
3451                                 }
3452                                 break;
3453                         }
3454                 }
3455                 //assert( i < 3 );
3456         }
3457
3458         Brush_Build( b, true );
3459 }
3460
3461 /*
3462 ================
3463 HasModel
3464 ================
3465 */
3466 eclass_t *HasModel(brush_t *b) {
3467         idVec3  vMin, vMax;
3468         vMin[0] = vMin[1] = vMin[2] = 999999;
3469         vMax[0] = vMax[1] = vMax[2] = -999999;
3470
3471         if (b->owner->md3Class != NULL) {
3472                 return b->owner->md3Class;
3473         }
3474
3475         if (b->owner->eclass->modelHandle > 0) {
3476                 return b->owner->eclass;
3477         }
3478
3479         eclass_t        *e = NULL;
3480
3481         // FIXME: entity needs to track whether a cache hit failed and not ask again
3482         if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) {
3483                 const char      *pModel = ValueForKey(b->owner, "model");
3484                 if (pModel != NULL && strlen(pModel) > 0) {
3485                         e = GetCachedModel(b->owner, pModel, vMin, vMax);
3486                         if (e != NULL) {
3487                                 //
3488                                 // we need to scale the brush to the proper size based on the model load recreate
3489                                 // brush just like in load/save
3490                                 //
3491                                 VectorAdd(vMin, b->owner->origin, vMin);
3492                                 VectorAdd(vMax, b->owner->origin, vMax);
3493                                 Brush_Resize(b, vMin, vMax);
3494                                 b->bModelFailed = false;
3495                         }
3496                         else {
3497                                 b->bModelFailed = true;
3498                         }
3499                 }
3500         }
3501
3502         return e;
3503 }
3504
3505 /*
3506 ================
3507 Entity_GetRotationMatrixAngles
3508 ================
3509 */
3510 bool Entity_GetRotationMatrixAngles( entity_t *e, idMat3 &mat, idAngles &angles ) {
3511         int angle;
3512
3513         /* the angle keyword is a yaw value, except for two special markers */
3514         if ( GetMatrixForKey( e, "rotation", mat ) ) {
3515                 angles = mat.ToAngles();
3516                 return true;
3517         }
3518         else if ( e->epairs.GetInt( "angle", "0", angle ) ) {
3519                 if ( angle == -1 ) {            // up
3520                         angles.Set( 270, 0, 0 );
3521                 }
3522                 else if ( angle == -2 ) {       // down
3523                         angles.Set( 90, 0, 0 );
3524                 }
3525                 else {
3526                         angles.Set( 0, angle, 0 );
3527                 }
3528                 mat = angles.ToMat3();
3529                 return true;
3530         }
3531         else {
3532                 mat.Identity();
3533                 angles.Zero();
3534                 return false;
3535         }
3536 }
3537
3538 /*
3539 ================
3540 FacingVectors
3541 ================
3542 */
3543 static void FacingVectors(entity_t *e, idVec3 &forward, idVec3 &right, idVec3 &up) {
3544         idAngles        angles;
3545         idMat3          mat;
3546
3547         Entity_GetRotationMatrixAngles(e, mat, angles);
3548         angles.ToVectors( &forward, &right, &up);
3549 }
3550
3551 /*
3552 ================
3553 Brush_DrawFacingAngle
3554 ================
3555 */
3556 void Brush_DrawFacingAngle( brush_t *b, entity_t *e, bool particle ) {
3557         idVec3  forward, right, up;
3558         idVec3  endpoint, tip1, tip2;
3559         idVec3  start;
3560         float   dist;
3561
3562         VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
3563         VectorScale(start, 0.5f, start);
3564         dist = (b->maxs[0] - start[0]) * 2.5f;
3565
3566         FacingVectors(e, forward, right, up);
3567         VectorMA(start, dist, ( particle ) ? up : forward, endpoint);
3568
3569         dist = (b->maxs[0] - start[0]) * 0.5f;
3570         VectorMA(endpoint, -dist, ( particle ) ? up : forward, tip1);
3571         VectorMA(tip1, -dist, ( particle ) ? forward : up, tip1);
3572         VectorMA(tip1, 2 * dist, ( particle ) ? forward : up, tip2);
3573         globalImages->BindNull();
3574         qglColor4f(1, 1, 1, 1);
3575         qglLineWidth(2);
3576         qglBegin(GL_LINES);
3577         qglVertex3fv(start.ToFloatPtr());
3578         qglVertex3fv(endpoint.ToFloatPtr());
3579         qglVertex3fv(endpoint.ToFloatPtr());
3580         qglVertex3fv(tip1.ToFloatPtr());
3581         qglVertex3fv(endpoint.ToFloatPtr());
3582         qglVertex3fv(tip2.ToFloatPtr());
3583         qglEnd();
3584         qglLineWidth(0.5f);
3585 }
3586
3587 /*
3588 ================
3589 DrawProjectedLight
3590 ================
3591 */
3592 void DrawProjectedLight(brush_t *b, bool bSelected, bool texture) {
3593         int             i;
3594         idVec3  v1, v2, cross, vieworg, edge[8][2], v[4];
3595         idVec3  target, start;
3596
3597         if (!bSelected && !g_bShowLightVolumes) {
3598                 return;
3599         }
3600
3601         // use the renderer to get the volume outline
3602         idPlane         lightProject[4];
3603         idPlane         planes[6];
3604         srfTriangles_t  *tri;
3605
3606         // use the game's epair parsing code so
3607         // we can use the same renderLight generation
3608         entity_t *ent = b->owner;
3609         idDict  spawnArgs;
3610         renderLight_t   parms;
3611
3612         spawnArgs = ent->epairs;
3613         gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &parms );
3614         R_RenderLightFrustum( parms, planes );
3615
3616         tri = R_PolytopeSurface(6, planes, NULL);
3617
3618         qglColor3f(1, 0, 1);
3619         for (i = 0; i < tri->numIndexes; i += 3) {
3620                 qglBegin(GL_LINE_LOOP);
3621                 glVertex3fv(tri->verts[tri->indexes[i]].xyz.ToFloatPtr());
3622                 glVertex3fv(tri->verts[tri->indexes[i + 1]].xyz.ToFloatPtr());
3623                 glVertex3fv(tri->verts[tri->indexes[i + 2]].xyz.ToFloatPtr());
3624                 qglEnd();
3625         }
3626
3627         R_FreeStaticTriSurf(tri);
3628
3629         // draw different selection points for point lights or projected
3630         // lights (FIXME: rotate these based on parms!)
3631         if ( !bSelected ) {
3632                 return;
3633         }
3634
3635         idMat3 mat;
3636         bool transform = GetMatrixForKey(b->owner, "light_rotation", mat);
3637         if (!transform) {
3638                 transform = GetMatrixForKey(b->owner, "rotation", mat);
3639         }
3640         idVec3 tv;
3641         idVec3 *origin = (b->trackLightOrigin) ? &b->owner->lightOrigin : &b->owner->origin;
3642         if (b->pointLight) {
3643                 if ( b->lightCenter[0] || b->lightCenter[1] || b->lightCenter[2] ) {
3644                         qglPointSize(8);
3645                         qglColor3f( 1.0f, 0.4f, 0.8f );
3646                         qglBegin(GL_POINTS);
3647                         tv = b->lightCenter;
3648                         if (transform) {
3649                                 tv -= *origin;
3650                                 tv *= mat;
3651                                 tv += *origin;
3652                         }
3653                         qglVertex3fv(tv.ToFloatPtr());
3654                         qglEnd();
3655                         qglPointSize(1);
3656                 }
3657                 return;
3658         }
3659
3660         // projected light
3661         qglPointSize(8);
3662         qglColor3f( 1.0f, 0.4f, 0.8f );
3663         qglBegin(GL_POINTS);
3664         tv = b->lightRight;
3665         if (transform) {
3666                 tv -= *origin;
3667                 tv *= mat;
3668                 tv += *origin;
3669         }
3670         qglVertex3fv(tv.ToFloatPtr());
3671         tv = b->lightTarget;
3672         if (transform) {
3673                 tv -= *origin;
3674                 tv *= mat;
3675                 tv += *origin;
3676         }
3677         qglVertex3fv(tv.ToFloatPtr());
3678         tv = b->lightUp;
3679         if (transform) {
3680                 tv -= *origin;
3681                 tv *= mat;
3682                 tv += *origin;
3683         }
3684         qglVertex3fv(tv.ToFloatPtr());
3685         qglEnd();
3686
3687         if (b->startEnd) {
3688                 qglColor3f( 0.4f, 1.0f, 0.8f );
3689                 qglBegin(GL_POINTS);
3690                 qglVertex3fv(b->lightStart.ToFloatPtr());
3691                 qglVertex3fv(b->lightEnd.ToFloatPtr());
3692                 qglEnd();
3693         }
3694
3695         qglPointSize(1);
3696 }
3697
3698 /*
3699 ================
3700 GLCircle
3701 ================
3702 */
3703 void GLCircle(float x, float y, float z, float r) 
3704
3705         float ix = 0; 
3706         float iy = r; 
3707         float ig = 3 - 2 * r; 
3708         float idgr = -6;
3709         float idgd = 4 * r - 10;
3710         qglPointSize(0.5f);
3711         qglBegin(GL_POINTS);
3712         while (ix <= iy) {
3713                 if (ig < 0) {
3714                         ig += idgd;
3715                         idgd -= 8;
3716                         iy--;
3717                 } else {
3718                         ig += idgr;
3719                         idgd -= 4;
3720                 }
3721                 idgr -= 4;
3722                 ix++;
3723                 qglVertex3f(x + ix, y + iy, z);
3724                 qglVertex3f(x - ix, y + iy, z);
3725                 qglVertex3f(x + ix, y - iy, z);
3726                 qglVertex3f(x - ix, y - iy, z);
3727                 qglVertex3f(x + iy, y + ix, z);
3728                 qglVertex3f(x - iy, y + ix, z);
3729                 qglVertex3f(x + iy, y - ix, z);
3730                 qglVertex3f(x - iy, y - ix, z);
3731         }
3732         qglEnd();
3733
3734
3735 /*
3736 ================
3737 DrawSpeaker
3738 ================
3739 */
3740 void DrawSpeaker(brush_t *b, bool bSelected, bool twoD) {
3741
3742         if (!(g_qeglobals.d_savedinfo.showSoundAlways || (g_qeglobals.d_savedinfo.showSoundWhenSelected && bSelected))) {
3743                 return;
3744         }
3745         
3746         // convert to units ( inches )
3747         float min = FloatForKey(b->owner, "s_mindistance"); 
3748         float max = FloatForKey(b->owner, "s_maxdistance");
3749
3750         const char *s = b->owner->epairs.GetString("s_shader");
3751         if (s && *s) {
3752                 const idSoundShader *shader = declManager->FindSound( s, false );
3753                 if ( shader ) {
3754                         if ( !min ) {
3755                                 min = shader->GetMinDistance();
3756                         }
3757                         if ( !max ) {
3758                                 max = shader->GetMaxDistance();
3759                         }
3760                 }
3761         } 
3762
3763         if (min == 0 && max == 0) {
3764                 return;
3765         }
3766         
3767
3768         // convert from meters to doom units
3769         min *= METERS_TO_DOOM;
3770         max *= METERS_TO_DOOM;
3771
3772         if (twoD) {
3773                 if (bSelected) {
3774                         qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, .5);
3775                 } else {
3776                         qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, .5);
3777                 }
3778                 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3779                 GLCircle(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z, min);
3780                 if (bSelected) {
3781                         qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 1);
3782                 } else {
3783                         qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 1);
3784                 }
3785                 GLCircle(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z, max);
3786         } else {
3787                 qglPushMatrix();
3788                 qglTranslatef(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z );
3789                 qglColor3f( 0.4f, 0.4f, 0.4f );
3790                 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3791                 GLUquadricObj* qobj = gluNewQuadric();
3792                 gluSphere(qobj, min, 8, 8);
3793                 qglColor3f( 0.8f, 0.8f, 0.8f );
3794                 gluSphere(qobj, max, 8, 8);
3795                 qglEnable(GL_BLEND);
3796                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3797                 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3798                 globalImages->BindNull();
3799                 if (bSelected) {
3800                         qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 0.35f );
3801                 } else {
3802                         qglColor4f( b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 0.35f );
3803                 }
3804                 gluSphere(qobj, min, 8, 8);
3805                 if (bSelected) {
3806                         qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 0.1f );
3807                 } else {
3808                         qglColor4f( b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 0.1f );
3809                 }
3810                 gluSphere(qobj, max, 8, 8);
3811                 gluDeleteQuadric(qobj);
3812                 qglPopMatrix();
3813         }
3814
3815                 
3816 }
3817
3818 /*
3819 ================
3820 DrawLight
3821 ================
3822 */
3823 void DrawLight(brush_t *b, bool bSelected) {
3824         idVec3  vTriColor;
3825         bool    bTriPaint = false;
3826
3827         vTriColor[0] = vTriColor[2] = 1.0f;
3828         vTriColor[1] = 1.0f;
3829         bTriPaint = true;
3830
3831         CString strColor = ValueForKey(b->owner, "_color");
3832         if (strColor.GetLength() > 0) {
3833                 float   fR, fG, fB;
3834                 int             n = sscanf(strColor, "%f %f %f", &fR, &fG, &fB);
3835                 if (n == 3) {
3836                         vTriColor[0] = fR;
3837                         vTriColor[1] = fG;
3838                         vTriColor[2] = fB;
3839                 }
3840         }
3841
3842         qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3843
3844         idVec3  vCorners[4];
3845         float   fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
3846
3847         vCorners[0][0] = b->mins[0];
3848         vCorners[0][1] = b->mins[1];
3849         vCorners[0][2] = fMid;
3850
3851         vCorners[1][0] = b->mins[0];
3852         vCorners[1][1] = b->maxs[1];
3853         vCorners[1][2] = fMid;
3854
3855         vCorners[2][0] = b->maxs[0];
3856         vCorners[2][1] = b->maxs[1];
3857         vCorners[2][2] = fMid;
3858
3859         vCorners[3][0] = b->maxs[0];
3860         vCorners[3][1] = b->mins[1];
3861         vCorners[3][2] = fMid;
3862
3863         idVec3  vTop, vBottom;
3864
3865         vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
3866         vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
3867         vTop[2] = b->maxs[2];
3868
3869         VectorCopy(vTop, vBottom);
3870         vBottom[2] = b->mins[2];
3871
3872         idVec3  vSave;
3873         VectorCopy(vTriColor, vSave);
3874
3875         globalImages->BindNull();
3876         qglBegin(GL_TRIANGLE_FAN);
3877         qglVertex3fv(vTop.ToFloatPtr());
3878         int i;
3879         for (i = 0; i <= 3; i++) {
3880                 vTriColor[0] *= 0.95f;
3881                 vTriColor[1] *= 0.95f;
3882                 vTriColor[2] *= 0.95f;
3883                 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3884                 qglVertex3fv(vCorners[i].ToFloatPtr());
3885         }
3886
3887         qglVertex3fv(vCorners[0].ToFloatPtr());
3888         qglEnd();
3889
3890         VectorCopy(vSave, vTriColor);
3891         vTriColor[0] *= 0.95f;
3892         vTriColor[1] *= 0.95f;
3893         vTriColor[2] *= 0.95f;
3894
3895         qglBegin(GL_TRIANGLE_FAN);
3896         qglVertex3fv(vBottom.ToFloatPtr());
3897         qglVertex3fv(vCorners[0].ToFloatPtr());
3898         for (i = 3; i >= 0; i--) {
3899                 vTriColor[0] *= 0.95f;
3900                 vTriColor[1] *= 0.95f;
3901                 vTriColor[2] *= 0.95f;
3902                 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3903                 qglVertex3fv(vCorners[i].ToFloatPtr());
3904         }
3905
3906         qglEnd();
3907
3908         DrawProjectedLight(b, bSelected, true);
3909 }
3910
3911 /*
3912 ================
3913 Control_Draw
3914 ================
3915 */
3916 void Control_Draw(brush_t *b) {
3917         face_t          *face;
3918         int                     i, order;
3919         qtexture_t      *prev = 0;
3920         idWinding       *w;
3921
3922         // guarantee the texture will be set first
3923         prev = NULL;
3924         for ( face = b->brush_faces, order = 0; face; face = face->next, order++ ) {
3925                 w = face->face_winding;
3926                 if (!w) {
3927                         continue;       // freed face
3928                 }
3929
3930                 qglColor4f(1, 1, .5, 1);
3931                 qglBegin(GL_POLYGON);
3932                 for (i = 0; i < w->GetNumPoints(); i++) {
3933                         qglVertex3fv( (*w)[i].ToFloatPtr() );
3934                 }
3935
3936                 qglEnd();
3937         }
3938 }
3939
3940 /*
3941 ================
3942 Brush_DrawModel
3943 ================
3944 */
3945 void Brush_DrawModel( brush_t *b, bool camera, bool bSelected ) {
3946         idMat3 axis;
3947         idAngles angles;
3948         int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
3949
3950         if ( camera && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME && nDrawMode != cd_wire ) {
3951                 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
3952         }
3953         else {
3954                 qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
3955         }
3956
3957         idRenderModel *model = b->modelHandle;
3958         if ( model == NULL ) {
3959                 model = b->owner->eclass->entityModel;
3960         }
3961         if ( model ) {
3962                 idRenderModel *model2; 
3963
3964                 model2 = NULL;
3965                 bool fixedBounds = false;
3966
3967                 if ( model->IsDynamicModel() != DM_STATIC ) {
3968                         if ( dynamic_cast<idRenderModelMD5 *>( model ) ) {
3969                                 const char *classname = ValueForKey( b->owner, "classname" );
3970                                 if (stricmp(classname, "func_static") == 0) {
3971                                         classname = ValueForKey(b->owner, "animclass");
3972                                 }
3973                                 const char *anim = ValueForKey( b->owner, "anim" );
3974                                 int frame = IntForKey( b->owner, "frame" ) + 1;
3975                                 if ( frame < 1 ) {
3976                                         frame = 1;
3977                                 }
3978                                 if ( !anim || !anim[ 0 ] ) {
3979                                         anim = "idle";
3980                                 }
3981                                 model2 = gameEdit->ANIM_CreateMeshForAnim( model, classname, anim, frame, false );
3982                         } else if ( dynamic_cast<idRenderModelPrt*>( model ) || dynamic_cast<idRenderModelLiquid*>( model ) ) {
3983                                 fixedBounds = true;
3984                         }
3985
3986                         if ( !model2 ) {
3987                                 idBounds bounds;
3988                                 if (fixedBounds) {
3989                                         bounds.Zero();
3990                                         bounds.ExpandSelf(12.0f);
3991                                 } else {
3992                                         bounds = model->Bounds( NULL );
3993                                 }
3994                                 idVec4 color;
3995                                 color.w = 1.0f;
3996                                 if (bSelected) {
3997                                         color.x = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x;
3998                                         color.y = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y;
3999                                         color.z = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z;
4000                                 } else {
4001                                         color.x = b->owner->eclass->color.x;
4002                                         color.y = b->owner->eclass->color.y;
4003                                         color.z = b->owner->eclass->color.z;
4004                                 }
4005                                 idVec3 center = bounds.GetCenter();
4006                                 glBox(color, b->owner->origin + center, bounds.GetRadius( center ) );
4007                                 model = renderModelManager->DefaultModel();
4008                         } else {
4009                                 model = model2;
4010                         }
4011                 }
4012
4013                 Entity_GetRotationMatrixAngles( b->owner, axis, angles );
4014
4015                 idVec4  colorSave;
4016                 qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4017
4018                 if ( bSelected ) {
4019                         qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() );
4020                 }
4021
4022                 DrawRenderModel( model, b->owner->origin, axis, camera );
4023
4024                 qglColor4fv( colorSave.ToFloatPtr() );
4025
4026         if ( bSelected && camera )
4027         {
4028             //draw selection tints
4029                         /*
4030             if ( camera && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME ) {
4031                 qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL );
4032                 qglColor3fv ( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr () );
4033                 qglEnable ( GL_BLEND );
4034                 qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );                
4035                 DrawRenderModel( model, b->owner->origin, axis, camera );
4036             }
4037                         */
4038
4039             //draw white triangle outlines
4040                         globalImages->BindNull();
4041
4042             qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
4043             qglDisable( GL_BLEND );
4044                         qglDisable( GL_DEPTH_TEST );
4045             qglColor3f( 1.0f, 1.0f, 1.0f );
4046             qglPolygonOffset( 1.0f, 3.0f );
4047             DrawRenderModel( model, b->owner->origin, axis, false );
4048                         qglEnable( GL_DEPTH_TEST );
4049         }
4050
4051                 if ( model2 ) {
4052                         delete model2;
4053                         model2 = NULL;
4054                 }
4055         }
4056
4057         if ( bSelected && camera ) {
4058                 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4059         }
4060         else if ( camera ) {
4061                 globalImages->BindNull();
4062         }
4063
4064         if ( g_bPatchShowBounds ) {
4065                 for ( face_t *face = b->brush_faces; face; face = face->next ) {
4066                         // only draw polygons facing in a direction we care about
4067                         idWinding *w = face->face_winding;
4068                         if (!w) {
4069                                 continue;
4070                         }
4071
4072                         //
4073                         // if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA)) continue;
4074                         // draw the polygon
4075                         //
4076                         qglBegin(GL_LINE_LOOP);
4077                         for (int i = 0; i < w->GetNumPoints(); i++) {
4078                                 qglVertex3fv( (*w)[i].ToFloatPtr() );
4079                         }
4080                         qglEnd();
4081                 }
4082         }
4083 }
4084
4085 /*
4086 ================
4087 GLTransformedVertex
4088 ================
4089 */
4090 void GLTransformedVertex(float x, float y, float z, idMat3 mat, idVec3 origin, idVec3 color, float maxDist) {
4091         idVec3 v(x,y,z);
4092         v -= origin;
4093         v *= mat;
4094         v += origin;
4095
4096         idVec3 n = v - g_pParentWnd->GetCamera()->Camera().origin;
4097         float max = n.Length() / maxDist;
4098         if (color.x) {
4099                 color.x = max;
4100         } else if (color.y) {
4101                 color.y = max;
4102         } else {
4103                 color.z = max;
4104         }
4105         qglColor3f(color.x, color.y, color.z);
4106         qglVertex3f(v.x, v.y, v.z);
4107
4108 }
4109
4110 /*
4111 ================
4112 GLTransformedCircle
4113 ================
4114 */
4115 void GLTransformedCircle(int type, idVec3 origin, float r, idMat3 mat, float pointSize, idVec3 color, float maxDist) {
4116         qglPointSize(pointSize);
4117         qglBegin(GL_POINTS);
4118         for (int i = 0; i < 360; i++) {
4119                 float cx = origin.x;
4120                 float cy = origin.y;
4121                 float cz = origin.z;
4122                 switch (type) {
4123                         case 0:
4124                                 cx += r * cos((float)i);
4125                                 cy += r * sin((float)i);
4126                                 break;
4127                         case 1:
4128                                 cx += r * cos((float)i);
4129                                 cz += r * sin((float)i);
4130                                 break;
4131                         case 2:
4132                                 cy += r * sin((float)i);
4133                                 cz += r * cos((float)i);
4134                                 break;
4135                         default:
4136                                 break;
4137                 }
4138                 GLTransformedVertex(cx, cy, cz, mat, origin, color, maxDist);
4139         }
4140         qglEnd();
4141 }
4142
4143 /*
4144 ================
4145 Brush_DrawAxis
4146 ================
4147 */
4148 void Brush_DrawAxis(brush_t *b) {
4149         if ( g_pParentWnd->ActiveXY()->RotateMode() && b->modelHandle ) {
4150                 bool matrix = false;
4151                 idMat3 mat;
4152                 float a, s, c;
4153                 if (GetMatrixForKey(b->owner, "rotation", mat)) {
4154                         matrix = true;
4155                 } else {
4156                         a = FloatForKey(b->owner, "angle");
4157                         if (a) {
4158                                 s = sin( DEG2RAD( a ) );
4159                                 c = cos( DEG2RAD( a ) );
4160                         }
4161                         else {
4162                                 s = c = 0;
4163                         }
4164                 }
4165
4166                 idBounds bo;
4167                 bo.FromTransformedBounds(b->modelHandle->Bounds(), b->owner->origin, b->owner->rotation);
4168
4169                 float dist = (g_pParentWnd->GetCamera()->Camera().origin - bo[0]).Length();
4170                 float dist2 = (g_pParentWnd->GetCamera()->Camera().origin - bo[1]).Length();
4171                 if (dist2 > dist) {
4172                         dist = dist2;
4173                 }
4174
4175                 float xr, yr, zr;
4176                 xr = (b->modelHandle->Bounds()[1].x > b->modelHandle->Bounds()[0].x) ? b->modelHandle->Bounds()[1].x - b->modelHandle->Bounds()[0].x : b->modelHandle->Bounds()[0].x - b->modelHandle->Bounds()[1].x;
4177                 yr = (b->modelHandle->Bounds()[1].y > b->modelHandle->Bounds()[0].y) ? b->modelHandle->Bounds()[1].y - b->modelHandle->Bounds()[0].y : b->modelHandle->Bounds()[0].y - b->modelHandle->Bounds()[1].y;
4178                 zr = (b->modelHandle->Bounds()[1].z > b->modelHandle->Bounds()[0].z) ? b->modelHandle->Bounds()[1].z - b->modelHandle->Bounds()[0].z : b->modelHandle->Bounds()[0].z - b->modelHandle->Bounds()[1].z;
4179
4180                 globalImages->BindNull();
4181
4182                 GLTransformedCircle(0, b->owner->origin, xr, mat, 1.25, idVec3(0, 0, 1), dist);
4183                 GLTransformedCircle(1, b->owner->origin, yr, mat, 1.25, idVec3(0, 1, 0), dist);
4184                 GLTransformedCircle(2, b->owner->origin, zr, mat, 1.25, idVec3(1, 0, 0), dist);
4185
4186                 float wr = xr;
4187                 int type = 0;
4188                 idVec3 org = b->owner->origin;
4189                 if (g_qeglobals.rotateAxis == 0) {
4190                         wr = zr;
4191                         type = 2;
4192                 } else if (g_qeglobals.rotateAxis == 1) {
4193                         wr = yr;
4194                         type = 1;
4195                 }
4196                 
4197                 if (g_qeglobals.flatRotation) {
4198                         if (yr > wr) {
4199                                 wr = yr;
4200                         }
4201                         if (zr > wr) {
4202                                 wr = zr;
4203                         }
4204                         idVec3 vec = vec3_origin;
4205                         vec[g_qeglobals.rotateAxis] = 1.0f;
4206                         if (g_qeglobals.flatRotation == 1) {
4207                                 org = g_pParentWnd->ActiveXY()->RotateOrigin();
4208                                 float t = (org - bo.GetCenter()).Length();
4209                                 if (t > wr) {
4210                                         wr = t;
4211                                 }
4212                         } else {
4213                                 org = bo.GetCenter();
4214                         }
4215                         idRotation rot(org, vec, 0);
4216                         mat = rot.ToMat3();
4217                 }
4218                 GLTransformedCircle(type, org, wr * 1.03f, mat, 1.45f, idVec3(1, 1, 1), dist);
4219         }
4220 }
4221
4222 /*
4223 ================
4224 Brush_DrawModelInfo
4225 ================
4226 */
4227 void Brush_DrawModelInfo(brush_t *b, bool selected) {
4228         if (b->modelHandle > 0) {
4229                 GLfloat color[4];
4230                 qglGetFloatv(GL_CURRENT_COLOR, &color[0]);
4231                 if (selected) {
4232                         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr());
4233                 }
4234                 else {
4235                         qglColor3fv(b->owner->eclass->color.ToFloatPtr());
4236                 }
4237
4238                 Brush_DrawModel(b, true, selected);
4239                 qglColor4fv(color);
4240
4241                 if ( selected ) {
4242                         Brush_DrawAxis(b);
4243                 }
4244                 return;
4245         }
4246 }
4247
4248 /*
4249 ================
4250 Brush_DrawEmitter
4251 ================
4252 */
4253 void Brush_DrawEmitter(brush_t *b, bool bSelected, bool cam) {
4254         if ( !( b->owner->eclass->nShowFlags & ECLASS_PARTICLE ) ) {
4255                 return;
4256         }
4257                 
4258         if (bSelected) {
4259                 qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, .5);
4260         } else {
4261                 qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, .5);
4262         }
4263
4264         if ( cam ) {
4265                 Brush_DrawFacingAngle( b, b->owner, true );
4266         }
4267 }
4268
4269 /*
4270 ================
4271 Brush_DrawEnv
4272 ================
4273 */
4274 void Brush_DrawEnv( brush_t *b, bool cameraView, bool bSelected ) {
4275         idVec3 origin, newOrigin;
4276         idMat3 axis, newAxis;
4277         idAngles newAngles;
4278         bool poseIsSet;
4279
4280         idRenderModel *model = gameEdit->AF_CreateMesh( b->owner->epairs, origin, axis, poseIsSet );
4281
4282         if ( !poseIsSet ) {
4283                 if ( Entity_GetRotationMatrixAngles( b->owner, newAxis, newAngles ) ) {
4284                         axis = newAxis;
4285                 }
4286                 if ( b->owner->epairs.GetVector( "origin", "0 0 0", newOrigin ) ) {
4287                         origin = newOrigin;
4288                 }
4289         }
4290
4291         if ( model ) {
4292                 if ( cameraView && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME ) {
4293                         qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4294                 }
4295                 else {
4296                         qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
4297                 }
4298
4299                 idVec4  colorSave;
4300                 qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4301
4302                 if ( bSelected ) {
4303                         qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() );
4304                 } else {
4305                         qglColor3f( 1.f, 1.f, 1.f );
4306                 }
4307                 DrawRenderModel( model, origin, axis, true );
4308                 globalImages->BindNull();
4309                 delete model;
4310                 model = NULL;
4311
4312                 qglColor4fv( colorSave.ToFloatPtr() );
4313         }
4314 }
4315
4316 /*
4317 ================
4318 Brush_DrawCombatNode
4319 ================
4320 */
4321 void Brush_DrawCombatNode( brush_t *b, bool cameraView, bool bSelected ) {
4322         float min_dist = b->owner->epairs.GetFloat( "min" );
4323         float max_dist = b->owner->epairs.GetFloat( "max" );
4324         float fov = b->owner->epairs.GetFloat( "fov", "60" );
4325         float yaw = b->owner->epairs.GetFloat("angle");
4326         idVec3 offset = b->owner->epairs.GetVector("offset");
4327
4328         idAngles leftang( 0.0f, yaw + fov * 0.5f - 90.0f, 0.0f );
4329         idVec3 cone_left = leftang.ToForward();
4330         idAngles rightang( 0.0f, yaw - fov * 0.5f + 90.0f, 0.0f );
4331         idVec3 cone_right = rightang.ToForward();
4332         bool disabled = b->owner->epairs.GetBool( "start_off" );
4333
4334         idVec4 color;
4335         if ( bSelected ) {
4336                 color = colorRed;
4337         } else  {
4338                 color = colorBlue;
4339         } 
4340                 
4341         idVec3 leftDir( -cone_left.y, cone_left.x, 0.0f );
4342         idVec3 rightDir( cone_right.y, -cone_right.x, 0.0f );
4343         leftDir.NormalizeFast();
4344         rightDir.NormalizeFast();
4345
4346         idMat3 axis = idAngles(0, yaw, 0).ToMat3();
4347         idVec3 org = b->owner->origin + offset;
4348         idVec3 entorg = b->owner->origin;
4349         float cone_dot = cone_right * axis[ 1 ];
4350         if ( idMath::Fabs( cone_dot ) > 0.1 ) {
4351                 idVec3 pt, pt1, pt2, pt3, pt4;
4352                 float cone_dist = max_dist / cone_dot;
4353                 pt1 = org + leftDir * min_dist;
4354                 pt2 = org + leftDir * cone_dist;
4355                 pt3 = org + rightDir * cone_dist;
4356                 pt4 = org + rightDir * min_dist;
4357                 qglColor4fv(color.ToFloatPtr());
4358                 qglBegin(GL_LINE_STRIP);
4359                 qglVertex3fv( pt1.ToFloatPtr());
4360                 qglVertex3fv( pt2.ToFloatPtr());
4361                 qglVertex3fv( pt3.ToFloatPtr());
4362                 qglVertex3fv( pt4.ToFloatPtr());
4363                 qglVertex3fv( pt1.ToFloatPtr());
4364                 qglEnd();
4365
4366                 qglColor4fv(colorGreen.ToFloatPtr());
4367                 qglBegin(GL_LINE_STRIP);
4368                 qglVertex3fv( entorg.ToFloatPtr());
4369                 pt = (pt1 + pt4) * 0.5f;
4370                 qglVertex3fv( pt.ToFloatPtr());
4371                 pt = (pt2 + pt3) * 0.5f;
4372                 qglVertex3fv( pt.ToFloatPtr());
4373                 idVec3 tip = pt;
4374                 idVec3 dir = ((pt1 + pt2) * 0.5f) - tip;
4375                 dir.Normalize();
4376                 pt = tip + dir * 15.0f;
4377                 qglVertex3fv( pt.ToFloatPtr());
4378                 qglVertex3fv( tip.ToFloatPtr());
4379                 dir = ((pt4 + pt3) * 0.5f) - tip;
4380                 dir.Normalize();
4381                 pt = tip + dir * 15.0f;
4382                 qglVertex3fv( pt.ToFloatPtr());
4383                 qglEnd();
4384         }
4385
4386 }
4387
4388 /*
4389 ================
4390 Brush_Draw
4391 ================
4392 */
4393 void Brush_Draw(brush_t *b, bool bSelected) {
4394         face_t          *face;
4395         int                     i, order;
4396         const idMaterial        *prev = NULL;
4397         idWinding       *w;
4398         bool model = false;
4399
4400         //
4401         // (TTimo) NOTE: added by build 173, I check after pPlugEnt so it doesn't
4402         // interfere ?
4403         //
4404         if ( b->hiddenBrush ) {
4405                 return;
4406         }
4407
4408         Brush_DrawCurve( b, bSelected, true );
4409
4410         if (b->pPatch) {
4411                 Patch_DrawCam(b->pPatch, bSelected);
4412                 return;
4413         }
4414
4415         int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
4416
4417         if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES) && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) {
4418                 Brush_DrawFacingAngle(b, b->owner, false);
4419         }
4420
4421         if ( b->owner->eclass->fixedsize ) {
4422
4423                 DrawSpeaker( b, bSelected, false );
4424
4425                 if ( g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT) && !(b->modelHandle || b->entityModel) ) {
4426                         DrawLight( b, bSelected );
4427                         return;
4428                 }
4429
4430                 if ( b->owner->eclass->nShowFlags & ECLASS_ENV ) {
4431                         Brush_DrawEnv( b, true, bSelected );
4432                 }
4433
4434                 if ( b->owner->eclass->nShowFlags & ECLASS_COMBATNODE ) {
4435                         Brush_DrawCombatNode( b, true, bSelected );
4436                 }
4437
4438         }
4439
4440
4441         if (!(b->owner && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) {
4442                 qglColor4f( 1.0f, 0.0f, 0.0f, 0.8f );
4443                 qglPointSize(4);
4444                 qglBegin(GL_POINTS);
4445                 qglVertex3fv(b->owner->origin.ToFloatPtr());
4446                 qglEnd();
4447         }
4448
4449         if ( b->owner->eclass->entityModel ) {
4450                 qglColor3fv( b->owner->eclass->color.ToFloatPtr() );
4451                 Brush_DrawModel( b, true, bSelected );
4452                 return;
4453         }
4454
4455         Brush_DrawEmitter( b, bSelected, true );
4456
4457         if ( b->modelHandle > 0 && !model ) {
4458                 Brush_DrawModelInfo( b, bSelected );
4459                 return;
4460         }
4461
4462         // guarantee the texture will be set first
4463         prev = NULL;
4464         for (face = b->brush_faces, order = 0; face; face = face->next, order++) {
4465                 w = face->face_winding;
4466                 if (!w) {
4467                         continue;       // freed face
4468                 }
4469
4470                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
4471                         if (strstr(face->texdef.name, "caulk")) {
4472                                 continue;
4473                         }
4474                 }
4475
4476                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_VISPORTALS) {
4477                         if (strstr(face->texdef.name, "visportal")) {
4478                                 continue;
4479                         }
4480                 }
4481
4482                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_NODRAW) {
4483                         if (strstr(face->texdef.name, "nodraw")) {
4484                                 continue;
4485                         }
4486                 }
4487
4488                 if ( (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev && !b->forceWireFrame ) {
4489                         // set the texture for this face
4490                         prev = face->d_texture;
4491                         face->d_texture->GetEditorImage()->Bind();
4492                 }
4493
4494                 if (model) {
4495                         qglEnable(GL_BLEND);
4496                         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4497                         qglColor4f( face->d_color.x, face->d_color.y, face->d_color.z, 0.1f );
4498                 } else {
4499                         qglColor4f( face->d_color.x, face->d_color.y, face->d_color.z, face->d_texture->GetEditorAlpha() );
4500                 }
4501
4502                 qglBegin(GL_POLYGON);
4503
4504                 for (i = 0; i < w->GetNumPoints(); i++) {
4505                         if ( !b->forceWireFrame && ( nDrawMode == cd_texture || nDrawMode == cd_light ) ) {
4506                                 qglTexCoord2fv( &(*w)[i][3] );
4507                         }
4508
4509                         qglVertex3fv( (*w)[i].ToFloatPtr() );
4510                 }
4511
4512                 qglEnd();
4513
4514                 if (model) {
4515                         qglDisable(GL_BLEND);
4516                 }
4517         }
4518
4519         globalImages->BindNull();
4520 }
4521
4522 /*
4523 ================
4524 Face_Draw
4525 ================
4526 */
4527 void Face_Draw(face_t *f) {
4528         int i;
4529
4530         if (f->face_winding == NULL) {
4531                 return;
4532         }
4533
4534         qglBegin(GL_POLYGON);
4535         for (i = 0; i < f->face_winding->GetNumPoints(); i++) {
4536                 qglVertex3fv( (*f->face_winding)[i].ToFloatPtr() );
4537         }
4538
4539         qglEnd();
4540 }
4541
4542
4543 idSurface_SweptSpline *SplineToSweptSpline( idCurve<idVec3> *curve ) {
4544         // expects a vec3 curve and creates a vec4 based swept spline
4545         // must be either nurbs or catmull
4546         idCurve_Spline<idVec4> *newCurve = NULL;
4547         if ( dynamic_cast<idCurve_NURBS<idVec3>*>( curve ) ) {
4548                 newCurve = new idCurve_NURBS<idVec4>;
4549         } else if ( dynamic_cast<idCurve_CatmullRomSpline<idVec3>*>( curve ) ) {
4550                 newCurve = new idCurve_CatmullRomSpline<idVec4>;
4551         }
4552
4553         if ( curve == NULL || newCurve == NULL ) {
4554                 return NULL;
4555         }
4556
4557         int c = curve->GetNumValues();
4558         float len = 0.0f;
4559         for ( int i = 0; i < c; i++ ) {
4560                 idVec3 v = curve->GetValue( i );
4561                 newCurve->AddValue( curve->GetTime( i ), idVec4( v.x, v.y, v.z, len ) );
4562                 if ( i < c - 1 ) {
4563                         len += curve->GetLengthBetweenKnots( i, i + 1 ) * 0.1f;
4564                 }
4565         }
4566
4567         idSurface_SweptSpline *ss = new idSurface_SweptSpline;
4568         ss->SetSpline( newCurve );
4569         ss->SetSweptCircle( 10.0f );
4570         ss->Tessellate( newCurve->GetNumValues() * 6, 6 );
4571
4572         return ss;
4573 }
4574
4575 /*
4576 ================
4577 Brush_DrawCurve
4578 ================
4579 */
4580 void Brush_DrawCurve( brush_t *b, bool bSelected, bool cam ) { 
4581         if ( b == NULL || b->owner->curve == NULL ) {
4582                 return;
4583         }
4584
4585         int maxage = b->owner->curve->GetNumValues();
4586         int i, time = 0;
4587         qglColor3f( 0.0f, 0.0f, 1.0f );
4588         for ( i = 0; i < maxage; i++) {
4589
4590                 if ( bSelected && g_qeglobals.d_select_mode == sel_editpoint ) { 
4591                         idVec3 v = b->owner->curve->GetValue( i );
4592                         if ( cam ) {
4593                                 glBox( colorBlue, v, 6.0f );
4594                                 if ( PointInMoveList( b->owner->curve->GetValueAddress( i ) ) >= 0 ) {
4595                                         glBox(colorBlue, v, 8.0f );
4596                                 }
4597                         } else {
4598                                 qglPointSize( 4.0f );
4599                                 qglBegin( GL_POINTS );
4600                                 qglVertex3f( v.x, v.y, v.z );
4601                                 qglEnd();
4602
4603                                 if ( PointInMoveList( b->owner->curve->GetValueAddress( i ) ) >= 0 ) {
4604                                         glBox(colorBlue, v, 4.0f );
4605                                 }
4606                         }
4607                 }
4608 /*              
4609                 if ( cam ) {
4610                         idSurface_SweptSpline *ss = SplineToSweptSpline( b->owner->curve );
4611                         if ( ss ) {
4612                                 idMaterial *mat = declManager->FindMaterial( "_default" );
4613                                 mat->GetEditorImage()->Bind();
4614                                 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4615                                 qglBegin( GL_TRIANGLES );
4616                                 const int *indexes = ss->GetIndexes();
4617                                 const idDrawVert *verts = ss->GetVertices();
4618                                 for ( j = 0; j < ss->GetNumIndexes(); j += 3 ) {
4619                                         for ( k = 0; k < 3; k++ ) {
4620                                                 int     index = indexes[ j + 2 - k ];
4621                                                 float f = ShadeForNormal( verts[index].normal  );
4622                                                 qglColor3f( f, f, f );
4623                                                 qglTexCoord2fv( verts[index].st.ToFloatPtr() );
4624                                                 qglVertex3fv( verts[index].xyz.ToFloatPtr() );
4625                                         }
4626                                 }
4627                                 qglEnd();
4628                                 delete ss;
4629                         }
4630                 } else {
4631 */
4632 /*                      qglPointSize( 1.0f );
4633                         qglBegin( GL_POINTS );
4634                         if ( i + 1  < maxage ) {
4635                                 int start = b->owner->curve->GetTime( i );
4636                                 int end = b->owner->curve->GetTime( i + 1 );
4637                                 int inc = (end - start) / POINTS_PER_KNOT;
4638                                 for ( int j = 0; j < POINTS_PER_KNOT; j++ ) {
4639                                         idVec3 v = b->owner->curve->GetCurrentValue( start );
4640                                         qglVertex3f( v.x, v.y, v.z );
4641                                         start += inc;                                                           
4642                                 }
4643                         }*/
4644                 // DHM - _D3XP : Makes it easier to see curve
4645                 qglBegin( GL_LINE_STRIP );
4646                 if ( i + 1  < maxage ) {
4647                         int start = b->owner->curve->GetTime( i );
4648                         int end = b->owner->curve->GetTime( i + 1 );
4649                         int inc = (end - start) / POINTS_PER_KNOT;
4650                         for ( int j = 0; j <= POINTS_PER_KNOT; j++ ) {
4651                                 idVec3 v = b->owner->curve->GetCurrentValue( start );
4652                                 qglVertex3f( v.x, v.y, v.z );
4653                                 start += inc;                                                           
4654                         }
4655                         }
4656                         qglEnd();
4657 /*
4658                 }
4659 */
4660
4661         }
4662         qglPointSize(1);
4663 }
4664
4665 /*
4666 ================
4667 Brush_DrawXY
4668 ================
4669 */
4670 void Brush_DrawXY(brush_t *b, int nViewType, bool bSelected, bool ignoreViewType) {
4671         face_t          *face;
4672         int                     order;
4673         idWinding       *w;
4674         int                     i;
4675
4676         if ( b->hiddenBrush ) {
4677                 return;
4678         }
4679
4680         idVec4  colorSave;
4681         qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4682
4683         if (!(b->owner && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) {
4684                 qglColor4f( 1.0f, 0.0f, 0.0f, 0.8f );
4685                 qglPointSize(4);
4686                 qglBegin(GL_POINTS);
4687                 qglVertex3fv(b->owner->origin.ToFloatPtr());
4688                 qglEnd();
4689         }
4690
4691         Brush_DrawCurve( b, bSelected, false );
4692
4693         qglColor4fv(colorSave.ToFloatPtr());
4694
4695
4696         if (b->pPatch) {
4697                 Patch_DrawXY(b->pPatch);
4698                 if (!g_bPatchShowBounds) {
4699                         return;
4700                 }
4701         }
4702
4703         if (b->owner->eclass->fixedsize) {
4704
4705                 DrawSpeaker(b, bSelected, true);
4706                 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT) && !(b->modelHandle || b->entityModel)) {
4707                         idVec3  vCorners[4];
4708                         float   fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
4709
4710                         vCorners[0][0] = b->mins[0];
4711                         vCorners[0][1] = b->mins[1];
4712                         vCorners[0][2] = fMid;
4713
4714                         vCorners[1][0] = b->mins[0];
4715                         vCorners[1][1] = b->maxs[1];
4716                         vCorners[1][2] = fMid;
4717
4718                         vCorners[2][0] = b->maxs[0];
4719                         vCorners[2][1] = b->maxs[1];
4720                         vCorners[2][2] = fMid;
4721
4722                         vCorners[3][0] = b->maxs[0];
4723                         vCorners[3][1] = b->mins[1];
4724                         vCorners[3][2] = fMid;
4725
4726                         idVec3  vTop, vBottom;
4727
4728                         vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
4729                         vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
4730                         vTop[2] = b->maxs[2];
4731
4732                         VectorCopy(vTop, vBottom);
4733                         vBottom[2] = b->mins[2];
4734
4735                         qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
4736                         qglBegin(GL_TRIANGLE_FAN);
4737                         qglVertex3fv(vTop.ToFloatPtr());
4738                         qglVertex3fv(vCorners[0].ToFloatPtr());
4739                         qglVertex3fv(vCorners[1].ToFloatPtr());
4740                         qglVertex3fv(vCorners[2].ToFloatPtr());
4741                         qglVertex3fv(vCorners[3].ToFloatPtr());
4742                         qglVertex3fv(vCorners[0].ToFloatPtr());
4743                         qglEnd();
4744                         qglBegin(GL_TRIANGLE_FAN);
4745                         qglVertex3fv(vBottom.ToFloatPtr());
4746                         qglVertex3fv(vCorners[0].ToFloatPtr());
4747                         qglVertex3fv(vCorners[3].ToFloatPtr());
4748                         qglVertex3fv(vCorners[2].ToFloatPtr());
4749                         qglVertex3fv(vCorners[1].ToFloatPtr());
4750                         qglVertex3fv(vCorners[0].ToFloatPtr());
4751                         qglEnd();
4752                         DrawBrushEntityName(b);
4753                         DrawProjectedLight(b, bSelected, false);
4754                         return;
4755                 } else if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) {
4756                         // if (PaintedModel(b, false)) return;
4757                 } else if (b->owner->eclass->nShowFlags & ECLASS_ENV) {
4758                         Brush_DrawEnv( b, false, bSelected );
4759                 } else if (b->owner->eclass->nShowFlags & ECLASS_COMBATNODE) {
4760                         Brush_DrawCombatNode(b, false, bSelected);
4761                 }
4762
4763                 if (b->owner->eclass->entityModel) {
4764                         Brush_DrawModel( b, false, bSelected );
4765                         DrawBrushEntityName(b);
4766                         qglColor4fv(colorSave.ToFloatPtr());
4767             return;
4768                 }
4769
4770         }
4771
4772         qglColor4fv(colorSave.ToFloatPtr());
4773
4774         if (b->modelHandle > 0) {
4775                 Brush_DrawEmitter( b, bSelected, false );
4776                 Brush_DrawModel(b, false, bSelected);
4777                 qglColor4fv(colorSave.ToFloatPtr());
4778                 return;
4779         }
4780
4781         for (face = b->brush_faces, order = 0; face; face = face->next, order++) {
4782                 // only draw polygons facing in a direction we care about
4783                 if (!ignoreViewType) {
4784                         if (nViewType == XY) {
4785                                 if (face->plane[2] <= 0) {
4786                                         continue;
4787                                 }
4788                         } else {
4789                                 if (nViewType == XZ) {
4790                                         if (face->plane[1] <= 0) {
4791                                                 continue;
4792                                         }
4793                                 } else {
4794                                         if (face->plane[0] <= 0) {
4795                                                 continue;
4796                                         }
4797                                 }
4798                         }
4799                 }
4800
4801                 w = face->face_winding;
4802                 if (!w) {
4803                         continue;
4804                 }
4805
4806                 //
4807                 // if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA)) continue;
4808                 // draw the polygon
4809                 //
4810                 qglBegin(GL_LINE_LOOP);
4811                 for (i = 0; i < w->GetNumPoints(); i++) {
4812                         qglVertex3fv( (*w)[i].ToFloatPtr() );
4813                 }
4814                 qglEnd();
4815 /*
4816                 for (i = 0; i < 3; i++) {
4817                         glLabeledPoint(idVec4(1, 0, 0, 1), face->planepts[i], 3, va("%i", i));
4818                 }
4819 */
4820         }
4821
4822         DrawBrushEntityName(b);
4823 }
4824
4825 /*
4826 ==================
4827 PointValueInPointList
4828 ==================
4829 */
4830 static int PointValueInPointList( idVec3 v ) {
4831         for ( int i = 0; i < g_qeglobals.d_numpoints; i++ ) {
4832                 if ( v == g_qeglobals.d_points[i] ) {
4833                         return i;
4834                 }
4835         }
4836         return -1;
4837 }
4838
4839
4840 extern bool Sys_KeyDown(int key);
4841 /*
4842 ================
4843 Brush_Move
4844 ================
4845 */
4846 void Brush_Move(brush_t *b, const idVec3 move, bool bSnap, bool updateOrigin) {
4847         int             i;
4848         face_t  *f;
4849         char    text[128];
4850
4851         for (f = b->brush_faces; f; f = f->next) {
4852                 idVec3  vTemp;
4853                 VectorCopy(move, vTemp);
4854
4855                 if (g_PrefsDlg.m_bTextureLock) {
4856                         Face_MoveTexture(f, vTemp);
4857                 }
4858
4859                 for (i = 0; i < 3; i++) {
4860                         VectorAdd(f->planepts[i], move, f->planepts[i]);
4861                 }
4862         }
4863
4864         bool controlDown = Sys_KeyDown(VK_CONTROL);
4865         Brush_Build(b, bSnap, true, false, !controlDown);
4866
4867         if (b->pPatch) {
4868                 Patch_Move(b->pPatch, move);
4869         }
4870
4871         if ( b->owner->curve ) {
4872                 b->owner->curve->Translate( move );
4873                 Entity_UpdateCurveData( b->owner );
4874         }
4875
4876         idVec3  temp;
4877
4878         // PGM - keep the origin vector up to date on fixed size entities.
4879         if (b->owner->eclass->fixedsize || EntityHasModel(b->owner) || (updateOrigin && GetVectorForKey(b->owner, "origin", temp))) {
4880 //              if (!b->entityModel) {
4881                         bool adjustOrigin = true;
4882                         if(b->trackLightOrigin) {
4883                                 b->owner->lightOrigin += move;
4884                                 sprintf(text, "%i %i %i", (int)b->owner->lightOrigin[0], (int)b->owner->lightOrigin[1], (int)b->owner->lightOrigin[2]);
4885                                 SetKeyValue(b->owner, "light_origin", text);
4886                                 if (QE_SingleBrush(true, true)) {
4887                                         adjustOrigin = false;
4888                                 }
4889                         } 
4890
4891                         if (adjustOrigin && updateOrigin) {
4892                                 b->owner->origin += move;
4893                                 if (g_moveOnly) {
4894                                         sprintf(text, "%g %g %g", b->owner->origin[0], b->owner->origin[1], b->owner->origin[2]);
4895                                 } else {
4896                                         sprintf(text, "%i %i %i", (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
4897                                 }
4898                                 SetKeyValue(b->owner, "origin", text);
4899                         }
4900
4901                         // rebuild the light dragging points now that the origin has changed
4902                         idVec3 offset;
4903                         offset.Zero();
4904                         if (controlDown) {
4905                                 offset.x = -move.x;
4906                                 offset.y = -move.y;
4907                                 offset.z = -move.z;
4908                                 Brush_UpdateLightPoints(b, offset);
4909                         } else {
4910                                 offset.Zero();
4911                                 Brush_UpdateLightPoints(b, offset);
4912                         }
4913
4914                 //}
4915                 if (b->owner->eclass->nShowFlags & ECLASS_ENV) {
4916                         const idKeyValue *arg  = b->owner->epairs.MatchPrefix( "body ", NULL );
4917                         idStr val;
4918                         idVec3 org;
4919                         idAngles ang;
4920                         while ( arg ) {
4921                                 sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll );
4922                                 org += move;
4923                                 val = org.ToString(8);
4924                                 val += " ";
4925                                 val += ang.ToString(8);
4926                                 b->owner->epairs.Set(arg->GetKey(), val);
4927                                 arg = b->owner->epairs.MatchPrefix( "body ", arg );
4928                         }
4929                 }
4930         }
4931 }
4932
4933 /*
4934 ================
4935 Select_AddProjectedLight
4936 ================
4937 */
4938 void Select_AddProjectedLight() {
4939         idVec3  vTemp;
4940         CString str;
4941
4942         // if (!QE_SingleBrush ()) return;
4943         brush_t *b = selected_brushes.next;
4944
4945         if (b->owner->eclass->nShowFlags & ECLASS_LIGHT) {
4946                 vTemp[0] = vTemp[1] = 0;
4947                 vTemp[2] = -256;
4948                 str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4949                 SetKeyValue(b->owner, "light_target", str);
4950
4951                 vTemp[2] = 0;
4952                 vTemp[1] = -128;
4953                 str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4954                 SetKeyValue(b->owner, "light_up", str);
4955
4956                 vTemp[1] = 0;
4957                 vTemp[0] = -128;
4958                 str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4959                 SetKeyValue(b->owner, "light_right", str);
4960                 Brush_Build(b);
4961         }
4962 }
4963
4964 /*
4965 ================
4966 Brush_Print
4967 ================
4968 */
4969 void Brush_Print(brush_t *b) {
4970         int nFace = 0;
4971         for (face_t * f = b->brush_faces; f; f = f->next) {
4972                 common->Printf("Face %i\n", nFace++);
4973                 common->Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
4974                 common->Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
4975                 common->Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
4976         }
4977 }
4978
4979 /*
4980 ================
4981 Brush_MakeSidedCone
4982
4983   Makes the current brush have the given number of 2d sides and turns it into a cone
4984 ================
4985 */
4986 void Brush_MakeSidedCone(int sides) {
4987         int                     i;
4988         idVec3          mins, maxs;
4989         brush_t         *b;
4990         texdef_t        *texdef;
4991         face_t          *f;
4992         idVec3          mid;
4993         float           width;
4994         float           sv, cv;
4995
4996         if (sides < 3) {
4997                 Sys_Status("Bad sides number", 0);
4998                 return;
4999         }
5000
5001         if (!QE_SingleBrush()) {
5002                 Sys_Status("Must have a single brush selected", 0);
5003                 return;
5004         }
5005
5006         b = selected_brushes.next;
5007         VectorCopy(b->mins, mins);
5008         VectorCopy(b->maxs, maxs);
5009         texdef = &g_qeglobals.d_texturewin.texdef;
5010
5011         Brush_Free(b);
5012
5013         // find center of brush
5014         width = 8;
5015         for (i = 0; i < 2; i++) {
5016                 mid[i] = (maxs[i] + mins[i]) * 0.5f;
5017                 if (maxs[i] - mins[i] > width) {
5018                         width = maxs[i] - mins[i];
5019                 }
5020         }
5021
5022         width *= 0.5f;
5023
5024         b = Brush_Alloc();
5025
5026         // create bottom face
5027         f = Face_Alloc();
5028         f->texdef = *texdef;
5029         f->next = b->brush_faces;
5030         b->brush_faces = f;
5031
5032         f->planepts[0][0] = mins[0];
5033         f->planepts[0][1] = mins[1];
5034         f->planepts[0][2] = mins[2];
5035         f->planepts[1][0] = maxs[0];
5036         f->planepts[1][1] = mins[1];
5037         f->planepts[1][2] = mins[2];
5038         f->planepts[2][0] = maxs[0];
5039         f->planepts[2][1] = maxs[1];
5040         f->planepts[2][2] = mins[2];
5041
5042         for (i = 0; i < sides; i++) {
5043                 f = Face_Alloc();
5044                 f->texdef = *texdef;
5045                 f->next = b->brush_faces;
5046                 b->brush_faces = f;
5047
5048                 sv = sin(i * idMath::TWO_PI / sides);
5049                 cv = cos(i * idMath::TWO_PI / sides);
5050
5051                 f->planepts[0][0] = floor( mid[0] + width * cv + 0.5f );
5052                 f->planepts[0][1] = floor( mid[1] + width * sv + 0.5f );
5053                 f->planepts[0][2] = mins[2];
5054
5055                 f->planepts[1][0] = mid[0];
5056                 f->planepts[1][1] = mid[1];
5057                 f->planepts[1][2] = maxs[2];
5058
5059                 f->planepts[2][0] = floor( f->planepts[0][0] - width * sv + 0.5f );
5060                 f->planepts[2][1] = floor( f->planepts[0][1] + width * cv + 0.5f );
5061                 f->planepts[2][2] = maxs[2];
5062         }
5063
5064         Brush_AddToList(b, &selected_brushes);
5065
5066         Entity_LinkBrush(world_entity, b);
5067
5068         Brush_Build(b);
5069
5070         Sys_UpdateWindows(W_ALL);
5071 }
5072
5073 /*
5074 ================
5075 Brush_MakeSidedSphere
5076
5077   Makes the current brushhave the given number of 2d sides and turns it into a sphere
5078 ================
5079 */
5080 void Brush_MakeSidedSphere(int sides) {
5081         int                     i, j;
5082         idVec3          mins, maxs;
5083         brush_t         *b;
5084         texdef_t        *texdef;
5085         face_t          *f;
5086         idVec3          mid;
5087         float           radius;
5088
5089         if (sides < 4) {
5090                 Sys_Status("Bad sides number", 0);
5091                 return;
5092         }
5093
5094         if (!QE_SingleBrush()) {
5095                 Sys_Status("Must have a single brush selected", 0);
5096                 return;
5097         }
5098
5099         b = selected_brushes.next;
5100         mins = b->mins;
5101         maxs = b->maxs;
5102         texdef = &g_qeglobals.d_texturewin.texdef;
5103
5104         Brush_Free(b);
5105
5106         // find center of brush
5107         radius = 8;
5108         for ( i = 0; i < 3; i++ ) {
5109                 mid[i] = (maxs[i] + mins[i]) * 0.5f;
5110                 if (maxs[i] - mins[i] > radius) {
5111                         radius = maxs[i] - mins[i];
5112                 }
5113         }
5114
5115         radius *= 0.5f;
5116
5117         b = Brush_Alloc();
5118
5119         for (i = 0; i < sides; i++) {
5120                 for (j = 0; j < sides - 1; j++) {
5121                         f = Face_Alloc();
5122                         f->texdef = *texdef;
5123                         f->next = b->brush_faces;
5124                         b->brush_faces = f;
5125
5126                         f->planepts[0] = idPolar3(radius, idMath::TWO_PI * i / sides, idMath::PI * ((float)(j) / sides - 0.5f) ).ToVec3() + mid;
5127                         f->planepts[1] = idPolar3(radius, idMath::TWO_PI * i / sides, idMath::PI * ((float)(j+1) / sides - 0.5f) ).ToVec3() + mid;
5128                         f->planepts[2] = idPolar3(radius, idMath::TWO_PI * (i+1) / sides, idMath::PI * ((float)(j+1) / sides - 0.5f) ).ToVec3() + mid;
5129                 }
5130         }
5131
5132         Brush_AddToList(b, &selected_brushes);
5133
5134         Entity_LinkBrush(world_entity, b);
5135
5136         Brush_Build(b);
5137
5138         Sys_UpdateWindows(W_ALL);
5139 }
5140
5141 extern void Face_FitTexture_BrushPrimit(face_t *f, idVec3 mins, idVec3 maxs, float nHeight, float nWidth);
5142
5143 /*
5144 ================
5145 Face_FitTexture
5146 ================
5147 */
5148 void Face_FitTexture(face_t *face, float nHeight, float nWidth) {
5149         if (g_qeglobals.m_bBrushPrimitMode) {
5150                 idVec3  mins, maxs;
5151                 mins[0] = maxs[0] = 0;
5152                 Face_FitTexture_BrushPrimit(face, mins, maxs, nHeight, nWidth);
5153         }
5154         else {
5155                 /*
5156                  * winding_t *w; idBounds bounds; int i; float width, height, temp; float rot_width,
5157                  * rot_height; float cosv,sinv,ang; float min_t, min_s, max_t, max_s; float s,t;
5158                  * idVec3 vecs[2]; idVec3 coords[4]; texdef_t *td; if (nHeight < 1) { nHeight = 1;
5159                  * } if (nWidth < 1) { nWidth = 1; } bounds.Clear(); td = &face->texdef; w =
5160                  * face->face_winding; if (!w) { return; } for (i=0 ; i<w->numpoints ; i++) {
5161                  * bounds.AddPoint( w->p[i] ); } // // get the current angle // ang = td->rotate /
5162                  * 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); // get natural texture axis
5163                  * TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); min_s = DotProduct(
5164                  * bounds.b[0], vecs[0] ); min_t = DotProduct( bounds.b[0], vecs[1] ); max_s =
5165                  * DotProduct( bounds.b[1], vecs[0] ); max_t = DotProduct( bounds.b[1], vecs[1] );
5166                  * width = max_s - min_s; height = max_t - min_t; coords[0][0] = min_s;
5167                  * coords[0][1] = min_t; coords[1][0] = max_s; coords[1][1] = min_t; coords[2][0]
5168                  * = min_s; coords[2][1] = max_t; coords[3][0] = max_s; coords[3][1] = max_t;
5169                  * min_s = min_t = 999999; max_s = max_t = -999999; for (i=0; i<4; i++) { s = cosv
5170                  * * coords[i][0] - sinv * coords[i][1]; t = sinv * coords[i][0] + cosv *
5171                  * coords[i][1]; if (i&1) { if (s > max_s) { max_s = s; } } else { if (s < min_s)
5172                  * { min_s = s; } if (i<2) { if (t < min_t) { min_t = t; } } else { if (t > max_t)
5173                  * { max_t = t; } } } } rot_width = (max_s - min_s); rot_height = (max_t - min_t);
5174                  * td->scale[0] =
5175                  * -(rot_width/((float)(face->d_texture->GetEditorImage()->uploadWidth*nWidth)));
5176                  * td->scale[1] =
5177                  * -(rot_height/((float)(face->d_texture->GetEditorImage()->uploadHeight*nHeight)));
5178                  * td->shift[0] = min_s/td->scale[0]; temp = (int)(td->shift[0] /
5179                  * (face->d_texture->GetEditorImage()->uploadWidth*nWidth)); temp =
5180                  * (temp+1)*face->d_texture->GetEditorImage()->uploadWidth*nWidth; td->shift[0] =
5181                  * (int)(temp -
5182                  * td->shift[0])%(face->d_texture->GetEditorImage()->uploadWidth*nWidth);
5183                  * td->shift[1] = min_t/td->scale[1]; temp = (int)(td->shift[1] /
5184                  * (face->d_texture->GetEditorImage()->uploadHeight*nHeight)); temp =
5185                  * (temp+1)*(face->d_texture->GetEditorImage()->uploadHeight*nHeight);
5186                  * td->shift[1] = (int)(temp -
5187                  * td->shift[1])%(face->d_texture->GetEditorImage()->uploadHeight*nHeight);
5188                  */
5189         }
5190 }
5191
5192 /*
5193 ================
5194 Brush_FitTexture
5195 ================
5196 */
5197 void Brush_FitTexture(brush_t *b, float nHeight, float nWidth) {
5198         face_t  *face;
5199         for (face = b->brush_faces; face; face = face->next) {
5200                 Face_FitTexture(face, nHeight, nWidth);
5201         }
5202 }
5203
5204 void Brush_GetBounds( brush_t *b, idBounds &bo ) {
5205         if ( b == NULL ) {
5206                 return;
5207         }
5208
5209         bo.Clear();
5210         bo.AddPoint( b->mins );
5211         bo.AddPoint( b->maxs );
5212
5213         if ( b->owner->curve ) {
5214                 int c = b->owner->curve->GetNumValues();
5215                 for ( int i = 0; i < c; i++ ) {
5216                         bo.AddPoint ( b->owner->curve->GetValue( i ) );
5217                 }
5218         } 
5219
5220 }