]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/XYWnd.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / tools / radiant / XYWnd.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 "Radiant.h"
34 #include "XYWnd.h"
35 #include "DialogInfo.h"
36 #include "splines.h"
37 #include "../../renderer/tr_local.h"
38 #include "../../renderer/model_local.h" // for idRenderModelLiquid
39
40 #ifdef _DEBUG
41         #define new DEBUG_NEW
42         #undef THIS_FILE
43 static char             THIS_FILE[] = __FILE__;
44 #endif
45
46 const char              *g_pDimStrings[] = { "x:%.f", "y:%.f", "z:%.f" };
47 const char              *g_pOrgStrings[] = { "(x:%.f  y:%.f)", "(x:%.f  z:%.f)", "(y:%.f  z:%.f)" };
48 CString                 g_strDim;
49 CString                 g_strStatus;
50
51 bool                    g_bCrossHairs = false;
52 bool                    g_bScaleMode;
53 int                             g_nScaleHow;
54 bool                    g_bRotateMode;
55 bool                    g_bClipMode;
56 bool                    g_bRogueClipMode;
57 bool                    g_bSwitch;
58 CClipPoint              g_Clip1;
59 CClipPoint              g_Clip2;
60 CClipPoint              g_Clip3;
61 CClipPoint              *g_pMovingClip;
62 brush_t                 g_brFrontSplits;
63 brush_t                 g_brBackSplits;
64
65 brush_t                 g_brClipboard;
66 brush_t                 g_brUndo;
67 entity_t                g_enClipboard;
68
69 idVec3                  g_vRotateOrigin;
70 idVec3                  g_vRotation;
71
72 bool                    g_bPathMode;
73 CClipPoint              g_PathPoints[256];
74 CClipPoint              *g_pMovingPath;
75 int                             g_nPathCount;
76 int                             g_nPathLimit;
77
78 bool                    g_bSmartGo;
79
80 bool                    g_bPointMode;
81 CClipPoint              g_PointPoints[512];
82 CClipPoint              *g_pMovingPoint;
83 int                             g_nPointCount;
84 int                             g_nPointLimit;
85
86 const int               XY_LEFT = 0x01;
87 const int               XY_RIGHT = 0x02;
88 const int               XY_UP = 0x04;
89 const int               XY_DOWN = 0x08;
90
91 PFNPathCallback *g_pPathFunc = NULL;
92 void    Select_Ungroup();
93
94 /*
95  =======================================================================================================================
96  =======================================================================================================================
97  */
98 void AcquirePath(int nCount, PFNPathCallback *pFunc) {
99         g_nPathCount = 0;
100         g_nPathLimit = nCount;
101         g_pPathFunc = pFunc;
102         g_bPathMode = true;
103 }
104
105 CPtrArray       g_ptrMenus;
106
107 CMemFile        g_Clipboard(4096);
108 CMemFile        g_PatchClipboard(4096);
109
110 extern int      pressx;
111 extern int      pressy;
112
113 /*
114  =======================================================================================================================
115  =======================================================================================================================
116  */
117 float fDiff(float f1, float f2) {
118         if (f1 > f2) {
119                 return f1 - f2;
120         }
121         else {
122                 return f2 - f1;
123         }
124 }
125
126 #define MAX_DRAG_POINTS 128
127
128 CPtrArray                       dragPoints;
129 static CDragPoint       *activeDrag = NULL;
130 static bool                     activeDragging = false;
131
132 /*
133  =======================================================================================================================
134  =======================================================================================================================
135  */
136 bool CDragPoint::PointWithin(idVec3 p, int nView) {
137         if (nView == -1) {
138                 if (fDiff(p[0], vec[0]) <= 3 && fDiff(p[1], vec[1]) <= 3 && fDiff(p[2], vec[2]) <= 3) {
139                         return true;
140                 }
141         }
142         else {
143                 int nDim1 = (nView == YZ) ? 1 : 0;
144                 int nDim2 = (nView == XY) ? 1 : 2;
145                 if (fDiff(p[nDim1], vec[nDim1]) <= 3 && fDiff(p[nDim2], vec[nDim2]) <= 3) {
146                         return true;
147                 }
148         }
149
150         return false;
151 }
152
153 /*
154  =======================================================================================================================
155  =======================================================================================================================
156  */
157 CDragPoint *PointRay(const idVec3 &org, const idVec3 &dir, float *dist) {
158         int                     i, besti;
159         float           d, bestd;
160         idVec3          temp;
161         CDragPoint      *drag = NULL;
162         CDragPoint      *priority = NULL;
163
164         // find the point closest to the ray
165         float scale = g_pParentWnd->ActiveXY()->Scale();
166         besti = -1;
167         bestd = 12 / scale / 2;
168
169         int count = dragPoints.GetSize();
170         for (i = 0; i < count; i++) {
171                 drag = reinterpret_cast < CDragPoint * > (dragPoints[i]);
172                 temp = drag->vec - org;
173                 d = temp * dir;
174                 temp = org + d * dir;
175                 temp = drag->vec - temp;
176                 d = temp.Length();
177                 if ( d < bestd ) {
178                         bestd = d;
179                         besti = i;
180                         if (priority == NULL) {
181                                 priority = reinterpret_cast < CDragPoint * > (dragPoints[besti]);
182                                 if (!priority->priority) {
183                                         priority = NULL;
184                                 }
185                         }
186                 }
187         }
188
189         if (besti == -1) {
190                 return NULL;
191         }
192
193         drag = reinterpret_cast < CDragPoint * > (dragPoints[besti]);
194         if (priority && !drag->priority) {
195                 drag = priority;
196         }
197
198         return drag;
199 }
200
201 /*
202  =======================================================================================================================
203  =======================================================================================================================
204  */
205 void ClearSelectablePoints(brush_t *b) {
206         if (b == NULL) {
207                 dragPoints.RemoveAll();
208         }
209         else {
210                 CPtrArray       ptr;
211                 ptr.Copy(dragPoints);
212                 dragPoints.RemoveAll();
213
214                 int count = ptr.GetSize();
215                 for (int i = 0; i < count; i++) {
216                         if (b == reinterpret_cast < CDragPoint * > ( ptr.GetAt(i))->pBrush ) {
217                                 continue;
218                         }
219                         else {
220                                 dragPoints.Add(ptr.GetAt(i));
221                         }
222                 }
223         }
224 }
225
226 /*
227  =======================================================================================================================
228  =======================================================================================================================
229  */
230 void AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority) {
231         dragPoints.Add(new CDragPoint(b, v, type, priority));
232 }
233
234 /*
235  =======================================================================================================================
236  =======================================================================================================================
237  */
238 void UpdateSelectablePoint(brush_t *b, idVec3 v, int type) {
239         int count = dragPoints.GetSize();
240         for (int i = 0; i < count; i++) {
241                 CDragPoint      *drag = reinterpret_cast < CDragPoint * > (dragPoints.GetAt(i));
242                 if (b == drag->pBrush && type == drag->nType) {
243                         VectorCopy(v, drag->vec);
244                         return;
245                 }
246         }
247 }
248
249 /*
250  =======================================================================================================================
251  =======================================================================================================================
252  */
253 void VectorToAngles(idVec3 vec, idVec3 angles) {
254         float   forward;
255         float   yaw, pitch;
256
257         if ((vec[0] == 0) && (vec[1] == 0)) {
258                 yaw = 0;
259                 if (vec[2] > 0) {
260                         pitch = 90;
261                 }
262                 else {
263                         pitch = 270;
264                 }
265         }
266         else {
267                 yaw = RAD2DEG( atan2(vec[1], vec[0]) );
268                 if (yaw < 0) {
269                         yaw += 360;
270                 }
271
272                 forward = (float)idMath::Sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
273                 pitch = RAD2DEG( atan2(vec[2], forward) );
274                 if (pitch < 0) {
275                         pitch += 360;
276                 }
277         }
278
279         angles[0] = pitch;
280         angles[1] = yaw;
281         angles[2] = 0;
282 }
283
284 /*
285  =======================================================================================================================
286     RotateLight target is relative to the light origin up and right are relative to the target up and right are
287     perpendicular and are on a plane through the target with the target vector as normal delta is the movement of the
288     target relative to the light
289  =======================================================================================================================
290 */
291 void VectorSnapGrid(idVec3 &v) {
292         v.x = floor(v.x / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
293         v.y = floor(v.y / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
294         v.z = floor(v.z / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
295 }
296
297 /*
298  =======================================================================================================================
299  =======================================================================================================================
300 */
301 static void RotateLight(idVec3 &target, idVec3 &up, idVec3 &right, const idVec3 &delta) {
302         idVec3  newtarget, cross, dst;
303         idVec3  normal;
304         double  angle, dist, d, len;
305         idMat3  rot;
306
307         // calculate new target
308         newtarget = target + delta;
309
310         // get the up and right vector relative to the light origin
311         up += target;
312         right += target;
313
314         len = target.Length() * newtarget.Length();
315
316         if (len > 0.1) {
317                 // calculate the rotation angle between the vectors
318                 double  dp = target * newtarget;
319                 double  dv = dp / len;
320
321                 angle = RAD2DEG( idMath::ACos( dv ) );
322
323                 // get a vector orthogonal to the rotation plane
324                 cross = target.Cross( newtarget );
325                 cross.Normalize();
326
327                 if (cross[0] || cross[1] || cross[2]) {
328                         // build the rotation matrix
329                         rot = idRotation( vec3_origin, cross, angle ).ToMat3();
330
331                         rot.ProjectVector(target, dst);
332                         target = dst;
333                         rot.ProjectVector( up, dst );
334                         up = dst;
335                         rot.ProjectVector( right, dst);
336                         right = dst;
337                 }
338         }
339
340         //
341         // project the up and right vectors onto a plane that goes through the target and
342         // has normal vector target.Normalize()
343         //
344         normal = target;
345         normal.Normalize();
346         dist = normal * target;
347
348         d = (normal * up) - dist;
349         up -= d * normal;
350
351         d = (normal * right) - dist;
352         right -= d * normal;
353
354         //
355         // FIXME: maybe calculate the right vector with a cross product between the target
356         // and up vector, just to make sure the up and right vectors are perpendicular
357         // get the up and right vectors relative to the target
358         //
359         up -= target;
360         right -= target;
361
362         // move the target in the (target - light_origin) direction
363         target = newtarget;
364         VectorSnapGrid(target);
365         VectorSnapGrid(up);
366         VectorSnapGrid(right);
367 }
368
369 /*
370  =======================================================================================================================
371  =======================================================================================================================
372 */
373 extern idVec3 Brush_TransformedPoint(brush_t *b, const idVec3 &in);
374 extern idMat3 Brush_RotationMatrix(brush_t *b);
375 bool UpdateActiveDragPoint(const idVec3 &move) {
376         if (activeDrag) {
377                 idMat3 mat = Brush_RotationMatrix(activeDrag->pBrush);
378                 idMat3 invmat = mat.Transpose();
379                 idVec3  target, up, right, start, end;
380                 CString str;
381                 if (activeDrag->nType == LIGHT_TARGET) {
382                         GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
383                         GetVectorForKey(activeDrag->pBrush->owner, "light_up", up);
384                         GetVectorForKey(activeDrag->pBrush->owner, "light_right", right);
385                         target *= mat;
386                         up *= mat;
387                         right *= mat;
388                         RotateLight(target, up, right, move);
389                         target *= invmat;
390                         up *= invmat;
391                         right *= invmat;
392                         SetKeyVec3(activeDrag->pBrush->owner, "light_target", target);
393                         SetKeyVec3(activeDrag->pBrush->owner, "light_up", up);
394                         SetKeyVec3(activeDrag->pBrush->owner, "light_right", right);
395                         target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
396                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush, target), LIGHT_TARGET);
397                         up += target;
398                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,up), LIGHT_UP);
399                         right += target;
400                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,right), LIGHT_RIGHT);
401                 }
402                 else if (activeDrag->nType == LIGHT_UP) {
403                         GetVectorForKey(activeDrag->pBrush->owner, "light_up", up);
404                         up *= mat;
405                         up += move;
406                         up *= invmat;
407                         SetKeyVec3(activeDrag->pBrush->owner, "light_up", up);
408                         GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
409                         target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
410                         up += target;
411                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,up), LIGHT_UP);
412                 }
413                 else if (activeDrag->nType == LIGHT_RIGHT) {
414                         GetVectorForKey(activeDrag->pBrush->owner, "light_right", right);
415                         right *= mat;
416                         right += move;
417                         right *= invmat;
418                         SetKeyVec3(activeDrag->pBrush->owner, "light_right", right);
419                         GetVectorForKey(activeDrag->pBrush->owner, "light_target", target);
420                         target += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
421                         right += target;
422                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,right), LIGHT_RIGHT);
423                 }
424                 else if (activeDrag->nType == LIGHT_START) {
425                         GetVectorForKey(activeDrag->pBrush->owner, "light_start", start);
426                         start *= mat;
427                         start += move;
428                         start *= invmat;
429                         SetKeyVec3(activeDrag->pBrush->owner, "light_start", start);
430                         start += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
431                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,start), LIGHT_START);
432                 }
433                 else if (activeDrag->nType == LIGHT_END) {
434                         GetVectorForKey(activeDrag->pBrush->owner, "light_end", end);
435                         end *= mat;
436                         end += move;
437                         end *= invmat;
438                         SetKeyVec3(activeDrag->pBrush->owner, "light_end", end);
439                         end += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
440                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush,end), LIGHT_END);
441                 }
442                 else if (activeDrag->nType == LIGHT_CENTER) {
443                         GetVectorForKey(activeDrag->pBrush->owner, "light_center", end);
444                         end *= mat;
445                         end += move;
446                         end *= invmat;
447                         SetKeyVec3(activeDrag->pBrush->owner, "light_center", end);
448                         end += (activeDrag->pBrush->trackLightOrigin) ? activeDrag->pBrush->owner->lightOrigin : activeDrag->pBrush->owner->origin;
449                         UpdateSelectablePoint(activeDrag->pBrush, Brush_TransformedPoint(activeDrag->pBrush, end), LIGHT_CENTER);
450                 }
451
452                 // FIXME: just build the frustrum values
453                 Brush_Build(activeDrag->pBrush);
454                 return true;
455         }
456
457         return false;
458 }
459
460 /*
461  =======================================================================================================================
462  =======================================================================================================================
463 */
464 bool SetDragPointCursor(idVec3 p, int nView) {
465         activeDrag = NULL;
466
467         int numDragPoints = dragPoints.GetSize();
468         for (int i = 0; i < numDragPoints; i++) {
469                 if (reinterpret_cast < CDragPoint * > (dragPoints[i])->PointWithin(p, nView)) {
470                         activeDrag = reinterpret_cast < CDragPoint * > (dragPoints[i]);
471                         return true;
472                 }
473         }
474
475         return false;
476 }
477
478 /*
479  =======================================================================================================================
480  =======================================================================================================================
481  */
482 void SetActiveDrag(CDragPoint *p) {
483         activeDrag = p;
484 }
485
486 /*
487  =======================================================================================================================
488  =======================================================================================================================
489  */
490 void ClearActiveDrag() {
491         activeDrag = NULL;
492 }
493
494 // CXYWnd
495 IMPLEMENT_DYNCREATE(CXYWnd, CWnd);
496
497 /*
498  =======================================================================================================================
499  =======================================================================================================================
500  */
501 CXYWnd::CXYWnd() {
502         g_brClipboard.next = &g_brClipboard;
503         g_brUndo.next = &g_brUndo;
504         g_nScaleHow = 0;
505         g_bRotateMode = false;
506         g_bClipMode = false;
507         g_bRogueClipMode = false;
508         g_bSwitch = true;
509         g_pMovingClip = NULL;
510         g_pMovingPath = NULL;
511         g_brFrontSplits.next = &g_brFrontSplits;
512         g_brBackSplits.next = &g_brBackSplits;
513         m_bActive = false;
514
515         m_bRButtonDown = false;
516         m_nUpdateBits = W_XY;
517         g_bPathMode = false;
518         g_nPathCount = 0;
519         g_nPathLimit = 0;
520         m_nTimerID = -1;
521         m_nButtonstate = 0;
522         XY_Init();
523 }
524
525 /*
526  =======================================================================================================================
527  =======================================================================================================================
528  */
529 CXYWnd::~CXYWnd() {
530         int nSize = g_ptrMenus.GetSize();
531         while (nSize > 0) {
532                 CMenu   *pMenu = reinterpret_cast < CMenu * > (g_ptrMenus.GetAt(nSize - 1));
533                 ASSERT(pMenu);
534                 pMenu->DestroyMenu();
535                 delete pMenu;
536                 nSize--;
537         }
538
539         g_ptrMenus.RemoveAll();
540         m_mnuDrop.DestroyMenu();
541 }
542
543 BEGIN_MESSAGE_MAP(CXYWnd, CWnd)
544 //{{AFX_MSG_MAP(CXYWnd)
545         ON_WM_CREATE()
546         ON_WM_LBUTTONDOWN()
547         ON_WM_MBUTTONDOWN()
548         ON_WM_RBUTTONDOWN()
549         ON_WM_LBUTTONUP()
550         ON_WM_MBUTTONUP()
551         ON_WM_RBUTTONUP()
552         ON_WM_MOUSEMOVE()
553         ON_WM_PAINT()
554         ON_WM_KEYDOWN()
555         ON_WM_SIZE()
556         ON_WM_DESTROY()
557         ON_COMMAND(ID_SELECT_MOUSEROTATE, OnSelectMouserotate)
558         ON_WM_TIMER()
559         ON_WM_KEYUP()
560         ON_WM_NCCALCSIZE()
561         ON_WM_KILLFOCUS()
562         ON_WM_SETFOCUS()
563         ON_WM_CLOSE()
564         ON_WM_ERASEBKGND()
565         ON_WM_MOUSEWHEEL()
566         ON_COMMAND(ID_DROP_NEWMODEL, OnDropNewmodel)
567         //}}AFX_MSG_MAP
568         ON_COMMAND_RANGE(ID_ENTITY_START, ID_ENTITY_END, OnEntityCreate)
569 END_MESSAGE_MAP()
570 // CXYWnd message handlers
571 LONG WINAPI XYWndProc(HWND, UINT, WPARAM, LPARAM);
572
573 /*
574  =======================================================================================================================
575  =======================================================================================================================
576  */
577 BOOL CXYWnd::PreCreateWindow(CREATESTRUCT &cs) {
578         WNDCLASS        wc;
579         HINSTANCE       hInstance = AfxGetInstanceHandle();
580         if (::GetClassInfo(hInstance, XY_WINDOW_CLASS, &wc) == FALSE) {
581                 // Register a new class
582                 memset(&wc, 0, sizeof(wc));
583                 wc.style = CS_NOCLOSE;
584                 wc.lpszClassName = XY_WINDOW_CLASS;
585                 wc.hCursor = NULL;      // LoadCursor (NULL,IDC_ARROW);
586                 wc.lpfnWndProc = ::DefWindowProc;
587                 if (AfxRegisterClass(&wc) == FALSE) {
588                         Error("CCamWnd RegisterClass: failed");
589                 }
590         }
591
592         cs.lpszClass = XY_WINDOW_CLASS;
593         cs.lpszName = "VIEW";
594         if (cs.style != QE3_CHILDSTYLE) {
595                 cs.style = QE3_SPLITTER_STYLE;
596         }
597
598         return CWnd::PreCreateWindow(cs);
599 }
600
601 HDC                             s_hdcXY;
602 HGLRC                   s_hglrcXY;
603
604 static unsigned s_stipple[32] = {
605         0xaaaaaaaa,
606         0x55555555,
607         0xaaaaaaaa,
608         0x55555555,
609         0xaaaaaaaa,
610         0x55555555,
611         0xaaaaaaaa,
612         0x55555555,
613         0xaaaaaaaa,
614         0x55555555,
615         0xaaaaaaaa,
616         0x55555555,
617         0xaaaaaaaa,
618         0x55555555,
619         0xaaaaaaaa,
620         0x55555555,
621         0xaaaaaaaa,
622         0x55555555,
623         0xaaaaaaaa,
624         0x55555555,
625         0xaaaaaaaa,
626         0x55555555,
627         0xaaaaaaaa,
628         0x55555555,
629         0xaaaaaaaa,
630         0x55555555,
631         0xaaaaaaaa,
632         0x55555555,
633         0xaaaaaaaa,
634         0x55555555,
635         0xaaaaaaaa,
636         0x55555555,
637 };
638
639 /*
640  =======================================================================================================================
641     WXY_WndProc
642  =======================================================================================================================
643  */
644 LONG WINAPI XYWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
645         switch (uMsg)
646         {
647                 case WM_DESTROY:
648                         return 0;
649
650                 case WM_NCCALCSIZE: // don't let windows copy pixels
651                         DefWindowProc(hWnd, uMsg, wParam, lParam);
652                         return WVR_REDRAW;
653
654                 case WM_KILLFOCUS:
655                 case WM_SETFOCUS:
656                         SendMessage(hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0);
657                         return 0;
658
659                 case WM_CLOSE:
660                         DestroyWindow(hWnd);
661                         return 0;
662         }
663
664         return DefWindowProc(hWnd, uMsg, wParam, lParam);
665 }
666
667 /*
668  =======================================================================================================================
669  =======================================================================================================================
670  */
671 static void WXY_InitPixelFormat(PIXELFORMATDESCRIPTOR *pPFD) {
672         memset(pPFD, 0, sizeof(*pPFD));
673
674         pPFD->nSize = sizeof(PIXELFORMATDESCRIPTOR);
675         pPFD->nVersion = 1;
676         pPFD->dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
677         pPFD->iPixelType = PFD_TYPE_RGBA;
678         pPFD->cColorBits = 24;
679         pPFD->cDepthBits = 32;
680         pPFD->iLayerType = PFD_MAIN_PLANE;
681 }
682
683 /*
684  =======================================================================================================================
685  =======================================================================================================================
686  */
687 void WXY_Print(void) {
688         DOCINFO         di;
689
690         PRINTDLG        pd;
691
692         /* initialize the PRINTDLG struct and execute it */
693         memset(&pd, 0, sizeof(pd));
694         pd.lStructSize = sizeof(pd);
695         pd.hwndOwner = g_pParentWnd->GetXYWnd()->GetSafeHwnd();
696         pd.Flags = PD_RETURNDC;
697         pd.hInstance = 0;
698         if (!PrintDlg(&pd) || !pd.hDC) {
699                 g_pParentWnd->MessageBox("Could not PrintDlg()", "QE4 Print Error", MB_OK | MB_ICONERROR);
700                 return;
701         }
702
703         /* StartDoc */
704         memset(&di, 0, sizeof(di));
705         di.cbSize = sizeof(di);
706         di.lpszDocName = "QE4";
707         if (StartDoc(pd.hDC, &di) <= 0) {
708                 g_pParentWnd->MessageBox("Could not StartDoc()", "QE4 Print Error", MB_OK | MB_ICONERROR);
709                 return;
710         }
711
712         /* StartPage */
713         if (StartPage(pd.hDC) <= 0) {
714                 g_pParentWnd->MessageBox("Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR);
715                 return;
716         } { /* read pixels from the XY window */
717                 int             bmwidth = 320, bmheight = 320;
718                 int             pwidth, pheight;
719
720                 RECT    r;
721
722                 GetWindowRect(g_pParentWnd->GetXYWnd()->GetSafeHwnd(), &r);
723
724                 bmwidth = r.right - r.left;
725                 bmheight = r.bottom - r.top;
726
727                 pwidth = GetDeviceCaps(pd.hDC, PHYSICALWIDTH) - GetDeviceCaps(pd.hDC, PHYSICALOFFSETX);
728                 pheight = GetDeviceCaps(pd.hDC, PHYSICALHEIGHT) - GetDeviceCaps(pd.hDC, PHYSICALOFFSETY);
729
730                 StretchBlt(pd.hDC, 0, 0, pwidth, pheight, s_hdcXY, 0, 0, bmwidth, bmheight, SRCCOPY);
731         }
732
733         /* EndPage and EndDoc */
734         if (EndPage(pd.hDC) <= 0) {
735                 g_pParentWnd->MessageBox("QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR);
736                 return;
737         }
738
739         if (EndDoc(pd.hDC) <= 0) {
740                 g_pParentWnd->MessageBox("QE4 Print Error", "Could not EndDoc()", MB_OK | MB_ICONERROR);
741                 return;
742         }
743 }
744
745 /*
746  =======================================================================================================================
747  =======================================================================================================================
748  */
749 int CXYWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
750         if (CWnd::OnCreate(lpCreateStruct) == -1) {
751                 return -1;
752         }
753
754         s_hdcXY = ::GetDC(GetSafeHwnd());
755         QEW_SetupPixelFormat(s_hdcXY, false);
756
757         qglPolygonStipple((unsigned char *)s_stipple);
758         qglLineStipple(3, 0xaaaa);
759         return 0;
760 }
761
762 /*
763  =======================================================================================================================
764  =======================================================================================================================
765  */
766 float ptSum(idVec3 pt) {
767         return pt[0] + pt[1] + pt[2];
768 }
769
770 /*
771  =======================================================================================================================
772  =======================================================================================================================
773  */
774 void CXYWnd::DropClipPoint(UINT nFlags, CPoint point) {
775         CRect   rctZ;
776         GetClientRect(rctZ);
777         if (g_pMovingClip) {
778                 SetCapture();
779                 SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *g_pMovingClip);
780         }
781         else {
782                 idVec3  *pPt = NULL;
783                 if (g_Clip1.Set() == false) {
784                         pPt = g_Clip1;
785                         g_Clip1.Set(true);
786                         g_Clip1.m_ptScreen = point;
787                 }
788                 else if (g_Clip2.Set() == false) {
789                         pPt = g_Clip2;
790                         g_Clip2.Set(true);
791                         g_Clip2.m_ptScreen = point;
792                 }
793                 else if (g_Clip3.Set() == false) {
794                         pPt = g_Clip3;
795                         g_Clip3.Set(true);
796                         g_Clip3.m_ptScreen = point;
797                 }
798                 else {
799                         RetainClipMode(true);
800                         pPt = g_Clip1;
801                         g_Clip1.Set(true);
802                         g_Clip1.m_ptScreen = point;
803                 }
804
805                 SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *pPt);
806
807                 // Put the off-viewaxis coordinate at the top or bottom of selected brushes
808                 if ( GetAsyncKeyState(VK_CONTROL) & 0x8000 ) {
809                         if ( selected_brushes.next != &selected_brushes ) {
810                                 idVec3  smins, smaxs;
811                                 Select_GetBounds( smins, smaxs );
812
813                                 if ( m_nViewType == XY ) {
814                                         if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
815                                                 pPt->z = smaxs.z;
816                                         } else {
817                                                 pPt->z = smins.z;
818                                         }
819                                 } else if ( m_nViewType == YZ ) {
820                                         if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
821                                                 pPt->x = smaxs.x;
822                                         } else {
823                                                 pPt->x = smins.x;
824                                         }
825                                 } else {
826                                         if ( GetAsyncKeyState(VK_SHIFT) & 0x8000 ) {
827                                                 pPt->y = smaxs.y;
828                                         } else {
829                                                 pPt->y = smins.y;
830                                         }
831                                 }
832                         }
833                 }
834         }
835
836         Sys_UpdateWindows(XY | W_CAMERA_IFON);
837 }
838
839 /*
840  =======================================================================================================================
841  =======================================================================================================================
842  */
843 void CXYWnd::DropPathPoint(UINT nFlags, CPoint point) {
844         CRect   rctZ;
845         GetClientRect(rctZ);
846         if (g_pMovingPath) {
847                 SetCapture();
848                 SnapToPoint(point.x, rctZ.Height() - 1 - point.y, *g_pMovingPath);
849         }
850         else {
851                 g_PathPoints[g_nPathCount].Set(true);
852                 g_PathPoints[g_nPathCount].m_ptScreen = point;
853                 SnapToPoint(point.x, rctZ.Height() - 1 - point.y, g_PathPoints[g_nPathCount]);
854                 g_nPathCount++;
855                 if (g_nPathCount == g_nPathLimit) {
856                         if (g_pPathFunc) {
857                                 g_pPathFunc(true, g_nPathCount);
858                         }
859
860                         g_nPathCount = 0;
861                         g_bPathMode = false;
862                         g_pPathFunc = NULL;
863                 }
864         }
865
866         Sys_UpdateWindows(XY | W_CAMERA_IFON);
867 }
868
869 /*
870  =======================================================================================================================
871  =======================================================================================================================
872  */
873 void CXYWnd::AddPointPoint(UINT nFlags, idVec3 *pVec) {
874         g_PointPoints[g_nPointCount].Set(true);
875
876         // g_PointPoints[g_nPointCount].m_ptScreen = point;
877         g_PointPoints[g_nPointCount].m_ptClip = *pVec;
878         g_PointPoints[g_nPointCount].SetPointPtr(pVec);
879         g_nPointCount++;
880         Sys_UpdateWindows(XY | W_CAMERA_IFON);
881 }
882
883 /*
884  =======================================================================================================================
885  =======================================================================================================================
886  */
887 void CXYWnd::OnLButtonDown(UINT nFlags, CPoint point) {
888         g_pParentWnd->SetActiveXY(this);
889         UndoCopy();
890
891         if (g_pParentWnd->GetNurbMode()) {
892                 int i, num = g_pParentWnd->GetNurb()->GetNumValues();
893                 idList<idVec2> temp;
894                         for (i = 0; i < num; i++) {
895                         temp.Append(g_pParentWnd->GetNurb()->GetValue(i));
896                 }
897                 CRect   rctZ;
898                 GetClientRect(rctZ);
899                 idVec3 v3;
900                 SnapToPoint(point.x, rctZ.Height() - 1 - point.y, v3);
901                 temp.Append(idVec2(v3.x, v3.y));
902                 num++;
903                 g_pParentWnd->GetNurb()->Clear();
904                 for (i = 0; i < num; i++) {
905                         g_pParentWnd->GetNurb()->AddValue((1000 * i)/num, temp[i]);
906                 }
907         }
908         if (ClipMode() && !RogueClipMode()) {
909                 DropClipPoint(nFlags, point);
910         }
911         else if (PathMode()) {
912                 DropPathPoint(nFlags, point);
913         }
914         else {
915                 OriginalButtonDown(nFlags, point);
916         }
917 }
918
919 /*
920  =======================================================================================================================
921  =======================================================================================================================
922  */
923 void CXYWnd::OnMButtonDown(UINT nFlags, CPoint point) {
924         OriginalButtonDown(nFlags, point);
925 }
926
927 /*
928  =======================================================================================================================
929  =======================================================================================================================
930  */
931 float Betwixt(float f1, float f2) {
932         if (f1 > f2) {
933                 return f2 + ((f1 - f2) / 2);
934         }
935         else {
936                 return f1 + ((f2 - f1) / 2);
937         }
938 }
939
940 /*
941  =======================================================================================================================
942  =======================================================================================================================
943  */
944 void CXYWnd::ProduceSplits(brush_t **pFront, brush_t **pBack) {
945         *pFront = NULL;
946         *pBack = NULL;
947         if (ClipMode()) {
948                 if (g_Clip1.Set() && g_Clip2.Set()) {
949                         face_t  face;
950                         VectorCopy(g_Clip1.m_ptClip, face.planepts[0]);
951                         VectorCopy(g_Clip2.m_ptClip, face.planepts[1]);
952                         VectorCopy(g_Clip3.m_ptClip, face.planepts[2]);
953                         if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes)) {
954                                 if (g_Clip3.Set() == false) {
955                                         if (m_nViewType == XY) {
956                                                 face.planepts[0][2] = selected_brushes.next->mins[2];
957                                                 face.planepts[1][2] = selected_brushes.next->mins[2];
958                                                 face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
959                                                 face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
960                                                 face.planepts[2][2] = selected_brushes.next->maxs[2];
961                                         }
962                                         else if (m_nViewType == YZ) {
963                                                 face.planepts[0][0] = selected_brushes.next->mins[0];
964                                                 face.planepts[1][0] = selected_brushes.next->mins[0];
965                                                 face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
966                                                 face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
967                                                 face.planepts[2][0] = selected_brushes.next->maxs[0];
968                                         }
969                                         else {
970                                                 face.planepts[0][1] = selected_brushes.next->mins[1];
971                                                 face.planepts[1][1] = selected_brushes.next->mins[1];
972                                                 face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
973                                                 face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
974                                                 face.planepts[2][1] = selected_brushes.next->maxs[1];
975                                         }
976                                 }
977
978                                 Brush_SplitBrushByFace(selected_brushes.next, &face, pFront, pBack);
979                         }
980                 }
981         }
982 }
983
984 /*
985  =======================================================================================================================
986  =======================================================================================================================
987  */
988 void CleanList(brush_t *pList) {
989         brush_t *pBrush = pList->next;
990         while (pBrush != NULL && pBrush != pList) {
991                 brush_t *pNext = pBrush->next;
992                 Brush_Free(pBrush);
993                 pBrush = pNext;
994         }
995 }
996
997 /*
998  =======================================================================================================================
999  =======================================================================================================================
1000  */
1001 void CXYWnd::ProduceSplitLists() {
1002         if (AnyPatchesSelected()) {
1003                 Sys_Status("Deslecting patches for clip operation.\n");
1004
1005                 brush_t *next;
1006                 for (brush_t * pb = selected_brushes.next; pb != &selected_brushes; pb = next) {
1007                         next = pb->next;
1008                         if (pb->pPatch) {
1009                                 Brush_RemoveFromList(pb);
1010                                 Brush_AddToList(pb, &active_brushes);
1011                                 UpdatePatchInspector();
1012                         }
1013                 }
1014         }
1015
1016         CleanList(&g_brFrontSplits);
1017         CleanList(&g_brBackSplits);
1018         g_brFrontSplits.next = &g_brFrontSplits;
1019         g_brBackSplits.next = &g_brBackSplits;
1020
1021         brush_t *pBrush;
1022         for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) {
1023                 brush_t *pFront = NULL;
1024                 brush_t *pBack = NULL;
1025                 if (ClipMode()) {
1026                         if (g_Clip1.Set() && g_Clip2.Set()) {
1027                                 face_t  face;
1028                                 VectorCopy(g_Clip1.m_ptClip, face.planepts[0]);
1029                                 VectorCopy(g_Clip2.m_ptClip, face.planepts[1]);
1030                                 VectorCopy(g_Clip3.m_ptClip, face.planepts[2]);
1031                                 if (g_Clip3.Set() == false) {
1032                                         if (g_pParentWnd->ActiveXY()->GetViewType() == XY) {
1033                                                 face.planepts[0][2] = pBrush->mins[2];
1034                                                 face.planepts[1][2] = pBrush->mins[2];
1035                                                 face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
1036                                                 face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
1037                                                 face.planepts[2][2] = pBrush->maxs[2];
1038                                         }
1039                                         else if (g_pParentWnd->ActiveXY()->GetViewType() == YZ) {
1040                                                 face.planepts[0][0] = pBrush->mins[0];
1041                                                 face.planepts[1][0] = pBrush->mins[0];
1042                                                 face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
1043                                                 face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
1044                                                 face.planepts[2][0] = pBrush->maxs[0];
1045                                         }
1046                                         else {
1047                                                 face.planepts[0][1] = pBrush->mins[1];
1048                                                 face.planepts[1][1] = pBrush->mins[1];
1049                                                 face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
1050                                                 face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
1051                                                 face.planepts[2][1] = pBrush->maxs[1];
1052                                         }
1053                                 }
1054
1055                                 Brush_SplitBrushByFace(pBrush, &face, &pFront, &pBack);
1056                                 if (pBack) {
1057                                         Brush_AddToList(pBack, &g_brBackSplits);
1058                                 }
1059
1060                                 if (pFront) {
1061                                         Brush_AddToList(pFront, &g_brFrontSplits);
1062                                 }
1063                         }
1064                 }
1065         }
1066 }
1067
1068 /*
1069  =======================================================================================================================
1070  =======================================================================================================================
1071  */
1072 void Brush_CopyList(brush_t *pFrom, brush_t *pTo) {
1073         brush_t *pBrush = pFrom->next;
1074         while (pBrush != NULL && pBrush != pFrom) {
1075                 brush_t *pNext = pBrush->next;
1076                 Brush_RemoveFromList(pBrush);
1077                 Brush_AddToList(pBrush, pTo);
1078                 pBrush = pNext;
1079         }
1080 }
1081
1082 /*
1083  =======================================================================================================================
1084  =======================================================================================================================
1085  */
1086 void CXYWnd::OnRButtonDown(UINT nFlags, CPoint point) {
1087         g_pParentWnd->SetActiveXY(this);
1088         m_ptDown = point;
1089         m_bRButtonDown = true;
1090
1091         if (g_PrefsDlg.m_nMouseButtons == 3) {  // 3 button mouse
1092                 if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
1093                         if (ClipMode()) {                               // already there?
1094                                 DropClipPoint(nFlags, point);
1095                         }
1096                         else {
1097                                 SetClipMode(true);
1098                                 g_bRogueClipMode = true;
1099                                 DropClipPoint(nFlags, point);
1100                         }
1101
1102                         return;
1103                 }
1104         }
1105
1106         OriginalButtonDown(nFlags, point);
1107 }
1108
1109 /*
1110  =======================================================================================================================
1111  =======================================================================================================================
1112  */
1113 void CXYWnd::OnLButtonUp(UINT nFlags, CPoint point) {
1114
1115         if (ClipMode()) {
1116                 if (g_pMovingClip) {
1117                         ReleaseCapture();
1118                         g_pMovingClip = NULL;
1119                 }
1120         }
1121
1122         OriginalButtonUp(nFlags, point);
1123 }
1124
1125 /*
1126  =======================================================================================================================
1127  =======================================================================================================================
1128  */
1129 void CXYWnd::OnMButtonUp(UINT nFlags, CPoint point) {
1130         OriginalButtonUp(nFlags, point);
1131 }
1132
1133 /*
1134  =======================================================================================================================
1135  =======================================================================================================================
1136  */
1137 void CXYWnd::OnRButtonUp(UINT nFlags, CPoint point) {
1138         m_bRButtonDown = false;
1139         if (point == m_ptDown) {        // mouse didn't move
1140                 bool    bGo = true;
1141                 if ((GetAsyncKeyState(VK_MENU) & 0x8000)) {
1142                         bGo = false;
1143                 }
1144
1145                 if ((GetAsyncKeyState(VK_CONTROL) & 0x8000)) {
1146                         bGo = false;
1147                 }
1148
1149                 if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
1150                         bGo = false;
1151                 }
1152
1153                 if (bGo) {
1154                         HandleDrop();
1155                 }
1156         }
1157
1158         OriginalButtonUp(nFlags, point);
1159 }
1160
1161 /*
1162  =======================================================================================================================
1163  =======================================================================================================================
1164  */
1165 void CXYWnd::OriginalButtonDown(UINT nFlags, CPoint point) {
1166         CRect   rctZ;
1167         GetClientRect(rctZ);
1168         SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1169         if (g_pParentWnd->GetTopWindow() != this) {
1170                 BringWindowToTop();
1171         }
1172
1173         SetFocus();
1174         SetCapture();
1175         XY_MouseDown(point.x, rctZ.Height() - 1 - point.y, nFlags);
1176         m_nScrollFlags = nFlags;
1177 }
1178
1179 /*
1180  =======================================================================================================================
1181  =======================================================================================================================
1182  */
1183 void CXYWnd::OriginalButtonUp(UINT nFlags, CPoint point) {
1184         CRect   rctZ;
1185         GetClientRect(rctZ);
1186         XY_MouseUp(point.x, rctZ.Height() - 1 - point.y, nFlags);
1187         if (!(nFlags & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON))) {
1188                 ReleaseCapture();
1189         }
1190 }
1191
1192 idVec3  tdp;
1193
1194 /*
1195  =======================================================================================================================
1196  =======================================================================================================================
1197  */
1198 void CXYWnd::OnMouseMove(UINT nFlags, CPoint point) {
1199
1200         m_ptDown.x = 0;
1201         m_ptDown.y = 0;
1202
1203         if
1204         (
1205                 g_PrefsDlg.m_bChaseMouse == TRUE &&
1206                 (point.x < 0 || point.y < 0 || point.x > m_nWidth || point.y > m_nHeight) &&
1207                 GetCapture() == this
1208         ) {
1209                 float   fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale;
1210
1211                 // m_ptDrag = point;
1212                 m_ptDragAdj.x = 0;
1213                 m_ptDragAdj.y = 0;
1214                 if (point.x < 0) {
1215                         m_ptDragAdj.x = -fAdjustment;
1216                 }
1217                 else if (point.x > m_nWidth) {
1218                         m_ptDragAdj.x = fAdjustment;
1219                 }
1220
1221                 if (point.y < 0) {
1222                         m_ptDragAdj.y = -fAdjustment;
1223                 }
1224                 else if (point.y > m_nHeight) {
1225                         m_ptDragAdj.y = fAdjustment;
1226                 }
1227
1228                 if (m_nTimerID == -1) {
1229                         m_nTimerID = SetTimer(100, 50, NULL);
1230                         m_ptDrag = point;
1231                         m_ptDragTotal = 0;
1232                 }
1233
1234                 return;
1235         }
1236
1237         // else if (m_nTimerID != -1)
1238         if (m_nTimerID != -1) {
1239                 KillTimer(m_nTimerID);
1240                 pressx -= m_ptDragTotal.x;
1241                 pressy += m_ptDragTotal.y;
1242                 m_nTimerID = -1;
1243
1244                 // return;
1245         }
1246
1247         bool    bCrossHair = false;
1248         if (!m_bRButtonDown) {
1249                 tdp[0] = tdp[1] = tdp[2] = 0.0;
1250                 SnapToPoint(point.x, m_nHeight - 1 - point.y, tdp);
1251
1252                 g_strStatus.Format("x:: %.1f  y:: %.1f  z:: %.1f", tdp[0], tdp[1], tdp[2]);
1253                 g_pParentWnd->SetStatusText(1, g_strStatus);
1254
1255                 //
1256                 // i need to generalize the point code.. having 3 flavors pretty much sucks.. once
1257                 // the new curve stuff looks like it is going to stick i will rationalize this
1258                 // down to a single interface..
1259                 //
1260                 if (PointMode()) {
1261                         if (g_pMovingPoint && GetCapture() == this) {
1262                                 bCrossHair = true;
1263                                 SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingPoint->m_ptClip);
1264                                 g_pMovingPoint->UpdatePointPtr();
1265                                 Sys_UpdateWindows(XY | W_CAMERA_IFON);
1266                         }
1267                         else {
1268                                 g_pMovingPoint = NULL;
1269
1270                                 int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1271                                 int nDim2 = (m_nViewType == XY) ? 1 : 2;
1272                                 for (int n = 0; n < g_nPointCount; n++) {
1273                                         if
1274                                         (
1275                                                 fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1276                                                 fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3
1277                                         ) {
1278                                                 bCrossHair = true;
1279                                                 g_pMovingPoint = &g_PointPoints[n];
1280                                         }
1281                                 }
1282                         }
1283                 }
1284                 else if (ClipMode()) {
1285                         if (g_pMovingClip && GetCapture() == this) {
1286                                 bCrossHair = true;
1287                                 SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingClip->m_ptClip);
1288                                 Sys_UpdateWindows(XY | W_CAMERA_IFON);
1289                         }
1290                         else {
1291                                 g_pMovingClip = NULL;
1292
1293                                 int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1294                                 int nDim2 = (m_nViewType == XY) ? 1 : 2;
1295                                 if (g_Clip1.Set()) {
1296                                         if
1297                                         (
1298                                                 fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1299                                                 fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3
1300                                         ) {
1301                                                 bCrossHair = true;
1302                                                 g_pMovingClip = &g_Clip1;
1303                                         }
1304                                 }
1305
1306                                 if (g_Clip2.Set()) {
1307                                         if
1308                                         (
1309                                                 fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1310                                                 fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3
1311                                         ) {
1312                                                 bCrossHair = true;
1313                                                 g_pMovingClip = &g_Clip2;
1314                                         }
1315                                 }
1316
1317                                 if (g_Clip3.Set()) {
1318                                         if
1319                                         (
1320                                                 fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1321                                                 fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3
1322                                         ) {
1323                                                 bCrossHair = true;
1324                                                 g_pMovingClip = &g_Clip3;
1325                                         }
1326                                 }
1327                         }
1328
1329                         if (bCrossHair == false) {
1330                                 XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
1331                         }
1332                 }
1333                 else if (PathMode()) {
1334                         if (g_pMovingPath && GetCapture() == this) {
1335                                 bCrossHair = true;
1336                                 SnapToPoint(point.x, m_nHeight - 1 - point.y, g_pMovingPath->m_ptClip);
1337                                 Sys_UpdateWindows(XY | W_CAMERA_IFON);
1338                         }
1339                         else {
1340                                 g_pMovingPath = NULL;
1341
1342                                 int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1343                                 int nDim2 = (m_nViewType == XY) ? 1 : 2;
1344                                 for (int n = 0; n < g_nPathCount; n++) {
1345                                         if
1346                                         (
1347                                                 fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1348                                                 fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3
1349                                         ) {
1350                                                 bCrossHair = true;
1351                                                 g_pMovingPath = &g_PathPoints[n];
1352                                         }
1353                                 }
1354                         }
1355                 }
1356                 else {
1357                         bCrossHair = XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
1358                 }
1359         }
1360         else {
1361                 bCrossHair = XY_MouseMoved(point.x, m_nHeight - 1 - point.y, nFlags);
1362         }
1363
1364         if (bCrossHair) {
1365                 SetCursor(::LoadCursor(NULL, IDC_CROSS));
1366         }
1367         else {
1368                 SetCursor(::LoadCursor(NULL, IDC_ARROW));
1369         }
1370
1371         /// If precision crosshair is active, force redraw of the 2d view on mouse move 
1372         if( m_precisionCrosshairMode != PRECISION_CROSSHAIR_NONE )
1373         {
1374                 /// Force 2d view redraw (so that the precision cursor moves with the mouse)
1375                 Sys_UpdateWindows( W_XY );
1376         }
1377 }
1378
1379 /*
1380  =======================================================================================================================
1381  =======================================================================================================================
1382  */
1383 void CXYWnd::RetainClipMode(bool bMode) {
1384         bool    bSave = g_bRogueClipMode;
1385         SetClipMode(bMode);
1386         if (bMode == true) {
1387                 g_bRogueClipMode = bSave;
1388         }
1389         else {
1390                 g_bRogueClipMode = false;
1391         }
1392 }
1393
1394 /*
1395  =======================================================================================================================
1396  =======================================================================================================================
1397  */
1398 void CXYWnd::SetClipMode(bool bMode) {
1399         g_bClipMode = bMode;
1400         g_bRogueClipMode = false;
1401         if (bMode) {
1402                 g_Clip1.Reset();
1403                 g_Clip2.Reset();
1404                 g_Clip3.Reset();
1405                 CleanList(&g_brFrontSplits);
1406                 CleanList(&g_brBackSplits);
1407                 g_brFrontSplits.next = &g_brFrontSplits;
1408                 g_brBackSplits.next = &g_brBackSplits;
1409         }
1410         else {
1411                 if (g_pMovingClip) {
1412                         ReleaseCapture();
1413                         g_pMovingClip = NULL;
1414                 }
1415
1416                 CleanList(&g_brFrontSplits);
1417                 CleanList(&g_brBackSplits);
1418                 g_brFrontSplits.next = &g_brFrontSplits;
1419                 g_brBackSplits.next = &g_brBackSplits;
1420                 Sys_UpdateWindows(XY | W_CAMERA_IFON);
1421         }
1422 }
1423
1424 /*
1425  =======================================================================================================================
1426  =======================================================================================================================
1427  */
1428 bool CXYWnd::ClipMode() {
1429         return g_bClipMode;
1430 }
1431
1432 /*
1433  =======================================================================================================================
1434  =======================================================================================================================
1435  */
1436 bool CXYWnd::RogueClipMode() {
1437         return g_bRogueClipMode;
1438 }
1439
1440 /*
1441  =======================================================================================================================
1442  =======================================================================================================================
1443  */
1444 bool CXYWnd::PathMode() {
1445         return g_bPathMode;
1446 }
1447
1448 /*
1449  =======================================================================================================================
1450  =======================================================================================================================
1451  */
1452 bool CXYWnd::PointMode() {
1453         return g_bPointMode;
1454 }
1455
1456 /*
1457  =======================================================================================================================
1458  =======================================================================================================================
1459  */
1460 void CXYWnd::SetPointMode(bool b) {
1461         g_bPointMode = b;
1462         if (!b) {
1463                 g_nPointCount = 0;
1464         }
1465 }
1466
1467 /*
1468  =======================================================================================================================
1469  =======================================================================================================================
1470  */
1471 void CXYWnd::OnPaint() {
1472         CPaintDC        dc(this);                                       // device context for painting
1473         bool            bPaint = true;
1474         if (!qwglMakeCurrent(dc.m_hDC, win32.hGLRC)) {
1475                 common->Printf("ERROR: wglMakeCurrent failed.. Error:%i\n", qglGetError());
1476                 common->Printf("Please restart Q3Radiant if the Map view is not working\n");
1477                 bPaint = false;
1478         }
1479
1480         if (bPaint) {
1481                 QE_CheckOpenGLForErrors();
1482                 XY_Draw();
1483                 QE_CheckOpenGLForErrors();
1484
1485                 if (m_nViewType != XY) {
1486                         qglPushMatrix();
1487                         if (m_nViewType == YZ) {
1488                                 qglRotatef(-90, 0, 1, 0);       // put Z going up
1489                         }
1490
1491                         qglRotatef(-90, 1, 0, 0);               // put Z going up
1492                 }
1493
1494                 if ( g_bCrossHairs ) {
1495                         qglColor4f( 0.2f, 0.9f, 0.2f, 0.8f );
1496                         qglBegin(GL_LINES);
1497                         if (m_nViewType == XY) {
1498                                 qglVertex2f(-16384, tdp[1]);
1499                                 qglVertex2f(16384, tdp[1]);
1500                                 qglVertex2f(tdp[0], -16384);
1501                                 qglVertex2f(tdp[0], 16384);
1502                         }
1503                         else if (m_nViewType == YZ) {
1504                                 qglVertex3f(tdp[0], -16384, tdp[2]);
1505                                 qglVertex3f(tdp[0], 16384, tdp[2]);
1506                                 qglVertex3f(tdp[0], tdp[1], -16384);
1507                                 qglVertex3f(tdp[0], tdp[1], 16384);
1508                         }
1509                         else {
1510                                 qglVertex3f(-16384, tdp[1], tdp[2]);
1511                                 qglVertex3f(16384, tdp[1], tdp[2]);
1512                                 qglVertex3f(tdp[0], tdp[1], -16384);
1513                                 qglVertex3f(tdp[0], tdp[1], 16384);
1514                         }
1515
1516                         qglEnd();
1517                 }
1518
1519                 if (ClipMode()) {
1520                         qglPointSize(4);
1521                         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER].ToFloatPtr());
1522                         qglBegin(GL_POINTS);
1523                         if (g_Clip1.Set()) {
1524                                 qglVertex3fv(g_Clip1);
1525                         }
1526
1527                         if (g_Clip2.Set()) {
1528                                 qglVertex3fv(g_Clip2);
1529                         }
1530
1531                         if (g_Clip3.Set()) {
1532                                 qglVertex3fv(g_Clip3);
1533                         }
1534
1535                         qglEnd();
1536                         qglPointSize(1);
1537
1538                         CString strMsg;
1539                         if (g_Clip1.Set()) {
1540                                 qglRasterPos3f(g_Clip1.m_ptClip[0] + 2, g_Clip1.m_ptClip[1] + 2, g_Clip1.m_ptClip[2] + 2);
1541                                 strMsg = "1";
1542
1543                                 // strMsg.Format("1 (%f, %f, %f)", g_Clip1[0], g_Clip1[1], g_Clip1[2]);
1544                                 qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1545                         }
1546
1547                         if (g_Clip2.Set()) {
1548                                 qglRasterPos3f(g_Clip2.m_ptClip[0] + 2, g_Clip2.m_ptClip[1] + 2, g_Clip2.m_ptClip[2] + 2);
1549                                 strMsg = "2";
1550
1551                                 // strMsg.Format("2 (%f, %f, %f)", g_Clip2[0], g_Clip2[1], g_Clip2[2]);
1552                                 qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1553                         }
1554
1555                         if (g_Clip3.Set()) {
1556                                 qglRasterPos3f(g_Clip3.m_ptClip[0] + 2, g_Clip3.m_ptClip[1] + 2, g_Clip3.m_ptClip[2] + 2);
1557                                 strMsg = "3";
1558
1559                                 // strMsg.Format("3 (%f, %f, %f)", g_Clip3[0], g_Clip3[1], g_Clip3[2]);
1560                                 qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1561                         }
1562
1563                         if (g_Clip1.Set() && g_Clip2.Set() && selected_brushes.next != &selected_brushes) {
1564                                 ProduceSplitLists();
1565
1566                                 brush_t *pBrush;
1567                                 brush_t *pList = ((m_nViewType == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits;
1568                                 for (pBrush = pList->next; pBrush != NULL && pBrush != pList; pBrush = pBrush->next) {
1569                                         qglColor3f(1, 1, 0);
1570
1571                                         face_t  *face;
1572                                         int             order;
1573                                         for (face = pBrush->brush_faces, order = 0; face; face = face->next, order++) {
1574                                                 idWinding *w = face->face_winding;
1575                                                 if (!w) {
1576                                                         continue;
1577                                                 }
1578
1579                                                 // draw the polygon
1580                                                 qglBegin(GL_LINE_LOOP);
1581                                                 for (int i = 0; i < w->GetNumPoints(); i++) {
1582                                                         qglVertex3fv( (*w)[i].ToFloatPtr() );
1583                                                 }
1584
1585                                                 qglEnd();
1586                                         }
1587                                 }
1588                         }
1589                 }
1590
1591                 if (PathMode()) {
1592                         qglPointSize(4);
1593                         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER].ToFloatPtr());
1594                         qglBegin(GL_POINTS);
1595
1596                         int n;
1597                         for ( n = 0; n < g_nPathCount; n++) {
1598                                 qglVertex3fv(g_PathPoints[n]);
1599                         }
1600
1601                         qglEnd();
1602                         qglPointSize(1);
1603
1604                         CString strMsg;
1605                         for (n = 0; n < g_nPathCount; n++) {
1606                                 qglRasterPos3f
1607                                 (
1608                                         g_PathPoints[n].m_ptClip[0] + 2,
1609                                         g_PathPoints[n].m_ptClip[1] + 2,
1610                                         g_PathPoints[n].m_ptClip[2] + 2
1611                                 );
1612                                 strMsg.Format("%i", n + 1);
1613                                 qglCallLists(strMsg.GetLength(), GL_UNSIGNED_BYTE, strMsg);
1614                         }
1615                 }
1616
1617                 if (m_nViewType != XY) {
1618                         qglPopMatrix();
1619                 }
1620
1621                 qwglSwapBuffers(dc.m_hDC);
1622                 TRACE("XY Paint\n");
1623         }
1624 }
1625
1626 /*
1627  =======================================================================================================================
1628  =======================================================================================================================
1629  */
1630 void CXYWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
1631         g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags);
1632 }
1633
1634 //
1635 // =======================================================================================================================
1636 //    FIXME: the brush_t *pBrush is never used. ( Entity_Create uses selected_brushes )
1637 // =======================================================================================================================
1638 //
1639 void CreateEntityFromName(char *pName, brush_t *pBrush, bool forceFixed, idVec3 min, idVec3 max, idVec3 org) {
1640         eclass_t        *pecNew;
1641         entity_t        *petNew;
1642         if (stricmp(pName, "worldspawn") == 0) {
1643                 g_pParentWnd->MessageBox("Can't create an entity with worldspawn.", "info", 0);
1644                 return;
1645         }
1646
1647         pecNew = Eclass_ForName(pName, false);
1648
1649         if ((GetAsyncKeyState(VK_SHIFT) & 0x8000)) {
1650                 Select_Ungroup();
1651         }
1652
1653         // create it
1654         petNew = Entity_Create(pecNew, forceFixed);
1655
1656         if (petNew && idStr::Icmp(pName, "light") == 0 ) {
1657                 idVec3  rad = max - min;
1658                 rad *= 0.5;
1659                 if (rad.x != 0 && rad.y != 0 && rad.z != 0) {
1660                         SetKeyValue(petNew, "light_radius", va("%g %g %g", idMath::Fabs(rad.x), idMath::Fabs(rad.y), idMath::Fabs(rad.z)));
1661                         DeleteKey(petNew, "light");
1662                 }
1663         }
1664
1665
1666         if (petNew == NULL) {
1667                 if (!((selected_brushes.next == &selected_brushes) || (selected_brushes.next->next != &selected_brushes))) {
1668                         brush_t *b = selected_brushes.next;
1669                         if (b->owner != world_entity && ((b->owner->eclass->fixedsize && pecNew->fixedsize) || forceFixed)) {
1670                                 idVec3  mins, maxs;
1671                                 idVec3  origin;
1672                                 for (int i = 0; i < 3; i++) {
1673                                         origin[i] = b->mins[i] - pecNew->mins[i];
1674                                 }
1675
1676                                 VectorAdd(pecNew->mins, origin, mins);
1677                                 VectorAdd(pecNew->maxs, origin, maxs);
1678
1679                                 brush_t *nb = Brush_Create(mins, maxs, &pecNew->texdef);
1680                                 Entity_LinkBrush(b->owner, nb);
1681                                 nb->owner->eclass = pecNew;
1682                                 SetKeyValue(nb->owner, "classname", pName);
1683                                 Brush_Free(b);
1684                                 Brush_Build(nb);
1685                                 Brush_AddToList(nb, &active_brushes);
1686                                 Select_Brush(nb);
1687                                 return;
1688                         }
1689                 }
1690
1691                 g_pParentWnd->MessageBox("Failed to create entity.", "info", 0);
1692                 return;
1693         }
1694
1695         Select_Deselect();
1696
1697         //
1698         // entity_t* pEntity = world_entity; if (selected_brushes.next !=
1699         // &selected_brushes) pEntity = selected_brushes.next->owner;
1700         //
1701         Select_Brush(petNew->brushes.onext);
1702         Brush_Build(petNew->brushes.onext);
1703
1704 }
1705
1706 /*
1707  =======================================================================================================================
1708  =======================================================================================================================
1709  */
1710 brush_t *CreateEntityBrush(int x, int y, CXYWnd *pWnd) {
1711         idVec3  mins, maxs;
1712         int             i;
1713         float   temp;
1714         brush_t *n;
1715
1716         pWnd->SnapToPoint(x, y, mins);
1717         x += 32;
1718         y += 32;
1719         pWnd->SnapToPoint(x, y, maxs);
1720
1721         int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1;
1722         mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom[nDim] / g_qeglobals.d_gridsize));
1723         maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top[nDim] / g_qeglobals.d_gridsize));
1724
1725         if (maxs[nDim] <= mins[nDim]) {
1726                 maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
1727         }
1728
1729         for (i = 0; i < 3; i++) {
1730                 if (mins[i] == maxs[i]) {
1731                         maxs[i] += 16;  // don't create a degenerate brush
1732                 }
1733
1734                 if (mins[i] > maxs[i]) {
1735                         temp = mins[i];
1736                         mins[i] = maxs[i];
1737                         maxs[i] = temp;
1738                 }
1739         }
1740
1741         n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
1742         if (!n) {
1743                 return NULL;
1744         }
1745
1746         Brush_AddToList(n, &selected_brushes);
1747         Entity_LinkBrush(world_entity, n);
1748         Brush_Build(n);
1749         return n;
1750 }
1751
1752 /*
1753  =======================================================================================================================
1754  =======================================================================================================================
1755  */
1756 void CreateRightClickEntity(CXYWnd *pWnd, int x, int y, char *pName) {
1757         idVec3  min, max, org;
1758         Select_GetBounds(min, max);
1759         Select_GetMid(org);
1760
1761         CRect   rctZ;
1762         pWnd->GetClientRect(rctZ);
1763
1764         brush_t *pBrush;
1765         if (selected_brushes.next == &selected_brushes) {
1766                 pBrush = CreateEntityBrush(x, rctZ.Height() - 1 - y, pWnd);
1767                 min.Zero();
1768                 max.Zero();
1769                 CreateEntityFromName(pName, pBrush, true, min, max, org);
1770         }
1771         else {
1772                 pBrush = selected_brushes.next;
1773                 CreateEntityFromName(pName, pBrush, false, min, max, org);
1774         }
1775 }
1776
1777 /*
1778  =======================================================================================================================
1779  =======================================================================================================================
1780  */
1781 brush_t *CreateSmartBrush(idVec3 v) {
1782         idVec3  mins, maxs;
1783         int             i;
1784         brush_t *n;
1785
1786         for (i = 0; i < 3; i++) {
1787                 mins[i] = v[i] - 16;
1788                 maxs[i] = v[i] + 16;
1789         }
1790
1791         n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
1792         if (!n) {
1793                 return NULL;
1794         }
1795
1796         Brush_AddToList(n, &selected_brushes);
1797
1798         // Entity_LinkBrush(world_entity, n);
1799         Brush_Build(n);
1800         return n;
1801 }
1802
1803 CString g_strSmartEntity;
1804 int             g_nSmartX;
1805 int             g_nSmartY;
1806 bool    g_bSmartWaiting;
1807
1808 /*
1809  =======================================================================================================================
1810  =======================================================================================================================
1811  */
1812 void _SmartPointDone(bool b, int n) {
1813         g_bSmartWaiting = false;
1814 }
1815
1816 /*
1817  =======================================================================================================================
1818  =======================================================================================================================
1819  */
1820 void CreateSmartEntity(CXYWnd *pWnd, int x, int y, const char *pName) {
1821         g_nSmartX = x;
1822         g_nSmartY = y;
1823         g_strSmartEntity = pName;
1824         if (g_strSmartEntity.Find("Smart_Train") >= 0) {
1825                 ShowInfoDialog("Select the path of the train by left clicking in XY, YZ and/or XZ views. You can move an already dropped point by grabbing and moving it. When you are finished, press ENTER to accept and create the entity and path(s), press ESC to abandon the creation");
1826                 g_bPathMode = true;
1827                 g_nPathLimit = 0;
1828                 g_nPathCount = 0;
1829                 g_bSmartGo = true;
1830         }
1831         else if (g_strSmartEntity.Find("Smart_Monster...") >= 0) {
1832                 g_bPathMode = true;
1833                 g_nPathLimit = 0;
1834                 g_nPathCount = 0;
1835         }
1836         else if (g_strSmartEntity.Find("Smart_Rotating") >= 0) {
1837                 g_bSmartWaiting = true;
1838                 ShowInfoDialog("Left click to specify the rotation origin");
1839                 AcquirePath(1, &_SmartPointDone);
1840                 while (g_bSmartWaiting) {
1841                         MSG msg;
1842                         if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1843                                 TranslateMessage(&msg);
1844                                 DispatchMessage(&msg);
1845                         }
1846                 }
1847
1848                 HideInfoDialog();
1849
1850                 CPtrArray       array;
1851                 g_bScreenUpdates = false;
1852                 CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating");
1853                 array.Add(reinterpret_cast < void * > (selected_brushes.next));
1854                 Select_Deselect();
1855
1856                 brush_t *pBrush = CreateSmartBrush(g_PathPoints[0]);
1857                 array.Add(pBrush);
1858                 Select_Deselect();
1859                 Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(0)));
1860                 Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(1)));
1861                 ConnectEntities();
1862                 g_bScreenUpdates = true;
1863         }
1864 }
1865
1866 /*
1867  =======================================================================================================================
1868  =======================================================================================================================
1869  */
1870 void FinishSmartCreation() {
1871         CPtrArray       array;
1872         HideInfoDialog();
1873
1874         brush_t *pEntities = NULL;
1875         if (g_strSmartEntity.Find("Smart_Train") >= 0) {
1876                 g_bScreenUpdates = false;
1877                 CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train");
1878                 array.Add(reinterpret_cast < void * > (selected_brushes.next));
1879                 int n;
1880                 for (n = 0; n < g_nPathCount; n++) {
1881                         Select_Deselect();
1882                         CreateRightClickEntity
1883                         (
1884                                 g_pParentWnd->ActiveXY(),
1885                                 g_PathPoints[n].m_ptScreen.x,
1886                                 g_PathPoints[n].m_ptScreen.y,
1887                                 "path_corner"
1888                         );
1889                         array.Add(reinterpret_cast < void * > (selected_brushes.next));
1890                 }
1891
1892                 for (n = 0; n < g_nPathCount; n++) {
1893                         Select_Deselect();
1894                         Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(n)));
1895                         Select_Brush(reinterpret_cast < brush_t * > (array.GetAt(n + 1)));
1896                         ConnectEntities();
1897                 }
1898
1899                 g_bScreenUpdates = true;
1900         }
1901
1902         g_nPathCount = 0;
1903         g_bPathMode = false;
1904         Sys_UpdateWindows(W_ALL);
1905 }
1906
1907 /*
1908  =======================================================================================================================
1909  =======================================================================================================================
1910  */
1911 void CXYWnd::KillPathMode() {
1912         g_bSmartGo = false;
1913         g_bPathMode = false;
1914         if (g_pPathFunc) {
1915                 g_pPathFunc(false, g_nPathCount);
1916         }
1917
1918         g_nPathCount = 0;
1919         g_pPathFunc = NULL;
1920         Sys_UpdateWindows(W_ALL);
1921 }
1922
1923 //
1924 // =======================================================================================================================
1925 //    gets called for drop down menu messages TIP: it's not always about EntityCreate
1926 // =======================================================================================================================
1927 //
1928 void CXYWnd::OnEntityCreate(unsigned int nID) {
1929         if (m_mnuDrop.GetSafeHmenu()) {
1930                 CString strItem;
1931                 m_mnuDrop.GetMenuString(nID, strItem, MF_BYCOMMAND);
1932
1933                 if (strItem.CompareNoCase("Add to...") == 0) {
1934                         //
1935                         // ++timo TODO: fill the menu with current groups? this one is for adding to
1936                         // existing groups only
1937                         //
1938                         common->Printf("TODO: Add to... in CXYWnd::OnEntityCreate\n");
1939                 }
1940                 else if (strItem.CompareNoCase("Remove") == 0) {
1941                         // remove selected brushes from their current group
1942                         brush_t *b;
1943                         for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
1944                         }
1945                 }
1946
1947                 // ++timo FIXME: remove when all hooks are in
1948                 if
1949                 (
1950                         strItem.CompareNoCase("Add to...") == 0 ||
1951                         strItem.CompareNoCase("Remove") == 0 ||
1952                         strItem.CompareNoCase("Name...") == 0 ||
1953                         strItem.CompareNoCase("New group...") == 0
1954                 ) {
1955                         common->Printf("TODO: hook drop down group menu\n");
1956                         return;
1957                 }
1958
1959                 if (strItem.Find("Smart_") >= 0) {
1960                         CreateSmartEntity(this, m_ptDown.x, m_ptDown.y, strItem);
1961                 }
1962                 else {
1963                         CreateRightClickEntity(this, m_ptDown.x, m_ptDown.y, strItem.GetBuffer(0));
1964                 }
1965
1966                 Sys_UpdateWindows(W_ALL);
1967
1968                 // OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2));
1969         }
1970 }
1971
1972 BOOL CXYWnd::OnCmdMsg( UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo )
1973 {
1974         if ( CWnd::OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ) ) {
1975                 return TRUE;
1976         }
1977         return AfxGetMainWnd()->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo );
1978 }
1979
1980 bool MergeMenu(CMenu * pMenuDestination, const CMenu * pMenuAdd, bool bTopLevel /*=false*/)
1981 {
1982         // get the number menu items in the menus
1983         int iMenuAddItemCount   = pMenuAdd->GetMenuItemCount();
1984         int iMenuDestItemCount  = pMenuDestination->GetMenuItemCount();
1985
1986         // if there are no items return
1987         if (iMenuAddItemCount == 0)
1988                 return true;
1989
1990         // if we are not at top level and the destination menu is not empty
1991         // -> we append a seperator
1992         if (!bTopLevel && iMenuDestItemCount > 0)
1993                 pMenuDestination->AppendMenu(MF_SEPARATOR);
1994
1995         // iterate through the top level of <pMenuAdd>
1996         for(int iLoop = 0; iLoop < iMenuAddItemCount; iLoop++)
1997         {
1998                 // get the menu string from the add menu
1999                 CString sMenuAddString;
2000                 pMenuAdd->GetMenuString(iLoop, sMenuAddString, MF_BYPOSITION);
2001
2002                 // try to get the submenu of the current menu item
2003                 CMenu* pSubMenu = pMenuAdd->GetSubMenu(iLoop);
2004
2005                 // check if we have a sub menu
2006                 if (!pSubMenu)
2007                 {
2008                         // normal menu item
2009                         // read the source and append at the destination
2010                         UINT nState      = pMenuAdd->GetMenuState(iLoop, MF_BYPOSITION);
2011                         UINT nItemID = pMenuAdd->GetMenuItemID(iLoop);
2012                         if (pMenuDestination->AppendMenu(nState, nItemID, sMenuAddString))
2013                         {
2014                                 // menu item added, don't forget to correct the item count
2015                                 iMenuDestItemCount++;
2016                         }
2017                         else
2018                         {
2019                                 TRACE("MergeMenu: AppendMenu failed!\n");
2020                                 return false;
2021                         }
2022                 }
2023                 else
2024                 {
2025                         // create or insert a new popup menu item
2026
2027                         // default insert pos is like ap
2028                         int iInsertPosDefault = -1;
2029
2030                         // if we are at top level merge into existing popups rather than
2031                         // creating new ones
2032                         if(bTopLevel)
2033                         {
2034                                 ASSERT(sMenuAddString != "&?" && sMenuAddString !=
2035                                         "?");
2036                                 CString csAdd(sMenuAddString);
2037                                 csAdd.Remove('&');      // for comparison of menu items supress '&'
2038                                 bool bAdded = false;
2039
2040                                 // try to find existing popup
2041                                 for( int iLoop1 = 0; iLoop1 < iMenuDestItemCount; iLoop1++ )
2042                                 {
2043                                         // get the menu string from the destination menu
2044                                         CString sDest;
2045                                         pMenuDestination->GetMenuString(iLoop1, sDest, MF_BYPOSITION);
2046                                         sDest.Remove('&'); // for a better compare (s.a.)
2047
2048                                         if (csAdd == sDest)
2049                                         {
2050                                                 // we got a hit -> merge the two popups
2051                                                 // try to get the submenu of the desired destination menu item
2052                                                         CMenu* pSubMenuDest =
2053                                                         pMenuDestination->GetSubMenu(iLoop1);
2054
2055                                                 if (pSubMenuDest)
2056                                                 {
2057                                                         // merge the popup recursivly and continue with outer for loop
2058                                                                 if (!MergeMenu(pSubMenuDest, pSubMenu, false))
2059                                                                         return false;
2060                                                         bAdded = true;
2061                                                         break;
2062                                                 }
2063                                         }
2064
2065                                         // alternativ insert before <Window> or <Help>
2066                                         if (iInsertPosDefault == -1 && (sDest == "Window"
2067                                                 || sDest == "?" || sDest == "Help"))
2068                                         {
2069                                                 iInsertPosDefault = iLoop1;
2070                                         }
2071                                 } // for (iLoop1)
2072                                 if (bAdded)
2073                                 {
2074                                         // menu added, so go on with loop over pMenuAdd's top level
2075                                         continue;
2076                                 }
2077                         } // if (bTopLevel)
2078
2079                         // if the top level search did not find a position append the menu
2080                         if( iInsertPosDefault == -1 )
2081                         {
2082                                 iInsertPosDefault = pMenuDestination->GetMenuItemCount();
2083                         }
2084
2085                         // create a new popup and insert before <Window> or <Help>
2086                         CMenu NewPopupMenu;
2087                         if (!NewPopupMenu.CreatePopupMenu())
2088                         {
2089                                 TRACE("MergeMenu: CreatePopupMenu failed!\n");
2090                                 return false;
2091                         }
2092
2093                         // merge the new popup recursivly
2094                         if (!MergeMenu(&NewPopupMenu, pSubMenu, false))
2095                                 return false;
2096
2097                         // insert the new popup menu into the destination menu
2098                         HMENU hNewMenu = NewPopupMenu.GetSafeHmenu();
2099                         if (pMenuDestination->InsertMenu(iInsertPosDefault,
2100                                 MF_BYPOSITION | MF_POPUP | MF_ENABLED, 
2101                                 (UINT)hNewMenu, sMenuAddString ))
2102                         {
2103                                 // don't forget to correct the item count
2104                                 iMenuDestItemCount++;
2105                         }
2106                         else
2107                         {
2108                                 TRACE("MergeMenu: InsertMenu failed!\n");
2109                                 return false;
2110                         }
2111
2112                         // don't destroy the new menu           
2113                         NewPopupMenu.Detach();
2114                 } // if (pSubMenu)
2115         } // for (iLoop)
2116         return true;
2117 }
2118
2119
2120
2121
2122 /*
2123  =======================================================================================================================
2124  =======================================================================================================================
2125  */
2126 void CXYWnd::HandleDrop() {
2127         if (g_PrefsDlg.m_bRightClick == false) {
2128                 return;
2129         }
2130
2131         if (!m_mnuDrop.GetSafeHmenu()) {                // first time, load it up
2132                 m_mnuDrop.CreatePopupMenu();
2133                 
2134                 CMenu *drop = new CMenu;
2135                 drop->LoadMenu( IDR_MENU_DROP );
2136
2137                 MergeMenu( &m_mnuDrop, drop, false );
2138
2139                 int             nID = ID_ENTITY_START;
2140
2141                 CMenu   *pMakeEntityPop = &m_mnuDrop;
2142
2143                 // Todo: Make this a config option maybe?
2144                 const int entitiesOnSubMenu = false;
2145                 if ( entitiesOnSubMenu ) {
2146                         pMakeEntityPop = new CMenu;
2147                         pMakeEntityPop->CreateMenu();
2148                 }
2149
2150                 CMenu   *pChild = NULL;
2151
2152                 eclass_t        *e;
2153                 CString         strActive;
2154                 CString         strLast;
2155                 CString         strName;
2156                 for (e = eclass; e; e = e->next) {
2157                         strLast = strName;
2158                         strName = e->name;
2159
2160                         int n_ = strName.Find("_");
2161                         if (n_ > 0) {
2162                                 CString strLeft = strName.Left(n_);
2163                                 CString strRight = strName.Right(strName.GetLength() - n_ - 1);
2164                                 if (strLeft == strActive) { // this is a child
2165                                         ASSERT(pChild);
2166                                         pChild->AppendMenu(MF_STRING, nID++, strName);
2167                                 }
2168                                 else {
2169                                         if (pChild) {
2170                                                 pMakeEntityPop->AppendMenu (
2171                                                         MF_POPUP,
2172                                                         reinterpret_cast < unsigned int > (pChild->GetSafeHmenu()),
2173                                                         strActive
2174                                                 );
2175                                                 g_ptrMenus.Add(pChild);
2176
2177                                                 // pChild->DestroyMenu(); delete pChild;
2178                                                 pChild = NULL;
2179                                         }
2180
2181                                         strActive = strLeft;
2182                                         pChild = new CMenu;
2183                                         pChild->CreateMenu();
2184                                         pChild->AppendMenu(MF_STRING, nID++, strName);
2185                                 }
2186                         }
2187                         else {
2188                                 if (pChild) {
2189                                         pMakeEntityPop->AppendMenu (
2190                                                 MF_POPUP,
2191                                                 reinterpret_cast < unsigned int > (pChild->GetSafeHmenu()),
2192                                                 strActive
2193                                         );
2194                                         g_ptrMenus.Add(pChild);
2195
2196                                         // pChild->DestroyMenu(); delete pChild;
2197                                         pChild = NULL;
2198                                 }
2199
2200                                 strActive = "";
2201                                 pMakeEntityPop->AppendMenu(MF_STRING, nID++, strName);
2202                         }
2203                 }
2204                 if ( pMakeEntityPop != &m_mnuDrop ) {
2205                         m_mnuDrop.AppendMenu (
2206                                 MF_POPUP,
2207                                 reinterpret_cast < unsigned int > (pMakeEntityPop->GetSafeHmenu()),
2208                                 "Make Entity"
2209                         );
2210                 }
2211         }
2212
2213         CPoint  ptMouse;
2214         GetCursorPos(&ptMouse);
2215         m_mnuDrop.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, ptMouse.x, ptMouse.y, this);
2216 }
2217
2218 /*
2219  =======================================================================================================================
2220  =======================================================================================================================
2221  */
2222 void CXYWnd::XY_Init() {
2223         m_vOrigin[0] = 0;
2224         m_vOrigin[1] = 20;
2225         m_vOrigin[2] = 46;
2226         m_fScale = 1;
2227         m_precisionCrosshairMode = PRECISION_CROSSHAIR_NONE;
2228 }
2229
2230 /*
2231  =======================================================================================================================
2232  =======================================================================================================================
2233  */
2234 void CXYWnd::SnapToPoint(int x, int y, idVec3 &point) {
2235         if (g_PrefsDlg.m_bNoClamp) {
2236                 XY_ToPoint(x, y, point);
2237         }
2238         else {
2239                 XY_ToGridPoint(x, y, point);
2240         }
2241
2242         // -- else -- XY_ToPoint(x, y, point); -- //XY_ToPoint(x, y, point);
2243 }
2244
2245 /*
2246  =======================================================================================================================
2247  =======================================================================================================================
2248  */
2249 void CXYWnd::XY_ToPoint(int x, int y, idVec3 &point) {
2250         float   fx = x;
2251         float   fy = y;
2252         float   fw = m_nWidth;
2253         float   fh = m_nHeight;
2254         if (m_nViewType == XY) {
2255                 point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
2256                 point[1] = m_vOrigin[1] + (fy - fh / 2) / m_fScale;
2257
2258                 // point[2] = 0;
2259         }
2260         else if (m_nViewType == YZ) {
2261                 //
2262                 // //point[0] = 0; point[1] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; point[2] =
2263                 // m_vOrigin[1] + (fy - fh / 2 ) / m_fScale;
2264                 //
2265                 point[1] = m_vOrigin[1] + (fx - fw / 2) / m_fScale;
2266                 point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale;
2267         }
2268         else {
2269                 //
2270                 // point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale; /point[1] = 0; point[2] =
2271                 // m_vOrigin[1] + (fy - fh / 2) / m_fScale;
2272                 //
2273                 point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
2274
2275                 // point[1] = 0;
2276                 point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale;
2277         }
2278 }
2279
2280 /*
2281  =======================================================================================================================
2282  =======================================================================================================================
2283  */
2284 void CXYWnd::XY_ToGridPoint(int x, int y, idVec3 &point) {
2285         if (m_nViewType == XY) {
2286                 point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
2287                 point[1] = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
2288
2289                 // point[2] = 0;
2290                 point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2291                 point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2292         }
2293         else if (m_nViewType == YZ) {
2294                 //
2295                 // point[0] = 0; point[1] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; point[2]
2296                 // = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
2297                 //
2298                 point[1] = m_vOrigin[1] + (x - m_nWidth / 2) / m_fScale;
2299                 point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
2300                 point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2301                 point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2302         }
2303         else {
2304                 //
2305                 // point[1] = 0; point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale; point[2]
2306                 // = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
2307                 //
2308                 point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
2309                 point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
2310                 point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2311                 point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2312         }
2313 }
2314
2315 /*
2316  =======================================================================================================================
2317  =======================================================================================================================
2318  */
2319 idVec3 dragOrigin;
2320 idVec3 dragDir;
2321 idVec3 dragX;
2322 idVec3 dragY;
2323
2324 void CXYWnd::XY_MouseDown(int x, int y, int buttons) {
2325         idVec3  point,center;
2326         idVec3  origin, dir, right, up;
2327
2328         m_nButtonstate = buttons;
2329         m_nPressx = x;
2330         m_nPressy = y;
2331         VectorCopy(vec3_origin, m_vPressdelta);
2332
2333         point.Zero();
2334
2335         XY_ToPoint(x, y, point);
2336
2337         VectorCopy(point, origin);
2338
2339         dir.Zero();
2340         if (m_nViewType == XY) {
2341                 origin[2] = HUGE_DISTANCE;
2342                 dir[2] = -1;
2343                 right[0] = 1 / m_fScale;
2344                 right[1] = 0;
2345                 right[2] = 0;
2346                 up[0] = 0;
2347                 up[1] = 1 / m_fScale;
2348                 up[2] = 0;
2349                 point[2] = g_pParentWnd->GetCamera()->Camera().origin[2];
2350         }
2351         else if (m_nViewType == YZ) {
2352                 origin[0] = HUGE_DISTANCE;
2353                 dir[0] = -1;
2354                 right[1] = 1 / m_fScale;
2355                 right[2] = 0;
2356                 right[0] = 0;
2357                 up[0] = 0;
2358                 up[2] = 1 / m_fScale;
2359                 up[1] = 0;
2360                 point[0] = g_pParentWnd->GetCamera()->Camera().origin[0];
2361         }
2362         else {
2363                 origin[1] = HUGE_DISTANCE;
2364                 dir[1] = -1;
2365                 right[0] = 1 / m_fScale;
2366                 right[2] = 0;
2367                 right[1] = 0;
2368                 up[0] = 0;
2369                 up[2] = 1 / m_fScale;
2370                 up[1] = 0;
2371                 point[1] = g_pParentWnd->GetCamera()->Camera().origin[1];
2372         }
2373
2374         dragOrigin = m_vOrigin;
2375         dragDir = dir;
2376         dragX = right;
2377         dragY = up;
2378
2379         m_bPress_selection = (selected_brushes.next != &selected_brushes);
2380
2381         GetCursorPos(&m_ptCursor);
2382
2383         // Sys_GetCursorPos (&m_ptCursor.x, &m_ptCursor.y);
2384         if (buttons == MK_LBUTTON && activeDrag) {
2385                 activeDragging = true;
2386         }
2387         else {
2388                 activeDragging = false;
2389         }
2390
2391         // lbutton = manipulate selection shift-LBUTTON = select
2392         if
2393         (
2394                 (buttons == MK_LBUTTON) ||
2395                 (buttons == (MK_LBUTTON | MK_SHIFT)) ||
2396                 (buttons == (MK_LBUTTON | MK_CONTROL)) ||
2397                 (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT))
2398         ) {
2399                 if (g_qeglobals.d_select_mode == sel_addpoint) {
2400                         XY_ToGridPoint(x, y, point);
2401                         if (g_qeglobals.selectObject) {
2402                                 g_qeglobals.selectObject->addPoint(point);
2403                         }
2404
2405                         return;
2406                 }
2407
2408                 Patch_SetView((m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ);
2409                 Drag_Begin(x, y, buttons, right, up, origin, dir);
2410                 return;
2411         }
2412
2413         int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
2414
2415         // control mbutton = move camera
2416         if (m_nButtonstate == (MK_CONTROL | nMouseButton)) {
2417                 VectorCopyXY(point, g_pParentWnd->GetCamera()->Camera().origin);
2418                 Sys_UpdateWindows(W_CAMERA | W_XY_OVERLAY);
2419         }
2420
2421         // mbutton = angle camera
2422         if
2423         (
2424                 (g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
2425                 (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT | MK_CONTROL | MK_RBUTTON))
2426         ) {
2427                 VectorSubtract(point, g_pParentWnd->GetCamera()->Camera().origin, point);
2428
2429                 int n1 = (m_nViewType == XY) ? 1 : 2;
2430                 int n2 = (m_nViewType == YZ) ? 1 : 0;
2431                 int nAngle = (m_nViewType == XY) ? YAW : PITCH;
2432                 if (point[n1] || point[n2]) {
2433                         g_pParentWnd->GetCamera()->Camera().angles[nAngle] = RAD2DEG( atan2(point[n1], point[n2]) );
2434                         Sys_UpdateWindows(W_CAMERA_IFON | W_XY_OVERLAY);
2435                 }
2436         }
2437
2438         // shift mbutton = move z checker
2439         if (m_nButtonstate == (MK_SHIFT | nMouseButton)) {
2440                 if (RotateMode() || g_bPatchBendMode) {
2441                         SnapToPoint(x, y, point);
2442                         VectorCopyXY(point, g_vRotateOrigin);
2443                         if (g_bPatchBendMode) {
2444                                 VectorCopy(point, g_vBendOrigin);
2445                         }
2446
2447                         Sys_UpdateWindows(W_XY);
2448                         return;
2449                 }
2450                 else {
2451                         SnapToPoint(x, y, point);
2452                         if (m_nViewType == XY) {
2453                                 z.origin[0] = point[0];
2454                                 z.origin[1] = point[1];
2455                         }
2456                         else if (m_nViewType == YZ) {
2457                                 z.origin[0] = point[1];
2458                                 z.origin[1] = point[2];
2459                         }
2460                         else {
2461                                 z.origin[0] = point[0];
2462                                 z.origin[1] = point[2];
2463                         }
2464
2465                         Sys_UpdateWindows(W_XY_OVERLAY | W_Z);
2466                         return;
2467                 }
2468         }
2469 }
2470
2471 /*
2472  =======================================================================================================================
2473  =======================================================================================================================
2474  */
2475 void CXYWnd::XY_MouseUp(int x, int y, int buttons) {
2476         activeDragging = false;
2477         Drag_MouseUp(buttons);
2478         if (!m_bPress_selection) {
2479                 Sys_UpdateWindows(W_ALL);
2480         }
2481
2482         m_nButtonstate = 0;
2483         while (::ShowCursor(TRUE) < 0)
2484                 ;
2485 }
2486
2487 /*
2488  =======================================================================================================================
2489  =======================================================================================================================
2490  */
2491 bool CXYWnd::DragDelta(int x, int y, idVec3 &move) {
2492         idVec3  xvec, yvec, delta;
2493         int             i;
2494
2495         xvec[0] = 1 / m_fScale;
2496         xvec[1] = xvec[2] = 0;
2497         yvec[1] = 1 / m_fScale;
2498         yvec[0] = yvec[2] = 0;
2499
2500         for (i = 0; i < 3; i++) {
2501                 delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy);
2502                 if (!g_PrefsDlg.m_bNoClamp) {
2503                         delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2504                 }
2505         }
2506
2507         VectorSubtract(delta, m_vPressdelta, move);
2508         VectorCopy(delta, m_vPressdelta);
2509
2510
2511         if (move[0] || move[1] || move[2]) {
2512                 return true;
2513         }
2514
2515         return false;
2516 }
2517
2518 /*
2519  =======================================================================================================================
2520     NewBrushDrag
2521  =======================================================================================================================
2522  */
2523 void CXYWnd::NewBrushDrag(int x, int y) {
2524         idVec3  mins, maxs, junk;
2525         int             i;
2526         float   temp;
2527         brush_t *n;
2528
2529         if ( radiant_entityMode.GetBool() ) {
2530                 return;
2531         }
2532
2533         if (!DragDelta(x, y, junk)) {
2534                 return;
2535         }
2536
2537         // delete the current selection
2538         if (selected_brushes.next != &selected_brushes) {
2539                 Brush_Free(selected_brushes.next);
2540         }
2541
2542         SnapToPoint(m_nPressx, m_nPressy, mins);
2543
2544         int nDim = (m_nViewType == XY) ? 2 : (m_nViewType == YZ) ? 0 : 1;
2545
2546         mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom[nDim] / g_qeglobals.d_gridsize));
2547         SnapToPoint(x, y, maxs);
2548         maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top[nDim] / g_qeglobals.d_gridsize));
2549         if (maxs[nDim] <= mins[nDim]) {
2550                 maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
2551         }
2552
2553         for (i = 0; i < 3; i++) {
2554                 if (mins[i] == maxs[i]) {
2555                         return; // don't create a degenerate brush
2556                 }
2557
2558                 if (mins[i] > maxs[i]) {
2559                         temp = mins[i];
2560                         mins[i] = maxs[i];
2561                         maxs[i] = temp;
2562                 }
2563         }
2564
2565         n = Brush_Create(mins, maxs, &g_qeglobals.d_texturewin.texdef);
2566         if (!n) {
2567                 return;
2568         }
2569
2570         idVec3  vSize;
2571         VectorSubtract(maxs, mins, vSize);
2572         g_strStatus.Format("Size X:: %.1f  Y:: %.1f  Z:: %.1f", vSize[0], vSize[1], vSize[2]);
2573         g_pParentWnd->SetStatusText(2, g_strStatus);
2574
2575         Brush_AddToList(n, &selected_brushes);
2576
2577         Entity_LinkBrush(world_entity, n);
2578
2579         Brush_Build(n);
2580
2581         // Sys_UpdateWindows (W_ALL);
2582         Sys_UpdateWindows(W_XY | W_CAMERA);
2583 }
2584
2585 /*
2586  =======================================================================================================================
2587     XY_MouseMoved
2588  =======================================================================================================================
2589  */
2590 bool CXYWnd::XY_MouseMoved(int x, int y, int buttons) {
2591         idVec3  point;
2592
2593         if (!m_nButtonstate) {
2594                 if (g_bCrossHairs) {
2595                         ::ShowCursor(FALSE);
2596                         Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
2597                         ::ShowCursor(TRUE);
2598                 }
2599
2600                 return false;
2601         }
2602
2603         //
2604         // lbutton without selection = drag new brush if (m_nButtonstate == MK_LBUTTON &&
2605         // !m_bPress_selection && g_qeglobals.d_select_mode != sel_curvepoint &&
2606         // g_qeglobals.d_select_mode != sel_splineedit)
2607         //
2608         if (m_nButtonstate == MK_LBUTTON && !m_bPress_selection && g_qeglobals.d_select_mode == sel_brush) {
2609                 NewBrushDrag(x, y);
2610                 return false;
2611         }
2612
2613         // lbutton (possibly with control and or shift) with selection = drag selection
2614         if (m_nButtonstate & MK_LBUTTON) {
2615                 Drag_MouseMoved(x, y, buttons);
2616                 Sys_UpdateWindows(W_XY_OVERLAY | W_CAMERA_IFON | W_Z);
2617                 return false;
2618         }
2619
2620         int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
2621
2622         // control mbutton = move camera
2623         if (m_nButtonstate == (MK_CONTROL | nMouseButton)) {
2624                 SnapToPoint(x, y, point);
2625                 VectorCopyXY(point, g_pParentWnd->GetCamera()->Camera().origin);
2626                 Sys_UpdateWindows(W_XY_OVERLAY | W_CAMERA);
2627                 return false;
2628         }
2629
2630         // shift mbutton = move z checker
2631         if (m_nButtonstate == (MK_SHIFT | nMouseButton)) {
2632                 if (RotateMode() || g_bPatchBendMode) {
2633                         SnapToPoint(x, y, point);
2634                         VectorCopyXY(point, g_vRotateOrigin);
2635                         if (g_bPatchBendMode) {
2636                                 VectorCopy(point, g_vBendOrigin);
2637                         }
2638
2639                         Sys_UpdateWindows(W_XY);
2640                         return false;
2641                 }
2642                 else {
2643                         SnapToPoint(x, y, point);
2644                         if (m_nViewType == XY) {
2645                                 z.origin[0] = point[0];
2646                                 z.origin[1] = point[1];
2647                         }
2648                         else if (m_nViewType == YZ) {
2649                                 z.origin[0] = point[1];
2650                                 z.origin[1] = point[2];
2651                         }
2652                         else {
2653                                 z.origin[0] = point[0];
2654                                 z.origin[1] = point[2];
2655                         }
2656                 }
2657
2658                 Sys_UpdateWindows(W_XY_OVERLAY | W_Z);
2659                 return false;
2660         }
2661
2662         // mbutton = angle camera
2663         if
2664         (
2665                 (g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
2666                 (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT | MK_CONTROL | MK_RBUTTON))
2667         ) {
2668                 SnapToPoint(x, y, point);
2669                 VectorSubtract(point, g_pParentWnd->GetCamera()->Camera().origin, point);
2670
2671                 int n1 = (m_nViewType == XY) ? 1 : 2;
2672                 int n2 = (m_nViewType == YZ) ? 1 : 0;
2673                 int nAngle = (m_nViewType == XY) ? YAW : PITCH;
2674                 if (point[n1] || point[n2]) {
2675                         g_pParentWnd->GetCamera()->Camera().angles[nAngle] = RAD2DEG( atan2(point[n1], point[n2]) );
2676                         Sys_UpdateWindows(W_CAMERA_IFON | W_XY_OVERLAY);
2677                 }
2678
2679                 return false;
2680         }
2681
2682         // rbutton = drag xy origin
2683         if (m_nButtonstate == MK_RBUTTON) {
2684                 Sys_GetCursorPos(&x, &y);
2685
2686                 if (x != m_ptCursor.x || y != m_ptCursor.y) {
2687                         if ((GetAsyncKeyState(VK_MENU) & 0x8000)) {
2688                                 int             *px = &x;
2689                                 long    *px2 = &m_ptCursor.x;
2690
2691                                 if (fDiff(y, m_ptCursor.y) > fDiff(x, m_ptCursor.x)) {
2692                                         px = &y;
2693                                         px2 = &m_ptCursor.y;
2694                                 }
2695
2696                                 if (*px > *px2) {
2697                                         // zoom in
2698                                         SetScale( Scale() * 1.1f );
2699                                         if ( Scale() < 0.1f ) {
2700                                                 SetScale( 0.1f );
2701                                         }
2702                                 }
2703                                 else if (*px < *px2) {
2704                                         // zoom out
2705                                         SetScale( Scale() * 0.9f );
2706                                         if ( Scale() > 16.0f ) {
2707                                                 SetScale( 16.0f );
2708                                         }
2709                                 }
2710
2711                                 *px2 = *px;
2712                                 Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
2713                         }
2714                         else {
2715                                 int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2716                                 int nDim2 = (m_nViewType == XY) ? 1 : 2;
2717                                 m_vOrigin[nDim1] -= (x - m_ptCursor.x) / m_fScale;
2718                                 m_vOrigin[nDim2] += (y - m_ptCursor.y) / m_fScale;
2719                                 SetCursorPos(m_ptCursor.x, m_ptCursor.y);
2720                                 ::ShowCursor(FALSE);
2721
2722                                 // XY_Draw(); RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
2723                                 Sys_UpdateWindows(W_XY | W_XY_OVERLAY);
2724
2725                                 // ::ShowCursor(TRUE);
2726                         }
2727                 }
2728
2729                 return false;
2730         }
2731
2732         return false;
2733 }
2734
2735 /*
2736  =======================================================================================================================
2737     DRAWING Â£
2738     XY_DrawGrid
2739  =======================================================================================================================
2740  */
2741 void CXYWnd::XY_DrawGrid() {
2742         float   x, y, xb, xe, yb, ye;
2743         int             w, h;
2744         char    text[32];
2745
2746         int startPos = max ( 64 , g_qeglobals.d_gridsize );
2747
2748         w = m_nWidth / 2 / m_fScale;
2749         h = m_nHeight / 2 / m_fScale;
2750
2751         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2752         int nDim2 = (m_nViewType == XY) ? 1 : 2;
2753
2754         // int nDim1 = 0; int nDim2 = 1;
2755         xb = m_vOrigin[nDim1] - w;
2756         if (xb < region_mins[nDim1]) {
2757                 xb = region_mins[nDim1];
2758         }
2759
2760         xb = startPos * floor(xb / startPos);
2761
2762         xe = m_vOrigin[nDim1] + w;
2763         if (xe > region_maxs[nDim1]) {
2764                 xe = region_maxs[nDim1];
2765         }
2766
2767         xe = startPos * ceil(xe / startPos);
2768
2769         yb = m_vOrigin[nDim2] - h;
2770         if (yb < region_mins[nDim2]) {
2771                 yb = region_mins[nDim2];
2772         }
2773
2774         yb = startPos * floor(yb / startPos);
2775
2776         ye = m_vOrigin[nDim2] + h;
2777         if (ye > region_maxs[nDim2]) {
2778                 ye = region_maxs[nDim2];
2779         }
2780
2781         ye = startPos * ceil(ye / startPos);
2782
2783         // draw major blocks
2784         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR].ToFloatPtr());
2785
2786         int stepSize = 64 * 0.1 / m_fScale;
2787         if (stepSize < 64) {
2788                 stepSize = max ( 64 , g_qeglobals.d_gridsize ); 
2789         }
2790         else {
2791                 int i;
2792                 for (i = 1; i < stepSize; i <<= 1) {
2793                 }
2794
2795                 stepSize = i;
2796         }
2797
2798         if (g_qeglobals.d_showgrid) {
2799                 qglBegin(GL_LINES);
2800
2801                 for (x = xb; x <= xe; x += stepSize) {
2802                         qglVertex2f(x, yb);
2803                         qglVertex2f(x, ye);
2804                 }
2805
2806                 for (y = yb; y <= ye; y += stepSize) {
2807                         qglVertex2f(xb, y);
2808                         qglVertex2f(xe, y);
2809                 }
2810
2811                 qglEnd();
2812         }
2813
2814         // draw minor blocks
2815         if ( m_fScale > .1 &&
2816                 g_qeglobals.d_showgrid &&
2817                 g_qeglobals.d_gridsize * m_fScale >= 4 &&
2818                 !g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR].Compare( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK] ) ) {
2819
2820                 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR].ToFloatPtr());
2821
2822                 qglBegin(GL_LINES);
2823                 for (x = xb; x < xe; x += g_qeglobals.d_gridsize) {
2824                         if (!((int)x & (startPos - 1))) {
2825                                 continue;
2826                         }
2827
2828                         qglVertex2f(x, yb);
2829                         qglVertex2f(x, ye);
2830                 }
2831
2832                 for (y = yb; y < ye; y += g_qeglobals.d_gridsize) {
2833                         if (!((int)y & (startPos - 1))) {
2834                                 continue;
2835                         }
2836
2837                         qglVertex2f(xb, y);
2838                         qglVertex2f(xe, y);
2839                 }
2840
2841                 qglEnd();
2842         }
2843
2844
2845         // draw ZClip boundaries (if applicable)...
2846         //
2847         if (m_nViewType == XZ || m_nViewType == YZ)
2848         {
2849                 if (g_pParentWnd->GetZWnd()->m_pZClip)  // should always be the case at this point I think, but this is safer
2850                 {
2851                         if (g_pParentWnd->GetZWnd()->m_pZClip->IsEnabled())
2852                         {
2853                                 qglColor3f(ZCLIP_COLOUR);
2854                                 qglLineWidth(2);
2855                                 qglBegin (GL_LINES);
2856
2857                                 qglVertex2f (xb, g_pParentWnd->GetZWnd()->m_pZClip->GetTop());
2858                                 qglVertex2f (xe, g_pParentWnd->GetZWnd()->m_pZClip->GetTop());
2859
2860                                 qglVertex2f (xb, g_pParentWnd->GetZWnd()->m_pZClip->GetBottom());
2861                                 qglVertex2f (xe, g_pParentWnd->GetZWnd()->m_pZClip->GetBottom());
2862
2863                                 qglEnd ();
2864                                 qglLineWidth(1);
2865                         }
2866                 }               
2867         }
2868
2869         
2870
2871
2872         // draw coordinate text if needed
2873         if (g_qeglobals.d_savedinfo.show_coordinates) {
2874                 // glColor4f(0, 0, 0, 0);
2875                 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT].ToFloatPtr());
2876
2877                 float   lastRaster = xb;
2878
2879                 for (x = xb; x < xe; x += stepSize) {
2880                         qglRasterPos2f(x, m_vOrigin[nDim2] + h - 10 / m_fScale);
2881                         sprintf(text, "%i", (int)x);
2882                         qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
2883                 }
2884
2885                 for (y = yb; y < ye; y += stepSize) {
2886                         qglRasterPos2f(m_vOrigin[nDim1] - w + 1, y);
2887                         sprintf(text, "%i", (int)y);
2888                         qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
2889                 }
2890
2891                 if (Active()) {
2892                         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME].ToFloatPtr());
2893                 }
2894
2895                 qglRasterPos2f(m_vOrigin[nDim1] - w + 35 / m_fScale, m_vOrigin[nDim2] + h - 20 / m_fScale);
2896
2897                 char    cView[20];
2898                 if (m_nViewType == XY) {
2899                         strcpy(cView, "XY Top");
2900                 }
2901                 else if (m_nViewType == XZ) {
2902                         strcpy(cView, "XZ Front");
2903                 }
2904                 else {
2905                         strcpy(cView, "YZ Side");
2906                 }
2907
2908                 qglCallLists(strlen(cView), GL_UNSIGNED_BYTE, cView);
2909         }
2910
2911         /*
2912          * if (true) { qglColor3f(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]);
2913          * qglBegin (GL_LINES); qglVertex2f (x, yb); qglVertex2f (x, ye); qglEnd(); }
2914          */
2915 }
2916
2917 /*
2918  =======================================================================================================================
2919     XY_DrawBlockGrid
2920  =======================================================================================================================
2921  */
2922 void CXYWnd::XY_DrawBlockGrid() {
2923         float   x, y, xb, xe, yb, ye;
2924         int             w, h;
2925         char    text[32];
2926
2927         w = m_nWidth / 2 / m_fScale;
2928         h = m_nHeight / 2 / m_fScale;
2929
2930         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2931         int nDim2 = (m_nViewType == XY) ? 1 : 2;
2932
2933         xb = m_vOrigin[nDim1] - w;
2934         if (xb < region_mins[nDim1]) {
2935                 xb = region_mins[nDim1];
2936         }
2937
2938         xb = 1024 * floor(xb / 1024);
2939
2940         xe = m_vOrigin[nDim1] + w;
2941         if (xe > region_maxs[nDim1]) {
2942                 xe = region_maxs[nDim1];
2943         }
2944
2945         xe = 1024 * ceil(xe / 1024);
2946
2947         yb = m_vOrigin[nDim2] - h;
2948         if (yb < region_mins[nDim2]) {
2949                 yb = region_mins[nDim2];
2950         }
2951
2952         yb = 1024 * floor(yb / 1024);
2953
2954         ye = m_vOrigin[nDim2] + h;
2955         if (ye > region_maxs[nDim2]) {
2956                 ye = region_maxs[nDim2];
2957         }
2958
2959         ye = 1024 * ceil(ye / 1024);
2960
2961         // draw major blocks
2962         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK].ToFloatPtr());
2963         qglLineWidth(0.5);
2964
2965         qglBegin(GL_LINES);
2966
2967         for (x = xb; x <= xe; x += 1024) {
2968                 qglVertex2f(x, yb);
2969                 qglVertex2f(x, ye);
2970         }
2971
2972         for (y = yb; y <= ye; y += 1024) {
2973                 qglVertex2f(xb, y);
2974                 qglVertex2f(xe, y);
2975         }
2976
2977         qglEnd();
2978         qglLineWidth(0.25);
2979
2980         // draw coordinate text if needed
2981         for (x = xb; x < xe; x += 1024) {
2982                 for (y = yb; y < ye; y += 1024) {
2983                         qglRasterPos2f(x + 512, y + 512);
2984                         sprintf(text, "%i,%i", (int)floor(x / 1024), (int)floor(y / 1024));
2985                         qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
2986                 }
2987         }
2988
2989         qglColor4f(0, 0, 0, 0);
2990 }
2991
2992 void GLColoredBoxWithLabel(float x, float y, float size, idVec4 color, const char *text, idVec4 textColor, float xofs, float yofs, float lineSize) {
2993         globalImages->BindNull();       
2994         qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2995         qglDisable(GL_CULL_FACE);
2996         qglDisable(GL_BLEND);
2997         qglColor4f(color[0], color[1], color[2], color[3]);
2998         qglBegin(GL_QUADS);
2999         qglVertex3f(x - size, y - size, 0);
3000         qglVertex3f(x + size, y - size, 0);
3001         qglVertex3f(x + size, y + size, 0);
3002         qglVertex3f(x - size, y + size, 0);
3003         qglEnd();
3004
3005         qglColor4f(textColor[0], textColor[1], textColor[2], textColor[3]);
3006         qglLineWidth(lineSize);
3007         qglRasterPos2f(x + xofs, y + yofs);
3008         qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
3009 }
3010
3011 /*
3012  =======================================================================================================================
3013  =======================================================================================================================
3014  */
3015 void CXYWnd::DrawRotateIcon() {
3016         float   x, y;
3017
3018         if (m_nViewType == XY) {
3019                 x = g_vRotateOrigin[0];
3020                 y = g_vRotateOrigin[1];
3021         }
3022         else if (m_nViewType == YZ) {
3023                 x = g_vRotateOrigin[1];
3024                 y = g_vRotateOrigin[2];
3025         }
3026         else {
3027                 x = g_vRotateOrigin[0];
3028                 y = g_vRotateOrigin[2];
3029         }
3030
3031         qglEnable(GL_BLEND);
3032         globalImages->BindNull();
3033         qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3034         qglDisable(GL_CULL_FACE);
3035         qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3036         qglColor4f( 0.8f, 0.1f, 0.9f, 0.25f );
3037
3038         qglBegin(GL_QUADS);
3039         qglVertex3f(x - 4, y - 4, 0);
3040         qglVertex3f(x + 4, y - 4, 0);
3041         qglVertex3f(x + 4, y + 4, 0);
3042         qglVertex3f(x - 4, y + 4, 0);
3043         qglEnd();
3044         qglDisable(GL_BLEND);
3045
3046         qglColor4f( 1.0f, 0.2f, 1.0f, 1.0f );
3047         qglBegin(GL_POINTS);
3048         qglVertex3f(x, y, 0);
3049         qglEnd();
3050
3051
3052         int w = m_nWidth / 2 / m_fScale;
3053         int h = m_nHeight / 2 / m_fScale;
3054         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
3055         int nDim2 = (m_nViewType == XY) ? 1 : 2;
3056         x = m_vOrigin[nDim1] - w + 35 / m_fScale;
3057         y = m_vOrigin[nDim2] + h - 40 / m_fScale;
3058         const char *p = "Rotate Z Axis";
3059         if (g_qeglobals.rotateAxis == 1) {
3060                 p = "Rotate Y Axis";
3061         } else if (g_qeglobals.rotateAxis == 0) {
3062                 p = "Rotate X Axis";
3063         }
3064         idStr str = p;
3065         if (g_qeglobals.flatRotation) {
3066                 str += g_qeglobals.flatRotation == 2 ? " Flat [center] " : " Flat [ rot origin ] ";
3067         }
3068         qglRasterPos2f(x, y);
3069         qglCallLists(str.Length(), GL_UNSIGNED_BYTE, str.c_str());
3070 }
3071
3072 /*
3073  =======================================================================================================================
3074  =======================================================================================================================
3075  */
3076 void CXYWnd::DrawCameraIcon() {
3077         float   x, y, a;
3078
3079         if (m_nViewType == XY) {
3080                 x = g_pParentWnd->GetCamera()->Camera().origin[0];
3081                 y = g_pParentWnd->GetCamera()->Camera().origin[1];
3082                 a = g_pParentWnd->GetCamera()->Camera().angles[YAW] * idMath::M_DEG2RAD;
3083         }
3084         else if (m_nViewType == YZ) {
3085                 x = g_pParentWnd->GetCamera()->Camera().origin[1];
3086                 y = g_pParentWnd->GetCamera()->Camera().origin[2];
3087                 a = g_pParentWnd->GetCamera()->Camera().angles[PITCH] * idMath::M_DEG2RAD;
3088         }
3089         else {
3090                 x = g_pParentWnd->GetCamera()->Camera().origin[0];
3091                 y = g_pParentWnd->GetCamera()->Camera().origin[2];
3092                 a = g_pParentWnd->GetCamera()->Camera().angles[PITCH] * idMath::M_DEG2RAD;
3093         }
3094
3095         float scale = 1.0/m_fScale;     //jhefty - keep the camera icon proportionally the same size 
3096
3097         qglColor3f(0.0, 0.0, 1.0);
3098         qglBegin(GL_LINE_STRIP);
3099         qglVertex3f(x - 16*scale, y, 0);
3100         qglVertex3f(x, y + 8*scale, 0);
3101         qglVertex3f(x + 16*scale, y, 0);
3102         qglVertex3f(x, y - 8*scale, 0);
3103         qglVertex3f(x - 16*scale, y, 0);
3104         qglVertex3f(x + 16*scale, y, 0);
3105         qglEnd();
3106
3107         qglBegin(GL_LINE_STRIP);
3108         qglVertex3f(x + (48 * cos( a + idMath::PI * 0.25f )*scale), y + (48 * sin( a + idMath::PI * 0.25f )*scale), 0);
3109         qglVertex3f(x, y, 0);
3110         qglVertex3f(x + (48 * cos( a - idMath::PI * 0.25f )*scale), y + (48 * sin( a - idMath::PI * 0.25f )*scale), 0);
3111         qglEnd();
3112
3113 #if 0
3114
3115         char    text[128];
3116         qglRasterPos2f(x + 64, y + 64);
3117         sprintf(text, "%f", g_pParentWnd->GetCamera()->Camera().angles[YAW]);
3118         qglCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
3119 #endif
3120 }
3121
3122 /*
3123  =======================================================================================================================
3124  =======================================================================================================================
3125  */
3126 void CXYWnd::DrawZIcon(void) {
3127         if (m_nViewType == XY) {
3128                 float   x = z.origin[0];
3129                 float   y = z.origin[1];
3130                 qglEnable(GL_BLEND);
3131                 globalImages->BindNull();
3132                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3133                 qglDisable(GL_CULL_FACE);
3134                 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3135                 qglColor4f(0.0, 0.0, 1.0, 0.25);
3136                 qglBegin(GL_QUADS);
3137                 qglVertex3f(x - 8, y - 8, 0);
3138                 qglVertex3f(x + 8, y - 8, 0);
3139                 qglVertex3f(x + 8, y + 8, 0);
3140                 qglVertex3f(x - 8, y + 8, 0);
3141                 qglEnd();
3142                 qglDisable(GL_BLEND);
3143
3144                 qglColor4f(0.0, 0.0, 1.0, 1);
3145
3146                 qglBegin(GL_LINE_LOOP);
3147                 qglVertex3f(x - 8, y - 8, 0);
3148                 qglVertex3f(x + 8, y - 8, 0);
3149                 qglVertex3f(x + 8, y + 8, 0);
3150                 qglVertex3f(x - 8, y + 8, 0);
3151                 qglEnd();
3152
3153                 qglBegin(GL_LINE_STRIP);
3154                 qglVertex3f(x - 4, y + 4, 0);
3155                 qglVertex3f(x + 4, y + 4, 0);
3156                 qglVertex3f(x - 4, y - 4, 0);
3157                 qglVertex3f(x + 4, y - 4, 0);
3158                 qglEnd();
3159         }
3160 }
3161
3162 /*
3163  =======================================================================================================================
3164     FilterBrush
3165  =======================================================================================================================
3166  */
3167 bool FilterBrush(brush_t *pb) {
3168         
3169         if (!pb->owner) {
3170                 return false;   // during construction
3171         }
3172
3173         if (pb->hiddenBrush) {
3174                 return true;
3175         }
3176
3177         if ( pb->forceVisibile ) {
3178                 return false;
3179         }
3180
3181         if (g_pParentWnd->GetZWnd()->m_pZClip)  // ZClip class up and running? (and hence Z window built)
3182         {
3183                 if (g_pParentWnd->GetZWnd()->m_pZClip->IsEnabled())
3184                 {
3185                         // ZClipping active...
3186                         //
3187                         if (pb->mins[2] > g_pParentWnd->GetZWnd()->m_pZClip->GetTop()   // brush bottom edge is above clip top
3188                                 ||
3189                                 pb->maxs[2] < g_pParentWnd->GetZWnd()->m_pZClip->GetBottom()// brush top edge is below clip bottom 
3190                                 )
3191                         {
3192                                 return TRUE;
3193                         }
3194                 }
3195         }
3196
3197         if (g_qeglobals.d_savedinfo.exclude & (EXCLUDE_CAULK | EXCLUDE_VISPORTALS)) {
3198                 //
3199                 // filter out the brush only if all faces are caulk if not don't hide the whole
3200                 // brush, proceed on a per-face basis (Cam_Draw) ++timo TODO: set this as a
3201                 // preference .. show caulk: hide any brush with caulk // don't draw caulk faces
3202                 //
3203                 face_t  *f;
3204                 f = pb->brush_faces;
3205                 while (f) {
3206                         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
3207                                 if (!strstr(f->texdef.name, "caulk")) {
3208                                         break;
3209                                 }
3210                         } else {
3211                                 if (strstr(f->texdef.name, "visportal")) {
3212                                         return true;
3213                                 }
3214                         }
3215
3216                         f = f->next;
3217                 }
3218
3219                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
3220                         if (!f) {
3221                                 return true;
3222                         }
3223                 }
3224
3225                 // ++timo FIXME: .. same deal here?
3226                 if (strstr(pb->brush_faces->texdef.name, "donotenter")) {
3227                         return true;
3228                 }
3229         }
3230
3231         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_HINT) {
3232                 if (strstr(pb->brush_faces->texdef.name, "hint")) {
3233                         return true;
3234                 }
3235         }
3236
3237         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) {
3238                 if (strstr(pb->brush_faces->texdef.name, "clip")) {
3239                         return true;
3240                 }
3241         }
3242
3243         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_TRIGGERS) {
3244                 if (strstr(pb->brush_faces->texdef.name, "trig")) {
3245                         return true;
3246                 }
3247         }
3248
3249         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_NODRAW) {
3250                 if (strstr(pb->brush_faces->texdef.name, "nodraw")) {
3251                         return true;
3252                 }
3253         }
3254
3255
3256         if (strstr(pb->brush_faces->texdef.name, "skip")) {
3257                 return true;
3258         }
3259
3260         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DYNAMICS) {
3261                 if (pb->modelHandle > 0) {
3262                         idRenderModel *model = pb->modelHandle;
3263                         if ( dynamic_cast<idRenderModelLiquid*>(model) ) {
3264                                 return true;                    
3265                         }
3266                 }
3267         }
3268
3269         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CURVES) {
3270                 if (pb->pPatch) {
3271                         return true;
3272                 }
3273         }
3274
3275         if (pb->owner == world_entity) {
3276                 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) {
3277                         return true;
3278                 }
3279
3280                 return false;
3281         }
3282         else {
3283                 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT ) {
3284                         return ( idStr::Cmpn( pb->owner->eclass->name, "func_static", 10 ) != 0 );
3285                 }
3286         }
3287
3288         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS && pb->owner->eclass->nShowFlags & ECLASS_LIGHT ) {
3289                 return true;
3290         }
3291
3292         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_COMBATNODES && pb->owner->eclass->nShowFlags & ECLASS_COMBATNODE ) {
3293                 return true;
3294         }
3295
3296         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS && pb->owner->eclass->nShowFlags & ECLASS_PATH) {
3297                 return true;
3298         }
3299
3300         if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_MODELS && ( pb->owner->eclass->entityModel != NULL || pb->modelHandle > 0 ) ) {
3301                 return true;
3302         }
3303
3304         return false;
3305 }
3306
3307 /*
3308  =======================================================================================================================
3309     PATH LINES Â£
3310     DrawPathLines Draws connections between entities. Needs to consider all entities, not just ones on screen, because
3311     the lines can be visible when neither end is. Called for both camera view and xy view.
3312  =======================================================================================================================
3313  */
3314 void DrawPathLines(void) {
3315         int                     i, k;
3316         idVec3          mid, mid1;
3317         entity_t        *se, *te;
3318         brush_t         *sb, *tb;
3319         const char              *psz;
3320         idVec3          dir, s1, s2;
3321         float           len, f;
3322         int                     arrows;
3323         int                     num_entities;
3324         const char              *ent_target[MAX_MAP_ENTITIES];
3325         entity_t        *ent_entity[MAX_MAP_ENTITIES];
3326
3327         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) {
3328                 return;
3329         }
3330
3331         num_entities = 0;
3332         for (te = entities.next; te != &entities && num_entities != MAX_MAP_ENTITIES; te = te->next) {
3333                 for (int i = 0; i < 2048; i++) {
3334                         if (i == 0) {
3335                                 ent_target[num_entities] = ValueForKey(te, "target");
3336                         } else {
3337                                 ent_target[num_entities] = ValueForKey(te, va("target%i", i));
3338                         }
3339                         if (ent_target[num_entities][0]) {
3340                                 ent_entity[num_entities] = te;
3341                                 num_entities++;
3342                         } else if (i > 16) {
3343                                 break;
3344                         }
3345                 }
3346         }
3347
3348         for (se = entities.next; se != &entities; se = se->next) {
3349                 psz = ValueForKey(se, "name");
3350
3351                 if (psz == NULL || psz[0] == '\0') {
3352                         continue;
3353                 }
3354
3355                 sb = se->brushes.onext;
3356                 if (sb == &se->brushes) {
3357                         continue;
3358                 }
3359
3360                 for (k = 0; k < num_entities; k++) {
3361                         if (strcmp(ent_target[k], psz)) {
3362                                 continue;
3363                         }
3364
3365                         te = ent_entity[k];
3366                         tb = te->brushes.onext;
3367                         if (tb == &te->brushes) {
3368                                 continue;
3369                         }
3370
3371                         mid = sb->owner->origin;
3372                         mid1 = tb->owner->origin;
3373
3374                         VectorSubtract(mid1, mid, dir);
3375                         len = dir.Normalize();
3376                         s1[0] = -dir[1] * 8 + dir[0] * 8;
3377                         s2[0] = dir[1] * 8 + dir[0] * 8;
3378                         s1[1] = dir[0] * 8 + dir[1] * 8;
3379                         s2[1] = -dir[0] * 8 + dir[1] * 8;
3380
3381                         qglColor3f(se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);
3382
3383                         qglBegin(GL_LINES);
3384                         qglVertex3fv(mid.ToFloatPtr());
3385                         qglVertex3fv(mid1.ToFloatPtr());
3386
3387                         arrows = (int)(len / 256) + 1;
3388
3389                         for (i = 0; i < arrows; i++) {
3390                                 f = len * (i + 0.5) / arrows;
3391
3392                                 mid1 = mid + (f * dir);
3393
3394                                 qglVertex3fv(mid1.ToFloatPtr());
3395                                 qglVertex3f(mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
3396                                 qglVertex3fv(mid1.ToFloatPtr());
3397                                 qglVertex3f(mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
3398                         }
3399
3400                         qglEnd();
3401                 }
3402         }
3403
3404         return;
3405 }
3406
3407 //
3408 // =======================================================================================================================
3409 //    can be greatly simplified but per usual i am in a hurry which is not an excuse, just a fact
3410 // =======================================================================================================================
3411 //
3412 void CXYWnd::PaintSizeInfo(int nDim1, int nDim2, idVec3 vMinBounds, idVec3 vMaxBounds) {
3413         idVec3  vSize;
3414         VectorSubtract(vMaxBounds, vMinBounds, vSize);
3415
3416         qglColor3f
3417         (
3418                 g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] * .65,
3419                 g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] * .65,
3420                 g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] * .65
3421         );
3422
3423         if (m_nViewType == XY) {
3424                 qglBegin(GL_LINES);
3425
3426                 qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f);
3427                 qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3428
3429                 qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3430                 qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3431
3432                 qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f);
3433                 qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
3434
3435                 qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2], 0.0f);
3436                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f);
3437
3438                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f);
3439                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
3440
3441                 qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
3442                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f);
3443
3444                 qglEnd();
3445
3446                 qglRasterPos3f(Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale, 0.0f);
3447                 g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
3448                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3449
3450                 qglRasterPos3f(vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]), 0.0f);
3451                 g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
3452                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3453
3454                 qglRasterPos3f(vMinBounds[nDim1] + 4, vMaxBounds[nDim2] + 8 / m_fScale, 0.0f);
3455                 g_strDim.Format(g_pOrgStrings[0], vMinBounds[nDim1], vMaxBounds[nDim2]);
3456                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3457         }
3458         else if (m_nViewType == XZ) {
3459                 qglBegin(GL_LINES);
3460
3461                 qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale);
3462                 qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3463
3464                 qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3465                 qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3466
3467                 qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale);
3468                 qglVertex3f(vMaxBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
3469
3470                 qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0, vMinBounds[nDim2]);
3471                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMinBounds[nDim2]);
3472
3473                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMinBounds[nDim2]);
3474                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMaxBounds[nDim2]);
3475
3476                 qglVertex3f(vMaxBounds[nDim1] + 6.0f / m_fScale, 0, vMaxBounds[nDim2]);
3477                 qglVertex3f(vMaxBounds[nDim1] + 10.0f / m_fScale, 0, vMaxBounds[nDim2]);
3478
3479                 qglEnd();
3480
3481                 qglRasterPos3f(Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), 0, vMinBounds[nDim2] - 20.0 / m_fScale);
3482                 g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
3483                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3484
3485                 qglRasterPos3f(vMaxBounds[nDim1] + 16.0 / m_fScale, 0, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
3486                 g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
3487                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3488
3489                 qglRasterPos3f(vMinBounds[nDim1] + 4, 0, vMaxBounds[nDim2] + 8 / m_fScale);
3490                 g_strDim.Format(g_pOrgStrings[1], vMinBounds[nDim1], vMaxBounds[nDim2]);
3491                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3492         }
3493         else {
3494                 qglBegin(GL_LINES);
3495
3496                 qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale);
3497                 qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3498
3499                 qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3500                 qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3501
3502                 qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale);
3503                 qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
3504
3505                 qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2]);
3506                 qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]);
3507
3508                 qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2]);
3509                 qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]);
3510
3511                 qglVertex3f(0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2]);
3512                 qglVertex3f(0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2]);
3513
3514                 qglEnd();
3515
3516                 qglRasterPos3f(0, Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), vMinBounds[nDim2] - 20.0 / m_fScale);
3517                 g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
3518                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3519
3520                 qglRasterPos3f(0, vMaxBounds[nDim1] + 16.0 / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
3521                 g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
3522                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3523
3524                 qglRasterPos3f(0, vMinBounds[nDim1] + 4.0, vMaxBounds[nDim2] + 8 / m_fScale);
3525                 g_strDim.Format(g_pOrgStrings[2], vMinBounds[nDim1], vMaxBounds[nDim2]);
3526                 qglCallLists(g_strDim.GetLength(), GL_UNSIGNED_BYTE, g_strDim);
3527         }
3528 }
3529
3530 /* XY_Draw */
3531 long            g_lCount = 0;
3532 long            g_lTotal = 0;
3533 extern void DrawBrushEntityName(brush_t *b);
3534
3535 /*
3536  =======================================================================================================================
3537  =======================================================================================================================
3538  */
3539 void CXYWnd::XY_Draw() {
3540         brush_t         *brush;
3541         float           w, h;
3542         entity_t        *e;
3543         idVec3          mins, maxs;
3544         int                     drawn, culled;
3545         int                     i;
3546
3547         if (!active_brushes.next) {
3548                 return; // not valid yet
3549         }
3550
3551         // clear
3552         m_bDirty = false;
3553
3554         GL_State( GLS_DEFAULT );
3555         qglViewport(0, 0, m_nWidth, m_nHeight);
3556         qglScissor(0, 0, m_nWidth, m_nHeight);
3557         qglClearColor
3558         (
3559                 g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
3560                 g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
3561                 g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
3562                 0
3563         );
3564
3565         qglDisable(GL_DEPTH_TEST);
3566         qglDisable(GL_CULL_FACE);
3567         qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
3568
3569         // set up viewpoint
3570         qglMatrixMode(GL_PROJECTION);
3571         qglLoadIdentity();
3572
3573         w = m_nWidth / 2 / m_fScale;
3574         h = m_nHeight / 2 / m_fScale;
3575
3576         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
3577         int nDim2 = (m_nViewType == XY) ? 1 : 2;
3578         mins[0] = m_vOrigin[nDim1] - w;
3579         maxs[0] = m_vOrigin[nDim1] + w;
3580         mins[1] = m_vOrigin[nDim2] - h;
3581         maxs[1] = m_vOrigin[nDim2] + h;
3582
3583         idBounds viewBounds( mins, maxs );
3584         viewBounds[0].z = -99999;
3585         viewBounds[1].z = 99999;
3586
3587         qglOrtho(mins[0], maxs[0], mins[1], maxs[1], MIN_WORLD_COORD, MAX_WORLD_COORD);
3588
3589         // draw stuff
3590         globalImages->BindNull();
3591         // now draw the grid
3592         qglLineWidth(0.25);
3593         XY_DrawGrid();
3594         qglLineWidth(0.5);
3595
3596         drawn = culled = 0;
3597
3598         if (m_nViewType != XY) {
3599                 qglPushMatrix();
3600                 if (m_nViewType == YZ) {
3601                         qglRotatef(-90, 0, 1, 0);       // put Z going up
3602                 }
3603
3604                 // else
3605                 qglRotatef(-90, 1, 0, 0);               // put Z going up
3606         }
3607
3608         e = world_entity;
3609
3610         for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) {
3611                 if ( brush->forceVisibile || ( brush->owner->eclass->nShowFlags & ( ECLASS_LIGHT | ECLASS_PROJECTEDLIGHT ) ) ) {
3612                 } else if (     brush->mins[nDim1] > maxs[0] || brush->mins[nDim2] > maxs[1] || brush->maxs[nDim1] < mins[0] || brush->maxs[nDim2] < mins[1] ) {
3613                         culled++;
3614                         continue;                               // off screen
3615                 }
3616
3617                 if ( FilterBrush(brush) ) {
3618                         continue;
3619                 }
3620
3621                 drawn++;
3622
3623                 if (brush->owner != e && brush->owner) {
3624                         qglColor3fv(brush->owner->eclass->color.ToFloatPtr());
3625                 }
3626                 else {
3627                         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES].ToFloatPtr());
3628                 }
3629
3630                 Brush_DrawXY( brush, m_nViewType );
3631         }
3632
3633         DrawPathLines();
3634
3635         // draw pointfile
3636         if (g_qeglobals.d_pointfile_display_list) {
3637                 qglCallList(g_qeglobals.d_pointfile_display_list);
3638         }
3639
3640         if (!(m_nViewType == XY)) {
3641                 qglPopMatrix();
3642         }
3643
3644         // draw block grid
3645         if (g_qeglobals.show_blocks) {
3646                 XY_DrawBlockGrid();
3647         }
3648
3649         // now draw selected brushes
3650         if (m_nViewType != XY) {
3651                 qglPushMatrix();
3652                 if (m_nViewType == YZ) {
3653                         qglRotatef(-90, 0, 1, 0);       // put Z going up
3654                 }
3655
3656                 // else
3657                 qglRotatef(-90, 1, 0, 0);               // put Z going up
3658         }
3659
3660         qglPushMatrix();
3661         qglTranslatef
3662         (
3663                 g_qeglobals.d_select_translate[0],
3664                 g_qeglobals.d_select_translate[1],
3665                 g_qeglobals.d_select_translate[2]
3666         );
3667
3668         if (RotateMode()) {
3669                 qglColor3f( 0.8f, 0.1f, 0.9f );
3670         }
3671         else if (ScaleMode()) {
3672                 qglColor3f( 0.1f, 0.8f, 0.1f );
3673         }
3674         else {
3675                 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr());
3676         }
3677
3678         if (g_PrefsDlg.m_bNoStipple == FALSE) {
3679                 qglEnable(GL_LINE_STIPPLE);
3680                 qglLineStipple(3, 0xaaaa);
3681         }
3682
3683         qglLineWidth(1);
3684
3685         idVec3  vMinBounds;
3686         idVec3  vMaxBounds;
3687         vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = 999999.9f;
3688         vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = -999999.9f;
3689
3690         int             nSaveDrawn = drawn;
3691         bool    bFixedSize = false;
3692         for (brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next) {
3693                 drawn++;
3694                 Brush_DrawXY(brush, m_nViewType, true);
3695
3696                 if (!bFixedSize) {
3697                         if (brush->owner->eclass->fixedsize) {
3698                                 bFixedSize = true;
3699                         }
3700
3701                         if (g_PrefsDlg.m_bSizePaint) {
3702                                 for (i = 0; i < 3; i++) {
3703                                         if (brush->mins[i] < vMinBounds[i]) {
3704                                                 vMinBounds[i] = brush->mins[i];
3705                                         }
3706
3707                                         if (brush->maxs[i] > vMaxBounds[i]) {
3708                                                 vMaxBounds[i] = brush->maxs[i];
3709                                         }
3710                                 }
3711                         }
3712                 }
3713         }
3714
3715         if (g_PrefsDlg.m_bNoStipple == FALSE) {
3716                 qglDisable(GL_LINE_STIPPLE);
3717         }
3718
3719         qglLineWidth(0.5);
3720
3721         if (!bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint) {
3722                 PaintSizeInfo(nDim1, nDim2, vMinBounds, vMaxBounds);
3723         }
3724
3725         // edge / vertex flags
3726         if (g_qeglobals.d_select_mode == sel_vertex) {
3727                 qglPointSize(4);
3728                 qglColor3f(0, 1, 0);
3729                 qglBegin(GL_POINTS);
3730                 for (i = 0; i < g_qeglobals.d_numpoints; i++) {
3731                         qglVertex3fv(g_qeglobals.d_points[i].ToFloatPtr());
3732                 }
3733
3734                 qglEnd();
3735                 qglPointSize(1);
3736         }
3737         else if (g_qeglobals.d_select_mode == sel_edge) {
3738                 float   *v1, *v2;
3739
3740                 qglPointSize(4);
3741                 qglColor3f(0, 0, 1);
3742                 qglBegin(GL_POINTS);
3743                 for (i = 0; i < g_qeglobals.d_numedges; i++) {
3744                         v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1].ToFloatPtr();
3745                         v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2].ToFloatPtr();
3746                         qglVertex3f((v1[0] + v2[0]) * 0.5, (v1[1] + v2[1]) * 0.5, (v1[2] + v2[2]) * 0.5);
3747                 }
3748
3749                 qglEnd();
3750                 qglPointSize(1);
3751         }
3752
3753         g_splineList->draw (static_cast<bool>(g_qeglobals.d_select_mode == sel_editpoint || g_qeglobals.d_select_mode == sel_addpoint));
3754
3755         if (g_pParentWnd->GetNurbMode() && g_pParentWnd->GetNurb()->GetNumValues()) {
3756                 int maxage = g_pParentWnd->GetNurb()->GetNumValues();
3757                 int time = 0;
3758                 qglColor3f(0, 0, 1);
3759                 qglPointSize(1);
3760                 qglBegin(GL_POINTS);
3761                 g_pParentWnd->GetNurb()->SetOrder(3);
3762                 for (i = 0; i < 100; i++) {
3763                         idVec2 v = g_pParentWnd->GetNurb()->GetCurrentValue(time);
3764                         qglVertex3f(v.x, v.y, 0.0f);
3765                         time += 10;
3766                 }
3767                 qglEnd();
3768                 qglPointSize(4);
3769                 qglColor3f(0, 0, 1);
3770                 qglBegin(GL_POINTS);
3771                 for (i = 0; i < maxage; i++) {
3772                         idVec2 v = g_pParentWnd->GetNurb()->GetValue(i);
3773                         qglVertex3f(v.x, v.y, 0.0f);
3774                 }
3775                 qglEnd();
3776                 qglPointSize(1);
3777         }
3778
3779         qglPopMatrix();
3780
3781         qglTranslatef
3782         (
3783                 -g_qeglobals.d_select_translate[0],
3784                 -g_qeglobals.d_select_translate[1],
3785                 -g_qeglobals.d_select_translate[2]
3786         );
3787
3788         if (!(m_nViewType == XY)) {
3789                 qglPopMatrix();
3790         }
3791
3792         // area selection hack
3793         if (g_qeglobals.d_select_mode == sel_area) {
3794                 qglEnable(GL_BLEND);
3795         qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL );
3796                 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3797                 qglColor4f(0.0, 0.0, 1.0, 0.25);
3798                 qglRectf
3799                 (
3800                         g_qeglobals.d_vAreaTL[nDim1],
3801                         g_qeglobals.d_vAreaTL[nDim2],
3802                         g_qeglobals.d_vAreaBR[nDim1],
3803                         g_qeglobals.d_vAreaBR[nDim2]
3804                 );
3805                 qglDisable(GL_BLEND);
3806         qglPolygonMode ( GL_FRONT_AND_BACK , GL_LINE );
3807                 qglColor3f(1.0f, 1.0f, 1.0f);
3808                 qglRectf
3809                 (
3810                         g_qeglobals.d_vAreaTL[nDim1],
3811                         g_qeglobals.d_vAreaTL[nDim2],
3812                         g_qeglobals.d_vAreaBR[nDim1],
3813                         g_qeglobals.d_vAreaBR[nDim2]
3814                 );
3815
3816         }
3817
3818         // now draw camera point
3819         DrawCameraIcon();
3820         DrawZIcon();
3821
3822         if (RotateMode()) {
3823                 DrawRotateIcon();
3824         }
3825
3826         /// Draw a "precision crosshair" if enabled 
3827         if( m_precisionCrosshairMode != PRECISION_CROSSHAIR_NONE )
3828                 DrawPrecisionCrosshair();
3829
3830         qglFlush();
3831
3832         // QE_CheckOpenGLForErrors();
3833 }
3834
3835
3836 /*
3837  =======================================================================================================================
3838  =======================================================================================================================
3839  */
3840 idVec3 &CXYWnd::GetOrigin() {
3841         return m_vOrigin;
3842 }
3843
3844 /*
3845  =======================================================================================================================
3846  =======================================================================================================================
3847  */
3848 void CXYWnd::SetOrigin(idVec3 org) {
3849         m_vOrigin[0] = org[0];
3850         m_vOrigin[1] = org[1];
3851         m_vOrigin[2] = org[2];
3852 }
3853
3854 /*
3855  =======================================================================================================================
3856  =======================================================================================================================
3857  */
3858 void CXYWnd::OnSize(UINT nType, int cx, int cy) {
3859         CWnd::OnSize(nType, cx, cy);
3860
3861         CRect   rect;
3862         GetClientRect(rect);
3863         m_nWidth = rect.Width();
3864         m_nHeight = rect.Height();
3865         InvalidateRect(NULL, false);
3866 }
3867
3868 brush_t hold_brushes;
3869
3870 /*
3871  =======================================================================================================================
3872  =======================================================================================================================
3873  */
3874 void CXYWnd::Clip() {
3875         if (ClipMode()) {
3876                 hold_brushes.next = &hold_brushes;
3877                 ProduceSplitLists();
3878
3879                 // brush_t* pList = (g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
3880                 brush_t *pList;
3881                 if (g_PrefsDlg.m_bSwitchClip) {
3882                         pList = ((m_nViewType == XZ) ? g_bSwitch : !g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
3883                 }
3884                 else {
3885                         pList = ((m_nViewType == XZ) ? !g_bSwitch : g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
3886                 }
3887
3888                 if (pList->next != pList) {
3889                         Brush_CopyList(pList, &hold_brushes);
3890                         CleanList(&g_brFrontSplits);
3891                         CleanList(&g_brBackSplits);
3892                         Select_Delete();
3893                         Brush_CopyList(&hold_brushes, &selected_brushes);
3894                         if (RogueClipMode()) {
3895                                 RetainClipMode(false);
3896                         }
3897                         else {
3898                                 RetainClipMode(true);
3899                         }
3900
3901                         Sys_UpdateWindows(W_ALL);
3902                 }
3903         }
3904         else if (PathMode()) {
3905                 FinishSmartCreation();
3906                 if (g_pPathFunc) {
3907                         g_pPathFunc(true, g_nPathCount);
3908                 }
3909
3910                 g_pPathFunc = NULL;
3911                 g_nPathCount = 0;
3912                 g_bPathMode = false;
3913         }
3914 }
3915
3916 /*
3917  =======================================================================================================================
3918  =======================================================================================================================
3919  */
3920 void CXYWnd::SplitClip() {
3921         ProduceSplitLists();
3922         if ((g_brFrontSplits.next != &g_brFrontSplits) && (g_brBackSplits.next != &g_brBackSplits)) {
3923                 Select_Delete();
3924                 Brush_CopyList(&g_brFrontSplits, &selected_brushes);
3925                 Brush_CopyList(&g_brBackSplits, &selected_brushes);
3926                 CleanList(&g_brFrontSplits);
3927                 CleanList(&g_brBackSplits);
3928                 if (RogueClipMode()) {
3929                         RetainClipMode(false);
3930                 }
3931                 else {
3932                         RetainClipMode(true);
3933                 }
3934         }
3935 }
3936
3937 /*
3938  =======================================================================================================================
3939  =======================================================================================================================
3940  */
3941 void CXYWnd::FlipClip() {
3942         g_bSwitch = !g_bSwitch;
3943         Sys_UpdateWindows(XY | W_CAMERA_IFON);
3944 }
3945
3946 //
3947 // =======================================================================================================================
3948 //    makes sure the selected brush or camera is in view
3949 // =======================================================================================================================
3950 //
3951 void CXYWnd::PositionView() {
3952         int             nDim1 = (m_nViewType == YZ) ? 1 : 0;
3953         int             nDim2 = (m_nViewType == XY) ? 1 : 2;
3954         brush_t *b = selected_brushes.next;
3955         if (b && b->next != b) {
3956                 m_vOrigin[nDim1] = b->mins[nDim1];
3957                 m_vOrigin[nDim2] = b->mins[nDim2];
3958         }
3959         else {
3960                 m_vOrigin[nDim1] = g_pParentWnd->GetCamera()->Camera().origin[nDim1];
3961                 m_vOrigin[nDim2] = g_pParentWnd->GetCamera()->Camera().origin[nDim2];
3962         }
3963 }
3964
3965 /*
3966  =======================================================================================================================
3967  =======================================================================================================================
3968  */
3969 void CXYWnd::VectorCopyXY(const idVec3 &in, idVec3 &out) {
3970         if (m_nViewType == XY) {
3971                 out[0] = in[0];
3972                 out[1] = in[1];
3973         }
3974         else if (m_nViewType == XZ) {
3975                 out[0] = in[0];
3976                 out[2] = in[2];
3977         }
3978         else {
3979                 out[1] = in[1];
3980                 out[2] = in[2];
3981         }
3982 }
3983
3984 /*
3985  =======================================================================================================================
3986  =======================================================================================================================
3987  */
3988 void CXYWnd::OnDestroy() {
3989         CWnd::OnDestroy();
3990
3991         // delete this;
3992 }
3993
3994 /*
3995  =======================================================================================================================
3996  =======================================================================================================================
3997  */
3998 void CXYWnd::SetViewType(int n) {
3999         m_nViewType = n;
4000         char *p = "YZ Side";
4001         if (m_nViewType == XY) {
4002                 p = "XY Top";
4003         } else if (m_nViewType == XZ) {
4004                 p = "XZ Front";
4005         }
4006         SetWindowText(p);
4007 };
4008
4009 /*
4010  =======================================================================================================================
4011  =======================================================================================================================
4012  */
4013 void CXYWnd::Redraw(unsigned int nBits) {
4014         m_nUpdateBits = nBits;
4015         RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
4016         m_nUpdateBits = W_XY;
4017 }
4018
4019 /*
4020  =======================================================================================================================
4021  =======================================================================================================================
4022  */
4023 bool CXYWnd::RotateMode() {
4024         return g_bRotateMode;
4025 }
4026
4027 /*
4028  =======================================================================================================================
4029  =======================================================================================================================
4030  */
4031 bool CXYWnd::ScaleMode() {
4032         return g_bScaleMode;
4033 }
4034
4035 /*
4036  =======================================================================================================================
4037  =======================================================================================================================
4038  */
4039 extern bool Select_OnlyModelsSelected();
4040 bool CXYWnd::SetRotateMode(bool bMode) {
4041         if (bMode && selected_brushes.next != &selected_brushes) {
4042                 g_bRotateMode = true;
4043                 if (Select_OnlyModelsSelected()) {
4044                         Select_GetTrueMid(g_vRotateOrigin);
4045                 } else {
4046                         Select_GetMid(g_vRotateOrigin);
4047                 }
4048                 g_vRotation.Zero();
4049                 Select_InitializeRotation();
4050         }
4051         else {
4052                 if (bMode) {
4053                         Sys_Status("Need a brush selected to turn on Mouse Rotation mode\n");
4054                 }
4055
4056                 g_bRotateMode = false;
4057                 Select_FinalizeRotation();
4058         }
4059
4060         RedrawWindow();
4061         return g_bRotateMode;
4062 }
4063
4064 /*
4065  =======================================================================================================================
4066  =======================================================================================================================
4067  */
4068 void CXYWnd::SetScaleMode(bool bMode) {
4069         g_bScaleMode = bMode;
4070         RedrawWindow();
4071 }
4072
4073 //
4074 // =======================================================================================================================
4075 //    xy - z xz - y yz - x
4076 // =======================================================================================================================
4077 //
4078 void CXYWnd::OnSelectMouserotate() {
4079         // TODO: Add your command handler code here
4080 }
4081
4082 /*
4083  =======================================================================================================================
4084  =======================================================================================================================
4085  */
4086 void CleanCopyEntities() {
4087         entity_t        *pe = g_enClipboard.next;
4088         while (pe != NULL && pe != &g_enClipboard) {
4089                 entity_t        *next = pe->next;
4090                 pe->epairs.Clear();
4091
4092                 Entity_Free(pe);
4093                 pe = next;
4094         }
4095
4096         g_enClipboard.next = g_enClipboard.prev = &g_enClipboard;
4097 }
4098
4099 /*
4100  =======================================================================================================================
4101  =======================================================================================================================
4102  */
4103 entity_t *Entity_CopyClone(entity_t *e) {
4104         entity_t        *n;
4105
4106         n = Entity_New();
4107         n->brushes.onext = n->brushes.oprev = &n->brushes;
4108         n->eclass = e->eclass;
4109         n->rotation = e->rotation;
4110
4111         // add the entity to the entity list
4112         n->next = g_enClipboard.next;
4113         g_enClipboard.next = n;
4114         n->next->prev = n;
4115         n->prev = &g_enClipboard;
4116
4117         n->epairs = e->epairs;
4118
4119         return n;
4120 }
4121
4122 /*
4123  =======================================================================================================================
4124  =======================================================================================================================
4125  */
4126 bool OnList(entity_t *pFind, CPtrArray *pList) {
4127         int nSize = pList->GetSize();
4128         while (nSize-- > 0) {
4129                 entity_t        *pEntity = reinterpret_cast < entity_t * > (pList->GetAt(nSize));
4130                 if (pEntity == pFind) {
4131                         return true;
4132                 }
4133         }
4134
4135         return false;
4136 }
4137
4138 /*
4139  =======================================================================================================================
4140  =======================================================================================================================
4141  */
4142 void CXYWnd::Copy()
4143 {
4144 #if 1
4145         CWaitCursor WaitCursor;
4146         g_Clipboard.SetLength(0);
4147         g_PatchClipboard.SetLength(0);
4148
4149         Map_SaveSelected(&g_Clipboard, &g_PatchClipboard);
4150
4151         bool    bClipped = false;
4152         UINT    nClipboard = ::RegisterClipboardFormat("RadiantClippings");
4153         if (nClipboard > 0) {
4154                 if (OpenClipboard()) {
4155                         ::EmptyClipboard();
4156
4157                         long    lSize = g_Clipboard.GetLength();
4158                         HANDLE  h = ::GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, lSize + sizeof (long));
4159                         if (h != NULL) {
4160                                 unsigned char   *cp = reinterpret_cast < unsigned char * > (::GlobalLock(h));
4161                                 memcpy(cp, &lSize, sizeof (long));
4162                                 cp += sizeof (long);
4163                                 g_Clipboard.SeekToBegin();
4164                                 g_Clipboard.Read(cp, lSize);
4165                                 ::GlobalUnlock(h);
4166                                 ::SetClipboardData(nClipboard, h);
4167                                 ::CloseClipboard();
4168                                 bClipped = true;
4169                         }
4170                 }
4171         }
4172
4173         if (!bClipped) {
4174                 common->Printf("Unable to register Windows clipboard formats, copy/paste between editors will not be possible");
4175         }
4176
4177         /*
4178          * CString strOut; ::GetTempPath(1024, strOut.GetBuffer(1024));
4179          * strOut.ReleaseBuffer(); AddSlash(strOut); strOut += "RadiantClipboard.$$$";
4180          * Map_SaveSelected(strOut.GetBuffer(0));
4181          */
4182 #else
4183         CPtrArray       holdArray;
4184         CleanList(&g_brClipboard);
4185         CleanCopyEntities();
4186         for (brush_t * pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) {
4187                 if (pBrush->owner == world_entity) {
4188                         brush_t *pClone = Brush_Clone(pBrush);
4189                         pClone->owner = NULL;
4190                         Brush_AddToList(pClone, &g_brClipboard);
4191                 }
4192                 else {
4193                         if (!OnList(pBrush->owner, &holdArray)) {
4194                                 entity_t        *e = pBrush->owner;
4195                                 holdArray.Add(reinterpret_cast < void * > (e));
4196
4197                                 entity_t        *pEClone = Entity_CopyClone(e);
4198                                 for (brush_t * pEB = e->brushes.onext; pEB != &e->brushes; pEB = pEB->onext) {
4199                                         brush_t *pClone = Brush_Clone(pEB);
4200
4201                                         // Brush_AddToList (pClone, &g_brClipboard);
4202                                         Entity_LinkBrush(pEClone, pClone);
4203                                         Brush_Build(pClone);
4204                                 }
4205                         }
4206                 }
4207         }
4208 #endif
4209 }
4210
4211 /*
4212  =======================================================================================================================
4213  =======================================================================================================================
4214  */
4215 void CXYWnd::Undo() {
4216         /*
4217          * if (g_brUndo.next != &g_brUndo) { g_bScreenUpdates = false; Select_Delete();
4218          * for (brush_t* pBrush = g_brUndo.next ; pBrush != NULL && pBrush != &g_brUndo ;
4219          * pBrush=pBrush->next) { brush_t* pClone = Brush_Clone(pBrush); Brush_AddToList
4220          * (pClone, &active_brushes); Entity_LinkBrush (pBrush->pUndoOwner, pClone);
4221          * Brush_Build(pClone); Select_Brush(pClone); } CleanList(&g_brUndo);
4222          * g_bScreenUpdates = true; Sys_UpdateWindows(W_ALL); } else common->Printf("Nothing
4223          * to undo.../n");
4224          */
4225 }
4226
4227 /*
4228  =======================================================================================================================
4229  =======================================================================================================================
4230  */
4231 void CXYWnd::UndoClear() {
4232         /* CleanList(&g_brUndo); */
4233 }
4234
4235 /*
4236  =======================================================================================================================
4237  =======================================================================================================================
4238  */
4239 void CXYWnd::UndoCopy() {
4240         /*
4241          * CleanList(&g_brUndo); for (brush_t* pBrush = selected_brushes.next ; pBrush !=
4242          * NULL && pBrush != &selected_brushes ; pBrush=pBrush->next) { brush_t* pClone =
4243          * Brush_Clone(pBrush); pClone->pUndoOwner = pBrush->owner; Brush_AddToList
4244          * (pClone, &g_brUndo); }
4245          */
4246 }
4247
4248 /*
4249  =======================================================================================================================
4250  =======================================================================================================================
4251  */
4252 bool CXYWnd::UndoAvailable() {
4253         return(g_brUndo.next != &g_brUndo);
4254 }
4255
4256 /*
4257  =======================================================================================================================
4258  =======================================================================================================================
4259  */
4260 void CXYWnd::Paste()
4261 {
4262 #if 1
4263
4264         CWaitCursor WaitCursor;
4265         bool            bPasted = false;
4266         UINT            nClipboard = ::RegisterClipboardFormat("RadiantClippings");
4267         if (nClipboard > 0 && OpenClipboard() && ::IsClipboardFormatAvailable(nClipboard)) {
4268                 HANDLE  h = ::GetClipboardData(nClipboard);
4269                 if (h) {
4270                         g_Clipboard.SetLength(0);
4271
4272                         unsigned char   *cp = reinterpret_cast < unsigned char * > (::GlobalLock(h));
4273                         long                    lSize = 0;
4274                         memcpy(&lSize, cp, sizeof (long));
4275                         cp += sizeof (long);
4276                         g_Clipboard.Write(cp, lSize);
4277                 }
4278
4279                 ::GlobalUnlock(h);
4280                 ::CloseClipboard();
4281         }
4282
4283         if (g_Clipboard.GetLength() > 0) {
4284                 g_Clipboard.SeekToBegin();
4285
4286                 int             nLen = g_Clipboard.GetLength();
4287                 char    *pBuffer = new char[nLen + 1];
4288                 memset(pBuffer, 0, sizeof(pBuffer));
4289                 g_Clipboard.Read(pBuffer, nLen);
4290                 pBuffer[nLen] = '\0';
4291                 Map_ImportBuffer(pBuffer, !(GetAsyncKeyState(VK_SHIFT) & 0x8000));
4292                 delete[] pBuffer;
4293         }
4294
4295         #if 0
4296         if (g_PatchClipboard.GetLength() > 0) {
4297                 g_PatchClipboard.SeekToBegin();
4298
4299                 int             nLen = g_PatchClipboard.GetLength();
4300                 char    *pBuffer = new char[nLen + 1];
4301                 g_PatchClipboard.Read(pBuffer, nLen);
4302                 pBuffer[nLen] = '\0';
4303                 Patch_ReadBuffer(pBuffer, true);
4304                 delete[] pBuffer;
4305         }
4306         #endif
4307 #else
4308         if (g_brClipboard.next != &g_brClipboard || g_enClipboard.next != &g_enClipboard) {
4309                 Select_Deselect();
4310
4311                 for (brush_t * pBrush = g_brClipboard.next; pBrush != NULL && pBrush != &g_brClipboard; pBrush = pBrush->next) {
4312                         brush_t *pClone = Brush_Clone(pBrush);
4313
4314                         // pClone->owner = pBrush->owner;
4315                         if (pClone->owner == NULL) {
4316                                 Entity_LinkBrush(world_entity, pClone);
4317                         }
4318
4319                         Brush_AddToList(pClone, &selected_brushes);
4320                         Brush_Build(pClone);
4321                 }
4322
4323                 for
4324                 (
4325                         entity_t * pEntity = g_enClipboard.next;
4326                         pEntity != NULL && pEntity != &g_enClipboard;
4327                         pEntity = pEntity->next
4328                 ) {
4329                         entity_t        *pEClone = Entity_Clone(pEntity);
4330                         for (brush_t * pEB = pEntity->brushes.onext; pEB != &pEntity->brushes; pEB = pEB->onext) {
4331                                 brush_t *pClone = Brush_Clone(pEB);
4332                                 Brush_AddToList(pClone, &selected_brushes);
4333                                 Entity_LinkBrush(pEClone, pClone);
4334                                 Brush_Build(pClone);
4335                                 if (pClone->owner && pClone->owner != world_entity) {
4336                                         g_Inspectors->UpdateEntitySel(pClone->owner->eclass);
4337                                 }
4338                         }
4339                 }
4340
4341                 Sys_UpdateWindows(W_ALL);
4342         }
4343         else {
4344                 common->Printf("Nothing to paste.../n");
4345         }
4346 #endif
4347 }
4348
4349 /*
4350  =======================================================================================================================
4351  =======================================================================================================================
4352  */
4353 idVec3 &CXYWnd::Rotation() {
4354         return g_vRotation;
4355 }
4356
4357 /*
4358  =======================================================================================================================
4359  =======================================================================================================================
4360  */
4361 idVec3 &CXYWnd::RotateOrigin() {
4362         return g_vRotateOrigin;
4363 }
4364
4365 /*
4366  =======================================================================================================================
4367  =======================================================================================================================
4368  */
4369 void CXYWnd::OnTimer(UINT nIDEvent) {
4370         if (nIDEvent == 100) {
4371                 int nDim1 = (m_nViewType == YZ) ? 1 : 0;
4372                 int nDim2 = (m_nViewType == XY) ? 1 : 2;
4373                 m_vOrigin[nDim1] += m_ptDragAdj.x / m_fScale;
4374                 m_vOrigin[nDim2] -= m_ptDragAdj.y / m_fScale;
4375                 Sys_UpdateWindows(W_XY | W_CAMERA);
4376
4377                 // int nH = (m_ptDrag.y == 0) ? -1 : m_ptDrag.y;
4378                 m_ptDrag += m_ptDragAdj;
4379                 m_ptDragTotal += m_ptDragAdj;
4380                 XY_MouseMoved(m_ptDrag.x, m_nHeight - 1 - m_ptDrag.y, m_nScrollFlags);
4381
4382                 //
4383                 // m_vOrigin[nDim1] -= m_ptDrag.x / m_fScale; m_vOrigin[nDim1] -= m_ptDrag.x /
4384                 // m_fScale;
4385                 //
4386         } 
4387 }
4388
4389 /*
4390  =======================================================================================================================
4391  =======================================================================================================================
4392  */
4393 void CXYWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) {
4394         g_pParentWnd->HandleKey(nChar, nRepCnt, nFlags, false);
4395
4396         // CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
4397 }
4398
4399 /*
4400  =======================================================================================================================
4401  =======================================================================================================================
4402  */
4403 void CXYWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR *lpncsp) {
4404         CWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
4405 }
4406
4407 /*
4408  =======================================================================================================================
4409  =======================================================================================================================
4410  */
4411 void CXYWnd::OnKillFocus(CWnd *pNewWnd) {
4412         CWnd::OnKillFocus(pNewWnd);
4413         SendMessage(WM_NCACTIVATE, FALSE, 0);
4414 }
4415
4416 /*
4417  =======================================================================================================================
4418  =======================================================================================================================
4419  */
4420 void CXYWnd::OnSetFocus(CWnd *pOldWnd) {
4421         CWnd::OnSetFocus(pOldWnd);
4422         SendMessage(WM_NCACTIVATE, TRUE, 0);
4423 }
4424
4425 /*
4426  =======================================================================================================================
4427  =======================================================================================================================
4428  */
4429 void CXYWnd::OnClose() {
4430         CWnd::OnClose();
4431 }
4432
4433 //
4434 // =======================================================================================================================
4435 //    should be static as should be the rotate scale stuff
4436 // =======================================================================================================================
4437 //
4438 bool CXYWnd::AreaSelectOK() {
4439         return RotateMode() ? false : ScaleMode() ? false : true;
4440 }
4441
4442 /*
4443  =======================================================================================================================
4444  =======================================================================================================================
4445  */
4446 BOOL CXYWnd::OnEraseBkgnd(CDC *pDC) {
4447         return TRUE;
4448
4449         // return CWnd::OnEraseBkgnd(pDC);
4450 }
4451
4452 extern void AssignModel();
4453 void CXYWnd::OnDropNewmodel() 
4454 {
4455         CPoint point;
4456         GetCursorPos(&point);
4457         CreateRightClickEntity(this, m_ptDown.x, m_ptDown.y, "func_static");
4458         g_Inspectors->SetMode(W_ENTITY);
4459         g_Inspectors->AssignModel();
4460 }
4461
4462 BOOL CXYWnd::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
4463 {
4464         if (zDelta > 0) {
4465                 g_pParentWnd->OnViewZoomin();
4466         } else {
4467                 g_pParentWnd->OnViewZoomout();
4468         }
4469         return TRUE;
4470 }
4471
4472
4473
4474
4475  //---------------------------------------------------------------------------
4476  // CyclePrecisionCrosshairMode
4477  // 
4478  // Called when the user presses the "cycle precision cursor mode" key.
4479  // Cycles the precision cursor among the following three modes:
4480  //             PRECISION_CURSOR_NONE
4481  //             PRECISION_CURSOR_SNAP
4482  //             PRECISION_CURSOR_FREE
4483  //---------------------------------------------------------------------------
4484  void CXYWnd::CyclePrecisionCrosshairMode( void )
4485  {
4486          common->Printf("TODO: Make DrawPrecisionCrosshair work..." );
4487
4488          /// Cycle to next mode, wrap if necessary
4489          m_precisionCrosshairMode ++;
4490          if( m_precisionCrosshairMode >= PRECISION_CROSSHAIR_MAX )
4491                  m_precisionCrosshairMode = PRECISION_CROSSHAIR_NONE;
4492          Sys_UpdateWindows( W_XY );
4493  }
4494
4495  //---------------------------------------------------------------------------
4496 // DrawPrecisionCrosshair 
4497 // 
4498 // Draws a precision crosshair beneath the cursor in the 2d (XY) view,
4499 //  depending on one of the following values for m_precisionCrosshairMode:
4500 // 
4501 // PRECISION_CROSSHAIR_NONE             No crosshair is drawn.  Do not force refresh of XY view.
4502 // PRECISION_CROSSHAIR_SNAP             Crosshair snaps to grid size.  Force refresh of XY view.
4503 // PRECISION_CROSSHAIR_FREE             Crosshair does not snap to grid.  Force refresh of XY view.
4504 //---------------------------------------------------------------------------
4505 void CXYWnd::DrawPrecisionCrosshair( void )
4506 {
4507         // FIXME: m_mouseX, m_mouseY, m_axisHoriz, m_axisVert, etc... are never set
4508         return;
4509
4510         idVec3 mouse3dPos (0.0f, 0.0f, 0.0f);
4511         float x, y;
4512         idVec4 crossEndColor (1.0f, 0.0f, 1.0f, 1.0f); // the RGBA color of the precision crosshair at its ends
4513         idVec4 crossMidColor; // the RGBA color of the precision crosshair at the crossing point
4514         
4515         /// Transform the mouse coordinates into axis-correct map-coordinates
4516         if( m_precisionCrosshairMode == PRECISION_CROSSHAIR_SNAP )
4517                 SnapToPoint( m_mouseX, m_mouseY, mouse3dPos );
4518         else
4519                 XY_ToPoint( m_mouseX, m_mouseY, mouse3dPos );
4520         x = mouse3dPos[ m_axisHoriz ];
4521         y = mouse3dPos[ m_axisVert ];
4522         
4523         /// Use the color specified by the user
4524
4525         crossEndColor[0] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][0];
4526         crossEndColor[1] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][1];
4527         crossEndColor[2] = g_qeglobals.d_savedinfo.colors[ COLOR_PRECISION_CROSSHAIR ][2];
4528         crossEndColor[3] = 1.0f;
4529
4530         crossMidColor = crossEndColor;
4531
4532         if( m_precisionCrosshairMode == PRECISION_CROSSHAIR_FREE )
4533                 crossMidColor[ 3 ] = 0.0f; // intersection-color is 100% transparent (alpha = 0.0f)
4534         
4535         /// Set up OpenGL states (for drawing smooth-shaded plain-colored lines)
4536         qglEnable( GL_BLEND );
4537         qglDisable( GL_TEXTURE_2D );
4538         qglShadeModel( GL_SMOOTH );
4539         qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
4540         
4541         /// Draw a fullscreen-sized crosshair over the cursor
4542         qglBegin( GL_LINES );
4543         {
4544                 /// Draw the horizontal precision line (in two pieces)
4545                 qglColor4fv( crossEndColor.ToFloatPtr() );
4546                 qglVertex2f( m_mcLeft, y );
4547                 qglColor4fv( crossMidColor.ToFloatPtr() );
4548                 qglVertex2f( x, y );
4549                 qglColor4fv( crossMidColor.ToFloatPtr() );
4550                 qglVertex2f( x, y );
4551                 qglColor4fv( crossEndColor.ToFloatPtr() );
4552                 qglVertex2f( m_mcRight, y );
4553                 
4554                 /// Draw the vertical precision line (in two pieces)
4555                 qglColor4fv( crossEndColor.ToFloatPtr() );
4556                 qglVertex2f( x, m_mcTop );
4557                 qglColor4fv( crossMidColor.ToFloatPtr() );
4558                 qglVertex2f( x, y );
4559                 qglColor4fv( crossMidColor.ToFloatPtr() );
4560                 qglVertex2f( x, y );
4561                 qglColor4fv( crossEndColor.ToFloatPtr() );
4562                 qglVertex2f( x, m_mcBottom );
4563         }
4564         qglEnd(); // GL_LINES
4565         
4566         // Radiant was in opaque, flat-shaded mode by default; restore this to prevent possible slowdown
4567         qglShadeModel( GL_FLAT );
4568         qglDisable( GL_BLEND );
4569 }