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