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