]> git.saurik.com Git - wxWidgets.git/blob - utils/glcanvas/win/glcanvas.cpp
Cured memory leak report in wxDateTime; wxGLCanvas corrections
[wxWidgets.git] / utils / glcanvas / win / glcanvas.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL with wxWindows under MS Windows
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "glcanvas.h"
14 #endif
15
16 #include "wx/wxprec.h"
17
18 #if defined(__BORLANDC__)
19 #pragma hdrstop
20 #endif
21
22 #ifndef WX_PRECOMP
23 #include <wx/frame.h>
24 #endif
25
26 #include <wx/msw/private.h>
27
28 #include "glcanvas.h"
29
30 wxChar wxGLCanvasClassName[] = wxT("wxGLCanvasClass");
31
32 LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
33 WPARAM wParam, LPARAM lParam);
34
35 /*
36 * GLContext implementation
37 */
38
39 wxGLContext::wxGLContext(bool isRGB, wxGLCanvas *win, const wxPalette& palette)
40 {
41 m_window = win;
42
43 m_hDC = win->GetHDC();
44
45 m_glContext = wglCreateContext((HDC) m_hDC);
46 wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" );
47
48 wglMakeCurrent((HDC) m_hDC, m_glContext);
49 }
50
51 wxGLContext::wxGLContext(
52 bool isRGB, wxGLCanvas *win,
53 const wxPalette& palette,
54 const wxGLContext *other /* for sharing display lists */
55 )
56 {
57 m_window = win;
58
59 m_hDC = win->GetHDC();
60
61 m_glContext = wglCreateContext((HDC) m_hDC);
62 wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" );
63
64 if( other != 0 )
65 wglShareLists( other->m_glContext, m_glContext );
66
67 wglMakeCurrent((HDC) m_hDC, m_glContext);
68 }
69
70 wxGLContext::~wxGLContext()
71 {
72 if (m_glContext)
73 {
74 wglMakeCurrent(NULL, NULL);
75 wglDeleteContext(m_glContext);
76 }
77 }
78
79 void wxGLContext::SwapBuffers()
80 {
81 if (m_glContext)
82 {
83 wglMakeCurrent((HDC) m_hDC, m_glContext);
84 ::SwapBuffers((HDC) m_hDC); //blits the backbuffer into DC
85 }
86 }
87
88 void wxGLContext::SetCurrent()
89 {
90 if (m_glContext)
91 {
92 wglMakeCurrent((HDC) m_hDC, m_glContext);
93 }
94
95 /*
96 setupPixelFormat(hDC);
97 setupPalette(hDC);
98 */
99 }
100
101 void wxGLContext::SetColour(const char *colour)
102 {
103 float r = 0.0;
104 float g = 0.0;
105 float b = 0.0;
106 wxColour *col = wxTheColourDatabase->FindColour(colour);
107 if (col)
108 {
109 r = (float)(col->Red()/256.0);
110 g = (float)(col->Green()/256.0);
111 b = (float)(col->Blue()/256.0);
112 glColor3f( r, g, b);
113 }
114 }
115
116
117 /*
118 * wxGLCanvas implementation
119 */
120
121 IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow)
122
123 BEGIN_EVENT_TABLE(wxGLCanvas, wxScrolledWindow)
124 EVT_SIZE(wxGLCanvas::OnSize)
125 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
126 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
127 END_EVENT_TABLE()
128
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()
133 {
134 m_glContext = (wxGLContext*) NULL;
135
136 bool ret = Create(parent, id, pos, size, style, name);
137
138 if ( ret )
139 {
140 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
141 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
142 }
143
144 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
145
146 SetupPixelFormat();
147 SetupPalette(palette);
148
149 m_glContext = new wxGLContext(TRUE, this, palette);
150
151 }
152
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 )
157 : wxScrolledWindow()
158 {
159 m_glContext = (wxGLContext*) NULL;
160
161 bool ret = Create(parent, id, pos, size, style, name);
162
163 if ( ret )
164 {
165 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
166 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
167 }
168
169 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
170
171 SetupPixelFormat();
172 SetupPalette(palette);
173
174 m_glContext = new wxGLContext(TRUE, this, palette, shared );
175 }
176
177 wxGLCanvas::~wxGLCanvas()
178 {
179 if (m_glContext)
180 delete m_glContext;
181
182 ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC);
183 }
184
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)
188 {
189 static bool registeredGLCanvasClass = FALSE;
190
191 // We have to register a special window class because we need
192 // the CS_OWNDC style for GLCanvas.
193
194 /*
195 From Angel Popov <jumpo@bitex.com>
196
197 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
198 how this problem can be fixed:
199
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."
204
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."
209 */
210
211 if (!registeredGLCanvasClass)
212 {
213 WNDCLASS wndclass;
214
215 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
216
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;
225
226 // Register the GLCanvas class name
227 wndclass.hbrBackground = (HBRUSH)NULL;
228 wndclass.lpszClassName = wxGLCanvasClassName;
229 wndclass.style = styleNormal;
230
231 if ( !RegisterClass(&wndclass) )
232 {
233 wxLogLastError("RegisterClass(wxGLCanvasClass)");
234
235 return FALSE;
236 }
237 registeredGLCanvasClass = TRUE;
238 }
239
240 wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
241
242 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
243 return FALSE;
244
245 parent->AddChild(this);
246
247 DWORD msflags = 0;
248 if ( style & wxBORDER )
249 msflags |= WS_BORDER;
250 if ( style & wxTHICK_FRAME )
251 msflags |= WS_THICKFRAME;
252
253 msflags |= WS_CHILD | WS_VISIBLE;
254 if ( style & wxCLIP_CHILDREN )
255 msflags |= WS_CLIPCHILDREN;
256
257 bool want3D;
258 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
259
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))
264 {
265 msflags |= WS_BORDER;
266 }
267
268 // calculate the value to return from WM_GETDLGCODE handler
269 if ( GetWindowStyleFlag() & wxWANTS_CHARS )
270 {
271 // want everything: i.e. all keys and WM_CHAR message
272 m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS |
273 DLGC_WANTTAB | DLGC_WANTMESSAGE;
274 }
275
276 MSWCreate(m_windowId, parent, wxGLCanvasClassName, this, NULL,
277 pos.x, pos.y,
278 WidthDefault(size.x), HeightDefault(size.y),
279 msflags, NULL, exStyle);
280
281 return TRUE;
282
283 }
284
285 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
286 {
287 PIXELFORMATDESCRIPTOR pfd = {
288 sizeof(PIXELFORMATDESCRIPTOR), /* size */
289 1, /* version */
290 PFD_SUPPORT_OPENGL |
291 PFD_DRAW_TO_WINDOW |
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 */
304 0, /* reserved */
305 0, 0, 0, /* no layer, visible, damage masks */
306 };
307 int pixelFormat;
308
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);
313 exit(1);
314 }
315
316 if (SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) != TRUE) {
317 MessageBox(WindowFromDC((HDC) m_hDC), "SetPixelFormat failed.", "Error",
318 MB_ICONERROR | MB_OK);
319 exit(1);
320 }
321 }
322
323 void wxGLCanvas::SetupPalette(const wxPalette& palette)
324 {
325 int pixelFormat = GetPixelFormat((HDC) m_hDC);
326 PIXELFORMATDESCRIPTOR pfd;
327
328 DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
329
330 if (pfd.dwFlags & PFD_NEED_PALETTE)
331 {
332 }
333 else
334 {
335 return;
336 }
337
338 m_palette = palette;
339
340 if ( !m_palette.Ok() )
341 {
342 m_palette = CreateDefaultPalette();
343 }
344
345 if (m_palette.Ok())
346 {
347 SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE);
348 RealizePalette((HDC) m_hDC);
349 }
350 }
351
352 wxPalette wxGLCanvas::CreateDefaultPalette()
353 {
354 PIXELFORMATDESCRIPTOR pfd;
355 int paletteSize;
356 int pixelFormat = GetPixelFormat((HDC) m_hDC);
357
358 DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
359
360 paletteSize = 1 << pfd.cColorBits;
361
362 LOGPALETTE* pPal =
363 (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
364 pPal->palVersion = 0x300;
365 pPal->palNumEntries = paletteSize;
366
367 /* build a simple RGB color palette */
368 {
369 int redMask = (1 << pfd.cRedBits) - 1;
370 int greenMask = (1 << pfd.cGreenBits) - 1;
371 int blueMask = (1 << pfd.cBlueBits) - 1;
372 int i;
373
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;
382 }
383 }
384
385 HPALETTE hPalette = CreatePalette(pPal);
386 free(pPal);
387
388 wxPalette palette;
389 palette.SetHPALETTE((WXHPALETTE) hPalette);
390
391 return palette;
392 }
393
394 void wxGLCanvas::SwapBuffers()
395 {
396 if (m_glContext)
397 m_glContext->SwapBuffers();
398 }
399
400 void wxGLCanvas::OnSize(wxSizeEvent& event)
401 {
402 int width, height;
403 GetClientSize(& width, & height);
404
405 if (m_glContext)
406 {
407 m_glContext->SetCurrent();
408
409 glViewport(0, 0, (GLint)width, (GLint)height);
410 glMatrixMode(GL_PROJECTION);
411 glLoadIdentity();
412 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
413 glMatrixMode(GL_MODELVIEW);
414 }
415 }
416
417 void wxGLCanvas::SetCurrent()
418 {
419 if (m_glContext)
420 {
421 m_glContext->SetCurrent();
422 }
423 }
424
425 void wxGLCanvas::SetColour(const char *colour)
426 {
427 if (m_glContext)
428 m_glContext->SetColour(colour);
429 }
430
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)
434 {
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());
440 Refresh();
441 event.SetPaletteRealized(TRUE);
442 }
443 else
444 event.SetPaletteRealized(FALSE);
445 }
446
447 // I think this doesn't have to be propagated to child windows.
448 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
449 {
450 /* realize palette if this is *not* the current window */
451 if ( GetPalette() &&
452 GetPalette()->Ok() && (this != event.GetChangedWindow()) )
453 {
454 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
455 ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
456 ::RealizePalette((HDC) GetHDC());
457 Refresh();
458 }
459 }
460
461 /* Give extensions proper function names. */
462
463 /* EXT_vertex_array */
464 void glArrayElementEXT(GLint i)
465 {
466 }
467
468 void glColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
469 {
470 }
471
472 void glDrawArraysEXT(GLenum mode, GLint first, GLsizei count)
473 {
474 #ifdef GL_EXT_vertex_array
475 static PFNGLDRAWARRAYSEXTPROC proc = 0;
476
477 if ( !proc )
478 {
479 proc = (PFNGLDRAWARRAYSEXTPROC) wglGetProcAddress("glDrawArraysEXT");
480 }
481
482 if ( proc )
483 (* proc) (mode, first, count);
484 #endif
485 }
486
487 void glEdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *pointer)
488 {
489 }
490
491 void glGetPointervEXT(GLenum pname, GLvoid* *params)
492 {
493 }
494
495 void glIndexPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
496 {
497 }
498
499 void glNormalPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
500 {
501 #ifdef GL_EXT_vertex_array
502 static PFNGLNORMALPOINTEREXTPROC proc = 0;
503
504 if ( !proc )
505 {
506 proc = (PFNGLNORMALPOINTEREXTPROC) wglGetProcAddress("glNormalPointerEXT");
507 }
508
509 if ( proc )
510 (* proc) (type, stride, count, pointer);
511 #endif
512 }
513
514 void glTexCoordPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
515 {
516 }
517
518 void glVertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
519 {
520 #ifdef GL_EXT_vertex_array
521 static PFNGLVERTEXPOINTEREXTPROC proc = 0;
522
523 if ( !proc )
524 {
525 proc = (PFNGLVERTEXPOINTEREXTPROC) wglGetProcAddress("glVertexPointerEXT");
526 }
527
528 if ( proc )
529 (* proc) (size, type, stride, count, pointer);
530 #endif
531 }
532
533 /* EXT_color_subtable */
534 void glColorSubtableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *table)
535 {
536 }
537
538 /* EXT_color_table */
539 void glColorTableEXT(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table)
540 {
541 }
542
543 void glCopyColorTableEXT(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width)
544 {
545 }
546
547 void glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *table)
548 {
549 }
550
551 void glGetColorTableParamaterfvEXT(GLenum target, GLenum pname, GLfloat *params)
552 {
553 }
554
555 void glGetColorTavleParameterivEXT(GLenum target, GLenum pname, GLint *params)
556 {
557 }
558
559 /* SGI_compiled_vertex_array */
560 void glLockArraysSGI(GLint first, GLsizei count)
561 {
562 }
563
564 void glUnlockArraysSGI()
565 {
566 }
567
568
569 /* SGI_cull_vertex */
570 void glCullParameterdvSGI(GLenum pname, GLdouble* params)
571 {
572 }
573
574 void glCullParameterfvSGI(GLenum pname, GLfloat* params)
575 {
576 }
577
578 /* SGI_index_func */
579 void glIndexFuncSGI(GLenum func, GLclampf ref)
580 {
581 }
582
583 /* SGI_index_material */
584 void glIndexMaterialSGI(GLenum face, GLenum mode)
585 {
586 }
587
588 /* WIN_swap_hint */
589 void glAddSwapHintRectWin(GLint x, GLint y, GLsizei width, GLsizei height)
590 {
591 }
592