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
/* not used yet! */, const wxPalette
& palette
):
140 m_glContext
= (wxGLContext
*) NULL
;
142 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
146 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
147 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
150 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
153 SetupPalette(palette
);
155 m_glContext
= new wxGLContext(TRUE
, this, palette
);
158 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
159 const wxGLContext
*shared
, wxWindowID id
,
160 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
161 int *attribList
, const wxPalette
& palette
)
164 m_glContext
= (wxGLContext
*) NULL
;
166 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
170 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
171 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
174 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
177 SetupPalette(palette
);
179 m_glContext
= new wxGLContext(TRUE
, this, palette
, shared
);
182 // Not very useful for wxMSW, but this is to be wxGTK compliant
184 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, const wxGLCanvas
*shared
, wxWindowID id
,
185 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
186 int *attribList
, const wxPalette
& palette
):
189 m_glContext
= (wxGLContext
*) NULL
;
191 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
195 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
196 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
199 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
202 SetupPalette(palette
);
204 wxGLContext
*sharedContext
=0;
205 if (shared
) sharedContext
=shared
->GetContext();
206 m_glContext
= new wxGLContext(TRUE
, this, palette
, sharedContext
);
209 wxGLCanvas::~wxGLCanvas()
214 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
217 // Replaces wxWindow::Create functionality, since we need to use a different window class
218 bool wxGLCanvas::Create(wxWindow
*parent
, wxWindowID id
,
219 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:
225 wxSize parentSize = GetClientSize();
226 All locations within the function that use 'size' are changed to
228 The above corrects the initial display corruption with the GeForce and
229 TNT2, not sure about other NVidia cards yet.
232 static bool registeredGLCanvasClass
= FALSE
;
234 // We have to register a special window class because we need
235 // the CS_OWNDC style for GLCanvas.
238 From Angel Popov <jumpo@bitex.com>
240 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
241 how this problem can be fixed:
243 "There are 5 common DCs available in Win95. These are aquired when you call
244 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
245 OWNDC flagged windows do not get their DC from the common DC pool, the issue
246 is they require 800 bytes each from the limited 64Kb local heap for GDI."
248 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
249 do), Win95 will actually "steal" it from you. MakeCurrent fails,
250 apparently, because Windows re-assigns the HDC to a different window. The
251 only way to prevent this, the only reliable means, is to set CS_OWNDC."
254 if (!registeredGLCanvasClass
)
258 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
260 // the fields which are common to all classes
261 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
262 wndclass
.cbClsExtra
= 0;
263 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
264 wndclass
.hInstance
= wxhInstance
;
265 wndclass
.hIcon
= (HICON
) NULL
;
266 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
267 wndclass
.lpszMenuName
= NULL
;
269 // Register the GLCanvas class name
270 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
271 wndclass
.lpszClassName
= wxGLCanvasClassName
;
272 wndclass
.style
= styleNormal
;
274 if ( !RegisterClass(&wndclass
) )
276 wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
280 registeredGLCanvasClass
= TRUE
;
283 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
285 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
288 parent
->AddChild(this);
291 if ( style
& wxBORDER
)
292 msflags
|= WS_BORDER
;
293 if ( style
& wxTHICK_FRAME
)
294 msflags
|= WS_THICKFRAME
;
297 A general rule with OpenGL and Win32 is that any window that will have a
298 HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
299 You can find references about this within the knowledge base and most OpenGL
300 books that contain the wgl function descriptions.
303 msflags
|= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
;
304 // if ( style & wxCLIP_CHILDREN )
305 // msflags |= WS_CLIPCHILDREN;
306 msflags
|= WS_CLIPCHILDREN
;
309 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
311 // Even with extended styles, need to combine with WS_BORDER
312 // for them to look right.
313 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
314 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
316 msflags
|= WS_BORDER
;
319 // calculate the value to return from WM_GETDLGCODE handler
320 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
322 // want everything: i.e. all keys and WM_CHAR message
323 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
324 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
327 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
329 WidthDefault(size
.x
), HeightDefault(size
.y
),
330 msflags
, NULL
, exStyle
);
336 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
338 PIXELFORMATDESCRIPTOR pfd
= {
339 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
343 PFD_DOUBLEBUFFER
, /* support double-buffering */
344 PFD_TYPE_RGBA
, /* color type */
345 16, /* prefered color depth */
346 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
347 0, /* no alpha buffer */
348 0, /* alpha bits (ignored) */
349 0, /* no accumulation buffer */
350 0, 0, 0, 0, /* accum bits (ignored) */
351 16, /* depth buffer */
352 0, /* no stencil buffer */
353 0, /* no auxiliary buffers */
354 PFD_MAIN_PLANE
, /* main layer */
356 0, 0, 0, /* no layer, visible, damage masks */
360 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
361 if (pixelFormat
== 0) {
362 MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("ChoosePixelFormat failed."), wxT("Error"),
363 MB_ICONERROR
| MB_OK
);
367 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
368 MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("SetPixelFormat failed."), wxT("Error"),
369 MB_ICONERROR
| MB_OK
);
374 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
376 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
377 PIXELFORMATDESCRIPTOR pfd
;
379 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
381 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
391 if ( !m_palette
.Ok() )
393 m_palette
= CreateDefaultPalette();
398 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
399 RealizePalette((HDC
) m_hDC
);
403 wxPalette
wxGLCanvas::CreateDefaultPalette()
405 PIXELFORMATDESCRIPTOR pfd
;
407 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
409 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
411 paletteSize
= 1 << pfd
.cColorBits
;
414 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
415 pPal
->palVersion
= 0x300;
416 pPal
->palNumEntries
= paletteSize
;
418 /* build a simple RGB color palette */
420 int redMask
= (1 << pfd
.cRedBits
) - 1;
421 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
422 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
425 for (i
=0; i
<paletteSize
; ++i
) {
426 pPal
->palPalEntry
[i
].peRed
=
427 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
428 pPal
->palPalEntry
[i
].peGreen
=
429 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
430 pPal
->palPalEntry
[i
].peBlue
=
431 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
432 pPal
->palPalEntry
[i
].peFlags
= 0;
436 HPALETTE hPalette
= CreatePalette(pPal
);
440 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
445 void wxGLCanvas::SwapBuffers()
448 m_glContext
->SwapBuffers();
451 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
454 GetClientSize(& width
, & height
);
458 m_glContext
->SetCurrent();
460 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
461 glMatrixMode(GL_PROJECTION
);
463 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
464 glMatrixMode(GL_MODELVIEW
);
468 void wxGLCanvas::SetCurrent()
472 m_glContext
->SetCurrent();
476 void wxGLCanvas::SetColour(const char *colour
)
479 m_glContext
->SetColour(colour
);
482 // TODO: Have to have this called by parent frame (?)
483 // So we need wxFrame to call OnQueryNewPalette for all children...
484 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
486 /* realize palette if this is the current window */
487 if ( GetPalette()->Ok() ) {
488 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
489 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
490 ::RealizePalette((HDC
) GetHDC());
492 event
.SetPaletteRealized(TRUE
);
495 event
.SetPaletteRealized(FALSE
);
498 // I think this doesn't have to be propagated to child windows.
499 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
501 /* realize palette if this is *not* the current window */
503 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
505 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
506 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
507 ::RealizePalette((HDC
) GetHDC());
512 /* Give extensions proper function names. */
514 /* EXT_vertex_array */
515 void glArrayElementEXT(GLint i
)
519 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
523 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
525 #ifdef GL_EXT_vertex_array
526 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
530 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
534 (* proc
) (mode
, first
, count
);
538 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
542 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
546 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
550 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
552 #ifdef GL_EXT_vertex_array
553 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
557 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
561 (* proc
) (type
, stride
, count
, pointer
);
565 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
569 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
571 #ifdef GL_EXT_vertex_array
572 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
576 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
580 (* proc
) (size
, type
, stride
, count
, pointer
);
584 /* EXT_color_subtable */
585 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
589 /* EXT_color_table */
590 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
594 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
598 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
602 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
606 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
610 /* SGI_compiled_vertex_array */
611 void glLockArraysSGI(GLint first
, GLsizei count
)
615 void glUnlockArraysSGI()
620 /* SGI_cull_vertex */
621 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
625 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
630 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
634 /* SGI_index_material */
635 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
640 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)