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