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