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