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