2020-03-02 10:58:46 +01:00
#include "libslic3r/libslic3r.h"
2018-05-09 10:47:04 +02:00
#include "GLCanvas3DManager.hpp"
#include "../../slic3r/GUI/GUI.hpp"
#include "../../slic3r/GUI/AppConfig.hpp"
2018-06-11 15:13:13 +02:00
#include "../../slic3r/GUI/GLCanvas3D.hpp"
2018-05-09 10:47:04 +02:00
#include <GL/glew.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
2020-03-02 11:40:35 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
#include <boost/log/trivial.hpp>
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 10:47:04 +02:00
#include <wx/glcanvas.h>
2018-05-30 15:18:45 +02:00
#include <wx/timer.h>
2020-02-03 10:13:15 +01:00
#include <wx/msgdlg.h>
2018-05-09 10:47:04 +02:00
#include <vector>
#include <string>
#include <iostream>
2020-02-27 14:55:27 +01:00
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
// Part of temporary hack to remove crash when closing on OSX 10.9.5
#include <wx/platinfo.h>
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2019-05-23 13:49:57 +02:00
#ifdef __APPLE__
#include "../Utils/MacDarkMode.hpp"
#endif // __APPLE__
2018-05-09 10:47:04 +02:00
namespace Slic3r {
namespace GUI {
2020-03-02 10:58:46 +01:00
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-06-04 10:14:09 +02:00
GLCanvas3DManager :: GLInfo :: GLInfo ()
2019-05-23 13:49:57 +02:00
: m_detected ( false )
, m_version ( "" )
, m_glsl_version ( "" )
, m_vendor ( "" )
, m_renderer ( "" )
, m_max_tex_size ( 0 )
, m_max_anisotropy ( 0.0f )
2018-05-09 10:47:04 +02:00
{
}
2020-03-02 10:58:46 +01:00
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 10:47:04 +02:00
2019-05-23 13:49:57 +02:00
const std :: string & GLCanvas3DManager :: GLInfo :: get_version () const
{
if ( ! m_detected )
detect ();
return m_version ;
}
const std :: string & GLCanvas3DManager :: GLInfo :: get_glsl_version () const
{
if ( ! m_detected )
detect ();
return m_glsl_version ;
}
const std :: string & GLCanvas3DManager :: GLInfo :: get_vendor () const
{
if ( ! m_detected )
detect ();
return m_vendor ;
}
const std :: string & GLCanvas3DManager :: GLInfo :: get_renderer () const
{
if ( ! m_detected )
detect ();
return m_renderer ;
}
int GLCanvas3DManager :: GLInfo :: get_max_tex_size () const
{
if ( ! m_detected )
detect ();
// clamp to avoid the texture generation become too slow and use too much GPU memory
#ifdef __APPLE__
// and use smaller texture for non retina systems
return ( Slic3r :: GUI :: mac_max_scaling_factor () > 1.0 ) ? std :: min ( m_max_tex_size , 8192 ) : std :: min ( m_max_tex_size / 2 , 4096 );
#else
// and use smaller texture for older OpenGL versions
return is_version_greater_or_equal_to ( 3 , 0 ) ? std :: min ( m_max_tex_size , 8192 ) : std :: min ( m_max_tex_size / 2 , 4096 );
#endif // __APPLE__
}
float GLCanvas3DManager :: GLInfo :: get_max_anisotropy () const
{
if ( ! m_detected )
detect ();
return m_max_anisotropy ;
}
void GLCanvas3DManager :: GLInfo :: detect () const
{
const char * data = ( const char * ) :: glGetString ( GL_VERSION );
if ( data != nullptr )
m_version = data ;
data = ( const char * ) :: glGetString ( GL_SHADING_LANGUAGE_VERSION );
if ( data != nullptr )
m_glsl_version = data ;
data = ( const char * ) :: glGetString ( GL_VENDOR );
if ( data != nullptr )
m_vendor = data ;
data = ( const char * ) :: glGetString ( GL_RENDERER );
if ( data != nullptr )
m_renderer = data ;
glsafe ( :: glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & m_max_tex_size ));
2019-10-10 09:35:21 +02:00
m_max_tex_size /= 2 ;
2020-02-27 15:38:35 +01:00
if ( Slic3r :: total_physical_memory () / ( 1024 * 1024 * 1024 ) < 6 )
m_max_tex_size /= 2 ;
2019-05-23 13:49:57 +02:00
if ( GLEW_EXT_texture_filter_anisotropic )
glsafe ( :: glGetFloatv ( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT , & m_max_anisotropy ));
m_detected = true ;
}
2018-06-04 10:14:09 +02:00
2019-05-23 13:49:57 +02:00
bool GLCanvas3DManager :: GLInfo :: is_version_greater_or_equal_to ( unsigned int major , unsigned int minor ) const
{
if ( ! m_detected )
detect ();
std :: vector < std :: string > tokens ;
boost :: split ( tokens , m_version , boost :: is_any_of ( " " ), boost :: token_compress_on );
if ( tokens . empty ())
return false ;
std :: vector < std :: string > numbers ;
boost :: split ( numbers , tokens [ 0 ], boost :: is_any_of ( "." ), boost :: token_compress_on );
unsigned int gl_major = 0 ;
unsigned int gl_minor = 0 ;
if ( numbers . size () > 0 )
gl_major = :: atoi ( numbers [ 0 ]. c_str ());
if ( numbers . size () > 1 )
gl_minor = :: atoi ( numbers [ 1 ]. c_str ());
if ( gl_major < major )
return false ;
else if ( gl_major > major )
return true ;
else
return gl_minor >= minor ;
}
2018-06-04 10:14:09 +02:00
std :: string GLCanvas3DManager :: GLInfo :: to_string ( bool format_as_html , bool extensions ) const
{
2019-05-23 13:49:57 +02:00
if ( ! m_detected )
detect ();
2018-06-04 10:14:09 +02:00
std :: stringstream out ;
std :: string h2_start = format_as_html ? "<b>" : "" ;
2018-07-12 13:34:39 +02:00
std :: string h2_end = format_as_html ? "</b>" : "" ;
std :: string b_start = format_as_html ? "<b>" : "" ;
std :: string b_end = format_as_html ? "</b>" : "" ;
2018-06-04 10:14:09 +02:00
std :: string line_end = format_as_html ? "<br>" : " \n " ;
out << h2_start << "OpenGL installation" << h2_end << line_end ;
2019-05-23 13:49:57 +02:00
out << b_start << "GL version: " << b_end << ( m_version . empty () ? "N/A" : m_version ) << line_end ;
out << b_start << "Vendor: " << b_end << ( m_vendor . empty () ? "N/A" : m_vendor ) << line_end ;
out << b_start << "Renderer: " << b_end << ( m_renderer . empty () ? "N/A" : m_renderer ) << line_end ;
out << b_start << "GLSL version: " << b_end << ( m_glsl_version . empty () ? "N/A" : m_glsl_version ) << line_end ;
2018-07-12 12:15:30 +02:00
2018-06-04 10:14:09 +02:00
if ( extensions )
{
std :: vector < std :: string > extensions_list ;
2018-07-12 13:10:18 +02:00
std :: string extensions_str = ( const char * ) :: glGetString ( GL_EXTENSIONS );
boost :: split ( extensions_list , extensions_str , boost :: is_any_of ( " " ), boost :: token_compress_off );
2018-07-12 12:15:30 +02:00
if ( ! extensions_list . empty ())
2018-06-04 10:14:09 +02:00
{
2018-07-12 12:15:30 +02:00
out << h2_start << "Installed extensions:" << h2_end << line_end ;
std :: sort ( extensions_list . begin (), extensions_list . end ());
for ( const std :: string & ext : extensions_list )
{
out << ext << line_end ;
}
2018-06-04 10:14:09 +02:00
}
}
return out . str ();
2018-05-09 10:47:04 +02:00
}
2019-05-23 13:49:57 +02:00
GLCanvas3DManager :: GLInfo GLCanvas3DManager :: s_gl_info ;
2020-03-02 10:58:46 +01:00
bool GLCanvas3DManager :: s_compressed_textures_supported = false ;
#if ENABLE_NON_STATIC_CANVAS_MANAGER
GLCanvas3DManager :: EMultisampleState GLCanvas3DManager :: s_multisample = GLCanvas3DManager :: EMultisampleState :: Unknown ;
GLCanvas3DManager :: EFramebufferType GLCanvas3DManager :: s_framebuffers_type = GLCanvas3DManager :: EFramebufferType :: None ;
#else
GLCanvas3DManager :: EMultisampleState GLCanvas3DManager :: s_multisample = GLCanvas3DManager :: MS_Unknown ;
GLCanvas3DManager :: EFramebufferType GLCanvas3DManager :: s_framebuffers_type = GLCanvas3DManager :: FB_None ;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-10-02 14:01:22 +02:00
2020-02-27 14:55:27 +01:00
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
GLCanvas3DManager :: OSInfo GLCanvas3DManager :: s_os_info ;
#endif // __APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2018-10-02 14:01:22 +02:00
2020-03-02 10:58:46 +01:00
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 10:47:04 +02:00
GLCanvas3DManager :: GLCanvas3DManager ()
2018-10-04 10:41:11 +02:00
: m_context ( nullptr )
2018-06-11 15:49:04 +02:00
, m_gl_initialized ( false )
2018-05-09 10:47:04 +02:00
{
}
2020-03-02 10:58:46 +01:00
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 10:47:04 +02:00
2018-10-04 10:41:11 +02:00
GLCanvas3DManager ::~ GLCanvas3DManager ()
{
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( m_context != nullptr )
delete m_context ;
#else
this -> destroy ();
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-10-04 10:41:11 +02:00
}
2020-03-02 10:58:46 +01:00
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
2019-03-07 11:49:00 +01:00
bool GLCanvas3DManager :: add ( wxGLCanvas * canvas , Bed3D & bed , Camera & camera , GLToolbar & view_toolbar )
2018-06-11 15:49:04 +02:00
{
if ( canvas == nullptr )
return false ;
2019-05-21 14:19:03 +02:00
if ( do_get_canvas ( canvas ) != m_canvases . end ())
2018-05-09 10:47:04 +02:00
return false ;
2019-03-07 11:49:00 +01:00
GLCanvas3D * canvas3D = new GLCanvas3D ( canvas , bed , camera , view_toolbar );
2018-05-09 10:47:04 +02:00
if ( canvas3D == nullptr )
return false ;
2018-06-06 14:19:28 +02:00
canvas3D -> bind_event_handlers ();
2018-10-04 10:41:11 +02:00
if ( m_context == nullptr )
{
m_context = new wxGLContext ( canvas );
if ( m_context == nullptr )
return false ;
2020-02-27 14:55:27 +01:00
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of temporary hack to remove crash when closing on OSX 10.9.5
s_os_info . major = wxPlatformInfo :: Get (). GetOSMajorVersion ();
s_os_info . minor = wxPlatformInfo :: Get (). GetOSMinorVersion ();
s_os_info . micro = wxPlatformInfo :: Get (). GetOSMicroVersion ();
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2018-10-04 10:41:11 +02:00
}
canvas3D -> set_context ( m_context );
2018-05-09 10:47:04 +02:00
m_canvases . insert ( CanvasesMap :: value_type ( canvas , canvas3D ));
return true ;
}
bool GLCanvas3DManager :: remove ( wxGLCanvas * canvas )
{
2019-05-21 14:19:03 +02:00
CanvasesMap :: iterator it = do_get_canvas ( canvas );
2018-05-09 10:47:04 +02:00
if ( it == m_canvases . end ())
return false ;
2018-06-06 14:19:28 +02:00
it -> second -> unbind_event_handlers ();
2018-05-09 10:47:04 +02:00
delete it -> second ;
m_canvases . erase ( it );
return true ;
}
void GLCanvas3DManager :: remove_all ()
{
for ( CanvasesMap :: value_type & item : m_canvases )
{
2018-06-06 14:19:28 +02:00
item . second -> unbind_event_handlers ();
2018-05-09 10:47:04 +02:00
delete item . second ;
}
m_canvases . clear ();
}
2020-03-02 10:58:46 +01:00
size_t GLCanvas3DManager :: count () const
2018-05-09 10:47:04 +02:00
{
2020-03-02 10:58:46 +01:00
return m_canvases . size ();
2018-05-09 10:47:04 +02:00
}
2020-03-02 10:58:46 +01:00
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 10:47:04 +02:00
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
bool GLCanvas3DManager :: init_gl ()
#else
2018-05-09 10:47:04 +02:00
void GLCanvas3DManager :: init_gl ()
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 10:47:04 +02:00
{
if ( ! m_gl_initialized )
{
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( glewInit () != GLEW_OK )
{
BOOST_LOG_TRIVIAL ( error ) << "Unable to init glew library" ;
return false ;
}
#else
2018-05-09 10:47:04 +02:00
glewInit ();
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-06-20 14:34:20 +02:00
m_gl_initialized = true ;
2019-05-21 14:19:03 +02:00
if ( GLEW_EXT_texture_compression_s3tc )
s_compressed_textures_supported = true ;
else
s_compressed_textures_supported = false ;
2019-08-30 09:19:45 +02:00
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( GLEW_ARB_framebuffer_object )
s_framebuffers_type = EFramebufferType :: Arb ;
else if ( GLEW_EXT_framebuffer_object )
s_framebuffers_type = EFramebufferType :: Ext ;
else
s_framebuffers_type = EFramebufferType :: None ;
#else
2019-11-05 14:50:58 +01:00
if ( GLEW_ARB_framebuffer_object )
s_framebuffers_type = FB_Arb ;
else if ( GLEW_EXT_framebuffer_object )
s_framebuffers_type = FB_Ext ;
2019-10-29 10:27:51 +01:00
else
2019-11-05 14:50:58 +01:00
s_framebuffers_type = FB_None ;
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-10-29 10:27:51 +01:00
2019-08-30 09:19:45 +02:00
if ( ! s_gl_info . is_version_greater_or_equal_to ( 2 , 0 )) {
// Complain about the OpenGL version.
wxString message = wxString :: Format (
_ ( L ( "PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n "
"while OpenGL version %s, render %s, vendor %s was detected." )), wxString ( s_gl_info . get_version ()), wxString ( s_gl_info . get_renderer ()), wxString ( s_gl_info . get_vendor ()));
message += " \n " ;
message += _ ( L ( "You may need to update your graphics card driver." ));
#ifdef _WIN32
message += " \n " ;
message += _ ( L ( "As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter." ));
#endif
wxMessageBox ( message , wxString ( "PrusaSlicer - " ) + _ ( L ( "Unsupported OpenGL version" )), wxOK | wxICON_ERROR );
}
2018-05-09 10:47:04 +02:00
}
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
return true ;
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-05-09 10:47:04 +02:00
}
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGLContext * GLCanvas3DManager :: init_glcontext ( wxGLCanvas & canvas )
{
if ( m_context == nullptr )
m_context = new wxGLContext ( & canvas );
return m_context ;
}
#else
2018-06-04 13:15:28 +02:00
bool GLCanvas3DManager :: init ( wxGLCanvas * canvas )
2018-05-23 09:57:44 +02:00
{
2019-05-21 14:19:03 +02:00
CanvasesMap :: const_iterator it = do_get_canvas ( canvas );
2018-06-04 13:15:28 +02:00
if ( it != m_canvases . end ())
2019-05-21 14:19:03 +02:00
return ( it -> second != nullptr ) ? init ( * it -> second ) : false ;
2018-06-04 13:15:28 +02:00
else
return false ;
2018-05-23 09:57:44 +02:00
}
2019-08-22 20:02:25 +02:00
void GLCanvas3DManager :: destroy ()
{
if ( m_context != nullptr )
{
2020-02-27 14:55:27 +01:00
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5
// the crash is inside wxGLContext destructor
if ( s_os_info . major == 10 && s_os_info . minor == 9 && s_os_info . micro == 5 )
return ;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2019-08-22 20:02:25 +02:00
delete m_context ;
m_context = nullptr ;
}
}
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2019-08-22 20:02:25 +02:00
2020-03-02 10:58:46 +01:00
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-10-11 10:24:19 +02:00
GLCanvas3D * GLCanvas3DManager :: get_canvas ( wxGLCanvas * canvas )
{
2019-05-21 14:19:03 +02:00
CanvasesMap :: const_iterator it = do_get_canvas ( canvas );
2018-10-11 10:24:19 +02:00
return ( it != m_canvases . end ()) ? it -> second : nullptr ;
}
2020-03-02 10:58:46 +01:00
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-06-08 09:40:00 +02:00
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
wxGLCanvas * GLCanvas3DManager :: create_wxglcanvas ( wxWindow & parent )
#else
2018-10-01 16:48:08 +02:00
wxGLCanvas * GLCanvas3DManager :: create_wxglcanvas ( wxWindow * parent )
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-10-01 16:48:08 +02:00
{
2019-08-07 14:55:34 +02:00
int attribList [] = {
WX_GL_RGBA ,
WX_GL_DOUBLEBUFFER ,
// RGB channels each should be allocated with 8 bit depth. One should almost certainly get these bit depths by default.
WX_GL_MIN_RED , 8 ,
WX_GL_MIN_GREEN , 8 ,
WX_GL_MIN_BLUE , 8 ,
// Requesting an 8 bit alpha channel. Interestingly, the NVIDIA drivers would most likely work with some alpha plane, but glReadPixels would not return
// the alpha channel on NVIDIA if not requested when the GL context is created.
2019-08-07 15:03:43 +02:00
WX_GL_MIN_ALPHA , 8 ,
2019-08-07 14:55:34 +02:00
WX_GL_DEPTH_SIZE , 24 ,
WX_GL_SAMPLE_BUFFERS , GL_TRUE ,
WX_GL_SAMPLES , 4 ,
0
};
2018-10-01 16:48:08 +02:00
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
if ( s_multisample == EMultisampleState :: Unknown )
#else
2018-10-02 14:01:22 +02:00
if ( s_multisample == MS_Unknown )
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-10-02 14:01:22 +02:00
{
2019-05-21 14:19:03 +02:00
detect_multisample ( attribList );
// // debug output
// std::cout << "Multisample " << (can_multisample() ? "enabled" : "disabled") << std::endl;
2018-10-02 14:01:22 +02:00
}
2019-05-21 14:19:03 +02:00
if ( ! can_multisample ())
2019-08-07 15:03:43 +02:00
attribList [ 12 ] = 0 ;
2018-10-01 16:48:08 +02:00
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
return new wxGLCanvas ( & parent , wxID_ANY , attribList , wxDefaultPosition , wxDefaultSize , wxWANTS_CHARS );
#else
2019-02-15 15:35:32 +01:00
return new wxGLCanvas ( parent , wxID_ANY , attribList , wxDefaultPosition , wxDefaultSize , wxWANTS_CHARS );
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-10-01 16:48:08 +02:00
}
2020-03-02 10:58:46 +01:00
#if !ENABLE_NON_STATIC_CANVAS_MANAGER
2019-05-21 14:19:03 +02:00
GLCanvas3DManager :: CanvasesMap :: iterator GLCanvas3DManager :: do_get_canvas ( wxGLCanvas * canvas )
2018-05-09 10:47:04 +02:00
{
return ( canvas == nullptr ) ? m_canvases . end () : m_canvases . find ( canvas );
}
2019-05-21 14:19:03 +02:00
GLCanvas3DManager :: CanvasesMap :: const_iterator GLCanvas3DManager :: do_get_canvas ( wxGLCanvas * canvas ) const
2018-05-09 10:47:04 +02:00
{
return ( canvas == nullptr ) ? m_canvases . end () : m_canvases . find ( canvas );
}
2019-05-21 14:19:03 +02:00
bool GLCanvas3DManager :: init ( GLCanvas3D & canvas )
2018-06-04 13:15:28 +02:00
{
if ( ! m_gl_initialized )
init_gl ();
2019-07-01 12:28:16 +02:00
return canvas . init ();
2018-06-04 13:15:28 +02:00
}
2020-03-02 10:58:46 +01:00
#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER
2018-06-04 13:15:28 +02:00
2019-05-21 14:19:03 +02:00
void GLCanvas3DManager :: detect_multisample ( int * attribList )
2018-10-02 14:01:22 +02:00
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER ;
2019-06-25 09:20:58 +02:00
bool enable_multisample = wxVersion >= 30003 ;
2020-03-02 10:58:46 +01:00
#if ENABLE_NON_STATIC_CANVAS_MANAGER
s_multisample = ( enable_multisample && wxGLCanvas :: IsDisplaySupported ( attribList )) ? EMultisampleState :: Enabled : EMultisampleState :: Disabled ;
#else
2018-10-02 14:01:22 +02:00
s_multisample = ( enable_multisample && wxGLCanvas :: IsDisplaySupported ( attribList )) ? MS_Enabled : MS_Disabled ;
2020-03-02 10:58:46 +01:00
#endif // ENABLE_NON_STATIC_CANVAS_MANAGER
2018-10-02 14:01:22 +02:00
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
}
2018-05-09 10:47:04 +02:00
} // namespace GUI
} // namespace Slic3r