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
):
134 m_glContext
= (wxGLContext
*) NULL
;
136 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
140 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
141 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
144 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
147 SetupPalette(palette
);
149 m_glContext
= new wxGLContext(TRUE
, this, palette
);
152 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
153 const wxGLContext
*shared
, wxWindowID id
,
154 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
155 int *attribList
, const wxPalette
& palette
)
158 m_glContext
= (wxGLContext
*) NULL
;
160 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
164 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
165 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
168 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
171 SetupPalette(palette
);
173 m_glContext
= new wxGLContext(TRUE
, this, palette
, shared
);
176 // Not very usefull for wxMSW, but this is to be wxGTK compliant
178 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, const wxGLCanvas
*shared
, wxWindowID id
,
179 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
180 int *attribList
, const wxPalette
& palette
):
183 m_glContext
= (wxGLContext
*) NULL
;
185 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
189 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
190 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
193 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
196 SetupPalette(palette
);
198 wxGLContext
*sharedContext
=0;
199 if (shared
) sharedContext
=shared
->GetContext();
200 m_glContext
= new wxGLContext(TRUE
, this, palette
, sharedContext
);
203 wxGLCanvas::~wxGLCanvas()
208 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
211 // Replaces wxWindow::Create functionality, since we need to use a different window class
212 bool wxGLCanvas::Create(wxWindow
*parent
, wxWindowID id
,
213 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
)
215 static bool registeredGLCanvasClass
= FALSE
;
217 // We have to register a special window class because we need
218 // the CS_OWNDC style for GLCanvas.
221 From Angel Popov <jumpo@bitex.com>
223 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
224 how this problem can be fixed:
226 "There are 5 common DCs available in Win95. These are aquired when you call
227 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
228 OWNDC flagged windows do not get their DC from the common DC pool, the issue
229 is they require 800 bytes each from the limited 64Kb local heap for GDI."
231 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
232 do), Win95 will actually "steal" it from you. MakeCurrent fails,
233 apparently, because Windows re-assigns the HDC to a different window. The
234 only way to prevent this, the only reliable means, is to set CS_OWNDC."
237 if (!registeredGLCanvasClass
)
241 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
243 // the fields which are common to all classes
244 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
245 wndclass
.cbClsExtra
= 0;
246 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
247 wndclass
.hInstance
= wxhInstance
;
248 wndclass
.hIcon
= (HICON
) NULL
;
249 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
250 wndclass
.lpszMenuName
= NULL
;
252 // Register the GLCanvas class name
253 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
254 wndclass
.lpszClassName
= wxGLCanvasClassName
;
255 wndclass
.style
= styleNormal
;
257 if ( !RegisterClass(&wndclass
) )
259 wxLogLastError("RegisterClass(wxGLCanvasClass)");
263 registeredGLCanvasClass
= TRUE
;
266 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
268 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
271 parent
->AddChild(this);
274 if ( style
& wxBORDER
)
275 msflags
|= WS_BORDER
;
276 if ( style
& wxTHICK_FRAME
)
277 msflags
|= WS_THICKFRAME
;
279 msflags
|= WS_CHILD
| WS_VISIBLE
;
280 if ( style
& wxCLIP_CHILDREN
)
281 msflags
|= WS_CLIPCHILDREN
;
284 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
286 // Even with extended styles, need to combine with WS_BORDER
287 // for them to look right.
288 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
289 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
291 msflags
|= WS_BORDER
;
294 // calculate the value to return from WM_GETDLGCODE handler
295 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
297 // want everything: i.e. all keys and WM_CHAR message
298 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
299 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
302 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
304 WidthDefault(size
.x
), HeightDefault(size
.y
),
305 msflags
, NULL
, exStyle
);
311 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
313 PIXELFORMATDESCRIPTOR pfd
= {
314 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
318 PFD_DOUBLEBUFFER
, /* support double-buffering */
319 PFD_TYPE_RGBA
, /* color type */
320 16, /* prefered color depth */
321 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
322 0, /* no alpha buffer */
323 0, /* alpha bits (ignored) */
324 0, /* no accumulation buffer */
325 0, 0, 0, 0, /* accum bits (ignored) */
326 16, /* depth buffer */
327 0, /* no stencil buffer */
328 0, /* no auxiliary buffers */
329 PFD_MAIN_PLANE
, /* main layer */
331 0, 0, 0, /* no layer, visible, damage masks */
335 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
336 if (pixelFormat
== 0) {
337 MessageBox(WindowFromDC((HDC
) m_hDC
), "ChoosePixelFormat failed.", "Error",
338 MB_ICONERROR
| MB_OK
);
342 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
343 MessageBox(WindowFromDC((HDC
) m_hDC
), "SetPixelFormat failed.", "Error",
344 MB_ICONERROR
| MB_OK
);
349 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
351 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
352 PIXELFORMATDESCRIPTOR pfd
;
354 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
356 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
366 if ( !m_palette
.Ok() )
368 m_palette
= CreateDefaultPalette();
373 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
374 RealizePalette((HDC
) m_hDC
);
378 wxPalette
wxGLCanvas::CreateDefaultPalette()
380 PIXELFORMATDESCRIPTOR pfd
;
382 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
384 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
386 paletteSize
= 1 << pfd
.cColorBits
;
389 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
390 pPal
->palVersion
= 0x300;
391 pPal
->palNumEntries
= paletteSize
;
393 /* build a simple RGB color palette */
395 int redMask
= (1 << pfd
.cRedBits
) - 1;
396 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
397 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
400 for (i
=0; i
<paletteSize
; ++i
) {
401 pPal
->palPalEntry
[i
].peRed
=
402 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
403 pPal
->palPalEntry
[i
].peGreen
=
404 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
405 pPal
->palPalEntry
[i
].peBlue
=
406 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
407 pPal
->palPalEntry
[i
].peFlags
= 0;
411 HPALETTE hPalette
= CreatePalette(pPal
);
415 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
420 void wxGLCanvas::SwapBuffers()
423 m_glContext
->SwapBuffers();
426 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
429 GetClientSize(& width
, & height
);
433 m_glContext
->SetCurrent();
435 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
436 glMatrixMode(GL_PROJECTION
);
438 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
439 glMatrixMode(GL_MODELVIEW
);
443 void wxGLCanvas::SetCurrent()
447 m_glContext
->SetCurrent();
451 void wxGLCanvas::SetColour(const char *colour
)
454 m_glContext
->SetColour(colour
);
457 // TODO: Have to have this called by parent frame (?)
458 // So we need wxFrame to call OnQueryNewPalette for all children...
459 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
461 /* realize palette if this is the current window */
462 if ( GetPalette()->Ok() ) {
463 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
464 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
465 ::RealizePalette((HDC
) GetHDC());
467 event
.SetPaletteRealized(TRUE
);
470 event
.SetPaletteRealized(FALSE
);
473 // I think this doesn't have to be propagated to child windows.
474 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
476 /* realize palette if this is *not* the current window */
478 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
480 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
481 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
482 ::RealizePalette((HDC
) GetHDC());
487 /* Give extensions proper function names. */
489 /* EXT_vertex_array */
490 void glArrayElementEXT(GLint i
)
494 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
498 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
500 #ifdef GL_EXT_vertex_array
501 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
505 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
509 (* proc
) (mode
, first
, count
);
513 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
517 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
521 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
525 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
527 #ifdef GL_EXT_vertex_array
528 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
532 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
536 (* proc
) (type
, stride
, count
, pointer
);
540 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
544 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
546 #ifdef GL_EXT_vertex_array
547 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
551 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
555 (* proc
) (size
, type
, stride
, count
, pointer
);
559 /* EXT_color_subtable */
560 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
564 /* EXT_color_table */
565 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
569 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
573 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
577 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
581 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
585 /* SGI_compiled_vertex_array */
586 void glLockArraysSGI(GLint first
, GLsizei count
)
590 void glUnlockArraysSGI()
595 /* SGI_cull_vertex */
596 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
600 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
605 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
609 /* SGI_index_material */
610 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
615 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)