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