Combined patch with the following changes: - Don't add wxGLAttributes::Defaults() when the attributes-list is NULL. - Add display default attributes used in wx versions before 3.1 when the attributes-list is NULL. These attributes are different for each platform. - Fix wxMSW PixelFormatDescriptor initialization. - Don't set color buffers when RGBA() is used. - Fix setting colour sizes in OS X and a few other fixes. - Make documentation more clear about these subjects. Closes #17425.
1389 lines
42 KiB
C++
1389 lines
42 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/msw/glcanvas.cpp
|
|
// Purpose: wxGLCanvas, for using OpenGL with wxWidgets under MS Windows
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 04/01/98
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
#if defined(__BORLANDC__)
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_GLCANVAS
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/intl.h"
|
|
#include "wx/log.h"
|
|
#include "wx/app.h"
|
|
#endif
|
|
|
|
#include "wx/msw/private.h"
|
|
|
|
#include "wx/glcanvas.h"
|
|
|
|
// from src/msw/window.cpp
|
|
LRESULT WXDLLEXPORT APIENTRY
|
|
wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
#ifdef GL_EXT_vertex_array
|
|
#define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) name
|
|
#else
|
|
#define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) WXUNUSED(name)
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// define possibly missing WGL constants and types
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifndef WGL_ARB_pixel_format
|
|
#define WGL_ARB_pixel_format
|
|
#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_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_GREEN_BITS_ARB 0x2017
|
|
#define WGL_BLUE_BITS_ARB 0x2019
|
|
#define WGL_ALPHA_BITS_ARB 0x201B
|
|
#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_TYPE_RGBA_ARB 0x202B
|
|
#define WGL_TYPE_COLORINDEX_ARB 0x202C
|
|
#endif
|
|
|
|
#ifndef WGL_ARB_multisample
|
|
#define WGL_ARB_multisample
|
|
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
|
|
#define WGL_SAMPLES_ARB 0x2042
|
|
#endif
|
|
|
|
#ifndef WGL_ARB_framebuffer_sRGB
|
|
#define WGL_ARB_framebuffer_sRGB
|
|
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
|
|
#endif
|
|
|
|
#ifndef WGL_ARB_create_context
|
|
#define WGL_ARB_create_context
|
|
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
|
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
|
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
|
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
|
|
#endif
|
|
|
|
#ifndef WGL_ARB_create_context_profile
|
|
#define WGL_ARB_create_context_profile
|
|
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
|
#endif
|
|
|
|
#ifndef WGL_ARB_create_context_robustness
|
|
#define WGL_ARB_create_context_robustness
|
|
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
|
|
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
|
|
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
|
|
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
|
|
#endif
|
|
|
|
#ifndef WGL_ARB_robustness_application_isolation
|
|
#define WGL_ARB_robustness_application_isolation
|
|
#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008
|
|
#endif
|
|
#ifndef WGL_ARB_robustness_share_group_isolation
|
|
#define WGL_ARB_robustness_share_group_isolation
|
|
#endif
|
|
|
|
#ifndef WGL_ARB_context_flush_control
|
|
#define WGL_ARB_context_flush_control
|
|
#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
|
|
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
|
|
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
|
|
#endif
|
|
|
|
#ifndef WGL_EXT_create_context_es2_profile
|
|
#define WGL_EXT_create_context_es2_profile
|
|
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
|
|
#endif
|
|
|
|
#ifndef WGL_EXT_create_context_es_profile
|
|
#define WGL_EXT_create_context_es_profile
|
|
#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
|
|
#endif
|
|
|
|
typedef HGLRC(WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)
|
|
(HDC hDC, HGLRC hShareContext, const int *attribList);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// libraries
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*
|
|
The following two compiler directives are specific to the Microsoft Visual
|
|
C++ family of compilers
|
|
|
|
Fundementally what they do is instruct the linker to use these two libraries
|
|
for the resolution of symbols. In essence, this is the equivalent of adding
|
|
these two libraries to either the Makefile or project file.
|
|
|
|
This is NOT a recommended technique, and certainly is unlikely to be used
|
|
anywhere else in wxWidgets given it is so specific to not only wxMSW, but
|
|
also the VC compiler. However, in the case of opengl support, it's an
|
|
applicable technique as opengl is optional in setup.h This code (wrapped by
|
|
wxUSE_GLCANVAS), now allows opengl support to be added purely by modifying
|
|
setup.h rather than by having to modify either the project or DSP fle.
|
|
|
|
See MSDN for further information on the exact usage of these commands.
|
|
*/
|
|
#ifdef _MSC_VER
|
|
# pragma comment( lib, "opengl32" )
|
|
# pragma comment( lib, "glu32" )
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Documentation on internals
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// OpenGL has evolved not only adding new features, but also there are new
|
|
// ways of doing things. Among these new ways, we pay special attention to
|
|
// pixel format choosing and context creation.
|
|
//
|
|
// The old way of choosing a pixel format is to use a PIXELFORMATDESCRIPTOR
|
|
// struct for setting the wanted attributes and to call ChoosePixelFormat()
|
|
// with that struct.
|
|
// When new attributes came into scene, the MSW struct became inadequate, and
|
|
// a new method was implemented: wglChoosePixelFormatARB().
|
|
//
|
|
// For rendering context creation wglCreateContext() was the function to call.
|
|
// Starting with OpenGL 3.0 (2009) there are several attributes for context,
|
|
// specially for wanted version and "core" or "compatibility" profiles.
|
|
// In order to use these new features, wglCreateContextAttribsARB() must be
|
|
// called instead of wglCreateContext().
|
|
//
|
|
// wxWidgets handles this OpenGL evolution trying to use the new ways, and
|
|
// falling back to the old ways if neither the latter are available nor the
|
|
// user requires them.
|
|
//
|
|
// wxGLAttributes is used for pixel format attributes.
|
|
// wxGLContextAttrs is used for OpenGL rendering context attributes.
|
|
// wxWidgets does not handle all of OpenGL attributes. This is because some of
|
|
// them are platform-dependent, or perhaps too new for wx. To cope with these
|
|
// cases, these two objects allow the user to set his own attributes.
|
|
//
|
|
// To keep wxWidgets backwards compatibility, a list of mixed attributes is
|
|
// still allowed at wxGLCanvas constructor.
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxGLContextAttrs: OpenGL rendering context attributes
|
|
// ----------------------------------------------------------------------------
|
|
// MSW specific values
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::CoreProfile()
|
|
{
|
|
AddAttribBits(WGL_CONTEXT_PROFILE_MASK_ARB,
|
|
WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::MajorVersion(int val)
|
|
{
|
|
if ( val > 0 )
|
|
{
|
|
AddAttribute(WGL_CONTEXT_MAJOR_VERSION_ARB);
|
|
AddAttribute(val);
|
|
if ( val >= 3 )
|
|
SetNeedsARB();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::MinorVersion(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_CONTEXT_MINOR_VERSION_ARB);
|
|
AddAttribute(val);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::CompatibilityProfile()
|
|
{
|
|
AddAttribBits(WGL_CONTEXT_PROFILE_MASK_ARB,
|
|
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::ForwardCompatible()
|
|
{
|
|
AddAttribBits(WGL_CONTEXT_FLAGS_ARB,
|
|
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::ES2()
|
|
{
|
|
AddAttribBits(WGL_CONTEXT_PROFILE_MASK_ARB,
|
|
WGL_CONTEXT_ES2_PROFILE_BIT_EXT);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::DebugCtx()
|
|
{
|
|
AddAttribBits(WGL_CONTEXT_FLAGS_ARB,
|
|
WGL_CONTEXT_DEBUG_BIT_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::Robust()
|
|
{
|
|
AddAttribBits(WGL_CONTEXT_FLAGS_ARB,
|
|
WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::NoResetNotify()
|
|
{
|
|
AddAttribute(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
|
|
AddAttribute(WGL_NO_RESET_NOTIFICATION_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::LoseOnReset()
|
|
{
|
|
AddAttribute(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
|
|
AddAttribute(WGL_LOSE_CONTEXT_ON_RESET_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::ResetIsolation()
|
|
{
|
|
AddAttribBits(WGL_CONTEXT_FLAGS_ARB,
|
|
WGL_CONTEXT_RESET_ISOLATION_BIT_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::ReleaseFlush(int val)
|
|
{
|
|
AddAttribute(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB);
|
|
if ( val == 1 )
|
|
AddAttribute(WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
|
|
else
|
|
AddAttribute(WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
wxGLContextAttrs& wxGLContextAttrs::PlatformDefaults()
|
|
{
|
|
// No MSW specific defaults
|
|
return *this;
|
|
}
|
|
|
|
void wxGLContextAttrs::EndList()
|
|
{
|
|
AddAttribute(0);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxGLAttributes: pixel format attributes
|
|
// ----------------------------------------------------------------------------
|
|
// MSW specific values
|
|
|
|
wxGLAttributes& wxGLAttributes::RGBA()
|
|
{
|
|
AddAttribute(WGL_PIXEL_TYPE_ARB);
|
|
AddAttribute(WGL_TYPE_RGBA_ARB);
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::BufferSize(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_COLOR_BITS_ARB);
|
|
AddAttribute(val);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::Level(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_NUMBER_OVERLAYS_ARB);
|
|
AddAttribute(val);
|
|
}
|
|
else if ( val < 0 )
|
|
{
|
|
AddAttribute(WGL_NUMBER_UNDERLAYS_ARB);
|
|
AddAttribute(-val);
|
|
}
|
|
if ( val < -1 || val > 1 )
|
|
{
|
|
SetNeedsARB();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::DoubleBuffer()
|
|
{
|
|
AddAttribute(WGL_DOUBLE_BUFFER_ARB);
|
|
AddAttribute(GL_TRUE);
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::Stereo()
|
|
{
|
|
AddAttribute(WGL_STEREO_ARB);
|
|
AddAttribute(GL_TRUE);
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::AuxBuffers(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_AUX_BUFFERS_ARB);
|
|
AddAttribute(val);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::MinRGBA(int mRed, int mGreen, int mBlue, int mAlpha)
|
|
{
|
|
int colorBits = 0;
|
|
if ( mRed >= 0)
|
|
{
|
|
AddAttribute(WGL_RED_BITS_ARB);
|
|
AddAttribute(mRed);
|
|
colorBits += mRed;
|
|
}
|
|
if ( mGreen >= 0)
|
|
{
|
|
AddAttribute(WGL_GREEN_BITS_ARB);
|
|
AddAttribute(mGreen);
|
|
colorBits += mGreen;
|
|
}
|
|
if ( mBlue >= 0)
|
|
{
|
|
AddAttribute(WGL_BLUE_BITS_ARB);
|
|
AddAttribute(mBlue);
|
|
colorBits += mBlue;
|
|
}
|
|
if ( mAlpha >= 0)
|
|
{
|
|
AddAttribute(WGL_ALPHA_BITS_ARB);
|
|
AddAttribute(mAlpha);
|
|
// doesn't count in colorBits
|
|
}
|
|
if ( colorBits )
|
|
{
|
|
AddAttribute(WGL_COLOR_BITS_ARB);
|
|
AddAttribute(colorBits);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::Depth(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_DEPTH_BITS_ARB);
|
|
AddAttribute(val);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::Stencil(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_STENCIL_BITS_ARB);
|
|
AddAttribute(val);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::MinAcumRGBA(int mRed, int mGreen, int mBlue, int mAlpha)
|
|
{
|
|
int acumBits = 0;
|
|
if ( mRed >= 0)
|
|
{
|
|
AddAttribute(WGL_ACCUM_RED_BITS_ARB);
|
|
AddAttribute(mRed);
|
|
acumBits += mRed;
|
|
}
|
|
if ( mGreen >= 0)
|
|
{
|
|
AddAttribute(WGL_ACCUM_GREEN_BITS_ARB);
|
|
AddAttribute(mGreen);
|
|
acumBits += mGreen;
|
|
}
|
|
if ( mBlue >= 0)
|
|
{
|
|
AddAttribute(WGL_ACCUM_BLUE_BITS_ARB);
|
|
AddAttribute(mBlue);
|
|
acumBits += mBlue;
|
|
}
|
|
if ( mAlpha >= 0)
|
|
{
|
|
AddAttribute(WGL_ACCUM_ALPHA_BITS_ARB);
|
|
AddAttribute(mAlpha);
|
|
acumBits += mAlpha;
|
|
}
|
|
if ( acumBits )
|
|
{
|
|
AddAttribute(WGL_ACCUM_BITS_ARB);
|
|
AddAttribute(acumBits);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::SampleBuffers(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_SAMPLE_BUFFERS_ARB);
|
|
AddAttribute(val);
|
|
SetNeedsARB();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::Samplers(int val)
|
|
{
|
|
if ( val >= 0 )
|
|
{
|
|
AddAttribute(WGL_SAMPLES_ARB);
|
|
AddAttribute(val);
|
|
SetNeedsARB();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::FrameBuffersRGB()
|
|
{
|
|
AddAttribute(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
|
|
AddAttribute(GL_TRUE);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
void wxGLAttributes::EndList()
|
|
{
|
|
AddAttribute(0);
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::PlatformDefaults()
|
|
{
|
|
AddAttribute(WGL_DRAW_TO_WINDOW_ARB);
|
|
AddAttribute(GL_TRUE);
|
|
AddAttribute(WGL_SUPPORT_OPENGL_ARB);
|
|
AddAttribute(GL_TRUE);
|
|
AddAttribute(WGL_ACCELERATION_ARB);
|
|
AddAttribute(WGL_FULL_ACCELERATION_ARB);
|
|
return *this;
|
|
}
|
|
|
|
wxGLAttributes& wxGLAttributes::Defaults()
|
|
{
|
|
RGBA().Depth(16).DoubleBuffer().SampleBuffers(1).Samplers(4);
|
|
SetNeedsARB();
|
|
return *this;
|
|
}
|
|
|
|
void wxGLAttributes::AddDefaultsForWXBefore31()
|
|
{
|
|
// ParseAttribList() will add EndList(), don't do it now
|
|
RGBA().DoubleBuffer().Depth(16);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxGLContext
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxIMPLEMENT_CLASS(wxGLContext, wxObject);
|
|
|
|
wxGLContext::wxGLContext(wxGLCanvas *win,
|
|
const wxGLContext *other,
|
|
const wxGLContextAttrs *ctxAttrs)
|
|
: m_glContext(NULL)
|
|
{
|
|
const int* contextAttribs = NULL;
|
|
bool needsARB = false;
|
|
|
|
if ( ctxAttrs )
|
|
{
|
|
contextAttribs = ctxAttrs->GetGLAttrs();
|
|
needsARB = ctxAttrs->NeedsARB();
|
|
}
|
|
else if ( win->GetGLCTXAttrs().GetGLAttrs() )
|
|
{
|
|
// If OpenGL context parameters were set at wxGLCanvas ctor, get them now
|
|
contextAttribs = win->GetGLCTXAttrs().GetGLAttrs();
|
|
needsARB = win->GetGLCTXAttrs().NeedsARB();
|
|
}
|
|
// else use GPU driver defaults
|
|
|
|
m_isOk = false;
|
|
|
|
// We need to create a temporary context to get the pointer to
|
|
// wglCreateContextAttribsARB function
|
|
HGLRC tempContext = wglCreateContext(win->GetHDC());
|
|
wxCHECK_RET( tempContext, "wglCreateContext failed!" );
|
|
|
|
wglMakeCurrent(win->GetHDC(), tempContext);
|
|
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB
|
|
= (PFNWGLCREATECONTEXTATTRIBSARBPROC)
|
|
wglGetProcAddress("wglCreateContextAttribsARB");
|
|
wglMakeCurrent(win->GetHDC(), NULL);
|
|
wglDeleteContext(tempContext);
|
|
|
|
// The preferred way is using wglCreateContextAttribsARB, even for old context
|
|
if ( !wglCreateContextAttribsARB && needsARB ) // OpenGL 3 context creation
|
|
{
|
|
wxLogMessage(_("OpenGL 3.0 or later is not supported by the OpenGL driver."));
|
|
return;
|
|
}
|
|
|
|
if ( wglCreateContextAttribsARB )
|
|
{
|
|
m_glContext = wglCreateContextAttribsARB(win->GetHDC(),
|
|
other ? other->m_glContext : 0,
|
|
contextAttribs);
|
|
}
|
|
|
|
|
|
// Some old hardware may accept the use of this ARB, but may fail.
|
|
// In case of NULL attributes we'll try creating the context old-way.
|
|
if ( !m_glContext && (!contextAttribs || !needsARB) )
|
|
{
|
|
// Create legacy context
|
|
m_glContext = wglCreateContext(win->GetHDC());
|
|
// Set shared context
|
|
if ( other && !wglShareLists(other->m_glContext, m_glContext) )
|
|
wxLogLastError("wglShareLists");
|
|
}
|
|
|
|
if ( !m_glContext )
|
|
wxLogMessage(_("Couldn't create OpenGL context"));
|
|
else
|
|
m_isOk = true;
|
|
}
|
|
|
|
wxGLContext::~wxGLContext()
|
|
{
|
|
// note that it's ok to delete the context even if it's the current one
|
|
if ( m_glContext )
|
|
{
|
|
wglDeleteContext(m_glContext);
|
|
}
|
|
}
|
|
|
|
bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
|
|
{
|
|
if ( !wglMakeCurrent(win.GetHDC(), m_glContext) )
|
|
{
|
|
wxLogLastError(wxT("wglMakeCurrent"));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// wxGLCanvas
|
|
// ============================================================================
|
|
|
|
wxIMPLEMENT_CLASS(wxGLCanvas, wxWindow);
|
|
|
|
wxBEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
|
|
#if wxUSE_PALETTE
|
|
EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
|
|
EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
|
|
#endif
|
|
wxEND_EVENT_TABLE()
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxGLCanvas construction
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxGLCanvas::Init()
|
|
{
|
|
#if WXWIN_COMPATIBILITY_2_8
|
|
m_glContext = NULL;
|
|
#endif
|
|
m_hDC = NULL;
|
|
}
|
|
|
|
wxGLCanvas::wxGLCanvas(wxWindow *parent,
|
|
const wxGLAttributes& dispAttrs,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name,
|
|
const wxPalette& palette)
|
|
{
|
|
Init();
|
|
|
|
(void)Create(parent, dispAttrs, id, pos, size, style, name, palette);
|
|
}
|
|
|
|
wxGLCanvas::wxGLCanvas(wxWindow *parent,
|
|
wxWindowID id,
|
|
const int *attribList,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name,
|
|
const wxPalette& palette)
|
|
{
|
|
Init();
|
|
|
|
(void)Create(parent, id, pos, size, style, name, attribList, palette);
|
|
}
|
|
|
|
wxGLCanvas::~wxGLCanvas()
|
|
{
|
|
::ReleaseDC(GetHwnd(), m_hDC);
|
|
}
|
|
|
|
// Replaces wxWindow::Create functionality, since we need to use a different
|
|
// window class
|
|
bool wxGLCanvas::CreateWindow(wxWindow *parent,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name)
|
|
{
|
|
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
|
|
|
|
if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
|
|
return false;
|
|
|
|
parent->AddChild(this);
|
|
|
|
/*
|
|
A general rule with OpenGL and Win32 is that any window that will have a
|
|
HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
|
|
You can find references about this within the knowledge base and most OpenGL
|
|
books that contain the wgl function descriptions.
|
|
*/
|
|
WXDWORD exStyle = 0;
|
|
DWORD msflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
msflags |= MSWGetStyle(style, &exStyle);
|
|
|
|
if ( !MSWCreate(wxApp::GetRegisteredClassName(wxT("wxGLCanvas"), -1, CS_OWNDC),
|
|
NULL, pos, size, msflags, exStyle) )
|
|
return false;
|
|
|
|
m_hDC = ::GetDC(GetHwnd());
|
|
if ( !m_hDC )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxGLCanvas::Create(wxWindow *parent,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name,
|
|
const int *attribList,
|
|
const wxPalette& palette)
|
|
{
|
|
// Separate 'pixel format' attributes and add platform-defaults.
|
|
// Also store context attributes for wxGLContext ctor
|
|
wxGLAttributes dispAttrs;
|
|
if ( ! ParseAttribList(attribList, dispAttrs, &m_GLCTXAttrs) )
|
|
return false;
|
|
|
|
return Create(parent, dispAttrs, id, pos, size, style, name, palette);
|
|
}
|
|
|
|
bool wxGLCanvas::Create(wxWindow *parent,
|
|
const wxGLAttributes& dispAttrs,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name,
|
|
const wxPalette& palette)
|
|
{
|
|
if ( !CreateWindow(parent, id, pos, size, style, name) )
|
|
return false;
|
|
|
|
// Choose a matching pixel format.
|
|
// Need a PIXELFORMATDESCRIPTOR for SetPixelFormat()
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
int pixelFormat = FindMatchingPixelFormat(dispAttrs, &pfd);
|
|
if ( !pixelFormat )
|
|
{
|
|
wxFAIL_MSG("Can't find a pixel format for the requested attributes");
|
|
return false;
|
|
}
|
|
|
|
// From SetPixelFormat() docs, relating pfd parameter:
|
|
// https://msdn.microsoft.com/en-us/library/dd369049%28v=vs.85%29.aspx
|
|
// "The system's metafile component uses this structure to record the
|
|
// logical pixel format specification."
|
|
// If anybody understands this sentence, please explain.
|
|
// Pass pfd just in case it's somehow needed. Passing NULL also works here.
|
|
if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) )
|
|
{
|
|
wxLogLastError("SetPixelFormat");
|
|
return false;
|
|
}
|
|
|
|
#if wxUSE_PALETTE
|
|
if ( !SetupPalette(palette) )
|
|
return false;
|
|
#else // !wxUSE_PALETTE
|
|
wxUnusedVar(palette);
|
|
#endif // wxUSE_PALETTE/!wxUSE_PALETTE
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// operations
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxGLCanvas::SwapBuffers()
|
|
{
|
|
if ( !::SwapBuffers(m_hDC) )
|
|
{
|
|
wxLogLastError(wxT("SwapBuffers"));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// 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);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// pixel format stuff
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// A dummy window, needed at FindMatchingPixelFormat()
|
|
class WXDLLIMPEXP_GL wxGLdummyWin : public wxWindow
|
|
{
|
|
public:
|
|
wxGLdummyWin()
|
|
{
|
|
hdc = 0;
|
|
CreateBase(NULL, wxID_ANY);
|
|
DWORD msflags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
|
if( MSWCreate(wxApp::GetRegisteredClassName(wxT("wxGLCanvas"), -1, CS_OWNDC),
|
|
NULL, wxDefaultPosition, wxDefaultSize, msflags, 0) )
|
|
{
|
|
hdc = ::GetDC(GetHwnd());
|
|
}
|
|
}
|
|
~wxGLdummyWin()
|
|
{
|
|
if ( hdc )
|
|
::ReleaseDC(GetHwnd(), hdc);
|
|
}
|
|
HDC hdc;
|
|
};
|
|
|
|
// Fills PIXELFORMATDESCRIPTOR struct
|
|
static void SetPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int* attrsListWGL)
|
|
{
|
|
// Some defaults
|
|
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
|
pfd.nVersion = 1;
|
|
pfd.iPixelType = PFD_TYPE_COLORINDEX; // If no RGBA is specified
|
|
pfd.iLayerType = PFD_MAIN_PLANE; // For very early MSW OpenGL
|
|
// Initialize rest of fields
|
|
pfd.dwFlags = 0;
|
|
pfd.cColorBits = 0;
|
|
pfd.cRedBits = pfd.cRedShift = pfd.cGreenBits = pfd.cGreenShift = pfd.cBlueBits = pfd.cBlueShift = 0;
|
|
pfd.cAlphaBits = pfd.cAlphaShift = 0;
|
|
pfd.cAccumBits = 0;
|
|
pfd.cAccumRedBits = pfd.cAccumGreenBits = pfd.cAccumBlueBits = pfd.cAccumAlphaBits = 0;
|
|
pfd.cDepthBits = pfd.cStencilBits = pfd.cAuxBuffers = 0;
|
|
pfd.bReserved = 0;
|
|
pfd.dwLayerMask = pfd.dwVisibleMask = pfd.dwDamageMask = 0;
|
|
|
|
// We can meet some WGL_XX values not managed by wx. But the user
|
|
// may require them. Allow here those that are also used for pfd.
|
|
// Notice that the user can't require PFD values, only WGL ones.
|
|
// Color shift and transparency are not handled.
|
|
for ( int arg = 0; attrsListWGL[arg]; )
|
|
{
|
|
switch ( attrsListWGL[arg++] )
|
|
{
|
|
case WGL_DRAW_TO_WINDOW_ARB:
|
|
if ( attrsListWGL[arg++] ) //arg++ is for skipping 'true' attribute
|
|
pfd.dwFlags |= PFD_DRAW_TO_WINDOW;
|
|
break;
|
|
|
|
case WGL_DRAW_TO_BITMAP_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_DRAW_TO_BITMAP;
|
|
break;
|
|
|
|
case WGL_ACCELERATION_ARB:
|
|
if ( attrsListWGL[arg++] == WGL_GENERIC_ACCELERATION_ARB )
|
|
pfd.dwFlags |= PFD_GENERIC_ACCELERATED;
|
|
break;
|
|
|
|
case WGL_NEED_PALETTE_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_NEED_PALETTE;
|
|
break;
|
|
|
|
case WGL_NEED_SYSTEM_PALETTE_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_NEED_SYSTEM_PALETTE;
|
|
break;
|
|
|
|
case WGL_SWAP_LAYER_BUFFERS_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_SWAP_LAYER_BUFFERS;
|
|
break;
|
|
|
|
case WGL_SWAP_METHOD_ARB:
|
|
if ( attrsListWGL[arg++] == WGL_SWAP_EXCHANGE_ARB )
|
|
pfd.dwFlags |= PFD_SWAP_EXCHANGE;
|
|
else if ( attrsListWGL[arg] == WGL_SWAP_COPY_ARB )
|
|
pfd.dwFlags |= PFD_SWAP_COPY;
|
|
break;
|
|
|
|
case WGL_NUMBER_OVERLAYS_ARB:
|
|
// Bits 0-3
|
|
pfd.bReserved |= attrsListWGL[arg++] & 15;
|
|
break;
|
|
|
|
case WGL_NUMBER_UNDERLAYS_ARB:
|
|
// Bits 4-7
|
|
pfd.bReserved |= attrsListWGL[arg++] & 240;
|
|
break;
|
|
|
|
case WGL_SUPPORT_GDI_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_SUPPORT_GDI;
|
|
break;
|
|
|
|
case WGL_SUPPORT_OPENGL_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_SUPPORT_OPENGL;
|
|
break;
|
|
|
|
case WGL_DOUBLE_BUFFER_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_DOUBLEBUFFER;
|
|
break;
|
|
|
|
case WGL_STEREO_ARB:
|
|
if ( attrsListWGL[arg++] )
|
|
pfd.dwFlags |= PFD_STEREO;
|
|
break;
|
|
|
|
case WGL_PIXEL_TYPE_ARB:
|
|
if ( attrsListWGL[arg++] == WGL_TYPE_RGBA_ARB )
|
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
|
else
|
|
pfd.iPixelType = PFD_TYPE_COLORINDEX;
|
|
break;
|
|
|
|
case WGL_COLOR_BITS_ARB:
|
|
pfd.cColorBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_RED_BITS_ARB:
|
|
pfd.cRedBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_GREEN_BITS_ARB:
|
|
pfd.cGreenBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_BLUE_BITS_ARB:
|
|
pfd.cBlueBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_ALPHA_BITS_ARB:
|
|
pfd.cAlphaBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_ACCUM_BITS_ARB:
|
|
pfd.cAccumBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_ACCUM_RED_BITS_ARB:
|
|
pfd.cAccumRedBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_ACCUM_GREEN_BITS_ARB:
|
|
pfd.cAccumGreenBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_ACCUM_BLUE_BITS_ARB:
|
|
pfd.cAccumBlueBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_ACCUM_ALPHA_BITS_ARB:
|
|
pfd.cAccumAlphaBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_DEPTH_BITS_ARB:
|
|
pfd.cDepthBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_STENCIL_BITS_ARB:
|
|
pfd.cStencilBits = attrsListWGL[arg++];
|
|
break;
|
|
|
|
case WGL_AUX_BUFFERS_ARB:
|
|
pfd.cAuxBuffers = attrsListWGL[arg++];
|
|
break;
|
|
|
|
default:
|
|
// ignore
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
int wxGLCanvas::FindMatchingPixelFormat(const wxGLAttributes& dispAttrs,
|
|
PIXELFORMATDESCRIPTOR* ppfd)
|
|
{
|
|
// WGL_XX attributes
|
|
const int* attrsListWGL = dispAttrs.GetGLAttrs();
|
|
if ( !attrsListWGL )
|
|
{
|
|
wxFAIL_MSG("wxGLAttributes object is empty.");
|
|
return 0;
|
|
}
|
|
|
|
// The preferred way is using wglChoosePixelFormatARB. This is not a MSW
|
|
// function, we must ask the GPU driver for a pointer to it. We need a
|
|
// rendering context for this operation. Create a dummy one.
|
|
// Notice that we don't create a wxGLContext on purpose.
|
|
// We meet another issue:
|
|
// Before creating any context, we must set a pixel format for its hdc:
|
|
// https://msdn.microsoft.com/en-us/library/dd374379%28v=vs.85%29.aspx
|
|
// but we can't set a pixel format more than once:
|
|
// https://msdn.microsoft.com/en-us/library/dd369049%28v=vs.85%29.aspx
|
|
// To cope with this we need a dummy hidden window.
|
|
//
|
|
// Having this dummy window allows also calling IsDisplaySupported()
|
|
// without creating a wxGLCanvas.
|
|
wxGLdummyWin* dummyWin = new wxGLdummyWin();
|
|
HDC dummyHDC = dummyWin->hdc;
|
|
if ( !dummyHDC )
|
|
{
|
|
dummyWin->Destroy();
|
|
wxFAIL_MSG("Can't create dummy window");
|
|
return 0;
|
|
}
|
|
// Dummy context
|
|
PIXELFORMATDESCRIPTOR dpfd; //any one is valid
|
|
::SetPixelFormat(dummyHDC, 1, &dpfd); // pixelformat=1, any one is valid
|
|
HGLRC dumctx = ::wglCreateContext(dummyHDC);
|
|
if ( !dumctx )
|
|
{
|
|
dummyWin->Destroy();
|
|
// A fatal error!
|
|
wxFAIL_MSG("wglCreateContext failed!");
|
|
return 0;
|
|
}
|
|
|
|
::wglMakeCurrent(dummyHDC, dumctx);
|
|
|
|
typedef BOOL (WINAPI * wglChoosePixelFormatARB_t)
|
|
(HDC hdc,
|
|
const int *piAttribIList,
|
|
const FLOAT *pfAttribFList,
|
|
UINT nMaxFormats,
|
|
int *piFormats,
|
|
UINT *nNumFormats
|
|
);
|
|
|
|
wxDEFINE_WGL_FUNC(wglChoosePixelFormatARB); // get a pointer to it
|
|
|
|
// If wglChoosePixelFormatARB is not supported but the attributes require
|
|
// it, then fail.
|
|
if ( !wglChoosePixelFormatARB && dispAttrs.NeedsARB() )
|
|
{
|
|
wxLogLastError("wglChoosePixelFormatARB unavailable");
|
|
// Delete the dummy objects
|
|
::wglMakeCurrent(NULL, NULL);
|
|
::wglDeleteContext(dumctx);
|
|
dummyWin->Destroy();
|
|
return 0;
|
|
}
|
|
|
|
int pixelFormat = 0;
|
|
|
|
if ( !wglChoosePixelFormatARB && !dispAttrs.NeedsARB() )
|
|
{
|
|
// Old way
|
|
if ( !ppfd )
|
|
{
|
|
// We have been called from IsDisplaySupported()
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
SetPFDForAttributes(pfd, attrsListWGL);
|
|
pixelFormat = ::ChoosePixelFormat(dummyHDC, &pfd);
|
|
}
|
|
else
|
|
{
|
|
SetPFDForAttributes(*ppfd, attrsListWGL);
|
|
pixelFormat = ::ChoosePixelFormat(dummyHDC, ppfd);
|
|
}
|
|
// We should ensure that we have got what we have asked for. This can
|
|
// be done using DescribePixelFormat() and comparing attributes.
|
|
// Nevertheless wglChoosePixelFormatARB exists since 2001, so it's
|
|
// very unlikely that ChoosePixelFormat() is used. So, do nothing.
|
|
}
|
|
else
|
|
{
|
|
// New way, using wglChoosePixelFormatARB
|
|
// 'ppfd' is used at wxGLCanvas::Create(). See explanations there.
|
|
if ( ppfd )
|
|
SetPFDForAttributes(*ppfd, attrsListWGL);
|
|
|
|
UINT numFormats = 0;
|
|
|
|
// Get the first good match
|
|
if ( !wglChoosePixelFormatARB(dummyHDC, attrsListWGL, NULL,
|
|
1, &pixelFormat, &numFormats) )
|
|
{
|
|
wxLogLastError("wglChoosePixelFormatARB. Is the list zero-terminated?");
|
|
numFormats = 0;
|
|
}
|
|
|
|
// Although TRUE is returned if no matching formats are found (see
|
|
// https://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt),
|
|
// pixelFormat is not initialized in this case so we need to check
|
|
// for numFormats being not 0 explicitly (however this is not an error
|
|
// so don't call wxLogLastError() here).
|
|
if ( !numFormats )
|
|
pixelFormat = 0;
|
|
}
|
|
|
|
// Delete the dummy objects
|
|
::wglMakeCurrent(NULL, NULL);
|
|
::wglDeleteContext(dumctx);
|
|
dummyWin->Destroy();
|
|
|
|
return pixelFormat;
|
|
}
|
|
|
|
/* static */
|
|
int
|
|
wxGLCanvas::ChooseMatchingPixelFormat(HDC hdc,
|
|
const int *attribList,
|
|
PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
wxGLAttributes dispAttrs;
|
|
ParseAttribList(attribList, dispAttrs);
|
|
wxUnusedVar(hdc);
|
|
return FindMatchingPixelFormat(dispAttrs, ppfd);
|
|
}
|
|
|
|
/* static */
|
|
bool wxGLCanvasBase::IsDisplaySupported(const wxGLAttributes& dispAttrs)
|
|
{
|
|
return wxGLCanvas::FindMatchingPixelFormat(dispAttrs) > 0;
|
|
}
|
|
|
|
/* static */
|
|
bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
|
|
{
|
|
// We need a device context to test the pixel format, so get one
|
|
// for the root window.
|
|
// Not true anymore. Keep it just in case somebody uses this undocumented function
|
|
return wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) > 0;
|
|
}
|
|
|
|
int wxGLCanvas::DoSetup(PIXELFORMATDESCRIPTOR &pfd, const int *attribList)
|
|
{
|
|
// Keep this member is case somebody is overriding it
|
|
wxUnusedVar(pfd);
|
|
wxUnusedVar(attribList);
|
|
return -1;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// palette stuff
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if wxUSE_PALETTE
|
|
|
|
bool wxGLCanvas::SetupPalette(const wxPalette& palette)
|
|
{
|
|
const int pixelFormat = ::GetPixelFormat(m_hDC);
|
|
if ( !pixelFormat )
|
|
{
|
|
wxLogLastError(wxT("GetPixelFormat"));
|
|
return false;
|
|
}
|
|
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
if ( !::DescribePixelFormat(m_hDC, pixelFormat, sizeof(pfd), &pfd) )
|
|
{
|
|
wxLogLastError(wxT("DescribePixelFormat"));
|
|
return false;
|
|
}
|
|
|
|
if ( !(pfd.dwFlags & PFD_NEED_PALETTE) )
|
|
return true;
|
|
|
|
m_palette = palette;
|
|
|
|
if ( !m_palette.IsOk() )
|
|
{
|
|
m_palette = CreateDefaultPalette();
|
|
if ( !m_palette.IsOk() )
|
|
return false;
|
|
}
|
|
|
|
if ( !::SelectPalette(m_hDC, GetHpaletteOf(m_palette), FALSE) )
|
|
{
|
|
wxLogLastError(wxT("SelectPalette"));
|
|
return false;
|
|
}
|
|
|
|
if ( ::RealizePalette(m_hDC) == GDI_ERROR )
|
|
{
|
|
wxLogLastError(wxT("RealizePalette"));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
wxPalette wxGLCanvas::CreateDefaultPalette()
|
|
{
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
int paletteSize;
|
|
int pixelFormat = GetPixelFormat(m_hDC);
|
|
|
|
DescribePixelFormat(m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
|
|
|
|
paletteSize = 1 << pfd.cColorBits;
|
|
|
|
LOGPALETTE* pPal =
|
|
(LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
|
|
pPal->palVersion = 0x300;
|
|
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;
|
|
|
|
for (int i=0; i<paletteSize; ++i)
|
|
{
|
|
pPal->palPalEntry[i].peRed =
|
|
(BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask);
|
|
pPal->palPalEntry[i].peGreen =
|
|
(BYTE)((((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask);
|
|
pPal->palPalEntry[i].peBlue =
|
|
(BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask);
|
|
pPal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
|
|
HPALETTE hPalette = CreatePalette(pPal);
|
|
free(pPal);
|
|
|
|
wxPalette palette;
|
|
palette.SetHPALETTE((WXHPALETTE) hPalette);
|
|
|
|
return palette;
|
|
}
|
|
|
|
void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
|
|
{
|
|
/* realize palette if this is the current window */
|
|
if ( GetPalette()->IsOk() ) {
|
|
::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
|
|
::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
|
|
::RealizePalette(GetHDC());
|
|
Refresh();
|
|
event.SetPaletteRealized(true);
|
|
}
|
|
else
|
|
event.SetPaletteRealized(false);
|
|
}
|
|
|
|
void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
|
|
{
|
|
/* realize palette if this is *not* the current window */
|
|
if ( GetPalette() &&
|
|
GetPalette()->IsOk() && (this != event.GetChangedWindow()) )
|
|
{
|
|
::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
|
|
::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
|
|
::RealizePalette(GetHDC());
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_PALETTE
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// deprecated wxGLCanvas methods using implicit wxGLContext
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// deprecated constructors creating an implicit m_glContext
|
|
#if WXWIN_COMPATIBILITY_2_8
|
|
|
|
wxGLCanvas::wxGLCanvas(wxWindow *parent,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name,
|
|
const int *attribList,
|
|
const wxPalette& palette)
|
|
{
|
|
Init();
|
|
|
|
if ( Create(parent, id, pos, size, style, name, attribList, palette) )
|
|
m_glContext = new wxGLContext(this);
|
|
}
|
|
|
|
wxGLCanvas::wxGLCanvas(wxWindow *parent,
|
|
const wxGLContext *shared,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name,
|
|
const int *attribList,
|
|
const wxPalette& palette)
|
|
{
|
|
Init();
|
|
|
|
if ( Create(parent, id, pos, size, style, name, attribList, palette) )
|
|
m_glContext = new wxGLContext(this, shared);
|
|
}
|
|
|
|
wxGLCanvas::wxGLCanvas(wxWindow *parent,
|
|
const wxGLCanvas *shared,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name,
|
|
const int *attribList,
|
|
const wxPalette& palette)
|
|
{
|
|
Init();
|
|
|
|
if ( Create(parent, id, pos, size, style, name, attribList, palette) )
|
|
m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
|
|
}
|
|
|
|
#endif // WXWIN_COMPATIBILITY_2_8
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxGLApp
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxGLApp::InitGLVisual(const int *attribList)
|
|
{
|
|
if ( !wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) )
|
|
{
|
|
wxLogError(_("Failed to initialize OpenGL"));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // wxUSE_GLCANVAS
|