1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/msw/glcanvas.cpp
3// Purpose:     wxGLCanvas, for using OpenGL with wxWidgets under MS Windows
4// Author:      Julian Smart
5// Modified by:
6// Created:     04/01/98
7// RCS-ID:      $Id: glcanvas.cpp 41031 2006-09-06 13:31:20Z RR $
8// Copyright:   (c) Julian Smart
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#if defined(__BORLANDC__)
15    #pragma hdrstop
16#endif
17
18#if wxUSE_GLCANVAS
19
20#ifndef WX_PRECOMP
21    #include "wx/frame.h"
22    #include "wx/settings.h"
23    #include "wx/intl.h"
24    #include "wx/log.h"
25    #include "wx/app.h"
26    #include "wx/module.h"
27#endif
28
29#include "wx/msw/private.h"
30
31// DLL options compatibility check:
32#include "wx/build.h"
33WX_CHECK_BUILD_OPTIONS("wxGL")
34
35#include "wx/glcanvas.h"
36
37#if GL_EXT_vertex_array
38    #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) name
39#else
40    #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) WXUNUSED(name)
41#endif
42
43/*
44  The following two compiler directives are specific to the Microsoft Visual
45  C++ family of compilers
46
47  Fundementally what they do is instruct the linker to use these two libraries
48  for the resolution of symbols. In essence, this is the equivalent of adding
49  these two libraries to either the Makefile or project file.
50
51  This is NOT a recommended technique, and certainly is unlikely to be used
52  anywhere else in wxWidgets given it is so specific to not only wxMSW, but
53  also the VC compiler. However, in the case of opengl support, it's an
54  applicable technique as opengl is optional in setup.h This code (wrapped by
55  wxUSE_GLCANVAS), now allows opengl support to be added purely by modifying
56  setup.h rather than by having to modify either the project or DSP fle.
57
58  See MSDN for further information on the exact usage of these commands.
59*/
60#ifdef _MSC_VER
61#  pragma comment( lib, "opengl32" )
62#  pragma comment( lib, "glu32" )
63#endif
64
65
66static const wxChar *wxGLCanvasClassName = wxT("wxGLCanvasClass");
67static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR");
68
69LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
70                                   WPARAM wParam, LPARAM lParam);
71
72// ----------------------------------------------------------------------------
73// wxGLModule is responsible for unregistering wxGLCanvasClass Windows class
74// ----------------------------------------------------------------------------
75
76class wxGLModule : public wxModule
77{
78public:
79    bool OnInit() { return true; }
80    void OnExit() { UnregisterClasses(); }
81
82    // register the GL classes if not done yet, return true if ok, false if
83    // registration failed
84    static bool RegisterClasses();
85
86    // unregister the classes, done automatically on program termination
87    static void UnregisterClasses();
88
89private:
90    // wxGLCanvas is only used from the main thread so this is MT-ok
91    static bool ms_registeredGLClasses;
92
93    DECLARE_DYNAMIC_CLASS(wxGLModule)
94};
95
96IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule)
97
98bool wxGLModule::ms_registeredGLClasses = false;
99
100/* static */
101bool wxGLModule::RegisterClasses()
102{
103    if (ms_registeredGLClasses)
104        return true;
105
106    // We have to register a special window class because we need the CS_OWNDC
107    // style for GLCanvas.
108
109  /*
110  From Angel Popov <jumpo@bitex.com>
111
112  Here are two snips from a dicussion in the OpenGL Gamedev list that explains
113  how this problem can be fixed:
114
115  "There are 5 common DCs available in Win95. These are aquired when you call
116  GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
117  OWNDC flagged windows do not get their DC from the common DC pool, the issue
118  is they require 800 bytes each from the limited 64Kb local heap for GDI."
119
120  "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
121  do), Win95 will actually "steal" it from you.  MakeCurrent fails,
122  apparently, because Windows re-assigns the HDC to a different window.  The
123  only way to prevent this, the only reliable means, is to set CS_OWNDC."
124  */
125
126    WNDCLASS wndclass;
127
128    // the fields which are common to all classes
129    wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
130    wndclass.cbClsExtra    = 0;
131    wndclass.cbWndExtra    = sizeof( DWORD ); // VZ: what is this DWORD used for?
132    wndclass.hInstance     = wxhInstance;
133    wndclass.hIcon         = (HICON) NULL;
134    wndclass.hCursor       = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
135    wndclass.lpszMenuName  = NULL;
136
137    // Register the GLCanvas class name
138    wndclass.hbrBackground = (HBRUSH)NULL;
139    wndclass.lpszClassName = wxGLCanvasClassName;
140    wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
141
142    if ( !::RegisterClass(&wndclass) )
143    {
144        wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
145        return false;
146    }
147
148    // Register the GLCanvas class name for windows which don't do full repaint
149    // on resize
150    wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw;
151    wndclass.style        &= ~(CS_HREDRAW | CS_VREDRAW);
152
153    if ( !::RegisterClass(&wndclass) )
154    {
155        wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
156
157        ::UnregisterClass(wxGLCanvasClassName, wxhInstance);
158
159        return false;
160    }
161
162    ms_registeredGLClasses = true;
163
164    return true;
165}
166
167/* static */
168void wxGLModule::UnregisterClasses()
169{
170    // we need to unregister the classes in case we're in a DLL which is
171    // unloaded and then loaded again because if we don't, the registration is
172    // going to fail in wxGLCanvas::Create() the next time we're loaded
173    if ( ms_registeredGLClasses )
174    {
175        ::UnregisterClass(wxGLCanvasClassName, wxhInstance);
176        ::UnregisterClass(wxGLCanvasClassNameNoRedraw, wxhInstance);
177
178        ms_registeredGLClasses = false;
179    }
180}
181
182/*
183 * GLContext implementation
184 */
185
186IMPLEMENT_CLASS(wxGLContext, wxObject)
187
188wxGLContext::wxGLContext(wxGLCanvas* win, const wxGLContext* other /* for sharing display lists */)
189{
190  m_glContext = wglCreateContext((HDC) win->GetHDC());
191  wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") );
192
193  if( other != 0 )
194    wglShareLists( other->m_glContext, m_glContext );
195}
196
197wxGLContext::~wxGLContext()
198{
199    // If this context happens to be the current context, wglDeleteContext() makes it un-current first.
200    wglDeleteContext(m_glContext);
201}
202
203void wxGLContext::SetCurrent(const wxGLCanvas& win) const
204{
205    wglMakeCurrent((HDC) win.GetHDC(), m_glContext);
206}
207
208
209/*
210 * wxGLCanvas implementation
211 */
212
213IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
214
215BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
216    EVT_SIZE(wxGLCanvas::OnSize)
217    EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
218    EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
219END_EVENT_TABLE()
220
221wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, int *attribList,
222    const wxPoint& pos, const wxSize& size, long style,
223    const wxString& name, const wxPalette& palette) : wxWindow()
224{
225    m_glContext = NULL;
226
227    if (Create(parent, id, pos, size, style, name))
228    {
229        SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
230    }
231
232    m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
233
234    SetupPixelFormat(attribList);
235    SetupPalette(palette);
236
237    // This ctor does *not* create an instance of wxGLContext,
238    // m_glContext intentionally remains NULL.
239}
240
241wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id,
242    const wxPoint& pos, const wxSize& size, long style, const wxString& name,
243    int *attribList, const wxPalette& palette) : wxWindow()
244{
245  m_glContext = (wxGLContext*) NULL;
246
247  bool ret = Create(parent, id, pos, size, style, name);
248
249  if ( ret )
250  {
251    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
252  }
253
254  m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
255
256  SetupPixelFormat(attribList);
257  SetupPalette(palette);
258
259  m_glContext = new wxGLContext(this);
260}
261
262wxGLCanvas::wxGLCanvas( wxWindow *parent,
263              const wxGLContext *shared, wxWindowID id,
264              const wxPoint& pos, const wxSize& size, long style, const wxString& name,
265              int *attribList, const wxPalette& palette )
266  : wxWindow()
267{
268  m_glContext = (wxGLContext*) NULL;
269
270  bool ret = Create(parent, id, pos, size, style, name);
271
272  if ( ret )
273  {
274    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
275  }
276
277  m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
278
279  SetupPixelFormat(attribList);
280  SetupPalette(palette);
281
282  m_glContext = new wxGLContext(this, shared);
283}
284
285// Not very useful for wxMSW, but this is to be wxGTK compliant
286
287wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id,
288                        const wxPoint& pos, const wxSize& size, long style, const wxString& name,
289                        int *attribList, const wxPalette& palette ):
290  wxWindow()
291{
292  m_glContext = (wxGLContext*) NULL;
293
294  bool ret = Create(parent, id, pos, size, style, name);
295
296  if ( ret )
297  {
298    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
299  }
300
301  m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
302
303  SetupPixelFormat(attribList);
304  SetupPalette(palette);
305
306  wxGLContext *sharedContext=0;
307  if (shared) sharedContext=shared->GetContext();
308  m_glContext = new wxGLContext(this, sharedContext);
309}
310
311wxGLCanvas::~wxGLCanvas()
312{
313  delete m_glContext;
314
315  ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC);
316}
317
318// Replaces wxWindow::Create functionality, since we need to use a different
319// window class
320bool wxGLCanvas::Create(wxWindow *parent,
321                        wxWindowID id,
322                        const wxPoint& pos,
323                        const wxSize& size,
324                        long style,
325                        const wxString& name)
326{
327    wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
328
329    if ( !wxGLModule::RegisterClasses() )
330    {
331        wxLogError(_("Failed to register OpenGL window class."));
332
333        return false;
334    }
335
336    if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
337        return false;
338
339    parent->AddChild(this);
340
341    DWORD msflags = 0;
342
343    /*
344       A general rule with OpenGL and Win32 is that any window that will have a
345       HGLRC built for it must have two flags:  WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
346       You can find references about this within the knowledge base and most OpenGL
347       books that contain the wgl function descriptions.
348     */
349
350    WXDWORD exStyle = 0;
351    msflags |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
352    msflags |= MSWGetStyle(style, & exStyle) ;
353
354    return MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle);
355}
356
357static void AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, int *attribList)
358{
359  if (attribList) {
360    pfd.dwFlags &= ~PFD_DOUBLEBUFFER;
361    pfd.iPixelType = PFD_TYPE_COLORINDEX;
362    pfd.cColorBits = 0;
363    int arg=0;
364
365    while( (attribList[arg]!=0) )
366    {
367      switch( attribList[arg++] )
368      {
369        case WX_GL_RGBA:
370          pfd.iPixelType = PFD_TYPE_RGBA;
371          break;
372        case WX_GL_BUFFER_SIZE:
373          pfd.cColorBits = (BYTE)attribList[arg++];
374          break;
375        case WX_GL_LEVEL:
376          // this member looks like it may be obsolete
377          if (attribList[arg] > 0) {
378            pfd.iLayerType = (BYTE)PFD_OVERLAY_PLANE;
379          } else if (attribList[arg] < 0) {
380            pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE;
381          } else {
382            pfd.iLayerType = (BYTE)PFD_MAIN_PLANE;
383          }
384          arg++;
385          break;
386        case WX_GL_DOUBLEBUFFER:
387          pfd.dwFlags |= PFD_DOUBLEBUFFER;
388          break;
389        case WX_GL_STEREO:
390          pfd.dwFlags |= PFD_STEREO;
391          break;
392        case WX_GL_AUX_BUFFERS:
393          pfd.cAuxBuffers = (BYTE)attribList[arg++];
394          break;
395        case WX_GL_MIN_RED:
396          pfd.cColorBits = (BYTE)(pfd.cColorBits + (pfd.cRedBits = (BYTE)attribList[arg++]));
397          break;
398        case WX_GL_MIN_GREEN:
399          pfd.cColorBits = (BYTE)(pfd.cColorBits + (pfd.cGreenBits = (BYTE)attribList[arg++]));
400          break;
401        case WX_GL_MIN_BLUE:
402          pfd.cColorBits = (BYTE)(pfd.cColorBits + (pfd.cBlueBits = (BYTE)attribList[arg++]));
403          break;
404        case WX_GL_MIN_ALPHA:
405          // doesn't count in cColorBits
406          pfd.cAlphaBits = (BYTE)attribList[arg++];
407          break;
408        case WX_GL_DEPTH_SIZE:
409          pfd.cDepthBits = (BYTE)attribList[arg++];
410          break;
411        case WX_GL_STENCIL_SIZE:
412          pfd.cStencilBits = (BYTE)attribList[arg++];
413          break;
414        case WX_GL_MIN_ACCUM_RED:
415          pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumRedBits = (BYTE)attribList[arg++]));
416          break;
417        case WX_GL_MIN_ACCUM_GREEN:
418          pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumGreenBits = (BYTE)attribList[arg++]));
419          break;
420        case WX_GL_MIN_ACCUM_BLUE:
421          pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumBlueBits = (BYTE)attribList[arg++]));
422          break;
423        case WX_GL_MIN_ACCUM_ALPHA:
424          pfd.cAccumBits = (BYTE)(pfd.cAccumBits + (pfd.cAccumAlphaBits = (BYTE)attribList[arg++]));
425          break;
426        default:
427          break;
428      }
429    }
430  }
431}
432
433void wxGLCanvas::SetupPixelFormat(int *attribList) // (HDC hDC)
434{
435  PIXELFORMATDESCRIPTOR pfd = {
436        sizeof(PIXELFORMATDESCRIPTOR),    /* size */
437        1,                /* version */
438        PFD_SUPPORT_OPENGL |
439        PFD_DRAW_TO_WINDOW |
440        PFD_DOUBLEBUFFER,        /* support double-buffering */
441        PFD_TYPE_RGBA,            /* color type */
442        16,                /* preferred color depth */
443        0, 0, 0, 0, 0, 0,        /* color bits (ignored) */
444        0,                /* no alpha buffer */
445        0,                /* alpha bits (ignored) */
446        0,                /* no accumulation buffer */
447        0, 0, 0, 0,            /* accum bits (ignored) */
448        16,                /* depth buffer */
449        0,                /* no stencil buffer */
450        0,                /* no auxiliary buffers */
451        PFD_MAIN_PLANE,            /* main layer */
452        0,                /* reserved */
453        0, 0, 0,            /* no layer, visible, damage masks */
454    };
455
456  AdjustPFDForAttributes(pfd, attribList);
457
458  int pixelFormat = ChoosePixelFormat((HDC) m_hDC, &pfd);
459  if (pixelFormat == 0) {
460    wxLogLastError(_T("ChoosePixelFormat"));
461  }
462  else {
463    if ( !::SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) ) {
464      wxLogLastError(_T("SetPixelFormat"));
465    }
466  }
467}
468
469void wxGLCanvas::SetupPalette(const wxPalette& palette)
470{
471    int pixelFormat = GetPixelFormat((HDC) m_hDC);
472    PIXELFORMATDESCRIPTOR pfd;
473
474    DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
475
476    if (pfd.dwFlags & PFD_NEED_PALETTE)
477    {
478    }
479    else
480    {
481      return;
482    }
483
484    m_palette = palette;
485
486    if ( !m_palette.Ok() )
487    {
488        m_palette = CreateDefaultPalette();
489    }
490
491    if (m_palette.Ok())
492    {
493        ::SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE);
494        ::RealizePalette((HDC) m_hDC);
495    }
496}
497
498wxPalette wxGLCanvas::CreateDefaultPalette()
499{
500    PIXELFORMATDESCRIPTOR pfd;
501    int paletteSize;
502    int pixelFormat = GetPixelFormat((HDC) m_hDC);
503
504    DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
505
506    paletteSize = 1 << pfd.cColorBits;
507
508    LOGPALETTE* pPal =
509     (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
510    pPal->palVersion = 0x300;
511    pPal->palNumEntries = (WORD)paletteSize;
512
513    /* build a simple RGB color palette */
514    {
515    int redMask = (1 << pfd.cRedBits) - 1;
516    int greenMask = (1 << pfd.cGreenBits) - 1;
517    int blueMask = (1 << pfd.cBlueBits) - 1;
518    int i;
519
520    for (i=0; i<paletteSize; ++i) {
521        pPal->palPalEntry[i].peRed =
522            (BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask);
523        pPal->palPalEntry[i].peGreen =
524            (BYTE)((((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask);
525        pPal->palPalEntry[i].peBlue =
526            (BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask);
527        pPal->palPalEntry[i].peFlags = 0;
528    }
529    }
530
531    HPALETTE hPalette = CreatePalette(pPal);
532    free(pPal);
533
534    wxPalette palette;
535    palette.SetHPALETTE((WXHPALETTE) hPalette);
536
537    return palette;
538}
539
540void wxGLCanvas::SwapBuffers()
541{
542    ::SwapBuffers((HDC) m_hDC);
543}
544
545void wxGLCanvas::OnSize(wxSizeEvent& WXUNUSED(event))
546{
547}
548
549void wxGLCanvas::SetCurrent(const wxGLContext& RC) const
550{
551    // although on MSW it works even if the window is still hidden, it doesn't
552  	// under wxGTK and documentation mentions that SetCurrent() can only be
553  	// called for a shown window, so check it
554  	wxASSERT_MSG( GetParent()->IsShown(), _T("can't make hidden GL canvas current") );
555
556    RC.SetCurrent(*this);
557}
558
559void wxGLCanvas::SetCurrent()
560{
561  // although on MSW it works even if the window is still hidden, it doesn't
562  // under wxGTK and documentation mentions that SetCurrent() can only be
563  // called for a shown window, so check it
564  wxASSERT_MSG( GetParent()->IsShown(),
565                    _T("can't make hidden GL canvas current") );
566
567  if (m_glContext)
568  {
569    m_glContext->SetCurrent(*this);
570  }
571}
572
573void wxGLCanvas::SetColour(const wxChar *colour)
574{
575    wxColour col = wxTheColourDatabase->Find(colour);
576
577    if (col.Ok())
578    {
579        float r = (float)(col.Red()/256.0);
580        float g = (float)(col.Green()/256.0);
581        float b = (float)(col.Blue()/256.0);
582        glColor3f( r, g, b);
583    }
584}
585
586// TODO: Have to have this called by parent frame (?)
587// So we need wxFrame to call OnQueryNewPalette for all children...
588void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
589{
590  /* realize palette if this is the current window */
591  if ( GetPalette()->Ok() ) {
592    ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
593    ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
594    ::RealizePalette((HDC) GetHDC());
595    Refresh();
596    event.SetPaletteRealized(true);
597  }
598  else
599    event.SetPaletteRealized(false);
600}
601
602// I think this doesn't have to be propagated to child windows.
603void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
604{
605  /* realize palette if this is *not* the current window */
606  if ( GetPalette() &&
607       GetPalette()->Ok() && (this != event.GetChangedWindow()) )
608  {
609    ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
610    ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
611    ::RealizePalette((HDC) GetHDC());
612    Refresh();
613  }
614}
615
616
617//---------------------------------------------------------------------------
618// wxGLApp
619//---------------------------------------------------------------------------
620
621IMPLEMENT_CLASS(wxGLApp, wxApp)
622
623bool wxGLApp::InitGLVisual(int *attribList)
624{
625  int pixelFormat;
626  PIXELFORMATDESCRIPTOR pfd = {
627        sizeof(PIXELFORMATDESCRIPTOR),    /* size */
628        1,                /* version */
629        PFD_SUPPORT_OPENGL |
630        PFD_DRAW_TO_WINDOW |
631        PFD_DOUBLEBUFFER,        /* support double-buffering */
632        PFD_TYPE_RGBA,            /* color type */
633        16,                /* preferred color depth */
634        0, 0, 0, 0, 0, 0,        /* color bits (ignored) */
635        0,                /* no alpha buffer */
636        0,                /* alpha bits (ignored) */
637        0,                /* no accumulation buffer */
638        0, 0, 0, 0,            /* accum bits (ignored) */
639        16,                /* depth buffer */
640        0,                /* no stencil buffer */
641        0,                /* no auxiliary buffers */
642        PFD_MAIN_PLANE,            /* main layer */
643        0,                /* reserved */
644        0, 0, 0,            /* no layer, visible, damage masks */
645    };
646
647  AdjustPFDForAttributes(pfd, attribList);
648
649  // use DC for whole (root) screen, since no windows have yet been created
650  pixelFormat = ChoosePixelFormat(ScreenHDC(), &pfd);
651
652  if (pixelFormat == 0) {
653    wxLogError(_("Failed to initialize OpenGL"));
654    return false;
655  }
656
657  return true;
658}
659
660wxGLApp::~wxGLApp()
661{
662}
663
664#endif
665    // wxUSE_GLCANVAS
666