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