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