1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxGLCanvas, for using OpenGL with wxWindows under MS Windows
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "glcanvas.h"
16 #include "wx/wxprec.h"
18 #if defined(__BORLANDC__)
30 #include <wx/msw/private.h>
31 #include <wx/settings.h>
34 #include <wx/glcanvas.h>
36 wxChar wxGLCanvasClassName
[] = wxT("wxGLCanvasClass");
38 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
39 WPARAM wParam
, LPARAM lParam
);
42 * GLContext implementation
45 wxGLContext::wxGLContext(bool isRGB
, wxGLCanvas
*win
, const wxPalette
& palette
)
49 m_hDC
= win
->GetHDC();
51 m_glContext
= wglCreateContext((HDC
) m_hDC
);
52 wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGl context") );
54 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
57 wxGLContext::wxGLContext(
58 bool isRGB
, wxGLCanvas
*win
,
59 const wxPalette
& palette
,
60 const wxGLContext
*other
/* for sharing display lists */
65 m_hDC
= win
->GetHDC();
67 m_glContext
= wglCreateContext((HDC
) m_hDC
);
68 wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGl context") );
71 wglShareLists( other
->m_glContext
, m_glContext
);
73 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
76 wxGLContext::~wxGLContext()
80 wglMakeCurrent(NULL
, NULL
);
81 wglDeleteContext(m_glContext
);
85 void wxGLContext::SwapBuffers()
89 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
90 ::SwapBuffers((HDC
) m_hDC
); //blits the backbuffer into DC
94 void wxGLContext::SetCurrent()
98 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
102 setupPixelFormat(hDC);
107 void wxGLContext::SetColour(const char *colour
)
112 wxColour
*col
= wxTheColourDatabase
->FindColour(colour
);
115 r
= (float)(col
->Red()/256.0);
116 g
= (float)(col
->Green()/256.0);
117 b
= (float)(col
->Blue()/256.0);
124 * wxGLCanvas implementation
127 IMPLEMENT_CLASS(wxGLCanvas
, wxScrolledWindow
)
129 BEGIN_EVENT_TABLE(wxGLCanvas
, wxScrolledWindow
)
130 EVT_SIZE(wxGLCanvas::OnSize
)
131 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged
)
132 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette
)
135 wxGLCanvas::wxGLCanvas(wxWindow
*parent
, wxWindowID id
,
136 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
137 int *attribList
, const wxPalette
& palette
) : wxScrolledWindow()
139 m_glContext
= (wxGLContext
*) NULL
;
141 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
145 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
146 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
149 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
151 SetupPixelFormat(attribList
);
152 SetupPalette(palette
);
154 m_glContext
= new wxGLContext(TRUE
, this, palette
);
157 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
158 const wxGLContext
*shared
, wxWindowID id
,
159 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
160 int *attribList
, const wxPalette
& palette
)
163 m_glContext
= (wxGLContext
*) NULL
;
165 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
169 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
170 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
173 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
175 SetupPixelFormat(attribList
);
176 SetupPalette(palette
);
178 m_glContext
= new wxGLContext(TRUE
, this, palette
, shared
);
181 // Not very useful for wxMSW, but this is to be wxGTK compliant
183 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, const wxGLCanvas
*shared
, wxWindowID id
,
184 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
185 int *attribList
, const wxPalette
& palette
):
188 m_glContext
= (wxGLContext
*) NULL
;
190 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
194 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
195 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
198 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
200 SetupPixelFormat(attribList
);
201 SetupPalette(palette
);
203 wxGLContext
*sharedContext
=0;
204 if (shared
) sharedContext
=shared
->GetContext();
205 m_glContext
= new wxGLContext(TRUE
, this, palette
, sharedContext
);
208 wxGLCanvas::~wxGLCanvas()
213 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
216 // Replaces wxWindow::Create functionality, since we need to use a different window class
217 bool wxGLCanvas::Create(wxWindow
*parent
, wxWindowID id
,
218 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
)
221 Suggestion from Kelly Brock <kbrock@8cs.com> (not yet implemented):
223 OpenGL corruption fix is simple assuming it doesn't screw anything else
224 up. Add the following line to the top of the create function:
226 wxSize parentSize = GetClientSize();
228 All locations within the function that use 'size' are changed to
230 The above corrects the initial display corruption with the GeForce and
231 TNT2, not sure about other NVidia cards yet.
234 static bool registeredGLCanvasClass
= FALSE
;
236 // We have to register a special window class because we need
237 // the CS_OWNDC style for GLCanvas.
240 From Angel Popov <jumpo@bitex.com>
242 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
243 how this problem can be fixed:
245 "There are 5 common DCs available in Win95. These are aquired when you call
246 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
247 OWNDC flagged windows do not get their DC from the common DC pool, the issue
248 is they require 800 bytes each from the limited 64Kb local heap for GDI."
250 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
251 do), Win95 will actually "steal" it from you. MakeCurrent fails,
252 apparently, because Windows re-assigns the HDC to a different window. The
253 only way to prevent this, the only reliable means, is to set CS_OWNDC."
256 if (!registeredGLCanvasClass
)
260 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
262 // the fields which are common to all classes
263 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
264 wndclass
.cbClsExtra
= 0;
265 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
266 wndclass
.hInstance
= wxhInstance
;
267 wndclass
.hIcon
= (HICON
) NULL
;
268 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
269 wndclass
.lpszMenuName
= NULL
;
271 // Register the GLCanvas class name
272 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
273 wndclass
.lpszClassName
= wxGLCanvasClassName
;
274 wndclass
.style
= styleNormal
;
276 if ( !RegisterClass(&wndclass
) )
278 wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
282 registeredGLCanvasClass
= TRUE
;
285 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
287 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
290 parent
->AddChild(this);
293 if ( style
& wxBORDER
)
294 msflags
|= WS_BORDER
;
295 if ( style
& wxTHICK_FRAME
)
296 msflags
|= WS_THICKFRAME
;
299 A general rule with OpenGL and Win32 is that any window that will have a
300 HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
301 You can find references about this within the knowledge base and most OpenGL
302 books that contain the wgl function descriptions.
305 msflags
|= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
;
306 // if ( style & wxCLIP_CHILDREN )
307 // msflags |= WS_CLIPCHILDREN;
308 msflags
|= WS_CLIPCHILDREN
;
311 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
313 // Even with extended styles, need to combine with WS_BORDER
314 // for them to look right.
315 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
316 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
318 msflags
|= WS_BORDER
;
321 // calculate the value to return from WM_GETDLGCODE handler
322 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
324 // want everything: i.e. all keys and WM_CHAR message
325 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
326 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
329 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
331 WidthDefault(size
.x
), HeightDefault(size
.y
),
332 msflags
, NULL
, exStyle
);
337 void wxGLCanvas::SetupPixelFormat(int *attribList
) // (HDC hDC)
340 PIXELFORMATDESCRIPTOR pfd
= {
341 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
345 PFD_DOUBLEBUFFER
, /* support double-buffering */
346 PFD_TYPE_RGBA
, /* color type */
347 16, /* prefered color depth */
348 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
349 0, /* no alpha buffer */
350 0, /* alpha bits (ignored) */
351 0, /* no accumulation buffer */
352 0, 0, 0, 0, /* accum bits (ignored) */
353 16, /* depth buffer */
354 0, /* no stencil buffer */
355 0, /* no auxiliary buffers */
356 PFD_MAIN_PLANE
, /* main layer */
358 0, 0, 0, /* no layer, visible, damage masks */
362 pfd
.dwFlags
&= ~PFD_DOUBLEBUFFER
;
363 pfd
.iPixelType
= PFD_TYPE_COLORINDEX
;
367 while( (attribList
[arg
]!=0) )
369 switch( attribList
[arg
++] )
372 pfd
.iPixelType
= PFD_TYPE_RGBA
;
374 case WX_GL_BUFFER_SIZE
:
375 pfd
.cColorBits
= attribList
[arg
++];
378 // this member looks like it may be obsolete
379 if (attribList
[arg
] > 0) {
380 pfd
.iLayerType
= PFD_OVERLAY_PLANE
;
381 } else if (attribList
[arg
] < 0) {
382 pfd
.iLayerType
= PFD_UNDERLAY_PLANE
;
384 pfd
.iLayerType
= PFD_MAIN_PLANE
;
388 case WX_GL_DOUBLEBUFFER
:
389 pfd
.dwFlags
|= PFD_DOUBLEBUFFER
;
392 pfd
.dwFlags
|= PFD_STEREO
;
394 case WX_GL_AUX_BUFFERS
:
395 pfd
.cAuxBuffers
= attribList
[arg
++];
398 pfd
.cColorBits
+= (pfd
.cRedBits
= attribList
[arg
++]);
400 case WX_GL_MIN_GREEN
:
401 pfd
.cColorBits
+= (pfd
.cGreenBits
= attribList
[arg
++]);
404 pfd
.cColorBits
+= (pfd
.cBlueBits
= attribList
[arg
++]);
406 case WX_GL_MIN_ALPHA
:
407 // doesn't count in cColorBits
408 pfd
.cAlphaBits
= attribList
[arg
++];
410 case WX_GL_DEPTH_SIZE
:
411 pfd
.cDepthBits
= attribList
[arg
++];
413 case WX_GL_STENCIL_SIZE
:
414 pfd
.cStencilBits
= attribList
[arg
++];
416 case WX_GL_MIN_ACCUM_RED
:
417 pfd
.cAccumBits
+= (pfd
.cAccumRedBits
= attribList
[arg
++]);
419 case WX_GL_MIN_ACCUM_GREEN
:
420 pfd
.cAccumBits
+= (pfd
.cAccumGreenBits
= attribList
[arg
++]);
422 case WX_GL_MIN_ACCUM_BLUE
:
423 pfd
.cAccumBits
+= (pfd
.cAccumBlueBits
= attribList
[arg
++]);
425 case WX_GL_MIN_ACCUM_ALPHA
:
426 pfd
.cAccumBits
+= (pfd
.cAccumAlphaBits
= attribList
[arg
++]);
433 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
434 if (pixelFormat
== 0) {
435 MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("ChoosePixelFormat failed."), wxT("Error"),
436 MB_ICONERROR
| MB_OK
);
440 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
441 MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("SetPixelFormat failed."), wxT("Error"),
442 MB_ICONERROR
| MB_OK
);
447 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
449 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
450 PIXELFORMATDESCRIPTOR pfd
;
452 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
454 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
464 if ( !m_palette
.Ok() )
466 m_palette
= CreateDefaultPalette();
471 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
472 RealizePalette((HDC
) m_hDC
);
476 wxPalette
wxGLCanvas::CreateDefaultPalette()
478 PIXELFORMATDESCRIPTOR pfd
;
480 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
482 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
484 paletteSize
= 1 << pfd
.cColorBits
;
487 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
488 pPal
->palVersion
= 0x300;
489 pPal
->palNumEntries
= paletteSize
;
491 /* build a simple RGB color palette */
493 int redMask
= (1 << pfd
.cRedBits
) - 1;
494 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
495 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
498 for (i
=0; i
<paletteSize
; ++i
) {
499 pPal
->palPalEntry
[i
].peRed
=
500 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
501 pPal
->palPalEntry
[i
].peGreen
=
502 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
503 pPal
->palPalEntry
[i
].peBlue
=
504 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
505 pPal
->palPalEntry
[i
].peFlags
= 0;
509 HPALETTE hPalette
= CreatePalette(pPal
);
513 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
518 void wxGLCanvas::SwapBuffers()
521 m_glContext
->SwapBuffers();
524 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
527 GetClientSize(& width
, & height
);
531 m_glContext
->SetCurrent();
533 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
534 glMatrixMode(GL_PROJECTION
);
536 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
537 glMatrixMode(GL_MODELVIEW
);
541 void wxGLCanvas::SetCurrent()
545 m_glContext
->SetCurrent();
549 void wxGLCanvas::SetColour(const char *colour
)
552 m_glContext
->SetColour(colour
);
555 // TODO: Have to have this called by parent frame (?)
556 // So we need wxFrame to call OnQueryNewPalette for all children...
557 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
559 /* realize palette if this is the current window */
560 if ( GetPalette()->Ok() ) {
561 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
562 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
563 ::RealizePalette((HDC
) GetHDC());
565 event
.SetPaletteRealized(TRUE
);
568 event
.SetPaletteRealized(FALSE
);
571 // I think this doesn't have to be propagated to child windows.
572 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
574 /* realize palette if this is *not* the current window */
576 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
578 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
579 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
580 ::RealizePalette((HDC
) GetHDC());
585 /* Give extensions proper function names. */
587 /* EXT_vertex_array */
588 void glArrayElementEXT(GLint i
)
592 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
596 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
598 #ifdef GL_EXT_vertex_array
599 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
603 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
607 (* proc
) (mode
, first
, count
);
611 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
615 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
619 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
623 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
625 #ifdef GL_EXT_vertex_array
626 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
630 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
634 (* proc
) (type
, stride
, count
, pointer
);
638 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
642 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
644 #ifdef GL_EXT_vertex_array
645 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
649 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
652 (* proc
) (size
, type
, stride
, count
, pointer
);
656 /* EXT_color_subtable */
657 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
661 /* EXT_color_table */
662 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
666 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
670 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
674 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
678 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
682 /* SGI_compiled_vertex_array */
683 void glLockArraysSGI(GLint first
, GLsizei count
)
687 void glUnlockArraysSGI()
692 /* SGI_cull_vertex */
693 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
697 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
702 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
706 /* SGI_index_material */
707 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
712 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)