]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/SELECT.CPP
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / radiant / SELECT.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 "../../renderer/model_local.h" // for idRenderModelPrt
34
35 // externs
36 CPtrArray       g_SelectedFaces;
37 CPtrArray       g_SelectedFaceBrushes;
38 CPtrArray       &g_ptrSelectedFaces = g_SelectedFaces;
39 CPtrArray       &g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes;
40
41 extern void Brush_Resize(brush_t *b, idVec3 vMin, idVec3 vMax);
42
43 /*
44  =======================================================================================================================
45  =======================================================================================================================
46  */
47 qertrace_t Test_Ray(const idVec3 &origin, const idVec3 &dir, int flags) {
48         brush_t         *brush;
49         face_t          *face;
50         float           dist;
51         qertrace_t      t;
52
53         memset(&t, 0, sizeof(t));
54         t.dist = HUGE_DISTANCE*2;
55
56         // check for points first
57         CDragPoint      *drag = PointRay(origin, dir, &dist);
58         if (drag) {
59                 t.dist = dist;
60                 t.brush = NULL;
61                 t.face = NULL;
62                 t.point = drag;
63                 t.selected = false;
64                 return t;
65         }
66
67         if (flags & SF_CYCLE) {
68                 CPtrArray       array;
69                 brush_t         *pToSelect = (selected_brushes.next != &selected_brushes) ? selected_brushes.next : NULL;
70                 Select_Deselect();
71
72                 // go through active brushes and accumulate all "hit" brushes
73                 for (brush = active_brushes.next; brush != &active_brushes; brush = brush->next) {
74                         // if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) continue;
75                         if (FilterBrush(brush)) {
76                                 continue;
77                         }
78
79                         if (g_PrefsDlg.m_selectOnlyBrushes) {
80                                 if (brush->pPatch || brush->modelHandle > 0) {
81                                         continue;
82                                 }
83                         }
84
85                         if (g_PrefsDlg.m_selectNoModels) {
86                                 if (brush->modelHandle > 0) {
87                                         continue;
88                                 }
89                         }
90
91                         // if (!g_bShowPatchBounds && brush->pPatch) continue;
92                         face = Brush_Ray(origin, dir, brush, &dist, true);
93
94                         if (face) {
95                                 array.Add(brush);
96                         }
97                 }
98
99                 int nSize = array.GetSize();
100                 if (nSize > 0) {
101                         bool    bFound = false;
102                         for (int i = 0; i < nSize; i++) {
103                                 brush_t *b = reinterpret_cast < brush_t * > (array.GetAt(i));
104
105                                 // did we hit the last one selected yet ?
106                                 if (b == pToSelect) {
107                                         // yes we want to select the next one in the list
108                                         int n = (i > 0) ? i - 1 : nSize - 1;
109                                         pToSelect = reinterpret_cast < brush_t * > (array.GetAt(n));
110                                         bFound = true;
111                                         break;
112                                 }
113                         }
114
115                         if (!bFound) {
116                                 pToSelect = reinterpret_cast < brush_t * > (array.GetAt(0));
117                         }
118                 }
119
120                 if (pToSelect) {
121                         face = Brush_Ray(origin, dir, pToSelect, &dist, true);
122                         t.dist = dist;
123                         t.brush = pToSelect;
124                         t.face = face;
125                         t.selected = false;
126                         return t;
127                 }
128         }
129
130         if (!(flags & SF_SELECTED_ONLY)) {
131                 for (brush = active_brushes.next; brush != &active_brushes; brush = brush->next) {
132                         if ((flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) {
133                                 continue;
134                         }
135
136                         if (FilterBrush(brush)) {
137                                 continue;
138                         }
139
140                         if (g_PrefsDlg.m_selectOnlyBrushes) {
141                                 if (brush->pPatch || brush->modelHandle > 0) {
142                                         continue;
143                                 }
144                         }
145
146                         if (g_PrefsDlg.m_selectNoModels) {
147                                 if (brush->modelHandle > 0) {
148                                         continue;
149                                 }                                                                       
150                         }
151
152                         face = Brush_Ray(origin, dir, brush, &dist, true);
153                         if (dist > 0 && dist < t.dist) {
154                                 t.dist = dist;
155                                 t.brush = brush;
156                                 t.face = face;
157                                 t.selected = false;
158                         }
159             }
160         }
161
162         for (brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) {
163                 if ((flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) {
164                         continue;
165                 }
166
167                 if (FilterBrush(brush)) {
168                         continue;
169                 }
170
171                 if (g_PrefsDlg.m_selectOnlyBrushes) {
172                         if (brush->pPatch || brush->modelHandle > 0) {
173                                 continue;
174                         }
175                 }
176
177                 if (g_PrefsDlg.m_selectNoModels) {
178                         if (brush->modelHandle > 0) {
179                                 continue;
180                         }
181                 }
182
183                 face = Brush_Ray(origin, dir, brush, &dist, true);
184                 if (dist > 0 && dist < t.dist) {
185                         t.dist = dist;
186                         t.brush = brush;
187                         t.face = face;
188                         t.selected = true;
189                 }
190         }
191
192         // if entites first, but didn't find any, check regular
193         if ((flags & SF_ENTITIES_FIRST) && t.brush == NULL) {
194                 return Test_Ray(origin, dir, flags - SF_ENTITIES_FIRST);
195         }
196
197         return t;
198 }
199
200 extern void     AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority);
201 extern void     ClearSelectablePoints(brush_t *b);
202 extern idVec3 Brush_TransformedPoint(brush_t *b, const idVec3 &in);
203
204 /*
205  =======================================================================================================================
206     Select_Brush
207  =======================================================================================================================
208  */
209 void Select_Brush(brush_t *brush, bool bComplete, bool bStatus) {
210         brush_t         *b;
211         entity_t        *e;
212
213         g_ptrSelectedFaces.RemoveAll();
214         g_ptrSelectedFaceBrushes.RemoveAll();
215
216         // selected_face = NULL;
217         if (g_qeglobals.d_select_count < MAX_MAP_ENTITIES) {
218                 g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush;
219         }
220
221         g_qeglobals.d_select_count++;
222
223         e = brush->owner;
224         if (e) {
225
226                 if ( e == world_entity && radiant_entityMode.GetBool() ) {
227                         return;
228                 }
229                 // select complete entity on first click
230                 if (e != world_entity && bComplete == true) {
231                         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
232                                 if (b->owner == e) {
233                                         goto singleselect;
234                                 }
235                         }
236
237                         for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
238                                 Brush_RemoveFromList(b);
239                                 Brush_AddToList(b, &selected_brushes);
240                         }
241                 }
242                 else
243                 {
244 singleselect:
245                         Brush_RemoveFromList(brush);
246                         Brush_AddToList(brush, &selected_brushes);
247                         UpdateSurfaceDialog();
248                         UpdatePatchInspector();
249                         UpdateLightInspector();
250                 }
251
252                 if (e->eclass) {
253                         g_Inspectors->UpdateEntitySel(brush->owner->eclass);
254                         if ( radiant_entityMode.GetBool() && e->eclass->nShowFlags & (ECLASS_LIGHT | ECLASS_SPEAKER) ) {
255                                 const char *p = ValueForKey(e, "s_shader");
256                                 if (p && *p) {
257                                         g_Inspectors->mediaDlg.SelectCurrentItem(true, p, CDialogTextures::SOUNDS);
258                                 }
259                                 
260                         }
261                         if ( ( e->eclass->nShowFlags & ECLASS_LIGHT ) && !brush->entityModel ) {
262                                 if (brush->pointLight) {
263                                         // add center drag point if not at the origin
264                                         if (brush->lightCenter[0] || brush->lightCenter[1] || brush->lightCenter[2]) {
265                                                 AddSelectablePoint(brush, Brush_TransformedPoint(brush, brush->lightCenter), LIGHT_CENTER, false);
266                                         }
267                                 }
268                                 else {
269                                         AddSelectablePoint(brush, Brush_TransformedPoint(brush, brush->lightTarget), LIGHT_TARGET, true);
270                                         AddSelectablePoint(brush, Brush_TransformedPoint(brush, brush->lightUp), LIGHT_UP, false);
271                                         AddSelectablePoint(brush, Brush_TransformedPoint(brush, brush->lightRight), LIGHT_RIGHT, false);
272                                         if (brush->startEnd) {
273                                                 AddSelectablePoint(brush, Brush_TransformedPoint(brush, brush->lightStart), LIGHT_START, false);
274                                                 AddSelectablePoint(brush, Brush_TransformedPoint(brush, brush->lightEnd), LIGHT_END, false);
275                                         }
276                                 }
277                 UpdateLightInspector();
278                         }
279                         if (e->eclass->nShowFlags & ECLASS_CAMERAVIEW) {
280                                 g_pParentWnd->GetCamera()->UpdateCameraView();
281                         }
282                 }
283         }
284
285         if (bStatus) {
286                 idVec3  vMin, vMax, vSize;
287                 Select_GetBounds(vMin, vMax);
288                 VectorSubtract(vMax, vMin, vSize);
289
290                 CString strStatus;
291                 strStatus.Format("Selection X:: %.1f  Y:: %.1f  Z:: %.1f", vSize[0], vSize[1], vSize[2]);
292                 g_pParentWnd->SetStatusText(2, strStatus);
293         }
294 }
295
296 /*
297  =======================================================================================================================
298     Select_Ray If the origin is inside a brush, that brush will be ignored.
299  =======================================================================================================================
300  */
301 void Select_Ray(idVec3 origin, idVec3 dir, int flags) {
302         qertrace_t      t;
303
304         t = Test_Ray(origin, dir, flags);
305
306         if (!t.brush) {
307                 return;
308         }
309
310         if (flags == SF_SINGLEFACE) {
311                 int             nCount = g_SelectedFaces.GetSize();
312                 bool    bOk = true;
313                 for (int i = 0; i < nCount; i++) {
314                         if (t.face == reinterpret_cast < face_t * > (g_SelectedFaces.GetAt(i))) {
315                                 bOk = false;
316
317                                 // need to move remove i'th entry
318                                 g_SelectedFaces.RemoveAt(i, 1);
319                                 g_SelectedFaceBrushes.RemoveAt(i, 1);
320                                 nCount--;
321                         }
322                 }
323
324                 if (bOk) {
325                         if ( t.selected ) {
326                                 face_t *face;
327
328                                 // DeSelect brush
329                                 Brush_RemoveFromList(t.brush);
330                                 Brush_AddToList(t.brush, &active_brushes);
331
332                                 // Select all brush faces
333                                 for ( face = t.brush->brush_faces; face; face = face->next ) {
334                                         //Don't add face that was clicked
335                                         if ( face != t.face ) {
336                                                 g_SelectedFaces.Add( face );
337                                                 g_SelectedFaceBrushes.Add( t.brush );
338                                         }
339                                 }
340                         } else {
341                                 g_SelectedFaces.Add(t.face);
342                                 g_SelectedFaceBrushes.Add(t.brush);
343                         }
344                 }
345
346                 // selected_face = t.face; selected_face_brush = t.brush;
347                 Sys_UpdateWindows(W_ALL);
348                 g_qeglobals.d_select_mode = sel_brush;
349
350
351                 //common->Printf("before\n");
352                 //extern void Face_Info_BrushPrimit(face_t *face);
353                 //Face_Info_BrushPrimit(t.face);
354                 //common->Printf("after\n");
355
356                 //
357                 // Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2
358                 // height=2 texture
359                 //
360                 brushprimit_texdef_t    brushprimit_texdef;
361                 ConvertTexMatWithQTexture(&t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL);
362                 Texture_SetTexture(&t.face->texdef, &brushprimit_texdef, false, false);
363                 UpdateSurfaceDialog();
364
365
366                 return;
367         }
368
369         // move the brush to the other list
370         g_qeglobals.d_select_mode = sel_brush;
371
372         if (t.selected) {
373                 Brush_RemoveFromList(t.brush);
374                 Brush_AddToList(t.brush, &active_brushes);
375                 UpdatePatchInspector();
376                 UpdateSurfaceDialog();
377
378                 entity_t        *e = t.brush->owner;
379                 if (e->eclass->nShowFlags & ECLASS_LIGHT && !t.brush->entityModel) {
380                         if (t.brush->pointLight) {
381                         }
382                         else {
383                                 ClearSelectablePoints(t.brush);
384                         }
385                 }
386         }
387         else {
388                 Select_Brush(t.brush, !(GetAsyncKeyState(VK_MENU) & 0x8000));
389         }
390
391         Sys_UpdateWindows(W_ALL);
392 }
393
394 /*
395  =======================================================================================================================
396  =======================================================================================================================
397  */
398 void Select_Delete(void) {
399         brush_t *brush;
400
401         g_ptrSelectedFaces.RemoveAll();
402         g_ptrSelectedFaceBrushes.RemoveAll();
403
404         // selected_face = NULL;
405         g_qeglobals.d_select_mode = sel_brush;
406
407         g_qeglobals.d_select_count = 0;
408         g_qeglobals.d_num_move_points = 0;
409         while (selected_brushes.next != &selected_brushes) {
410                 brush = selected_brushes.next;
411                 if (brush->pPatch) {
412                         // Patch_Delete(brush->nPatchID);
413                         Patch_Delete(brush->pPatch);
414                 }
415
416                 Brush_Free(brush);
417         }
418
419         // FIXME: remove any entities with no brushes
420         Sys_UpdateWindows(W_ALL);
421 }
422
423 /*
424  =======================================================================================================================
425  =======================================================================================================================
426  */
427 void Select_Deselect(bool bDeselectFaces) {
428         brush_t *b;
429
430         ClearSelectablePoints(NULL);
431         Patch_Deselect();
432
433         g_pParentWnd->ActiveXY()->UndoClear();
434
435         g_qeglobals.d_workcount++;
436         g_qeglobals.d_select_count = 0;
437         g_qeglobals.d_num_move_points = 0;
438         b = selected_brushes.next;
439
440         if (b == &selected_brushes) {
441                 if (bDeselectFaces) {
442                         g_ptrSelectedFaces.RemoveAll();
443                         g_ptrSelectedFaceBrushes.RemoveAll();
444
445                         // selected_face = NULL;
446                 }
447
448                 Sys_UpdateWindows(W_ALL);
449                 return;
450         }
451
452         if (bDeselectFaces) {
453                 g_ptrSelectedFaces.RemoveAll();
454                 g_ptrSelectedFaceBrushes.RemoveAll();
455
456                 // selected_face = NULL;
457         }
458
459         g_qeglobals.d_select_mode = sel_brush;
460
461         // grab top / bottom height for new brushes
462         if (b->mins[2] < b->maxs[2]) {
463                 g_qeglobals.d_new_brush_bottom = b->mins;
464                 g_qeglobals.d_new_brush_top = b->maxs;
465         }
466
467         selected_brushes.next->prev = &active_brushes;
468         selected_brushes.prev->next = active_brushes.next;
469         active_brushes.next->prev = selected_brushes.prev;
470         active_brushes.next = selected_brushes.next;
471         selected_brushes.prev = selected_brushes.next = &selected_brushes;
472
473         g_pParentWnd->GetCamera()->UpdateCameraView();
474
475         Sys_UpdateWindows(W_ALL);
476 }
477
478 /*
479  =======================================================================================================================
480     Select_Move
481  =======================================================================================================================
482  */
483 void Select_Move(idVec3 delta, bool bSnap) {
484         brush_t         *b;
485
486         // actually move the selected brushes
487         bool            updateOrigin = true;
488         entity_t        *lastOwner = selected_brushes.next->owner;
489
490         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
491                 Brush_Move(b, delta, bSnap, updateOrigin);
492                 if (updateOrigin) {
493                         updateOrigin = false;
494                 }
495
496                 if (b->next->owner != lastOwner) {
497                         updateOrigin = true;
498                         lastOwner = b->next->owner;
499                 }
500         }
501
502         idVec3  vMin, vMax;
503         Select_GetBounds(vMin, vMax);
504
505         CString strStatus;
506         strStatus.Format("Origin X:: %.1f  Y:: %.1f  Z:: %.1f", vMin[0], vMax[1], vMax[2]);
507         g_pParentWnd->SetStatusText(2, strStatus);
508         g_pParentWnd->GetCamera()->UpdateCameraView();
509
510         // Sys_UpdateWindows (W_ALL);
511 }
512
513 /*
514  =======================================================================================================================
515     Select_Clone Creates an exact duplicate of the selection in place, then moves the selected brushes off of their old
516     positions
517  =======================================================================================================================
518  */
519 void Select_Clone(void) {
520         ASSERT(g_pParentWnd->ActiveXY());
521         g_bScreenUpdates = false;
522         g_pParentWnd->ActiveXY()->Copy();
523         g_pParentWnd->ActiveXY()->Paste();
524         g_pParentWnd->NudgeSelection(2, g_qeglobals.d_gridsize);
525         g_pParentWnd->NudgeSelection(3, g_qeglobals.d_gridsize);
526         g_bScreenUpdates = true;
527         Sys_UpdateWindows(W_ALL);
528 }
529
530 /*
531  =======================================================================================================================
532     Select_SetTexture Timo:: bFitScale to compute scale on the plane and counteract plane / axial plane snapping Timo::
533     brush primitive texturing the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes
534     ) Timo:: texture plugin, added an IPluginTexdef* parameter must be casted to an IPluginTexdef! if not NULL, get
535     ->Copy() of it into each face or brush ( and remember to hook ) if NULL, means we have no information, ask for a
536     default
537  =======================================================================================================================
538  */
539 void WINAPI Select_SetTexture(texdef_t *texdef,brushprimit_texdef_t     *brushprimit_texdef,bool bFitScale,void *pPlugTexdef,bool update) {
540         brush_t *b;
541         int             nCount = g_ptrSelectedFaces.GetSize();
542         if (nCount > 0) {
543                 Undo_Start("set face textures");
544                 ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize());
545                 for (int i = 0; i < nCount; i++) {
546                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
547                         brush_t *selBrush = reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(i));
548                         Undo_AddBrush(selBrush);
549                         SetFaceTexdef(selBrush,selFace,texdef,brushprimit_texdef,bFitScale);
550                         Brush_Build(selBrush, bFitScale);
551                         Undo_EndBrush(selBrush);
552                 }
553
554                 Undo_End();
555         }
556         else if (selected_brushes.next != &selected_brushes) {
557                 Undo_Start("set brush textures");
558                 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
559                         if (!b->owner->eclass->fixedsize) {
560                                 Undo_AddBrush(b);
561                                 Brush_SetTexture(b, texdef, brushprimit_texdef, bFitScale);
562                                 Undo_EndBrush(b);
563                         } else if (b->owner->eclass->nShowFlags & ECLASS_LIGHT) {
564                                 if ( idStr::Cmpn(texdef->name, "lights/", strlen("lights/")) == 0 ) {
565                                         SetKeyValue(b->owner, "texture", texdef->name);
566                                         g_Inspectors->UpdateEntitySel(b->owner->eclass);
567                                         UpdateLightInspector();
568                                         Brush_Build(b);
569                                 } else {
570                                         Undo_AddBrush(b);
571                                         Brush_SetTexture(b, texdef, brushprimit_texdef, bFitScale);
572                                         Undo_EndBrush(b);
573                                 }
574                         }
575                 }
576
577                 Undo_End();
578         }
579
580         if (update) {
581                 Sys_UpdateWindows(W_ALL);
582         }
583 }
584
585 /*
586  =======================================================================================================================
587     TRANSFORMATIONS
588  =======================================================================================================================
589  */
590 void Select_GetBounds(idVec3 &mins, idVec3 &maxs) {
591         brush_t *b;
592         int             i;
593
594         for (i = 0; i < 3; i++) {
595                 mins[i] = 999999;
596                 maxs[i] = -999999;
597         }
598
599         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
600                 for (i = 0; i < 3; i++) {
601                         if (b->mins[i] < mins[i]) {
602                                 mins[i] = b->mins[i];
603                         }
604
605                         if (b->maxs[i] > maxs[i]) {
606                                 maxs[i] = b->maxs[i];
607                         }
608                 }
609         }
610 }
611
612 /*
613  =======================================================================================================================
614  =======================================================================================================================
615  */
616 void Select_GetTrueMid(idVec3 &mid) {
617         idVec3  mins, maxs;
618         Select_GetBounds(mins, maxs);
619
620         for (int i = 0; i < 3; i++) {
621                 mid[i] = (mins[i] + ((maxs[i] - mins[i]) / 2));
622         }
623 }
624
625 /*
626  =======================================================================================================================
627  =======================================================================================================================
628  */
629 void Select_GetMid(idVec3 &mid) {
630 #if 0
631         Select_GetTrueMid(mid);
632         return;
633 #else
634         idVec3  mins, maxs;
635         int             i;
636
637         //if (g_PrefsDlg.m_bNoClamp) {
638         //      Select_GetTrueMid(mid);
639         //      return;
640         //}
641
642         Select_GetBounds(mins, maxs);
643
644         for (i = 0; i < 3; i++) {
645                 mid[i] = g_qeglobals.d_gridsize * floor(((mins[i] + maxs[i]) * 0.5) / g_qeglobals.d_gridsize);
646         }
647 #endif
648 }
649
650 idVec3  select_origin;
651 idMat3  select_matrix;
652 idMat3  select_bmatrix;
653 idRotation select_rotation;
654 bool    select_fliporder;
655 int             select_flipAxis;
656 float   select_orgDeg;
657
658 void Select_InitializeRotation() {
659         for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) {
660                 for (face_t *f = b->brush_faces; f; f = f->next) {
661                         for (int i = 0; i < 3; i++) {
662                                 f->orgplanepts[i] = f->planepts[i];
663                         }
664                 }
665         }
666         select_orgDeg = 0.0;
667 }
668
669 void Select_FinalizeRotation() {
670
671 }
672
673 bool Select_OnlyModelsSelected() {
674         for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) {
675                 if (!b->modelHandle) {
676                         return false;
677                 }
678         }
679         return true;
680 }
681
682 bool OkForRotationKey(brush_t *b) {
683         if (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN) {
684                 return false;
685         }
686
687         if (stricmp(b->owner->epairs.GetString("name"), b->owner->epairs.GetString("model")) == 0) {
688                 return false;
689         }
690
691         return true;
692 }
693
694 /*
695 =================
696 VectorRotate3
697
698         rotation order is roll - pitch - yaw
699 =================
700 */
701 void VectorRotate3( const idVec3 &vIn, const idVec3 &vRotation, idVec3 &out) {
702 #if 1
703         int i, nIndex[3][2];
704         idVec3 vWork, va;
705
706         va = vIn;
707         vWork = va;
708         nIndex[0][0] = 1; nIndex[0][1] = 2;
709         nIndex[1][0] = 2; nIndex[1][1] = 0;
710         nIndex[2][0] = 0; nIndex[2][1] = 1;
711
712         for (i = 0; i < 3; i++) {
713                 if ( vRotation[i] != 0.0f ) {
714                         double dAngle = DEG2RAD( vRotation[i] );
715                         double c = cos( dAngle );
716                         double s = sin( dAngle );
717                         vWork[nIndex[i][0]] = va[nIndex[i][0]] * c - va[nIndex[i][1]] * s;
718                         vWork[nIndex[i][1]] = va[nIndex[i][0]] * s + va[nIndex[i][1]] * c;
719                 }
720                 va = vWork;
721         }
722         out = vWork;
723 #else
724         idAngles angles;
725
726         angles.pitch = vRotation[1];
727         angles.yaw = vRotation[2];
728         angles.roll = vRotation[0];
729
730         out = vIn * angles.ToMat3();
731 #endif
732 }
733
734 /*
735 =================
736 VectorRotate3Origin
737 =================
738 */
739 void VectorRotate3Origin( const idVec3 &vIn, const idVec3 &vRotation, const idVec3 &vOrigin, idVec3 &out ) {
740         out = vIn - vOrigin;
741         VectorRotate3( out, vRotation, out );
742         out += vOrigin;
743 }
744
745 /*
746  =======================================================================================================================
747  =======================================================================================================================
748  */
749 extern void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild);
750
751 void Select_ApplyMatrix(bool bSnap, bool rotateOrigins) {
752         brush_t *b;
753         face_t  *f;
754         int             i;
755         idVec3  temp;
756         idStr str;
757         char    text[128];
758         entity_t *lastOwner = NULL;
759
760         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
761                 
762                 bool doBrush = true;
763                 if (!(b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN) && b->owner != lastOwner) {
764                         if (b->modelHandle || b->owner->eclass->nShowFlags & ECLASS_ROTATABLE) {
765                                 if (rotateOrigins) {
766                                         b->owner->rotation *= select_matrix;
767                                         b->owner->origin *= select_rotation;
768                                         SetKeyVec3(b->owner, "origin", b->owner->origin);
769                                         if (b->trackLightOrigin) {
770                                                 b->owner->lightRotation *= select_matrix;
771                                                 b->owner->lightOrigin *= select_rotation;
772                                                 SetKeyVec3(b->owner, "light_origin", b->owner->lightOrigin);
773                                         }
774                                 } else {
775
776                                         b->owner->rotation *= select_matrix;
777                                         if ( select_fliporder ) {
778                                                 if ( select_flipAxis == 0 ) {
779                                                         temp = b->owner->rotation[1];
780                                                         b->owner->rotation[1] = b->owner->rotation[2];
781                                                         b->owner->rotation[2] = temp;
782                                                 } else if ( select_flipAxis == 1 ) {
783                                                         temp = b->owner->rotation[0];
784                                                         b->owner->rotation[0] = b->owner->rotation[1];
785                                                         b->owner->rotation[1] = temp;
786                                                 } else {
787                                                         temp = b->owner->rotation[0];
788                                                         b->owner->rotation[0] = b->owner->rotation[2];
789                                                         b->owner->rotation[2] = temp;
790                                                 }
791                                         }
792
793                                         if (b->trackLightOrigin) {
794                                                 b->owner->lightRotation = select_matrix * b->owner->lightRotation;
795                                         }
796                                 }
797                                 b->owner->rotation.OrthoNormalizeSelf();
798                                 b->owner->lightRotation.OrthoNormalizeSelf();
799
800                                 if (b->modelHandle) {
801                                         idBounds bo, bo2;
802                                         bo2.Zero();
803                                         if ( dynamic_cast<idRenderModelPrt*>( b->modelHandle ) || dynamic_cast<idRenderModelLiquid*>( b->modelHandle ) ) {
804                                                 bo2.ExpandSelf( 12.0f );
805                                         } else {
806                                                 bo2 = b->modelHandle->Bounds();
807                                         }
808                                         bo.FromTransformedBounds(bo2, b->owner->origin, b->owner->rotation);
809                                         Brush_Resize(b, bo[0], bo[1]);
810                                         doBrush = false;
811                                 } 
812                                 if (b->owner->eclass->fixedsize) {
813                                         doBrush = false;
814                                 }
815                         } else if (b->owner->eclass->fixedsize && !rotateOrigins) {
816                                 doBrush = false;
817                         } else {
818                                 b->owner->origin -= select_origin;
819                                 b->owner->origin *= select_matrix;
820                                 b->owner->origin += select_origin;
821                                 sprintf(text, "%i %i %i", (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
822
823                                 SetKeyValue(b->owner, "origin", text);
824                         }
825                         
826                    
827
828                         if (OkForRotationKey(b)) {
829                                 sprintf(str, "%g %g %g %g %g %g %g %g %g",b->owner->rotation[0][0],b->owner->rotation[0][1],b->owner->rotation[0][2],
830                                                 b->owner->rotation[1][0],b->owner->rotation[1][1],b->owner->rotation[1][2],b->owner->rotation[2][0],
831                                                 b->owner->rotation[2][1],b->owner->rotation[2][2]);
832                                 SetKeyValue(b->owner, "rotation", str);
833                         }
834                         
835                         if (b->trackLightOrigin) {
836                                 sprintf(str, "%g %g %g %g %g %g %g %g %g",b->owner->lightRotation[0][0],b->owner->lightRotation[0][1],b->owner->lightRotation[0][2],
837                                                 b->owner->lightRotation[1][0],b->owner->lightRotation[1][1],b->owner->lightRotation[1][2],b->owner->lightRotation[2][0],
838                                                 b->owner->lightRotation[2][1],b->owner->lightRotation[2][2]);
839                                 SetKeyValue(b->owner, "light_rotation", str);
840                         }
841                         DeleteKey(b->owner, "angle");
842                         DeleteKey(b->owner, "angles");
843                 }
844
845                 if (doBrush) {
846                         for (f = b->brush_faces; f; f = f->next) {
847                                 for (i = 0; i < 3; i++) {
848                                         f->planepts[i] = ( ((g_bRotateMode) ? f->orgplanepts[i] : f->planepts[i]) - select_origin ) * ((g_bRotateMode) ? select_bmatrix : select_matrix) + select_origin; 
849                                 }
850
851                                 if ( select_fliporder ) {
852                                         VectorCopy(f->planepts[0], temp);
853                                         VectorCopy(f->planepts[2], f->planepts[0]);
854                                         VectorCopy(temp, f->planepts[2]);
855                                 }
856                         }
857                 }
858
859                 if (b->owner->eclass->fixedsize && b->owner->eclass->entityModel == NULL) {
860                         idVec3 min, max;
861                         if (b->trackLightOrigin) {
862                                 min = b->owner->lightOrigin + b->owner->eclass->mins;
863                                 max = b->owner->lightOrigin + b->owner->eclass->maxs;
864                         } else {
865                                 min = b->owner->origin + b->owner->eclass->mins;
866                                 max = b->owner->origin + b->owner->eclass->maxs;
867                         }
868                         Brush_Resize(b, min, max);
869                 } else {
870                         Brush_Build(b, bSnap);
871                 }
872
873                 if (b->pPatch) {
874                         Patch_ApplyMatrix(b->pPatch, select_origin, select_matrix, bSnap);
875                 }
876
877                 if ( b->owner->curve ) {
878                         int c = b->owner->curve->GetNumValues();
879                         for ( i = 0; i < c; i++ ) {
880                                 idVec3 v = b->owner->curve->GetValue( i );
881                                 v -= select_origin;
882                                 v *= select_matrix;
883                                 v += select_origin;
884                                 b->owner->curve->SetValue( i, v );
885                         }
886                 }
887
888                 lastOwner = b->owner;
889         }
890 }
891
892 /*
893  =======================================================================================================================
894  =======================================================================================================================
895  */
896 void RotateFaceTexture(face_t *f, int nAxis, float fDeg) {
897         idVec3  p1, p2, p3, rota;
898         p1[0] = p1[1] = p1[2] = 0;
899         VectorCopy(p1, p2);
900         VectorCopy(p1, p3);
901         VectorCopy(p1, rota);
902         ComputeAbsolute(f, p1, p2, p3);
903
904         rota[nAxis] = fDeg;
905         VectorRotate3Origin(p1, rota, select_origin, p1);
906         VectorRotate3Origin(p2, rota, select_origin, p2);
907         VectorRotate3Origin(p3, rota, select_origin, p3);
908
909         idPlane         normal2;
910         idVec3          vNormal;
911         vNormal[0] = f->plane[0];
912         vNormal[1] = f->plane[1];
913         vNormal[2] = f->plane[2];
914         VectorRotate3(vNormal, rota, vNormal);
915         normal2[0] = vNormal[0];
916         normal2[1] = vNormal[1];
917         normal2[2] = vNormal[2];
918         AbsoluteToLocal(normal2, f, p1, p2, p3);
919 }
920
921 /*
922  =======================================================================================================================
923  =======================================================================================================================
924  */
925 void RotateTextures(int nAxis, float fDeg, idVec3 vOrigin) {
926         for (brush_t * b = selected_brushes.next; b != &selected_brushes; b = b->next) {
927                 for (face_t * f = b->brush_faces; f; f = f->next) {
928                         if (g_qeglobals.m_bBrushPrimitMode) {
929                                 RotateFaceTexture_BrushPrimit(f, nAxis, fDeg, vOrigin);
930                         }
931                         else {
932                                 RotateFaceTexture(f, nAxis, fDeg);
933                         }
934
935                         // ++timo removed that call .. works fine .. ??????? Brush_Build(b, false);
936                 }
937
938                 Brush_Build(b, false);
939         }
940 }
941
942 /*
943  =======================================================================================================================
944  =======================================================================================================================
945  */
946 void Select_ApplyMatrix_BrushPrimit() {
947         for (brush_t * b = selected_brushes.next; b != &selected_brushes; b = b->next) {
948                 for (face_t * f = b->brush_faces; f; f = f->next) {
949                         ApplyMatrix_BrushPrimit(f, select_matrix, select_origin);
950                 }
951         }
952 }
953
954 /*
955  =======================================================================================================================
956  =======================================================================================================================
957  */
958 void Select_RotateAxis(int axis, float deg, bool bPaint, bool bMouse) {
959         idVec3  temp;
960
961         if (deg == 0) {
962                 return;
963         }
964
965         if (bMouse) {
966                 if (g_qeglobals.flatRotation == 2) {
967                         Select_GetTrueMid(select_origin);
968                 } else {
969                         VectorCopy(g_pParentWnd->ActiveXY()->RotateOrigin(), select_origin);
970                 }
971         } else {
972                 Select_GetMid(select_origin);
973         }
974
975         select_fliporder = false;
976
977         idVec3 vec = vec3_origin;
978         vec[axis] = 1.0f;
979
980         if (g_bRotateMode) {
981                 select_orgDeg += deg;
982         }
983
984         select_rotation.Set( select_origin, vec, deg );
985         select_matrix = select_rotation.ToMat3();
986         idRotation rot(select_origin, vec, select_orgDeg);
987         rot.Normalize360();
988         select_bmatrix = rot.ToMat3();
989
990
991         if (g_PrefsDlg.m_bRotateLock) {
992                 select_matrix.TransposeSelf();
993                 Select_ApplyMatrix_BrushPrimit();
994                 //RotateTextures(axis, -deg, select_origin);
995         }
996
997         select_matrix.TransposeSelf();
998         Select_ApplyMatrix( !bMouse, ( g_qeglobals.flatRotation != 0 ) );
999
1000         if (bPaint) {
1001                 Sys_UpdateWindows(W_ALL);
1002         }
1003 }
1004
1005 /*
1006  =======================================================================================================================
1007  =======================================================================================================================
1008  */
1009 void ProjectOnPlane( const idVec3 &normal, float dist, idVec3 &ez, idVec3 &p) {
1010         if (idMath::Fabs(ez[0]) == 1) {
1011                 p[0] = (dist - normal[1] * p[1] - normal[2] * p[2]) / normal[0];
1012         }
1013         else if (idMath::Fabs(ez[1]) == 1) {
1014                 p[1] = (dist - normal[0] * p[0] - normal[2] * p[2]) / normal[1];
1015         }
1016         else {
1017                 p[2] = (dist - normal[0] * p[0] - normal[1] * p[1]) / normal[2];
1018         }
1019 }
1020
1021 /*
1022  =======================================================================================================================
1023  =======================================================================================================================
1024  */
1025 void Back(idVec3 &dir, idVec3 &p) {
1026         if (idMath::Fabs(dir[0]) == 1) {
1027                 p[0] = 0;
1028         }
1029         else if (idMath::Fabs(dir[1]) == 1) {
1030                 p[1] = 0;
1031         }
1032         else {
1033                 p[2] = 0;
1034         }
1035 }
1036
1037 //
1038 // =======================================================================================================================
1039 //    using scale[0] and scale[1]
1040 // =======================================================================================================================
1041 //
1042 void ComputeScale(idVec3 &rex, idVec3 &rey, idVec3 &p, face_t *f) {
1043         float   px = DotProduct(rex, p);
1044         float   py = DotProduct(rey, p);
1045         px *= f->texdef.scale[0];
1046         py *= f->texdef.scale[1];
1047
1048         idVec3  aux;
1049         VectorCopy(rex, aux);
1050         VectorScale(aux, px, aux);
1051         VectorCopy(aux, p);
1052         VectorCopy(rey, aux);
1053         VectorScale(aux, py, aux);
1054         VectorAdd(p, aux, p);
1055 }
1056
1057 /*
1058  =======================================================================================================================
1059  =======================================================================================================================
1060  */
1061 void ComputeAbsolute(face_t *f, idVec3 &p1, idVec3 &p2, idVec3 &p3) {
1062         idVec3  ex, ey, ez; // local axis base
1063
1064 #ifdef _DEBUG
1065         if (g_qeglobals.m_bBrushPrimitMode) {
1066                 common->Printf("Warning : illegal call of ComputeAbsolute in brush primitive mode\n");
1067         }
1068 #endif
1069         // compute first local axis base
1070         TextureAxisFromPlane( f->plane, ex, ey );
1071         ez = ex.Cross( ey );
1072
1073         idVec3  aux;
1074         VectorCopy(ex, aux);
1075         VectorScale(aux, -f->texdef.shift[0], aux);
1076         VectorCopy(aux, p1);
1077         VectorCopy(ey, aux);
1078         VectorScale(aux, -f->texdef.shift[1], aux);
1079         VectorAdd(p1, aux, p1);
1080         VectorCopy(p1, p2);
1081         VectorAdd(p2, ex, p2);
1082         VectorCopy(p1, p3);
1083         VectorAdd(p3, ey, p3);
1084         VectorCopy(ez, aux);
1085         VectorScale(aux, -f->texdef.rotate, aux);
1086         VectorRotate3(p1, aux, p1);
1087         VectorRotate3(p2, aux, p2);
1088         VectorRotate3(p3, aux, p3);
1089
1090         // computing rotated local axis base
1091         idVec3  rex, rey;
1092         VectorCopy(ex, rex);
1093         VectorRotate3(rex, aux, rex);
1094         VectorCopy(ey, rey);
1095         VectorRotate3(rey, aux, rey);
1096
1097         ComputeScale(rex, rey, p1, f);
1098         ComputeScale(rex, rey, p2, f);
1099         ComputeScale(rex, rey, p3, f);
1100
1101         // project on normal plane along ez assumes plane normal is normalized
1102         ProjectOnPlane(f->plane.Normal(), -f->plane[3], ez, p1);
1103         ProjectOnPlane(f->plane.Normal(), -f->plane[3], ez, p2);
1104         ProjectOnPlane(f->plane.Normal(), -f->plane[3], ez, p3);
1105 };
1106
1107 /*
1108  =======================================================================================================================
1109  =======================================================================================================================
1110  */
1111 void AbsoluteToLocal( const idPlane &normal2, face_t *f, idVec3 &p1, idVec3 &p2, idVec3 &p3) {
1112         idVec3  ex, ey, ez;
1113
1114 #ifdef _DEBUG
1115         if (g_qeglobals.m_bBrushPrimitMode) {
1116                 common->Printf("Warning : illegal call of AbsoluteToLocal in brush primitive mode\n");
1117         }
1118 #endif
1119         // computing new local axis base
1120         TextureAxisFromPlane( normal2, ex, ey );
1121         ez = ex.Cross( ey );
1122
1123         // projecting back on (ex,ey)
1124         Back(ez, p1);
1125         Back(ez, p2);
1126         Back(ez, p3);
1127
1128         idVec3  aux;
1129
1130         // rotation
1131         VectorCopy(p2, aux);
1132         VectorSubtract(aux, p1, aux);
1133
1134         float   x = DotProduct(aux, ex);
1135         float   y = DotProduct(aux, ey);
1136         f->texdef.rotate = RAD2DEG( atan2(y, x) );
1137
1138         idVec3  rex, rey;
1139
1140         // computing rotated local axis base
1141         VectorCopy(ez, aux);
1142         VectorScale(aux, f->texdef.rotate, aux);
1143         VectorCopy(ex, rex);
1144         VectorRotate3(rex, aux, rex);
1145         VectorCopy(ey, rey);
1146         VectorRotate3(rey, aux, rey);
1147
1148         // scale
1149         VectorCopy(p2, aux);
1150         VectorSubtract(aux, p1, aux);
1151         f->texdef.scale[0] = DotProduct(aux, rex);
1152         VectorCopy(p3, aux);
1153         VectorSubtract(aux, p1, aux);
1154         f->texdef.scale[1] = DotProduct(aux, rey);
1155
1156         // shift only using p1
1157         x = DotProduct(rex, p1);
1158         y = DotProduct(rey, p1);
1159         x /= f->texdef.scale[0];
1160         y /= f->texdef.scale[1];
1161
1162         VectorCopy(rex, p1);
1163         VectorScale(p1, x, p1);
1164         VectorCopy(rey, aux);
1165         VectorScale(aux, y, aux);
1166         VectorAdd(p1, aux, p1);
1167         VectorCopy(ez, aux);
1168         VectorScale(aux, -f->texdef.rotate, aux);
1169         VectorRotate3(p1, aux, p1);
1170         f->texdef.shift[0] = -DotProduct(p1, ex);
1171         f->texdef.shift[1] = -DotProduct(p1, ey);
1172
1173         // stored rot is good considering local axis base change it if necessary
1174         f->texdef.rotate = -f->texdef.rotate;
1175
1176         Clamp(f->texdef.shift[0], f->d_texture->GetEditorImage()->uploadWidth);
1177         Clamp(f->texdef.shift[1], f->d_texture->GetEditorImage()->uploadHeight);
1178         Clamp(f->texdef.rotate, 360);
1179 }
1180
1181 /*
1182  =======================================================================================================================
1183  =======================================================================================================================
1184  */
1185 void Select_FlipAxis(int axis) {
1186
1187         Select_GetMid( select_origin );
1188         
1189         for ( int i = 0; i < 3; i++) {
1190                 VectorCopy(vec3_origin, select_matrix[i]);
1191                 select_matrix[i][i] = 1;
1192         }
1193
1194         select_matrix[axis][axis] = -1;
1195
1196         select_matrix.Identity();
1197         select_matrix[axis][axis] = -1;
1198
1199         select_fliporder = true;
1200         select_flipAxis = axis;
1201
1202         // texture locking
1203         if (g_PrefsDlg.m_bRotateLock) {
1204                 //
1205                 // axis flipping inverts space orientation, we have to use a general texture
1206                 // locking algorithm instead of the RotateFaceTexture
1207                 //
1208                 if (g_qeglobals.m_bBrushPrimitMode) {
1209                         Select_ApplyMatrix_BrushPrimit();
1210                 }
1211                 else {
1212                         //
1213                         // there's never been flip locking for non BP mode, this would be tricky to write
1214                         // and there's not much interest for it with the coming of BP format what could be
1215                         // done is converting regular to BP, locking, then back to regular :)
1216                         // Sys_FPrintf(SYS_WRN, "WARNING: regular texturing doesn't have texture lock on
1217                         // flipping operations\n");
1218                         //
1219                 }
1220         }
1221
1222         // geometric transformation
1223         Select_ApplyMatrix(true, false);
1224         Sys_UpdateWindows(W_ALL);}
1225
1226 /*
1227  =======================================================================================================================
1228  =======================================================================================================================
1229  */
1230 void Select_Scale(float x, float y, float z) {
1231         Select_GetMid(select_origin);
1232         for (brush_t * b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1233                 for (face_t * f = b->brush_faces; f; f = f->next) {
1234                         for (int i = 0; i < 3; i++) {
1235                                 f->planepts[i][0] -= select_origin[0];
1236                                 f->planepts[i][1] -= select_origin[1];
1237                                 f->planepts[i][2] -= select_origin[2];
1238                                 f->planepts[i][0] *= x;
1239
1240                                 //
1241                                 // f->planepts[i][0] = floor(f->planepts[i][0] / g_qeglobals.d_gridsize + 0.5) *
1242                                 // g_qeglobals.d_gridsize;
1243                                 //
1244                                 f->planepts[i][1] *= y;
1245
1246                                 //
1247                                 // f->planepts[i][1] = floor(f->planepts[i][1] / g_qeglobals.d_gridsize + 0.5) *
1248                                 // g_qeglobals.d_gridsize;
1249                                 //
1250                                 f->planepts[i][2] *= z;
1251
1252                                 //
1253                                 // f->planepts[i][2] = floor(f->planepts[i][2] / g_qeglobals.d_gridsize + 0.5) *
1254                                 // g_qeglobals.d_gridsize;
1255                                 //
1256                                 f->planepts[i][0] += select_origin[0];
1257                                 f->planepts[i][1] += select_origin[1];
1258                                 f->planepts[i][2] += select_origin[2];
1259                         }
1260                 }
1261
1262                 Brush_Build(b, false);
1263                 if (b->pPatch) {
1264                         idVec3  v;
1265                         v[0] = x;
1266                         v[1] = y;
1267                         v[2] = z;
1268
1269                         // Patch_Scale(b->nPatchID, select_origin, v);
1270                         Patch_Scale(b->pPatch, select_origin, v);
1271                 }
1272         }
1273 }
1274
1275 /*
1276  =======================================================================================================================
1277     GROUP SELECTIONS
1278  =======================================================================================================================
1279  */
1280 void Select_CompleteTall(void) {
1281         brush_t *b, *next;
1282
1283         // int i;
1284         idVec3  mins, maxs;
1285
1286         if (!QE_SingleBrush()) {
1287                 return;
1288         }
1289
1290         g_qeglobals.d_select_mode = sel_brush;
1291
1292         VectorCopy(selected_brushes.next->mins, mins);
1293         VectorCopy(selected_brushes.next->maxs, maxs);
1294         Select_Delete();
1295
1296         int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
1297         int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
1298
1299         for (b = active_brushes.next; b != &active_brushes; b = next) {
1300                 next = b->next;
1301
1302                 if ((b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1]) || (b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2])) {
1303                         if (!(b->owner->origin[nDim1] > mins[nDim1] && b->owner->origin[nDim1] < maxs[nDim1] && b->owner->origin[nDim2] > mins[nDim2] && b->owner->origin[nDim2] < maxs[nDim2])) {
1304                                 continue;
1305                         }
1306                         if (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN) {
1307                                 continue;
1308                         }
1309                 }
1310
1311                 if (FilterBrush(b)) {
1312                         continue;
1313                 }
1314
1315                 Brush_RemoveFromList(b);
1316                 Brush_AddToList(b, &selected_brushes);
1317         }
1318
1319         Sys_UpdateWindows(W_ALL);
1320 }
1321
1322 /*
1323  =======================================================================================================================
1324  =======================================================================================================================
1325  */
1326 void Select_PartialTall(void) {
1327         brush_t *b, *next;
1328
1329         // int i;
1330         idVec3  mins, maxs;
1331
1332         if (!QE_SingleBrush()) {
1333                 return;
1334         }
1335
1336         g_qeglobals.d_select_mode = sel_brush;
1337
1338         VectorCopy(selected_brushes.next->mins, mins);
1339         VectorCopy(selected_brushes.next->maxs, maxs);
1340         Select_Delete();
1341
1342         int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
1343         int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
1344
1345         for (b = active_brushes.next; b != &active_brushes; b = next) {
1346                 next = b->next;
1347
1348                 if
1349                 (
1350                         (b->mins[nDim1] > maxs[nDim1] || b->maxs[nDim1] < mins[nDim1]) ||
1351                         (b->mins[nDim2] > maxs[nDim2] || b->maxs[nDim2] < mins[nDim2])
1352                 ) {
1353                         continue;
1354                 }
1355
1356                 if (FilterBrush(b)) {
1357                         continue;
1358                 }
1359
1360                 Brush_RemoveFromList(b);
1361                 Brush_AddToList(b, &selected_brushes);
1362
1363 #if 0
1364                 // old stuff
1365                 for (i = 0; i < 2; i++) {
1366                         if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i]) {
1367                                 break;
1368                         }
1369                 }
1370
1371                 if (i == 2) {
1372                         Brush_RemoveFromList(b);
1373                         Brush_AddToList(b, &selected_brushes);
1374                 }
1375 #endif
1376         }
1377
1378         Sys_UpdateWindows(W_ALL);
1379 }
1380
1381 /*
1382  =======================================================================================================================
1383  =======================================================================================================================
1384  */
1385 void Select_Touching(void) {
1386         brush_t *b, *next;
1387         int             i;
1388         idVec3  mins, maxs;
1389
1390         if (!QE_SingleBrush()) {
1391                 return;
1392         }
1393
1394         g_qeglobals.d_select_mode = sel_brush;
1395
1396         VectorCopy(selected_brushes.next->mins, mins);
1397         VectorCopy(selected_brushes.next->maxs, maxs);
1398
1399         for (b = active_brushes.next; b != &active_brushes; b = next) {
1400                 next = b->next;
1401
1402                 if (FilterBrush(b)) {
1403                         continue;
1404                 }
1405
1406                 for (i = 0; i < 3; i++) {
1407                         if (b->mins[i] > maxs[i] + 1 || b->maxs[i] < mins[i] - 1) {
1408                                 break;
1409                         }
1410                 }
1411
1412                 if (i == 3) {
1413                         Brush_RemoveFromList(b);
1414                         Brush_AddToList(b, &selected_brushes);
1415                 }
1416         }
1417
1418         Sys_UpdateWindows(W_ALL);
1419 }
1420
1421 /*
1422  =======================================================================================================================
1423  =======================================================================================================================
1424  */
1425 void Select_Inside(void) {
1426         brush_t *b, *next;
1427         int             i;
1428         idVec3  mins, maxs;
1429
1430         if (!QE_SingleBrush()) {
1431                 return;
1432         }
1433
1434         g_qeglobals.d_select_mode = sel_brush;
1435
1436         VectorCopy(selected_brushes.next->mins, mins);
1437         VectorCopy(selected_brushes.next->maxs, maxs);
1438         Select_Delete();
1439
1440         for (b = active_brushes.next; b != &active_brushes; b = next) {
1441                 next = b->next;
1442
1443                 if (FilterBrush(b)) {
1444                         continue;
1445                 }
1446
1447                 for (i = 0; i < 3; i++) {
1448                         if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) {
1449                                 break;
1450                         }
1451                 }
1452
1453                 if (i == 3) {
1454                         Brush_RemoveFromList(b);
1455                         Brush_AddToList(b, &selected_brushes);
1456                 }
1457         }
1458
1459         Sys_UpdateWindows(W_ALL);
1460 }
1461
1462 /*
1463  =======================================================================================================================
1464     Select_Ungroup Turn the currently selected entity back into normal brushes
1465  =======================================================================================================================
1466  */
1467 void Select_Ungroup() {
1468         int                     numselectedgroups;
1469         entity_t        *e;
1470         brush_t         *b, *sb;
1471
1472         numselectedgroups = 0;
1473         for (sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next) {
1474                 e = sb->owner;
1475
1476                 if (!e || e == world_entity) {
1477                         continue;
1478                 }
1479
1480                 for (b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext) {
1481                         Entity_UnlinkBrush(b);
1482                         Entity_LinkBrush(world_entity, b);
1483                         Brush_Build(b);
1484                         b->owner = world_entity;
1485                 }
1486
1487                 Entity_Free(e);
1488                 numselectedgroups++;
1489         }
1490
1491         if (numselectedgroups <= 0) {
1492                 Sys_Status("No grouped entities selected.\n");
1493                 return;
1494         }
1495
1496         common->Printf("Ungrouped %d entit%s.\n", numselectedgroups, (numselectedgroups == 1) ? "y" : "ies");
1497         Sys_UpdateWindows(W_ALL);
1498 }
1499
1500 /*
1501  =======================================================================================================================
1502  =======================================================================================================================
1503  */
1504 void Select_ShiftTexture(float x, float y, bool autoAdjust) {
1505         brush_t *b;
1506         face_t  *f;
1507
1508         int             nFaceCount = g_ptrSelectedFaces.GetSize();
1509
1510         if (selected_brushes.next == &selected_brushes && nFaceCount == 0) {
1511                 return;
1512         }
1513
1514         x = -x;
1515
1516         Undo_Start("Select shift textures");
1517         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1518                 for (f = b->brush_faces; f; f = f->next) {
1519                         if (g_qeglobals.m_bBrushPrimitMode) {
1520                                 // use face normal to compute a true translation
1521                                 Select_ShiftTexture_BrushPrimit(f, x, y, autoAdjust);
1522                         }
1523                         else {
1524                                 f->texdef.shift[0] += x;
1525                                 f->texdef.shift[1] += y;
1526                         }
1527                 }
1528
1529                 Brush_Build(b);
1530                 if (b->pPatch) {
1531                         // Patch_ShiftTexture(b->nPatchID, x, y);
1532                         Patch_ShiftTexture(b->pPatch, x, y, autoAdjust);
1533                 }
1534         }
1535
1536         if (nFaceCount > 0) {
1537                 for (int i = 0; i < nFaceCount; i++) {
1538                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1539                         brush_t *selBrush = reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(i));
1540                         if (g_qeglobals.m_bBrushPrimitMode) {
1541                                 //
1542                                 // use face normal to compute a true translation Select_ShiftTexture_BrushPrimit(
1543                                 // selected_face, x, y ); use camera view to compute texture shift
1544                                 //
1545                                 Select_ShiftTexture_BrushPrimit(selFace, x, y, autoAdjust);
1546                         }
1547                         else {
1548                                 selFace->texdef.shift[0] += x;
1549                                 selFace->texdef.shift[1] += y;
1550                         }
1551
1552                         Brush_Build(selBrush);
1553                 }
1554         }
1555
1556         Undo_End();
1557         Sys_UpdateWindows(W_CAMERA);
1558 }
1559
1560 extern void     Face_SetExplicitScale_BrushPrimit(face_t *face, float s, float t);
1561 extern void Face_ScaleTexture_BrushPrimit(face_t *face, float sS, float sT);
1562
1563 /*
1564  =======================================================================================================================
1565  =======================================================================================================================
1566  */
1567 void Select_ScaleTexture(float x, float y, bool update, bool absolute) {
1568         brush_t *b;
1569         face_t  *f;
1570
1571         int             nFaceCount = g_ptrSelectedFaces.GetSize();
1572
1573         if (selected_brushes.next == &selected_brushes && nFaceCount == 0) {
1574                 return;
1575         }
1576
1577         Undo_Start("Select_SetExplicitScale_BrushPrimit");
1578         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1579                 for (f = b->brush_faces; f; f = f->next) {
1580                         if (g_qeglobals.m_bBrushPrimitMode && f->face_winding) {
1581                                 if (absolute) {
1582                                         Face_SetExplicitScale_BrushPrimit(f, x, y);
1583                                 } else {
1584                                         Face_ScaleTexture_BrushPrimit(f, x, y);
1585                                 }
1586                         }
1587                         else {
1588                                 f->texdef.scale[0] += x;
1589                                 f->texdef.scale[1] += y;
1590                         }
1591                 }
1592
1593                 Brush_Build(b);
1594                 if (b->pPatch) {
1595                         Patch_ScaleTexture(b->pPatch, x, y, absolute);
1596                 }
1597         }
1598
1599         if (nFaceCount > 0) {
1600                 for (int i = 0; i < nFaceCount; i++) {
1601                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1602                         brush_t *selBrush = reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(i));
1603                         if (g_qeglobals.m_bBrushPrimitMode) {
1604                                 if (absolute) {
1605                                         Face_SetExplicitScale_BrushPrimit(selFace, x, y);
1606                                 } else {
1607                                         Face_ScaleTexture_BrushPrimit(selFace, x, y);
1608                                 }
1609                         }
1610                         else {
1611                                 selFace->texdef.scale[0] += x;
1612                                 selFace->texdef.scale[1] += y;
1613                         }
1614
1615                         Brush_Build(selBrush);
1616                 }
1617         }
1618
1619         Undo_End();
1620         if (update) {
1621                 Sys_UpdateWindows(W_CAMERA);
1622         }
1623 }
1624
1625 extern void Face_RotateTexture_BrushPrimit(face_t *face, float amount, idVec3 origin);
1626
1627 /*
1628  =======================================================================================================================
1629  =======================================================================================================================
1630  */
1631 void Select_RotateTexture(float amt, bool absolute) {
1632         brush_t *b;
1633         face_t  *f;
1634
1635         int             nFaceCount = g_ptrSelectedFaces.GetSize();
1636
1637         if (selected_brushes.next == &selected_brushes && nFaceCount == 0) {
1638                 return;
1639         }
1640
1641         Undo_Start("Select_RotateTexture_BrushPrimit");
1642         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1643                 for (f = b->brush_faces; f; f = f->next) {
1644                         if (g_qeglobals.m_bBrushPrimitMode) {
1645                                 Face_RotateTexture_BrushPrimit(f, amt, b->owner->origin);
1646                         }
1647                         else {
1648                                 f->texdef.rotate += amt;
1649                                 f->texdef.rotate = static_cast<int>(f->texdef.rotate) % 360;
1650                         }
1651                 }
1652
1653                 Brush_Build(b);
1654                 if (b->pPatch) {
1655                         // Patch_RotateTexture(b->nPatchID, amt);
1656                         Patch_RotateTexture(b->pPatch, amt);
1657                 }
1658         }
1659
1660         if (nFaceCount > 0) {
1661                 for (int i = 0; i < nFaceCount; i++) {
1662                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1663                         brush_t *selBrush = reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(i));
1664                         if (g_qeglobals.m_bBrushPrimitMode) {
1665                                 idVec3 org;
1666                                 org.Zero();
1667                                 //Face_RotateTexture_BrushPrimit(selFace, amt, selBrush->owner->origin);
1668                                 Face_RotateTexture_BrushPrimit(selFace, amt, org);
1669                         }
1670                         else {
1671                                 selFace->texdef.rotate += amt;
1672                                 selFace->texdef.rotate = static_cast<int>(selFace->texdef.rotate) % 360;
1673                         }
1674
1675                         Brush_Build(selBrush);
1676                 }
1677         }
1678
1679         Undo_End();
1680         Sys_UpdateWindows(W_CAMERA);
1681 }
1682
1683 /*
1684  =======================================================================================================================
1685  =======================================================================================================================
1686  */
1687 void FindReplaceTextures(const char *pFind, const char *pReplace, bool bSelected, bool bForce) {
1688         brush_t *pList = (bSelected) ? &selected_brushes : &active_brushes;
1689         if (!bSelected) {
1690                 Select_Deselect();
1691         }
1692
1693         for (brush_t * pBrush = pList->next; pBrush != pList; pBrush = pBrush->next) {
1694                 if (pBrush->pPatch) {
1695                         Patch_FindReplaceTexture(pBrush, pFind, pReplace, bForce);
1696                 }
1697
1698                 for (face_t * pFace = pBrush->brush_faces; pFace; pFace = pFace->next) {
1699                         if (bForce || idStr::Icmp(pFace->texdef.name, pFind) == 0 ) {
1700                                 pFace->d_texture = Texture_ForName(pReplace);
1701
1702                                 // strcpy(pFace->texdef.name, pReplace);
1703                                 pFace->texdef.SetName(pReplace);
1704                         }
1705                 }
1706
1707                 Brush_Build(pBrush);
1708         }
1709
1710         Sys_UpdateWindows(W_CAMERA);
1711 }
1712
1713 /*
1714  =======================================================================================================================
1715  =======================================================================================================================
1716  */
1717 void Select_AllOfType() {
1718         brush_t         *b, *next;
1719         entity_t        *e;
1720         if ((selected_brushes.next == &selected_brushes) || (selected_brushes.next->next != &selected_brushes)) {
1721                 CString strName;
1722                 if (g_ptrSelectedFaces.GetSize() == 0) {
1723                         strName = g_qeglobals.d_texturewin.texdef.name;
1724                 }
1725                 else {
1726                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(0));
1727                         strName = selFace->texdef.name;
1728                 }
1729
1730                 Select_Deselect();
1731                 for (b = active_brushes.next; b != &active_brushes; b = next) {
1732                         next = b->next;
1733
1734                         if (FilterBrush(b)) {
1735                                 continue;
1736                         }
1737
1738                         if (b->pPatch) {
1739                                 if ( idStr::Icmp(strName, b->pPatch->d_texture->GetName()) == 0 ) {
1740                                         Brush_RemoveFromList(b);
1741                                         Brush_AddToList(b, &selected_brushes);
1742                                 }
1743                         }
1744                         else {
1745                                 for (face_t * pFace = b->brush_faces; pFace; pFace = pFace->next) {
1746                                         if ( idStr::Icmp(strName, pFace->texdef.name) == 0 ) {
1747                                                 Brush_RemoveFromList(b);
1748                                                 Brush_AddToList(b, &selected_brushes);
1749                                         }
1750                                 }
1751                         }
1752                 }
1753
1754                 Sys_UpdateWindows(W_ALL);
1755                 return;
1756         }
1757
1758         b = selected_brushes.next;
1759         e = b->owner;
1760         if (e != NULL) {
1761                 if (e != world_entity) {
1762                         CString strName = e->eclass->name;
1763                         idStr strKey, strVal;
1764                         bool    bCriteria = g_Inspectors->GetSelectAllCriteria(strKey, strVal);
1765                         common->Printf("Selecting all %s(s)\n", strName);
1766                         Select_Deselect();
1767
1768                         for (b = active_brushes.next; b != &active_brushes; b = next) {
1769                                 next = b->next;
1770
1771                                 if (FilterBrush(b)) {
1772                                         continue;
1773                                 }
1774
1775                                 e = b->owner;
1776                                 if (e != NULL) {
1777                                         if ( idStr::Icmp(e->eclass->name, strName) == 0 ) {
1778                                                 bool    doIt = true;
1779                                                 if (bCriteria) {
1780                                                         CString str = ValueForKey(e, strKey);
1781                                                         if (str.CompareNoCase(strVal) != 0) {
1782                                                                 doIt = false;
1783                                                         }
1784                                                 }
1785
1786                                                 if (doIt) {
1787                                                         Brush_RemoveFromList(b);
1788                                                         Brush_AddToList(b, &selected_brushes);
1789                                                 }
1790                                         }
1791                                 }
1792                         }
1793                 }
1794         }
1795
1796
1797         if ( selected_brushes.next && selected_brushes.next->owner ) {
1798                 g_Inspectors->UpdateEntitySel( selected_brushes.next->owner->eclass );
1799         }
1800
1801         Sys_UpdateWindows(W_ALL);
1802 }
1803
1804 /*
1805  =======================================================================================================================
1806  =======================================================================================================================
1807  */
1808 void Select_Reselect() {
1809         CPtrArray       holdArray;
1810         brush_t *b;
1811         for ( b = selected_brushes.next; b && b != &selected_brushes; b = b->next ) {
1812                 holdArray.Add(reinterpret_cast < void * > (b));
1813         }
1814
1815         int n = holdArray.GetSize();
1816         while (n-- > 0) {
1817                 b = reinterpret_cast < brush_t * > (holdArray.GetAt(n));
1818                 Select_Brush(b);
1819         }
1820
1821         Sys_UpdateWindows(W_ALL);
1822 }
1823
1824 /*
1825  =======================================================================================================================
1826  =======================================================================================================================
1827  */
1828 void Select_FitTexture(float height, float width) {
1829         brush_t *b;
1830         int             nFaceCount = g_ptrSelectedFaces.GetSize();
1831
1832         if (selected_brushes.next == &selected_brushes && nFaceCount == 0) {
1833                 return;
1834         }
1835
1836         Undo_Start("Select_FitTexture");
1837         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1838                 if (b->pPatch) {
1839                         Patch_FitTexture(b->pPatch, width, height);
1840                 }
1841                 else {
1842                         Brush_FitTexture(b, height, width);
1843                         Brush_Build(b);
1844                 }
1845         }
1846
1847         if (nFaceCount > 0) {
1848                 for (int i = 0; i < nFaceCount; i++) {
1849                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
1850                         brush_t *selBrush = reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(i));
1851                         Face_FitTexture(selFace, height, width);
1852                         Brush_Build(selBrush);
1853                 }
1854         }
1855
1856         Undo_End();
1857         Sys_UpdateWindows(W_CAMERA);
1858 }
1859
1860 /*
1861  =======================================================================================================================
1862  =======================================================================================================================
1863  */
1864 void Select_AxialTexture() {
1865 }
1866
1867 /*
1868  =======================================================================================================================
1869  =======================================================================================================================
1870  */
1871 void Select_Hide(bool invert) {
1872
1873         if (invert) {
1874                 for (brush_t * b = active_brushes.next; b && b != &active_brushes; b = b->next) {
1875                         b->hiddenBrush = true;
1876                 }
1877         } else {
1878                 for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
1879                         b->hiddenBrush = true;
1880                 }
1881         }
1882         Sys_UpdateWindows(W_ALL);
1883 }
1884
1885 void Select_WireFrame( bool wireFrame ) {
1886         for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
1887                 b->forceWireFrame = wireFrame;
1888         }
1889         Sys_UpdateWindows(W_ALL);
1890 }
1891
1892 void Select_ForceVisible( bool visible ) {
1893         for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
1894                 b->forceVisibile = visible;
1895         }
1896         Sys_UpdateWindows(W_ALL);
1897 }
1898
1899 /*
1900  =======================================================================================================================
1901  =======================================================================================================================
1902  */
1903 void Select_ShowAllHidden() {
1904         brush_t *b;
1905         for (b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
1906                 b->hiddenBrush = false;
1907         }
1908
1909         for (b = active_brushes.next; b && b != &active_brushes; b = b->next) {
1910                 b->hiddenBrush = false;
1911         }
1912
1913         Sys_UpdateWindows(W_ALL);
1914 }
1915
1916 /*
1917  =======================================================================================================================
1918     Select_Invert
1919  =======================================================================================================================
1920  */
1921 void Select_Invert(void) {
1922         brush_t *next, *prev;
1923
1924         Sys_Status("inverting selection...\n");
1925
1926         next = active_brushes.next;
1927         prev = active_brushes.prev;
1928         if (selected_brushes.next != &selected_brushes) {
1929                 active_brushes.next = selected_brushes.next;
1930                 active_brushes.prev = selected_brushes.prev;
1931                 active_brushes.next->prev = &active_brushes;
1932                 active_brushes.prev->next = &active_brushes;
1933         }
1934         else {
1935                 active_brushes.next = &active_brushes;
1936                 active_brushes.prev = &active_brushes;
1937         }
1938
1939         if (next != &active_brushes) {
1940                 selected_brushes.next = next;
1941                 selected_brushes.prev = prev;
1942                 selected_brushes.next->prev = &selected_brushes;
1943                 selected_brushes.prev->next = &selected_brushes;
1944         }
1945         else {
1946                 selected_brushes.next = &selected_brushes;
1947                 selected_brushes.prev = &selected_brushes;
1948         }
1949
1950         Sys_UpdateWindows(W_ALL);
1951
1952         Sys_Status("done.\n");
1953 }
1954
1955 /*
1956  =======================================================================================================================
1957     Select_Name
1958  =======================================================================================================================
1959  */
1960 void Select_Name(const char *pName) {
1961         if (g_qeglobals.m_bBrushPrimitMode) {
1962                 for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
1963                         Brush_SetEpair(b, "Name", pName);
1964                 }
1965         }
1966 }
1967
1968 /*
1969  =======================================================================================================================
1970  =======================================================================================================================
1971  */
1972 void Select_CenterOrigin() {
1973         idVec3  mid;
1974
1975         Select_GetTrueMid(mid);
1976         mid.Snap();
1977
1978         brush_t         *b = selected_brushes.next;
1979         entity_t        *e = b->owner;
1980         if (e != NULL) {
1981                 if (e != world_entity) {
1982                         char    text[1024];
1983                         sprintf(text, "%i %i %i", (int)mid[0], (int)mid[1], (int)mid[2]);
1984                         SetKeyValue(e, "origin", text);
1985                         VectorCopy(mid, e->origin);
1986                 }
1987         }
1988
1989         Sys_UpdateWindows(W_ALL);
1990 }
1991
1992 /*
1993  =======================================================================================================================
1994  =======================================================================================================================
1995  */
1996 int Select_NumSelectedFaces() {
1997         return g_ptrSelectedFaces.GetSize();
1998 }
1999
2000 /*
2001  =======================================================================================================================
2002  =======================================================================================================================
2003  */
2004 face_t *Select_GetSelectedFace(int index) {
2005         assert(index >= 0 && index < Select_NumSelectedFaces());
2006         return reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(index));
2007 }
2008
2009 /*
2010  =======================================================================================================================
2011  =======================================================================================================================
2012  */
2013 brush_t *Select_GetSelectedFaceBrush(int index) {
2014         assert(index >= 0 && index < Select_NumSelectedFaces());
2015         return reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(index));
2016 }
2017
2018 /*
2019  =======================================================================================================================
2020  =======================================================================================================================
2021  */
2022 void Select_SetDefaultTexture(const idMaterial *mat, bool fitScale, bool setTexture) {
2023         texdef_t                                tex;
2024         brushprimit_texdef_t    brushprimit_tex;
2025         memset(&tex, 0, sizeof(tex));
2026         memset(&brushprimit_tex, 0, sizeof(brushprimit_tex));
2027         if (g_qeglobals.m_bBrushPrimitMode) {
2028                 // brushprimit fitted to a 2x2 texture
2029                 brushprimit_tex.coords[0][0] = 1.0f;
2030                 brushprimit_tex.coords[1][1] = 1.0f;
2031         }
2032         else {
2033                 tex.scale[0] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1;
2034                 tex.scale[1] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1;
2035         }
2036
2037         tex.SetName(mat->GetName());
2038         Texture_SetTexture(&tex, &brushprimit_tex, fitScale, setTexture);
2039
2040         CString strTex;
2041         strTex.Format
2042                 (
2043                         "%s (%s) W: %i H: %i",
2044                         mat->GetName(),
2045                         mat->GetDescription(),
2046                         mat->GetEditorImage()->uploadWidth,
2047                         mat->GetEditorImage()->uploadHeight
2048                 );
2049         g_pParentWnd->SetStatusText(3, strTex);
2050 }
2051
2052
2053 void Select_UpdateTextureName(const char *name) {
2054         brush_t *b;
2055         int             nCount = g_ptrSelectedFaces.GetSize();
2056         if (nCount > 0) {
2057                 Undo_Start("set face texture name");
2058                 ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize());
2059                 for (int i = 0; i < nCount; i++) {
2060                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
2061                         brush_t *selBrush = reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(i));
2062                         Undo_AddBrush(selBrush);
2063                         selFace->texdef.SetName(name);
2064                         Brush_Build(selBrush);
2065                         Undo_EndBrush(selBrush);
2066                 }
2067
2068                 Undo_End();
2069         }
2070         else if (selected_brushes.next != &selected_brushes) {
2071                 Undo_Start("set brush textures");
2072                 for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
2073                         if (!b->owner->eclass->fixedsize) {
2074                                 Undo_AddBrush(b);
2075                                 Brush_SetTextureName(b, name);
2076                                 Undo_EndBrush(b);
2077                         } else if (b->owner->eclass->nShowFlags & ECLASS_LIGHT) {
2078                                 if ( idStr::Cmpn(name, "lights/", strlen("lights/")) == 0 ) {
2079                                         SetKeyValue(b->owner, "texture", name);
2080                                         g_Inspectors->UpdateEntitySel(b->owner->eclass);
2081                                         UpdateLightInspector();
2082                                         Brush_Build(b);
2083                                 }
2084                         }
2085                 }
2086
2087                 Undo_End();
2088         }
2089
2090         Sys_UpdateWindows(W_ALL);
2091 }
2092
2093
2094 /*
2095  =======================================================================================================================
2096  =======================================================================================================================
2097  */
2098 void Select_FlipTexture(bool y) {
2099
2100         int faceCount = g_ptrSelectedFaces.GetSize();
2101         
2102         Undo_Start("Select_FlipTexture");
2103         for (brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next) {
2104                 if (b->pPatch) {
2105                         Patch_FlipTexture(b->pPatch, y);
2106                 } else {
2107                         Brush_FlipTexture_BrushPrimit(b, y);
2108                 }
2109         }
2110
2111         if (faceCount > 0) {
2112                 for (int i = 0; i < faceCount; i++) {
2113                         face_t  *selFace = reinterpret_cast < face_t * > (g_ptrSelectedFaces.GetAt(i));
2114                         brush_t *selBrush = reinterpret_cast < brush_t * > (g_ptrSelectedFaceBrushes.GetAt(i));
2115                         Face_FlipTexture_BrushPrimit(selFace, y);
2116                 }
2117         }
2118
2119         Undo_End();
2120         Sys_UpdateWindows(W_CAMERA);
2121 }
2122
2123
2124
2125
2126 /*
2127  =======================================================================================================================
2128     Select_SetKeyVal 
2129         sets values on non-world entities
2130  =======================================================================================================================
2131  */
2132 void Select_SetKeyVal(const char *key, const char *val) {
2133         for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
2134                 if (b->owner != world_entity) {
2135                         SetKeyValue(b->owner, key, val, false);
2136                 }
2137         }
2138 }
2139
2140 /*
2141  =======================================================================================================================
2142         Select_CopyPatchTextureCoords( patchMesh_t *p )
2143  =======================================================================================================================
2144  */
2145 void Select_CopyPatchTextureCoords( patchMesh_t *p ) {
2146         for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
2147                 if (b->pPatch) {
2148                         if ( b->pPatch->width <= p->width && b->pPatch->height <= p->height ) {
2149                                 for ( int i = 0; i < b->pPatch->width; i ++ ) {
2150                                         for ( int j = 0; j < b->pPatch->height; j++ ) {
2151                                                 b->pPatch->ctrl(i, j).st = p->ctrl(i, j).st;
2152                                         }
2153                                 }
2154                         }
2155                 }
2156         }
2157 }
2158
2159
2160 /*
2161  =======================================================================================================================
2162         Select_SetProjectFaceOntoPatch     
2163  =======================================================================================================================
2164  */
2165 void Select_ProjectFaceOntoPatch( face_t *face ) {
2166         for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
2167                 if (b->pPatch) {
2168                         EmitBrushPrimitTextureCoordinates(face, NULL, b->pPatch);
2169                         Patch_MakeDirty(b->pPatch);
2170                 }
2171         }
2172 }
2173
2174 /*
2175  =======================================================================================================================
2176     Select_SetPatchFit 
2177  =======================================================================================================================
2178  */
2179 extern float Patch_Width(patchMesh_t *p);
2180 extern float Patch_Height(patchMesh_t *p);
2181 void Select_SetPatchFit(float dim1, float dim2, float srcWidth, float srcHeight, float rot) {
2182         for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
2183                 if (b->pPatch) {
2184                         float w = Patch_Width(b->pPatch);
2185                         float h = Patch_Height(b->pPatch);
2186                         Patch_RotateTexture(b->pPatch, -90 + rot);
2187                         Patch_FitTexture(b->pPatch, dim1 * (w / srcWidth), dim2 * (h / srcHeight));
2188                         Patch_FlipTexture(b->pPatch, true);
2189                 }
2190         }
2191 }
2192
2193 void Select_SetPatchST(float s1, float t1, float s2, float t2) {
2194 }
2195
2196
2197 void Select_AllTargets() {
2198         for (brush_t * b = selected_brushes.next; b && b != &selected_brushes; b = b->next) {
2199                 if (b->owner != world_entity) {
2200                         const idKeyValue *kv = b->owner->epairs.MatchPrefix("target", NULL);
2201                         while (kv) {
2202                                 entity_t *ent = FindEntity("name", kv->GetValue());
2203                                 if (ent) {
2204                                         Select_Brush(ent->brushes.onext, true, false);
2205                                 }
2206                                 kv = b->owner->epairs.MatchPrefix("target", kv);
2207                         }
2208                 }
2209         }
2210 }