From e14027e1175885910068bc6f1f377230c3310478 Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 2 Aug 2017 09:52:30 +0300 Subject: [PATCH] Radiant: misc... * render scene to FBO to get following options: preferences->camera->MSAA (def = 8 samples) preferences->orthographic->MSAA (def = 8 samples) coloured camera POV icon w/o rerendering the scene coloured rectangular selector box w/o rerendering the scene * fallback to glCopyTexImage2D (NPoT), if FBO isn't available --- libs/gtkutil/xorrectangle.h | 111 +++++++--------- libs/render.h | 230 ++++++++++++++++++++++++++++++++ radiant/camwindow.cpp | 76 ++++++++++- radiant/xywindow.cpp | 253 +++++++++++++++++++++++------------- radiant/xywindow.h | 8 +- 5 files changed, 512 insertions(+), 166 deletions(-) diff --git a/libs/gtkutil/xorrectangle.h b/libs/gtkutil/xorrectangle.h index 3c3d838f..abb5bf19 100644 --- a/libs/gtkutil/xorrectangle.h +++ b/libs/gtkutil/xorrectangle.h @@ -67,71 +67,56 @@ inline rectangle_t rectangle_from_area( const float min[2], const float max[2], return rectangle_t( botleft.x, botleft.y, topright.x - botleft.x, topright.y - botleft.y ); } -class XORRectangle -{ -rectangle_t m_rectangle; -GtkWidget* m_widget; - +class XORRectangle { public: -XORRectangle( GtkWidget* widget ) : m_widget( widget ){ -} -~XORRectangle(){ -} -void set( rectangle_t rectangle ){ - if ( GTK_WIDGET_REALIZED( m_widget ) ) { - if( m_rectangle.w != rectangle.w || m_rectangle.h != rectangle.h ){ - //if( !(m_rectangle.w == 0 && m_rectangle.h == 0 && rectangle.w == 0 && rectangle.h == 0) ){ - //globalOutputStream() << "m_x" << m_rectangle.x << " m_y" << m_rectangle.y << " m_w" << m_rectangle.w << " m_h" << m_rectangle.h << "\n"; - //globalOutputStream() << "__x" << rectangle.x << " __y" << rectangle.y << " __w" << rectangle.w << " __h" << rectangle.h << "\n"; - if ( glwidget_make_current( m_widget ) != FALSE ) { - GlobalOpenGL_debugAssertNoErrors(); - - gint width, height; - gdk_gl_drawable_get_size( gtk_widget_get_gl_drawable( m_widget ), &width, &height ); - - glViewport( 0, 0, width, height ); - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - glOrtho( 0, width, 0, height, -100, 100 ); - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); - glDisable( GL_DEPTH_TEST ); - - glDrawBuffer( GL_FRONT ); - - glEnable( GL_BLEND ); - glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO ); - - glLineWidth( 2 ); - glColor3f( 1, 1, 1 ); - glDisable( GL_TEXTURE_2D ); - glBegin( GL_LINE_LOOP ); - glVertex2f( m_rectangle.x, m_rectangle.y + m_rectangle.h ); - glVertex2f( m_rectangle.x + m_rectangle.w, m_rectangle.y + m_rectangle.h ); - glVertex2f( m_rectangle.x + m_rectangle.w, m_rectangle.y ); - glVertex2f( m_rectangle.x, m_rectangle.y ); - glEnd(); - - glBegin( GL_LINE_LOOP ); - glVertex2f( rectangle.x, rectangle.y + rectangle.h ); - glVertex2f( rectangle.x + rectangle.w, rectangle.y + rectangle.h ); - glVertex2f( rectangle.x + rectangle.w, rectangle.y ); - glVertex2f( rectangle.x, rectangle.y ); - glEnd(); - - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - glDrawBuffer( GL_BACK ); - GlobalOpenGL_debugAssertNoErrors(); - //glwidget_swap_buffers( m_widget ); - glwidget_make_current( m_widget ); - } - } - m_rectangle = rectangle; + XORRectangle() { + } + ~XORRectangle() { + } + void set( rectangle_t rectangle ) { + if( rectangle.w != 0.f && rectangle.h != 0.f ) { + GlobalOpenGL_debugAssertNoErrors(); + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_TEXTURE_2D ); + + if( GlobalOpenGL().GL_1_3() ) { + glDisable( GL_MULTISAMPLE ); + } + + glEnable( GL_BLEND ); + glBlendFunc( GL_ONE, GL_ONE ); + //glColor4f( 0.94902f / 5.f, 0.396078f / 5.f, 0.133333f / 5.f, .2f ); + glColor3f( 1.f / 10.f, .5f / 10.f, 0.f ); + + glBegin( GL_QUADS ); + glVertex2f( rectangle.x, rectangle.y + rectangle.h ); + glVertex2f( rectangle.x + rectangle.w, rectangle.y + rectangle.h ); + glVertex2f( rectangle.x + rectangle.w, rectangle.y ); + glVertex2f( rectangle.x, rectangle.y ); + glEnd(); + + glDisable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + glLineWidth( 1 ); + //glColor3f( 0.94902f, 0.396078f, 0.133333f ); + glColor3f( 1.f, .5f, 0.f ); + + glBegin( GL_LINE_LOOP ); + glVertex2f( rectangle.x, rectangle.y + rectangle.h ); + glVertex2f( rectangle.x + rectangle.w, rectangle.y + rectangle.h ); + glVertex2f( rectangle.x + rectangle.w, rectangle.y ); + glVertex2f( rectangle.x, rectangle.y ); + glEnd(); + + if( GlobalOpenGL().GL_1_3() ) { + glEnable( GL_MULTISAMPLE ); + } + GlobalOpenGL_debugAssertNoErrors(); + } } -} }; diff --git a/libs/render.h b/libs/render.h index b2e6c5e9..e9f7ea25 100644 --- a/libs/render.h +++ b/libs/render.h @@ -1197,5 +1197,235 @@ inline void ArbitraryMeshTriangle_sumTangents( ArbitraryMeshVertex& a, Arbitrary reinterpret_cast( c.bitangent ) += t; } +namespace { +/////////////////////////////////////////////////////////////////////////////// +// check FBO completeness +/////////////////////////////////////////////////////////////////////////////// +bool checkFramebufferStatus() { + // check FBO status + GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER ); + switch( status ) { + case GL_FRAMEBUFFER_COMPLETE: +// globalErrorStream() << "Framebuffer complete.\n"; + return true; + + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + globalErrorStream() << "[ERROR] Framebuffer incomplete: Attachment is NOT complete.\n"; + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + globalErrorStream() << "[ERROR] Framebuffer incomplete: No image is attached to FBO.\n"; + return false; +/* + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + globalErrorStream() << "[ERROR] Framebuffer incomplete: Attached images have different dimensions.\n"; + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: + globalErrorStream() << "[ERROR] Framebuffer incomplete: Color attached images have different internal formats.\n"; + return false; +*/ + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + globalErrorStream() << "[ERROR] Framebuffer incomplete: Draw buffer.\n"; + return false; + + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + globalErrorStream() << "[ERROR] Framebuffer incomplete: Read buffer.\n"; + return false; + + case GL_FRAMEBUFFER_UNSUPPORTED: + globalErrorStream() << "[ERROR] Framebuffer incomplete: Unsupported by FBO implementation.\n"; + return false; + + default: + globalErrorStream() << "[ERROR] Framebuffer incomplete: Unknown error.\n"; + return false; + } +} + +} //namespace + +class FBO +{ +public: + FBO(): + _constructed( false ), + _has_depth( false ), + _width( 0 ), + _height( 0 ), + _fbo( 0 ), + _tex( 0 ), + _depth( 0 ), + _color( 0 ){ + } + virtual ~FBO(){ + reset( 0, 0, 0, false ); + } + virtual void reset( int width, int height, int samples, bool has_depth ){ + _width = width; + _height = height; + _samples = samples; + _has_depth = has_depth; + if( _depth ) + glDeleteRenderbuffers( 1, &_depth ); + _depth = 0; + if( _color ) + glDeleteRenderbuffers( 1, &_color ); + _color = 0; + if( _fbo ) + glDeleteFramebuffers( 1, &_fbo ); + _fbo = 0; + _constructed = false; + } + virtual void start(){ +// if ( GlobalOpenGL().GL_1_3() ) { +// glDisable( GL_MULTISAMPLE ); +// } + if( !_constructed ){ + construct(); + } + glBindFramebuffer( GL_FRAMEBUFFER, _fbo ); + } + virtual void save(){ + blit(); + } + virtual void blit(){ + glBindFramebuffer( GL_READ_FRAMEBUFFER, _fbo ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); + //glDrawBuffer( GL_BACK ); + glBlitFramebuffer( 0, 0, _width, _height, 0, 0, _width, _height, GL_COLOR_BUFFER_BIT, GL_NEAREST ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + } +protected: + bool _constructed; + bool _has_depth; + int _width; + int _height; + int _samples; + GLuint _fbo; + GLuint _tex; + GLuint _depth; + GLuint _color; + virtual void construct() { + int curSamples; + glGetIntegerv( GL_SAMPLES, &curSamples ); + if( curSamples > 0 && _samples != 0 ){ + _samples = curSamples; + } + else{ + int maxSamples; + glGetIntegerv( GL_MAX_SAMPLES, &maxSamples ); + if( _samples > maxSamples ){ + _samples = maxSamples; + } + } + + glGenFramebuffers( 1, &_fbo ); + glBindFramebuffer( GL_FRAMEBUFFER, _fbo ); + + // Color buffer + glGenRenderbuffers( 1, &_color ); + glBindRenderbuffer( GL_RENDERBUFFER, _color ); + glRenderbufferStorageMultisample( GL_RENDERBUFFER, _samples, GL_RGBA8, _width, _height ); + glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _color ); + + if( _has_depth ){ + // Depth buffer + glGenRenderbuffers( 1, &_depth ); + glBindRenderbuffer( GL_RENDERBUFFER, _depth ); + glRenderbufferStorageMultisample( GL_RENDERBUFFER, _samples, GL_DEPTH_COMPONENT, _width, _height ); + glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depth ); + } + + if( !checkFramebufferStatus() && _samples > 0 ){ + globalErrorStream() << "Falling back to no multisampling.\n"; + _samples = 0; + reset( _width, _height, 0, _has_depth ); + construct(); + } + + _constructed = true; + } +private: +}; + +class FBO_fallback : public FBO +{ +public: + ~FBO_fallback(){ + reset( 0, 0, 0, false ); + } + void reset( int width, int height, int samples, bool has_depth ){ + _width = width; + _height = height; + if( _tex ) + glDeleteTextures( 1, &_tex ); + _tex = 0; + _constructed = false; + } + void start(){ + if( !_constructed ){ + construct(); + } + } + void save(){ + glBindTexture( GL_TEXTURE_2D, _tex ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 0, 0, _width, _height, 0 ); + //glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_nWidth, m_nHeight ); + glBindTexture( GL_TEXTURE_2D, 0 ); + } + void blit(){ + glViewport( 0, 0, _width, _height ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0, _width, 0, _height, -100, 100 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + glDisable( GL_LINE_STIPPLE ); + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + glDisableClientState( GL_NORMAL_ARRAY ); + glDisableClientState( GL_COLOR_ARRAY ); + glDisable( GL_LIGHTING ); + glDisable( GL_COLOR_MATERIAL ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_TEXTURE_1D ); + + glEnable( GL_TEXTURE_2D ); + glDisable( GL_BLEND ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); + glBindTexture( GL_TEXTURE_2D, _tex ); + + + glColor4f( 1.0, 1.0, 1.0, 1.0 ); + glBegin( GL_QUADS ); + + glTexCoord2f( 0, 0 ); + glVertex3f( 0, 0, 0 ); + glTexCoord2f( 0, 1 ); + glVertex3f( 0, _height, 0 ); + glTexCoord2f( 1, 1 ); + glVertex3f( _width, _height, 0 ); + glTexCoord2f( 1, 0 ); + glVertex3f( _width, 0, 0 ); + glEnd(); + glBindTexture( GL_TEXTURE_2D, 0 ); + } +protected: + void construct() { + glGenTextures( 1, &_tex ); + _constructed = true; + } +private: +}; + #endif diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 49094dc3..a10489e3 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -81,6 +81,7 @@ struct camwindow_globals_private_t bool m_bCubicClipping; int m_nStrafeMode; bool m_bFaceWire; + int m_MSAA; camwindow_globals_private_t() : m_nMoveSpeed( 100 ), @@ -90,7 +91,8 @@ struct camwindow_globals_private_t m_bCamDiscrete( true ), m_bCubicClipping( false ), m_nStrafeMode( 3 ), - m_bFaceWire( true ){ + m_bFaceWire( true ), + m_MSAA( 8 ){ } }; @@ -710,6 +712,7 @@ static Shader* m_state_facewire; FreezePointer m_freezePointer; public: +FBO* m_fbo; GtkWidget* m_gl_widget; GtkWindow* m_parent; @@ -940,7 +943,30 @@ gboolean mousecontrol_button_press( GtkWidget* widget, GdkEventButton* event, Ca void camwnd_update_xor_rectangle( CamWnd& self, rect_t area ){ if ( GTK_WIDGET_VISIBLE( self.m_gl_widget ) ) { - self.m_XORRectangle.set( rectangle_from_area( area.min, area.max, self.getCamera().width, self.getCamera().height ) ); + if ( glwidget_make_current( self.m_gl_widget ) != FALSE ) { + if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) { + GlobalOpenGL_debugAssertNoErrors(); + + glDrawBuffer( GL_FRONT ); + self.m_fbo->blit(); + + glViewport( 0, 0, self.getCamera().width, self.getCamera().height ); + // set up viewpoint + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0, self.getCamera().width, 0, self.getCamera().height, -100, 100 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + self.m_XORRectangle.set( rectangle_from_area( area.min, area.max, self.getCamera().width, self.getCamera().height ) ); + + glDrawBuffer( GL_BACK ); + + GlobalOpenGL_debugAssertNoErrors(); + glwidget_make_current( self.m_gl_widget ); + } + } } } @@ -1048,6 +1074,7 @@ gboolean wheelmove_scroll( GtkWidget* widget, GdkEventScroll* event, CamWnd* cam } gboolean camera_size_allocate( GtkWidget* widget, GtkAllocation* allocation, CamWnd* camwnd ){ + camwnd->m_fbo->reset( allocation->width, allocation->height, g_camwindow_globals_private.m_MSAA, true ); camwnd->getCamera().width = allocation->width; camwnd->getCamera().height = allocation->height; Camera_updateProjection( camwnd->getCamera() ); @@ -1347,7 +1374,6 @@ CamWnd::CamWnd() : m_cameraview( m_Camera, &m_view, ReferenceCaller( *this ) ), m_gl_widget( glwidget_new( TRUE ) ), m_window_observer( NewWindowObserver() ), - m_XORRectangle( m_gl_widget ), m_deferredDraw( WidgetQueueDrawCaller( *m_gl_widget ) ), m_deferred_motion( selection_motion, m_window_observer ), m_deferred_motion_freemove( selection_motion_freemove, this ), @@ -1357,6 +1383,8 @@ CamWnd::CamWnd() : m_freelook_button_press_handler( 0 ), m_freelook_button_release_handler( 0 ), m_drawing( false ){ + m_fbo = GlobalOpenGL().support_ARB_framebuffer_object? new FBO : new FBO_fallback; + m_bFreeMove = false; GlobalWindowObservers_add( m_window_observer ); @@ -1398,6 +1426,8 @@ CamWnd::~CamWnd(){ gtk_widget_unref( m_gl_widget ); + delete m_fbo; + m_window_observer->release(); } @@ -1637,6 +1667,8 @@ void ShowStatsToggle(){ void CamWnd::Cam_Draw(){ // globalOutputStream() << "Cam_Draw()\n"; + m_fbo->start(); + glViewport( 0, 0, m_Camera.width, m_Camera.height ); #if 0 GLint viewprt[4]; @@ -1797,6 +1829,8 @@ void CamWnd::Cam_Draw(){ // bind back to the default texture so that we don't have problems // elsewhere using/modifying texture maps between contexts glBindTexture( GL_TEXTURE_2D, 0 ); + + m_fbo->save(); } void CamWnd::draw(){ @@ -1810,7 +1844,7 @@ void CamWnd::draw(){ GlobalOpenGL_debugAssertNoErrors(); //qglFinish(); - m_XORRectangle.set( rectangle_t() ); + //m_XORRectangle.set( rectangle_t() ); } glwidget_swap_buffers( m_gl_widget ); @@ -2085,6 +2119,28 @@ void RenderModeExport( const IntImportCallback& importer ){ } typedef FreeCaller1 RenderModeExportCaller; +void CamMSAAImport( int value ){ + g_camwindow_globals_private.m_MSAA = value ? 1 << value : value; + if ( g_camwnd != 0 ) { + g_camwnd->m_fbo->reset( g_camwnd->getCamera().width, g_camwnd->getCamera().height, g_camwindow_globals_private.m_MSAA, true ); + } +} +typedef FreeCaller1 MSAAImportCaller; + +void CamMSAAExport( const IntImportCallback& importer ){ + if( g_camwindow_globals_private.m_MSAA <= 0 ){ + importer( 0 ); + } + else{ + int exponent = 1; + while( !( ( g_camwindow_globals_private.m_MSAA >> exponent ) & 1 ) ){ + ++exponent; + } + importer( exponent ); + } +} +typedef FreeCaller1 MSAAExportCaller; + void fieldOfViewImport( float value ){ camera_t::fieldOfView = value; if( g_camwnd ){ @@ -2137,6 +2193,17 @@ void Camera_constructPreferences( PreferencesPage& page ){ ); } + if( GlobalOpenGL().support_ARB_framebuffer_object ){ + const char* samples[] = { "0", "2", "4", "8", "16", "32" }; + + page.appendCombo( + "MSAA", + STRING_ARRAY_RANGE( samples ), + IntImportCallback( MSAAImportCaller() ), + IntExportCallback( MSAAExportCaller() ) + ); + } + const char* strafe_mode[] = { "None", "Up", "Forward", "Both", "Both Inverted" }; page.appendCombo( @@ -2245,6 +2312,7 @@ void CamWnd_Construct(){ GlobalPreferenceSystem().registerPreference( "SI_Colors4", Vector3ImportStringCaller( g_camwindow_globals.color_cameraback ), Vector3ExportStringCaller( g_camwindow_globals.color_cameraback ) ); GlobalPreferenceSystem().registerPreference( "SI_Colors12", Vector3ImportStringCaller( g_camwindow_globals.color_selbrushes3d ), Vector3ExportStringCaller( g_camwindow_globals.color_selbrushes3d ) ); GlobalPreferenceSystem().registerPreference( "CameraRenderMode", makeIntStringImportCallback( RenderModeImportCaller() ), makeIntStringExportCallback( RenderModeExportCaller() ) ); + GlobalPreferenceSystem().registerPreference( "CameraMSAA", IntImportStringCaller( g_camwindow_globals_private.m_MSAA ), IntExportStringCaller( g_camwindow_globals_private.m_MSAA ) ); GlobalPreferenceSystem().registerPreference( "StrafeMode", IntImportStringCaller( g_camwindow_globals_private.m_nStrafeMode ), IntExportStringCaller( g_camwindow_globals_private.m_nStrafeMode ) ); GlobalPreferenceSystem().registerPreference( "CameraFaceWire", BoolImportStringCaller( g_camwindow_globals_private.m_bFaceWire ), BoolExportStringCaller( g_camwindow_globals_private.m_bFaceWire ) ); GlobalPreferenceSystem().registerPreference( "3DZoomInToPointer", BoolImportStringCaller( g_camwindow_globals.m_bZoomInToPointer ), BoolExportStringCaller( g_camwindow_globals.m_bZoomInToPointer ) ); diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp index a3753955..07455b82 100644 --- a/radiant/xywindow.cpp +++ b/radiant/xywindow.cpp @@ -71,6 +71,8 @@ #include "grid.h" #include "windowobservers.h" +#include "render.h" + void LoadTextureRGBA( qtexture_t* q, unsigned char* pPixels, int nWidth, int nHeight ); // d1223m @@ -354,6 +356,8 @@ struct xywindow_globals_private_t bool m_bChaseMouse; bool m_bSizePaint; + int m_MSAA; + xywindow_globals_private_t() : d_showgrid( true ), @@ -369,7 +373,8 @@ struct xywindow_globals_private_t // m_bCamXYUpdate( true ), m_bChaseMouse( true ), - m_bSizePaint( true ){ + m_bSizePaint( true ), + m_MSAA( 8 ){ } }; @@ -743,16 +748,31 @@ Shader* XYWnd::m_state_selected = 0; void xy_update_xor_rectangle( XYWnd& self, rect_t area ){ if ( GTK_WIDGET_VISIBLE( self.GetWidget() ) ) { - rectangle_t rect = rectangle_from_area( area.min, area.max, self.Width(), self.Height() ); -// int nDim1 = ( self.GetViewType() == YZ ) ? 1 : 0; -// int nDim2 = ( self.GetViewType() == XY ) ? 1 : 2; -// rect.x /= self.Scale(); -// rect.y /= self.Scale(); -// rect.w /= self.Scale(); -// rect.h /= self.Scale(); -// rect.x += self.GetOrigin()[nDim1]; -// rect.y += self.GetOrigin()[nDim2]; - self.m_XORRectangle.set( rect ); + if ( glwidget_make_current( self.GetWidget() ) != FALSE ) { + if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) { + GlobalOpenGL_debugAssertNoErrors(); + + glDrawBuffer( GL_FRONT ); + self.m_fbo->blit(); + + glViewport( 0, 0, self.Width(), self.Height() ); + // set up viewpoint + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glOrtho( 0, self.Width(), 0, self.Height(), -100, 100 ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + rectangle_t rect = rectangle_from_area( area.min, area.max, self.Width(), self.Height() ); + self.m_XORRectangle.set( rect ); + + glDrawBuffer( GL_BACK ); + + GlobalOpenGL_debugAssertNoErrors(); + glwidget_make_current( self.GetWidget() ); + } + } } } @@ -817,6 +837,7 @@ gboolean xywnd_wheel_scroll( GtkWidget* widget, GdkEventScroll* event, XYWnd* xy } gboolean xywnd_size_allocate( GtkWidget* widget, GtkAllocation* allocation, XYWnd* xywnd ){ + xywnd->m_fbo->reset( allocation->width, allocation->height, g_xywindow_globals_private.m_MSAA, false ); xywnd->m_nWidth = allocation->width; xywnd->m_nHeight = allocation->height; xywnd->updateProjection(); @@ -831,7 +852,7 @@ gboolean xywnd_expose( GtkWidget* widget, GdkEventExpose* event, XYWnd* xywnd ){ xywnd->XY_Draw(); GlobalOpenGL_debugAssertNoErrors(); - xywnd->m_XORRectangle.set( rectangle_t() ); + //xywnd->m_XORRectangle.set( rectangle_t() ); } glwidget_swap_buffers( xywnd->GetWidget() ); } @@ -852,8 +873,9 @@ XYWnd::XYWnd() : m_deferred_motion( xywnd_motion, this ), m_parent( 0 ), m_window_observer( NewWindowObserver() ), - m_XORRectangle( m_gl_widget ), m_chasemouse_handler( 0 ){ + m_fbo = GlobalOpenGL().support_ARB_framebuffer_object? new FBO : new FBO_fallback; + m_bActive = false; m_buttonstate = 0; @@ -918,6 +940,8 @@ XYWnd::XYWnd() : XYWnd::~XYWnd(){ onDestroyed(); + delete m_fbo; + if ( m_mnuDrop != 0 ) { gtk_widget_destroy( GTK_WIDGET( m_mnuDrop ) ); m_mnuDrop = 0; @@ -1774,13 +1798,14 @@ void XYWnd::XY_DrawAxis( void ){ Vector3 colourX = ( m_viewType == YZ ) ? g_xywindow_globals.AxisColorY : g_xywindow_globals.AxisColorX; Vector3 colourY = ( m_viewType == XY ) ? g_xywindow_globals.AxisColorY : g_xywindow_globals.AxisColorZ; +#if 0 //gray for nonActive if( !Active() ){ float grayX = vector3_dot( colourX, Vector3( 0.2989, 0.5870, 0.1140 ) ); float grayY = vector3_dot( colourY, Vector3( 0.2989, 0.5870, 0.1140 ) ); colourX[0] = colourX[1] = colourX[2] = grayX; colourY[0] = colourY[1] = colourY[2] = grayY; } - +#endif // draw two lines with corresponding axis colors to highlight current view // horizontal line: nDim1 color glLineWidth( 2 ); @@ -1854,6 +1879,7 @@ void XYWnd::RenderActive( void ){ glVertex2f( 0.5, m_nHeight - 0.5 ); glEnd(); } +#if 0 //gray for nonActive // we do this part (the old way) only if show_axis is disabled if ( !g_xywindow_globals_private.show_axis ) { glMatrixMode( GL_PROJECTION ); @@ -1902,7 +1928,7 @@ void XYWnd::RenderActive( void ){ XYWnd::XY_DrawAxis(); } - +#endif glDrawBuffer( GL_BACK ); GlobalOpenGL_debugAssertNoErrors(); glwidget_make_current( m_gl_widget ); @@ -2277,42 +2303,44 @@ void XYWnd::XY_DrawBlockGrid(){ } void XYWnd::DrawCameraIcon( const Vector3& origin, const Vector3& angles ){ - Cam.fov = 48 / m_fScale; - Cam.box = 16 / m_fScale; + float x, y, fov, box; + double a; + + fov = 48 / m_fScale; + box = 16 / m_fScale; // globalOutputStream() << "pitch " << angles[CAMERA_PITCH] << " yaw " << angles[CAMERA_YAW] << "\n"; if ( m_viewType == XY ) { - Cam.x = origin[0]; - Cam.y = origin[1]; - Cam.a = degrees_to_radians( angles[CAMERA_YAW] ); + x = origin[0]; + y = origin[1]; + a = degrees_to_radians( angles[CAMERA_YAW] ); } else if ( m_viewType == YZ ) { - Cam.x = origin[1]; - Cam.y = origin[2]; - Cam.a = degrees_to_radians( ( angles[CAMERA_YAW] > 180 ) ? ( 180.0f - angles[CAMERA_PITCH] ) : angles[CAMERA_PITCH] ); + x = origin[1]; + y = origin[2]; + a = degrees_to_radians( ( angles[CAMERA_YAW] > 180 ) ? ( 180.0f - angles[CAMERA_PITCH] ) : angles[CAMERA_PITCH] ); } else { - Cam.x = origin[0]; - Cam.y = origin[2]; - Cam.a = degrees_to_radians( ( angles[CAMERA_YAW] < 270 && angles[CAMERA_YAW] > 90 ) ? ( 180.0f - angles[CAMERA_PITCH] ) : angles[CAMERA_PITCH] ); + x = origin[0]; + y = origin[2]; + a = degrees_to_radians( ( angles[CAMERA_YAW] < 270 && angles[CAMERA_YAW] > 90 ) ? ( 180.0f - angles[CAMERA_PITCH] ) : angles[CAMERA_PITCH] ); } - //glColor3f( 0.0, 0.0, 1.0 ); - glColor3f( 1.0, 1.0, 1.0 ); + glColor3f( 0.0, 0.0, 1.0 ); glBegin( GL_LINE_STRIP ); - glVertex3f( Cam.x - Cam.box,Cam.y,0 ); - glVertex3f( Cam.x,Cam.y + ( Cam.box / 2 ),0 ); - glVertex3f( Cam.x + Cam.box,Cam.y,0 ); - glVertex3f( Cam.x,Cam.y - ( Cam.box / 2 ),0 ); - glVertex3f( Cam.x - Cam.box,Cam.y,0 ); - glVertex3f( Cam.x + Cam.box,Cam.y,0 ); + glVertex3f( x - box,y,0 ); + glVertex3f( x,y + ( box / 2 ),0 ); + glVertex3f( x + box,y,0 ); + glVertex3f( x,y - ( box / 2 ),0 ); + glVertex3f( x - box,y,0 ); + glVertex3f( x + box,y,0 ); glEnd(); glBegin( GL_LINE_STRIP ); - glVertex3f( Cam.x + static_cast( Cam.fov * cos( Cam.a + c_pi / 4 ) ), Cam.y + static_cast( Cam.fov * sin( Cam.a + c_pi / 4 ) ), 0 ); - glVertex3f( Cam.x, Cam.y, 0 ); - glVertex3f( Cam.x + static_cast( Cam.fov * cos( Cam.a - c_pi / 4 ) ), Cam.y + static_cast( Cam.fov * sin( Cam.a - c_pi / 4 ) ), 0 ); + glVertex3f( x + static_cast( fov * cos( a + c_pi / 4 ) ), y + static_cast( fov * sin( a + c_pi / 4 ) ), 0 ); + glVertex3f( x, y, 0 ); + glVertex3f( x + static_cast( fov * cos( a - c_pi / 4 ) ), y + static_cast( fov * sin( a - c_pi / 4 ) ), 0 ); glEnd(); } @@ -2321,58 +2349,36 @@ void XYWnd::UpdateCameraIcon( void ){ if ( glwidget_make_current( m_gl_widget ) != FALSE ) { if ( Map_Valid( g_map ) && ScreenUpdates_Enabled() ) { GlobalOpenGL_debugAssertNoErrors(); + glDrawBuffer( GL_FRONT ); - { - // clear - glViewport( 0, 0, m_nWidth, m_nHeight ); - // set up viewpoint - glMatrixMode( GL_PROJECTION ); - glLoadMatrixf( reinterpret_cast( &m_projection ) ); + m_fbo->blit(); - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - glScalef( m_fScale, m_fScale, 1 ); - int nDim1 = ( m_viewType == YZ ) ? 1 : 0; - int nDim2 = ( m_viewType == XY ) ? 1 : 2; - glTranslatef( -m_vOrigin[nDim1], -m_vOrigin[nDim2], 0 ); + glViewport( 0, 0, m_nWidth, m_nHeight ); + // set up viewpoint + glMatrixMode( GL_PROJECTION ); + glLoadMatrixf( reinterpret_cast( &m_projection ) ); - glDisable( GL_LINE_STIPPLE ); - glDisableClientState( GL_TEXTURE_COORD_ARRAY ); - glDisableClientState( GL_NORMAL_ARRAY ); - glDisableClientState( GL_COLOR_ARRAY ); - glDisable( GL_TEXTURE_2D ); - glDisable( GL_LIGHTING ); - glDisable( GL_COLOR_MATERIAL ); - glDisable( GL_DEPTH_TEST ); - glDisable( GL_TEXTURE_1D ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glScalef( m_fScale, m_fScale, 1 ); + int nDim1 = ( m_viewType == YZ ) ? 1 : 0; + int nDim2 = ( m_viewType == XY ) ? 1 : 2; + glTranslatef( -m_vOrigin[nDim1], -m_vOrigin[nDim2], 0 ); - glEnable( GL_BLEND ); - glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO ); + glDisable( GL_LINE_STIPPLE ); + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + glDisableClientState( GL_NORMAL_ARRAY ); + glDisableClientState( GL_COLOR_ARRAY ); + glDisable( GL_TEXTURE_2D ); + glDisable( GL_LIGHTING ); + glDisable( GL_COLOR_MATERIAL ); + glDisable( GL_DEPTH_TEST ); + glDisable( GL_TEXTURE_1D ); - //glColor3f( 0.0, 0.0, 1.0 ); - glColor3f( 1.0, 1.0, 1.0 ); - glBegin( GL_LINE_STRIP ); - glVertex3f( Cam.x - Cam.box,Cam.y,0 ); - glVertex3f( Cam.x,Cam.y + ( Cam.box / 2 ),0 ); - glVertex3f( Cam.x + Cam.box,Cam.y,0 ); - glVertex3f( Cam.x,Cam.y - ( Cam.box / 2 ),0 ); - glVertex3f( Cam.x - Cam.box,Cam.y,0 ); - glVertex3f( Cam.x + Cam.box,Cam.y,0 ); - glEnd(); - - glBegin( GL_LINE_STRIP ); - glVertex3f( Cam.x + static_cast( Cam.fov * cos( Cam.a + c_pi / 4 ) ), Cam.y + static_cast( Cam.fov * sin( Cam.a + c_pi / 4 ) ), 0 ); - glVertex3f( Cam.x, Cam.y, 0 ); - glVertex3f( Cam.x + static_cast( Cam.fov * cos( Cam.a - c_pi / 4 ) ), Cam.y + static_cast( Cam.fov * sin( Cam.a - c_pi / 4 ) ), 0 ); - glEnd(); - - XYWnd::DrawCameraIcon( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ), Camera_getAngles( *g_pParentWnd->GetCamWnd() ) ); - - glDisable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - } + XYWnd::DrawCameraIcon( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ), Camera_getAngles( *g_pParentWnd->GetCamWnd() ) ); glDrawBuffer( GL_BACK ); + GlobalOpenGL_debugAssertNoErrors(); glwidget_make_current( m_gl_widget ); } @@ -2680,6 +2686,17 @@ void XYWnd::updateModelview(){ void XYWnd::XY_Draw(){ // globalOutputStream() << "XY_Draw()\n"; +/* + int maxSamples; + glGetIntegerv(GL_MAX_SAMPLES,&maxSamples); + globalOutputStream() << maxSamples << " GL_MAX_SAMPLES\n"; + int curSamples; + glGetIntegerv(GL_SAMPLE_BUFFERS,&curSamples); + globalOutputStream() << curSamples << " GL_SAMPLE_BUFFERS\n"; + glGetIntegerv(GL_SAMPLES,&curSamples); + globalOutputStream() << curSamples << " GL_SAMPLES\n"; +*/ + m_fbo->start(); // // clear // @@ -2812,18 +2829,14 @@ void XYWnd::XY_Draw(){ GlobalOpenGL_debugAssertNoErrors(); - // reset modelview - glLoadIdentity(); - glScalef( m_fScale, m_fScale, 1 ); - glTranslatef( -m_vOrigin[nDim1], -m_vOrigin[nDim2], 0 ); + { + // reset modelview + glLoadIdentity(); + glScalef( m_fScale, m_fScale, 1 ); + glTranslatef( -m_vOrigin[nDim1], -m_vOrigin[nDim2], 0 ); - glEnable( GL_BLEND ); - glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO ); - DrawCameraIcon( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ), Camera_getAngles( *g_pParentWnd->GetCamWnd() ) ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - glDisable( GL_BLEND ); - - Feedback_draw2D( m_viewType ); + Feedback_draw2D( m_viewType ); + } if ( g_xywindow_globals_private.show_outline ) { if ( Active() ) { @@ -2884,6 +2897,20 @@ void XYWnd::XY_Draw(){ m_render_time.start(); } + m_fbo->save(); + + { + // reset modelview + glMatrixMode( GL_PROJECTION ); + glLoadMatrixf( reinterpret_cast( &m_projection ) ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glScalef( m_fScale, m_fScale, 1 ); + glTranslatef( -m_vOrigin[nDim1], -m_vOrigin[nDim2], 0 ); + DrawCameraIcon( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ), Camera_getAngles( *g_pParentWnd->GetCamWnd() ) ); + } + GlobalOpenGL_debugAssertNoErrors(); glFinish(); @@ -3266,6 +3293,34 @@ void ToggleShowGrid(){ XY_UpdateAllWindows(); } +void MSAAImport( int value ){ + g_xywindow_globals_private.m_MSAA = value ? 1 << value : value; + if ( g_pParentWnd->GetXYWnd() ) { + g_pParentWnd->GetXYWnd()->m_fbo->reset( g_pParentWnd->GetXYWnd()->Width(), g_pParentWnd->GetXYWnd()->Height(), g_xywindow_globals_private.m_MSAA, false ); + } + if ( g_pParentWnd->GetXZWnd() ) { + g_pParentWnd->GetXZWnd()->m_fbo->reset( g_pParentWnd->GetXZWnd()->Width(), g_pParentWnd->GetXZWnd()->Height(), g_xywindow_globals_private.m_MSAA, false ); + } + if ( g_pParentWnd->GetYZWnd() ) { + g_pParentWnd->GetYZWnd()->m_fbo->reset( g_pParentWnd->GetYZWnd()->Width(), g_pParentWnd->GetYZWnd()->Height(), g_xywindow_globals_private.m_MSAA, false ); + } +} +typedef FreeCaller1 MSAAImportCaller; + +void MSAAExport( const IntImportCallback& importer ){ + if( g_xywindow_globals_private.m_MSAA <= 0 ){ + importer( 0 ); + } + else{ + int exponent = 1; + while( !( ( g_xywindow_globals_private.m_MSAA >> exponent ) & 1 ) ){ + ++exponent; + } + importer( exponent ); + } +} +typedef FreeCaller1 MSAAExportCaller; + void XYShow_registerCommands(){ GlobalToggles_insert( "ToggleSizePaint", FreeCaller(), ToggleItem::AddCallbackCaller( g_show_size_item ), Accelerator( 'J' ) ); @@ -3296,6 +3351,17 @@ void Orthographic_constructPreferences( PreferencesPage& page ){ page.appendCheckBox( "", "Chase mouse during drags", g_xywindow_globals_private.m_bChaseMouse ); // page.appendCheckBox( "", "Update views on camera move", g_xywindow_globals_private.m_bCamXYUpdate ); page.appendCheckBox( "", "Zoom In to Mouse pointer", g_xywindow_globals.m_bZoomInToPointer ); + + if( GlobalOpenGL().support_ARB_framebuffer_object ){ + const char* samples[] = { "0", "2", "4", "8", "16", "32" }; + + page.appendCombo( + "MSAA", + STRING_ARRAY_RANGE( samples ), + IntImportCallback( MSAAImportCaller() ), + IntExportCallback( MSAAExportCaller() ) + ); + } } void Orthographic_constructPage( PreferenceGroup& group ){ PreferencesPage page( group.createPage( "Orthographic", "Orthographic View Preferences" ) ); @@ -3354,6 +3420,7 @@ void XYWindow_Construct(){ GlobalPreferenceSystem().registerPreference( "ClipCaulk", BoolImportStringCaller( g_clip_useCaulk ), BoolExportStringCaller( g_clip_useCaulk ) ); // GlobalPreferenceSystem().registerPreference( "NewRightClick", BoolImportStringCaller( g_xywindow_globals.m_bRightClick ), BoolExportStringCaller( g_xywindow_globals.m_bRightClick ) ); + GlobalPreferenceSystem().registerPreference( "XYMSAA", IntImportStringCaller( g_xywindow_globals_private.m_MSAA ), IntExportStringCaller( g_xywindow_globals_private.m_MSAA ) ); GlobalPreferenceSystem().registerPreference( "2DZoomInToPointer", BoolImportStringCaller( g_xywindow_globals.m_bZoomInToPointer ), BoolExportStringCaller( g_xywindow_globals.m_bZoomInToPointer ) ); GlobalPreferenceSystem().registerPreference( "ChaseMouse", BoolImportStringCaller( g_xywindow_globals_private.m_bChaseMouse ), BoolExportStringCaller( g_xywindow_globals_private.m_bChaseMouse ) ); GlobalPreferenceSystem().registerPreference( "SizePainting", BoolImportStringCaller( g_xywindow_globals_private.m_bSizePaint ), BoolExportStringCaller( g_xywindow_globals_private.m_bSizePaint ) ); diff --git a/radiant/xywindow.h b/radiant/xywindow.h index fe1cf685..e0a1d4ee 100644 --- a/radiant/xywindow.h +++ b/radiant/xywindow.h @@ -66,6 +66,7 @@ inline const char* ViewType_getTitle( VIEWTYPE viewtype ){ } #include "timer.h" +class FBO; class XYWnd { @@ -76,6 +77,7 @@ guint m_exposeHandler; DeferredDraw m_deferredDraw; DeferredMotion m_deferred_motion; public: +FBO* m_fbo; GtkWindow* m_parent; XYWnd(); ~XYWnd(); @@ -147,12 +149,6 @@ void SetActive( bool b ){ bool Active(){ return m_bActive; }; -struct camera_icon_t -{ - float x, y, fov, box; - double a; -}; -camera_icon_t Cam; void UpdateCameraIcon();