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