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