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
, "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
, "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 usefull 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 static bool registeredGLCanvasClass
= FALSE
;
223 // We have to register a special window class because we need
224 // the CS_OWNDC style for GLCanvas.
227 From Angel Popov <jumpo@bitex.com>
229 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
230 how this problem can be fixed:
232 "There are 5 common DCs available in Win95. These are aquired when you call
233 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
234 OWNDC flagged windows do not get their DC from the common DC pool, the issue
235 is they require 800 bytes each from the limited 64Kb local heap for GDI."
237 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
238 do), Win95 will actually "steal" it from you. MakeCurrent fails,
239 apparently, because Windows re-assigns the HDC to a different window. The
240 only way to prevent this, the only reliable means, is to set CS_OWNDC."
243 if (!registeredGLCanvasClass
)
247 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
249 // the fields which are common to all classes
250 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
251 wndclass
.cbClsExtra
= 0;
252 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
253 wndclass
.hInstance
= wxhInstance
;
254 wndclass
.hIcon
= (HICON
) NULL
;
255 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
256 wndclass
.lpszMenuName
= NULL
;
258 // Register the GLCanvas class name
259 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
260 wndclass
.lpszClassName
= wxGLCanvasClassName
;
261 wndclass
.style
= styleNormal
;
263 if ( !RegisterClass(&wndclass
) )
265 wxLogLastError("RegisterClass(wxGLCanvasClass)");
269 registeredGLCanvasClass
= TRUE
;
272 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
274 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
277 parent
->AddChild(this);
280 if ( style
& wxBORDER
)
281 msflags
|= WS_BORDER
;
282 if ( style
& wxTHICK_FRAME
)
283 msflags
|= WS_THICKFRAME
;
285 msflags
|= WS_CHILD
| WS_VISIBLE
;
286 if ( style
& wxCLIP_CHILDREN
)
287 msflags
|= WS_CLIPCHILDREN
;
290 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
292 // Even with extended styles, need to combine with WS_BORDER
293 // for them to look right.
294 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
295 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
297 msflags
|= WS_BORDER
;
300 // calculate the value to return from WM_GETDLGCODE handler
301 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
303 // want everything: i.e. all keys and WM_CHAR message
304 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
305 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
308 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
310 WidthDefault(size
.x
), HeightDefault(size
.y
),
311 msflags
, NULL
, exStyle
);
317 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
319 PIXELFORMATDESCRIPTOR pfd
= {
320 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
324 PFD_DOUBLEBUFFER
, /* support double-buffering */
325 PFD_TYPE_RGBA
, /* color type */
326 16, /* prefered color depth */
327 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
328 0, /* no alpha buffer */
329 0, /* alpha bits (ignored) */
330 0, /* no accumulation buffer */
331 0, 0, 0, 0, /* accum bits (ignored) */
332 16, /* depth buffer */
333 0, /* no stencil buffer */
334 0, /* no auxiliary buffers */
335 PFD_MAIN_PLANE
, /* main layer */
337 0, 0, 0, /* no layer, visible, damage masks */
341 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
342 if (pixelFormat
== 0) {
343 MessageBox(WindowFromDC((HDC
) m_hDC
), "ChoosePixelFormat failed.", "Error",
344 MB_ICONERROR
| MB_OK
);
348 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
349 MessageBox(WindowFromDC((HDC
) m_hDC
), "SetPixelFormat failed.", "Error",
350 MB_ICONERROR
| MB_OK
);
355 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
357 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
358 PIXELFORMATDESCRIPTOR pfd
;
360 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
362 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
372 if ( !m_palette
.Ok() )
374 m_palette
= CreateDefaultPalette();
379 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
380 RealizePalette((HDC
) m_hDC
);
384 wxPalette
wxGLCanvas::CreateDefaultPalette()
386 PIXELFORMATDESCRIPTOR pfd
;
388 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
390 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
392 paletteSize
= 1 << pfd
.cColorBits
;
395 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
396 pPal
->palVersion
= 0x300;
397 pPal
->palNumEntries
= paletteSize
;
399 /* build a simple RGB color palette */
401 int redMask
= (1 << pfd
.cRedBits
) - 1;
402 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
403 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
406 for (i
=0; i
<paletteSize
; ++i
) {
407 pPal
->palPalEntry
[i
].peRed
=
408 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
409 pPal
->palPalEntry
[i
].peGreen
=
410 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
411 pPal
->palPalEntry
[i
].peBlue
=
412 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
413 pPal
->palPalEntry
[i
].peFlags
= 0;
417 HPALETTE hPalette
= CreatePalette(pPal
);
421 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
426 void wxGLCanvas::SwapBuffers()
429 m_glContext
->SwapBuffers();
432 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
435 GetClientSize(& width
, & height
);
439 m_glContext
->SetCurrent();
441 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
442 glMatrixMode(GL_PROJECTION
);
444 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
445 glMatrixMode(GL_MODELVIEW
);
449 void wxGLCanvas::SetCurrent()
453 m_glContext
->SetCurrent();
457 void wxGLCanvas::SetColour(const char *colour
)
460 m_glContext
->SetColour(colour
);
463 // TODO: Have to have this called by parent frame (?)
464 // So we need wxFrame to call OnQueryNewPalette for all children...
465 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
467 /* realize palette if this is the current window */
468 if ( GetPalette()->Ok() ) {
469 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
470 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
471 ::RealizePalette((HDC
) GetHDC());
473 event
.SetPaletteRealized(TRUE
);
476 event
.SetPaletteRealized(FALSE
);
479 // I think this doesn't have to be propagated to child windows.
480 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
482 /* realize palette if this is *not* the current window */
484 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
486 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
487 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
488 ::RealizePalette((HDC
) GetHDC());
493 /* Give extensions proper function names. */
495 /* EXT_vertex_array */
496 void glArrayElementEXT(GLint i
)
500 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
504 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
506 #ifdef GL_EXT_vertex_array
507 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
511 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
515 (* proc
) (mode
, first
, count
);
519 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
523 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
527 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
531 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
533 #ifdef GL_EXT_vertex_array
534 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
538 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
542 (* proc
) (type
, stride
, count
, pointer
);
546 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
550 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
552 #ifdef GL_EXT_vertex_array
553 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
557 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
561 (* proc
) (size
, type
, stride
, count
, pointer
);
565 /* EXT_color_subtable */
566 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
570 /* EXT_color_table */
571 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
575 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
579 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
583 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
587 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
591 /* SGI_compiled_vertex_array */
592 void glLockArraysSGI(GLint first
, GLsizei count
)
596 void glUnlockArraysSGI()
601 /* SGI_cull_vertex */
602 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
606 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
611 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
615 /* SGI_index_material */
616 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
621 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)