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__)
26 #include <wx/msw/private.h>
30 wxChar wxGLCanvasClassName
[] = wxT("wxGLCanvasClass");
32 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
33 WPARAM wParam
, LPARAM lParam
);
36 * GLContext implementation
39 wxGLContext::wxGLContext(bool isRGB
, wxGLCanvas
*win
, const wxPalette
& palette
)
43 m_hDC
= win
->GetHDC();
45 m_glContext
= wglCreateContext((HDC
) m_hDC
);
46 wxCHECK_RET( m_glContext
, "Couldn't create OpenGl context" );
48 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
51 wxGLContext::wxGLContext(
52 bool isRGB
, wxGLCanvas
*win
,
53 const wxPalette
& palette
,
54 const wxGLContext
*other
/* for sharing display lists */
59 m_hDC
= win
->GetHDC();
61 m_glContext
= wglCreateContext((HDC
) m_hDC
);
62 wxCHECK_RET( m_glContext
, "Couldn't create OpenGl context" );
65 wglShareLists( other
->m_glContext
, m_glContext
);
67 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
70 wxGLContext::~wxGLContext()
74 wglMakeCurrent(NULL
, NULL
);
75 wglDeleteContext(m_glContext
);
79 void wxGLContext::SwapBuffers()
83 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
84 ::SwapBuffers((HDC
) m_hDC
); //blits the backbuffer into DC
88 void wxGLContext::SetCurrent()
92 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
96 setupPixelFormat(hDC);
101 void wxGLContext::SetColour(const char *colour
)
106 wxColour
*col
= wxTheColourDatabase
->FindColour(colour
);
109 r
= (float)(col
->Red()/256.0);
110 g
= (float)(col
->Green()/256.0);
111 b
= (float)(col
->Blue()/256.0);
118 * wxGLCanvas implementation
121 IMPLEMENT_CLASS(wxGLCanvas
, wxScrolledWindow
)
123 BEGIN_EVENT_TABLE(wxGLCanvas
, wxScrolledWindow
)
124 EVT_SIZE(wxGLCanvas::OnSize
)
125 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged
)
126 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette
)
129 wxGLCanvas::wxGLCanvas(wxWindow
*parent
, wxWindowID id
,
130 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
131 int *attribList
/* not used yet! */, const wxPalette
& palette
):
132 wxScrolledWindow(parent
, id
, pos
, size
, style
, name
)
134 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
137 SetupPalette(palette
);
139 m_glContext
= new wxGLContext(TRUE
, this, palette
);
142 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
143 const wxGLContext
*shared
, wxWindowID id
,
144 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
145 int *attribList
, const wxPalette
& palette
)
147 // : wxScrolledWindow(parent, id, pos, size, style, name)
149 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
153 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
154 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
157 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
160 SetupPalette(palette
);
162 m_glContext
= new wxGLContext(TRUE
, this, palette
, shared
);
165 wxGLCanvas::~wxGLCanvas()
170 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
173 // Replaces wxWindow::Create functionality, since we need to use a different window class
174 bool wxGLCanvas::Create(wxWindow
*parent
, wxWindowID id
,
175 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
)
177 static bool registeredGLCanvasClass
= FALSE
;
179 // We have to register a special window class because we need
180 // the CS_OWNDC style for GLCanvas.
183 From Angel Popov <jumpo@bitex.com>
185 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
186 how this problem can be fixed:
188 "There are 5 common DCs available in Win95. These are aquired when you call
189 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
190 OWNDC flagged windows do not get their DC from the common DC pool, the issue
191 is they require 800 bytes each from the limited 64Kb local heap for GDI."
193 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
194 do), Win95 will actually "steal" it from you. MakeCurrent fails,
195 apparently, because Windows re-assigns the HDC to a different window. The
196 only way to prevent this, the only reliable means, is to set CS_OWNDC."
199 if (!registeredGLCanvasClass
)
203 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
205 // the fields which are common to all classes
206 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
207 wndclass
.cbClsExtra
= 0;
208 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
209 wndclass
.hInstance
= wxhInstance
;
210 wndclass
.hIcon
= (HICON
) NULL
;
211 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
212 wndclass
.lpszMenuName
= NULL
;
214 // Register the GLCanvas class name
215 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
216 wndclass
.lpszClassName
= wxGLCanvasClassName
;
217 wndclass
.style
= styleNormal
;
219 if ( !RegisterClass(&wndclass
) )
221 wxLogLastError("RegisterClass(wxGLCanvasClass)");
225 registeredGLCanvasClass
= TRUE
;
228 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
230 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
233 parent
->AddChild(this);
236 if ( style
& wxBORDER
)
237 msflags
|= WS_BORDER
;
238 if ( style
& wxTHICK_FRAME
)
239 msflags
|= WS_THICKFRAME
;
241 msflags
|= WS_CHILD
| WS_VISIBLE
;
242 if ( style
& wxCLIP_CHILDREN
)
243 msflags
|= WS_CLIPCHILDREN
;
246 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
248 // Even with extended styles, need to combine with WS_BORDER
249 // for them to look right.
250 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
251 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
253 msflags
|= WS_BORDER
;
256 // calculate the value to return from WM_GETDLGCODE handler
257 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
259 // want everything: i.e. all keys and WM_CHAR message
260 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
261 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
264 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
266 WidthDefault(size
.x
), HeightDefault(size
.y
),
267 msflags
, NULL
, exStyle
);
273 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
275 PIXELFORMATDESCRIPTOR pfd
= {
276 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
280 PFD_DOUBLEBUFFER
, /* support double-buffering */
281 PFD_TYPE_RGBA
, /* color type */
282 16, /* prefered color depth */
283 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
284 0, /* no alpha buffer */
285 0, /* alpha bits (ignored) */
286 0, /* no accumulation buffer */
287 0, 0, 0, 0, /* accum bits (ignored) */
288 16, /* depth buffer */
289 0, /* no stencil buffer */
290 0, /* no auxiliary buffers */
291 PFD_MAIN_PLANE
, /* main layer */
293 0, 0, 0, /* no layer, visible, damage masks */
297 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
298 if (pixelFormat
== 0) {
299 MessageBox(WindowFromDC((HDC
) m_hDC
), "ChoosePixelFormat failed.", "Error",
300 MB_ICONERROR
| MB_OK
);
304 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
305 MessageBox(WindowFromDC((HDC
) m_hDC
), "SetPixelFormat failed.", "Error",
306 MB_ICONERROR
| MB_OK
);
311 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
313 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
314 PIXELFORMATDESCRIPTOR pfd
;
316 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
318 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
328 if ( !m_palette
.Ok() )
330 m_palette
= CreateDefaultPalette();
335 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
336 RealizePalette((HDC
) m_hDC
);
340 wxPalette
wxGLCanvas::CreateDefaultPalette()
342 PIXELFORMATDESCRIPTOR pfd
;
344 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
346 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
348 paletteSize
= 1 << pfd
.cColorBits
;
351 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
352 pPal
->palVersion
= 0x300;
353 pPal
->palNumEntries
= paletteSize
;
355 /* build a simple RGB color palette */
357 int redMask
= (1 << pfd
.cRedBits
) - 1;
358 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
359 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
362 for (i
=0; i
<paletteSize
; ++i
) {
363 pPal
->palPalEntry
[i
].peRed
=
364 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
365 pPal
->palPalEntry
[i
].peGreen
=
366 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
367 pPal
->palPalEntry
[i
].peBlue
=
368 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
369 pPal
->palPalEntry
[i
].peFlags
= 0;
373 HPALETTE hPalette
= CreatePalette(pPal
);
377 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
382 void wxGLCanvas::SwapBuffers()
385 m_glContext
->SwapBuffers();
388 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
391 GetClientSize(& width
, & height
);
395 m_glContext
->SetCurrent();
397 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
398 glMatrixMode(GL_PROJECTION
);
400 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
401 glMatrixMode(GL_MODELVIEW
);
405 void wxGLCanvas::SetCurrent()
409 m_glContext
->SetCurrent();
413 void wxGLCanvas::SetColour(const char *colour
)
416 m_glContext
->SetColour(colour
);
419 // TODO: Have to have this called by parent frame (?)
420 // So we need wxFrame to call OnQueryNewPalette for all children...
421 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
423 /* realize palette if this is the current window */
424 if ( GetPalette()->Ok() ) {
425 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
426 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
427 ::RealizePalette((HDC
) GetHDC());
429 event
.SetPaletteRealized(TRUE
);
432 event
.SetPaletteRealized(FALSE
);
435 // I think this doesn't have to be propagated to child windows.
436 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
438 /* realize palette if this is *not* the current window */
440 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
442 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
443 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
444 ::RealizePalette((HDC
) GetHDC());
449 /* Give extensions proper function names. */
451 /* EXT_vertex_array */
452 void glArrayElementEXT(GLint i
)
456 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
460 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
462 #ifdef GL_EXT_vertex_array
463 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
467 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
471 (* proc
) (mode
, first
, count
);
475 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
479 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
483 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
487 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
489 #ifdef GL_EXT_vertex_array
490 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
494 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
498 (* proc
) (type
, stride
, count
, pointer
);
502 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
506 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
508 #ifdef GL_EXT_vertex_array
509 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
513 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
517 (* proc
) (size
, type
, stride
, count
, pointer
);
521 /* EXT_color_subtable */
522 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
526 /* EXT_color_table */
527 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
531 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
535 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
539 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
543 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
547 /* SGI_compiled_vertex_array */
548 void glLockArraysSGI(GLint first
, GLsizei count
)
552 void glUnlockArraysSGI()
557 /* SGI_cull_vertex */
558 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
562 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
567 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
571 /* SGI_index_material */
572 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
577 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)