From c39d2e0a3822e695efdfb2ead77a09defd6ed8c1 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 8 Jun 2008 00:12:12 +0000 Subject: [PATCH] added multisampling (anti-aliasing) support to wxGLCanvas (#9145) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@54022 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/glcanvas.h | 15 +- include/wx/mac/carbon/glcanvas.h | 3 + include/wx/msw/glcanvas.h | 3 +- include/wx/unix/glx11.h | 3 + interface/glcanvas.h | 8 +- src/common/glcmn.cpp | 24 +++ src/mac/carbon/glcanvas.cpp | 58 ++++++ src/msw/glcanvas.cpp | 295 ++++++++++++++++++++++++++++++- src/unix/glx11.cpp | 46 +++++ 10 files changed, 445 insertions(+), 11 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index d197393401..185cc4f340 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -292,6 +292,7 @@ All (GUI): - Added wxWindow::Show/HideWithEffect() - Added wxWrapSizer (Arne Steinarson) - Added wxSpinCtrlDouble (John Labenski) +- Added multisample (anti-aliasing) support to wxGLCanvas (Olivier Playez). - Added wxNativeContainerWindow to allow embedding wx into native windows - Added custom controls support to wxFileDialog (Diaa Sami and Marcin Wojdyr) - Added wxDC::StretchBlit() for wxMac and wxMSW (Vince Harron). diff --git a/include/wx/glcanvas.h b/include/wx/glcanvas.h index a7043a70d8..1d02f86652 100644 --- a/include/wx/glcanvas.h +++ b/include/wx/glcanvas.h @@ -47,7 +47,9 @@ enum WX_GL_MIN_ACCUM_RED, // use red accum buffer with most bits (> MIN_ACCUM_RED bits) WX_GL_MIN_ACCUM_GREEN, // use green buffer with most bits (> MIN_ACCUM_GREEN bits) WX_GL_MIN_ACCUM_BLUE, // use blue buffer with most bits (> MIN_ACCUM_BLUE bits) - WX_GL_MIN_ACCUM_ALPHA // use alpha buffer with most bits (> MIN_ACCUM_ALPHA bits) + WX_GL_MIN_ACCUM_ALPHA, // use alpha buffer with most bits (> MIN_ACCUM_ALPHA bits) + WX_GL_SAMPLE_BUFFERS, // 1 for multisampling support (antialiasing) + WX_GL_SAMPLES // 4 for 2x2 antialising supersampling on most graphics cards }; #define wxGLCanvasName _T("GLCanvas") @@ -121,6 +123,13 @@ public: bool SetColour(const wxString& colour); + // return true if the extension with given name is supported + // + // notice that while this function is implemented for all of GLX, WGL and + // AGL the extensions names are usually not the same for different + // platforms and so the code using it still usually uses conditional + // compilation + static bool IsExtensionSupported(const char *extension); // deprecated methods using the implicit wxGLContext #if WXWIN_COMPATIBILITY_2_8 @@ -145,6 +154,10 @@ protected: // (not supported in most ports) virtual wxPalette CreateDefaultPalette() { return wxNullPalette; } + // check if the given extension name is present in the space-separated list + // of extensions supported by the current implementation such as returned + // by glXQueryExtensionsString() or glGetString(GL_EXTENSIONS) + static bool IsExtensionInList(const char *list, const char *extension); wxPalette m_palette; diff --git a/include/wx/mac/carbon/glcanvas.h b/include/wx/mac/carbon/glcanvas.h index 10656f0ef8..cced04ff48 100644 --- a/include/wx/mac/carbon/glcanvas.h +++ b/include/wx/mac/carbon/glcanvas.h @@ -67,6 +67,9 @@ public: // Mac-specific functions // ---------------------- + // return true if multisample extension is supported + static bool IsAGLMultiSampleAvailable(); + // return the pixel format used by this window AGLPixelFormat GetAGLPixelFormat() const { return m_aglFormat; } diff --git a/include/wx/msw/glcanvas.h b/include/wx/msw/glcanvas.h index d37a569768..dba1cba083 100644 --- a/include/wx/msw/glcanvas.h +++ b/include/wx/msw/glcanvas.h @@ -141,10 +141,11 @@ protected: // HDC for this window, we keep it all the time HDC m_hDC; + void wxGLCanvas::DestroyWindowPFD(wxWindow *parent); + private: DECLARE_EVENT_TABLE() DECLARE_CLASS(wxGLCanvas) }; #endif // _WX_GLCANVAS_H_ - diff --git a/include/wx/unix/glx11.h b/include/wx/unix/glx11.h index 9f8d6353e2..b2d48eacac 100644 --- a/include/wx/unix/glx11.h +++ b/include/wx/unix/glx11.h @@ -66,6 +66,9 @@ public: // return GLX version: 13 means 1.3 &c static int GetGLXVersion(); + // return true if multisample extension is available + static bool IsGLXMultiSampleAvailable(); + // get the X11 handle of this window virtual Window GetXWindow() const = 0; diff --git a/interface/glcanvas.h b/interface/glcanvas.h index 89fcd6da94..c3694c591d 100644 --- a/interface/glcanvas.h +++ b/interface/glcanvas.h @@ -126,7 +126,13 @@ enum WX_GL_MIN_ACCUM_BLUE, /// Specifies minimal number of alpha accumulator bits. - WX_GL_MIN_ACCUM_ALPHA + WX_GL_MIN_ACCUM_ALPHA, + + /// 1 for multisampling support (antialiasing) + WX_GL_SAMPLE_BUFFERS, + + /// 4 for 2x2 antialising supersampling on most graphics cards + WX_GL_SAMPLES }; diff --git a/src/common/glcmn.cpp b/src/common/glcmn.cpp index 07db44d4c8..6b68538dc4 100644 --- a/src/common/glcmn.cpp +++ b/src/common/glcmn.cpp @@ -115,5 +115,29 @@ void wxGLCanvasBase::OnSize(wxSizeEvent& WXUNUSED(event)) #endif // WXWIN_COMPATIBILITY_2_8 +/* static */ +bool wxGLCanvasBase::IsExtensionInList(const char *list, const char *extension) +{ + for ( const char *p = list; *p; p++ ) + { + // advance up to the next possible match + p = wxStrstr(p, extension); + if ( !p ) + break; + + // check that the extension appears at the beginning/ending of the list + // or is preceded/followed by a space to avoid mistakenly finding + // "glExtension" in a list containing some "glFunkyglExtension" + if ( (p == list || p[-1] == ' ') ) + { + char c = p[strlen(extension)]; + if ( c == '\0' || c == ' ' ) + return true; + } + } + + return false; +} + #endif // wxUSE_GLCANVAS diff --git a/src/mac/carbon/glcanvas.cpp b/src/mac/carbon/glcanvas.cpp index 5fe1661ddd..7d265bc1d6 100644 --- a/src/mac/carbon/glcanvas.cpp +++ b/src/mac/carbon/glcanvas.cpp @@ -165,6 +165,34 @@ wxGLCanvas::wxGLCanvas(wxWindow *parent, #endif // WXWIN_COMPATIBILITY_2_8 +/* static */ +bool wxGLCanvasBase::IsExtensionSupported(const char *extension) +{ + // we need a valid context to query for extensions. + const GLint defaultAttribs[] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_NONE }; + AGLPixelFormat fmt = aglChoosePixelFormat(NULL, 0, defaultAttribs); + AGLContext ctx = aglCreateContext(fmt, NULL); + if ( !ctx ) + return false; + + wxString extensions = wxString::FromAscii(glGetString(GL_EXTENSIONS)); + + aglDestroyPixelFormat(fmt); + aglDestroyContext(ctx); + + return IsExtensionInList(extensions, extension); +} + +/* static */ +bool wxGLCanvas::IsAGLMultiSampleAvailable() +{ + static int s_isMultiSampleAvailable = -1; + if ( s_isMultiSampleAvailable == -1 ) + s_isMultiSampleAvailable = IsExtensionSupported("GL_ARB_multisample"); + + return s_isMultiSampleAvailable != 0; +} + static AGLPixelFormat ChoosePixelFormat(const int *attribList) { GLint data[512]; @@ -271,6 +299,36 @@ static AGLPixelFormat ChoosePixelFormat(const int *attribList) data[p++] = AGL_ACCUM_ALPHA_SIZE; data[p++] = attribList[arg++]; break; + + case WX_GL_SAMPLE_BUFFERS: + if ( !wxGLCanvas::IsAGLMultiSampleAvailable() ) + { + if ( !attribList[arg++] ) + break; + + return false; + } + + data[p++] = AGL_SAMPLE_BUFFERS_ARB; + if ( (data[p++] = attribList[arg++]) == true ) + { + // don't use software fallback + data[p++] = AGL_NO_RECOVERY; + } + break; + + case WX_GL_SAMPLES: + if ( !wxGLCanvas::IsAGLMultiSampleAvailable() ) + { + if ( !attribList[arg++] ) + break; + + return false; + } + + data[p++] = AGL_SAMPLES_ARB; + data[p++] = attribList[arg++]; + break; } } diff --git a/src/msw/glcanvas.cpp b/src/msw/glcanvas.cpp index cefcac96a9..b7035b4cd9 100644 --- a/src/msw/glcanvas.cpp +++ b/src/msw/glcanvas.cpp @@ -46,6 +46,67 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) WXUNUSED(name) #endif +// ---------------------------------------------------------------------------- +// define possibly missing WGL constants +// ---------------------------------------------------------------------------- + +#ifndef WGL_ARB_pixel_format +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_DRAW_TO_BITMAP_ARB 0x2002 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_NEED_PALETTE_ARB 0x2004 +#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 +#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_NUMBER_OVERLAYS_ARB 0x2008 +#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 +#define WGL_TRANSPARENT_ARB 0x200A +#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 +#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 +#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 +#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A +#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B +#define WGL_SHARE_DEPTH_ARB 0x200C +#define WGL_SHARE_STENCIL_ARB 0x200D +#define WGL_SHARE_ACCUM_ARB 0x200E +#define WGL_SUPPORT_GDI_ARB 0x200F +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_STEREO_ARB 0x2012 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_RED_SHIFT_ARB 0x2016 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_GREEN_SHIFT_ARB 0x2018 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_BLUE_SHIFT_ARB 0x201A +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_ALPHA_SHIFT_ARB 0x201C +#define WGL_ACCUM_BITS_ARB 0x201D +#define WGL_ACCUM_RED_BITS_ARB 0x201E +#define WGL_ACCUM_GREEN_BITS_ARB 0x201F +#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 +#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_AUX_BUFFERS_ARB 0x2024 +#define WGL_NO_ACCELERATION_ARB 0x2025 +#define WGL_GENERIC_ACCELERATION_ARB 0x2026 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_SWAP_COPY_ARB 0x2029 +#define WGL_SWAP_UNDEFINED_ARB 0x202A +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_TYPE_COLORINDEX_ARB 0x202C +#endif + +#ifndef WGL_ARB_multisample +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif + // ---------------------------------------------------------------------------- // libraries // ---------------------------------------------------------------------------- @@ -322,15 +383,213 @@ bool wxGLCanvas::SwapBuffers() return true; } + +// ---------------------------------------------------------------------------- +// multi sample support +// ---------------------------------------------------------------------------- + +// this macro defines a variable of type "name_t" called "name" and initializes +// it with the pointer to WGL function "name" (which may be NULL) +#define wxDEFINE_WGL_FUNC(name) \ + name##_t name = (name##_t)wglGetProcAddress(#name) + +/* static */ +bool wxGLCanvasBase::IsExtensionSupported(const char *extension) +{ + static const char *s_extensionsList = (char *)wxUIntPtr(-1); + if ( s_extensionsList == (char *)wxUIntPtr(-1) ) + { + typedef const char * (WINAPI *wglGetExtensionsStringARB_t)(HDC hdc); + + wxDEFINE_WGL_FUNC(wglGetExtensionsStringARB); + if ( wglGetExtensionsStringARB ) + { + s_extensionsList = wglGetExtensionsStringARB(wglGetCurrentDC()); + } + else + { + typedef const char * (WINAPI * wglGetExtensionsStringEXT_t)(); + + wxDEFINE_WGL_FUNC(wglGetExtensionsStringEXT); + if ( wglGetExtensionsStringEXT ) + { + s_extensionsList = wglGetExtensionsStringEXT(); + } + else + { + s_extensionsList = NULL; + } + } + } + + return s_extensionsList && IsExtensionInList(s_extensionsList, extension); +} + +// this is a wrapper around wglChoosePixelFormatARB(): returns the pixel format +// index matching the given attributes on success or 0 on failure +static int ChoosePixelFormatARB(HDC hdc, const int *attribList) +{ + if ( !wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample") ) + return 0; + + typedef BOOL (WINAPI * wglChoosePixelFormatARB_t) + (HDC hdc, + const int *piAttribIList, + const FLOAT *pfAttribFList, + UINT nMaxFormats, + int *piFormats, + UINT *nNumFormats + ); + + wxDEFINE_WGL_FUNC(wglChoosePixelFormatARB); + if ( !wglChoosePixelFormatARB ) + return 0; // should not occur if extension is supported + + int iAttributes[128]; + int dst = 0; // index in iAttributes array + + #define ADD_ATTR(attr, value) \ + iAttributes[dst++] = attr; iAttributes[dst++] = value + + ADD_ATTR( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); + ADD_ATTR( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); + ADD_ATTR( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); + + if ( !attribList ) + { + ADD_ATTR( WGL_COLOR_BITS_ARB, 24 ); + ADD_ATTR( WGL_ALPHA_BITS_ARB, 8 ); + ADD_ATTR( WGL_DEPTH_BITS_ARB, 16 ); + ADD_ATTR( WGL_STENCIL_BITS_ARB, 0 ); + ADD_ATTR( WGL_DOUBLE_BUFFER_ARB, GL_TRUE ); + ADD_ATTR( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); + ADD_ATTR( WGL_SAMPLES_ARB, 4 ); + } + else // have custom attributes + { + #define ADD_ATTR_VALUE(attr) ADD_ATTR(attr, attribList[src++]) + + int src = 0; + while ( attribList[src] ) + { + switch ( attribList[src++] ) + { + case WX_GL_RGBA: + ADD_ATTR( WGL_COLOR_BITS_ARB, 24 ); + ADD_ATTR( WGL_ALPHA_BITS_ARB, 8 ); + break; + + case WX_GL_BUFFER_SIZE: + ADD_ATTR_VALUE( WGL_COLOR_BITS_ARB); + break; + + case WX_GL_LEVEL: + if ( attribList[src] > 0 ) + { + ADD_ATTR( WGL_NUMBER_OVERLAYS_ARB, 1 ); + } + else if ( attribList[src] <0 ) + { + ADD_ATTR( WGL_NUMBER_UNDERLAYS_ARB, 1 ); + } + //else: ignore it + + src++; // skip the value in any case + break; + + case WX_GL_DOUBLEBUFFER: + ADD_ATTR( WGL_DOUBLE_BUFFER_ARB, GL_TRUE ); + break; + + case WX_GL_STEREO: + ADD_ATTR( WGL_STEREO_ARB, GL_TRUE ); + break; + + case WX_GL_AUX_BUFFERS: + ADD_ATTR_VALUE( WGL_AUX_BUFFERS_ARB ); + break; + + case WX_GL_MIN_RED: + ADD_ATTR_VALUE( WGL_RED_BITS_ARB ); + break; + + case WX_GL_MIN_GREEN: + ADD_ATTR_VALUE( WGL_GREEN_BITS_ARB ); + break; + + case WX_GL_MIN_BLUE: + ADD_ATTR_VALUE( WGL_BLUE_BITS_ARB ); + break; + + case WX_GL_MIN_ALPHA: + ADD_ATTR_VALUE( WGL_ALPHA_BITS_ARB ); + break; + + case WX_GL_DEPTH_SIZE: + ADD_ATTR_VALUE( WGL_DEPTH_BITS_ARB ); + break; + + case WX_GL_STENCIL_SIZE: + ADD_ATTR_VALUE( WGL_STENCIL_BITS_ARB ); + break; + + case WX_GL_MIN_ACCUM_RED: + ADD_ATTR_VALUE( WGL_ACCUM_RED_BITS_ARB ); + break; + + case WX_GL_MIN_ACCUM_GREEN: + ADD_ATTR_VALUE( WGL_ACCUM_GREEN_BITS_ARB ); + break; + + case WX_GL_MIN_ACCUM_BLUE: + ADD_ATTR_VALUE( WGL_ACCUM_BLUE_BITS_ARB ); + break; + + case WX_GL_MIN_ACCUM_ALPHA: + ADD_ATTR_VALUE( WGL_ACCUM_ALPHA_BITS_ARB ); + break; + + case WX_GL_SAMPLE_BUFFERS: + ADD_ATTR_VALUE( WGL_SAMPLE_BUFFERS_ARB ); + break; + + case WX_GL_SAMPLES: + ADD_ATTR_VALUE( WGL_SAMPLES_ARB ); + break; + } + } + + #undef ADD_ATTR_VALUE + } + + #undef ADD_ATTR + + iAttributes[dst++] = 0; + + int pf; + UINT numFormats = 0; + if ( !wglChoosePixelFormatARB(hdc, iAttributes, NULL, 1, &pf, &numFormats) ) + { + wxLogLastError(_T("wglChoosePixelFormatARB")); + return 0; + } + + return pf; +} + // ---------------------------------------------------------------------------- // pixel format stuff // ---------------------------------------------------------------------------- -static void +// returns true if pfd was adjusted accordingly to attributes provided, false +// if there is an error with attributes or -1 if the attributes indicate +// features not supported by ChoosePixelFormat() at all (currently only multi +// sampling) +static int AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int *attribList) { if ( !attribList ) - return; + return 1; // remove default attributes pfd.dwFlags &= ~PFD_DOUBLEBUFFER; @@ -411,8 +670,14 @@ AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int *attribList) case WX_GL_MIN_ACCUM_ALPHA: pfd.cAccumBits += (pfd.cAccumAlphaBits = attribList[arg++]); break; + + case WX_GL_SAMPLE_BUFFERS: + case WX_GL_SAMPLES: + return -1; } } + + return 1; } /* static */ @@ -448,9 +713,25 @@ wxGLCanvas::ChooseMatchingPixelFormat(HDC hdc, else *ppfd = pfd; - AdjustPFDForAttributes(*ppfd, attribList); + // adjust the PFD using the provided attributes and also check if we can + // use PIXELFORMATDESCRIPTOR at all: if multisampling is requested, we + // can't as it's not supported by ChoosePixelFormat() + switch ( AdjustPFDForAttributes(*ppfd, attribList) ) + { + case 1: + return ::ChoosePixelFormat(hdc, ppfd); + + default: + wxFAIL_MSG( "unexpected AdjustPFDForAttributes() return value" ); + // fall through - return ::ChoosePixelFormat(hdc, ppfd); + case 0: + // error in attributes + return 0; + + case -1: + return ::ChoosePixelFormatARB(hdc, attribList); + } } /* static */ @@ -545,13 +826,12 @@ wxPalette wxGLCanvas::CreateDefaultPalette() pPal->palNumEntries = (WORD)paletteSize; /* build a simple RGB color palette */ - { int redMask = (1 << pfd.cRedBits) - 1; int greenMask = (1 << pfd.cGreenBits) - 1; int blueMask = (1 << pfd.cBlueBits) - 1; - int i; - for (i=0; ipalPalEntry[i].peRed = (BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask); pPal->palPalEntry[i].peGreen = @@ -560,7 +840,6 @@ wxPalette wxGLCanvas::CreateDefaultPalette() (BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask); pPal->palPalEntry[i].peFlags = 0; } - } HPALETTE hPalette = CreatePalette(pPal); free(pPal); diff --git a/src/unix/glx11.cpp b/src/unix/glx11.cpp index ed777163d9..9e1c4464c0 100644 --- a/src/unix/glx11.cpp +++ b/src/unix/glx11.cpp @@ -122,6 +122,26 @@ wxGLCanvasX11::~wxGLCanvasX11() // working with GL attributes // ---------------------------------------------------------------------------- +/* static */ +bool wxGLCanvasBase::IsExtensionSupported(const char *extension) +{ + Display * const dpy = wxGetX11Display(); + + return IsExtensionInList(glXQueryExtensionsString(dpy, DefaultScreen(dpy)), + extension); +} + + +/* static */ +bool wxGLCanvasX11::IsGLXMultiSampleAvailable() +{ + static int s_isMultiSampleAvailable = -1; + if ( s_isMultiSampleAvailable == -1 ) + s_isMultiSampleAvailable = IsExtensionSupported("GLX_ARB_multisample"); + + return s_isMultiSampleAvailable != 0; +} + bool wxGLCanvasX11::ConvertWXAttrsToGL(const int *wxattrs, int *glattrs, size_t n) { @@ -257,6 +277,32 @@ wxGLCanvasX11::ConvertWXAttrsToGL(const int *wxattrs, int *glattrs, size_t n) glattrs[p++] = GLX_ACCUM_ALPHA_SIZE; break; + case WX_GL_SAMPLE_BUFFERS: + if ( !IsGLXMultiSampleAvailable() ) + { + // if it was specified just to disable it, no problem + if ( !wxattrs[arg++] ) + continue; + + // otherwise indicate that it's not supported + return false; + } + + glattrs[p++] = GLX_SAMPLE_BUFFERS_ARB; + break; + + case WX_GL_SAMPLES: + if ( !IsGLXMultiSampleAvailable() ) + { + if ( !wxattrs[arg++] ) + continue; + + return false; + } + + glattrs[p++] = GLX_SAMPLES_ARB; + break; + default: wxLogDebug(_T("Unsupported OpenGL attribute %d"), wxattrs[arg - 1]); -- 2.45.2