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
);
153 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
154 const wxGLContext
*shared
, wxWindowID id
,
155 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
156 int *attribList
, const wxPalette
& palette
)
159 m_glContext
= (wxGLContext
*) NULL
;
161 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
165 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
166 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
169 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
172 SetupPalette(palette
);
174 m_glContext
= new wxGLContext(TRUE
, this, palette
, shared
);
177 wxGLCanvas::~wxGLCanvas()
182 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
185 // Replaces wxWindow::Create functionality, since we need to use a different window class
186 bool wxGLCanvas::Create(wxWindow
*parent
, wxWindowID id
,
187 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
)
189 static bool registeredGLCanvasClass
= FALSE
;
191 // We have to register a special window class because we need
192 // the CS_OWNDC style for GLCanvas.
195 From Angel Popov <jumpo@bitex.com>
197 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
198 how this problem can be fixed:
200 "There are 5 common DCs available in Win95. These are aquired when you call
201 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
202 OWNDC flagged windows do not get their DC from the common DC pool, the issue
203 is they require 800 bytes each from the limited 64Kb local heap for GDI."
205 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
206 do), Win95 will actually "steal" it from you. MakeCurrent fails,
207 apparently, because Windows re-assigns the HDC to a different window. The
208 only way to prevent this, the only reliable means, is to set CS_OWNDC."
211 if (!registeredGLCanvasClass
)
215 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
217 // the fields which are common to all classes
218 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
219 wndclass
.cbClsExtra
= 0;
220 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
221 wndclass
.hInstance
= wxhInstance
;
222 wndclass
.hIcon
= (HICON
) NULL
;
223 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
224 wndclass
.lpszMenuName
= NULL
;
226 // Register the GLCanvas class name
227 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
228 wndclass
.lpszClassName
= wxGLCanvasClassName
;
229 wndclass
.style
= styleNormal
;
231 if ( !RegisterClass(&wndclass
) )
233 wxLogLastError("RegisterClass(wxGLCanvasClass)");
237 registeredGLCanvasClass
= TRUE
;
240 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
242 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
245 parent
->AddChild(this);
248 if ( style
& wxBORDER
)
249 msflags
|= WS_BORDER
;
250 if ( style
& wxTHICK_FRAME
)
251 msflags
|= WS_THICKFRAME
;
253 msflags
|= WS_CHILD
| WS_VISIBLE
;
254 if ( style
& wxCLIP_CHILDREN
)
255 msflags
|= WS_CLIPCHILDREN
;
258 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
260 // Even with extended styles, need to combine with WS_BORDER
261 // for them to look right.
262 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
263 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
265 msflags
|= WS_BORDER
;
268 // calculate the value to return from WM_GETDLGCODE handler
269 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
271 // want everything: i.e. all keys and WM_CHAR message
272 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
273 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
276 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
278 WidthDefault(size
.x
), HeightDefault(size
.y
),
279 msflags
, NULL
, exStyle
);
285 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
287 PIXELFORMATDESCRIPTOR pfd
= {
288 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
292 PFD_DOUBLEBUFFER
, /* support double-buffering */
293 PFD_TYPE_RGBA
, /* color type */
294 16, /* prefered color depth */
295 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
296 0, /* no alpha buffer */
297 0, /* alpha bits (ignored) */
298 0, /* no accumulation buffer */
299 0, 0, 0, 0, /* accum bits (ignored) */
300 16, /* depth buffer */
301 0, /* no stencil buffer */
302 0, /* no auxiliary buffers */
303 PFD_MAIN_PLANE
, /* main layer */
305 0, 0, 0, /* no layer, visible, damage masks */
309 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
310 if (pixelFormat
== 0) {
311 MessageBox(WindowFromDC((HDC
) m_hDC
), "ChoosePixelFormat failed.", "Error",
312 MB_ICONERROR
| MB_OK
);
316 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
317 MessageBox(WindowFromDC((HDC
) m_hDC
), "SetPixelFormat failed.", "Error",
318 MB_ICONERROR
| MB_OK
);
323 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
325 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
326 PIXELFORMATDESCRIPTOR pfd
;
328 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
330 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
340 if ( !m_palette
.Ok() )
342 m_palette
= CreateDefaultPalette();
347 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
348 RealizePalette((HDC
) m_hDC
);
352 wxPalette
wxGLCanvas::CreateDefaultPalette()
354 PIXELFORMATDESCRIPTOR pfd
;
356 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
358 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
360 paletteSize
= 1 << pfd
.cColorBits
;
363 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
364 pPal
->palVersion
= 0x300;
365 pPal
->palNumEntries
= paletteSize
;
367 /* build a simple RGB color palette */
369 int redMask
= (1 << pfd
.cRedBits
) - 1;
370 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
371 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
374 for (i
=0; i
<paletteSize
; ++i
) {
375 pPal
->palPalEntry
[i
].peRed
=
376 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
377 pPal
->palPalEntry
[i
].peGreen
=
378 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
379 pPal
->palPalEntry
[i
].peBlue
=
380 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
381 pPal
->palPalEntry
[i
].peFlags
= 0;
385 HPALETTE hPalette
= CreatePalette(pPal
);
389 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
394 void wxGLCanvas::SwapBuffers()
397 m_glContext
->SwapBuffers();
400 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
403 GetClientSize(& width
, & height
);
407 m_glContext
->SetCurrent();
409 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
410 glMatrixMode(GL_PROJECTION
);
412 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
413 glMatrixMode(GL_MODELVIEW
);
417 void wxGLCanvas::SetCurrent()
421 m_glContext
->SetCurrent();
425 void wxGLCanvas::SetColour(const char *colour
)
428 m_glContext
->SetColour(colour
);
431 // TODO: Have to have this called by parent frame (?)
432 // So we need wxFrame to call OnQueryNewPalette for all children...
433 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
435 /* realize palette if this is the current window */
436 if ( GetPalette()->Ok() ) {
437 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
438 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
439 ::RealizePalette((HDC
) GetHDC());
441 event
.SetPaletteRealized(TRUE
);
444 event
.SetPaletteRealized(FALSE
);
447 // I think this doesn't have to be propagated to child windows.
448 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
450 /* realize palette if this is *not* the current window */
452 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
454 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
455 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
456 ::RealizePalette((HDC
) GetHDC());
461 /* Give extensions proper function names. */
463 /* EXT_vertex_array */
464 void glArrayElementEXT(GLint i
)
468 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
472 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
474 #ifdef GL_EXT_vertex_array
475 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
479 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
483 (* proc
) (mode
, first
, count
);
487 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
491 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
495 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
499 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
501 #ifdef GL_EXT_vertex_array
502 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
506 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
510 (* proc
) (type
, stride
, count
, pointer
);
514 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
518 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
520 #ifdef GL_EXT_vertex_array
521 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
525 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
529 (* proc
) (size
, type
, stride
, count
, pointer
);
533 /* EXT_color_subtable */
534 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
538 /* EXT_color_table */
539 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
543 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
547 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
551 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
555 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
559 /* SGI_compiled_vertex_array */
560 void glLockArraysSGI(GLint first
, GLsizei count
)
564 void glUnlockArraysSGI()
569 /* SGI_cull_vertex */
570 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
574 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
579 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
583 /* SGI_index_material */
584 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
589 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)