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 #define wxUSE_GLCANVAS 1
33 #include <wx/msw/private.h>
34 #include <wx/settings.h>
37 #include "myglcanvas.h"
39 wxChar wxGLCanvasClassName
[] = wxT("wxGLCanvasClass");
41 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
42 WPARAM wParam
, LPARAM lParam
);
45 * GLContext implementation
48 wxGLContext::wxGLContext(bool isRGB
, wxGLCanvas
*win
, const wxPalette
& palette
)
52 m_hDC
= win
->GetHDC();
54 m_glContext
= wglCreateContext((HDC
) m_hDC
);
55 wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGl context") );
57 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
60 wxGLContext::wxGLContext(
61 bool isRGB
, wxGLCanvas
*win
,
62 const wxPalette
& palette
,
63 const wxGLContext
*other
/* for sharing display lists */
68 m_hDC
= win
->GetHDC();
70 m_glContext
= wglCreateContext((HDC
) m_hDC
);
71 wxCHECK_RET( m_glContext
, wxT("Couldn't create OpenGl context") );
74 wglShareLists( other
->m_glContext
, m_glContext
);
76 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
79 wxGLContext::~wxGLContext()
83 wglMakeCurrent(NULL
, NULL
);
84 wglDeleteContext(m_glContext
);
88 void wxGLContext::SwapBuffers()
92 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
93 ::SwapBuffers((HDC
) m_hDC
); //blits the backbuffer into DC
97 void wxGLContext::SetCurrent()
101 wglMakeCurrent((HDC
) m_hDC
, m_glContext
);
105 setupPixelFormat(hDC);
110 void wxGLContext::SetColour(const char *colour
)
115 wxColour
*col
= wxTheColourDatabase
->FindColour(colour
);
118 r
= (float)(col
->Red()/256.0);
119 g
= (float)(col
->Green()/256.0);
120 b
= (float)(col
->Blue()/256.0);
127 * wxGLCanvas implementation
130 IMPLEMENT_CLASS(wxGLCanvas
, wxScrolledWindow
)
132 BEGIN_EVENT_TABLE(wxGLCanvas
, wxScrolledWindow
)
133 EVT_SIZE(wxGLCanvas::OnSize
)
134 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged
)
135 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette
)
138 wxGLCanvas::wxGLCanvas(wxWindow
*parent
, wxWindowID id
,
139 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
140 int *attribList
, const wxPalette
& palette
) : wxScrolledWindow()
142 m_glContext
= (wxGLContext
*) NULL
;
144 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
148 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
149 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
152 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
154 SetupPixelFormat(attribList
);
155 SetupPalette(palette
);
157 m_glContext
= new wxGLContext(TRUE
, this, palette
);
160 wxGLCanvas::wxGLCanvas( wxWindow
*parent
,
161 const wxGLContext
*shared
, wxWindowID id
,
162 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
163 int *attribList
, const wxPalette
& palette
)
166 m_glContext
= (wxGLContext
*) NULL
;
168 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
172 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
173 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
176 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
178 SetupPixelFormat(attribList
);
179 SetupPalette(palette
);
181 m_glContext
= new wxGLContext(TRUE
, this, palette
, shared
);
184 // Not very useful for wxMSW, but this is to be wxGTK compliant
186 wxGLCanvas::wxGLCanvas( wxWindow
*parent
, const wxGLCanvas
*shared
, wxWindowID id
,
187 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
,
188 int *attribList
, const wxPalette
& palette
):
191 m_glContext
= (wxGLContext
*) NULL
;
193 bool ret
= Create(parent
, id
, pos
, size
, style
, name
);
197 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
));
198 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
));
201 m_hDC
= (WXHDC
) ::GetDC((HWND
) GetHWND());
203 SetupPixelFormat(attribList
);
204 SetupPalette(palette
);
206 wxGLContext
*sharedContext
=0;
207 if (shared
) sharedContext
=shared
->GetContext();
208 m_glContext
= new wxGLContext(TRUE
, this, palette
, sharedContext
);
211 wxGLCanvas::~wxGLCanvas()
216 ::ReleaseDC((HWND
) GetHWND(), (HDC
) m_hDC
);
219 // Replaces wxWindow::Create functionality, since we need to use a different window class
220 bool wxGLCanvas::Create(wxWindow
*parent
, wxWindowID id
,
221 const wxPoint
& pos
, const wxSize
& size
, long style
, const wxString
& name
)
224 Suggestion from Kelly Brock <kbrock@8cs.com> (not yet implemented):
226 OpenGL corruption fix is simple assuming it doesn't screw anything else
227 up. Add the following line to the top of the create function:
229 wxSize parentSize = GetClientSize();
231 All locations within the function that use 'size' are changed to
233 The above corrects the initial display corruption with the GeForce and
234 TNT2, not sure about other NVidia cards yet.
237 static bool registeredGLCanvasClass
= FALSE
;
239 // We have to register a special window class because we need
240 // the CS_OWNDC style for GLCanvas.
243 From Angel Popov <jumpo@bitex.com>
245 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
246 how this problem can be fixed:
248 "There are 5 common DCs available in Win95. These are aquired when you call
249 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
250 OWNDC flagged windows do not get their DC from the common DC pool, the issue
251 is they require 800 bytes each from the limited 64Kb local heap for GDI."
253 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
254 do), Win95 will actually "steal" it from you. MakeCurrent fails,
255 apparently, because Windows re-assigns the HDC to a different window. The
256 only way to prevent this, the only reliable means, is to set CS_OWNDC."
259 if (!registeredGLCanvasClass
)
263 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
| CS_OWNDC
;
265 // the fields which are common to all classes
266 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
267 wndclass
.cbClsExtra
= 0;
268 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
269 wndclass
.hInstance
= wxhInstance
;
270 wndclass
.hIcon
= (HICON
) NULL
;
271 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
272 wndclass
.lpszMenuName
= NULL
;
274 // Register the GLCanvas class name
275 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
276 wndclass
.lpszClassName
= wxGLCanvasClassName
;
277 wndclass
.style
= styleNormal
;
279 if ( !RegisterClass(&wndclass
) )
281 wxLogLastError(wxT("RegisterClass(wxGLCanvasClass)"));
285 registeredGLCanvasClass
= TRUE
;
288 wxCHECK_MSG( parent
, FALSE
, wxT("can't create wxWindow without parent") );
290 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
293 parent
->AddChild(this);
296 if ( style
& wxBORDER
)
297 msflags
|= WS_BORDER
;
298 if ( style
& wxTHICK_FRAME
)
299 msflags
|= WS_THICKFRAME
;
302 A general rule with OpenGL and Win32 is that any window that will have a
303 HGLRC built for it must have two flags: WS_CLIPCHILDREN & WS_CLIPSIBLINGS.
304 You can find references about this within the knowledge base and most OpenGL
305 books that contain the wgl function descriptions.
308 msflags
|= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
;
309 // if ( style & wxCLIP_CHILDREN )
310 // msflags |= WS_CLIPCHILDREN;
311 msflags
|= WS_CLIPCHILDREN
;
314 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
);
316 // Even with extended styles, need to combine with WS_BORDER
317 // for them to look right.
318 if ( want3D
|| (m_windowStyle
& wxSIMPLE_BORDER
) || (m_windowStyle
& wxRAISED_BORDER
) ||
319 (m_windowStyle
& wxSUNKEN_BORDER
) || (m_windowStyle
& wxDOUBLE_BORDER
))
321 msflags
|= WS_BORDER
;
324 // calculate the value to return from WM_GETDLGCODE handler
325 if ( GetWindowStyleFlag() & wxWANTS_CHARS
)
327 // want everything: i.e. all keys and WM_CHAR message
328 m_lDlgCode
= DLGC_WANTARROWS
| DLGC_WANTCHARS
|
329 DLGC_WANTTAB
| DLGC_WANTMESSAGE
;
332 MSWCreate(m_windowId
, parent
, wxGLCanvasClassName
, this, NULL
,
334 WidthDefault(size
.x
), HeightDefault(size
.y
),
335 msflags
, NULL
, exStyle
);
340 void wxGLCanvas::SetupPixelFormat(int *attribList
) // (HDC hDC)
343 PIXELFORMATDESCRIPTOR pfd
= {
344 sizeof(PIXELFORMATDESCRIPTOR
), /* size */
348 PFD_DOUBLEBUFFER
, /* support double-buffering */
349 PFD_TYPE_RGBA
, /* color type */
350 16, /* prefered color depth */
351 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
352 0, /* no alpha buffer */
353 0, /* alpha bits (ignored) */
354 0, /* no accumulation buffer */
355 0, 0, 0, 0, /* accum bits (ignored) */
356 16, /* depth buffer */
357 0, /* no stencil buffer */
358 0, /* no auxiliary buffers */
359 PFD_MAIN_PLANE
, /* main layer */
361 0, 0, 0, /* no layer, visible, damage masks */
365 pfd
.dwFlags
&= ~PFD_DOUBLEBUFFER
;
366 pfd
.iPixelType
= PFD_TYPE_COLORINDEX
;
370 while( (attribList
[arg
]!=0) )
372 switch( attribList
[arg
++] )
375 pfd
.iPixelType
= PFD_TYPE_RGBA
;
377 case WX_GL_BUFFER_SIZE
:
378 pfd
.cColorBits
= attribList
[arg
++];
381 // this member looks like it may be obsolete
382 if (attribList
[arg
] > 0) {
383 pfd
.iLayerType
= PFD_OVERLAY_PLANE
;
384 } else if (attribList
[arg
] < 0) {
385 pfd
.iLayerType
= PFD_UNDERLAY_PLANE
;
387 pfd
.iLayerType
= PFD_MAIN_PLANE
;
391 case WX_GL_DOUBLEBUFFER
:
392 pfd
.dwFlags
|= PFD_DOUBLEBUFFER
;
395 pfd
.dwFlags
|= PFD_STEREO
;
397 case WX_GL_AUX_BUFFERS
:
398 pfd
.cAuxBuffers
= attribList
[arg
++];
401 pfd
.cColorBits
+= (pfd
.cRedBits
= attribList
[arg
++]);
403 case WX_GL_MIN_GREEN
:
404 pfd
.cColorBits
+= (pfd
.cGreenBits
= attribList
[arg
++]);
407 pfd
.cColorBits
+= (pfd
.cBlueBits
= attribList
[arg
++]);
409 case WX_GL_MIN_ALPHA
:
410 // doesn't count in cColorBits
411 pfd
.cAlphaBits
= attribList
[arg
++];
413 case WX_GL_DEPTH_SIZE
:
414 pfd
.cDepthBits
= attribList
[arg
++];
416 case WX_GL_STENCIL_SIZE
:
417 pfd
.cStencilBits
= attribList
[arg
++];
419 case WX_GL_MIN_ACCUM_RED
:
420 pfd
.cAccumBits
+= (pfd
.cAccumRedBits
= attribList
[arg
++]);
422 case WX_GL_MIN_ACCUM_GREEN
:
423 pfd
.cAccumBits
+= (pfd
.cAccumGreenBits
= attribList
[arg
++]);
425 case WX_GL_MIN_ACCUM_BLUE
:
426 pfd
.cAccumBits
+= (pfd
.cAccumBlueBits
= attribList
[arg
++]);
428 case WX_GL_MIN_ACCUM_ALPHA
:
429 pfd
.cAccumBits
+= (pfd
.cAccumAlphaBits
= attribList
[arg
++]);
436 pixelFormat
= ChoosePixelFormat((HDC
) m_hDC
, &pfd
);
437 if (pixelFormat
== 0) {
438 MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("ChoosePixelFormat failed."), wxT("Error"),
439 MB_ICONERROR
| MB_OK
);
443 if (SetPixelFormat((HDC
) m_hDC
, pixelFormat
, &pfd
) != TRUE
) {
444 MessageBox(WindowFromDC((HDC
) m_hDC
), wxT("SetPixelFormat failed."), wxT("Error"),
445 MB_ICONERROR
| MB_OK
);
450 void wxGLCanvas::SetupPalette(const wxPalette
& palette
)
452 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
453 PIXELFORMATDESCRIPTOR pfd
;
455 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
457 if (pfd
.dwFlags
& PFD_NEED_PALETTE
)
467 if ( !m_palette
.Ok() )
469 m_palette
= CreateDefaultPalette();
474 SelectPalette((HDC
) m_hDC
, (HPALETTE
) m_palette
.GetHPALETTE(), FALSE
);
475 RealizePalette((HDC
) m_hDC
);
479 wxPalette
wxGLCanvas::CreateDefaultPalette()
481 PIXELFORMATDESCRIPTOR pfd
;
483 int pixelFormat
= GetPixelFormat((HDC
) m_hDC
);
485 DescribePixelFormat((HDC
) m_hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &pfd
);
487 paletteSize
= 1 << pfd
.cColorBits
;
490 (LOGPALETTE
*) malloc(sizeof(LOGPALETTE
) + paletteSize
* sizeof(PALETTEENTRY
));
491 pPal
->palVersion
= 0x300;
492 pPal
->palNumEntries
= paletteSize
;
494 /* build a simple RGB color palette */
496 int redMask
= (1 << pfd
.cRedBits
) - 1;
497 int greenMask
= (1 << pfd
.cGreenBits
) - 1;
498 int blueMask
= (1 << pfd
.cBlueBits
) - 1;
501 for (i
=0; i
<paletteSize
; ++i
) {
502 pPal
->palPalEntry
[i
].peRed
=
503 (((i
>> pfd
.cRedShift
) & redMask
) * 255) / redMask
;
504 pPal
->palPalEntry
[i
].peGreen
=
505 (((i
>> pfd
.cGreenShift
) & greenMask
) * 255) / greenMask
;
506 pPal
->palPalEntry
[i
].peBlue
=
507 (((i
>> pfd
.cBlueShift
) & blueMask
) * 255) / blueMask
;
508 pPal
->palPalEntry
[i
].peFlags
= 0;
512 HPALETTE hPalette
= CreatePalette(pPal
);
516 palette
.SetHPALETTE((WXHPALETTE
) hPalette
);
521 void wxGLCanvas::SwapBuffers()
524 m_glContext
->SwapBuffers();
527 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
530 GetClientSize(& width
, & height
);
534 m_glContext
->SetCurrent();
536 glViewport(0, 0, (GLint
)width
, (GLint
)height
);
537 glMatrixMode(GL_PROJECTION
);
539 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
540 glMatrixMode(GL_MODELVIEW
);
544 void wxGLCanvas::SetCurrent()
548 m_glContext
->SetCurrent();
552 void wxGLCanvas::SetColour(const char *colour
)
555 m_glContext
->SetColour(colour
);
558 // TODO: Have to have this called by parent frame (?)
559 // So we need wxFrame to call OnQueryNewPalette for all children...
560 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent
& event
)
562 /* realize palette if this is the current window */
563 if ( GetPalette()->Ok() ) {
564 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
565 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
566 ::RealizePalette((HDC
) GetHDC());
568 event
.SetPaletteRealized(TRUE
);
571 event
.SetPaletteRealized(FALSE
);
574 // I think this doesn't have to be propagated to child windows.
575 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent
& event
)
577 /* realize palette if this is *not* the current window */
579 GetPalette()->Ok() && (this != event
.GetChangedWindow()) )
581 ::UnrealizeObject((HPALETTE
) GetPalette()->GetHPALETTE());
582 ::SelectPalette((HDC
) GetHDC(), (HPALETTE
) GetPalette()->GetHPALETTE(), FALSE
);
583 ::RealizePalette((HDC
) GetHDC());
588 /* Give extensions proper function names. */
590 /* EXT_vertex_array */
591 void glArrayElementEXT(GLint i
)
595 void glColorPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
599 void glDrawArraysEXT(GLenum mode
, GLint first
, GLsizei count
)
601 #ifdef GL_EXT_vertex_array
602 static PFNGLDRAWARRAYSEXTPROC proc
= 0;
606 proc
= (PFNGLDRAWARRAYSEXTPROC
) wglGetProcAddress("glDrawArraysEXT");
610 (* proc
) (mode
, first
, count
);
614 void glEdgeFlagPointerEXT(GLsizei stride
, GLsizei count
, const GLboolean
*pointer
)
618 void glGetPointervEXT(GLenum pname
, GLvoid
* *params
)
622 void glIndexPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
626 void glNormalPointerEXT(GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
628 #ifdef GL_EXT_vertex_array
629 static PFNGLNORMALPOINTEREXTPROC proc
= 0;
633 proc
= (PFNGLNORMALPOINTEREXTPROC
) wglGetProcAddress("glNormalPointerEXT");
637 (* proc
) (type
, stride
, count
, pointer
);
641 void glTexCoordPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
645 void glVertexPointerEXT(GLint size
, GLenum type
, GLsizei stride
, GLsizei count
, const GLvoid
*pointer
)
647 #ifdef GL_EXT_vertex_array
648 static PFNGLVERTEXPOINTEREXTPROC proc
= 0;
652 proc
= (PFNGLVERTEXPOINTEREXTPROC
) wglGetProcAddress("glVertexPointerEXT");
655 (* proc
) (size
, type
, stride
, count
, pointer
);
659 /* EXT_color_subtable */
660 void glColorSubtableEXT(GLenum target
, GLsizei start
, GLsizei count
, GLenum format
, GLenum type
, const GLvoid
*table
)
664 /* EXT_color_table */
665 void glColorTableEXT(GLenum target
, GLenum internalformat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*table
)
669 void glCopyColorTableEXT(GLenum target
, GLenum internalformat
, GLint x
, GLint y
, GLsizei width
)
673 void glGetColorTableEXT(GLenum target
, GLenum format
, GLenum type
, GLvoid
*table
)
677 void glGetColorTableParamaterfvEXT(GLenum target
, GLenum pname
, GLfloat
*params
)
681 void glGetColorTavleParameterivEXT(GLenum target
, GLenum pname
, GLint
*params
)
685 /* SGI_compiled_vertex_array */
686 void glLockArraysSGI(GLint first
, GLsizei count
)
690 void glUnlockArraysSGI()
695 /* SGI_cull_vertex */
696 void glCullParameterdvSGI(GLenum pname
, GLdouble
* params
)
700 void glCullParameterfvSGI(GLenum pname
, GLfloat
* params
)
705 void glIndexFuncSGI(GLenum func
, GLclampf ref
)
709 /* SGI_index_material */
710 void glIndexMaterialSGI(GLenum face
, GLenum mode
)
715 void glAddSwapHintRectWin(GLint x
, GLint y
, GLsizei width
, GLsizei height
)