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