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