added multisampling (anti-aliasing) support to wxGLCanvas (#9145)
[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 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #if defined(__BORLANDC__)
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_GLCANVAS
27
28 #ifndef WX_PRECOMP
29 #include "wx/intl.h"
30 #include "wx/log.h"
31 #include "wx/app.h"
32 #include "wx/module.h"
33 #endif
34
35 #include "wx/msw/private.h"
36
37 #include "wx/glcanvas.h"
38
39 // from src/msw/window.cpp
40 LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
41 WPARAM wParam, LPARAM lParam);
42
43 #ifdef GL_EXT_vertex_array
44 #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) name
45 #else
46 #define WXUNUSED_WITHOUT_GL_EXT_vertex_array(name) WXUNUSED(name)
47 #endif
48
49 // ----------------------------------------------------------------------------
50 // define possibly missing WGL constants
51 // ----------------------------------------------------------------------------
52
53 #ifndef WGL_ARB_pixel_format
54 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
55 #define WGL_DRAW_TO_WINDOW_ARB 0x2001
56 #define WGL_DRAW_TO_BITMAP_ARB 0x2002
57 #define WGL_ACCELERATION_ARB 0x2003
58 #define WGL_NEED_PALETTE_ARB 0x2004
59 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
60 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
61 #define WGL_SWAP_METHOD_ARB 0x2007
62 #define WGL_NUMBER_OVERLAYS_ARB 0x2008
63 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009
64 #define WGL_TRANSPARENT_ARB 0x200A
65 #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
66 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
67 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
68 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
69 #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
70 #define WGL_SHARE_DEPTH_ARB 0x200C
71 #define WGL_SHARE_STENCIL_ARB 0x200D
72 #define WGL_SHARE_ACCUM_ARB 0x200E
73 #define WGL_SUPPORT_GDI_ARB 0x200F
74 #define WGL_SUPPORT_OPENGL_ARB 0x2010
75 #define WGL_DOUBLE_BUFFER_ARB 0x2011
76 #define WGL_STEREO_ARB 0x2012
77 #define WGL_PIXEL_TYPE_ARB 0x2013
78 #define WGL_COLOR_BITS_ARB 0x2014
79 #define WGL_RED_BITS_ARB 0x2015
80 #define WGL_RED_SHIFT_ARB 0x2016
81 #define WGL_GREEN_BITS_ARB 0x2017
82 #define WGL_GREEN_SHIFT_ARB 0x2018
83 #define WGL_BLUE_BITS_ARB 0x2019
84 #define WGL_BLUE_SHIFT_ARB 0x201A
85 #define WGL_ALPHA_BITS_ARB 0x201B
86 #define WGL_ALPHA_SHIFT_ARB 0x201C
87 #define WGL_ACCUM_BITS_ARB 0x201D
88 #define WGL_ACCUM_RED_BITS_ARB 0x201E
89 #define WGL_ACCUM_GREEN_BITS_ARB 0x201F
90 #define WGL_ACCUM_BLUE_BITS_ARB 0x2020
91 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
92 #define WGL_DEPTH_BITS_ARB 0x2022
93 #define WGL_STENCIL_BITS_ARB 0x2023
94 #define WGL_AUX_BUFFERS_ARB 0x2024
95 #define WGL_NO_ACCELERATION_ARB 0x2025
96 #define WGL_GENERIC_ACCELERATION_ARB 0x2026
97 #define WGL_FULL_ACCELERATION_ARB 0x2027
98 #define WGL_SWAP_EXCHANGE_ARB 0x2028
99 #define WGL_SWAP_COPY_ARB 0x2029
100 #define WGL_SWAP_UNDEFINED_ARB 0x202A
101 #define WGL_TYPE_RGBA_ARB 0x202B
102 #define WGL_TYPE_COLORINDEX_ARB 0x202C
103 #endif
104
105 #ifndef WGL_ARB_multisample
106 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
107 #define WGL_SAMPLES_ARB 0x2042
108 #endif
109
110 // ----------------------------------------------------------------------------
111 // libraries
112 // ----------------------------------------------------------------------------
113
114 /*
115 The following two compiler directives are specific to the Microsoft Visual
116 C++ family of compilers
117
118 Fundementally what they do is instruct the linker to use these two libraries
119 for the resolution of symbols. In essence, this is the equivalent of adding
120 these two libraries to either the Makefile or project file.
121
122 This is NOT a recommended technique, and certainly is unlikely to be used
123 anywhere else in wxWidgets given it is so specific to not only wxMSW, but
124 also the VC compiler. However, in the case of opengl support, it's an
125 applicable technique as opengl is optional in setup.h This code (wrapped by
126 wxUSE_GLCANVAS), now allows opengl support to be added purely by modifying
127 setup.h rather than by having to modify either the project or DSP fle.
128
129 See MSDN for further information on the exact usage of these commands.
130 */
131 #ifdef _MSC_VER
132 # pragma comment( lib, "opengl32" )
133 # pragma comment( lib, "glu32" )
134 #endif
135
136 // ----------------------------------------------------------------------------
137 // constants
138 // ----------------------------------------------------------------------------
139
140 static const wxChar *wxGLCanvasClassName = wxT("wxGLCanvasClass");
141 static const wxChar *wxGLCanvasClassNameNoRedraw = wxT("wxGLCanvasClassNR");
142
143 // ============================================================================
144 // implementation
145 // ============================================================================
146
147 // ----------------------------------------------------------------------------
148 // wxGLModule is responsible for unregistering wxGLCanvasClass Windows class
149 // ----------------------------------------------------------------------------
150
151 class wxGLModule : public wxModule
152 {
153 public:
154 bool OnInit() { return true; }
155 void OnExit() { UnregisterClasses(); }
156
157 // register the GL classes if not done yet, return true if ok, false if
158 // registration failed
159 static bool RegisterClasses();
160
161 // unregister the classes, done automatically on program termination
162 static void UnregisterClasses();
163
164 private:
165 // wxGLCanvas is only used from the main thread so this is MT-ok
166 static bool ms_registeredGLClasses;
167
168 DECLARE_DYNAMIC_CLASS(wxGLModule)
169 };
170
171 IMPLEMENT_DYNAMIC_CLASS(wxGLModule, wxModule)
172
173 bool wxGLModule::ms_registeredGLClasses = false;
174
175 /* static */
176 bool wxGLModule::RegisterClasses()
177 {
178 if ( ms_registeredGLClasses )
179 return true;
180
181 // We have to register a special window class because we need the CS_OWNDC
182 // style for GLCanvas: some OpenGL drivers are buggy and don't work with
183 // windows without this style
184 WNDCLASS wndclass;
185
186 // the fields which are common to all classes
187 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
188 wndclass.cbClsExtra = 0;
189 wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for?
190 wndclass.hInstance = wxhInstance;
191 wndclass.hIcon = (HICON) NULL;
192 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
193 wndclass.lpszMenuName = NULL;
194
195 // Register the GLCanvas class name
196 wndclass.hbrBackground = (HBRUSH)NULL;
197 wndclass.lpszClassName = wxGLCanvasClassName;
198 wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
199
200 if ( !::RegisterClass(&wndclass) )
201 {
202 wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
203 return false;
204 }
205
206 // Register the GLCanvas class name for windows which don't do full repaint
207 // on resize
208 wndclass.lpszClassName = wxGLCanvasClassNameNoRedraw;
209 wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
210
211 if ( !::RegisterClass(&wndclass) )
212 {
213 wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
214
215 ::UnregisterClass(wxGLCanvasClassName, wxhInstance);
216
217 return false;
218 }
219
220 ms_registeredGLClasses = true;
221
222 return true;
223 }
224
225 /* static */
226 void wxGLModule::UnregisterClasses()
227 {
228 // we need to unregister the classes in case we're in a DLL which is
229 // unloaded and then loaded again because if we don't, the registration is
230 // going to fail in wxGLCanvas::Create() the next time we're loaded
231 if ( ms_registeredGLClasses )
232 {
233 ::UnregisterClass(wxGLCanvasClassName, wxhInstance);
234 ::UnregisterClass(wxGLCanvasClassNameNoRedraw, wxhInstance);
235
236 ms_registeredGLClasses = false;
237 }
238 }
239
240 // ----------------------------------------------------------------------------
241 // wxGLContext
242 // ----------------------------------------------------------------------------
243
244 IMPLEMENT_CLASS(wxGLContext, wxObject)
245
246 wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext* other)
247 {
248 m_glContext = wglCreateContext(win->GetHDC());
249 wxCHECK_RET( m_glContext, wxT("Couldn't create OpenGL context") );
250
251 if ( other )
252 {
253 if ( !wglShareLists(other->m_glContext, m_glContext) )
254 wxLogLastError(_T("wglShareLists"));
255 }
256 }
257
258 wxGLContext::~wxGLContext()
259 {
260 // note that it's ok to delete the context even if it's the current one
261 wglDeleteContext(m_glContext);
262 }
263
264 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
265 {
266 if ( !wglMakeCurrent(win.GetHDC(), m_glContext) )
267 {
268 wxLogLastError(_T("wglMakeCurrent"));
269 return false;
270 }
271 return true;
272 }
273
274 // ============================================================================
275 // wxGLCanvas
276 // ============================================================================
277
278 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
279
280 BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
281 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
282 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
283 END_EVENT_TABLE()
284
285 // ----------------------------------------------------------------------------
286 // wxGLCanvas construction
287 // ----------------------------------------------------------------------------
288
289 void wxGLCanvas::Init()
290 {
291 #if WXWIN_COMPATIBILITY_2_8
292 m_glContext = NULL;
293 #endif
294 m_hDC = NULL;
295 }
296
297 wxGLCanvas::wxGLCanvas(wxWindow *parent,
298 wxWindowID id,
299 const int *attribList,
300 const wxPoint& pos,
301 const wxSize& size,
302 long style,
303 const wxString& name,
304 const wxPalette& palette)
305 {
306 Init();
307
308 (void)Create(parent, id, pos, size, style, name, attribList, palette);
309 }
310
311 wxGLCanvas::~wxGLCanvas()
312 {
313 ::ReleaseDC(GetHwnd(), m_hDC);
314 }
315
316 // Replaces wxWindow::Create functionality, since we need to use a different
317 // window class
318 bool wxGLCanvas::Create(wxWindow *parent,
319 wxWindowID id,
320 const wxPoint& pos,
321 const wxSize& size,
322 long style,
323 const wxString& name,
324 const int *attribList,
325 const wxPalette& palette)
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 /*
342 A general rule with OpenGL and Win32 is that any window that will have a
343 HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
344 You can find references about this within the knowledge base and most OpenGL
345 books that contain the wgl function descriptions.
346 */
347 WXDWORD exStyle = 0;
348 DWORD msflags = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
349 msflags |= MSWGetStyle(style, &exStyle);
350
351 if ( !MSWCreate(wxGLCanvasClassName, NULL, pos, size, msflags, exStyle) )
352 return false;
353
354 m_hDC = ::GetDC(GetHwnd());
355 if ( !m_hDC )
356 return false;
357
358 if ( !DoSetup(attribList) )
359 return false;
360
361 #if wxUSE_PALETTE
362 if ( !SetupPalette(palette) )
363 return false;
364 #else // !wxUSE_PALETTE
365 wxUnusedVar(palette);
366 #endif // wxUSE_PALETTE/!wxUSE_PALETTE
367
368 return true;
369 }
370
371 // ----------------------------------------------------------------------------
372 // operations
373 // ----------------------------------------------------------------------------
374
375 bool wxGLCanvas::SwapBuffers()
376 {
377 if ( !::SwapBuffers(m_hDC) )
378 {
379 wxLogLastError(_T("SwapBuffers"));
380 return false;
381 }
382
383 return true;
384 }
385
386
387 // ----------------------------------------------------------------------------
388 // multi sample support
389 // ----------------------------------------------------------------------------
390
391 // this macro defines a variable of type "name_t" called "name" and initializes
392 // it with the pointer to WGL function "name" (which may be NULL)
393 #define wxDEFINE_WGL_FUNC(name) \
394 name##_t name = (name##_t)wglGetProcAddress(#name)
395
396 /* static */
397 bool wxGLCanvasBase::IsExtensionSupported(const char *extension)
398 {
399 static const char *s_extensionsList = (char *)wxUIntPtr(-1);
400 if ( s_extensionsList == (char *)wxUIntPtr(-1) )
401 {
402 typedef const char * (WINAPI *wglGetExtensionsStringARB_t)(HDC hdc);
403
404 wxDEFINE_WGL_FUNC(wglGetExtensionsStringARB);
405 if ( wglGetExtensionsStringARB )
406 {
407 s_extensionsList = wglGetExtensionsStringARB(wglGetCurrentDC());
408 }
409 else
410 {
411 typedef const char * (WINAPI * wglGetExtensionsStringEXT_t)();
412
413 wxDEFINE_WGL_FUNC(wglGetExtensionsStringEXT);
414 if ( wglGetExtensionsStringEXT )
415 {
416 s_extensionsList = wglGetExtensionsStringEXT();
417 }
418 else
419 {
420 s_extensionsList = NULL;
421 }
422 }
423 }
424
425 return s_extensionsList && IsExtensionInList(s_extensionsList, extension);
426 }
427
428 // this is a wrapper around wglChoosePixelFormatARB(): returns the pixel format
429 // index matching the given attributes on success or 0 on failure
430 static int ChoosePixelFormatARB(HDC hdc, const int *attribList)
431 {
432 if ( !wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample") )
433 return 0;
434
435 typedef BOOL (WINAPI * wglChoosePixelFormatARB_t)
436 (HDC hdc,
437 const int *piAttribIList,
438 const FLOAT *pfAttribFList,
439 UINT nMaxFormats,
440 int *piFormats,
441 UINT *nNumFormats
442 );
443
444 wxDEFINE_WGL_FUNC(wglChoosePixelFormatARB);
445 if ( !wglChoosePixelFormatARB )
446 return 0; // should not occur if extension is supported
447
448 int iAttributes[128];
449 int dst = 0; // index in iAttributes array
450
451 #define ADD_ATTR(attr, value) \
452 iAttributes[dst++] = attr; iAttributes[dst++] = value
453
454 ADD_ATTR( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE );
455 ADD_ATTR( WGL_SUPPORT_OPENGL_ARB, GL_TRUE );
456 ADD_ATTR( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB );
457
458 if ( !attribList )
459 {
460 ADD_ATTR( WGL_COLOR_BITS_ARB, 24 );
461 ADD_ATTR( WGL_ALPHA_BITS_ARB, 8 );
462 ADD_ATTR( WGL_DEPTH_BITS_ARB, 16 );
463 ADD_ATTR( WGL_STENCIL_BITS_ARB, 0 );
464 ADD_ATTR( WGL_DOUBLE_BUFFER_ARB, GL_TRUE );
465 ADD_ATTR( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE );
466 ADD_ATTR( WGL_SAMPLES_ARB, 4 );
467 }
468 else // have custom attributes
469 {
470 #define ADD_ATTR_VALUE(attr) ADD_ATTR(attr, attribList[src++])
471
472 int src = 0;
473 while ( attribList[src] )
474 {
475 switch ( attribList[src++] )
476 {
477 case WX_GL_RGBA:
478 ADD_ATTR( WGL_COLOR_BITS_ARB, 24 );
479 ADD_ATTR( WGL_ALPHA_BITS_ARB, 8 );
480 break;
481
482 case WX_GL_BUFFER_SIZE:
483 ADD_ATTR_VALUE( WGL_COLOR_BITS_ARB);
484 break;
485
486 case WX_GL_LEVEL:
487 if ( attribList[src] > 0 )
488 {
489 ADD_ATTR( WGL_NUMBER_OVERLAYS_ARB, 1 );
490 }
491 else if ( attribList[src] <0 )
492 {
493 ADD_ATTR( WGL_NUMBER_UNDERLAYS_ARB, 1 );
494 }
495 //else: ignore it
496
497 src++; // skip the value in any case
498 break;
499
500 case WX_GL_DOUBLEBUFFER:
501 ADD_ATTR( WGL_DOUBLE_BUFFER_ARB, GL_TRUE );
502 break;
503
504 case WX_GL_STEREO:
505 ADD_ATTR( WGL_STEREO_ARB, GL_TRUE );
506 break;
507
508 case WX_GL_AUX_BUFFERS:
509 ADD_ATTR_VALUE( WGL_AUX_BUFFERS_ARB );
510 break;
511
512 case WX_GL_MIN_RED:
513 ADD_ATTR_VALUE( WGL_RED_BITS_ARB );
514 break;
515
516 case WX_GL_MIN_GREEN:
517 ADD_ATTR_VALUE( WGL_GREEN_BITS_ARB );
518 break;
519
520 case WX_GL_MIN_BLUE:
521 ADD_ATTR_VALUE( WGL_BLUE_BITS_ARB );
522 break;
523
524 case WX_GL_MIN_ALPHA:
525 ADD_ATTR_VALUE( WGL_ALPHA_BITS_ARB );
526 break;
527
528 case WX_GL_DEPTH_SIZE:
529 ADD_ATTR_VALUE( WGL_DEPTH_BITS_ARB );
530 break;
531
532 case WX_GL_STENCIL_SIZE:
533 ADD_ATTR_VALUE( WGL_STENCIL_BITS_ARB );
534 break;
535
536 case WX_GL_MIN_ACCUM_RED:
537 ADD_ATTR_VALUE( WGL_ACCUM_RED_BITS_ARB );
538 break;
539
540 case WX_GL_MIN_ACCUM_GREEN:
541 ADD_ATTR_VALUE( WGL_ACCUM_GREEN_BITS_ARB );
542 break;
543
544 case WX_GL_MIN_ACCUM_BLUE:
545 ADD_ATTR_VALUE( WGL_ACCUM_BLUE_BITS_ARB );
546 break;
547
548 case WX_GL_MIN_ACCUM_ALPHA:
549 ADD_ATTR_VALUE( WGL_ACCUM_ALPHA_BITS_ARB );
550 break;
551
552 case WX_GL_SAMPLE_BUFFERS:
553 ADD_ATTR_VALUE( WGL_SAMPLE_BUFFERS_ARB );
554 break;
555
556 case WX_GL_SAMPLES:
557 ADD_ATTR_VALUE( WGL_SAMPLES_ARB );
558 break;
559 }
560 }
561
562 #undef ADD_ATTR_VALUE
563 }
564
565 #undef ADD_ATTR
566
567 iAttributes[dst++] = 0;
568
569 int pf;
570 UINT numFormats = 0;
571 if ( !wglChoosePixelFormatARB(hdc, iAttributes, NULL, 1, &pf, &numFormats) )
572 {
573 wxLogLastError(_T("wglChoosePixelFormatARB"));
574 return 0;
575 }
576
577 return pf;
578 }
579
580 // ----------------------------------------------------------------------------
581 // pixel format stuff
582 // ----------------------------------------------------------------------------
583
584 // returns true if pfd was adjusted accordingly to attributes provided, false
585 // if there is an error with attributes or -1 if the attributes indicate
586 // features not supported by ChoosePixelFormat() at all (currently only multi
587 // sampling)
588 static int
589 AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int *attribList)
590 {
591 if ( !attribList )
592 return 1;
593
594 // remove default attributes
595 pfd.dwFlags &= ~PFD_DOUBLEBUFFER;
596 pfd.iPixelType = PFD_TYPE_COLORINDEX;
597
598 for ( int arg = 0; attribList[arg]; )
599 {
600 switch ( attribList[arg++] )
601 {
602 case WX_GL_RGBA:
603 pfd.iPixelType = PFD_TYPE_RGBA;
604 break;
605
606 case WX_GL_BUFFER_SIZE:
607 pfd.cColorBits = attribList[arg++];
608 break;
609
610 case WX_GL_LEVEL:
611 // this member looks like it may be obsolete
612 if ( attribList[arg] > 0 )
613 pfd.iLayerType = PFD_OVERLAY_PLANE;
614 else if ( attribList[arg] < 0 )
615 pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE;
616 else
617 pfd.iLayerType = PFD_MAIN_PLANE;
618 arg++;
619 break;
620
621 case WX_GL_DOUBLEBUFFER:
622 pfd.dwFlags |= PFD_DOUBLEBUFFER;
623 break;
624
625 case WX_GL_STEREO:
626 pfd.dwFlags |= PFD_STEREO;
627 break;
628
629 case WX_GL_AUX_BUFFERS:
630 pfd.cAuxBuffers = attribList[arg++];
631 break;
632
633 case WX_GL_MIN_RED:
634 pfd.cColorBits += (pfd.cRedBits = attribList[arg++]);
635 break;
636
637 case WX_GL_MIN_GREEN:
638 pfd.cColorBits += (pfd.cGreenBits = attribList[arg++]);
639 break;
640
641 case WX_GL_MIN_BLUE:
642 pfd.cColorBits += (pfd.cBlueBits = attribList[arg++]);
643 break;
644
645 case WX_GL_MIN_ALPHA:
646 // doesn't count in cColorBits
647 pfd.cAlphaBits = attribList[arg++];
648 break;
649
650 case WX_GL_DEPTH_SIZE:
651 pfd.cDepthBits = attribList[arg++];
652 break;
653
654 case WX_GL_STENCIL_SIZE:
655 pfd.cStencilBits = attribList[arg++];
656 break;
657
658 case WX_GL_MIN_ACCUM_RED:
659 pfd.cAccumBits += (pfd.cAccumRedBits = attribList[arg++]);
660 break;
661
662 case WX_GL_MIN_ACCUM_GREEN:
663 pfd.cAccumBits += (pfd.cAccumGreenBits = attribList[arg++]);
664 break;
665
666 case WX_GL_MIN_ACCUM_BLUE:
667 pfd.cAccumBits += (pfd.cAccumBlueBits = attribList[arg++]);
668 break;
669
670 case WX_GL_MIN_ACCUM_ALPHA:
671 pfd.cAccumBits += (pfd.cAccumAlphaBits = attribList[arg++]);
672 break;
673
674 case WX_GL_SAMPLE_BUFFERS:
675 case WX_GL_SAMPLES:
676 return -1;
677 }
678 }
679
680 return 1;
681 }
682
683 /* static */
684 int
685 wxGLCanvas::ChooseMatchingPixelFormat(HDC hdc,
686 const int *attribList,
687 PIXELFORMATDESCRIPTOR *ppfd)
688 {
689 // default neutral pixel format
690 PIXELFORMATDESCRIPTOR pfd =
691 {
692 sizeof(PIXELFORMATDESCRIPTOR), // size
693 1, // version
694 PFD_SUPPORT_OPENGL |
695 PFD_DRAW_TO_WINDOW |
696 PFD_DOUBLEBUFFER, // use double-buffering by default
697 PFD_TYPE_RGBA, // default pixel type
698 0, // preferred color depth (don't care)
699 0, 0, 0, 0, 0, 0, // color bits and shift bits (ignored)
700 0, 0, // alpha bits and shift (ignored)
701 0, // accumulation total bits
702 0, 0, 0, 0, // accumulator RGBA bits (not used)
703 16, // depth buffer
704 0, // no stencil buffer
705 0, // no auxiliary buffers
706 PFD_MAIN_PLANE, // main layer
707 0, // reserved
708 0, 0, 0, // no layer, visible, damage masks
709 };
710
711 if ( !ppfd )
712 ppfd = &pfd;
713 else
714 *ppfd = pfd;
715
716 // adjust the PFD using the provided attributes and also check if we can
717 // use PIXELFORMATDESCRIPTOR at all: if multisampling is requested, we
718 // can't as it's not supported by ChoosePixelFormat()
719 switch ( AdjustPFDForAttributes(*ppfd, attribList) )
720 {
721 case 1:
722 return ::ChoosePixelFormat(hdc, ppfd);
723
724 default:
725 wxFAIL_MSG( "unexpected AdjustPFDForAttributes() return value" );
726 // fall through
727
728 case 0:
729 // error in attributes
730 return 0;
731
732 case -1:
733 return ::ChoosePixelFormatARB(hdc, attribList);
734 }
735 }
736
737 /* static */
738 bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
739 {
740 // We need a device context to test the pixel format, so get one
741 // for the root window.
742 return wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) > 0;
743 }
744
745 bool wxGLCanvas::DoSetup(const int *attribList)
746 {
747 PIXELFORMATDESCRIPTOR pfd;
748 const int pixelFormat = ChooseMatchingPixelFormat(m_hDC, attribList, &pfd);
749 if ( !pixelFormat )
750 {
751 wxLogLastError(_T("ChoosePixelFormat"));
752 return false;
753 }
754
755 if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) )
756 {
757 wxLogLastError(_T("SetPixelFormat"));
758 return false;
759 }
760
761 return true;
762 }
763
764 // ----------------------------------------------------------------------------
765 // palette stuff
766 // ----------------------------------------------------------------------------
767
768 #if wxUSE_PALETTE
769
770 bool wxGLCanvas::SetupPalette(const wxPalette& palette)
771 {
772 const int pixelFormat = ::GetPixelFormat(m_hDC);
773 if ( !pixelFormat )
774 {
775 wxLogLastError(_T("GetPixelFormat"));
776 return false;
777 }
778
779 PIXELFORMATDESCRIPTOR pfd;
780 if ( !::DescribePixelFormat(m_hDC, pixelFormat, sizeof(pfd), &pfd) )
781 {
782 wxLogLastError(_T("DescribePixelFormat"));
783 return false;
784 }
785
786 if ( !(pfd.dwFlags & PFD_NEED_PALETTE) )
787 return true;
788
789 m_palette = palette;
790
791 if ( !m_palette.Ok() )
792 {
793 m_palette = CreateDefaultPalette();
794 if ( !m_palette.Ok() )
795 return false;
796 }
797
798 if ( !::SelectPalette(m_hDC, GetHpaletteOf(m_palette), FALSE) )
799 {
800 wxLogLastError(_T("SelectPalette"));
801 return false;
802 }
803
804 if ( ::RealizePalette(m_hDC) == GDI_ERROR )
805 {
806 wxLogLastError(_T("RealizePalette"));
807 return false;
808 }
809
810 return true;
811 }
812
813 wxPalette wxGLCanvas::CreateDefaultPalette()
814 {
815 PIXELFORMATDESCRIPTOR pfd;
816 int paletteSize;
817 int pixelFormat = GetPixelFormat(m_hDC);
818
819 DescribePixelFormat(m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
820
821 paletteSize = 1 << pfd.cColorBits;
822
823 LOGPALETTE* pPal =
824 (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
825 pPal->palVersion = 0x300;
826 pPal->palNumEntries = (WORD)paletteSize;
827
828 /* build a simple RGB color palette */
829 int redMask = (1 << pfd.cRedBits) - 1;
830 int greenMask = (1 << pfd.cGreenBits) - 1;
831 int blueMask = (1 << pfd.cBlueBits) - 1;
832
833 for (int i=0; i<paletteSize; ++i)
834 {
835 pPal->palPalEntry[i].peRed =
836 (BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask);
837 pPal->palPalEntry[i].peGreen =
838 (BYTE)((((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask);
839 pPal->palPalEntry[i].peBlue =
840 (BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask);
841 pPal->palPalEntry[i].peFlags = 0;
842 }
843
844 HPALETTE hPalette = CreatePalette(pPal);
845 free(pPal);
846
847 wxPalette palette;
848 palette.SetHPALETTE((WXHPALETTE) hPalette);
849
850 return palette;
851 }
852
853 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
854 {
855 /* realize palette if this is the current window */
856 if ( GetPalette()->Ok() ) {
857 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
858 ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
859 ::RealizePalette(GetHDC());
860 Refresh();
861 event.SetPaletteRealized(true);
862 }
863 else
864 event.SetPaletteRealized(false);
865 }
866
867 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
868 {
869 /* realize palette if this is *not* the current window */
870 if ( GetPalette() &&
871 GetPalette()->Ok() && (this != event.GetChangedWindow()) )
872 {
873 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
874 ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
875 ::RealizePalette(GetHDC());
876 Refresh();
877 }
878 }
879
880 #endif // wxUSE_PALETTE
881
882 // ----------------------------------------------------------------------------
883 // deprecated wxGLCanvas methods using implicit wxGLContext
884 // ----------------------------------------------------------------------------
885
886 // deprecated constructors creating an implicit m_glContext
887 #if WXWIN_COMPATIBILITY_2_8
888
889 wxGLCanvas::wxGLCanvas(wxWindow *parent,
890 wxWindowID id,
891 const wxPoint& pos,
892 const wxSize& size,
893 long style,
894 const wxString& name,
895 const int *attribList,
896 const wxPalette& palette)
897 {
898 Init();
899
900 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
901 m_glContext = new wxGLContext(this);
902 }
903
904 wxGLCanvas::wxGLCanvas(wxWindow *parent,
905 const wxGLContext *shared,
906 wxWindowID id,
907 const wxPoint& pos,
908 const wxSize& size,
909 long style,
910 const wxString& name,
911 const int *attribList,
912 const wxPalette& palette)
913 {
914 Init();
915
916 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
917 m_glContext = new wxGLContext(this, shared);
918 }
919
920 wxGLCanvas::wxGLCanvas(wxWindow *parent,
921 const wxGLCanvas *shared,
922 wxWindowID id,
923 const wxPoint& pos,
924 const wxSize& size,
925 long style,
926 const wxString& name,
927 const int *attribList,
928 const wxPalette& palette)
929 {
930 Init();
931
932 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
933 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
934 }
935
936 #endif // WXWIN_COMPATIBILITY_2_8
937
938
939 // ----------------------------------------------------------------------------
940 // wxGLApp
941 // ----------------------------------------------------------------------------
942
943 bool wxGLApp::InitGLVisual(const int *attribList)
944 {
945 if ( !wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) )
946 {
947 wxLogError(_("Failed to initialize OpenGL"));
948 return false;
949 }
950
951 return true;
952 }
953
954 #endif // wxUSE_GLCANVAS