Commit Carsten Fuchs' patch for separating wxGLCanvas
[wxWidgets.git] / src / msw / glcanvas.cpp
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$
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"
33 WX_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
66 static const wxChar *wxGLCanvasClassName = wxT("wxGLCanvasClass");
67 static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR");
68
69 LRESULT 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
76 class wxGLModule : public wxModule
77 {
78 public:
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
89 private:
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
96 IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule)
97
98 bool wxGLModule::ms_registeredGLClasses = false;
99
100 /* static */
101 bool 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 */
168 void 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
186 IMPLEMENT_CLASS(wxGLContext, wxObject)
187
188 wxGLContext::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
197 wxGLContext::~wxGLContext()
198 {
199 // If this context happens to be the current context, wglDeleteContext() makes it un-current first.
200 wglDeleteContext(m_glContext);
201 }
202
203 void wxGLContext::SetCurrent(const wxGLCanvas& win) const
204 {
205 wglMakeCurrent((HDC) win.GetHDC(), m_glContext);
206 }
207
208
209 /*
210 * wxGLCanvas implementation
211 */
212
213 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
214
215 BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
216 EVT_SIZE(wxGLCanvas::OnSize)
217 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
218 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
219 END_EVENT_TABLE()
220
221 wxGLCanvas::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
241 wxGLCanvas::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
262 wxGLCanvas::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
287 wxGLCanvas::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
311 wxGLCanvas::~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
320 bool 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
357 static 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
433 void 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
469 void 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
498 wxPalette 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
540 void wxGLCanvas::SwapBuffers()
541 {
542 ::SwapBuffers((HDC) m_hDC);
543 }
544
545 void wxGLCanvas::OnSize(wxSizeEvent& WXUNUSED(event))
546 {
547 }
548
549 void 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
559 void 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
573 void 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...
588 void 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.
603 void 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
621 IMPLEMENT_CLASS(wxGLApp, wxApp)
622
623 bool 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
660 wxGLApp::~wxGLApp()
661 {
662 }
663
664 #endif
665 // wxUSE_GLCANVAS