]> git.saurik.com Git - wxWidgets.git/blame - src/msw/glcanvas.cpp
More compilation fixes for new wxRTC image code without PCH.
[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;
af6da66c 496
c39d2e0a
VZ
497 if ( !wglChoosePixelFormatARB(hdc, iAttributes, NULL, 1, &pf, &numFormats) )
498 {
9a83f860 499 wxLogLastError(wxT("wglChoosePixelFormatARB"));
c39d2e0a
VZ
500 return 0;
501 }
502
af6da66c
VZ
503 // Although TRUE is returned if no matching formats are found (see
504 // http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt), pf is
505 // not initialized in this case so we need to check for numFormats being
506 // not 0 explicitly (however this is not an error so don't call
507 // wxLogLastError() here).
508 if ( !numFormats )
509 pf = 0;
510
c39d2e0a
VZ
511 return pf;
512}
513
dc3065a5
VZ
514// ----------------------------------------------------------------------------
515// pixel format stuff
516// ----------------------------------------------------------------------------
517
c39d2e0a
VZ
518// returns true if pfd was adjusted accordingly to attributes provided, false
519// if there is an error with attributes or -1 if the attributes indicate
520// features not supported by ChoosePixelFormat() at all (currently only multi
521// sampling)
522static int
dc3065a5 523AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR& pfd, const int *attribList)
8b089c5e 524{
dc3065a5 525 if ( !attribList )
c39d2e0a 526 return 1;
dc3065a5 527
4aa59c3d 528 // remove default attributes
f48d169c
UN
529 pfd.dwFlags &= ~PFD_DOUBLEBUFFER;
530 pfd.iPixelType = PFD_TYPE_COLORINDEX;
b225f659 531
82bf63a0 532 bool requestFSAA = false;
4aa59c3d 533 for ( int arg = 0; attribList[arg]; )
f48d169c 534 {
dc3065a5
VZ
535 switch ( attribList[arg++] )
536 {
537 case WX_GL_RGBA:
538 pfd.iPixelType = PFD_TYPE_RGBA;
539 break;
4aa59c3d 540
dc3065a5
VZ
541 case WX_GL_BUFFER_SIZE:
542 pfd.cColorBits = attribList[arg++];
543 break;
4aa59c3d 544
dc3065a5
VZ
545 case WX_GL_LEVEL:
546 // this member looks like it may be obsolete
547 if ( attribList[arg] > 0 )
548 pfd.iLayerType = PFD_OVERLAY_PLANE;
549 else if ( attribList[arg] < 0 )
550 pfd.iLayerType = (BYTE)PFD_UNDERLAY_PLANE;
551 else
552 pfd.iLayerType = PFD_MAIN_PLANE;
553 arg++;
554 break;
4aa59c3d 555
dc3065a5
VZ
556 case WX_GL_DOUBLEBUFFER:
557 pfd.dwFlags |= PFD_DOUBLEBUFFER;
558 break;
4aa59c3d 559
dc3065a5
VZ
560 case WX_GL_STEREO:
561 pfd.dwFlags |= PFD_STEREO;
562 break;
4aa59c3d 563
dc3065a5
VZ
564 case WX_GL_AUX_BUFFERS:
565 pfd.cAuxBuffers = attribList[arg++];
566 break;
4aa59c3d 567
dc3065a5 568 case WX_GL_MIN_RED:
4aa59c3d 569 pfd.cColorBits += (pfd.cRedBits = attribList[arg++]);
dc3065a5 570 break;
4aa59c3d 571
dc3065a5 572 case WX_GL_MIN_GREEN:
4aa59c3d 573 pfd.cColorBits += (pfd.cGreenBits = attribList[arg++]);
dc3065a5 574 break;
4aa59c3d 575
dc3065a5 576 case WX_GL_MIN_BLUE:
4aa59c3d 577 pfd.cColorBits += (pfd.cBlueBits = attribList[arg++]);
dc3065a5 578 break;
4aa59c3d 579
dc3065a5
VZ
580 case WX_GL_MIN_ALPHA:
581 // doesn't count in cColorBits
582 pfd.cAlphaBits = attribList[arg++];
583 break;
4aa59c3d 584
dc3065a5
VZ
585 case WX_GL_DEPTH_SIZE:
586 pfd.cDepthBits = attribList[arg++];
587 break;
4aa59c3d 588
dc3065a5
VZ
589 case WX_GL_STENCIL_SIZE:
590 pfd.cStencilBits = attribList[arg++];
591 break;
4aa59c3d 592
dc3065a5 593 case WX_GL_MIN_ACCUM_RED:
4aa59c3d 594 pfd.cAccumBits += (pfd.cAccumRedBits = attribList[arg++]);
dc3065a5 595 break;
4aa59c3d 596
dc3065a5 597 case WX_GL_MIN_ACCUM_GREEN:
4aa59c3d 598 pfd.cAccumBits += (pfd.cAccumGreenBits = attribList[arg++]);
dc3065a5 599 break;
4aa59c3d 600
dc3065a5 601 case WX_GL_MIN_ACCUM_BLUE:
4aa59c3d 602 pfd.cAccumBits += (pfd.cAccumBlueBits = attribList[arg++]);
dc3065a5 603 break;
4aa59c3d 604
dc3065a5 605 case WX_GL_MIN_ACCUM_ALPHA:
4aa59c3d 606 pfd.cAccumBits += (pfd.cAccumAlphaBits = attribList[arg++]);
dc3065a5 607 break;
c39d2e0a
VZ
608
609 case WX_GL_SAMPLE_BUFFERS:
610 case WX_GL_SAMPLES:
82bf63a0
VZ
611 // There is no support for multisample when using PIXELFORMATDESCRIPTOR
612 requestFSAA = true; // Remember that multi sample is requested.
613 arg++; // will call ChoosePixelFormatARB() later
614 break;
dc3065a5 615 }
8b089c5e 616 }
c39d2e0a 617
82bf63a0 618 return requestFSAA ? -1 : 1;
a3081354
VZ
619}
620
dc3065a5
VZ
621/* static */
622int
623wxGLCanvas::ChooseMatchingPixelFormat(HDC hdc,
624 const int *attribList,
625 PIXELFORMATDESCRIPTOR *ppfd)
a3081354 626{
dc3065a5
VZ
627 // default neutral pixel format
628 PIXELFORMATDESCRIPTOR pfd =
629 {
630 sizeof(PIXELFORMATDESCRIPTOR), // size
631 1, // version
b225f659
VZ
632 PFD_SUPPORT_OPENGL |
633 PFD_DRAW_TO_WINDOW |
4aa59c3d
VZ
634 PFD_DOUBLEBUFFER, // use double-buffering by default
635 PFD_TYPE_RGBA, // default pixel type
636 0, // preferred color depth (don't care)
637 0, 0, 0, 0, 0, 0, // color bits and shift bits (ignored)
638 0, 0, // alpha bits and shift (ignored)
639 0, // accumulation total bits
640 0, 0, 0, 0, // accumulator RGBA bits (not used)
dc3065a5
VZ
641 16, // depth buffer
642 0, // no stencil buffer
643 0, // no auxiliary buffers
644 PFD_MAIN_PLANE, // main layer
645 0, // reserved
646 0, 0, 0, // no layer, visible, damage masks
b225f659 647 };
a3081354 648
dc3065a5
VZ
649 if ( !ppfd )
650 ppfd = &pfd;
651 else
652 *ppfd = pfd;
a3081354 653
c39d2e0a
VZ
654 // adjust the PFD using the provided attributes and also check if we can
655 // use PIXELFORMATDESCRIPTOR at all: if multisampling is requested, we
656 // can't as it's not supported by ChoosePixelFormat()
657 switch ( AdjustPFDForAttributes(*ppfd, attribList) )
658 {
659 case 1:
660 return ::ChoosePixelFormat(hdc, ppfd);
661
662 default:
663 wxFAIL_MSG( "unexpected AdjustPFDForAttributes() return value" );
664 // fall through
dc3065a5 665
c39d2e0a
VZ
666 case 0:
667 // error in attributes
668 return 0;
669
670 case -1:
82bf63a0
VZ
671 // requestFSAA == true, will continue as normal
672 // in order to query later for a FSAA pixelformat
673 return -1;
c39d2e0a 674 }
8b089c5e
JS
675}
676
3f20f7d8
VZ
677/* static */
678bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
679{
680 // We need a device context to test the pixel format, so get one
681 // for the root window.
682 return wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) > 0;
683}
684
82bf63a0 685int wxGLCanvas::DoSetup(PIXELFORMATDESCRIPTOR &pfd, const int *attribList)
8b089c5e 686{
82bf63a0
VZ
687 int pixelFormat = ChooseMatchingPixelFormat(m_hDC, attribList, &pfd);
688
689 const bool requestFSAA = pixelFormat == -1;
690 if ( requestFSAA )
691 pixelFormat = ::ChoosePixelFormat(m_hDC, &pfd);
692
dc3065a5
VZ
693 if ( !pixelFormat )
694 {
9a83f860 695 wxLogLastError(wxT("ChoosePixelFormat"));
82bf63a0 696 return 0;
dc3065a5
VZ
697 }
698
699 if ( !::SetPixelFormat(m_hDC, pixelFormat, &pfd) )
700 {
9a83f860 701 wxLogLastError(wxT("SetPixelFormat"));
82bf63a0 702 return 0;
dc3065a5
VZ
703 }
704
82bf63a0 705 return requestFSAA ? -1 : 1;
dc3065a5
VZ
706}
707
708// ----------------------------------------------------------------------------
709// palette stuff
710// ----------------------------------------------------------------------------
8b089c5e 711
dc3065a5 712#if wxUSE_PALETTE
8b089c5e 713
dc3065a5
VZ
714bool wxGLCanvas::SetupPalette(const wxPalette& palette)
715{
716 const int pixelFormat = ::GetPixelFormat(m_hDC);
717 if ( !pixelFormat )
8b089c5e 718 {
9a83f860 719 wxLogLastError(wxT("GetPixelFormat"));
dc3065a5 720 return false;
8b089c5e 721 }
dc3065a5
VZ
722
723 PIXELFORMATDESCRIPTOR pfd;
724 if ( !::DescribePixelFormat(m_hDC, pixelFormat, sizeof(pfd), &pfd) )
8b089c5e 725 {
9a83f860 726 wxLogLastError(wxT("DescribePixelFormat"));
dc3065a5 727 return false;
8b089c5e
JS
728 }
729
dc3065a5
VZ
730 if ( !(pfd.dwFlags & PFD_NEED_PALETTE) )
731 return true;
732
8b089c5e
JS
733 m_palette = palette;
734
735 if ( !m_palette.Ok() )
736 {
737 m_palette = CreateDefaultPalette();
dc3065a5
VZ
738 if ( !m_palette.Ok() )
739 return false;
740 }
741
742 if ( !::SelectPalette(m_hDC, GetHpaletteOf(m_palette), FALSE) )
743 {
9a83f860 744 wxLogLastError(wxT("SelectPalette"));
dc3065a5 745 return false;
8b089c5e
JS
746 }
747
dc3065a5 748 if ( ::RealizePalette(m_hDC) == GDI_ERROR )
8b089c5e 749 {
9a83f860 750 wxLogLastError(wxT("RealizePalette"));
dc3065a5 751 return false;
8b089c5e 752 }
dc3065a5
VZ
753
754 return true;
8b089c5e
JS
755}
756
757wxPalette wxGLCanvas::CreateDefaultPalette()
758{
759 PIXELFORMATDESCRIPTOR pfd;
760 int paletteSize;
dc3065a5 761 int pixelFormat = GetPixelFormat(m_hDC);
8b089c5e 762
dc3065a5 763 DescribePixelFormat(m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
8b089c5e 764
f48d169c 765 paletteSize = 1 << pfd.cColorBits;
8b089c5e
JS
766
767 LOGPALETTE* pPal =
768 (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
769 pPal->palVersion = 0x300;
b8ee9a86 770 pPal->palNumEntries = (WORD)paletteSize;
8b089c5e
JS
771
772 /* build a simple RGB color palette */
b225f659
VZ
773 int redMask = (1 << pfd.cRedBits) - 1;
774 int greenMask = (1 << pfd.cGreenBits) - 1;
775 int blueMask = (1 << pfd.cBlueBits) - 1;
b225f659 776
c39d2e0a
VZ
777 for (int i=0; i<paletteSize; ++i)
778 {
b225f659 779 pPal->palPalEntry[i].peRed =
b8ee9a86 780 (BYTE)((((i >> pfd.cRedShift) & redMask) * 255) / redMask);
b225f659 781 pPal->palPalEntry[i].peGreen =
b8ee9a86 782 (BYTE)((((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask);
b225f659 783 pPal->palPalEntry[i].peBlue =
b8ee9a86 784 (BYTE)((((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask);
b225f659
VZ
785 pPal->palPalEntry[i].peFlags = 0;
786 }
8b089c5e
JS
787
788 HPALETTE hPalette = CreatePalette(pPal);
789 free(pPal);
790
791 wxPalette palette;
792 palette.SetHPALETTE((WXHPALETTE) hPalette);
793
794 return palette;
795}
796
8b089c5e
JS
797void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
798{
f48d169c
UN
799 /* realize palette if this is the current window */
800 if ( GetPalette()->Ok() ) {
801 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
dc3065a5
VZ
802 ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
803 ::RealizePalette(GetHDC());
f48d169c 804 Refresh();
213ceb3f 805 event.SetPaletteRealized(true);
f48d169c
UN
806 }
807 else
213ceb3f 808 event.SetPaletteRealized(false);
8b089c5e
JS
809}
810
8b089c5e
JS
811void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
812{
f48d169c
UN
813 /* realize palette if this is *not* the current window */
814 if ( GetPalette() &&
8b089c5e 815 GetPalette()->Ok() && (this != event.GetChangedWindow()) )
f48d169c
UN
816 {
817 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
dc3065a5
VZ
818 ::SelectPalette(GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
819 ::RealizePalette(GetHDC());
f48d169c
UN
820 Refresh();
821 }
8b089c5e
JS
822}
823
dc3065a5 824#endif // wxUSE_PALETTE
a3081354 825
dc3065a5
VZ
826// ----------------------------------------------------------------------------
827// deprecated wxGLCanvas methods using implicit wxGLContext
828// ----------------------------------------------------------------------------
a3081354 829
dc3065a5
VZ
830// deprecated constructors creating an implicit m_glContext
831#if WXWIN_COMPATIBILITY_2_8
832
833wxGLCanvas::wxGLCanvas(wxWindow *parent,
834 wxWindowID id,
835 const wxPoint& pos,
836 const wxSize& size,
837 long style,
838 const wxString& name,
839 const int *attribList,
840 const wxPalette& palette)
a3081354 841{
dc3065a5 842 Init();
a3081354 843
dc3065a5
VZ
844 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
845 m_glContext = new wxGLContext(this);
846}
a3081354 847
dc3065a5
VZ
848wxGLCanvas::wxGLCanvas(wxWindow *parent,
849 const wxGLContext *shared,
850 wxWindowID id,
851 const wxPoint& pos,
852 const wxSize& size,
853 long style,
854 const wxString& name,
855 const int *attribList,
856 const wxPalette& palette)
857{
858 Init();
a3081354 859
dc3065a5
VZ
860 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
861 m_glContext = new wxGLContext(this, shared);
862}
863
864wxGLCanvas::wxGLCanvas(wxWindow *parent,
865 const wxGLCanvas *shared,
866 wxWindowID id,
867 const wxPoint& pos,
868 const wxSize& size,
869 long style,
870 const wxString& name,
871 const int *attribList,
872 const wxPalette& palette)
873{
874 Init();
a3081354 875
dc3065a5
VZ
876 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
877 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
a3081354
VZ
878}
879
dc3065a5
VZ
880#endif // WXWIN_COMPATIBILITY_2_8
881
882
883// ----------------------------------------------------------------------------
884// wxGLApp
885// ----------------------------------------------------------------------------
886
887bool wxGLApp::InitGLVisual(const int *attribList)
a3081354 888{
dc3065a5
VZ
889 if ( !wxGLCanvas::ChooseMatchingPixelFormat(ScreenHDC(), attribList) )
890 {
891 wxLogError(_("Failed to initialize OpenGL"));
892 return false;
893 }
894
895 return true;
a3081354
VZ
896}
897
dc3065a5 898#endif // wxUSE_GLCANVAS