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