2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
25 // Leonardo Zide (leo@lokigames.com)
30 #include <glib/gi18n.h>
35 #include <gdk/gdkwin32.h>
38 // =============================================================================
44 bool g_bCrossHairs = false;
49 bool g_bRogueClipMode;
54 ClipPoint* g_pMovingClip;
55 brush_t g_brFrontSplits;
56 brush_t g_brBackSplits;
58 brush_t g_brClipboard;
60 entity_t g_enClipboard;
62 vec3_t g_vRotateOrigin;
66 ClipPoint g_PathPoints[256]; // this limit isn't enforced?
67 ClipPoint* g_pMovingPath;
74 ClipPoint g_PointPoints[512];
75 ClipPoint* g_pMovingPoint;
79 const int XY_LEFT = 0x01;
80 const int XY_RIGHT = 0x02;
81 const int XY_UP = 0x04;
82 const int XY_DOWN = 0x08;
84 PFNPathCallback* g_pPathFunc = NULL;
86 static unsigned s_stipple[32] =
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,
98 void AcquirePath( int nCount, PFNPathCallback* pFunc ){
100 g_nPathLimit = nCount;
106 CPtrArray g_ptrMenus;
108 MemStream g_Clipboard( 4096 );
109 MemStream g_PatchClipboard( 4096 );
113 extern bool g_bWaitCursor;
117 GtkWidget* XYWnd::m_mnuDrop = NULL;
119 extern int g_nPatchClickedView;
121 // =============================================================================
126 const long width = g_pParentWnd->ActiveXY()->Width();
127 const long height = g_pParentWnd->ActiveXY()->Height();
129 const char* filename;
131 filename = file_dialog( g_pParentWnd->m_pWidget, FALSE, _( "Save BMP Image" ), NULL, "bmp" );
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 );
141 fp = fopen( filename, "wb" );
144 unsigned long cmap, bfSize;
148 bfSize = 54 + width * height * 3;
150 long byteswritten = 0;
151 long pixoff = 54 + cmap * 4;
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
161 unsigned long biSize = 40, compress = 0, size = 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
176 unsigned long widthDW = ( ( ( width * 24 ) + 31 ) / 32 * 4 );
177 long row, row_size = width * 3;
178 for ( row = 0; row < height; row++ )
180 unsigned char* buf = img + row * row_size;
184 for ( col = 0; col < row_size; col += 3 )
186 putc( buf[col + 2], fp );
187 putc( buf[col + 1], fp );
188 putc( buf[col], fp );
190 byteswritten += row_size;
193 for ( count = row_size; count < widthDW; count++ )
195 putc( 0, fp ); // dummy
206 float ptSum( vec3_t pt ){
207 return pt[0] + pt[1] + pt[2];
210 float Betwixt( float f1, float f2 ){
212 return f2 + ( ( f1 - f2 ) / 2 );
215 return f1 + ( ( f2 - f1 ) / 2 );
219 void CleanList( brush_t* pList ){
220 brush_t* pBrush = pList->next;
221 while ( pBrush != NULL && pBrush != pList )
223 brush_t* pNext = pBrush->next;
224 Brush_Free( pBrush );
229 void Brush_CopyList( brush_t* pFrom, brush_t* pTo ){
230 brush_t* pBrush = pFrom->next;
231 while ( pBrush != NULL && pBrush != pFrom )
233 brush_t* pNext = pBrush->next;
234 Brush_RemoveFromList( pBrush );
235 Brush_AddToList( pBrush, pTo );
240 float fDiff( float f1, float f2 ){
250 =============================================================
254 =============================================================
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.
267 void DrawPathLines( void ){
277 const char *ent_target[MAX_MAP_ENTITIES];
278 entity_t *ent_entity[MAX_MAP_ENTITIES];
280 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS ) {
285 for ( te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next )
287 ent_target[num_entities] = ValueForKey( te, "target" );
288 if ( ent_target[num_entities][0] ) {
289 ent_entity[num_entities] = te;
294 for ( se = entities.next ; se != &entities ; se = se->next )
296 psz = ValueForKey( se, "targetname" );
298 if ( psz == NULL || psz[0] == '\0' ) {
302 sb = se->brushes.onext;
303 if ( sb == &se->brushes ) {
307 for ( k = 0 ; k < num_entities ; k++ )
309 if ( strcmp( ent_target[k], psz ) ) {
314 tb = te->brushes.onext;
315 if ( tb == &te->brushes ) {
319 for ( i = 0 ; i < 3 ; i++ )
320 mid[i] = ( sb->mins[i] + sb->maxs[i] ) * 0.5;
322 for ( i = 0 ; i < 3 ; i++ )
323 mid1[i] = ( tb->mins[i] + tb->maxs[i] ) * 0.5;
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;
332 qglColor3f( se->eclass->color[0], se->eclass->color[1], se->eclass->color[2] );
334 qglBegin( GL_LINES );
336 qglVertex3fv( mid1 );
338 arrows = (int)( len / 256 ) + 1;
340 for ( i = 0 ; i < arrows ; i++ )
342 f = len * ( i + 0.5 ) / arrows;
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] );
357 extern void AssignModel();
359 void CreateEntityFromName( const char* name, const vec3_t origin ){
362 if ( stricmp( name, "worldspawn" ) == 0 ) {
363 gtk_MessageBox( g_pParentWnd->m_pWidget, "Can't create an entity with worldspawn.", "info", 0 );
368 SetKeyValue( e, "classname", name );
370 if ( e->eclass->fixedsize ) {
372 b = Brush_Create( e->eclass->mins, e->eclass->maxs, &e->eclass->texdef );
373 Entity_LinkBrush( e, b );
374 Brush_AddToList( b, &active_brushes );
376 Brush_Move( b, origin, true );
380 Select_GroupEntity( e );
381 if ( e->brushes.onext == &e->brushes ) {
382 Sys_FPrintf( SYS_ERR, "CreateEntityFromName: selection could not be grouped\n" );
388 Entity_AddToList( e, &entities );
393 // tweaking: when right clic dropping a light entity, ask for light value in a custom dialog box
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;
403 // Create and show the dialog box
405 // pWnd = prompt.GetDlgItem( IDC_EDIT1 );
406 // prompt.GotoDlgCtrl( pWnd );
407 if ( DoLightIntensityDlg( &intensity ) == IDOK ) {
408 g_PrefsDlg.m_iLastLightIntensity = intensity;
410 sprintf( buf, "255 255 255 %d", intensity );
411 SetKeyValue( e, "_light", buf );
417 if ( stricmp( name, "light" ) == 0 ) {
418 int intensity = g_PrefsDlg.m_iLastLightIntensity;
420 // Create and show the dialog box
422 // pWnd = prompt.GetDlgItem( IDC_EDIT1 );
423 // prompt.GotoDlgCtrl( pWnd );
424 if ( DoLightIntensityDlg( &intensity ) == IDOK ) {
425 g_PrefsDlg.m_iLastLightIntensity = intensity;
427 sprintf( buf, "%d", intensity );
428 SetKeyValue( e, "light", buf );
432 Select_Brush( e->brushes.onext );
434 if ( ( stricmp( name, "misc_model" ) == 0 ) || ( stricmp( name, "misc_gamemodel" ) == 0 ) || ( strcmpi( name, "model_static" ) == 0 ) ) {
435 SetInspectorMode( W_ENTITY );
440 void CreateRightClickEntity( XYWnd* pWnd, int x, int y, char* pName ){
441 int height = pWnd->GetWidget()->allocation.height;
443 pWnd->SnapToPoint( x, height - 1 - y, point );
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 ) );
449 CreateEntityFromName( pName, point );
453 brush_t* CreateSmartBrush( vec3_t v ){
458 for ( i = 0 ; i < 3 ; i++ )
464 n = Brush_Create( mins, maxs, &g_qeglobals.d_texturewin.texdef );
469 Brush_AddToList( n, &selected_brushes );
470 //Entity_LinkBrush(world_entity, n);
475 CString g_strSmartEntity;
478 bool g_bSmartWaiting;
479 void _SmartPointDone( bool b, int n ){
480 g_bSmartWaiting = false;
483 void CreateSmartEntity( XYWnd* pWnd, int x, int y, const char* pName ){
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" );
495 if ( g_strSmartEntity.Find( "Smart_Monster..." ) >= 0 ) {
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();
509 g_bScreenUpdates = false;
510 CreateRightClickEntity( g_pParentWnd->ActiveXY(), g_nSmartX, g_nSmartY, "func_rotating" );
511 array.Add( reinterpret_cast<void*>( selected_brushes.next ) );
513 brush_t* pBrush = CreateSmartBrush( g_PathPoints[0] );
516 Select_Brush( reinterpret_cast<brush_t*>( array.GetAt( 0 ) ) );
517 Select_Brush( reinterpret_cast<brush_t*>( array.GetAt( 1 ) ) );
519 g_bScreenUpdates = true;
523 void FinishSmartCreation(){
526 // brush_t* pEntities = NULL;
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++ )
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 ) );
541 for ( n = 0; n < g_nPathCount; n++ )
544 Select_Brush( reinterpret_cast<brush_t*>( array.GetAt( n ) ) );
545 Select_Brush( reinterpret_cast<brush_t*>( array.GetAt( n + 1 ) ) );
548 g_bScreenUpdates = true;
553 Sys_UpdateWindows( W_ALL );
556 void CleanCopyEntities(){
557 entity_t* pe = g_enClipboard.next;
558 while ( pe != NULL && pe != &g_enClipboard )
560 entity_t* next = pe->next;
561 epair_t* enext = NULL;
562 for ( epair_t* ep = pe->epairs ; ep ; ep = enext )
572 g_enClipboard.next = g_enClipboard.prev = &g_enClipboard;
575 entity_t *Entity_CopyClone( entity_t *e ){
579 n = (entity_t*)qmalloc( sizeof( *n ) );
580 n->brushes.onext = n->brushes.oprev = &n->brushes;
581 n->eclass = e->eclass;
583 // add the entity to the entity list
584 n->next = g_enClipboard.next;
585 g_enClipboard.next = n;
587 n->prev = &g_enClipboard;
589 for ( ep = e->epairs ; ep ; ep = ep->next )
591 np = (epair_t*)qmalloc( sizeof( *np ) );
592 np->key = copystring( ep->key );
593 np->value = copystring( ep->value );
594 np->next = n->epairs;
600 bool OnList( entity_t* pFind, CPtrArray* pList ){
601 int nSize = pList->GetSize();
602 while ( nSize-- > 0 )
604 entity_t* pEntity = reinterpret_cast<entity_t*>( pList->GetAt( nSize ) );
605 if ( pEntity == pFind ) {
612 // =============================================================================
616 : GLWindow( FALSE ), m_XORRectangle( m_pWidget ){
617 g_brClipboard.next = &g_brClipboard;
618 g_brUndo.next = &g_brUndo;
620 g_bRotateMode = false;
622 g_bRogueClipMode = false;
624 g_pMovingClip = (ClipPoint*)NULL;
625 g_pMovingPath = (ClipPoint*)NULL;
626 g_brFrontSplits.next = &g_brFrontSplits;
627 g_brBackSplits.next = &g_brBackSplits;
631 m_bRButtonDown = false;
632 m_nUpdateBits = W_XY;
637 // m_mnuDrop = (GtkWidget*)NULL;
641 vec3_t& XYWnd::Rotation(){
645 vec3_t& XYWnd::RotateOrigin(){
646 return g_vRotateOrigin;
654 void XYWnd::XY_Overlay(){
658 static vec3_t lastcamera;
660 qglViewport( 0, 0, m_nWidth, m_nHeight );
665 qglMatrixMode( GL_PROJECTION );
668 w = (int)( m_nWidth / 2 / m_fScale );
669 h = (int)( m_nHeight / 2 / m_fScale );
671 qglOrtho( m_vOrigin[0] - w, m_vOrigin[0] + w, m_vOrigin[1] - h, m_vOrigin[1] + h, g_MinWorldCoord, g_MaxWorldCoord );
673 // erase the old camera and z checker positions
674 // if the entire xy hasn't been redrawn
677 qglReadBuffer( GL_BACK );
678 qglDrawBuffer( GL_FRONT );
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 );
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 );
691 // save off underneath where we are about to draw
693 VectorCopy( z.origin, lastz );
694 VectorCopy( g_pParentWnd->GetCamWnd()->Camera()->origin, lastcamera );
696 qglReadBuffer( GL_FRONT );
697 qglDrawBuffer( GL_BACK );
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 );
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 );
708 // draw the new icons
710 qglDrawBuffer( GL_FRONT );
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 );
722 qglDrawBuffer( GL_BACK );
726 vec3_t& XYWnd::GetOrigin(){
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];
736 void XYWnd::OnSize( int cx, int cy ){
741 brush_t hold_brushes;
745 hold_brushes.next = &hold_brushes;
748 if ( g_PrefsDlg.m_bSwitchClip ) {
749 pList = ( !g_bSwitch ) ? &g_brFrontSplits : &g_brBackSplits;
752 pList = ( g_bSwitch ) ? &g_brFrontSplits : &g_brBackSplits;
755 if ( pList->next != pList ) {
756 Brush_CopyList( pList, &hold_brushes );
757 CleanList( &g_brFrontSplits );
758 CleanList( &g_brBackSplits );
760 Brush_CopyList( &hold_brushes, &selected_brushes );
761 if ( RogueClipMode() ) {
762 RetainClipMode( false );
765 RetainClipMode( true );
767 Sys_UpdateWindows( W_ALL );
770 else if ( PathMode() ) {
771 FinishSmartCreation();
773 g_pPathFunc( true, g_nPathCount );
781 void XYWnd::SplitClip(){
783 if ( ( g_brFrontSplits.next != &g_brFrontSplits ) &&
784 ( g_brBackSplits.next != &g_brBackSplits ) ) {
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 );
794 RetainClipMode( true );
799 void XYWnd::FlipClip(){
800 g_bSwitch = !g_bSwitch;
801 Sys_UpdateWindows( XY | W_CAMERA_IFON );
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 );
814 m_vOrigin[nDim1] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim1];
815 m_vOrigin[nDim2] = g_pParentWnd->GetCamWnd()->Camera()->origin[nDim2];
819 void XYWnd::VectorCopyXY( vec3_t in, vec3_t out ){
820 if ( m_nViewType == XY ) {
824 else if ( m_nViewType == XZ ) {
835 void XYWnd::RetainClipMode( bool bMode ){
836 bool bSave = g_bRogueClipMode;
837 SetClipMode( bMode );
838 if ( bMode == true ) {
839 g_bRogueClipMode = bSave;
842 g_bRogueClipMode = false;
846 void XYWnd::SetClipMode( bool bMode ){
848 g_bRogueClipMode = false;
853 CleanList( &g_brFrontSplits );
854 CleanList( &g_brBackSplits );
855 g_brFrontSplits.next = &g_brFrontSplits;
856 g_brBackSplits.next = &g_brBackSplits;
858 // ydnar: set clipper points based on first selected patch mesh
859 if ( selected_brushes.next != &selected_brushes ) {
861 for ( brush_t *pb = selected_brushes.next; pb != &selected_brushes; pb = pb->next )
863 if ( pb->patchBrush ) {
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 );
876 // SetClipMode( true );
877 Sys_UpdateWindows( XY | W_CAMERA_IFON );
883 if ( g_pMovingClip ) {
885 g_pMovingClip = NULL;
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 );
895 bool XYWnd::ClipMode(){
899 bool XYWnd::RogueClipMode(){
900 return g_bRogueClipMode;
903 bool XYWnd::PathMode(){
907 bool XYWnd::PointMode(){
911 void XYWnd::SetPointMode( bool b ){
918 void XYWnd::SetViewType( int n ){
920 if ( g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) {
921 char* str = "YZ Side";
922 if ( m_nViewType == XY ) {
925 else if ( m_nViewType == XZ ) {
929 if ( m_pParent != NULL ) {
930 gtk_window_set_title( GTK_WINDOW( m_pParent ), str );
935 void XYWnd::Redraw( unsigned int nBits ){
936 m_nUpdateBits = nBits;
937 gtk_widget_queue_draw( m_pWidget );
938 m_nUpdateBits = W_XY;
941 bool XYWnd::RotateMode(){
942 return g_bRotateMode;
945 bool XYWnd::ScaleMode(){
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;
958 Sys_Printf( "Need a brush selected to turn on Mouse Rotation mode\n" );
960 g_bRotateMode = false;
963 return g_bRotateMode;
966 void XYWnd::SetScaleMode( bool bMode ){
967 g_bScaleMode = bMode;
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;
983 right *= xy->Scale();
984 bottom *= xy->Scale();
985 return rectangle_t( left, bottom, right - left, top - bottom );
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();
993 xor_rectangle.set( rectangle );
996 void XYWnd::OnMouseMove( guint32 nFlags, int pointx, int pointy ){
998 // TODO TTimo handle return code
999 DispatchOnMouseMove( nFlags, pointx, pointy );
1004 if ( g_PrefsDlg.m_bChaseMouse == TRUE &&
1005 ( pointx < 0 || pointy < 0 || pointx > m_nWidth || pointy > m_nHeight ) &&
1007 float fAdjustment = ( g_qeglobals.d_gridsize / 8 * 64 ) / m_fScale;
1013 m_ptDragAdjX = (int)( -fAdjustment );
1015 else if ( pointx > m_nWidth ) {
1016 m_ptDragAdjX = (int)( fAdjustment );
1020 m_ptDragAdjY = (int)( -fAdjustment );
1022 else if ( pointy > m_nHeight ) {
1023 m_ptDragAdjY = (int)( fAdjustment );
1026 if ( !HasTimer() ) {
1038 pressx -= m_ptDragTotalX;
1039 pressy += m_ptDragTotalY;
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 );
1047 g_strStatus.Format( "x:: %.1f y:: %.1f z:: %.1f", tdp[0], tdp[1], tdp[2] );
1048 g_pParentWnd->SetStatusText( 1, g_strStatus );
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() ) {
1056 SnapToPoint( pointx, m_nHeight - 1 - pointy, g_pMovingPoint->m_ptClip );
1057 g_pMovingPoint->UpdatePointPtr();
1058 Sys_UpdateWindows( XY | W_CAMERA_IFON );
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++ )
1067 if ( fDiff( g_PointPoints[n].m_ptClip[nDim1], tdp[nDim1] ) < 3 &&
1068 fDiff( g_PointPoints[n].m_ptClip[nDim2], tdp[nDim2] ) < 3 ) {
1070 g_pMovingPoint = &g_PointPoints[n];
1075 else if ( ClipMode() ) {
1076 if ( g_pMovingClip && HasCapture() ) {
1078 SnapToPoint( pointx, m_nHeight - 1 - pointy, g_pMovingClip->m_ptClip );
1079 Sys_UpdateWindows( XY | W_CAMERA_IFON );
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 ) {
1090 g_pMovingClip = &g_Clip1;
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 ) {
1097 g_pMovingClip = &g_Clip2;
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 ) {
1104 g_pMovingClip = &g_Clip3;
1108 if ( bCrossHair == false ) {
1109 XY_MouseMoved( pointx, m_nHeight - 1 - pointy, nFlags );
1112 else if ( PathMode() ) {
1113 if ( g_pMovingPath && HasCapture() ) {
1115 SnapToPoint( pointx, m_nHeight - 1 - pointy, g_pMovingPath->m_ptClip );
1116 Sys_UpdateWindows( XY | W_CAMERA_IFON );
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++ )
1125 if ( fDiff( g_PathPoints[n].m_ptClip[nDim1], tdp[nDim1] ) < 3 &&
1126 fDiff( g_PathPoints[n].m_ptClip[nDim2], tdp[nDim2] ) < 3 ) {
1128 g_pMovingPath = &g_PathPoints[n];
1135 XY_MouseMoved( pointx, m_nHeight - 1 - pointy, nFlags );
1140 XY_MouseMoved( pointx, m_nHeight - 1 - pointy, nFlags );
1143 if ( ( nFlags & MK_RBUTTON ) == 0 ) {
1144 if ( bCrossHair && !g_bWaitCursor ) {
1146 cursor = gdk_cursor_new( GDK_CROSSHAIR );
1147 gdk_window_set_cursor( m_pWidget->window, cursor );
1148 gdk_cursor_unref( cursor );
1152 gdk_window_set_cursor( m_pWidget->window, NULL );
1156 update_xor_rectangle_xy( m_XORRectangle );
1159 void XYWnd::OnMouseWheel( bool bUp ){
1161 g_pParentWnd->OnViewZoomin();
1164 g_pParentWnd->OnViewZoomout();
1167 int nUpdate = ( g_PrefsDlg.m_bCamXYUpdate ) ? ( W_CAMERA | W_XY ) : ( W_CAMERA );
1168 Sys_UpdateWindows( nUpdate );
1169 g_pParentWnd->OnTimer();
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 );
1185 void XYWnd::OnLButtonDown( guint32 flags, int pointx, int pointy ){
1186 g_pParentWnd->SetActiveXY( this );
1190 if ( DispatchOnLButtonDown( flags, pointx, pointy ) ) {
1194 if ( ClipMode() && !RogueClipMode() ) {
1195 DropClipPoint( flags, pointx, pointy );
1197 else if ( PathMode() ) {
1198 DropPathPoint( flags, pointx, pointy );
1200 else{ OriginalButtonDown( flags, pointx, pointy ); }
1203 void XYWnd::OnMButtonDown( guint32 flags, int pointx, int pointy ){
1204 OriginalButtonDown( flags, pointx, pointy );
1207 void XYWnd::OnRButtonDown( guint32 flags, int pointx, int pointy ){
1208 g_pParentWnd->SetActiveXY( this );
1211 m_bRButtonDown = true;
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 );
1220 SetClipMode( true );
1221 g_bRogueClipMode = true;
1222 DropClipPoint( flags, pointx, pointy );
1227 OriginalButtonDown( flags, pointx, pointy );
1230 void XYWnd::OnLButtonUp( guint32 flags, int pointx, int pointy ){
1232 if ( DispatchOnLButtonUp( flags, pointx, pointy ) ) {
1237 if ( g_pMovingClip ) {
1239 g_pMovingClip = NULL;
1242 OriginalButtonUp( flags, pointx, pointy );
1245 void XYWnd::OnMButtonUp( guint32 flags, int pointx, int pointy ){
1246 OriginalButtonUp( flags, pointx, pointy );
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
1253 if ( Sys_AltDown() ) {
1256 if ( flags & MK_CONTROL ) {
1259 if ( flags & MK_SHIFT ) {
1266 OriginalButtonUp( flags, pointx, pointy );
1269 void XYWnd::XY_MouseDown( int x, int y, int buttons ){
1271 vec3_t origin, dir, right, up;
1273 m_nButtonstate = buttons;
1276 VectorCopy( vec3_origin, m_vPressdelta );
1278 VectorClear( point );
1279 XY_ToPoint( x, y, point );
1281 VectorCopy( point, origin );
1284 if ( m_nViewType == XY ) { // view facing dir = negative Z
1285 origin[2] = g_MaxWorldCoord;
1287 right[0] = 1 / m_fScale;
1291 up[1] = 1 / m_fScale;
1294 else if ( m_nViewType == XZ ) {
1295 origin[1] = g_MinWorldCoord; // view facing dir = positive Y
1297 right[0] = 1 / m_fScale;
1302 up[2] = 1 / m_fScale;
1304 else // if (m_nViewType == YZ) // view facing dir = negative X
1306 origin[0] = g_MaxWorldCoord;
1309 right[1] = 1 / m_fScale;
1313 up[2] = 1 / m_fScale;
1316 m_bPress_selection = ( selected_brushes.next != &selected_brushes );
1318 Sys_GetCursorPos( &m_ptCursorX, &m_ptCursorY );
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 );
1331 int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON;
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 );
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 );
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 );
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 );
1361 Sys_UpdateWindows( W_XY );
1366 SnapToPoint( x, y, point );
1367 if ( m_nViewType == XY ) {
1368 z.origin[0] = point[0];
1369 z.origin[1] = point[1];
1371 else if ( m_nViewType == YZ ) {
1372 z.origin[0] = point[1];
1373 z.origin[1] = point[2];
1377 z.origin[0] = point[0];
1378 z.origin[1] = point[2];
1380 Sys_UpdateWindows( W_XY_OVERLAY | W_Z );
1385 update_xor_rectangle_xy( m_XORRectangle );
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 );
1395 gdk_window_set_cursor( m_pWidget->window, NULL );
1397 update_xor_rectangle_xy( m_XORRectangle );
1400 qboolean XYWnd::DragDelta( int x, int y, vec3_t move ){
1401 vec3_t xvec, yvec, delta;
1404 xvec[0] = 1 / m_fScale;
1405 xvec[1] = xvec[2] = 0;
1406 yvec[1] = 1 / m_fScale;
1407 yvec[0] = yvec[2] = 0;
1409 for ( i = 0 ; i < 3 ; i++ )
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;
1416 VectorSubtract( delta, m_vPressdelta, move );
1417 VectorCopy( delta, m_vPressdelta );
1419 if ( move[0] || move[1] || move[2] ) {
1425 void XYWnd::HandleDrop(){
1426 if ( g_PrefsDlg.m_bRightClick == false ) {
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;
1434 menu = m_mnuDrop = gtk_menu_new();
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)
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);
1459 create_menu_item_with_mnemonic( menu, "Ungroup Entity",
1460 GTK_SIGNAL_FUNC( HandleCommand ), ID_SELECTION_UNGROUPENTITY );
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 );
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++;
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++;
1479 submenu_root = NULL;
1484 for ( e = eclass ; e ; e = e->next )
1488 int n_ = strName.Find( "_" );
1490 CString strLeft = strName.Left( n_ );
1491 CString strRight = strName.Right( strName.GetLength() - n_ - 1 );
1492 if ( strLeft == strActive ) { // this is a child
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 );
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 );
1512 submenu_root = NULL;
1514 strActive = strLeft;
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 );
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 );
1536 submenu_root = NULL;
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 );
1549 gtk_menu_popup( GTK_MENU( m_mnuDrop ), NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME );
1557 void XYWnd::NewBrushDrag( int x, int y ){
1558 vec3_t mins, maxs, junk;
1563 if ( !DragDelta( x,y, junk ) ) {
1567 // delete the current selection
1568 if ( selected_brushes.next != &selected_brushes ) {
1569 Brush_Free( selected_brushes.next );
1572 SnapToPoint( m_nPressx, m_nPressy, mins );
1574 int nDim = ( m_nViewType == XY ) ? 2 : ( m_nViewType == YZ ) ? 0 : 1;
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 ) );
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;
1587 for ( i = 0 ; i < 3 ; i++ )
1589 if ( mins[i] == maxs[i] ) {
1590 return; // don't create a degenerate brush
1592 if ( mins[i] > maxs[i] ) {
1599 n = Brush_Create( mins, maxs, &g_qeglobals.d_texturewin.texdef );
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 );
1609 Brush_AddToList( n, &selected_brushes );
1611 Entity_LinkBrush( world_entity, n );
1615 // Sys_UpdateWindows (W_ALL);
1616 Sys_UpdateWindows( W_XY | W_CAMERA );
1625 void XYWnd::XY_MouseMoved( int x, int y, int buttons ){
1628 if ( !m_nButtonstate ) {
1629 if ( g_bCrossHairs ) {
1630 Sys_UpdateWindows( W_XY | W_XY_OVERLAY );
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 );
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 );
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 );
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 );
1668 Sys_UpdateWindows( W_XY );
1673 SnapToPoint( x, y, point );
1674 if ( m_nViewType == XY ) {
1675 z.origin[0] = point[0];
1676 z.origin[1] = point[1];
1678 else if ( m_nViewType == YZ ) {
1679 z.origin[0] = point[1];
1680 z.origin[1] = point[2];
1684 z.origin[0] = point[0];
1685 z.origin[1] = point[2];
1688 Sys_UpdateWindows( W_XY_OVERLAY | W_Z );
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 );
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 );
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 );
1718 // create an empty cursor
1719 if ( !g_bWaitCursor ) {
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 );
1735 Sys_UpdateWindows( W_XY | W_XY_OVERLAY );
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();
1749 g_pParentWnd->OnViewZoomin();
1752 Sys_SetCursorPos( m_ptCursorX, m_ptCursorY );
1759 void XYWnd::OriginalButtonDown( guint32 nFlags, int pointx, int pointy ){
1762 XY_MouseDown( pointx, m_pWidget->allocation.height - 1 - pointy, nFlags );
1763 m_nScrollFlags = nFlags;
1766 void XYWnd::OriginalButtonUp( guint32 nFlags, int pointx, int pointy ){
1767 XY_MouseUp( pointx, m_pWidget->allocation.height - 1 - pointy, nFlags );
1771 void XYWnd::DropClipPoint( guint32 nFlags, int pointx, int pointy ){
1772 if ( g_pMovingClip ) {
1774 SnapToPoint( pointx, m_pWidget->allocation.height - 1 - pointy, *g_pMovingClip );
1779 if ( g_Clip1.Set() == false ) {
1781 g_Clip1.Set( true );
1782 g_Clip1.m_ptScreenX = pointx;
1783 g_Clip1.m_ptScreenY = pointy;
1786 if ( g_Clip2.Set() == false ) {
1788 g_Clip2.Set( true );
1789 g_Clip2.m_ptScreenX = pointx;
1790 g_Clip2.m_ptScreenY = pointy;
1793 if ( g_Clip3.Set() == false ) {
1795 g_Clip3.Set( true );
1796 g_Clip3.m_ptScreenX = pointx;
1797 g_Clip3.m_ptScreenY = pointy;
1801 RetainClipMode( true );
1803 g_Clip1.Set( true );
1804 g_Clip1.m_ptScreenX = pointx;
1805 g_Clip1.m_ptScreenY = pointy;
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];
1816 Select_GetMid( mid );
1817 ( *pPt )[nDim] = mid[nDim];
1819 Sys_UpdateWindows( XY | W_CAMERA_IFON );
1822 void XYWnd::DropPathPoint( guint32 nFlags, int pointx, int pointy ){
1823 if ( g_pMovingPath ) {
1825 SnapToPoint( pointx, m_pWidget->allocation.height - 1 - pointy, *g_pMovingPath );
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];
1841 if ( g_nPathCount == g_nPathLimit ) {
1842 if ( g_pPathFunc ) {
1843 g_pPathFunc( true, g_nPathCount );
1846 g_bPathMode = false;
1850 Sys_UpdateWindows( XY | W_CAMERA_IFON );
1853 // FIXME: AddPointPoint() redundant function never called
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 );
1861 Sys_UpdateWindows( XY | W_CAMERA_IFON );
1864 // FIXME: ProduceSplits() redundant function never called
1865 void XYWnd::ProduceSplits( brush_t** pFront, brush_t** pBack ){
1869 if ( g_Clip1.Set() && g_Clip2.Set() ) {
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];
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];
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];
1900 Brush_SplitBrushByFace( selected_brushes.next, &face, pFront, pBack );
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;
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];
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];
1935 void XYWnd::ProduceSplitLists(){
1936 bool bCaulk = false;
1939 if ( AnyPatchesSelected() ) {
1940 Sys_Printf( "Deselecting patches for clip operation.\n" );
1942 for ( brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = next )
1945 if ( pb->patchBrush ) {
1946 Brush_RemoveFromList( pb );
1947 Brush_AddToList( pb, &active_brushes );
1948 UpdatePatchInspector();
1951 // ydnar: update the window if any patches are selected
1952 Sys_UpdateWindows( XY | W_CAMERA_IFON );
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() ) ) {
1961 for ( pBrush = selected_brushes.next ; pBrush != NULL && pBrush != &selected_brushes ; pBrush = pBrush->next )
1963 brush_t* pFront = NULL;
1964 brush_t* pBack = NULL;
1967 memset( &face,0,sizeof( face_t ) );
1968 PlanePointsFromClipPoints( face.planepts, pBrush );
1970 // decide wether caulking should be applied on the splits
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
1981 bCaulk = true; // use caulk
1985 Brush_SplitBrushByFace( pBrush, &face, &pFront, &pBack, bCaulk );
1987 Brush_AddToList( pBack, &g_brBackSplits );
1990 Brush_AddToList( pFront, &g_brFrontSplits );
1997 void XYWnd::XY_Init(){
2004 void XYWnd::SnapToPoint( int x, int y, vec3_t point ){
2005 if ( g_PrefsDlg.m_bSnap ) {
2006 XY_ToGridPoint( x, y, point );
2010 XY_ToPoint( x, y, point );
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 ){
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;
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;
2030 point[0] = m_vOrigin[0] + ( fx - fw / 2 ) / m_fScale;
2031 point[2] = m_vOrigin[2] + ( fy - fh / 2 ) / m_fScale;
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;
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;
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;
2058 ============================================================================
2062 ============================================================================
2070 void XYWnd::XY_DrawGrid(){
2071 float x, y, xb, xe, yb, ye;
2074 int step, stepx, stepy, colour;
2075 step = stepx = stepy = MAX( 64, (int)g_qeglobals.d_gridsize );
2078 int stepSize = (int)(8 / m_fScale);
2079 if (stepSize > step)
2082 for (i = 1; i < stepSize; i <<= 1)
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
2093 //Sys_Printf("step after: %i\n", step);
2094 while ( ( stepx * m_fScale ) < 40.0f ) // text step x must be at least 40 pixels
2096 while ( ( stepy * m_fScale ) < 40.0f ) // text step y must be at least 40 pixels
2099 qglDisable( GL_TEXTURE_2D );
2100 qglDisable( GL_TEXTURE_1D );
2101 qglDisable( GL_DEPTH_TEST );
2102 qglDisable( GL_BLEND );
2104 w = ( m_nWidth / 2 / m_fScale );
2105 h = ( m_nHeight / 2 / m_fScale );
2107 int nDim1 = ( m_nViewType == YZ ) ? 1 : 0;
2108 int nDim2 = ( m_nViewType == XY ) ? 1 : 2;
2110 xb = m_vOrigin[nDim1] - w;
2111 if ( xb < region_mins[nDim1] ) {
2112 xb = region_mins[nDim1];
2114 xb = step * floor( xb / step );
2116 xe = m_vOrigin[nDim1] + w;
2117 if ( xe > region_maxs[nDim1] ) {
2118 xe = region_maxs[nDim1];
2120 xe = step * ceil( xe / step );
2122 yb = m_vOrigin[nDim2] - h;
2123 if ( yb < region_mins[nDim2] ) {
2124 yb = region_mins[nDim2];
2126 yb = step * floor( yb / step );
2128 ye = m_vOrigin[nDim2] + h;
2129 if ( ye > region_maxs[nDim2] ) {
2130 ye = region_maxs[nDim2];
2132 ye = step * ceil( ye / step );
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] )
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;
2146 colour = COLOR_GRIDMINOR;
2149 if ( COLORS_DIFFER( colour, COLOR_GRIDBACK ) ) {
2150 qglColor3fv( g_qeglobals.d_savedinfo.colors[colour] );
2152 qglBegin( GL_LINES );
2153 for ( x = xb ; x < xe ; x += g_qeglobals.d_gridsize )
2155 if ( !( (int)x & ( step - 1 ) ) && !( (int)x - x ) ) {
2158 qglVertex2f( x, yb );
2159 qglVertex2f( x, ye );
2161 for ( y = yb ; y < ye ; y += g_qeglobals.d_gridsize )
2163 if ( !( (int)y & ( step - 1 ) ) && !( (int)y - y ) ) {
2166 qglVertex2f( xb, y );
2167 qglVertex2f( xe, y );
2173 if ( g_qeglobals.d_gridsize < 1 ) {
2174 colour = COLOR_GRIDMAJOR_ALT;
2177 colour = COLOR_GRIDMAJOR;
2180 // draw major blocks
2181 if ( COLORS_DIFFER( colour, COLOR_GRIDBACK ) ) {
2182 qglColor3fv( g_qeglobals.d_savedinfo.colors[colour] );
2185 if ( g_qeglobals.d_showgrid ) {
2186 qglBegin( GL_LINES );
2187 for ( x = xb ; x <= xe ; x += step )
2189 qglVertex2f( x, yb );
2190 qglVertex2f( x, ye );
2192 for ( y = yb ; y <= ye ; y += step )
2194 qglVertex2f( xb, y );
2195 qglVertex2f( xe, y );
2200 // draw coordinate text if needed
2201 if ( g_qeglobals.d_savedinfo.show_coordinates ) {
2202 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_GRIDTEXT] );
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
2209 const int pixelsTopCushion = 4;
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.
2217 // Pixels between baseline of horizontal grid line label and drawn horizontal grid line.
2218 const int pixelsButtomCushion = 2;
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;
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 );
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 );
2240 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME] );
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 );
2248 if ( m_nViewType == XY ) {
2249 strcpy( cView, "XY Top" );
2252 if ( m_nViewType == XZ ) {
2253 strcpy( cView, "XZ Front" );
2256 strcpy( cView, "YZ Side" );
2259 gtk_glwidget_print_string( cView );
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
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 );
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] );
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 );
2316 void XYWnd::XY_DrawBlockGrid(){
2317 const char *value = ValueForKey( world_entity, "_blocksize" );
2318 if ( strlen( value ) ) {
2319 sscanf( value, "%i", &g_qeglobals.blockSize );
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;
2327 float x, y, xb, xe, yb, ye;
2331 qglDisable( GL_TEXTURE_2D );
2332 qglDisable( GL_TEXTURE_1D );
2333 qglDisable( GL_DEPTH_TEST );
2334 qglDisable( GL_BLEND );
2336 w = ( m_nWidth / 2 / m_fScale );
2337 h = ( m_nHeight / 2 / m_fScale );
2339 int nDim1 = ( m_nViewType == YZ ) ? 1 : 0;
2340 int nDim2 = ( m_nViewType == XY ) ? 1 : 2;
2342 xb = m_vOrigin[nDim1] - w;
2343 if ( xb < region_mins[nDim1] ) {
2344 xb = region_mins[nDim1];
2346 xb = g_qeglobals.blockSize * floor( xb / g_qeglobals.blockSize );
2348 xe = m_vOrigin[nDim1] + w;
2349 if ( xe > region_maxs[nDim1] ) {
2350 xe = region_maxs[nDim1];
2352 xe = g_qeglobals.blockSize * ceil( xe / g_qeglobals.blockSize );
2354 yb = m_vOrigin[nDim2] - h;
2355 if ( yb < region_mins[nDim2] ) {
2356 yb = region_mins[nDim2];
2358 yb = g_qeglobals.blockSize * floor( yb / g_qeglobals.blockSize );
2360 ye = m_vOrigin[nDim2] + h;
2361 if ( ye > region_maxs[nDim2] ) {
2362 ye = region_maxs[nDim2];
2364 ye = g_qeglobals.blockSize * ceil( ye / g_qeglobals.blockSize );
2366 // draw major blocks
2368 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBLOCK] );
2371 qglBegin( GL_LINES );
2373 for ( x = xb ; x <= xe ; x += g_qeglobals.blockSize )
2375 qglVertex2f( x, yb );
2376 qglVertex2f( x, ye );
2379 if ( m_nViewType == XY ) {
2380 for ( y = yb ; y <= ye ; y += g_qeglobals.blockSize )
2382 qglVertex2f( xb, y );
2383 qglVertex2f( xe, y );
2390 // draw coordinate text if needed
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 )
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 );
2402 qglColor4f( 0, 0, 0, 0 );
2405 void XYWnd::DrawRotateIcon(){
2408 a = 4.0 / m_fScale; // compensate for zoom level
2411 if ( m_nViewType == XY ) {
2412 x = g_vRotateOrigin[0];
2413 y = g_vRotateOrigin[1];
2415 else if ( m_nViewType == YZ ) {
2416 x = g_vRotateOrigin[1];
2417 y = g_vRotateOrigin[2];
2421 x = g_vRotateOrigin[0];
2422 y = g_vRotateOrigin[2];
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 );
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 );
2438 qglDisable( GL_BLEND );
2440 qglColor4f( 1.0f, 0.2f, 1.0f, 1.f );
2441 qglBegin( GL_POINTS );
2442 qglVertex3f( x,y,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 );
2456 void XYWnd::DrawCameraIcon(){
2457 float x, y, a, fov, box;
2459 fov = 48 / m_fScale;
2460 box = 16 / m_fScale;
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;
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;
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;
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 );
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 );
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 );
2514 qglDisable( GL_BLEND );
2516 qglColor4f( 0.0, 0.0, 1.0, 1 );
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 );
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 );
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)"};
2543 VectorSubtract( vMaxBounds, vMinBounds, vSize );
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 );
2549 if ( m_nViewType == XY ) {
2550 qglBegin( GL_LINES );
2552 qglVertex3f( vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f );
2553 qglVertex3f( vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f );
2555 qglVertex3f( vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f );
2556 qglVertex3f( vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f );
2558 qglVertex3f( vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale, 0.0f );
2559 qglVertex3f( vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale, 0.0f );
2562 qglVertex3f( vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2], 0.0f );
2563 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f );
2565 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2], 0.0f );
2566 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f );
2568 qglVertex3f( vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2], 0.0f );
2569 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2], 0.0f );
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() );
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() );
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() );
2585 else if ( m_nViewType == XZ ) {
2586 qglBegin( GL_LINES );
2588 qglVertex3f( vMinBounds[nDim1], 0, vMinBounds[nDim2] - 6.0f / m_fScale );
2589 qglVertex3f( vMinBounds[nDim1], 0, vMinBounds[nDim2] - 10.0f / m_fScale );
2591 qglVertex3f( vMinBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale );
2592 qglVertex3f( vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale );
2594 qglVertex3f( vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 6.0f / m_fScale );
2595 qglVertex3f( vMaxBounds[nDim1], 0,vMinBounds[nDim2] - 10.0f / m_fScale );
2598 qglVertex3f( vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMinBounds[nDim2] );
2599 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2] );
2601 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMinBounds[nDim2] );
2602 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2] );
2604 qglVertex3f( vMaxBounds[nDim1] + 6.0f / m_fScale, 0,vMaxBounds[nDim2] );
2605 qglVertex3f( vMaxBounds[nDim1] + 10.0f / m_fScale, 0,vMaxBounds[nDim2] );
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() );
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() );
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() );
2623 qglBegin( GL_LINES );
2625 qglVertex3f( 0, vMinBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale );
2626 qglVertex3f( 0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale );
2628 qglVertex3f( 0, vMinBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale );
2629 qglVertex3f( 0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale );
2631 qglVertex3f( 0, vMaxBounds[nDim1], vMinBounds[nDim2] - 6.0f / m_fScale );
2632 qglVertex3f( 0, vMaxBounds[nDim1], vMinBounds[nDim2] - 10.0f / m_fScale );
2635 qglVertex3f( 0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMinBounds[nDim2] );
2636 qglVertex3f( 0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2] );
2638 qglVertex3f( 0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMinBounds[nDim2] );
2639 qglVertex3f( 0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2] );
2641 qglVertex3f( 0, vMaxBounds[nDim1] + 6.0f / m_fScale, vMaxBounds[nDim2] );
2642 qglVertex3f( 0, vMaxBounds[nDim1] + 10.0f / m_fScale, vMaxBounds[nDim2] );
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() );
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() );
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() );
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 ){
2669 scale = g_pParentWnd->GetXYWnd()->Scale();
2670 //scale = g_qeglobals.d_xyOld.scale;
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 ) );
2685 extern void DrawBrushEntityName( brush_t *b );
2687 //#define DBG_SCENEDUMP
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
2696 if ( ( now - s_start ) > 3 ) {
2699 Sys_FPrintf( SYS_WRN, "Starting scene dump\n" );
2701 else{ bDump = false; }
2708 double start2, end2;
2713 if ( !active_brushes.next ) {
2714 return; // not valid yet
2717 Patch_LODMatchAll(); // spog
2720 start = Sys_DoubleTime();
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 );
2732 qglClear( GL_COLOR_BUFFER_BIT );
2737 qglMatrixMode( GL_PROJECTION );
2740 w = m_nWidth / 2 / m_fScale;
2741 h = m_nHeight / 2 / m_fScale;
2743 // fix GL_INVALID_VALUE error on first time the window is updated (win32)
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;
2755 qglOrtho( mins[0], maxs[0], mins[1], maxs[1], g_MinWorldCoord, g_MaxWorldCoord );
2757 qglMatrixMode( GL_MODELVIEW );
2761 // now draw the grid
2768 if ( g_qeglobals.show_blocks ) {
2772 if ( m_nViewType != XY ) {
2774 if ( m_nViewType == YZ ) {
2775 qglRotatef( -90, 0, 1, 0 ); // put Z going up
2777 qglRotatef( -90, 1, 0, 0 ); // put Z going up
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 );
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 );
2806 start2 = Sys_DoubleTime();
2809 for ( brush = active_brushes.next ; brush != &active_brushes ; brush = brush->next )
2811 if ( brush->bFiltered ) {
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] ) {
2820 continue; // off screen
2825 if ( brush->owner != e && brush->owner ) {
2826 qglColor3fv( brush->owner->eclass->color );
2830 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES] );
2833 #ifdef DBG_SCENEDUMP
2835 Sys_FPrintf( SYS_WRN, "Active brush: %p ", brush );
2836 Sys_FPrintf( SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name );
2840 Brush_DrawXY( brush, m_nViewType );
2844 end2 = Sys_DoubleTime();
2852 //++timo why is the display list broken?
2853 if ( g_qeglobals.d_pointfile_display_list ) {
2858 // now draw selected brushes
2861 if ( RotateMode() ) {
2862 qglColor3f( 0.8f, 0.1f, 0.9f );
2865 if ( ScaleMode() ) {
2866 qglColor3f( 0.1f, 0.8f, 0.1f );
2869 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES] );
2873 if ( g_PrefsDlg.m_bNoStipple == FALSE ) {
2874 qglEnable( GL_LINE_STIPPLE );
2875 qglLineStipple( 3, 0xaaaa );
2881 vMinBounds[0] = vMinBounds[1] = vMinBounds[2] = g_MaxWorldCoord;
2882 vMaxBounds[0] = vMaxBounds[1] = vMaxBounds[2] = g_MinWorldCoord;
2884 int nSaveDrawn = drawn;
2885 bool bFixedSize = false;
2886 for ( brush = selected_brushes.next ; brush != &selected_brushes ; brush = brush->next )
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] ) {
2894 continue; // off screen
2897 #ifdef DBG_SCENEDUMP
2899 Sys_FPrintf( SYS_WRN, "Selected brush: %p ", brush );
2900 Sys_FPrintf( SYS_WRN, "owner->eclass: %s\n", brush->owner->eclass->name );
2903 Brush_DrawXY( brush, m_nViewType );
2905 if ( !bFixedSize ) {
2906 if ( brush->owner->eclass->fixedsize ) {
2909 if ( g_PrefsDlg.m_bSizePaint ) {
2910 for ( i = 0; i < 3; i++ )
2912 if ( brush->mins[i] < vMinBounds[i] ) {
2913 vMinBounds[i] = brush->mins[i];
2915 if ( brush->maxs[i] > vMaxBounds[i] ) {
2916 vMaxBounds[i] = brush->maxs[i];
2923 if ( g_PrefsDlg.m_bNoStipple == FALSE ) {
2924 qglDisable( GL_LINE_STIPPLE );
2928 if ( !bFixedSize && !RotateMode() && !ScaleMode() && drawn - nSaveDrawn > 0 && g_PrefsDlg.m_bSizePaint ) {
2929 PaintSizeInfo( nDim1, nDim2, vMinBounds, vMaxBounds );
2932 // edge / vertex flags
2933 if ( g_qeglobals.d_select_mode == sel_vertex ) {
2934 if ( !g_PrefsDlg.m_bGlPtWorkaround ) {
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] );
2943 if ( g_qeglobals.d_num_move_points ) {
2944 // selected brush verts
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] );
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 );
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] );
2973 qglLineWidth( 1.0 );
2976 else if ( g_qeglobals.d_select_mode == sel_edge ) {
2978 if ( !g_PrefsDlg.m_bGlPtWorkaround ) {
2980 qglColor3f( 0,0,1 );
2981 qglBegin( GL_POINTS );
2982 for ( i = 0 ; i < g_qeglobals.d_numedges ; i++ )
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 );
2992 qglColor3f( 0,0,1 );
2993 qglLineWidth( 2.0 );
2994 qglBegin( GL_LINES );
2995 for ( i = 0; i < g_qeglobals.d_numedges; i++ )
2997 v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
2998 v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
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 );
3006 qglLineWidth( 1.0 );
3010 if ( !( m_nViewType == XY ) ) {
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 );
3028 // now draw camera point
3033 if ( RotateMode() ) {
3038 //++timo TODO: use an object for the 2D view
3039 Draw2DPluginEntities( (VIEWTYPE)m_nViewType );
3041 if ( g_qeglobals.d_savedinfo.show_outline ) {
3043 qglMatrixMode( GL_PROJECTION );
3046 qglOrtho( 0, m_nWidth, 0, m_nHeight, 0, 1 );
3047 qglMatrixMode( GL_MODELVIEW );
3051 // four view mode doesn't colorize
3052 if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit ) {
3053 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_VIEWNAME] );
3056 qglColor3fv( g_qeglobals.d_savedinfo.AxisColors[m_nViewType] );
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 );
3065 qglMatrixMode( GL_PROJECTION );
3067 qglMatrixMode( GL_MODELVIEW );
3075 end = Sys_DoubleTime();
3076 i = (int)( 1000 * ( end - start ) );
3077 int i3 = (int)( 1000 * ( end2 - start2 ) );
3080 int i2 = g_lTotal / g_lCount;
3081 Sys_Printf( "xy: %i ab: %i avg: %i\n", i, i3, i2 );
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 );
3098 void XYWnd::UndoClear(){
3101 void XYWnd::UndoCopy(){
3104 bool XYWnd::UndoAvailable(){
3105 return ( g_brUndo.next != &g_brUndo );
3108 void XYWnd::Paste(){
3111 // should be static as should be the rotate scale stuff
3112 bool XYWnd::AreaSelectOK(){
3113 return RotateMode() ? false : ScaleMode() ? false : true;
3116 void XYWnd::OnCreate(){
3117 if ( !MakeCurrent() ) {
3118 Error( "glXMakeCurrent failed" );
3121 qglPolygonStipple( (unsigned char *)s_stipple );
3122 qglLineStipple( 3, 0xaaaa );
3125 void XYWnd::OnExpose(){
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" );
3133 QE_CheckOpenGLForErrors();
3135 QE_CheckOpenGLForErrors();
3137 if ( m_nViewType != XY ) {
3139 if ( m_nViewType == YZ ) {
3140 qglRotatef( -90, 0, 1, 0 ); // put Z going up
3142 qglRotatef( -90, 1, 0, 0 ); // put Z going up
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 );
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 );
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 );
3172 if ( g_Clip1.Set() ) {
3173 g_Clip1.Draw( m_fScale, 1 ); // qglVertex3fv (g_Clip1);
3175 if ( g_Clip2.Set() ) {
3176 g_Clip2.Draw( m_fScale, 2 ); // qglVertex3fv (g_Clip2);
3178 if ( g_Clip3.Set() ) {
3179 g_Clip3.Draw( m_fScale, 3 ); // qglVertex3fv (g_Clip3);
3181 if ( g_Clip1.Set() && g_Clip2.Set() ) {
3182 ProduceSplitLists();
3184 brush_t* pList = ( g_bSwitch ) ? &g_brBackSplits : &g_brFrontSplits;
3185 for ( pBrush = pList->next ; pBrush != NULL && pBrush != pList ; pBrush = pBrush->next )
3187 qglColor3f( 1,1,0 );
3190 for ( face = pBrush->brush_faces,order = 0 ; face ; face = face->next, order++ )
3192 winding_t* w = face->face_winding;
3197 qglBegin( GL_LINE_LOOP );
3198 for ( int i = 0 ; i < w->numpoints ; i++ )
3199 qglVertex3fv( w->points[i] );
3208 for ( n = 0; n < g_nPathCount; n++ )
3209 g_PathPoints[n].Draw( m_fScale, n + 1 ); // qglVertex3fv(g_PathPoints[n]);
3211 if ( m_nViewType != XY ) {
3215 m_XORRectangle.set( rectangle_t() );
3220 void XYWnd::KillPathMode(){
3222 g_bPathMode = false;
3223 if ( g_pPathFunc ) {
3224 g_pPathFunc( false, g_nPathCount );
3228 Sys_UpdateWindows( W_ALL );
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 );
3237 if ( m_mnuDrop != NULL ) {
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" );
3246 else if ( strItem.CompareNoCase( "Remove" ) == 0 ) {
3247 // remove selected brushes from their current group
3249 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
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" );
3264 if ( strItem.Find( "Smart_" ) >= 0 ) {
3265 CreateSmartEntity( this, m_ptDownX, m_ptDownY, strItem );
3269 CreateRightClickEntity( this, m_ptDownX, m_ptDownY, (char*)strItem.GetBuffer() );
3272 Sys_UpdateWindows( W_ALL );
3273 //OnLButtonDown((MK_LBUTTON | MK_SHIFT), CPoint(m_ptDown.x+2, m_ptDown.y+2));
3275 Undo_EndBrushList( &selected_brushes );
3279 /* Drawing clip points */
3280 void ClipPoint::Draw( float fScale, int num ){
3282 strLabel.Format( "%d", num );
3283 Draw( fScale, strLabel.GetBuffer() );
3286 #define ALT_POINT_VERTS 6
3288 void ClipPoint::Draw( float fScale, const char *label ){
3290 if ( !g_PrefsDlg.m_bGlPtWorkaround ) {
3292 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER] );
3293 qglBegin( GL_POINTS );
3294 qglVertex3fv( m_ptClip );
3300 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_CLIPPER] );
3301 qglLineWidth( 2.0 );
3302 qglBegin( GL_LINES );
3303 DrawAlternatePoint( m_ptClip, fScale );
3305 qglLineWidth( 1.0 );
3309 qglRasterPos3f( m_ptClip[0] + 2, m_ptClip[1] + 2, m_ptClip[2] + 2 );
3310 qglCallLists( strlen( label ), GL_UNSIGNED_BYTE, label );