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