1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL with wxWidgets under MS Windows
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "glcanvas.h"
16 #include "wx/wxprec.h"
18 #if defined(__BORLANDC__)
26 #include "wx/settings.h"
32 #include "wx/module.h"
34 #include "wx/msw/private.h"
36 // DLL options compatibility check:
38 WX_CHECK_BUILD_OPTIONS("wxGL")
40 #include "wx/glcanvas.h"
43 The following two compiler directives are specific to the Microsoft Visual
44 C++ family of compilers
46 Fundementally what they do is instruct the linker to use these two libraries
47 for the resolution of symbols. In essence, this is the equivalent of adding
48 these two libraries to either the Makefile or project file.
50 This is NOT a recommended technique, and certainly is unlikely to be used
51 anywhere else in wxWidgets given it is so specific to not only wxMSW, but
52 also the VC compiler. However, in the case of opengl support, it's an
53 applicable technique as opengl is optional in setup.h This code (wrapped by
54 wxUSE_GLCANVAS), now allows opengl support to be added purely by modifying
55 setup.h rather than by having to modify either the project or DSP fle.
57 See MSDN for further information on the exact usage of these commands.
60 # pragma comment( lib, "opengl32" )
61 # pragma comment( lib, "glu32" )
65 static const wxChar
*wxGLCanvasClassName
= wxT("wxGLCanvasClass");
66 static const wxChar
*wxGLCanvasClassNameNoRedraw
= wxT("wxGLCanvasClassNR");
68 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
69 WPARAM wParam
, LPARAM lParam
);
71 // ----------------------------------------------------------------------------
72 // wxGLModule is responsible for unregistering wxGLCanvasClass Windows class
73 // ----------------------------------------------------------------------------
75 class wxGLModule
: public wxModule
78 bool OnInit() { return true; }
79 void OnExit() { UnregisterClasses(); }
81 // register the GL classes if not done yet, return true if ok, false if
82 // registration failed
83 static bool RegisterClasses();
85 // unregister the classes, done automatically on program termination
86 static void UnregisterClasses();
89 // wxGLCanvas is only used from the main thread so this is MT-ok
90 static bool ms_registeredGLClasses
;
92 DECLARE_DYNAMIC_CLASS(wxGLModule
)
95 IMPLEMENT_DYNAMIC_CLASS(wxGLModule
, wxModule
)
97 bool wxGLModule::ms_registeredGLClasses
= false;
100 bool wxGLModule::RegisterClasses()
102 if (ms_registeredGLClasses
)
105 // We have to register a special window class because we need the CS_OWNDC
106 // style for GLCanvas.
109 From Angel Popov <jumpo@bitex.com>
111 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
112 how this problem can be fixed:
114 "There are 5 common DCs available in Win95. These are aquired when you call
115 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
116 OWNDC flagged windows do not get their DC from the common DC pool, the issue
117 is they require 800 bytes each from the limited 64Kb local heap for GDI."
119 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
120 do), Win95 will actually "steal" it from you. MakeCurrent fails,
121 apparently, because Windows re-assigns the HDC to a different window. The
122 only way to prevent this, the only reliable means, is to set CS_OWNDC."
127 // the fields which are common to all classes
128 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
129 wndclass
.cbClsExtra
= 0;
130 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
131 wndclass
.hInstance
= wxhInstance
;
132 wndclass
.hIcon
= (HICON
) NULL
;
133 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
134 wndclass
.lpszMenuName
= NULL
;
136 // Register the GLCanvas class name
137 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
138 wndclass
.lpszClassName
= wxGLCanvasClassName
;
139 wndclass
.style
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
141 if ( !::RegisterClass(&wndclass
) )
143 wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
147 // Register the GLCanvas class name for windows which don't do full repaint
149 wndclass
.lpszClassName
= wxGLCanvasClassNameNoRedraw
;
150 wndclass
.style
&= ~(CS_HREDRAW
| CS_VREDRAW
);
152 if ( !::RegisterClass(&wndclass
) )
154 wxLogLastError(wxT("RegisterClass(wxGLCanvasClassNameNoRedraw)"));
156 ::UnregisterClass(wxGLCanvasClassName
, wxhInstance
);
161 ms_registeredGLClasses
= true;
167 void wxGLModule::UnregisterClasses()
169 // we need to unregister the classes in case we're in a DLL which is
170 // unloaded and then loaded again because if we don't, the registration is
171 // going to fail in wxGLCanvas::Create() the next time we're loaded
172 if ( ms_registeredGLClasses
)
174 ::UnregisterClass(wxGLCanvasClassName
, wxhInstance
);
175 ::UnregisterClass(wxGLCanvasClassNameNoRedraw
, wxhInstance
);
177 ms_registeredGLClasses
= false;
182 * GLContext implementation
185 wxGLContext::wxGLContext(bool WXUNUSED(isRGB
), wxGLCanvas
*win
, const wxPalette
& WXUNUSED(palette
))
189 m_hDC
= win
->GetHDC();
191 m_glContext
= wglCreateContext((HDC
) m_hDC
);
192 wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGL context") );
194 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
197 wxGLContext::wxGLContext(
198 bool WXUNUSED(isRGB
), wxGLCanvas
*win
,
199 const wxPalette
& WXUNUSED(palette
),
200 const wxGLContext
*other
/* for sharing display lists */
205 m_hDC
= win
->GetHDC();
207 m_glContext
= wglCreateContext((HDC
) m_hDC
);
208 wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGL context") );
211 wglShareLists( other
->m_glContext
, m_glContext
);
213 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
216 wxGLContext::~wxGLContext()
220 wglMakeCurrent(NULL
, NULL
);
221 wglDeleteContext(m_glContext
);
225 void wxGLContext::SwapBuffers()
229 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
230 ::SwapBuffers((HDC
) m_hDC
); //blits the backbuffer into DC
234 void wxGLContext::SetCurrent()
238 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
242 setupPixelFormat(hDC);
247 void wxGLContext::SetColour(const wxChar
*colour
)
249 wxColour col
= wxTheColourDatabase
->Find(colour
);
252 float r
= (float)(col
.Red()/256.0);
253 float g
= (float)(col
.Green()/256.0);
254 float b
= (float)(col
.Blue()/256.0);
261 * wxGLCanvas implementation
264 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
)
266 BEGIN_EVENT_TABLE(wxGLCanvas
, wxWindow
)
267 EVT_SIZE(wxGLCanvas::OnSize
)
268 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged
)
269 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette
)
272 wxGLCanvas::wxGLCanvas(wxWindow
*parent
, wxWindowID id
,
273 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
274 int *attribList
, const wxPalette
& palette
) : wxWindow()
276 m_glContext
= (wxGLContext
*) NULL
;
278 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
282 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
));
285 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
287 SetupPixelFormat(attribList
);
288 SetupPalette(palette
);
290 m_glContext
= new wxGLContext(true, this, palette
);
293 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
294 const wxGLContext
*shared
, wxWindowID id
,
295 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
296 int *attribList
, const wxPalette
& palette
)
299 m_glContext
= (wxGLContext
*) NULL
;
301 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
305 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
));
308 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
310 SetupPixelFormat(attribList
);
311 SetupPalette(palette
);
313 m_glContext
= new wxGLContext(true, this, palette
, shared
);
316 // Not very useful for wxMSW, but this is to be wxGTK compliant
318 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, const wxGLCanvas
*shared
, wxWindowID id
,
319 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
320 int *attribList
, const wxPalette
& palette
):
323 m_glContext
= (wxGLContext
*) NULL
;
325 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
329 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
));
332 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
334 SetupPixelFormat(attribList
);
335 SetupPalette(palette
);
337 wxGLContext
*sharedContext
=0;
338 if (shared
) sharedContext
=shared
->GetContext();
339 m_glContext
= new wxGLContext(true, this, palette
, sharedContext
);
342 wxGLCanvas::~wxGLCanvas()
346 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
349 // Replaces wxWindow::Create functionality, since we need to use a different
351 bool wxGLCanvas::Create(wxWindow
*parent
,
356 const wxString
& name
)
358 wxCHECK_MSG( parent
, false, wxT("can't create wxWindow without parent") );
360 if ( !wxGLModule::RegisterClasses() )
362 wxLogError(_("Failed to register OpenGL window class."));
367 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
370 parent
->AddChild(this);
375 A general rule with OpenGL and Win32 is that any window that will have a
376 HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
377 You can find references about this within the knowledge base and most OpenGL
378 books that contain the wgl function descriptions.
382 msflags
|= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
383 msflags
|= MSWGetStyle(style
, & exStyle
) ;
385 return MSWCreate(wxGLCanvasClassName
, NULL
, pos
, size
, msflags
, exStyle
);
388 static void AdjustPFDForAttributes(PIXELFORMATDESCRIPTOR
& pfd
, int *attribList
)
391 pfd
.dwFlags
&= ~PFD_DOUBLEBUFFER
;
392 pfd
.iPixelType
= PFD_TYPE_COLORINDEX
;
396 while( (attribList
[arg
]!=0) )
398 switch( attribList
[arg
++] )
401 pfd
.iPixelType
= PFD_TYPE_RGBA
;
403 case WX_GL_BUFFER_SIZE
:
404 pfd
.cColorBits
= attribList
[arg
++];
407 // this member looks like it may be obsolete
408 if (attribList
[arg
] > 0) {
409 pfd
.iLayerType
= (BYTE
)PFD_OVERLAY_PLANE
;
410 } else if (attribList
[arg
] < 0) {
411 pfd
.iLayerType
= (BYTE
)PFD_UNDERLAY_PLANE
;
413 pfd
.iLayerType
= (BYTE
)PFD_MAIN_PLANE
;
417 case WX_GL_DOUBLEBUFFER
:
418 pfd
.dwFlags
|= PFD_DOUBLEBUFFER
;
421 pfd
.dwFlags
|= PFD_STEREO
;
423 case WX_GL_AUX_BUFFERS
:
424 pfd
.cAuxBuffers
= attribList
[arg
++];
427 pfd
.cColorBits
+= (pfd
.cRedBits
= attribList
[arg
++]);
429 case WX_GL_MIN_GREEN
:
430 pfd
.cColorBits
+= (pfd
.cGreenBits
= attribList
[arg
++]);
433 pfd
.cColorBits
+= (pfd
.cBlueBits
= attribList
[arg
++]);
435 case WX_GL_MIN_ALPHA
:
436 // doesn't count in cColorBits
437 pfd
.cAlphaBits
= attribList
[arg
++];
439 case WX_GL_DEPTH_SIZE
:
440 pfd
.cDepthBits
= attribList
[arg
++];
442 case WX_GL_STENCIL_SIZE
:
443 pfd
.cStencilBits
= attribList
[arg
++];
445 case WX_GL_MIN_ACCUM_RED
:
446 pfd
.cAccumBits
+= (pfd
.cAccumRedBits
= attribList
[arg
++]);
448 case WX_GL_MIN_ACCUM_GREEN
:
449 pfd
.cAccumBits
+= (pfd
.cAccumGreenBits
= attribList
[arg
++]);
451 case WX_GL_MIN_ACCUM_BLUE
:
452 pfd
.cAccumBits
+= (pfd
.cAccumBlueBits
= attribList
[arg
++]);
454 case WX_GL_MIN_ACCUM_ALPHA
:
455 pfd
.cAccumBits
+= (pfd
.cAccumAlphaBits
= attribList
[arg
++]);
464 void wxGLCanvas::SetupPixelFormat(int *attribList
) // (HDC hDC)
466 PIXELFORMATDESCRIPTOR pfd
= {
467 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
471 PFD_DOUBLEBUFFER
, /* support double-buffering */
472 PFD_TYPE_RGBA
, /* color type */
473 16, /* prefered color depth */
474 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
475 0, /* no alpha buffer */
476 0, /* alpha bits (ignored) */
477 0, /* no accumulation buffer */
478 0, 0, 0, 0, /* accum bits (ignored) */
479 16, /* depth buffer */
480 0, /* no stencil buffer */
481 0, /* no auxiliary buffers */
482 PFD_MAIN_PLANE
, /* main layer */
484 0, 0, 0, /* no layer, visible, damage masks */
487 AdjustPFDForAttributes(pfd
, attribList
);
489 int pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
490 if (pixelFormat
== 0) {
491 wxLogLastError(_T("ChoosePixelFormat"));
494 if ( !::SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) ) {
495 wxLogLastError(_T("SetPixelFormat"));
500 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
502 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
503 PIXELFORMATDESCRIPTOR pfd
;
505 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
507 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
517 if ( !m_palette
.Ok() )
519 m_palette
= CreateDefaultPalette();
524 ::SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
525 ::RealizePalette((HDC
) m_hDC
);
529 wxPalette
wxGLCanvas::CreateDefaultPalette()
531 PIXELFORMATDESCRIPTOR pfd
;
533 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
535 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
537 paletteSize
= 1 << pfd
.cColorBits
;
540 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
541 pPal
->palVersion
= 0x300;
542 pPal
->palNumEntries
= paletteSize
;
544 /* build a simple RGB color palette */
546 int redMask
= (1 << pfd
.cRedBits
) - 1;
547 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
548 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
551 for (i
=0; i
<paletteSize
; ++i
) {
552 pPal
->palPalEntry
[i
].peRed
=
553 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
554 pPal
->palPalEntry
[i
].peGreen
=
555 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
556 pPal
->palPalEntry
[i
].peBlue
=
557 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
558 pPal
->palPalEntry
[i
].peFlags
= 0;
562 HPALETTE hPalette
= CreatePalette(pPal
);
566 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
571 void wxGLCanvas::SwapBuffers()
574 m_glContext
->SwapBuffers();
577 void wxGLCanvas::OnSize(wxSizeEvent
& WXUNUSED(event
))
581 void wxGLCanvas::SetCurrent()
585 m_glContext
->SetCurrent();
589 void wxGLCanvas::SetColour(const wxChar
*colour
)
592 m_glContext
->SetColour(colour
);
595 // TODO: Have to have this called by parent frame (?)
596 // So we need wxFrame to call OnQueryNewPalette for all children...
597 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
599 /* realize palette if this is the current window */
600 if ( GetPalette()->Ok() ) {
601 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
602 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
603 ::RealizePalette((HDC
) GetHDC());
605 event
.SetPaletteRealized(true);
608 event
.SetPaletteRealized(false);
611 // I think this doesn't have to be propagated to child windows.
612 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
614 /* realize palette if this is *not* the current window */
616 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
618 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
619 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
620 ::RealizePalette((HDC
) GetHDC());
625 /* Give extensions proper function names. */
627 /* EXT_vertex_array */
628 void glArrayElementEXT(GLint
WXUNUSED(i
))
632 void glColorPointerEXT(GLint
WXUNUSED(size
), GLenum
WXUNUSED(type
), GLsizei
WXUNUSED(stride
), GLsizei
WXUNUSED(count
), const GLvoid
*WXUNUSED(pointer
))
636 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
638 #ifdef GL_EXT_vertex_array
639 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
643 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
647 (* proc
) (mode
, first
, count
);
651 void glEdgeFlagPointerEXT(GLsizei
WXUNUSED(stride
), GLsizei
WXUNUSED(count
), const GLboolean
*WXUNUSED(pointer
))
655 void glGetPointervEXT(GLenum
WXUNUSED(pname
), GLvoid
* *WXUNUSED(params
))
659 void glIndexPointerEXT(GLenum
WXUNUSED(type
), GLsizei
WXUNUSED(stride
), GLsizei
WXUNUSED(count
), const GLvoid
*WXUNUSED(pointer
))
663 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
665 #ifdef GL_EXT_vertex_array
666 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
670 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
674 (* proc
) (type
, stride
, count
, pointer
);
678 void glTexCoordPointerEXT(GLint
WXUNUSED(size
), GLenum
WXUNUSED(type
), GLsizei
WXUNUSED(stride
), GLsizei
WXUNUSED(count
), const GLvoid
*WXUNUSED(pointer
))
682 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
684 #ifdef GL_EXT_vertex_array
685 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
689 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
692 (* proc
) (size
, type
, stride
, count
, pointer
);
696 /* EXT_color_subtable */
697 void glColorSubtableEXT(GLenum
WXUNUSED(target
), GLsizei
WXUNUSED(start
), GLsizei
WXUNUSED(count
), GLenum
WXUNUSED(format
), GLenum
WXUNUSED(type
), const GLvoid
*WXUNUSED(table
))
701 /* EXT_color_table */
702 void glColorTableEXT(GLenum
WXUNUSED(target
), GLenum
WXUNUSED(internalformat
), GLsizei
WXUNUSED(width
), GLenum
WXUNUSED(format
), GLenum
WXUNUSED(type
), const GLvoid
*WXUNUSED(table
))
706 void glCopyColorTableEXT(GLenum
WXUNUSED(target
), GLenum
WXUNUSED(internalformat
), GLint
WXUNUSED(x
), GLint
WXUNUSED(y
), GLsizei
WXUNUSED(width
))
710 void glGetColorTableEXT(GLenum
WXUNUSED(target
), GLenum
WXUNUSED(format
), GLenum
WXUNUSED(type
), GLvoid
*WXUNUSED(table
))
714 void glGetColorTableParamaterfvEXT(GLenum
WXUNUSED(target
), GLenum
WXUNUSED(pname
), GLfloat
*WXUNUSED(params
))
718 void glGetColorTavleParameterivEXT(GLenum
WXUNUSED(target
), GLenum
WXUNUSED(pname
), GLint
*WXUNUSED(params
))
722 /* SGI_compiled_vertex_array */
723 void glLockArraysSGI(GLint
WXUNUSED(first
), GLsizei
WXUNUSED(count
))
727 void glUnlockArraysSGI()
732 /* SGI_cull_vertex */
733 void glCullParameterdvSGI(GLenum
WXUNUSED(pname
), GLdouble
* WXUNUSED(params
))
737 void glCullParameterfvSGI(GLenum
WXUNUSED(pname
), GLfloat
* WXUNUSED(params
))
742 void glIndexFuncSGI(GLenum
WXUNUSED(func
), GLclampf
WXUNUSED(ref
))
746 /* SGI_index_material */
747 void glIndexMaterialSGI(GLenum
WXUNUSED(face
), GLenum
WXUNUSED(mode
))
752 void glAddSwapHintRectWin(GLint
WXUNUSED(x
), GLint
WXUNUSED(y
), GLsizei
WXUNUSED(width
), GLsizei
WXUNUSED(height
))
757 //---------------------------------------------------------------------------
759 //---------------------------------------------------------------------------
761 IMPLEMENT_CLASS(wxGLApp
, wxApp
)
763 bool wxGLApp::InitGLVisual(int *attribList
)
766 PIXELFORMATDESCRIPTOR pfd
= {
767 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
771 PFD_DOUBLEBUFFER
, /* support double-buffering */
772 PFD_TYPE_RGBA
, /* color type */
773 16, /* prefered color depth */
774 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
775 0, /* no alpha buffer */
776 0, /* alpha bits (ignored) */
777 0, /* no accumulation buffer */
778 0, 0, 0, 0, /* accum bits (ignored) */
779 16, /* depth buffer */
780 0, /* no stencil buffer */
781 0, /* no auxiliary buffers */
782 PFD_MAIN_PLANE
, /* main layer */
784 0, 0, 0, /* no layer, visible, damage masks */
787 AdjustPFDForAttributes(pfd
, attribList
);
789 // use DC for whole (root) screen, since no windows have yet been created
790 pixelFormat
= ChoosePixelFormat(ScreenHDC(), &pfd
);
792 if (pixelFormat
== 0) {
793 wxLogError(_("Failed to initialize OpenGL"));