apply back 335 and 336, will need to update deps and put a zip out
[xonotic/netradiant.git] / radiant / xywindow.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 //
23 // XY Window
24 //
25 // Leonardo Zide (leo@lokigames.com)
26 //
27
28 #include "stdafx.h"
29 #include <gtk/gtk.h>
30 #include <glib/gi18n.h>
31 #include <assert.h>
32 #include <GL/gl.h>
33
34 #ifdef _WIN32
35 #include <gdk/gdkwin32.h>
36 #endif
37
38 // =============================================================================
39 // variables
40
41 #define PAGEFLIPS   2
42
43 CString g_strStatus;
44 bool g_bCrossHairs = false;
45 bool g_bScaleMode;
46 int g_nScaleHow;
47 bool g_bRotateMode;
48 bool g_bClipMode;
49 bool g_bRogueClipMode;
50 bool g_bSwitch;
51 ClipPoint g_Clip1;
52 ClipPoint g_Clip2;
53 ClipPoint g_Clip3;
54 ClipPoint* g_pMovingClip;
55 brush_t g_brFrontSplits;
56 brush_t g_brBackSplits;
57
58 brush_t g_brClipboard;
59 brush_t g_brUndo;
60 entity_t g_enClipboard;
61
62 vec3_t g_vRotateOrigin;
63 vec3_t g_vRotation;
64
65 bool g_bPathMode;
66 ClipPoint g_PathPoints[256]; // this limit isn't enforced?
67 ClipPoint* g_pMovingPath;
68 int g_nPathCount;
69 int g_nPathLimit;
70
71 bool g_bSmartGo;
72
73 bool g_bPointMode;
74 ClipPoint g_PointPoints[512];
75 ClipPoint* g_pMovingPoint;
76 int g_nPointCount;
77 int g_nPointLimit;
78
79 const int XY_LEFT = 0x01;
80 const int XY_RIGHT = 0x02;
81 const int XY_UP = 0x04;
82 const int XY_DOWN = 0x08;
83
84 PFNPathCallback* g_pPathFunc = NULL;
85
86 static unsigned s_stipple[32] =
87 {
88     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
89     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
90     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
91     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
92     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
93     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
94     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
95     0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555,
96 };
97
98 void AcquirePath(int nCount, PFNPathCallback* pFunc)
99 {
100   g_nPathCount = 0;
101   g_nPathLimit = nCount;
102   g_pPathFunc = pFunc;
103   g_bPathMode = true;
104 }
105
106
107 CPtrArray g_ptrMenus;
108
109 MemStream g_Clipboard(4096);
110 MemStream g_PatchClipboard(4096);
111
112 extern int pressx;
113 extern int pressy;
114 extern bool g_bWaitCursor;
115
116 vec3_t tdp;
117
118 GtkWidget* XYWnd::m_mnuDrop = NULL;
119
120 extern int g_nPatchClickedView;
121
122 // =============================================================================
123 // global functions
124
125
126 void WXY_Print ()
127 {
128   const long width = g_pParentWnd->ActiveXY()->Width();
129   const long height = g_pParentWnd->ActiveXY()->Height();
130   unsigned char* img;
131   const char* filename;
132
133   filename = file_dialog (g_pParentWnd->m_pWidget, FALSE, _("Save BMP Image"), NULL, "bmp");
134   if (!filename)
135     return;
136
137   g_pParentWnd->ActiveXY()->MakeCurrent();
138   img = (unsigned char*)malloc (width*height*3);
139   qglReadPixels (0,0,width,height,GL_RGB,GL_UNSIGNED_BYTE,img);
140
141   FILE *fp;
142   fp = fopen(filename, "wb");
143   if (fp)
144   {
145     unsigned short bits;
146     unsigned long cmap, bfSize;
147
148     bits = 24;
149     cmap = 0;
150     bfSize = 54 + width*height*3;
151
152     long byteswritten = 0;
153     long pixoff = 54 + cmap*4;
154     short res = 0;
155     char m1 ='B', m2 ='M';
156     fwrite(&m1, 1, 1, fp);      byteswritten++; // B
157     fwrite(&m2, 1, 1, fp);      byteswritten++; // M
158     fwrite(&bfSize, 4, 1, fp);  byteswritten+=4;// bfSize
159     fwrite(&res, 2, 1, fp);     byteswritten+=2;// bfReserved1
160     fwrite(&res, 2, 1, fp);     byteswritten+=2;// bfReserved2
161     fwrite(&pixoff, 4, 1, fp);  byteswritten+=4;// bfOffBits
162
163     unsigned long biSize = 40, compress = 0, size = 0;
164     long pixels = 0;
165     unsigned short planes = 1;
166     fwrite(&biSize, 4, 1, fp);  byteswritten+=4;// biSize
167     fwrite(&width, 4, 1, fp);   byteswritten+=4;// biWidth
168     fwrite(&height, 4, 1, fp);  byteswritten+=4;// biHeight
169     fwrite(&planes, 2, 1, fp);  byteswritten+=2;// biPlanes
170     fwrite(&bits, 2, 1, fp);    byteswritten+=2;// biBitCount
171     fwrite(&compress, 4, 1, fp);byteswritten+=4;// biCompression
172     fwrite(&size, 4, 1, fp);    byteswritten+=4;// biSizeImage
173     fwrite(&pixels, 4, 1, fp);  byteswritten+=4;// biXPelsPerMeter
174     fwrite(&pixels, 4, 1, fp);  byteswritten+=4;// biYPelsPerMeter
175     fwrite(&cmap, 4, 1, fp);    byteswritten+=4;// biClrUsed
176     fwrite(&cmap, 4, 1, fp);    byteswritten+=4;// biClrImportant
177
178     unsigned long widthDW = (((width*24) + 31) / 32 * 4);
179     long row, row_size = width*3;
180     for (row = 0; row < height; row++)
181     {
182         unsigned char* buf = img+row*row_size;
183
184       // write a row
185       int col;
186       for (col = 0; col < row_size; col += 3)
187         {
188           putc(buf[col+2], fp);
189           putc(buf[col+1], fp);
190           putc(buf[col], fp);
191         }
192       byteswritten += row_size;
193
194       unsigned long count;
195       for (count = row_size; count < widthDW; count++)
196         {
197         putc(0, fp);    // dummy
198           byteswritten++;
199         }
200     }
201
202     fclose(fp);
203   }
204
205   free (img);
206 }
207
208 float ptSum(vec3_t pt)
209 {
210   return pt[0] + pt[1] + pt[2];
211 }
212
213 float Betwixt(float f1, float f2)
214 {
215   if (f1 > f2)
216     return f2 + ((f1 - f2) / 2);
217   else
218     return f1 + ((f2 - f1) / 2);
219 }
220
221 void CleanList(brush_t* pList)
222 {
223   brush_t* pBrush = pList->next;
224   while (pBrush != NULL && pBrush != pList)
225   {
226     brush_t* pNext = pBrush->next;
227     Brush_Free(pBrush);
228     pBrush = pNext;
229   }
230 }
231
232 void Brush_CopyList (brush_t* pFrom, brush_t* pTo)
233 {
234   brush_t* pBrush = pFrom->next;
235   while (pBrush != NULL && pBrush != pFrom)
236   {
237     brush_t* pNext = pBrush->next;
238     Brush_RemoveFromList(pBrush);
239     Brush_AddToList(pBrush, pTo);
240     pBrush = pNext;
241   }
242 }
243
244 float fDiff(float f1, float f2)
245 {
246   if (f1 > f2)
247     return f1 - f2;
248   else
249     return f2 - f1;
250 }
251
252 /*
253 =============================================================
254
255   PATH LINES
256
257 =============================================================
258 */
259
260 /*
261 ==================
262 DrawPathLines
263
264 Draws connections between entities.
265 Needs to consider all entities, not just ones on screen,
266 because the lines can be visible when neither end is.
267 Called for both camera view and xy view.
268 ==================
269 */
270 void DrawPathLines (void)
271 {
272   int       i, j, k;
273   vec3_t    mid, mid1;
274   entity_t *se, *te;
275   brush_t   *sb, *tb;
276   const char    *psz;
277   vec3_t    dir, s1, s2;
278   vec_t len, f;
279   int       arrows;
280   int           num_entities;
281   const char        *ent_target[MAX_MAP_ENTITIES];
282   entity_t  *ent_entity[MAX_MAP_ENTITIES];
283
284   if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS)
285   {
286     return;
287   }
288
289   num_entities = 0;
290   for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next)
291   {
292     ent_target[num_entities] = ValueForKey (te, "target");
293     if (ent_target[num_entities][0])
294     {
295       ent_entity[num_entities] = te;
296       num_entities++;
297     }
298   }
299
300   for (se = entities.next ; se != &entities ; se = se->next)
301   {
302     psz = ValueForKey(se, "targetname");
303
304     if (psz == NULL || psz[0] == '\0')
305       continue;
306
307     sb = se->brushes.onext;
308     if (sb == &se->brushes)
309       continue;
310
311     for (k=0 ; k<num_entities ; k++)
312     {
313       if (strcmp (ent_target[k], psz))
314         continue;
315
316       te = ent_entity[k];
317       tb = te->brushes.onext;
318       if (tb == &te->brushes)
319         continue;
320
321       for (i=0 ; i<3 ; i++)
322         mid[i] = (sb->mins[i] + sb->maxs[i])*0.5;
323
324       for (i=0 ; i<3 ; i++)
325         mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5;
326
327       VectorSubtract (mid1, mid, dir);
328       len = VectorNormalize (dir, dir);
329       s1[0] = -dir[1]*8 + dir[0]*8;
330       s2[0] = dir[1]*8 + dir[0]*8;
331       s1[1] = dir[0]*8 + dir[1]*8;
332       s2[1] = -dir[0]*8 + dir[1]*8;
333
334       qglColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);
335
336       qglBegin(GL_LINES);
337       qglVertex3fv(mid);
338       qglVertex3fv(mid1);
339
340       arrows = (int)(len / 256) + 1;
341
342       for (i=0 ; i<arrows ; i++)
343       {
344         f = len * (i + 0.5) / arrows;
345
346         for (j=0 ; j<3 ; j++)
347           mid1[j] = mid[j] + f*dir[j];
348         qglVertex3fv (mid1);
349         qglVertex3f (mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
350         qglVertex3fv (mid1);
351         qglVertex3f (mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
352       }
353
354       qglEnd();
355     }
356   }
357 }
358
359 extern void AssignModel();
360
361 void CreateEntityFromName(const char* name, const vec3_t origin)
362 {
363   entity_t *e;
364   brush_t* b;
365   if (stricmp(name, "worldspawn") == 0)
366   {
367     gtk_MessageBox(g_pParentWnd->m_pWidget, "Can't create an entity with worldspawn.", "info", 0);
368     return;
369   }
370
371   e = Entity_Alloc();
372   SetKeyValue(e, "classname", name);
373
374   if(e->eclass->fixedsize)
375   {
376     Select_Delete();
377     b = Brush_Create(e->eclass->mins, e->eclass->maxs, &e->eclass->texdef);
378     Entity_LinkBrush(e, b);
379     Brush_AddToList(b, &active_brushes);
380     Select_Brush(b);
381     Brush_Move(b, origin, true);
382   }
383   else
384   {
385     Select_GroupEntity(e);
386     if(e->brushes.onext == &e->brushes)
387     {
388       Sys_FPrintf(SYS_ERR, "CreateEntityFromName: selection could not be grouped\n");
389       Entity_Free(e);
390       return;
391     }
392   }
393
394   Entity_AddToList(e, &entities);
395   Undo_EndEntity(e);
396
397   Select_Deselect ();
398
399   // tweaking: when right clic dropping a light entity, ask for light value in a custom dialog box
400   // see SF bug 105383
401
402   if (g_pGameDescription->mGameFile == "hl.game")
403   {
404     // FIXME - Hydra: really we need a combined light AND color dialog for halflife.
405     if ((stricmp(name, "light") == 0)  ||
406         (stricmp(name, "light_environment") == 0) ||
407         (stricmp(name, "light_spot") == 0) )
408     {
409       int intensity = g_PrefsDlg.m_iLastLightIntensity;
410
411       // Create and show the dialog box
412       //    CWnd *pWnd;
413       //    pWnd = prompt.GetDlgItem( IDC_EDIT1 );
414       //    prompt.GotoDlgCtrl( pWnd );
415       if (DoLightIntensityDlg (&intensity) == IDOK)
416       {
417         g_PrefsDlg.m_iLastLightIntensity = intensity;
418         char buf[30];
419         sprintf( buf, "255 255 255 %d", intensity );
420         SetKeyValue(e, "_light", buf);
421       }
422     }
423   }
424   else
425   {
426   if (stricmp(name, "light") == 0)
427   {
428     int intensity = g_PrefsDlg.m_iLastLightIntensity;
429
430     // Create and show the dialog box
431       //    CWnd *pWnd;
432       //    pWnd = prompt.GetDlgItem( IDC_EDIT1 );
433       //    prompt.GotoDlgCtrl( pWnd );
434     if (DoLightIntensityDlg (&intensity) == IDOK)
435     {
436       g_PrefsDlg.m_iLastLightIntensity = intensity;
437       char buf[10];
438       sprintf( buf, "%d", intensity );
439       SetKeyValue(e, "light", buf);
440     }
441   }
442   }
443   Select_Brush (e->brushes.onext);
444
445   if ( (stricmp(name, "misc_model") == 0) || (stricmp(name, "misc_gamemodel") == 0) || (strcmpi(name, "model_static") == 0) )
446   {
447     SetInspectorMode(W_ENTITY);
448     AssignModel();
449   }
450 }
451
452 void CreateRightClickEntity(XYWnd* pWnd, int x, int y, char* pName)
453 {
454   int height = pWnd->GetWidget()->allocation.height;
455   vec3_t point;
456   pWnd->SnapToPoint (x, height - 1 - y, point);
457
458   int nDim = (pWnd->GetViewType() == XY) ? 2 : (pWnd->GetViewType() == YZ) ? 0 : 1;
459   float fWorkMid = (g_qeglobals.d_work_min[nDim] + g_qeglobals.d_work_max[nDim]) * 0.5;
460   point[nDim] = g_qeglobals.d_gridsize * ((int)(fWorkMid/g_qeglobals.d_gridsize));
461
462   CreateEntityFromName(pName, point);
463 }
464
465
466 brush_t* CreateSmartBrush(vec3_t v)
467 {
468   vec3_t    mins, maxs;
469   int       i;
470   brush_t   *n;
471
472   for (i=0 ; i<3 ; i++)
473   {
474     mins[i] = v[i] - 16;
475     maxs[i] = v[i] + 16;
476   }
477
478   n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef);
479   if (!n)
480     return NULL;
481
482   Brush_AddToList(n, &selected_brushes);
483   //Entity_LinkBrush(world_entity, n);
484   Brush_Build(n);
485   return n;
486 }
487
488 CString g_strSmartEntity;
489 int g_nSmartX;
490 int g_nSmartY;
491 bool g_bSmartWaiting;
492 void _SmartPointDone(bool b, int n)
493 {
494   g_bSmartWaiting = false;
495 }
496
497 void CreateSmartEntity(XYWnd* pWnd, int x, int y, const char* pName)
498 {
499   g_nSmartX = x;
500   g_nSmartY = y;
501   g_strSmartEntity = pName;
502   if (g_strSmartEntity.Find("Smart_Train") >= 0)
503   {
504     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");
505     g_bPathMode = true;
506     g_nPathLimit = 0;
507     g_nPathCount = 0;
508     g_bSmartGo = true;
509   }
510   else
511   if (g_strSmartEntity.Find("Smart_Monster...") >= 0)
512   {
513     g_bPathMode = true;
514     g_nPathLimit = 0;
515     g_nPathCount = 0;
516   }
517   else
518   if (g_strSmartEntity.Find("Smart_Rotating") >= 0)
519   {
520     g_bSmartWaiting = true;
521     ShowInfoDialog("Left click to specify the rotation origin");
522     AcquirePath(1, &_SmartPointDone);
523     while (g_bSmartWaiting)
524       gtk_main_iteration ();
525     HideInfoDialog();
526     CPtrArray array;
527     g_bScreenUpdates = false;
528     CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating");
529     array.Add(reinterpret_cast<void*>(selected_brushes.next));
530     Select_Deselect();
531     brush_t* pBrush = CreateSmartBrush(g_PathPoints[0]);
532     array.Add(pBrush);
533     Select_Deselect();
534     Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(0)));
535     Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(1)));
536     ConnectEntities();
537     g_bScreenUpdates = true;
538   }
539 }
540
541 void FinishSmartCreation()
542 {
543   CPtrArray array;
544   HideInfoDialog();
545   //  brush_t* pEntities = NULL;
546   int n;
547
548   if (g_strSmartEntity.Find("Smart_Train") >= 0)
549   {
550     g_bScreenUpdates = false;
551     CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_train");
552     array.Add(reinterpret_cast<void*>(selected_brushes.next));
553     for (n = 0; n < g_nPathCount; n++)
554     {
555       Select_Deselect();
556       CreateRightClickEntity(g_pParentWnd->ActiveXY(), g_PathPoints[n].m_ptScreenX,
557                  g_PathPoints[n].m_ptScreenY, "path_corner");
558       array.Add(reinterpret_cast<void*>(selected_brushes.next));
559     }
560
561     for (n = 0; n < g_nPathCount; n++)
562     {
563       Select_Deselect();
564       Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(n)));
565       Select_Brush(reinterpret_cast<brush_t*>(array.GetAt(n+1)));
566       ConnectEntities();
567     }
568     g_bScreenUpdates = true;
569
570   }
571   g_nPathCount = 0;
572   g_bPathMode = false;
573   Sys_UpdateWindows(W_ALL);
574 }
575
576 void CleanCopyEntities()
577 {
578   entity_t* pe = g_enClipboard.next;
579   while (pe != NULL && pe != &g_enClipboard)
580   {
581     entity_t* next = pe->next;
582     epair_t* enext = NULL;
583       for (epair_t* ep = pe->epairs ; ep ; ep=enext)
584     {
585           enext = ep->next;
586       free (ep->key);
587       free (ep->value);
588           free (ep);
589     }
590       free (pe);
591     pe = next;
592   }
593   g_enClipboard.next = g_enClipboard.prev = &g_enClipboard;
594 }
595
596 entity_t *Entity_CopyClone (entity_t *e)
597 {
598   entity_t  *n;
599   epair_t       *ep, *np;
600
601   n = (entity_t*)qmalloc(sizeof(*n));
602   n->brushes.onext = n->brushes.oprev = &n->brushes;
603   n->eclass = e->eclass;
604
605   // add the entity to the entity list
606   n->next = g_enClipboard.next;
607   g_enClipboard.next = n;
608   n->next->prev = n;
609   n->prev = &g_enClipboard;
610
611   for (ep = e->epairs ; ep ; ep=ep->next)
612   {
613     np = (epair_t*)qmalloc(sizeof(*np));
614     np->key = copystring(ep->key);
615     np->value = copystring(ep->value);
616     np->next = n->epairs;
617     n->epairs = np;
618   }
619   return n;
620 }
621
622 bool OnList(entity_t* pFind, CPtrArray* pList)
623 {
624   int nSize = pList->GetSize();
625   while (nSize-- > 0)
626   {
627     entity_t* pEntity = reinterpret_cast<entity_t*>(pList->GetAt(nSize));
628     if (pEntity == pFind)
629       return true;
630   }
631   return false;
632 }
633
634 // =============================================================================
635 // XYWnd class
636
637 XYWnd::XYWnd ()
638   : GLWindow (FALSE), m_XORRectangle(m_pWidget)
639 {
640   g_brClipboard.next = &g_brClipboard;
641   g_brUndo.next = &g_brUndo;
642   g_nScaleHow = 0;
643   g_bRotateMode = false;
644   g_bClipMode = false;
645   g_bRogueClipMode = false;
646   g_bSwitch = true;
647   g_pMovingClip = (ClipPoint*)NULL;
648   g_pMovingPath = (ClipPoint*)NULL;
649   g_brFrontSplits.next = &g_brFrontSplits;
650   g_brBackSplits.next = &g_brBackSplits;
651   m_bActive = false;
652   //m_bTiming = true;
653   m_bTiming = false;
654   m_bRButtonDown = false;
655   m_nUpdateBits = W_XY;
656   g_bPathMode = false;
657   g_nPathCount = 0;
658   g_nPathLimit = 0;
659   m_nButtonstate = 0;
660 //  m_mnuDrop = (GtkWidget*)NULL;
661   XY_Init();
662 }
663
664 vec3_t& XYWnd::Rotation()
665 {
666   return g_vRotation;
667 }
668
669 vec3_t& XYWnd::RotateOrigin()
670 {
671   return g_vRotateOrigin;
672 }
673
674 /*
675 ==============
676 XY_Overlay
677 ==============
678 */
679 void XYWnd::XY_Overlay()
680 {
681   int   w, h;
682   int   r[4];
683   static vec3_t lastz;
684   static vec3_t lastcamera;
685
686   qglViewport(0, 0, m_nWidth, m_nHeight);
687
688   //
689   // set up viewpoint
690   //
691   qglMatrixMode(GL_PROJECTION);
692   qglLoadIdentity ();
693
694   w = (int)(m_nWidth / 2 / m_fScale);
695   h = (int)(m_nHeight / 2 / m_fScale);
696
697   qglOrtho (m_vOrigin[0] - w, m_vOrigin[0] + w  , m_vOrigin[1] - h, m_vOrigin[1] + h, g_MinWorldCoord, g_MaxWorldCoord);
698   //
699   // erase the old camera and z checker positions
700   // if the entire xy hasn't been redrawn
701   //
702   if (m_bDirty)
703   {
704     qglReadBuffer (GL_BACK);
705     qglDrawBuffer (GL_FRONT);
706
707     qglRasterPos2f (lastz[0]-9, lastz[1]-9);
708     qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
709     qglCopyPixels(r[0], r[1], 18,18, GL_COLOR);
710
711     qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50);
712     qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
713     qglCopyPixels(r[0], r[1], 100,100, GL_COLOR);
714   }
715   m_bDirty = true;
716
717   //
718   // save off underneath where we are about to draw
719   //
720   VectorCopy (z.origin, lastz);
721   VectorCopy (g_pParentWnd->GetCamWnd()->Camera()->origin, lastcamera);
722
723   qglReadBuffer (GL_FRONT);
724   qglDrawBuffer (GL_BACK);
725
726   qglRasterPos2f (lastz[0]-9, lastz[1]-9);
727   qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
728   qglCopyPixels(r[0], r[1], 18,18, GL_COLOR);
729
730   qglRasterPos2f (lastcamera[0]-50, lastcamera[1]-50);
731   qglGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
732   qglCopyPixels(r[0], r[1], 100,100, GL_COLOR);
733
734   //
735   // draw the new icons
736   //
737   qglDrawBuffer (GL_FRONT);
738
739   qglShadeModel (GL_FLAT);
740   qglDisable(GL_TEXTURE_2D);
741   qglDisable(GL_TEXTURE_1D);
742   qglDisable(GL_DEPTH_TEST);
743   qglDisable(GL_BLEND);
744   qglColor3f(0, 0, 0);
745
746   DrawCameraIcon ();
747   DrawZIcon ();
748
749   qglDrawBuffer (GL_BACK);
750   qglFinish();
751 }
752
753 vec3_t& XYWnd::GetOrigin()
754 {
755   return m_vOrigin;
756 }
757
758 void XYWnd::SetOrigin(vec3_t org)
759 {
760   m_vOrigin[0] = org[0];
761   m_vOrigin[1] = org[1];
762   m_vOrigin[2] = org[2];
763 }
764
765 void XYWnd::OnSize(int cx, int cy)
766 {
767   m_nWidth = cx;
768   m_nHeight = cy;
769 }
770
771 brush_t hold_brushes;
772
773 void XYWnd::Clip()
774 {
775   if (ClipMode())
776   {
777     hold_brushes.next = &hold_brushes;
778     ProduceSplitLists();
779     brush_t* pList;
780     if (g_PrefsDlg.m_bSwitchClip)
781       pList = (!g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
782     else
783       pList = (g_bSwitch) ? &g_brFrontSplits : &g_brBackSplits;
784
785     if (pList->next != pList)
786     {
787       Brush_CopyList(pList, &hold_brushes);
788       CleanList(&g_brFrontSplits);
789       CleanList(&g_brBackSplits);
790       Select_Delete();
791       Brush_CopyList(&hold_brushes, &selected_brushes);
792       if (RogueClipMode())
793         RetainClipMode(false);
794       else
795         RetainClipMode(true);
796       Sys_UpdateWindows(W_ALL);
797     }
798   }
799   else if (PathMode())
800   {
801     FinishSmartCreation();
802     if (g_pPathFunc)
803       g_pPathFunc(true, g_nPathCount);
804     g_pPathFunc = NULL;
805     g_nPathCount = 0;
806     g_bPathMode = false;
807   }
808 }
809
810 void XYWnd::SplitClip()
811 {
812   ProduceSplitLists();
813   if ((g_brFrontSplits.next != &g_brFrontSplits) &&
814       (g_brBackSplits.next != &g_brBackSplits))
815   {
816     Select_Delete();
817     Brush_CopyList(&g_brFrontSplits, &selected_brushes);
818     Brush_CopyList(&g_brBackSplits, &selected_brushes);
819     CleanList(&g_brFrontSplits);
820     CleanList(&g_brBackSplits);
821     if (RogueClipMode())
822       RetainClipMode(false);
823     else
824       RetainClipMode(true);
825   }
826 }
827
828 void XYWnd::FlipClip()
829 {
830   g_bSwitch = !g_bSwitch;
831   Sys_UpdateWindows(XY | W_CAMERA_IFON);
832 }
833
834 // makes sure the selected brush or camera is in view
835 void XYWnd::PositionView()
836 {
837   int nDim1 = (m_nViewType == YZ) ? 1 : 0;
838   int nDim2 = (m_nViewType == XY) ? 1 : 2;
839   brush_t* b = selected_brushes.next;
840   if (b && b->next != b)
841   {
842     Select_GetMid (m_vOrigin);
843   }
844   else
845   {
846     m_vOrigin[nDim1] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim1];
847     m_vOrigin[nDim2] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim2];
848   }
849 }
850
851 void XYWnd::VectorCopyXY(vec3_t in, vec3_t out)
852 {
853   if (m_nViewType == XY)
854   {
855     out[0] = in[0];
856     out[1] = in[1];
857   }
858   else if (m_nViewType == XZ)
859   {
860     out[0] = in[0];
861     out[2] = in[2];
862   }
863   else
864   {
865     out[1] = in[1];
866     out[2] = in[2];
867   }
868 }
869
870 void XYWnd::RetainClipMode(bool bMode)
871 {
872   bool bSave = g_bRogueClipMode;
873   SetClipMode(bMode);
874   if (bMode == true)
875     g_bRogueClipMode = bSave;
876   else
877     g_bRogueClipMode = false;
878 }
879
880 void XYWnd::SetClipMode(bool bMode)
881 {
882   g_bClipMode = bMode;
883   g_bRogueClipMode = false;
884   if (bMode)
885   {
886     g_Clip1.Reset();
887     g_Clip2.Reset();
888     g_Clip3.Reset();
889     CleanList(&g_brFrontSplits);
890     CleanList(&g_brBackSplits);
891     g_brFrontSplits.next = &g_brFrontSplits;
892     g_brBackSplits.next = &g_brBackSplits;
893
894     // ydnar: set clipper points based on first selected patch mesh
895     if( selected_brushes.next != &selected_brushes )
896     {
897       bool found = false;
898       for( brush_t *pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next )
899       {
900         if( pb->patchBrush )
901         {
902           found = true;
903           VectorCopy( pb->pPatch->ctrl[ 0 ][ 0 ].xyz, g_Clip1.m_ptClip );
904           VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ pb->pPatch->height - 1 ].xyz, g_Clip2.m_ptClip );
905           VectorCopy( pb->pPatch->ctrl[ pb->pPatch->width - 1 ][ 0 ].xyz, g_Clip3.m_ptClip );
906           g_Clip1.Set( true );
907           g_Clip2.Set( true );
908           g_Clip3.Set( true );
909           break;
910         }
911       }
912
913       if( found )
914       {
915         // SetClipMode( true );
916         Sys_UpdateWindows( XY | W_CAMERA_IFON );
917       }
918     }
919   }
920   else
921   {
922     if (g_pMovingClip)
923     {
924       ReleaseCapture();
925       g_pMovingClip = NULL;
926     }
927     CleanList(&g_brFrontSplits);
928     CleanList(&g_brBackSplits);
929     g_brFrontSplits.next = &g_brFrontSplits;
930     g_brBackSplits.next = &g_brBackSplits;
931     Sys_UpdateWindows(XY | W_CAMERA_IFON);
932   }
933 }
934
935 bool XYWnd::ClipMode()
936 {
937   return g_bClipMode;
938 }
939
940 bool XYWnd::RogueClipMode()
941 {
942   return g_bRogueClipMode;
943 }
944
945 bool XYWnd::PathMode()
946 {
947   return g_bPathMode;
948 }
949
950 bool XYWnd::PointMode()
951 {
952   return g_bPointMode;
953 }
954
955 void XYWnd::SetPointMode(bool b)
956 {
957   g_bPointMode = b;
958   if (!b)
959     g_nPointCount = 0;
960 }
961
962 void XYWnd::SetViewType(int n)
963 {
964   m_nViewType = n;
965   if (g_pParentWnd->CurrentStyle() == MainFrame::eFloating)
966   {
967     char* str = "YZ Side";
968     if (m_nViewType == XY)
969       str = "XY Top";
970     else if (m_nViewType == XZ)
971       str = "XZ Front";
972
973     if (m_pParent != NULL)
974       gtk_window_set_title (GTK_WINDOW (m_pParent), str);
975   }
976 }
977
978 void XYWnd::Redraw(unsigned int nBits)
979 {
980   m_nUpdateBits = nBits;
981   gtk_widget_queue_draw(m_pWidget);
982   m_nUpdateBits = W_XY;
983 }
984
985 bool XYWnd::RotateMode()
986 {
987   return g_bRotateMode;
988 }
989
990 bool XYWnd::ScaleMode()
991 {
992   return g_bScaleMode;
993 }
994
995 bool XYWnd::SetRotateMode(bool bMode)
996 {
997   if (bMode && selected_brushes.next != &selected_brushes)
998   {
999     g_bRotateMode = true;
1000     Select_GetTrueMid(g_vRotateOrigin);
1001     g_vRotation[0] = g_vRotation[1] = g_vRotation[2] = 0.0;
1002   }
1003   else
1004   {
1005     if (bMode)
1006       Sys_Printf("Need a brush selected to turn on Mouse Rotation mode\n");
1007     g_bRotateMode = false;
1008   }
1009   RedrawWindow();
1010   return g_bRotateMode;
1011 }
1012
1013 void XYWnd::SetScaleMode(bool bMode)
1014 {
1015   g_bScaleMode = bMode;
1016   RedrawWindow();
1017 }
1018
1019 rectangle_t rectangle_from_area_xy()
1020 {
1021   XYWnd* xy = g_pParentWnd->ActiveXY();
1022   int nDim1 = (xy->GetViewType() == YZ) ? 1 : 0;
1023   int nDim2 = (xy->GetViewType() == XY) ? 1 : 2;
1024   float origin_left = xy->GetOrigin()[nDim1] - (xy->Width() / 2) / xy->Scale();
1025   float origin_bottom = xy->GetOrigin()[nDim2] - (xy->Height() / 2) / xy->Scale();
1026   float left = MIN(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left;
1027   float top = MAX(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom;
1028   float right = MAX(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaBR[nDim1]) - origin_left;
1029   float bottom = MIN(g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim2]) - origin_bottom;
1030   left *= xy->Scale();
1031   top *= xy->Scale();
1032   right *= xy->Scale();
1033   bottom *= xy->Scale();
1034   return rectangle_t(left, bottom, right - left, top - bottom);
1035 }
1036
1037 void update_xor_rectangle_xy(XORRectangle& xor_rectangle)
1038 {
1039   rectangle_t rectangle;
1040     if ((g_qeglobals.d_select_mode == sel_area))
1041     rectangle = rectangle_from_area_xy();
1042   xor_rectangle.set(rectangle);
1043 }
1044
1045 void XYWnd::OnMouseMove(guint32 nFlags, int pointx, int pointy)
1046 {
1047   // plugin entities
1048   // TODO TTimo handle return code
1049   DispatchOnMouseMove (nFlags, pointx, pointy);
1050
1051   m_ptDownX = 0;
1052   m_ptDownY = 0;
1053
1054   if (g_PrefsDlg.m_bChaseMouse == TRUE &&
1055       (pointx < 0 || pointy < 0 || pointx > m_nWidth || pointy > m_nHeight) &&
1056        HasCapture ())
1057   {
1058     float fAdjustment = (g_qeglobals.d_gridsize / 8 * 64) / m_fScale;
1059     //m_ptDrag = point;
1060     m_ptDragAdjX = 0;
1061     m_ptDragAdjY = 0;
1062
1063     if (pointx < 0)
1064     {
1065       m_ptDragAdjX = (int)(-fAdjustment);
1066     }
1067     else if (pointx > m_nWidth)
1068     {
1069       m_ptDragAdjX = (int)(fAdjustment);
1070     }
1071
1072     if (pointy < 0)
1073     {
1074       m_ptDragAdjY = (int)(-fAdjustment);
1075     }
1076     else if (pointy > m_nHeight)
1077     {
1078       m_ptDragAdjY = (int)(fAdjustment);
1079     }
1080
1081     if (!HasTimer ())
1082     {
1083       SetTimer (50);
1084       m_ptDragX = pointx;
1085       m_ptDragY = pointy;
1086       m_ptDragTotalX = 0;
1087       m_ptDragTotalY = 0;
1088     }
1089     return;
1090   }
1091
1092   if (HasTimer ())
1093   {
1094     KillTimer ();
1095     pressx -= m_ptDragTotalX;
1096     pressy += m_ptDragTotalY;
1097   }
1098
1099   bool bCrossHair = false;
1100   if (!m_bRButtonDown)
1101   {
1102     tdp[0] = tdp[1] = tdp[2] = 0.0;
1103     SnapToPoint (pointx, m_nHeight - 1 - pointy , tdp);
1104
1105     g_strStatus.Format("x:: %.1f  y:: %.1f  z:: %.1f", tdp[0], tdp[1], tdp[2]);
1106     g_pParentWnd->SetStatusText(1, g_strStatus);
1107
1108     // i need to generalize the point code.. having 3 flavors pretty much sucks..
1109     // once the new curve stuff looks like it is going to stick i will
1110     // rationalize this down to a single interface..
1111     if (PointMode())
1112     {
1113       if (g_pMovingPoint && HasCapture ())
1114       {
1115         bCrossHair = true;
1116         SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPoint->m_ptClip);
1117         g_pMovingPoint->UpdatePointPtr();
1118         Sys_UpdateWindows(XY | W_CAMERA_IFON);
1119       }
1120       else
1121       {
1122         g_pMovingPoint = NULL;
1123         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1124         int nDim2 = (m_nViewType == XY) ? 1 : 2;
1125         for (int n = 0; n < g_nPointCount; n++)
1126         {
1127           if ( fDiff(g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1128                fDiff(g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 )
1129           {
1130             bCrossHair = true;
1131             g_pMovingPoint = &g_PointPoints[n];
1132           }
1133         }
1134       }
1135     }
1136     else if (ClipMode())
1137     {
1138       if (g_pMovingClip && HasCapture ())
1139       {
1140         bCrossHair = true;
1141         SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingClip->m_ptClip);
1142         Sys_UpdateWindows(XY | W_CAMERA_IFON);
1143       }
1144       else
1145       {
1146         g_pMovingClip = NULL;
1147         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1148         int nDim2 = (m_nViewType == XY) ? 1 : 2;
1149         if (g_Clip1.Set())
1150         {
1151           if ( fDiff(g_Clip1.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1152                fDiff(g_Clip1.m_ptClip[nDim2], tdp[nDim2]) < 3 )
1153           {
1154             bCrossHair = true;
1155             g_pMovingClip = &g_Clip1;
1156           }
1157         }
1158         if (g_Clip2.Set())
1159         {
1160           if ( fDiff(g_Clip2.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1161                fDiff(g_Clip2.m_ptClip[nDim2], tdp[nDim2]) < 3 )
1162           {
1163             bCrossHair = true;
1164             g_pMovingClip = &g_Clip2;
1165           }
1166         }
1167         if (g_Clip3.Set())
1168         {
1169           if ( fDiff(g_Clip3.m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1170                fDiff(g_Clip3.m_ptClip[nDim2], tdp[nDim2]) < 3 )
1171           {
1172             bCrossHair = true;
1173             g_pMovingClip = &g_Clip3;
1174           }
1175         }
1176       }
1177       if (bCrossHair == false)
1178         XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags);
1179     }
1180     else if (PathMode())
1181     {
1182       if (g_pMovingPath && HasCapture ())
1183       {
1184         bCrossHair = true;
1185         SnapToPoint (pointx, m_nHeight - 1 - pointy , g_pMovingPath->m_ptClip);
1186         Sys_UpdateWindows(XY | W_CAMERA_IFON);
1187       }
1188       else
1189       {
1190         g_pMovingPath = NULL;
1191         int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1192         int nDim2 = (m_nViewType == XY) ? 1 : 2;
1193         for (int n = 0; n < g_nPathCount; n++)
1194         {
1195           if ( fDiff(g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1]) < 3 &&
1196                fDiff(g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2]) < 3 )
1197           {
1198             bCrossHair = true;
1199             g_pMovingPath = &g_PathPoints[n];
1200           }
1201         }
1202       }
1203     }
1204     else
1205     {
1206       XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags);
1207     }
1208   }
1209   else
1210   {
1211     XY_MouseMoved (pointx, m_nHeight - 1 - pointy , nFlags);
1212   }
1213
1214   if ((nFlags & MK_RBUTTON) == 0)
1215   {
1216     if (bCrossHair && !g_bWaitCursor)
1217     {
1218       GdkCursor *cursor;
1219       cursor = gdk_cursor_new (GDK_CROSSHAIR);
1220       gdk_window_set_cursor (m_pWidget->window, cursor);
1221       gdk_cursor_unref (cursor);
1222     }
1223     else
1224     {
1225       gdk_window_set_cursor (m_pWidget->window, NULL);
1226     }
1227   }
1228
1229   update_xor_rectangle_xy(m_XORRectangle);
1230 }
1231
1232 void XYWnd::OnMouseWheel(bool bUp)
1233 {
1234   if (bUp)
1235     g_pParentWnd->OnViewZoomin ();
1236   else
1237     g_pParentWnd->OnViewZoomout ();
1238
1239   int nUpdate = (g_PrefsDlg.m_bCamXYUpdate) ? (W_CAMERA | W_XY) : (W_CAMERA);
1240   Sys_UpdateWindows (nUpdate);
1241   g_pParentWnd->OnTimer ();
1242 }
1243
1244 void XYWnd::OnTimer ()
1245 {
1246   int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1247   int nDim2 = (m_nViewType == XY) ? 1 : 2;
1248   m_vOrigin[nDim1] += m_ptDragAdjX / m_fScale;
1249   m_vOrigin[nDim2] -= m_ptDragAdjY / m_fScale;
1250   Sys_UpdateWindows(W_XY | W_CAMERA);
1251   m_ptDragX += m_ptDragAdjX;
1252   m_ptDragY += m_ptDragAdjY;
1253   m_ptDragTotalX += m_ptDragAdjX;
1254   m_ptDragTotalY += m_ptDragAdjY;
1255   XY_MouseMoved (m_ptDragX, m_nHeight - 1 - m_ptDragY , m_nScrollFlags);
1256 }
1257
1258 void XYWnd::OnLButtonDown(guint32 flags, int pointx, int pointy)
1259 {
1260   g_pParentWnd->SetActiveXY(this);
1261   UndoCopy();
1262
1263   // plugin entities
1264   if (DispatchOnLButtonDown(flags, pointx, pointy))
1265     return;
1266
1267   if (ClipMode() && !RogueClipMode())
1268   {
1269     DropClipPoint(flags, pointx, pointy);
1270   }
1271   else if (PathMode())
1272   {
1273     DropPathPoint(flags, pointx, pointy);
1274   }
1275   else OriginalButtonDown(flags, pointx, pointy);
1276 }
1277
1278 void XYWnd::OnMButtonDown(guint32 flags, int pointx, int pointy)
1279 {
1280   OriginalButtonDown(flags, pointx, pointy);
1281 }
1282
1283 void XYWnd::OnRButtonDown(guint32 flags, int pointx, int pointy)
1284 {
1285   g_pParentWnd->SetActiveXY(this);
1286   m_ptDownX = pointx;
1287   m_ptDownY = pointy;
1288   m_bRButtonDown = true;
1289
1290   if (g_PrefsDlg.m_nMouseButtons == 3) // 3 button mouse
1291   {
1292     if (flags & MK_CONTROL)
1293     {
1294       if (ClipMode()) // already there?
1295         DropClipPoint(flags, pointx, pointy);
1296       else
1297       {
1298         SetClipMode(true);
1299         g_bRogueClipMode = true;
1300         DropClipPoint(flags, pointx, pointy);
1301       }
1302       return;
1303     }
1304   }
1305   OriginalButtonDown(flags, pointx, pointy);
1306 }
1307
1308 void XYWnd::OnLButtonUp(guint32 flags, int pointx, int pointy)
1309 {
1310   // plugin entities
1311   if (DispatchOnLButtonUp(flags, pointx, pointy))
1312     return;
1313
1314   if (ClipMode())
1315   {
1316     if (g_pMovingClip)
1317     {
1318       ReleaseCapture();
1319       g_pMovingClip = NULL;
1320     }
1321   }
1322   OriginalButtonUp(flags, pointx, pointy);
1323 }
1324
1325 void XYWnd::OnMButtonUp(guint32 flags, int pointx, int pointy)
1326 {
1327   OriginalButtonUp(flags, pointx, pointy);
1328 }
1329
1330 void XYWnd::OnRButtonUp(guint32 flags, int pointx, int pointy)
1331 {
1332   m_bRButtonDown = false;
1333   if ((pointx == m_ptDownX) && (pointy == m_ptDownY))   // mouse didn't move
1334   {
1335     bool bGo = true;
1336     if (Sys_AltDown ())
1337       bGo = false;
1338     if (flags & MK_CONTROL)
1339       bGo = false;
1340     if (flags & MK_SHIFT)
1341       bGo = false;
1342     if (bGo)
1343       HandleDrop();
1344   }
1345   OriginalButtonUp(flags, pointx, pointy);
1346 }
1347
1348 void XYWnd::XY_MouseDown (int x, int y, int buttons)
1349 {
1350   vec3_t    point;
1351   vec3_t    origin, dir, right, up;
1352
1353   m_nButtonstate = buttons;
1354   m_nPressx = x;
1355   m_nPressy = y;
1356   VectorCopy (vec3_origin, m_vPressdelta);
1357
1358   VectorClear(point);
1359   XY_ToPoint (x, y, point);
1360
1361   VectorCopy (point, origin);
1362
1363     VectorClear (dir);
1364     if (m_nViewType == XY) // view facing dir = negative Z
1365     {
1366         origin[2] = g_MaxWorldCoord;
1367         dir[2] = -1;
1368         right[0] = 1 / m_fScale;
1369         right[1] = 0;
1370         right[2] = 0;
1371         up[0] = 0;
1372         up[1] = 1 / m_fScale;
1373         up[2] = 0;
1374     }
1375     else if (m_nViewType == XZ)
1376     {
1377         origin[1] = g_MinWorldCoord; // view facing dir = positive Y
1378         dir[1] = 1;
1379         right[0] = 1 / m_fScale;
1380         right[1] = 0;
1381         right[2] = 0;
1382         up[0] = 0;
1383         up[1] = 0;
1384         up[2] = 1 / m_fScale;
1385     }
1386     else  // if (m_nViewType == YZ)  // view facing dir = negative X
1387     {
1388         origin[0] = g_MaxWorldCoord;
1389         dir[0] = -1;
1390         right[0] = 0;
1391         right[1] = 1 / m_fScale;
1392         right[2] = 0;
1393         up[0] = 0;
1394         up[1] = 0;
1395         up[2] = 1 / m_fScale;
1396     }
1397
1398   m_bPress_selection = (selected_brushes.next != &selected_brushes);
1399
1400   Sys_GetCursorPos(&m_ptCursorX, &m_ptCursorY);
1401
1402   // lbutton = manipulate selection
1403   // shift-LBUTTON = select
1404   if ( (buttons == MK_LBUTTON)
1405        || (buttons == (MK_LBUTTON | MK_SHIFT))
1406        || (buttons == (MK_LBUTTON | MK_CONTROL))
1407        || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) )
1408   {
1409     Patch_SetView( (m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ);
1410     Drag_Begin (x, y, buttons, right, up,   origin, dir);
1411     return;
1412   }
1413
1414   int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
1415
1416   // control mbutton = move camera
1417   if (m_nButtonstate == (MK_CONTROL|nMouseButton) )
1418   {
1419     VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin);
1420     Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY);
1421   }
1422
1423   // mbutton = angle camera
1424   if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
1425       (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON)))
1426   {
1427     VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point);
1428
1429     int n1 = (m_nViewType == XY) ? 1 : 2;
1430     int n2 = (m_nViewType == YZ) ? 1 : 0;
1431     int nAngle = (m_nViewType == XY) ? YAW : PITCH;
1432     if (point[n1] || point[n2])
1433     {
1434       g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]);
1435       Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY);
1436     }
1437   }
1438
1439   // shift mbutton = move z checker
1440   if (m_nButtonstate == (MK_SHIFT | nMouseButton))
1441   {
1442     if (RotateMode() || g_bPatchBendMode)
1443     {
1444       SnapToPoint (x, y, point);
1445       VectorCopyXY(point, g_vRotateOrigin);
1446       if (g_bPatchBendMode)
1447       {
1448         VectorCopy(point, g_vBendOrigin);
1449       }
1450       Sys_UpdateWindows (W_XY);
1451       return;
1452     }
1453     else
1454     {
1455       SnapToPoint (x, y, point);
1456       if (m_nViewType == XY)
1457       {
1458         z.origin[0] = point[0];
1459         z.origin[1] = point[1];
1460       }
1461       else if (m_nViewType == YZ)
1462       {
1463         z.origin[0] = point[1];
1464         z.origin[1] = point[2];
1465       }
1466       else
1467       {
1468         z.origin[0] = point[0];
1469         z.origin[1] = point[2];
1470       }
1471       Sys_UpdateWindows (W_XY_OVERLAY|W_Z);
1472       return;
1473     }
1474   }
1475
1476   update_xor_rectangle_xy(m_XORRectangle);
1477 }
1478
1479 void XYWnd::XY_MouseUp(int x, int y, int buttons)
1480 {
1481   Drag_MouseUp (buttons);
1482   if (!m_bPress_selection)
1483     Sys_UpdateWindows (W_ALL);
1484   m_nButtonstate = 0;
1485
1486   gdk_window_set_cursor (m_pWidget->window, NULL);
1487
1488   update_xor_rectangle_xy(m_XORRectangle);
1489 }
1490
1491 qboolean XYWnd::DragDelta (int x, int y, vec3_t move)
1492 {
1493   vec3_t xvec, yvec, delta;
1494   int    i;
1495
1496   xvec[0] = 1 / m_fScale;
1497   xvec[1] = xvec[2] = 0;
1498   yvec[1] = 1 / m_fScale;
1499   yvec[0] = yvec[2] = 0;
1500
1501   for (i=0 ; i<3 ; i++)
1502   {
1503     delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy);
1504     if (g_PrefsDlg.m_bSnap)
1505     {
1506       delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
1507     }
1508   }
1509   VectorSubtract (delta, m_vPressdelta, move);
1510   VectorCopy (delta, m_vPressdelta);
1511
1512   if (move[0] || move[1] || move[2])
1513     return true;
1514   return false;
1515 }
1516
1517 void XYWnd::HandleDrop()
1518 {
1519   if (g_PrefsDlg.m_bRightClick == false)
1520     return;
1521
1522   if (m_mnuDrop == NULL) // first time, load it up
1523   {
1524     int nID = ID_ENTITY_START;
1525     GtkWidget *menu, *menu_in_menu, *item, *submenu, *submenu_root;
1526
1527     menu = m_mnuDrop = gtk_menu_new ();
1528
1529     menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Select");
1530     create_menu_item_with_mnemonic (menu_in_menu, "Select Complete Tall",
1531               GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTCOMPLETETALL);
1532     create_menu_item_with_mnemonic (menu_in_menu, "Select Touching",
1533               GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTTOUCHING);
1534     create_menu_item_with_mnemonic (menu_in_menu, "Select Partial Tall",
1535               GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTPARTIALTALL);
1536     create_menu_item_with_mnemonic (menu_in_menu, "Select Inside",
1537               GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SELECTINSIDE);
1538     menu_separator (menu); nID++;
1539     // NOTE: temporary commented out until we put it back in for good (that is with actual features)
1540     /*
1541     menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Group",);
1542     create_menu_item_with_mnemonic (menu_in_menu, "Add to...",
1543               GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_ADDTO);
1544     create_menu_item_with_mnemonic (menu_in_menu, "Remove",
1545               GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_REMOVE);
1546     create_menu_item_with_mnemonic (menu_in_menu, "Name...",
1547               GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NAME);
1548     menu_separator (menu_in_menu); nID++;
1549     create_menu_item_with_mnemonic (menu_in_menu, "New Group...",
1550               GTK_SIGNAL_FUNC (HandleCommand), ID_DROP_GROUP_NEWGROUP);
1551     */
1552     create_menu_item_with_mnemonic (menu, "Ungroup Entity",
1553               GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_UNGROUPENTITY);
1554
1555     create_menu_item_with_mnemonic (menu, "Move into entity",
1556       GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MERGE);
1557     create_menu_item_with_mnemonic (menu, "Move into worldspawn",
1558       GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_SEPERATE);
1559
1560     create_menu_item_with_mnemonic (menu, "Make Detail",
1561               GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_DETAIL);
1562     create_menu_item_with_mnemonic (menu, "Make Structural",
1563               GTK_SIGNAL_FUNC (HandleCommand), ID_SELECTION_MAKE_STRUCTURAL);
1564     menu_separator (menu); nID++;
1565
1566     menu_in_menu = create_menu_in_menu_with_mnemonic (menu, "Smart Entities");
1567     create_menu_item_with_mnemonic (menu_in_menu, "Smart__Train",
1568               GTK_SIGNAL_FUNC (HandleCommand), nID++);
1569     menu_separator (menu); nID++;
1570
1571     submenu = NULL;
1572     submenu_root = NULL;
1573     eclass_t    *e;
1574     CString strActive;
1575     CString strLast;
1576     CString strName;
1577     for (e=eclass ; e ; e=e->next)
1578     {
1579       strLast = strName;
1580       strName = e->name;
1581       int n_ = strName.Find("_");
1582       if (n_ > 0)
1583       {
1584         CString strLeft = strName.Left(n_);
1585         CString strRight = strName.Right(strName.GetLength() - n_ - 1);
1586         if (strLeft == strActive) // this is a child
1587         {
1588           assert (submenu);
1589           item = gtk_menu_item_new_with_label (strName);
1590           gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand),
1591             GINT_TO_POINTER (nID++));
1592           gtk_widget_show (item);
1593           CheckMenuSplitting(submenu);
1594           gtk_menu_append (GTK_MENU (submenu), item);
1595         }
1596         else
1597         {
1598           if (submenu)
1599           {
1600             // this is submenu from previous main_item, hook it back
1601             // we use submenu_root cause we may have been cascading submenu
1602             item = gtk_menu_item_new_with_label (strActive);
1603             gtk_widget_show (item);
1604             gtk_menu_append (GTK_MENU (menu), item);
1605             gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root);
1606             g_ptrMenus.Add(submenu_root);
1607             submenu = NULL;
1608             submenu_root = NULL;
1609           }
1610           strActive = strLeft;
1611
1612           submenu = gtk_menu_new ();
1613           submenu_root = submenu;
1614           item = gtk_menu_item_new_with_label (strName);
1615           gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand),
1616             GINT_TO_POINTER (nID++));
1617           gtk_widget_show (item);
1618           gtk_menu_append (GTK_MENU (submenu), item);
1619         }
1620       }
1621       else
1622       {
1623         if (submenu)
1624         {
1625           // this is submenu from previous main_item, hook it back
1626           // we use submenu_root cause we may have been cascading submenu
1627           item = gtk_menu_item_new_with_label (strActive);
1628           gtk_widget_show (item);
1629           gtk_menu_append (GTK_MENU (menu), item);
1630           gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu_root);
1631           g_ptrMenus.Add(submenu_root);
1632           submenu = NULL;
1633           submenu_root = NULL;
1634         }
1635         strActive = "";
1636
1637         item = gtk_menu_item_new_with_label (strName);
1638         gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (HandleCommand),
1639           GINT_TO_POINTER (nID++));
1640         gtk_widget_show (item);
1641         gtk_menu_append (GTK_MENU (menu), item);
1642       }
1643     }
1644   }
1645
1646   gtk_menu_popup (GTK_MENU (m_mnuDrop), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME);
1647 }
1648
1649 /*
1650 ==============
1651 NewBrushDrag
1652 ==============
1653 */
1654 void XYWnd::NewBrushDrag (int x, int y)
1655 {
1656   vec3_t    mins, maxs, junk;
1657   int       i;
1658   float temp;
1659   brush_t   *n;
1660
1661   if (!DragDelta (x,y, junk))
1662     return;
1663
1664   // delete the current selection
1665   if (selected_brushes.next != &selected_brushes)
1666     Brush_Free (selected_brushes.next);
1667
1668   SnapToPoint (m_nPressx, m_nPressy, mins);
1669
1670   int nDim = (m_nViewType == XY) ? 2 : (m_nViewType == YZ) ? 0 : 1;
1671
1672   //++timo clean
1673 //  mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z / g_qeglobals.d_gridsize));
1674   mins[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_min[nDim]/g_qeglobals.d_gridsize));
1675
1676     SnapToPoint (x, y, maxs);
1677 //  maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z / g_qeglobals.d_gridsize));
1678   maxs[nDim] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_work_max[nDim]/g_qeglobals.d_gridsize));
1679   if (maxs[nDim] <= mins[nDim])
1680     maxs[nDim] = mins[nDim] + g_qeglobals.d_gridsize;
1681
1682   for (i=0 ; i<3 ; i++)
1683   {
1684     if (mins[i] == maxs[i])
1685       return;   // don't create a degenerate brush
1686     if (mins[i] > maxs[i])
1687     {
1688       temp = mins[i];
1689       mins[i] = maxs[i];
1690       maxs[i] = temp;
1691     }
1692   }
1693
1694   n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef);
1695   if (!n)
1696     return;
1697
1698   vec3_t vSize;
1699   VectorSubtract(maxs, mins, vSize);
1700   g_strStatus.Format("Size X:: %.1f  Y:: %.1f  Z:: %.1f", vSize[0], vSize[1], vSize[2]);
1701   g_pParentWnd->SetStatusText(2, g_strStatus);
1702
1703   Brush_AddToList (n, &selected_brushes);
1704
1705   Entity_LinkBrush (world_entity, n);
1706
1707   Brush_Build( n );
1708
1709   //    Sys_UpdateWindows (W_ALL);
1710   Sys_UpdateWindows (W_XY| W_CAMERA);
1711
1712 }
1713
1714 /*
1715 ==============
1716 XY_MouseMoved
1717 ==============
1718 */
1719 void XYWnd::XY_MouseMoved (int x, int y, int buttons)
1720 {
1721   vec3_t point;
1722
1723   if (!m_nButtonstate)
1724   {
1725     if (g_bCrossHairs)
1726     {
1727       Sys_UpdateWindows (W_XY | W_XY_OVERLAY);
1728     }
1729     return;
1730   }
1731
1732   // lbutton without selection = drag new brush
1733   if (m_nButtonstate == MK_LBUTTON && !m_bPress_selection && g_qeglobals.d_select_mode != sel_curvepoint && g_qeglobals.d_select_mode != sel_areatall)
1734   {
1735     NewBrushDrag (x, y);
1736     return;
1737   }
1738
1739   // lbutton (possibly with control and or shift)
1740   // with selection = drag selection
1741   if (m_nButtonstate & MK_LBUTTON)
1742   {
1743     Drag_MouseMoved (x, y, buttons);
1744     if(g_qeglobals.d_select_mode != sel_area)
1745       Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA_IFON | W_Z);
1746     return;
1747   }
1748
1749   int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
1750   // control mbutton = move camera
1751   if (m_nButtonstate == (MK_CONTROL|nMouseButton) )
1752   {
1753     SnapToPoint (x, y, point);
1754     VectorCopyXY(point, g_pParentWnd->GetCamWnd()->Camera()->origin);
1755     Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA);
1756     return;
1757   }
1758
1759   // shift mbutton = move z checker
1760   if (m_nButtonstate == (MK_SHIFT|nMouseButton) )
1761   {
1762     if (RotateMode() || g_bPatchBendMode)
1763     {
1764       SnapToPoint (x, y, point);
1765       VectorCopyXY(point, g_vRotateOrigin);
1766       if (g_bPatchBendMode)
1767       {
1768         VectorCopy(point, g_vBendOrigin);
1769       }
1770       Sys_UpdateWindows (W_XY);
1771       return;
1772     }
1773     else
1774     {
1775       SnapToPoint (x, y, point);
1776       if (m_nViewType == XY)
1777       {
1778         z.origin[0] = point[0];
1779         z.origin[1] = point[1];
1780       }
1781       else if (m_nViewType == YZ)
1782       {
1783         z.origin[0] = point[1];
1784         z.origin[1] = point[2];
1785       }
1786       else
1787       {
1788         z.origin[0] = point[0];
1789         z.origin[1] = point[2];
1790       }
1791     }
1792     Sys_UpdateWindows (W_XY_OVERLAY|W_Z);
1793     return;
1794   }
1795
1796   // mbutton = angle camera
1797   if ((g_PrefsDlg.m_nMouseButtons == 3 && m_nButtonstate == MK_MBUTTON) ||
1798       (g_PrefsDlg.m_nMouseButtons == 2 && m_nButtonstate == (MK_SHIFT|MK_CONTROL|MK_RBUTTON)))
1799   {
1800     SnapToPoint (x, y, point);
1801     VectorSubtract (point, g_pParentWnd->GetCamWnd()->Camera()->origin, point);
1802
1803     int n1 = (m_nViewType == XY) ? 1 : 2;
1804     int n2 = (m_nViewType == YZ) ? 1 : 0;
1805     int nAngle = (m_nViewType == XY) ? YAW : PITCH;
1806     if (point[n1] || point[n2])
1807     {
1808       g_pParentWnd->GetCamWnd()->Camera()->angles[nAngle] = 180/Q_PI*atan2 (point[n1], point[n2]);
1809       Sys_UpdateWindows (W_CAMERA_IFON|W_XY_OVERLAY);
1810     }
1811     return;
1812   }
1813
1814   // rbutton = drag xy origin
1815   if (m_nButtonstate == MK_RBUTTON)
1816   {
1817     Sys_GetCursorPos (&x, &y);
1818     if (x != m_ptCursorX || y != m_ptCursorY)
1819     {
1820       int nDim1 = (m_nViewType == YZ) ? 1 : 0;
1821       int nDim2 = (m_nViewType == XY) ? 1 : 2;
1822       m_vOrigin[nDim1] -= (x - m_ptCursorX) / m_fScale;
1823       m_vOrigin[nDim2] += (y - m_ptCursorY) / m_fScale;
1824       Sys_SetCursorPos (m_ptCursorX, m_ptCursorY);
1825
1826       // create an empty cursor
1827       if (!g_bWaitCursor)
1828       {
1829         GdkPixmap *pixmap;
1830         GdkBitmap *mask;
1831         char buffer [(32 * 32)/8];
1832         memset (buffer, 0, (32 * 32)/8);
1833         GdkColor white = {0, 0xffff, 0xffff, 0xffff};
1834         GdkColor black = {0, 0x0000, 0x0000, 0x0000};
1835         pixmap = gdk_bitmap_create_from_data (NULL, buffer, 32, 32);
1836         mask   = gdk_bitmap_create_from_data (NULL, buffer, 32, 32);
1837         GdkCursor *cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &white, &black, 1, 1);
1838         gdk_window_set_cursor (m_pWidget->window, cursor);
1839         gdk_cursor_unref (cursor);
1840         gdk_drawable_unref (pixmap);
1841         gdk_drawable_unref (mask);
1842       }
1843
1844       Sys_UpdateWindows (W_XY | W_XY_OVERLAY);
1845     }
1846     return;
1847   }
1848
1849   // zoom in/out
1850   if (m_nButtonstate == (MK_SHIFT | MK_RBUTTON))
1851   {
1852     Sys_GetCursorPos (&x, &y);
1853     if (y != m_ptCursorY)
1854     {
1855       if (abs (m_ptCursorY - y) > 10)
1856       {
1857         if (m_ptCursorY < y)
1858           g_pParentWnd->OnViewZoomout ();
1859         else
1860           g_pParentWnd->OnViewZoomin ();
1861
1862         Sys_SetCursorPos (m_ptCursorX, m_ptCursorY);
1863       }
1864     }
1865     return;
1866   }
1867 }
1868
1869 void XYWnd::OriginalButtonDown(guint32 nFlags, int pointx, int pointy)
1870 {
1871   SetFocus();
1872   SetCapture();
1873   XY_MouseDown (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags);
1874   m_nScrollFlags = nFlags;
1875 }
1876
1877 void XYWnd::OriginalButtonUp(guint32 nFlags, int pointx, int pointy)
1878 {
1879   XY_MouseUp (pointx, m_pWidget->allocation.height - 1 - pointy , nFlags);
1880   ReleaseCapture ();
1881 }
1882
1883 void XYWnd::DropClipPoint(guint32 nFlags, int pointx, int pointy)
1884 {
1885   if (g_pMovingClip)
1886   {
1887     SetCapture();
1888     SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingClip);
1889   }
1890   else
1891   {
1892     vec3_t* pPt = NULL;
1893     if (g_Clip1.Set() == false)
1894     {
1895       pPt = g_Clip1;
1896       g_Clip1.Set(true);
1897       g_Clip1.m_ptScreenX = pointx;
1898       g_Clip1.m_ptScreenY = pointy;
1899     }
1900     else
1901     if (g_Clip2.Set() == false)
1902     {
1903       pPt = g_Clip2;
1904       g_Clip2.Set(true);
1905       g_Clip2.m_ptScreenX = pointx;
1906       g_Clip2.m_ptScreenY = pointy;
1907     }
1908     else
1909     if (g_Clip3.Set() == false)
1910     {
1911       pPt = g_Clip3;
1912       g_Clip3.Set(true);
1913       g_Clip3.m_ptScreenX = pointx;
1914       g_Clip3.m_ptScreenY = pointy;
1915     }
1916     else
1917     {
1918       RetainClipMode(true);
1919       pPt = g_Clip1;
1920       g_Clip1.Set(true);
1921       g_Clip1.m_ptScreenX = pointx;
1922       g_Clip1.m_ptScreenY = pointy;
1923     }
1924     SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *pPt);
1925     // third coordinates for clip point: use d_work_max
1926     // Arnout: changed to use center of selection for clipping, saves level designers moving points all over the map
1927     // g_pParentWnd->ActiveXY()->GetViewType()
1928     // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY};
1929     int nViewType = g_pParentWnd->ActiveXY()->GetViewType();
1930     int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 );
1931     //(*pPt)[nDim] = g_qeglobals.d_work_max[nDim];
1932     vec3_t mid;
1933     Select_GetMid( mid );
1934     (*pPt)[nDim] = mid[nDim];
1935   }
1936   Sys_UpdateWindows(XY | W_CAMERA_IFON);
1937 }
1938
1939 void XYWnd::DropPathPoint(guint32 nFlags, int pointx, int pointy)
1940 {
1941   if (g_pMovingPath)
1942   {
1943     SetCapture();
1944     SnapToPoint (pointx, m_pWidget->allocation.height - 1 - pointy , *g_pMovingPath);
1945   }
1946   else
1947   {
1948     g_PathPoints[g_nPathCount].Set(true);
1949     g_PathPoints[g_nPathCount].m_ptScreenX = pointx;
1950     g_PathPoints[g_nPathCount].m_ptScreenY = pointy;
1951     SnapToPoint(pointx, m_pWidget->allocation.height - 1 - pointy, g_PathPoints[g_nPathCount]);
1952     // third coordinates for dropped point: use d_work_max
1953     // g_pParentWnd->ActiveXY()->GetViewType()
1954     // cf VIEWTYPE definition: enum VIEWTYPE {YZ, XZ, XY};
1955     int nViewType = g_pParentWnd->ActiveXY()->GetViewType();
1956     int nDim = (nViewType == YZ ) ? nDim = 0 : ( (nViewType == XZ) ? nDim = 1 : nDim = 2 );
1957     g_PathPoints[g_nPathCount].m_ptClip[nDim] = g_qeglobals.d_work_max[nDim];
1958
1959     g_nPathCount++;
1960     if (g_nPathCount == g_nPathLimit)
1961     {
1962       if (g_pPathFunc)
1963         g_pPathFunc(true, g_nPathCount);
1964       g_nPathCount = 0;
1965       g_bPathMode = false;
1966       g_pPathFunc = NULL;
1967     }
1968   }
1969   Sys_UpdateWindows(XY | W_CAMERA_IFON);
1970 }
1971
1972 // FIXME: AddPointPoint() redundant function never called
1973 #if 0
1974 void XYWnd::AddPointPoint(guint32 nFlags, vec3_t* pVec)
1975 {
1976   g_PointPoints[g_nPointCount].Set(true);
1977   //g_PointPoints[g_nPointCount].m_ptScreen = point;
1978   _VectorCopy(*pVec, g_PointPoints[g_nPointCount]);
1979   g_PointPoints[g_nPointCount].SetPointPtr(pVec);
1980   g_nPointCount++;
1981   Sys_UpdateWindows(XY | W_CAMERA_IFON);
1982 }
1983
1984 // FIXME: ProduceSplits() redundant function never called
1985 void XYWnd::ProduceSplits(brush_t** pFront, brush_t** pBack)
1986 {
1987   *pFront = NULL;
1988   *pBack = NULL;
1989   if (ClipMode())
1990   {
1991     if (g_Clip1.Set() && g_Clip2.Set())
1992     {
1993       face_t face;
1994       VectorCopy(g_Clip1.m_ptClip,face.planepts[0]);
1995       VectorCopy(g_Clip2.m_ptClip,face.planepts[1]);
1996       VectorCopy(g_Clip3.m_ptClip,face.planepts[2]);
1997       if (selected_brushes.next && (selected_brushes.next->next == &selected_brushes))
1998       {
1999         if (g_Clip3.Set() == false)
2000         {
2001           if (m_nViewType == XY)
2002           {
2003             face.planepts[0][2] = selected_brushes.next->mins[2];
2004             face.planepts[1][2] = selected_brushes.next->mins[2];
2005             face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
2006             face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
2007             face.planepts[2][2] = selected_brushes.next->maxs[2];
2008           }
2009           else if (m_nViewType == YZ)
2010           {
2011             face.planepts[0][0] = selected_brushes.next->mins[0];
2012             face.planepts[1][0] = selected_brushes.next->mins[0];
2013             face.planepts[2][1] = Betwixt(g_Clip1.m_ptClip[1], g_Clip2.m_ptClip[1]);
2014             face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
2015             face.planepts[2][0] = selected_brushes.next->maxs[0];
2016           }
2017           else
2018           {
2019             face.planepts[0][1] = selected_brushes.next->mins[1];
2020             face.planepts[1][1] = selected_brushes.next->mins[1];
2021             face.planepts[2][0] = Betwixt(g_Clip1.m_ptClip[0], g_Clip2.m_ptClip[0]);
2022             face.planepts[2][2] = Betwixt(g_Clip1.m_ptClip[2], g_Clip2.m_ptClip[2]);
2023             face.planepts[2][1] = selected_brushes.next->maxs[1];
2024           }
2025         }
2026
2027         Brush_SplitBrushByFace (selected_brushes.next, &face, pFront, pBack);
2028       }
2029
2030     }
2031   }
2032 }
2033 #endif
2034
2035 void XYWnd::PlanePointsFromClipPoints(vec3_t planepts[3], brush_t *pBrush)
2036 {
2037   VectorCopy(g_Clip1.m_ptClip,planepts[0]);
2038         VectorCopy(g_Clip2.m_ptClip,planepts[1]);
2039         VectorCopy(g_Clip3.m_ptClip,planepts[2]);
2040         if (g_Clip3.Set() == false)
2041         {
2042                 int n = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 2 : (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 0 : 1;
2043                 int x = (n == 0) ? 1 : 0;
2044                 int y = (n == 2) ? 1 : 2;
2045
2046                 if (n == 1) // on viewtype XZ, flip clip points
2047                 {
2048                 planepts[0][n] = pBrush->maxs[n];
2049                 planepts[1][n] = pBrush->maxs[n];
2050                 planepts[2][x] = g_Clip1.m_ptClip[x];
2051                 planepts[2][y] = g_Clip1.m_ptClip[y];
2052                 planepts[2][n] = pBrush->mins[n];
2053                 }
2054                 else
2055                 {
2056                 planepts[0][n] = pBrush->mins[n];
2057                 planepts[1][n] = pBrush->mins[n];
2058                 planepts[2][x] = g_Clip1.m_ptClip[x];
2059                 planepts[2][y] = g_Clip1.m_ptClip[y];
2060                 planepts[2][n] = pBrush->maxs[n];
2061                 }
2062         }
2063 }
2064
2065 void XYWnd::ProduceSplitLists()
2066 {
2067         bool bCaulk = false;
2068   int nFlags;
2069
2070         if (AnyPatchesSelected())
2071         {
2072                 Sys_Printf("Deselecting patches for clip operation.\n");
2073                 brush_t *next;
2074                 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = next)
2075                 {
2076                         next = pb->next;
2077                         if (pb->patchBrush)
2078                         {
2079                                 Brush_RemoveFromList (pb);
2080                                 Brush_AddToList (pb, &active_brushes);
2081                                 UpdatePatchInspector();
2082                         }
2083                 }
2084         // ydnar: update the window if any patches are selected
2085         Sys_UpdateWindows( XY | W_CAMERA_IFON );
2086         }
2087
2088         CleanList(&g_brFrontSplits);
2089         CleanList(&g_brBackSplits);
2090         g_brFrontSplits.next = &g_brFrontSplits;
2091         g_brBackSplits.next = &g_brBackSplits;
2092         if (ClipMode() && (g_Clip1.Set() && g_Clip2.Set()))
2093         {
2094                 brush_t* pBrush;
2095                 for (pBrush = selected_brushes.next ; pBrush != NULL && pBrush != &selected_brushes ; pBrush=pBrush->next)
2096                 {
2097                         brush_t* pFront = NULL;
2098                         brush_t* pBack = NULL;
2099
2100                         face_t face;
2101                         memset(&face,0,sizeof(face_t));
2102       PlanePointsFromClipPoints(face.planepts, pBrush);
2103
2104                         // decide wether caulking should be applied on the splits
2105       // FIXME: hack
2106       // this should take the first brush face, check shader for NODRAW, if it isn't nodraw then find the appropriate
2107       // common/ shader to use, out of solid+nodraw, nonsolid+nodraw, water+nodraw, lava+nodraw, nonsolid+nodraw+trans, water+nodraw+trans, lava+nodraw+trans.. and fog.. etc
2108       // or if none of those apply (unlikely), construct a new shader (shadername_nodraw) based on the shader of the first face, but with surfaceparm nodraw
2109                         if (g_PrefsDlg.m_bClipCaulk)
2110                         {
2111         nFlags = pBrush->brush_faces->pShader->getFlags();
2112                           if ((nFlags & QER_NODRAW) || (nFlags & QER_NONSOLID) || (nFlags & QER_WATER) || (nFlags & QER_LAVA) || (nFlags & QER_FOG)) // first face shader is anything other than solid AND opaque like caulk
2113                                         bCaulk = false; // use first face's shader for the splitting face
2114                                 else
2115                                         bCaulk = true; // use caulk
2116                         }
2117
2118                         Brush_SplitBrushByFace (pBrush, &face, &pFront, &pBack, bCaulk);
2119                         if (pBack)
2120                                 Brush_AddToList(pBack, &g_brBackSplits);
2121                         if (pFront)
2122                                 Brush_AddToList(pFront, &g_brFrontSplits);
2123
2124                 }
2125         }
2126 }
2127
2128 void XYWnd::XY_Init()
2129 {
2130   m_vOrigin[0] = 0;
2131   m_vOrigin[1] = 20;
2132   m_vOrigin[2] = 46;
2133   m_fScale = 1;
2134 }
2135
2136 void XYWnd::SnapToPoint (int x, int y, vec3_t point)
2137 {
2138   if (g_PrefsDlg.m_bSnap)
2139   {
2140     XY_ToGridPoint(x, y, point);
2141   }
2142   else
2143   {
2144     XY_ToPoint(x, y, point);
2145   }
2146 }
2147
2148 // TTimo: watch it, this doesn't init one of the 3 coords
2149 void XYWnd::XY_ToPoint (int x, int y, vec3_t point)
2150 {
2151   float fx = x;
2152   float fy = y;
2153   float fw = m_nWidth;
2154   float fh = m_nHeight;
2155   if (m_nViewType == XY)
2156   {
2157     point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
2158     point[1] = m_vOrigin[1] + (fy - fh / 2) / m_fScale;
2159   }
2160   else if (m_nViewType == YZ)
2161   {
2162     point[1] = m_vOrigin[1] + (fx - fw / 2) / m_fScale;
2163     point[2] = m_vOrigin[2] + (fy - fh / 2 ) / m_fScale;
2164   }
2165   else
2166   {
2167     point[0] = m_vOrigin[0] + (fx - fw / 2) / m_fScale;
2168     point[2] = m_vOrigin[2] + (fy - fh / 2) / m_fScale;
2169   }
2170 }
2171
2172 void XYWnd::XY_ToGridPoint (int x, int y, vec3_t point)
2173 {
2174   if (m_nViewType == XY)
2175   {
2176     point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
2177     point[1] = m_vOrigin[1] + (y - m_nHeight / 2) / m_fScale;
2178     point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2179     point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2180   }
2181   else if (m_nViewType == YZ)
2182   {
2183     point[1] = m_vOrigin[1] + (x - m_nWidth / 2) / m_fScale;
2184     point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
2185     point[1] = floor(point[1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2186     point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2187   }
2188   else
2189   {
2190     point[0] = m_vOrigin[0] + (x - m_nWidth / 2) / m_fScale;
2191     point[2] = m_vOrigin[2] + (y - m_nHeight / 2) / m_fScale;
2192     point[0] = floor(point[0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2193     point[2] = floor(point[2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
2194   }
2195 }
2196
2197 /*
2198 ============================================================================
2199
2200 DRAWING
2201
2202 ============================================================================
2203 */
2204
2205 /*
2206 ==============
2207 XY_DrawGrid
2208 ==============
2209 */
2210 void XYWnd::XY_DrawGrid()
2211 {
2212   float x, y, xb, xe, yb, ye;
2213   float w, h;
2214   char  text[32];
2215   int   step, stepx, stepy, colour;
2216   step = stepx = stepy = MAX (64, (int)g_qeglobals.d_gridsize);
2217
2218   /*
2219   int stepSize = (int)(8 / m_fScale);
2220   if (stepSize > step)
2221   {
2222     int i;
2223     for (i = 1; i < stepSize; i <<= 1)
2224       ;
2225     step = i;
2226   }
2227   */
2228
2229   //Sys_Printf("scale: %f\n", m_fScale);
2230   //Sys_Printf("step before: %i\n", step);
2231   //Sys_Printf("scaled step: %f\n", step * m_fScale);
2232   while ((step * m_fScale) < 4.0f) // make sure major grid spacing is at least 4 pixels on the screen
2233     step *= 8;
2234   //Sys_Printf("step after: %i\n", step);
2235   while ((stepx * m_fScale) < 40.0f) // text step x must be at least 40 pixels
2236     stepx *= 2;
2237   while ((stepy * m_fScale) < 40.0f) // text step y must be at least 40 pixels
2238     stepy *= 2;
2239
2240   qglDisable(GL_TEXTURE_2D);
2241   qglDisable(GL_TEXTURE_1D);
2242   qglDisable(GL_DEPTH_TEST);
2243   qglDisable(GL_BLEND);
2244
2245   w = (m_nWidth / 2 / m_fScale);
2246   h = (m_nHeight / 2 / m_fScale);
2247
2248   int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2249   int nDim2 = (m_nViewType == XY) ? 1 : 2;
2250
2251   xb = m_vOrigin[nDim1] - w;
2252   if (xb < region_mins[nDim1])
2253     xb = region_mins[nDim1];
2254   xb = step * floor (xb/step);
2255
2256   xe = m_vOrigin[nDim1] + w;
2257   if (xe > region_maxs[nDim1])
2258     xe = region_maxs[nDim1];
2259   xe = step * ceil (xe/step);
2260
2261   yb = m_vOrigin[nDim2] - h;
2262   if (yb < region_mins[nDim2])
2263     yb = region_mins[nDim2];
2264   yb = step * floor (yb/step);
2265
2266   ye = m_vOrigin[nDim2] + h;
2267   if (ye > region_maxs[nDim2])
2268     ye = region_maxs[nDim2];
2269   ye = step * ceil (ye/step);
2270
2271 #define COLORS_DIFFER(a,b) \
2272   (g_qeglobals.d_savedinfo.colors[a][0] != g_qeglobals.d_savedinfo.colors[b][0] || \
2273    g_qeglobals.d_savedinfo.colors[a][1] != g_qeglobals.d_savedinfo.colors[b][1] || \
2274    g_qeglobals.d_savedinfo.colors[a][2] != g_qeglobals.d_savedinfo.colors[b][2])
2275
2276   // djbob
2277   // draw minor blocks
2278   if (m_fScale > .1 && g_qeglobals.d_showgrid && g_qeglobals.d_gridsize * m_fScale >= 4)
2279   {
2280     if (g_qeglobals.d_gridsize < 1)
2281       colour = COLOR_GRIDMINOR_ALT;
2282     else
2283       colour = COLOR_GRIDMINOR;
2284
2285     if (COLORS_DIFFER(colour, COLOR_GRIDBACK))
2286     {
2287       qglColor3fv(g_qeglobals.d_savedinfo.colors[colour]);
2288
2289       qglBegin (GL_LINES);
2290       for (x=xb ; x<xe ; x += g_qeglobals.d_gridsize)
2291       {
2292         if (!((int)x & (step-1)) && !((int)x - x))
2293           continue;
2294         qglVertex2f (x, yb);
2295         qglVertex2f (x, ye);
2296       }
2297       for (y=yb ; y<ye ; y+=g_qeglobals.d_gridsize)
2298       {
2299         if (!((int)y & (step-1))  && !((int)y - y))
2300           continue;
2301         qglVertex2f (xb, y);
2302         qglVertex2f (xe, y);
2303       }
2304       qglEnd ();
2305     }
2306   }
2307
2308   if(g_qeglobals.d_gridsize < 1)
2309     colour = COLOR_GRIDMAJOR_ALT;
2310   else
2311     colour = COLOR_GRIDMAJOR;
2312
2313   // draw major blocks
2314   if (COLORS_DIFFER(colour, COLOR_GRIDBACK))
2315     qglColor3fv(g_qeglobals.d_savedinfo.colors[colour]);
2316
2317   if ( g_qeglobals.d_showgrid )
2318   {
2319     qglBegin (GL_LINES);
2320     for (x=xb ; x<=xe ; x+=step)
2321     {
2322       qglVertex2f (x, yb);
2323       qglVertex2f (x, ye);
2324     }
2325     for (y=yb ; y<=ye ; y+=step)
2326     {
2327       qglVertex2f (xb, y);
2328       qglVertex2f (xe, y);
2329     }
2330     qglEnd();
2331   }
2332
2333   // draw coordinate text if needed
2334   if ( g_qeglobals.d_savedinfo.show_coordinates)
2335   {
2336     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT]);
2337
2338     // Pixels between top of label for vertical grid line and top of grid view window.
2339     // Note: There is currently a bug where the top few pixels of the grid view are hidden
2340     // under the border.  So you should add about 5 to the desired value here.  However,
2341     // the font ascent reaches higher than all digits, so you can subtract a few from the final
2342     // number.
2343     const int pixelsTopCushion = 4;
2344
2345     // Pixels between left of label and
2346     //   - left of grid view window (for horizontal grid line label) or
2347     //   - drawn vertical grid line (for vertical grid line label).
2348     const int pixelsLeftCushion = 2; // IMPORTANT!  Must be at least 1 otherwise labels might not be drawn
2349                                      // because the origin of the text might be off screen due to rounding.
2350
2351     // Pixels between baseline of horizontal grid line label and drawn horizontal grid line.
2352     const int pixelsButtomCushion = 2;
2353
2354     float yPosLabelsTop = m_vOrigin[nDim2] + h - (gtk_glwidget_font_ascent() + pixelsTopCushion) / m_fScale;
2355     float xPosLabelsLeft = m_vOrigin[nDim1] - w + pixelsLeftCushion / m_fScale;
2356     float leftCushion = pixelsLeftCushion / m_fScale;
2357     float bottomOffset = (pixelsButtomCushion - gtk_glwidget_font_descent()) / m_fScale;
2358
2359     // This renders the numbers along varying X on top of the grid view (labels vertical grid lines).
2360     for (x = xb - ((int) xb) % stepx; x <= xe; x += stepx) {
2361       qglRasterPos2f(x + leftCushion, yPosLabelsTop);
2362       sprintf(text, "%i", (int) x);
2363       gtk_glwidget_print_string(text);
2364     }
2365
2366     // This renders the numbers along varying Y on the left of the grid view (labels horizontal grid lines).
2367     for (y = yb - ((int) yb) % stepy; y <= ye; y += stepy) {
2368       qglRasterPos2f(xPosLabelsLeft, y + bottomOffset);
2369       sprintf(text, "%i", (int) y);
2370       gtk_glwidget_print_string(text);
2371     }
2372
2373     if (Active())
2374       qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME]);
2375
2376     // we do this part (the old way) only if show_axis is disabled
2377     if (!g_qeglobals.d_savedinfo.show_axis)
2378     {
2379       qglRasterPos2f ( m_vOrigin[nDim1] - w + 35 / m_fScale, m_vOrigin[nDim2] + h - 20 / m_fScale );
2380
2381       char cView[20];
2382       if (m_nViewType == XY)
2383         strcpy(cView, "XY Top");
2384       else
2385         if (m_nViewType == XZ)
2386           strcpy(cView, "XZ Front");
2387         else
2388           strcpy(cView, "YZ Side");
2389
2390         gtk_glwidget_print_string(cView);
2391     }
2392   }
2393
2394   if ( g_qeglobals.d_savedinfo.show_axis)
2395   {
2396     // draw two lines with corresponding axis colors to highlight current view
2397     // horizontal line: nDim1 color
2398     qglLineWidth(2);
2399     qglBegin( GL_LINES );
2400     qglColor3fv (g_qeglobals.d_savedinfo.AxisColors[nDim1]);
2401     qglVertex2f( m_vOrigin[nDim1] - w + 40 / m_fScale, m_vOrigin[nDim2] + h - 45 / m_fScale );
2402     qglVertex2f( m_vOrigin[nDim1] - w + 65 / m_fScale, m_vOrigin[nDim2] + h - 45 / m_fScale );
2403     qglVertex2f( 0, 0 );
2404     qglVertex2f( 32 / m_fScale, 0 );
2405     qglColor3fv (g_qeglobals.d_savedinfo.AxisColors[nDim2]);
2406     qglVertex2f( m_vOrigin[nDim1] - w + 40 / m_fScale, m_vOrigin[nDim2] + h - 45 / m_fScale );
2407     qglVertex2f( m_vOrigin[nDim1] - w + 40 / m_fScale, m_vOrigin[nDim2] + h - 20 / m_fScale );
2408     qglVertex2f( 0, 0 );
2409     qglVertex2f( 0, 32 / m_fScale );
2410     qglEnd();
2411     qglLineWidth(1);
2412     // now print axis symbols
2413     qglColor3fv (g_qeglobals.d_savedinfo.AxisColors[nDim1]);
2414     qglRasterPos2f ( m_vOrigin[nDim1] - w + 55 / m_fScale, m_vOrigin[nDim2] + h - 55 / m_fScale );
2415     gtk_glwidget_print_char(g_AxisName[nDim1]);
2416     qglRasterPos2f (28 / m_fScale, -10 / m_fScale );
2417     gtk_glwidget_print_char(g_AxisName[nDim1]);
2418     qglColor3fv (g_qeglobals.d_savedinfo.AxisColors[nDim2]);
2419     qglRasterPos2f ( m_vOrigin[nDim1] - w + 25 / m_fScale, m_vOrigin[nDim2] + h - 30 / m_fScale );
2420     gtk_glwidget_print_char(g_AxisName[nDim2]);
2421     qglRasterPos2f ( -10 / m_fScale, 28 / m_fScale );
2422     gtk_glwidget_print_char(g_AxisName[nDim2]);
2423
2424   }
2425
2426   // show current work zone?
2427   // the work zone is used to place dropped points and brushes
2428   if (g_qeglobals.d_show_work)
2429   {
2430     qglColor3f( 1.0f, 0.0f, 0.0f );
2431     qglBegin( GL_LINES );
2432     qglVertex2f( xb, g_qeglobals.d_work_min[nDim2] );
2433     qglVertex2f( xe, g_qeglobals.d_work_min[nDim2] );
2434     qglVertex2f( xb, g_qeglobals.d_work_max[nDim2] );
2435     qglVertex2f( xe, g_qeglobals.d_work_max[nDim2] );
2436     qglVertex2f( g_qeglobals.d_work_min[nDim1], yb );
2437     qglVertex2f( g_qeglobals.d_work_min[nDim1], ye );
2438     qglVertex2f( g_qeglobals.d_work_max[nDim1], yb );
2439     qglVertex2f( g_qeglobals.d_work_max[nDim1], ye );
2440     qglEnd();
2441   }
2442 }
2443
2444 /*
2445 ==============
2446 XY_DrawBlockGrid
2447 ==============
2448 */
2449 void XYWnd::XY_DrawBlockGrid()
2450 {
2451   const char *value = ValueForKey( world_entity, "_blocksize" );
2452   if (strlen(value))
2453         sscanf( value, "%i", &g_qeglobals.blockSize );
2454
2455   if (!g_qeglobals.blockSize || g_qeglobals.blockSize > 65536 || g_qeglobals.blockSize < 1024)
2456           // don't use custom blocksize if it is less than the default, or greater than the maximum world coordinate
2457         g_qeglobals.blockSize = 1024;
2458
2459   float x, y, xb, xe, yb, ye;
2460   float         w, h;
2461   char  text[32];
2462
2463   qglDisable(GL_TEXTURE_2D);
2464   qglDisable(GL_TEXTURE_1D);
2465   qglDisable(GL_DEPTH_TEST);
2466   qglDisable(GL_BLEND);
2467
2468   w = (m_nWidth / 2 / m_fScale);
2469   h = (m_nHeight / 2 / m_fScale);
2470
2471   int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2472   int nDim2 = (m_nViewType == XY) ? 1 : 2;
2473
2474   xb = m_vOrigin[nDim1] - w;
2475   if (xb < region_mins[nDim1])
2476     xb = region_mins[nDim1];
2477   xb = g_qeglobals.blockSize * floor (xb/g_qeglobals.blockSize);
2478
2479   xe = m_vOrigin[nDim1] + w;
2480   if (xe > region_maxs[nDim1])
2481     xe = region_maxs[nDim1];
2482   xe = g_qeglobals.blockSize * ceil (xe/g_qeglobals.blockSize);
2483
2484   yb = m_vOrigin[nDim2] - h;
2485   if (yb < region_mins[nDim2])
2486     yb = region_mins[nDim2];
2487   yb = g_qeglobals.blockSize * floor (yb/g_qeglobals.blockSize);
2488
2489   ye = m_vOrigin[nDim2] + h;
2490   if (ye > region_maxs[nDim2])
2491     ye = region_maxs[nDim2];
2492   ye = g_qeglobals.blockSize * ceil (ye/g_qeglobals.blockSize);
2493
2494   // draw major blocks
2495
2496   qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK]);
2497   qglLineWidth (2);
2498
2499   qglBegin (GL_LINES);
2500
2501   for (x=xb ; x<=xe ; x+=g_qeglobals.blockSize)
2502   {
2503     qglVertex2f (x, yb);
2504     qglVertex2f (x, ye);
2505   }
2506
2507   if (m_nViewType == XY)
2508   {
2509         for (y=yb ; y<=ye ; y+=g_qeglobals.blockSize)
2510         {
2511                 qglVertex2f (xb, y);
2512                 qglVertex2f (xe, y);
2513         }
2514   }
2515
2516   qglEnd ();
2517   qglLineWidth (1);
2518
2519   // draw coordinate text if needed
2520
2521   if (m_nViewType == XY && m_fScale > .1)
2522   {
2523         for (x=xb ; x<xe ; x+=g_qeglobals.blockSize)
2524                 for (y=yb ; y<ye ; y+=g_qeglobals.blockSize)
2525                 {
2526                         qglRasterPos2f (x+(g_qeglobals.blockSize/2), y+(g_qeglobals.blockSize/2));
2527                         sprintf (text, "%i,%i",(int)floor(x/g_qeglobals.blockSize), (int)floor(y/g_qeglobals.blockSize) );
2528                         gtk_glwidget_print_string(text);
2529                 }
2530   }
2531
2532   qglColor4f(0, 0, 0, 0);
2533 }
2534
2535 void XYWnd::DrawRotateIcon()
2536 {
2537   float x, y, a, b;
2538
2539   a = 4.0 / m_fScale;  // compensate for zoom level
2540   b = 6.0 / m_fScale;
2541
2542   if (m_nViewType == XY)
2543   {
2544     x = g_vRotateOrigin[0];
2545     y = g_vRotateOrigin[1];
2546   }
2547   else if (m_nViewType == YZ)
2548   {
2549     x = g_vRotateOrigin[1];
2550     y = g_vRotateOrigin[2];
2551   }
2552   else
2553   {
2554     x = g_vRotateOrigin[0];
2555     y = g_vRotateOrigin[2];
2556   }
2557
2558   qglEnable (GL_BLEND);
2559   qglDisable (GL_TEXTURE_2D);
2560   qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
2561   qglDisable (GL_CULL_FACE);
2562   qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2563   qglColor4f (0.8f, 0.1f, 0.9f, 0.25f);
2564
2565   qglBegin(GL_QUADS);
2566   qglVertex3f (x-a,y-a,0);
2567   qglVertex3f (x+a,y-a,0);
2568   qglVertex3f (x+a,y+a,0);
2569   qglVertex3f (x-a,y+a,0);
2570   qglEnd ();
2571   qglDisable (GL_BLEND);
2572
2573   qglColor4f (1.0f, 0.2f, 1.0f, 1.f);
2574   qglBegin(GL_POINTS);
2575   qglVertex3f (x,y,0);
2576   qglEnd ();
2577
2578 #if 0
2579   qglBegin(GL_LINES);
2580   qglVertex3f (x-b,y+b,0);
2581   qglVertex3f (x+b,y+b,0);
2582   qglVertex3f (x-b,y-b,0);
2583   qglVertex3f (x+b,y-b,0);
2584   qglEnd ();
2585 #endif
2586
2587 }
2588
2589 void XYWnd::DrawCameraIcon()
2590 {
2591   float x, y, a, fov, box;
2592
2593   fov = 48 / m_fScale;
2594   box = 16 / m_fScale;
2595
2596   if (m_nViewType == XY)
2597   {
2598     x = g_pParentWnd->GetCamWnd()->Camera()->origin[0];
2599     y = g_pParentWnd->GetCamWnd()->Camera()->origin[1];
2600     a = g_pParentWnd->GetCamWnd()->Camera()->angles[YAW]/180*Q_PI;
2601   }
2602   else if (m_nViewType == YZ)
2603   {
2604     x = g_pParentWnd->GetCamWnd()->Camera()->origin[1];
2605     y = g_pParentWnd->GetCamWnd()->Camera()->origin[2];
2606     a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI;
2607   }
2608   else
2609   {
2610     x = g_pParentWnd->GetCamWnd()->Camera()->origin[0];
2611     y = g_pParentWnd->GetCamWnd()->Camera()->origin[2];
2612     a = g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH]/180*Q_PI;
2613   }
2614
2615   qglColor3f (0.0, 0.0, 1.0);
2616   qglBegin(GL_LINE_STRIP);
2617   qglVertex3f (x-box,y,0);
2618   qglVertex3f (x,y+(box/2),0);
2619   qglVertex3f (x+box,y,0);
2620   qglVertex3f (x,y-(box/2),0);
2621   qglVertex3f (x-box,y,0);
2622   qglVertex3f (x+box,y,0);
2623   qglEnd ();
2624
2625   qglBegin(GL_LINE_STRIP);
2626   qglVertex3f (x+fov*cos(a+Q_PI/4), y+fov*sin(a+Q_PI/4), 0);
2627   qglVertex3f (x, y, 0);
2628   qglVertex3f (x+fov*cos(a-Q_PI/4), y+fov*sin(a-Q_PI/4), 0);
2629   qglEnd ();
2630
2631 }
2632
2633 void XYWnd::DrawZIcon (void)
2634 {
2635   if (m_nViewType == XY)
2636   {
2637     float x = z.origin[0];
2638     float y = z.origin[1];
2639         float zdim = 8 / m_fScale;
2640     qglEnable (GL_BLEND);
2641     qglDisable (GL_TEXTURE_2D);
2642     qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
2643     qglDisable (GL_CULL_FACE);
2644     qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2645     qglColor4f (0.0, 0.0, 1.0, 0.25);
2646     qglBegin(GL_QUADS);
2647     qglVertex3f (x-zdim,y-zdim,0);
2648     qglVertex3f (x+zdim,y-zdim,0);
2649     qglVertex3f (x+zdim,y+zdim,0);
2650     qglVertex3f (x-zdim,y+zdim,0);
2651     qglEnd ();
2652     qglDisable (GL_BLEND);
2653
2654     qglColor4f (0.0, 0.0, 1.0, 1);
2655
2656     qglBegin(GL_LINE_LOOP);
2657     qglVertex3f (x-zdim,y-zdim,0);
2658     qglVertex3f (x+zdim,y-zdim,0);
2659     qglVertex3f (x+zdim,y+zdim,0);
2660     qglVertex3f (x-zdim,y+zdim,0);
2661     qglEnd ();
2662
2663     qglBegin(GL_LINE_STRIP);
2664     qglVertex3f (x-(zdim/2),y+(zdim/2),0);
2665     qglVertex3f (x+(zdim/2),y+(zdim/2),0);
2666     qglVertex3f (x-(zdim/2),y-(zdim/2),0);
2667     qglVertex3f (x+(zdim/2),y-(zdim/2),0);
2668     qglEnd ();
2669   }
2670 }
2671
2672 // can be greatly simplified but per usual i am in a hurry
2673 // which is not an excuse, just a fact
2674 void XYWnd::PaintSizeInfo(int nDim1, int nDim2, vec3_t vMinBounds, vec3_t vMaxBounds)
2675 {
2676   const char* g_pDimStrings[] = {"x:%.f", "y:%.f", "z:%.f"};
2677   const char* g_pOrgStrings[] = {"(x:%.f  y:%.f)", "(x:%.f  z:%.f)", "(y:%.f  z:%.f)"};
2678
2679   CString g_strDim;
2680
2681   vec3_t vSize;
2682   VectorSubtract(vMaxBounds, vMinBounds, vSize);
2683
2684   qglColor3f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0] * .65,
2685              g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1] * .65,
2686              g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2] * .65);
2687
2688   if (m_nViewType == XY)
2689   {
2690     qglBegin (GL_LINES);
2691
2692     qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f  / m_fScale, 0.0f);
2693     qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
2694
2695     qglVertex3f(vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f  / m_fScale, 0.0f);
2696     qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f  / m_fScale, 0.0f);
2697
2698     qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f  / m_fScale, 0.0f);
2699     qglVertex3f(vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f);
2700
2701
2702     qglVertex3f(vMaxBounds[nDim1] + 6.0f  / m_fScale, vMinBounds[nDim2], 0.0f);
2703     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, vMinBounds[nDim2], 0.0f);
2704
2705     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, vMinBounds[nDim2], 0.0f);
2706     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, vMaxBounds[nDim2], 0.0f);
2707
2708     qglVertex3f(vMaxBounds[nDim1] + 6.0f  / m_fScale, vMaxBounds[nDim2], 0.0f);
2709     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, vMaxBounds[nDim2], 0.0f);
2710
2711     qglEnd();
2712
2713     qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]),  vMinBounds[nDim2] - 20.0  / m_fScale, 0.0f);
2714     g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
2715     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2716
2717     qglRasterPos3f (vMaxBounds[nDim1] + 16.0  / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]), 0.0f);
2718     g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
2719     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2720
2721     qglRasterPos3f (vMinBounds[nDim1] + 4, vMaxBounds[nDim2] + 8 / m_fScale, 0.0f);
2722     g_strDim.Format(g_pOrgStrings[0], vMinBounds[nDim1], vMaxBounds[nDim2]);
2723     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2724   }
2725   else if (m_nViewType == XZ)
2726   {
2727     qglBegin (GL_LINES);
2728
2729     qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f  / m_fScale);
2730     qglVertex3f(vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale);
2731
2732     qglVertex3f(vMinBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f  / m_fScale);
2733     qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f  / m_fScale);
2734
2735     qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 6.0f  / m_fScale);
2736     qglVertex3f(vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale);
2737
2738
2739     qglVertex3f(vMaxBounds[nDim1] + 6.0f  / m_fScale, 0,vMinBounds[nDim2]);
2740     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, 0,vMinBounds[nDim2]);
2741
2742     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, 0,vMinBounds[nDim2]);
2743     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, 0,vMaxBounds[nDim2]);
2744
2745     qglVertex3f(vMaxBounds[nDim1] + 6.0f  / m_fScale, 0,vMaxBounds[nDim2]);
2746     qglVertex3f(vMaxBounds[nDim1] + 10.0f  / m_fScale, 0,vMaxBounds[nDim2]);
2747
2748     qglEnd();
2749
2750     qglRasterPos3f (Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]), 0, vMinBounds[nDim2] - 20.0  / m_fScale);
2751     g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
2752     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2753
2754     qglRasterPos3f (vMaxBounds[nDim1] + 16.0  / m_fScale, 0, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
2755     g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
2756     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2757
2758     qglRasterPos3f (vMinBounds[nDim1] + 4, 0, vMaxBounds[nDim2] + 8 / m_fScale);
2759     g_strDim.Format(g_pOrgStrings[1], vMinBounds[nDim1], vMaxBounds[nDim2]);
2760     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2761   }
2762   else
2763   {
2764     qglBegin (GL_LINES);
2765
2766     qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f  / m_fScale);
2767     qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
2768
2769     qglVertex3f(0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f  / m_fScale);
2770     qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f  / m_fScale);
2771
2772     qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f  / m_fScale);
2773     qglVertex3f(0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale);
2774
2775
2776     qglVertex3f(0, vMaxBounds[nDim1] + 6.0f  / m_fScale, vMinBounds[nDim2]);
2777     qglVertex3f(0, vMaxBounds[nDim1] + 10.0f  / m_fScale, vMinBounds[nDim2]);
2778
2779     qglVertex3f(0, vMaxBounds[nDim1] + 10.0f  / m_fScale, vMinBounds[nDim2]);
2780     qglVertex3f(0, vMaxBounds[nDim1] + 10.0f  / m_fScale, vMaxBounds[nDim2]);
2781
2782     qglVertex3f(0, vMaxBounds[nDim1] + 6.0f  / m_fScale, vMaxBounds[nDim2]);
2783     qglVertex3f(0, vMaxBounds[nDim1] + 10.0f  / m_fScale, vMaxBounds[nDim2]);
2784
2785     qglEnd();
2786
2787     qglRasterPos3f (0, Betwixt(vMinBounds[nDim1], vMaxBounds[nDim1]),  vMinBounds[nDim2] - 20.0  / m_fScale);
2788     g_strDim.Format(g_pDimStrings[nDim1], vSize[nDim1]);
2789     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2790
2791     qglRasterPos3f (0, vMaxBounds[nDim1] + 16.0  / m_fScale, Betwixt(vMinBounds[nDim2], vMaxBounds[nDim2]));
2792     g_strDim.Format(g_pDimStrings[nDim2], vSize[nDim2]);
2793     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2794
2795     qglRasterPos3f (0, vMinBounds[nDim1] + 4.0, vMaxBounds[nDim2] + 8 / m_fScale);
2796     g_strDim.Format(g_pOrgStrings[2], vMinBounds[nDim1], vMaxBounds[nDim2]);
2797     gtk_glwidget_print_string((char *) g_strDim.GetBuffer());
2798   }
2799 }
2800
2801 /*
2802 ==============
2803 XY_Draw
2804 ==============
2805 */
2806 #define ALT_POINT_SIZE 4
2807 // Alternative to GL_POINTS (for; vertex handles, patch handles, clip points, path points)
2808 void DrawAlternatePoint(vec3_t v, float scale)
2809 {
2810   if(scale == 0)
2811   {
2812     scale = g_pParentWnd->GetXYWnd()->Scale();
2813     //scale = g_qeglobals.d_xyOld.scale;
2814   }
2815
2816   // ugly gl_line cross
2817   qglVertex3f    ( v[0]+(ALT_POINT_SIZE/scale), v[1], v[2] );
2818   qglVertex3f    ( v[0]-(ALT_POINT_SIZE/scale), v[1], v[2] );
2819   qglVertex3f    ( v[0], v[1]+(ALT_POINT_SIZE/scale), v[2] );
2820   qglVertex3f    ( v[0], v[1]-(ALT_POINT_SIZE/scale), v[2] );
2821   qglVertex3f    ( v[0], v[1], v[2]+(ALT_POINT_SIZE/scale) );
2822   qglVertex3f    ( v[0], v[1], v[2]-(ALT_POINT_SIZE/scale) );
2823 }
2824
2825
2826 long g_lCount = 0;
2827 long g_lTotal = 0;
2828 extern void DrawBrushEntityName (brush_t *b);
2829
2830 //#define DBG_SCENEDUMP
2831
2832 void XYWnd::XY_Draw()
2833 {
2834 #ifdef DBG_SCENEDUMP
2835   static time_t s_start = 0; // we use that to dump the selected stuff every 2 seconds
2836   time_t now;
2837   time (&now);
2838   bool bDump;
2839
2840   if ((now - s_start) > 3)
2841   {
2842     bDump = true;
2843     s_start = now;
2844     Sys_FPrintf(SYS_WRN, "Starting scene dump\n");
2845   }
2846   else bDump = false;
2847 #endif
2848
2849   brush_t       *brush;
2850   float w, h;
2851   entity_t      *e;
2852   double        start, end;
2853   double        start2, end2;
2854   vec3_t        mins, maxs;
2855   int           drawn, culled;
2856   int           i;
2857
2858   if (!active_brushes.next)
2859     return;     // not valid yet
2860
2861   Patch_LODMatchAll(); // spog
2862
2863   if (m_bTiming)
2864     start = Sys_DoubleTime();
2865   //
2866   // clear
2867   //
2868   m_bDirty = false;
2869
2870   qglViewport(0, 0, m_nWidth, m_nHeight);
2871   qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
2872                  g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
2873                  g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],0);
2874
2875   qglClear(GL_COLOR_BUFFER_BIT);
2876
2877   //
2878   // set up viewpoint
2879   //
2880   qglMatrixMode(GL_PROJECTION);
2881   qglLoadIdentity ();
2882
2883   w = m_nWidth / 2 / m_fScale;
2884   h = m_nHeight / 2/ m_fScale;
2885
2886   // fix GL_INVALID_VALUE error on first time the window is updated (win32)
2887   if (w == 0)
2888     w = 1;
2889
2890   int nDim1 = (m_nViewType == YZ) ? 1 : 0;
2891   int nDim2 = (m_nViewType == XY) ? 1 : 2;
2892   mins[0] = m_vOrigin[nDim1] - w;
2893   maxs[0] = m_vOrigin[nDim1] + w;
2894   mins[1] = m_vOrigin[nDim2] - h;
2895   maxs[1] = m_vOrigin[nDim2] + h;
2896
2897   qglOrtho (mins[0], maxs[0], mins[1], maxs[1], g_MinWorldCoord, g_MaxWorldCoord);
2898
2899   qglMatrixMode(GL_MODELVIEW);
2900   qglLoadIdentity ();
2901
2902   //
2903   // now draw the grid
2904   //
2905   XY_DrawGrid ();
2906
2907   //
2908   // draw block grid
2909   //
2910   if ( g_qeglobals.show_blocks)
2911     XY_DrawBlockGrid ();
2912
2913   if (m_nViewType != XY)
2914   {
2915     qglPushMatrix();
2916     if (m_nViewType == YZ)
2917       qglRotatef (-90,  0, 1, 0);           // put Z going up
2918     qglRotatef (-90,  1, 0, 0);     // put Z going up
2919   }
2920
2921   //
2922   // draw stuff
2923   //
2924   qglShadeModel (GL_FLAT);
2925   qglDisable(GL_TEXTURE_2D);
2926   qglDisable(GL_TEXTURE_1D);
2927   qglDisable(GL_DEPTH_TEST);
2928   qglDisable(GL_BLEND);
2929   qglDisable(GL_CULL_FACE);
2930   qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
2931   qglColor3f(0, 0, 0);
2932   qglEnableClientState(GL_VERTEX_ARRAY);
2933
2934         // Fishman - Add antialiazed points and lines support. 09/15/00
2935         if (g_PrefsDlg.m_bAntialiasedPointsAndLines)
2936         {
2937                 qglEnable(GL_BLEND);
2938                 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2939                 qglEnable(GL_POINT_SMOOTH);
2940                 qglEnable(GL_LINE_SMOOTH);
2941         }
2942
2943   drawn = culled = 0;
2944
2945   e = world_entity;
2946
2947   if (m_bTiming)
2948     start2 = Sys_DoubleTime();
2949
2950   for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
2951   {
2952           if (brush->bFiltered)
2953       continue;
2954
2955     if (brush->mins[nDim1] > maxs[0] ||
2956         brush->mins[nDim2] > maxs[1] ||
2957         brush->maxs[nDim1] < mins[0] ||
2958         brush->maxs[nDim2] < mins[1])
2959     {
2960       culled++;
2961       continue;         // off screen
2962     }
2963
2964     drawn++;
2965
2966     if (brush->owner != e && brush->owner)
2967     {
2968       qglColor3fv(brush->owner->eclass->color);
2969     }
2970     else
2971     {
2972       qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES]);
2973     }
2974
2975 #ifdef DBG_SCENEDUMP
2976     if (bDump)
2977     {
2978       Sys_FPrintf(SYS_WRN, "Active brush: %p ", brush);
2979       Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name);
2980     }
2981 #endif
2982
2983     Brush_DrawXY(brush, m_nViewType);
2984   }
2985
2986   if (m_bTiming)
2987     end2 = Sys_DoubleTime();
2988
2989   DrawPathLines ();
2990
2991   //
2992   // draw pointfile
2993   //
2994   //++timo why is the display list broken?
2995   if ( g_qeglobals.d_pointfile_display_list)
2996     Pointfile_Draw();
2997
2998   //
2999   // now draw selected brushes
3000   //
3001
3002   if (RotateMode())
3003     qglColor3f(0.8f, 0.1f, 0.9f);
3004   else
3005   if (ScaleMode())
3006     qglColor3f(0.1f, 0.8f, 0.1f);
3007   else
3008     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
3009
3010
3011   if (g_PrefsDlg.m_bNoStipple == FALSE)
3012   {
3013     qglEnable (GL_LINE_STIPPLE);
3014     qglLineStipple (3, 0xaaaa);
3015   }
3016   qglLineWidth (2);
3017
3018   vec3_t vMinBounds;
3019   vec3_t vMaxBounds;
3020   vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = g_MaxWorldCoord;
3021   vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = g_MinWorldCoord;
3022
3023   int nSaveDrawn = drawn;
3024   bool bFixedSize = false;
3025   for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
3026   {
3027         // spog - added culling of selected brushes in XY window
3028         if (brush->mins[nDim1] > maxs[0] ||
3029         brush->mins[nDim2] > maxs[1] ||
3030         brush->maxs[nDim1] < mins[0] ||
3031         brush->maxs[nDim2] < mins[1])
3032     {
3033       culled++;
3034       continue;         // off screen
3035     }
3036     drawn++;
3037 #ifdef DBG_SCENEDUMP
3038     if (bDump)
3039     {
3040       Sys_FPrintf(SYS_WRN, "Selected brush: %p ", brush);
3041       Sys_FPrintf(SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name);
3042     }
3043 #endif
3044     Brush_DrawXY(brush, m_nViewType);
3045
3046     if (!bFixedSize)
3047     {
3048       if (brush->owner->eclass->fixedsize)
3049         bFixedSize = true;
3050       if (g_PrefsDlg.m_bSizePaint)
3051       {
3052         for (i = 0; i < 3; i ++)
3053         {
3054           if (brush->mins[i] < vMinBounds[i])
3055             vMinBounds[i] = brush->mins[i];
3056           if (brush->maxs[i] > vMaxBounds[i])
3057             vMaxBounds[i] = brush->maxs[i];
3058         }
3059       }
3060     }
3061   }
3062
3063   if (g_PrefsDlg.m_bNoStipple == FALSE)
3064   {
3065     qglDisable (GL_LINE_STIPPLE);
3066   }
3067   qglLineWidth (1);
3068
3069   if (!bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint)
3070     PaintSizeInfo(nDim1, nDim2, vMinBounds, vMaxBounds);
3071
3072   // edge / vertex flags
3073   if (g_qeglobals.d_select_mode == sel_vertex)
3074   {
3075     if(!g_PrefsDlg.m_bGlPtWorkaround)
3076     {
3077       // brush verts
3078       qglPointSize (4);
3079                 qglColor3f (0,1,0);
3080       qglBegin (GL_POINTS);
3081         for (i=0 ; i<g_qeglobals.d_numpoints ; i++)
3082           qglVertex3fv (g_qeglobals.d_points[i]);
3083       qglEnd ();
3084
3085       if(g_qeglobals.d_num_move_points)
3086       {
3087         // selected brush verts
3088         qglPointSize (5);
3089         qglColor3f (0,0,1);
3090         qglBegin (GL_POINTS);
3091           for(i = 0; i < g_qeglobals.d_num_move_points; i++)
3092             qglVertex3fv (g_qeglobals.d_move_points[i]);
3093         qglEnd();
3094       }
3095       qglPointSize (1);
3096     }
3097     else
3098     {
3099       // brush verts
3100       qglColor3f (0,1,0);
3101       qglLineWidth(2.0);
3102       qglBegin (GL_LINES);
3103         for (i=0; i < g_qeglobals.d_numpoints; i++)
3104           DrawAlternatePoint(g_qeglobals.d_points[i], m_fScale);
3105       qglEnd();
3106
3107       if(g_qeglobals.d_num_move_points)
3108       {
3109         // selected brush verts
3110         qglColor3f (0,0,1);
3111         qglLineWidth (3.0);
3112         qglBegin (GL_LINES);
3113           for(i = 0; i < g_qeglobals.d_num_move_points; i++)
3114             qglVertex3fv (g_qeglobals.d_move_points[i]);
3115         qglEnd();
3116       }
3117       qglLineWidth(1.0);
3118     }
3119   }
3120   else if (g_qeglobals.d_select_mode == sel_edge)
3121   {
3122     float       *v1, *v2;
3123     if(!g_PrefsDlg.m_bGlPtWorkaround)
3124     {
3125       qglPointSize (4);
3126       qglColor3f (0,0,1);
3127       qglBegin (GL_POINTS);
3128       for (i=0 ; i<g_qeglobals.d_numedges ; i++)
3129       {
3130         v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
3131         v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
3132         qglVertex3f ( (v1[0]+v2[0])*0.5,(v1[1]+v2[1])*0.5,(v1[2]+v2[2])*0.5);
3133       }
3134       qglEnd ();
3135       qglPointSize (1);
3136     }
3137     else {
3138       qglColor3f (0,0,1);
3139       qglLineWidth(2.0);
3140       qglBegin (GL_LINES);
3141       for (i=0; i < g_qeglobals.d_numedges; i++)
3142       {
3143         v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
3144         v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
3145         vec3_t v3;
3146         v3[0] = (v1[0]+v2[0])*0.5;
3147         v3[1] = (v1[1]+v2[1])*0.5;
3148         v3[2] = (v1[2]+v2[2])*0.5;
3149         DrawAlternatePoint(v3, m_fScale);
3150       }
3151       qglEnd();
3152       qglLineWidth(1.0);
3153     }
3154   }
3155
3156   if (!(m_nViewType == XY))
3157     qglPopMatrix();
3158 #if 0
3159   // area selection hack
3160   if ((g_qeglobals.d_select_mode == sel_area || g_qeglobals.d_select_mode == sel_areatall) && (g_nPatchClickedView == ((m_nViewType == XY) ? W_XY : (m_nViewType == YZ) ? W_YZ : W_XZ)))
3161   {
3162     qglEnable (GL_BLEND);
3163     qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
3164     qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3165     qglColor4f(0.0, 0.0, 1.0, 0.25);
3166     qglRectf(g_qeglobals.d_vAreaTL[nDim1], g_qeglobals.d_vAreaTL[nDim2], g_qeglobals.d_vAreaBR[nDim1], g_qeglobals.d_vAreaBR[nDim2]);
3167     qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3168     qglDisable (GL_BLEND);
3169   }
3170 #endif
3171
3172
3173   //
3174   // now draw camera point
3175   //
3176   DrawCameraIcon ();
3177   DrawZIcon ();
3178
3179   if (RotateMode())
3180   {
3181     DrawRotateIcon();
3182   }
3183
3184   // plugin entities
3185   //++timo TODO: use an object for the 2D view
3186   Draw2DPluginEntities( (VIEWTYPE)m_nViewType );
3187
3188   if (g_qeglobals.d_savedinfo.show_outline)
3189   {
3190     if (Active())
3191     {
3192       qglMatrixMode (GL_PROJECTION);
3193       qglPushMatrix ();
3194       qglLoadIdentity ();
3195       qglOrtho (0, m_nWidth, 0, m_nHeight, 0, 1);
3196       qglMatrixMode (GL_MODELVIEW);
3197       qglPushMatrix ();
3198       qglLoadIdentity ();
3199
3200       // four view mode doesn't colorize
3201       if (g_pParentWnd->CurrentStyle() == MainFrame::eSplit)
3202         qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME]);
3203       else
3204         qglColor3fv( g_qeglobals.d_savedinfo.AxisColors[m_nViewType]);
3205       qglBegin (GL_LINE_LOOP);
3206       qglVertex2i (0, 0);
3207       qglVertex2i (m_nWidth-1, 0);
3208       qglVertex2i (m_nWidth-1, m_nHeight-1);
3209       qglVertex2i (0, m_nHeight-1);
3210       qglEnd ();
3211
3212       qglMatrixMode (GL_PROJECTION);
3213       qglPopMatrix ();
3214       qglMatrixMode (GL_MODELVIEW);
3215       qglPopMatrix ();
3216     }
3217   }
3218
3219   qglFinish();
3220
3221   if (m_bTiming)
3222   {
3223     end = Sys_DoubleTime ();
3224     i = (int)(1000*(end-start));
3225     int i3 = (int)(1000*(end2-start2));
3226     g_lCount++;
3227     g_lTotal += i;
3228     int i2 = g_lTotal / g_lCount;
3229     Sys_Printf ("xy: %i ab: %i  avg: %i\n", i, i3, i2);
3230   }
3231
3232         // Fishman - Add antialiazed points and lines support. 09/03/00
3233   if (g_PrefsDlg.m_bAntialiasedPointsAndLines)
3234   {
3235           qglDisable(GL_POINT_SMOOTH);
3236           qglDisable(GL_LINE_SMOOTH);
3237           qglDisable(GL_BLEND);
3238   }
3239 }
3240
3241 void XYWnd::Copy()
3242 {
3243 }
3244
3245 void XYWnd::Undo()
3246 {
3247 }
3248
3249 void XYWnd::UndoClear()
3250 {
3251 }
3252
3253 void XYWnd::UndoCopy()
3254 {
3255 }
3256
3257 bool XYWnd::UndoAvailable()
3258 {
3259   return (g_brUndo.next != &g_brUndo);
3260 }
3261
3262 void XYWnd::Paste()
3263 {
3264 }
3265
3266 // should be static as should be the rotate scale stuff
3267 bool XYWnd::AreaSelectOK()
3268 {
3269   return RotateMode() ? false : ScaleMode() ? false : true;
3270 }
3271
3272 void XYWnd::OnCreate ()
3273 {
3274   if (!MakeCurrent ())
3275     Error ("glXMakeCurrent failed");
3276
3277   qglPolygonStipple ((unsigned char *)s_stipple);
3278   qglLineStipple (3, 0xaaaa);
3279 }
3280
3281 void XYWnd::OnExpose ()
3282 {
3283   bool bPaint = true;
3284   if (!MakeCurrent ())
3285   {
3286     Sys_Printf("ERROR: glXMakeCurrent failed.. Error:%i\n",qglGetError());
3287     Sys_Printf("Please restart Radiant if the Map view is not working\n");
3288     bPaint = false;
3289   }
3290   if (bPaint)
3291   {
3292     QE_CheckOpenGLForErrors();
3293     XY_Draw ();
3294     QE_CheckOpenGLForErrors();
3295
3296     if (m_nViewType != XY)
3297     {
3298       qglPushMatrix();
3299       if (m_nViewType == YZ)
3300         qglRotatef (-90,  0, 1, 0);         // put Z going up
3301       qglRotatef (-90,  1, 0, 0);           // put Z going up
3302     }
3303
3304     if (g_bCrossHairs)
3305     {
3306       qglColor4f(0.2f, 0.9f, 0.2f, 0.8f);
3307       qglBegin (GL_LINES);
3308       if (m_nViewType == XY)
3309       {
3310         qglVertex2f(2*g_MinWorldCoord, tdp[1]);
3311         qglVertex2f(2*g_MaxWorldCoord, tdp[1]);
3312         qglVertex2f(tdp[0], 2*g_MinWorldCoord);
3313         qglVertex2f(tdp[0], 2*g_MaxWorldCoord);
3314       }
3315       else if (m_nViewType == YZ)
3316       {
3317         qglVertex3f(tdp[0], 2*g_MinWorldCoord, tdp[2]);
3318         qglVertex3f(tdp[0], 2*g_MaxWorldCoord, tdp[2]);
3319         qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord);
3320         qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord);
3321       }
3322       else
3323       {
3324         qglVertex3f (2*g_MinWorldCoord, tdp[1], tdp[2]);
3325         qglVertex3f (2*g_MaxWorldCoord, tdp[1], tdp[2]);
3326         qglVertex3f(tdp[0], tdp[1], 2*g_MinWorldCoord);
3327         qglVertex3f(tdp[0], tdp[1], 2*g_MaxWorldCoord);
3328       }
3329       qglEnd();
3330     }
3331
3332     if (ClipMode())
3333     {
3334       // Draw clip points
3335       if (g_Clip1.Set())
3336         g_Clip1.Draw(m_fScale, 1); // qglVertex3fv (g_Clip1);
3337       if (g_Clip2.Set())
3338         g_Clip2.Draw(m_fScale, 2); // qglVertex3fv (g_Clip2);
3339       if (g_Clip3.Set())
3340         g_Clip3.Draw(m_fScale, 3); // qglVertex3fv (g_Clip3);
3341       if (g_Clip1.Set() && g_Clip2.Set())
3342       {
3343         ProduceSplitLists();
3344         brush_t* pBrush;
3345         brush_t* pList = (g_bSwitch) ? &g_brBackSplits : &g_brFrontSplits;
3346         for (pBrush = pList->next ; pBrush != NULL && pBrush != pList ; pBrush=pBrush->next)
3347         {
3348           qglColor3f (1,1,0);
3349           face_t *face;
3350           int order;
3351           for (face = pBrush->brush_faces,order = 0 ; face ; face=face->next, order++)
3352           {
3353             winding_t* w = face->face_winding;
3354             if (!w)
3355               continue;
3356             // draw the polygon
3357             qglBegin(GL_LINE_LOOP);
3358             for (int i=0 ; i<w->numpoints ; i++)
3359               qglVertex3fv(w->points[i]);
3360             qglEnd();
3361           }
3362         }
3363       }
3364     }
3365
3366     if (PathMode())
3367     {
3368       int n;
3369       for (n = 0; n < g_nPathCount; n++)
3370         g_PathPoints[n].Draw(m_fScale, n+1); // qglVertex3fv(g_PathPoints[n]);
3371     }
3372     if (m_nViewType != XY)
3373       qglPopMatrix();
3374
3375     m_XORRectangle.set(rectangle_t());
3376     SwapBuffers ();
3377   }
3378 }
3379
3380 void XYWnd::KillPathMode()
3381 {
3382   g_bSmartGo = false;
3383   g_bPathMode = false;
3384   if (g_pPathFunc)
3385     g_pPathFunc(false, g_nPathCount);
3386   g_nPathCount = 0;
3387   g_pPathFunc = NULL;
3388   Sys_UpdateWindows(W_ALL);
3389 }
3390
3391 // gets called for drop down menu messages
3392 // TIP: it's not always about EntityCreate
3393 void XYWnd::OnEntityCreate (const char* item)
3394 {
3395   Undo_Start("create entity");
3396   Undo_AddBrushList(&selected_brushes);
3397
3398   if (m_mnuDrop != NULL)
3399   {
3400     CString strItem;
3401     strItem = item;
3402
3403     if (strItem.CompareNoCase("Add to...") == 0)
3404     {
3405       //++timo TODO: fill the menu with current groups?
3406       // this one is for adding to existing groups only
3407       Sys_Printf("TODO: Add to... in XYWnd::OnEntityCreate\n");
3408     }
3409     else if (strItem.CompareNoCase("Remove") == 0)
3410     {
3411       // remove selected brushes from their current group
3412       brush_t *b;
3413       for( b = selected_brushes.next; b != &selected_brushes; b = b->next )
3414       {
3415
3416       }
3417     }
3418
3419     //++timo FIXME: remove when all hooks are in
3420     if (strItem.CompareNoCase("Add to...") == 0
3421         || strItem.CompareNoCase("Remove") == 0
3422         || strItem.CompareNoCase("Name...") == 0
3423         || strItem.CompareNoCase("New group...") == 0)
3424       {
3425         Sys_Printf("TODO: hook drop down group menu\n");
3426         return;
3427       }
3428
3429     if (strItem.Find("Smart_") >= 0)
3430     {
3431       CreateSmartEntity(this, m_ptDownX, m_ptDownY, strItem);
3432     }
3433     else
3434     {
3435       CreateRightClickEntity(this, m_ptDownX, m_ptDownY, (char*)strItem.GetBuffer());
3436     }
3437
3438     Sys_UpdateWindows(W_ALL);
3439     //OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2));
3440   }
3441   Undo_EndBrushList(&selected_brushes);
3442   Undo_End();
3443 }
3444
3445 /* Drawing clip points */
3446 void ClipPoint::Draw(float fScale, int num)
3447 {
3448   CString strLabel;
3449   strLabel.Format("%d", num);
3450   Draw(fScale, strLabel.GetBuffer());
3451 }
3452
3453 #define ALT_POINT_VERTS 6
3454
3455 void ClipPoint::Draw(float fScale, const char *label)
3456 {
3457   // draw point
3458   if(!g_PrefsDlg.m_bGlPtWorkaround)
3459   {
3460     qglPointSize (4);
3461     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]);
3462     qglBegin (GL_POINTS);
3463     qglVertex3fv (m_ptClip);
3464     qglEnd();
3465     qglPointSize (1);
3466   }
3467   else
3468   {
3469     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER]);
3470     qglLineWidth(2.0);
3471     qglBegin (GL_LINES);
3472       DrawAlternatePoint(m_ptClip, fScale);
3473     qglEnd();
3474     qglLineWidth(1.0);
3475   }
3476
3477   // draw label
3478   qglRasterPos3f (m_ptClip[0]+2, m_ptClip[1]+2, m_ptClip[2]+2);
3479   qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label);
3480 }
3481