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