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