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>
32 #include <wx/glcanvas.h>
34 wxChar wxGLCanvasClassName
[] = wxT("wxGLCanvasClass");
36 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
37 WPARAM wParam
, LPARAM lParam
);
40 * GLContext implementation
43 wxGLContext::wxGLContext(bool isRGB
, wxGLCanvas
*win
, const wxPalette
& palette
)
47 m_hDC
= win
->GetHDC();
49 m_glContext
= wglCreateContext((HDC
) m_hDC
);
50 wxCHECK_RET( m_glContext
, "Couldn't create OpenGl context" );
52 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
55 wxGLContext::wxGLContext(
56 bool isRGB
, wxGLCanvas
*win
,
57 const wxPalette
& palette
,
58 const wxGLContext
*other
/* for sharing display lists */
63 m_hDC
= win
->GetHDC();
65 m_glContext
= wglCreateContext((HDC
) m_hDC
);
66 wxCHECK_RET( m_glContext
, "Couldn't create OpenGl context" );
69 wglShareLists( other
->m_glContext
, m_glContext
);
71 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
74 wxGLContext::~wxGLContext()
78 wglMakeCurrent(NULL
, NULL
);
79 wglDeleteContext(m_glContext
);
83 void wxGLContext::SwapBuffers()
87 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
88 ::SwapBuffers((HDC
) m_hDC
); //blits the backbuffer into DC
92 void wxGLContext::SetCurrent()
96 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
100 setupPixelFormat(hDC);
105 void wxGLContext::SetColour(const char *colour
)
110 wxColour
*col
= wxTheColourDatabase
->FindColour(colour
);
113 r
= (float)(col
->Red()/256.0);
114 g
= (float)(col
->Green()/256.0);
115 b
= (float)(col
->Blue()/256.0);
122 * wxGLCanvas implementation
125 IMPLEMENT_CLASS(wxGLCanvas
, wxScrolledWindow
)
127 BEGIN_EVENT_TABLE(wxGLCanvas
, wxScrolledWindow
)
128 EVT_SIZE(wxGLCanvas::OnSize
)
129 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged
)
130 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette
)
133 wxGLCanvas::wxGLCanvas(wxWindow
*parent
, wxWindowID id
,
134 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
135 int *attribList
/* not used yet! */, const wxPalette
& palette
):
138 m_glContext
= (wxGLContext
*) NULL
;
140 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
144 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
145 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
148 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
151 SetupPalette(palette
);
153 m_glContext
= new wxGLContext(TRUE
, this, palette
);
156 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
157 const wxGLContext
*shared
, wxWindowID id
,
158 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
159 int *attribList
, const wxPalette
& palette
)
162 m_glContext
= (wxGLContext
*) NULL
;
164 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
168 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
169 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
172 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
175 SetupPalette(palette
);
177 m_glContext
= new wxGLContext(TRUE
, this, palette
, shared
);
180 // Not very usefull for wxMSW, but this is to be wxGTK compliant
182 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, const wxGLCanvas
*shared
, wxWindowID id
,
183 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
184 int *attribList
, const wxPalette
& palette
):
187 m_glContext
= (wxGLContext
*) NULL
;
189 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
193 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
194 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
197 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
200 SetupPalette(palette
);
202 wxGLContext
*sharedContext
=0;
203 if (shared
) sharedContext
=shared
->GetContext();
204 m_glContext
= new wxGLContext(TRUE
, this, palette
, sharedContext
);
207 wxGLCanvas::~wxGLCanvas()
212 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
215 // Replaces wxWindow::Create functionality, since we need to use a different window class
216 bool wxGLCanvas::Create(wxWindow
*parent
, wxWindowID id
,
217 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
)
219 static bool registeredGLCanvasClass
= FALSE
;
221 // We have to register a special window class because we need
222 // the CS_OWNDC style for GLCanvas.
225 From Angel Popov <jumpo@bitex.com>
227 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
228 how this problem can be fixed:
230 "There are 5 common DCs available in Win95. These are aquired when you call
231 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
232 OWNDC flagged windows do not get their DC from the common DC pool, the issue
233 is they require 800 bytes each from the limited 64Kb local heap for GDI."
235 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
236 do), Win95 will actually "steal" it from you. MakeCurrent fails,
237 apparently, because Windows re-assigns the HDC to a different window. The
238 only way to prevent this, the only reliable means, is to set CS_OWNDC."
241 if (!registeredGLCanvasClass
)
245 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
247 // the fields which are common to all classes
248 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
249 wndclass
.cbClsExtra
= 0;
250 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
251 wndclass
.hInstance
= wxhInstance
;
252 wndclass
.hIcon
= (HICON
) NULL
;
253 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
254 wndclass
.lpszMenuName
= NULL
;
256 // Register the GLCanvas class name
257 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
258 wndclass
.lpszClassName
= wxGLCanvasClassName
;
259 wndclass
.style
= styleNormal
;
261 if ( !RegisterClass(&wndclass
) )
263 wxLogLastError("RegisterClass(wxGLCanvasClass)");
267 registeredGLCanvasClass
= TRUE
;
270 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
272 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
275 parent
->AddChild(this);
278 if ( style
& wxBORDER
)
279 msflags
|= WS_BORDER
;
280 if ( style
& wxTHICK_FRAME
)
281 msflags
|= WS_THICKFRAME
;
283 msflags
|= WS_CHILD
| WS_VISIBLE
;
284 if ( style
& wxCLIP_CHILDREN
)
285 msflags
|= WS_CLIPCHILDREN
;
288 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
290 // Even with extended styles, need to combine with WS_BORDER
291 // for them to look right.
292 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
293 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
295 msflags
|= WS_BORDER
;
298 // calculate the value to return from WM_GETDLGCODE handler
299 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
301 // want everything: i.e. all keys and WM_CHAR message
302 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
303 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
306 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
308 WidthDefault(size
.x
), HeightDefault(size
.y
),
309 msflags
, NULL
, exStyle
);
315 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
317 PIXELFORMATDESCRIPTOR pfd
= {
318 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
322 PFD_DOUBLEBUFFER
, /* support double-buffering */
323 PFD_TYPE_RGBA
, /* color type */
324 16, /* prefered color depth */
325 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
326 0, /* no alpha buffer */
327 0, /* alpha bits (ignored) */
328 0, /* no accumulation buffer */
329 0, 0, 0, 0, /* accum bits (ignored) */
330 16, /* depth buffer */
331 0, /* no stencil buffer */
332 0, /* no auxiliary buffers */
333 PFD_MAIN_PLANE
, /* main layer */
335 0, 0, 0, /* no layer, visible, damage masks */
339 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
340 if (pixelFormat
== 0) {
341 MessageBox(WindowFromDC((HDC
) m_hDC
), "ChoosePixelFormat failed.", "Error",
342 MB_ICONERROR
| MB_OK
);
346 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
347 MessageBox(WindowFromDC((HDC
) m_hDC
), "SetPixelFormat failed.", "Error",
348 MB_ICONERROR
| MB_OK
);
353 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
355 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
356 PIXELFORMATDESCRIPTOR pfd
;
358 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
360 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
370 if ( !m_palette
.Ok() )
372 m_palette
= CreateDefaultPalette();
377 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
378 RealizePalette((HDC
) m_hDC
);
382 wxPalette
wxGLCanvas::CreateDefaultPalette()
384 PIXELFORMATDESCRIPTOR pfd
;
386 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
388 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
390 paletteSize
= 1 << pfd
.cColorBits
;
393 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
394 pPal
->palVersion
= 0x300;
395 pPal
->palNumEntries
= paletteSize
;
397 /* build a simple RGB color palette */
399 int redMask
= (1 << pfd
.cRedBits
) - 1;
400 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
401 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
404 for (i
=0; i
<paletteSize
; ++i
) {
405 pPal
->palPalEntry
[i
].peRed
=
406 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
407 pPal
->palPalEntry
[i
].peGreen
=
408 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
409 pPal
->palPalEntry
[i
].peBlue
=
410 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
411 pPal
->palPalEntry
[i
].peFlags
= 0;
415 HPALETTE hPalette
= CreatePalette(pPal
);
419 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
424 void wxGLCanvas::SwapBuffers()
427 m_glContext
->SwapBuffers();
430 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
433 GetClientSize(& width
, & height
);
437 m_glContext
->SetCurrent();
439 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
440 glMatrixMode(GL_PROJECTION
);
442 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
443 glMatrixMode(GL_MODELVIEW
);
447 void wxGLCanvas::SetCurrent()
451 m_glContext
->SetCurrent();
455 void wxGLCanvas::SetColour(const char *colour
)
458 m_glContext
->SetColour(colour
);
461 // TODO: Have to have this called by parent frame (?)
462 // So we need wxFrame to call OnQueryNewPalette for all children...
463 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
465 /* realize palette if this is the current window */
466 if ( GetPalette()->Ok() ) {
467 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
468 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
469 ::RealizePalette((HDC
) GetHDC());
471 event
.SetPaletteRealized(TRUE
);
474 event
.SetPaletteRealized(FALSE
);
477 // I think this doesn't have to be propagated to child windows.
478 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
480 /* realize palette if this is *not* the current window */
482 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
484 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
485 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
486 ::RealizePalette((HDC
) GetHDC());
491 /* Give extensions proper function names. */
493 /* EXT_vertex_array */
494 void glArrayElementEXT(GLint i
)
498 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
502 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
504 #ifdef GL_EXT_vertex_array
505 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
509 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
513 (* proc
) (mode
, first
, count
);
517 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
521 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
525 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
529 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
531 #ifdef GL_EXT_vertex_array
532 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
536 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
540 (* proc
) (type
, stride
, count
, pointer
);
544 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
548 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
550 #ifdef GL_EXT_vertex_array
551 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
555 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
559 (* proc
) (size
, type
, stride
, count
, pointer
);
563 /* EXT_color_subtable */
564 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
568 /* EXT_color_table */
569 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
573 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
577 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
581 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
585 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
589 /* SGI_compiled_vertex_array */
590 void glLockArraysSGI(GLint first
, GLsizei count
)
594 void glUnlockArraysSGI()
599 /* SGI_cull_vertex */
600 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
604 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
609 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
613 /* SGI_index_material */
614 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
619 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)