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
This commit is contained in:
Vadim Zeitlin
2008-06-08 00:12:12 +00:00
parent abbcf16d06
commit c39d2e0a38
10 changed files with 445 additions and 11 deletions

View File

@@ -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).

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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_

View File

@@ -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;

View File

@@ -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
};

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);
return ::ChoosePixelFormat(hdc, ppfd);
default:
wxFAIL_MSG( "unexpected AdjustPFDForAttributes() return value" );
// fall through
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; i<paletteSize; ++i) {
for (int i=0; i<paletteSize; ++i)
{
pPal->palPalEntry[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);

View File

@@ -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]);