X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/655719367ac5e131d9642e5783f3ecf64d1a3385..dd9f8b6bb6935360a8271dc3e8749fb026b601a8:/src/msw/glcanvas.cpp diff --git a/src/msw/glcanvas.cpp b/src/msw/glcanvas.cpp index 75f1b955ff..edf2264d60 100644 --- a/src/msw/glcanvas.cpp +++ b/src/msw/glcanvas.cpp @@ -9,34 +9,47 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "glcanvas.h" -#endif +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- #include "wx/wxprec.h" #if defined(__BORLANDC__) -#pragma hdrstop + #pragma hdrstop #endif #if wxUSE_GLCANVAS #ifndef WX_PRECOMP - #include "wx/frame.h" - #include "wx/settings.h" #include "wx/intl.h" #include "wx/log.h" #include "wx/app.h" + #include "wx/module.h" #endif #include "wx/msw/private.h" -// DLL options compatibility check: -#include "wx/build.h" -WX_CHECK_BUILD_OPTIONS("wxGL") - #include "wx/glcanvas.h" +// from src/msw/window.cpp +LRESULT WXDLLEXPORT APIENTRY _EXPORT 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 + +// ---------------------------------------------------------------------------- +// libraries +// ---------------------------------------------------------------------------- + /* The following two compiler directives are specific to the Microsoft Visual C++ family of compilers @@ -59,183 +72,188 @@ WX_CHECK_BUILD_OPTIONS("wxGL") # pragma comment( lib, "glu32" ) #endif +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- static const wxChar *wxGLCanvasClassName = wxT("wxGLCanvasClass"); static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR"); -LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam); +// ============================================================================ +// implementation +// ============================================================================ -/* - * GLContext implementation - */ +// ---------------------------------------------------------------------------- +// wxGLModule is responsible for unregistering wxGLCanvasClass Windows class +// ---------------------------------------------------------------------------- -wxGLContext::wxGLContext(bool WXUNUSED(isRGB), wxGLCanvas *win, const wxPalette& WXUNUSED(palette)) +class wxGLModule : public wxModule { - m_window = win; +public: + bool OnInit() { return true; } + void OnExit() { UnregisterClasses(); } - m_hDC = win->GetHDC(); + // register the GL classes if not done yet, return true if ok, false if + // registration failed + static bool RegisterClasses(); - m_glContext = wglCreateContext((HDC) m_hDC); - wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGl context") ); + // unregister the classes, done automatically on program termination + static void UnregisterClasses(); - wglMakeCurrent((HDC) m_hDC, m_glContext); -} +private: + // wxGLCanvas is only used from the main thread so this is MT-ok + static bool ms_registeredGLClasses; + + DECLARE_DYNAMIC_CLASS(wxGLModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule) + +bool wxGLModule::ms_registeredGLClasses = false; -wxGLContext::wxGLContext( - bool WXUNUSED(isRGB), wxGLCanvas *win, - const wxPalette& WXUNUSED(palette), - const wxGLContext *other /* for sharing display lists */ - ) +/* static */ +bool wxGLModule::RegisterClasses() { - m_window = win; + if ( ms_registeredGLClasses ) + return true; + + // We have to register a special window class because we need the CS_OWNDC + // style for GLCanvas: some OpenGL drivers are buggy and don't work with + // windows without this style + WNDCLASS wndclass; + + // the fields which are common to all classes + wndclass.lpfnWndProc = (WNDPROC)wxWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for? + wndclass.hInstance = wxhInstance; + wndclass.hIcon = (HICON) NULL; + wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW); + wndclass.lpszMenuName = NULL; + + // Register the GLCanvas class name + wndclass.hbrBackground = (HBRUSH)NULL; + wndclass.lpszClassName = wxGLCanvasClassName; + wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC; - m_hDC = win->GetHDC(); + if ( !::RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)")); + return false; + } - m_glContext = wglCreateContext((HDC) m_hDC); - wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGl context") ); + // Register the GLCanvas class name for windows which don't do full repaint + // on resize + wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw; + wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW); - if( other != 0 ) - wglShareLists( other->m_glContext, m_glContext ); + if ( !::RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)")); + + ::UnregisterClass(wxGLCanvasClassName, wxhInstance); + + return false; + } + + ms_registeredGLClasses = true; - wglMakeCurrent((HDC) m_hDC, m_glContext); + return true; } -wxGLContext::~wxGLContext() +/* static */ +void wxGLModule::UnregisterClasses() { - if (m_glContext) - { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(m_glContext); - } + // we need to unregister the classes in case we're in a DLL which is + // unloaded and then loaded again because if we don't, the registration is + // going to fail in wxGLCanvas::Create() the next time we're loaded + if ( ms_registeredGLClasses ) + { + ::UnregisterClass(wxGLCanvasClassName, wxhInstance); + ::UnregisterClass(wxGLCanvasClassNameNoRedraw, wxhInstance); + + ms_registeredGLClasses = false; + } } -void wxGLContext::SwapBuffers() +// ---------------------------------------------------------------------------- +// wxGLContext +// ---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGLContext, wxObject) + +wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext* other) { - if (m_glContext) - { - wglMakeCurrent((HDC) m_hDC, m_glContext); - ::SwapBuffers((HDC) m_hDC); //blits the backbuffer into DC - } + m_glContext = wglCreateContext(win->GetHDC()); + wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") ); + + if ( other ) + { + if ( !wglShareLists(other->m_glContext, m_glContext) ) + wxLogLastError(_T("wglShareLists")); + } } -void wxGLContext::SetCurrent() +wxGLContext::~wxGLContext() { - if (m_glContext) - { - wglMakeCurrent((HDC) m_hDC, m_glContext); - } - - /* - setupPixelFormat(hDC); - setupPalette(hDC); - */ + // note that it's ok to delete the context even if it's the current one + wglDeleteContext(m_glContext); } -void wxGLContext::SetColour(const wxChar *colour) +bool wxGLContext::SetCurrent(const wxGLCanvas& win) const { - wxColour col = wxTheColourDatabase->Find(colour); - if (col.Ok()) + if ( !wglMakeCurrent(win.GetHDC(), m_glContext) ) { - float r = (float)(col.Red()/256.0); - float g = (float)(col.Green()/256.0); - float b = (float)(col.Blue()/256.0); - glColor3f( r, g, b); + wxLogLastError(_T("wglMakeCurrent")); + return false; } + return true; } - -/* - * wxGLCanvas implementation - */ +// ============================================================================ +// wxGLCanvas +// ============================================================================ IMPLEMENT_CLASS(wxGLCanvas, wxWindow) BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow) - EVT_SIZE(wxGLCanvas::OnSize) EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged) EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette) END_EVENT_TABLE() -wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, - const wxPoint& pos, const wxSize& size, long style, const wxString& name, - int *attribList, const wxPalette& palette) : wxWindow() -{ - m_glContext = (wxGLContext*) NULL; - - bool ret = Create(parent, id, pos, size, style, name); - - if ( ret ) - { - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); - SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - } +// ---------------------------------------------------------------------------- +// wxGLCanvas construction +// ---------------------------------------------------------------------------- - m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); - - SetupPixelFormat(attribList); - SetupPalette(palette); - - m_glContext = new wxGLContext(TRUE, this, palette); -} - -wxGLCanvas::wxGLCanvas( wxWindow *parent, - const wxGLContext *shared, wxWindowID id, - const wxPoint& pos, const wxSize& size, long style, const wxString& name, - int *attribList, const wxPalette& palette ) - : wxWindow() +void wxGLCanvas::Init() { - m_glContext = (wxGLContext*) NULL; - - bool ret = Create(parent, id, pos, size, style, name); - - if ( ret ) - { - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); - SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - } - - m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); - - SetupPixelFormat(attribList); - SetupPalette(palette); - - m_glContext = new wxGLContext(TRUE, this, palette, shared ); +#if WXWIN_COMPATIBILITY_2_8 + m_glContext = NULL; +#endif + m_hDC = NULL; } -// Not very useful for wxMSW, but this is to be wxGTK compliant - -wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id, - const wxPoint& pos, const wxSize& size, long style, const wxString& name, - int *attribList, const wxPalette& palette ): - wxWindow() +wxGLCanvas::wxGLCanvas(wxWindow *parent, + wxWindowID id, + const int *attribList, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const wxPalette& palette) { - m_glContext = (wxGLContext*) NULL; - - bool ret = Create(parent, id, pos, size, style, name); - - if ( ret ) - { - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); - SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - } - - m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); + Init(); - SetupPixelFormat(attribList); - SetupPalette(palette); - - wxGLContext *sharedContext=0; - if (shared) sharedContext=shared->GetContext(); - m_glContext = new wxGLContext(TRUE, this, palette, sharedContext ); + (void)Create(parent, id, pos, size, style, name, attribList, palette); } wxGLCanvas::~wxGLCanvas() { - if (m_glContext) +#if WXWIN_COMPATIBILITY_2_8 delete m_glContext; +#endif - ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC); + ::ReleaseDC(GetHwnd(), m_hDC); } // Replaces wxWindow::Create functionality, since we need to use a different @@ -245,249 +263,283 @@ bool wxGLCanvas::Create(wxWindow *parent, const wxPoint& pos, const wxSize& size, long style, - const wxString& name) + const wxString& name, + const int *attribList, + const wxPalette& palette) { - static bool s_registeredGLCanvasClass = FALSE; - - // We have to register a special window class because we need - // the CS_OWNDC style for GLCanvas. - - /* - From Angel Popov - - Here are two snips from a dicussion in the OpenGL Gamedev list that explains - how this problem can be fixed: - - "There are 5 common DCs available in Win95. These are aquired when you call - GetDC or GetDCEx from a window that does _not_ have the OWNDC flag. - OWNDC flagged windows do not get their DC from the common DC pool, the issue - is they require 800 bytes each from the limited 64Kb local heap for GDI." + wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") ); - "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps - do), Win95 will actually "steal" it from you. MakeCurrent fails, - apparently, because Windows re-assigns the HDC to a different window. The - only way to prevent this, the only reliable means, is to set CS_OWNDC." - */ - - if (!s_registeredGLCanvasClass) - { - WNDCLASS wndclass; - - // the fields which are common to all classes - wndclass.lpfnWndProc = (WNDPROC)wxWndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for? - wndclass.hInstance = wxhInstance; - wndclass.hIcon = (HICON) NULL; - wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW); - wndclass.lpszMenuName = NULL; - - // Register the GLCanvas class name - wndclass.hbrBackground = (HBRUSH)NULL; - wndclass.lpszClassName = wxGLCanvasClassName; - wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC; - - if ( !::RegisterClass(&wndclass) ) + if ( !wxGLModule::RegisterClasses() ) { - wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)")); - return FALSE; - } - - // Register the GLCanvas class name for windows which don't do full repaint - // on resize - wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw; - wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW); + wxLogError(_("Failed to register OpenGL window class.")); - if ( !::RegisterClass(&wndclass) ) - { - wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)")); + return false; + } - ::UnregisterClass(wxGLCanvasClassName, wxhInstance); + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return false; - return FALSE; - } + parent->AddChild(this); - s_registeredGLCanvasClass = TRUE; - } + /* + 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); - wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") ); + if ( !MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle) ) + return false; - if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) - return FALSE; + m_hDC = ::GetDC(GetHwnd()); + if ( !m_hDC ) + return false; - parent->AddChild(this); + if ( !DoSetup(attribList) ) + return false; - DWORD msflags = 0; +#if wxUSE_PALETTE + if ( !SetupPalette(palette) ) + return false; +#else // !wxUSE_PALETTE + wxUnusedVar(palette); +#endif // wxUSE_PALETTE/!wxUSE_PALETTE - /* - 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. - */ + return true; +} - WXDWORD exStyle = 0; - msflags |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - msflags |= MSWGetStyle(style, & exStyle) ; +// ---------------------------------------------------------------------------- +// operations +// ---------------------------------------------------------------------------- - return MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle); +bool wxGLCanvas::SwapBuffers() +{ + if ( !::SwapBuffers(m_hDC) ) + { + return false; + wxLogLastError(_T("SwapBuffers")); + } + return true; } -static void AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, int *attribList) +// ---------------------------------------------------------------------------- +// pixel format stuff +// ---------------------------------------------------------------------------- + +static void +AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int *attribList) { - if (attribList) { + if ( !attribList ) + return; + pfd.dwFlags &= ~PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_COLORINDEX; pfd.cColorBits = 0; int arg=0; - while( (attribList[arg]!=0) ) + while ( attribList[arg] ) { - switch( attribList[arg++] ) - { - case WX_GL_RGBA: - pfd.iPixelType = PFD_TYPE_RGBA; - break; - case WX_GL_BUFFER_SIZE: - pfd.cColorBits = attribList[arg++]; - break; - case WX_GL_LEVEL: - // this member looks like it may be obsolete - if (attribList[arg] > 0) { - pfd.iLayerType = (BYTE)PFD_OVERLAY_PLANE; - } else if (attribList[arg] < 0) { - pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE; - } else { - pfd.iLayerType = (BYTE)PFD_MAIN_PLANE; - } - arg++; - break; - case WX_GL_DOUBLEBUFFER: - pfd.dwFlags |= PFD_DOUBLEBUFFER; - break; - case WX_GL_STEREO: - pfd.dwFlags |= PFD_STEREO; - break; - case WX_GL_AUX_BUFFERS: - pfd.cAuxBuffers = attribList[arg++]; - break; - case WX_GL_MIN_RED: - pfd.cColorBits += (pfd.cRedBits = attribList[arg++]); - break; - case WX_GL_MIN_GREEN: - pfd.cColorBits += (pfd.cGreenBits = attribList[arg++]); - break; - case WX_GL_MIN_BLUE: - pfd.cColorBits += (pfd.cBlueBits = attribList[arg++]); - break; - case WX_GL_MIN_ALPHA: - // doesn't count in cColorBits - pfd.cAlphaBits = attribList[arg++]; - break; - case WX_GL_DEPTH_SIZE: - pfd.cDepthBits = attribList[arg++]; - break; - case WX_GL_STENCIL_SIZE: - pfd.cStencilBits = attribList[arg++]; - break; - case WX_GL_MIN_ACCUM_RED: - pfd.cAccumBits += (pfd.cAccumRedBits = attribList[arg++]); - break; - case WX_GL_MIN_ACCUM_GREEN: - pfd.cAccumBits += (pfd.cAccumGreenBits = attribList[arg++]); - break; - case WX_GL_MIN_ACCUM_BLUE: - pfd.cAccumBits += (pfd.cAccumBlueBits = attribList[arg++]); - break; - case WX_GL_MIN_ACCUM_ALPHA: - pfd.cAccumBits += (pfd.cAccumAlphaBits = attribList[arg++]); - break; - default: - break; - } + switch ( attribList[arg++] ) + { + case WX_GL_RGBA: + pfd.iPixelType = PFD_TYPE_RGBA; + break; + case WX_GL_BUFFER_SIZE: + pfd.cColorBits = attribList[arg++]; + break; + case WX_GL_LEVEL: + // this member looks like it may be obsolete + if ( attribList[arg] > 0 ) + pfd.iLayerType = PFD_OVERLAY_PLANE; + else if ( attribList[arg] < 0 ) + pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE; + else + pfd.iLayerType = PFD_MAIN_PLANE; + arg++; + break; + case WX_GL_DOUBLEBUFFER: + pfd.dwFlags |= PFD_DOUBLEBUFFER; + break; + case WX_GL_STEREO: + pfd.dwFlags |= PFD_STEREO; + break; + case WX_GL_AUX_BUFFERS: + pfd.cAuxBuffers = attribList[arg++]; + break; + case WX_GL_MIN_RED: + pfd.cColorBits = (pfd.cColorBits + + (pfd.cRedBits = attribList[arg++])); + break; + case WX_GL_MIN_GREEN: + pfd.cColorBits = (pfd.cColorBits + + (pfd.cGreenBits = attribList[arg++])); + break; + case WX_GL_MIN_BLUE: + pfd.cColorBits = (pfd.cColorBits + + (pfd.cBlueBits = attribList[arg++])); + break; + case WX_GL_MIN_ALPHA: + // doesn't count in cColorBits + pfd.cAlphaBits = attribList[arg++]; + break; + case WX_GL_DEPTH_SIZE: + pfd.cDepthBits = attribList[arg++]; + break; + case WX_GL_STENCIL_SIZE: + pfd.cStencilBits = attribList[arg++]; + break; + case WX_GL_MIN_ACCUM_RED: + pfd.cAccumBits = (pfd.cAccumBits + + (pfd.cAccumRedBits = attribList[arg++])); + break; + case WX_GL_MIN_ACCUM_GREEN: + pfd.cAccumBits = (pfd.cAccumBits + + (pfd.cAccumGreenBits = attribList[arg++])); + break; + case WX_GL_MIN_ACCUM_BLUE: + pfd.cAccumBits = (pfd.cAccumBits + + (pfd.cAccumBlueBits = attribList[arg++])); + break; + case WX_GL_MIN_ACCUM_ALPHA: + pfd.cAccumBits = (pfd.cAccumBits + + (pfd.cAccumAlphaBits = attribList[arg++])); + break; + } } - } } -void wxGLCanvas::SetupPixelFormat(int *attribList) // (HDC hDC) +/* static */ +int +wxGLCanvas::ChooseMatchingPixelFormat(HDC hdc, + const int *attribList, + PIXELFORMATDESCRIPTOR *ppfd) { - PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), /* size */ - 1, /* version */ + // default neutral pixel format + PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), // size + 1, // version PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | - PFD_DOUBLEBUFFER, /* support double-buffering */ - PFD_TYPE_RGBA, /* color type */ - 16, /* prefered color depth */ - 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ - 0, /* no alpha buffer */ - 0, /* alpha bits (ignored) */ - 0, /* no accumulation buffer */ - 0, 0, 0, 0, /* accum bits (ignored) */ - 16, /* depth buffer */ - 0, /* no stencil buffer */ - 0, /* no auxiliary buffers */ - PFD_MAIN_PLANE, /* main layer */ - 0, /* reserved */ - 0, 0, 0, /* no layer, visible, damage masks */ + PFD_DOUBLEBUFFER, // support double-buffering + PFD_TYPE_RGBA, // color type + 16, // preferred color depth + 0, 0, 0, 0, 0, 0, // color bits (ignored) + 0, // no alpha buffer + 0, // alpha bits (ignored) + 0, // no accumulation buffer + 0, 0, 0, 0, // accumulator bits (ignored) + 16, // depth buffer + 0, // no stencil buffer + 0, // no auxiliary buffers + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0, // no layer, visible, damage masks }; - AdjustPFDForAttributes(pfd, attribList); + if ( !ppfd ) + ppfd = &pfd; + else + *ppfd = pfd; - int pixelFormat = ChoosePixelFormat((HDC) m_hDC, &pfd); - if (pixelFormat == 0) { - wxLogLastError(_T("ChoosePixelFormat")); - } - else { - if ( !::SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) ) { - wxLogLastError(_T("SetPixelFormat")); - } - } + AdjustPFDForAttributes(*ppfd, attribList); + + return ::ChoosePixelFormat(hdc, ppfd); } -void wxGLCanvas::SetupPalette(const wxPalette& palette) +/* static */ +bool wxGLCanvasBase::IsDisplaySupported(const int *attribList) +{ + // We need a device context to test the pixel format, so get one + // for the root window. + return wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) > 0; +} + +bool wxGLCanvas::DoSetup(const int *attribList) { - int pixelFormat = GetPixelFormat((HDC) m_hDC); PIXELFORMATDESCRIPTOR pfd; + const int pixelFormat = ChooseMatchingPixelFormat(m_hDC, attribList, &pfd); + if ( !pixelFormat ) + { + wxLogLastError(_T("ChoosePixelFormat")); + return false; + } + + if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) ) + { + wxLogLastError(_T("SetPixelFormat")); + return false; + } - DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + return true; +} + +// ---------------------------------------------------------------------------- +// palette stuff +// ---------------------------------------------------------------------------- - if (pfd.dwFlags & PFD_NEED_PALETTE) +#if wxUSE_PALETTE + +bool wxGLCanvas::SetupPalette(const wxPalette& palette) +{ + const int pixelFormat = ::GetPixelFormat(m_hDC); + if ( !pixelFormat ) { + wxLogLastError(_T("GetPixelFormat")); + return false; } - else + + PIXELFORMATDESCRIPTOR pfd; + if ( !::DescribePixelFormat(m_hDC, pixelFormat, sizeof(pfd), &pfd) ) { - return; + wxLogLastError(_T("DescribePixelFormat")); + return false; } + if ( !(pfd.dwFlags & PFD_NEED_PALETTE) ) + return true; + m_palette = palette; if ( !m_palette.Ok() ) { m_palette = CreateDefaultPalette(); + if ( !m_palette.Ok() ) + return false; } - if (m_palette.Ok()) + if ( !::SelectPalette(m_hDC, GetHpaletteOf(m_palette), FALSE) ) { - SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE); - RealizePalette((HDC) m_hDC); + wxLogLastError(_T("SelectPalette")); + return false; } + + if ( ::RealizePalette(m_hDC) == GDI_ERROR ) + { + wxLogLastError(_T("RealizePalette")); + return false; + } + + return true; } wxPalette wxGLCanvas::CreateDefaultPalette() { PIXELFORMATDESCRIPTOR pfd; int paletteSize; - int pixelFormat = GetPixelFormat((HDC) m_hDC); + int pixelFormat = GetPixelFormat(m_hDC); - DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + 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 = paletteSize; + pPal->palNumEntries = (WORD)paletteSize; /* build a simple RGB color palette */ { @@ -498,11 +550,11 @@ wxPalette wxGLCanvas::CreateDefaultPalette() for (i=0; ipalPalEntry[i].peRed = - (((i >> pfd.cRedShift) & redMask) * 255) / redMask; + (BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask); pPal->palPalEntry[i].peGreen = - (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask; + (BYTE)((((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask); pPal->palPalEntry[i].peBlue = - (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask; + (BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask); pPal->palPalEntry[i].peFlags = 0; } } @@ -516,47 +568,20 @@ wxPalette wxGLCanvas::CreateDefaultPalette() return palette; } -void wxGLCanvas::SwapBuffers() -{ - if (m_glContext) - m_glContext->SwapBuffers(); -} - -void wxGLCanvas::OnSize(wxSizeEvent& WXUNUSED(event)) -{ -} - -void wxGLCanvas::SetCurrent() -{ - if (m_glContext) - { - m_glContext->SetCurrent(); - } -} - -void wxGLCanvas::SetColour(const wxChar *colour) -{ - if (m_glContext) - m_glContext->SetColour(colour); -} - -// TODO: Have to have this called by parent frame (?) -// So we need wxFrame to call OnQueryNewPalette for all children... void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event) { /* realize palette if this is the current window */ if ( GetPalette()->Ok() ) { ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE()); - ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); - ::RealizePalette((HDC) GetHDC()); + ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); + ::RealizePalette(GetHDC()); Refresh(); - event.SetPaletteRealized(TRUE); + event.SetPaletteRealized(true); } else - event.SetPaletteRealized(FALSE); + event.SetPaletteRealized(false); } -// I think this doesn't have to be propagated to child windows. void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event) { /* realize palette if this is *not* the current window */ @@ -564,190 +589,84 @@ void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event) GetPalette()->Ok() && (this != event.GetChangedWindow()) ) { ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE()); - ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); - ::RealizePalette((HDC) GetHDC()); + ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); + ::RealizePalette(GetHDC()); Refresh(); } } -/* Give extensions proper function names. */ - -/* EXT_vertex_array */ -void glArrayElementEXT(GLint WXUNUSED(i)) -{ -} - -void glColorPointerEXT(GLint WXUNUSED(size), GLenum WXUNUSED(type), GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLvoid *WXUNUSED(pointer)) -{ -} - -void glDrawArraysEXT(GLenum mode, GLint first, GLsizei count) -{ -#ifdef GL_EXT_vertex_array - static PFNGLDRAWARRAYSEXTPROC proc = 0; - - if ( !proc ) - { - proc = (PFNGLDRAWARRAYSEXTPROC) wglGetProcAddress("glDrawArraysEXT"); - } - - if ( proc ) - (* proc) (mode, first, count); -#endif -} - -void glEdgeFlagPointerEXT(GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLboolean *WXUNUSED(pointer)) -{ -} - -void glGetPointervEXT(GLenum WXUNUSED(pname), GLvoid* *WXUNUSED(params)) -{ -} - -void glIndexPointerEXT(GLenum WXUNUSED(type), GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLvoid *WXUNUSED(pointer)) -{ -} - -void glNormalPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) -{ -#ifdef GL_EXT_vertex_array - static PFNGLNORMALPOINTEREXTPROC proc = 0; - - if ( !proc ) - { - proc = (PFNGLNORMALPOINTEREXTPROC) wglGetProcAddress("glNormalPointerEXT"); - } - - if ( proc ) - (* proc) (type, stride, count, pointer); -#endif -} - -void glTexCoordPointerEXT(GLint WXUNUSED(size), GLenum WXUNUSED(type), GLsizei WXUNUSED(stride), GLsizei WXUNUSED(count), const GLvoid *WXUNUSED(pointer)) -{ -} +#endif // wxUSE_PALETTE -void glVertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) -{ -#ifdef GL_EXT_vertex_array - static PFNGLVERTEXPOINTEREXTPROC proc = 0; +// ---------------------------------------------------------------------------- +// deprecated wxGLCanvas methods using implicit wxGLContext +// ---------------------------------------------------------------------------- - if ( !proc ) - { - proc = (PFNGLVERTEXPOINTEREXTPROC) wglGetProcAddress("glVertexPointerEXT"); - } - if ( proc ) - (* proc) (size, type, stride, count, pointer); -#endif -} +// deprecated constructors creating an implicit m_glContext +#if WXWIN_COMPATIBILITY_2_8 -/* EXT_color_subtable */ -void glColorSubtableEXT(GLenum WXUNUSED(target), GLsizei WXUNUSED(start), GLsizei WXUNUSED(count), GLenum WXUNUSED(format), GLenum WXUNUSED(type), const GLvoid *WXUNUSED(table)) +wxGLCanvas::wxGLCanvas(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name, + const int *attribList, + const wxPalette& palette) { -} + Init(); -/* EXT_color_table */ -void glColorTableEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(internalformat), GLsizei WXUNUSED(width), GLenum WXUNUSED(format), GLenum WXUNUSED(type), const GLvoid *WXUNUSED(table)) -{ + if ( Create(parent, id, pos, size, style, name, attribList, palette) ) + m_glContext = new wxGLContext(this); } -void glCopyColorTableEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(internalformat), GLint WXUNUSED(x), GLint WXUNUSED(y), GLsizei WXUNUSED(width)) +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(); -void glGetColorTableEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(format), GLenum WXUNUSED(type), GLvoid *WXUNUSED(table)) -{ + if ( Create(parent, id, pos, size, style, name, attribList, palette) ) + m_glContext = new wxGLContext(this, shared); } -void glGetColorTableParamaterfvEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(pname), GLfloat *WXUNUSED(params)) +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(); -void glGetColorTavleParameterivEXT(GLenum WXUNUSED(target), GLenum WXUNUSED(pname), GLint *WXUNUSED(params)) -{ + if ( Create(parent, id, pos, size, style, name, attribList, palette) ) + m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL); } -/* SGI_compiled_vertex_array */ -void glLockArraysSGI(GLint WXUNUSED(first), GLsizei WXUNUSED(count)) -{ -} - -void glUnlockArraysSGI() -{ -} - - -/* SGI_cull_vertex */ -void glCullParameterdvSGI(GLenum WXUNUSED(pname), GLdouble* WXUNUSED(params)) -{ -} - -void glCullParameterfvSGI(GLenum WXUNUSED(pname), GLfloat* WXUNUSED(params)) -{ -} - -/* SGI_index_func */ -void glIndexFuncSGI(GLenum WXUNUSED(func), GLclampf WXUNUSED(ref)) -{ -} - -/* SGI_index_material */ -void glIndexMaterialSGI(GLenum WXUNUSED(face), GLenum WXUNUSED(mode)) -{ -} - -/* WIN_swap_hint */ -void glAddSwapHintRectWin(GLint WXUNUSED(x), GLint WXUNUSED(y), GLsizei WXUNUSED(width), GLsizei WXUNUSED(height)) -{ -} +#endif // WXWIN_COMPATIBILITY_2_8 -//--------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- // wxGLApp -//--------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- -IMPLEMENT_CLASS(wxGLApp, wxApp) - -bool wxGLApp::InitGLVisual(int *attribList) +bool wxGLApp::InitGLVisual(const int *attribList) { - int pixelFormat; - PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), /* size */ - 1, /* version */ - PFD_SUPPORT_OPENGL | - PFD_DRAW_TO_WINDOW | - PFD_DOUBLEBUFFER, /* support double-buffering */ - PFD_TYPE_RGBA, /* color type */ - 16, /* prefered color depth */ - 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ - 0, /* no alpha buffer */ - 0, /* alpha bits (ignored) */ - 0, /* no accumulation buffer */ - 0, 0, 0, 0, /* accum bits (ignored) */ - 16, /* depth buffer */ - 0, /* no stencil buffer */ - 0, /* no auxiliary buffers */ - PFD_MAIN_PLANE, /* main layer */ - 0, /* reserved */ - 0, 0, 0, /* no layer, visible, damage masks */ - }; - - AdjustPFDForAttributes(pfd, attribList); - - // use DC for whole (root) screen, since no windows have yet been created - pixelFormat = ChoosePixelFormat(ScreenHDC(), &pfd); - - if (pixelFormat == 0) { - wxLogError(_("Failed to initialize OpenGL")); - return FALSE; - } - - return TRUE; -} + if ( !wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) ) + { + wxLogError(_("Failed to initialize OpenGL")); + return false; + } -wxGLApp::~wxGLApp() -{ + return true; } -#endif - // wxUSE_GLCANVAS +#endif // wxUSE_GLCANVAS