included missing header files - without them mingw32 compilation failed
[wxWidgets.git] / src / msw / 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 #include <wx/setup.h>
23
24 #if wxUSE_GLCANVAS
25
26 #ifndef WX_PRECOMP
27 #include <wx/frame.h>
28 #endif
29
30 #include <wx/msw/private.h>
31 #include <wx/settings.h>
32 #include <wx/log.h>
33
34 #include <wx/glcanvas.h>
35
36 wxChar wxGLCanvasClassName[] = wxT("wxGLCanvasClass");
37
38 LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
39 WPARAM wParam, LPARAM lParam);
40
41 /*
42 * GLContext implementation
43 */
44
45 wxGLContext::wxGLContext(bool isRGB, wxGLCanvas *win, const wxPalette& palette)
46 {
47 m_window = win;
48
49 m_hDC = win->GetHDC();
50
51 m_glContext = wglCreateContext((HDC) m_hDC);
52 wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" );
53
54 wglMakeCurrent((HDC) m_hDC, m_glContext);
55 }
56
57 wxGLContext::wxGLContext(
58 bool isRGB, wxGLCanvas *win,
59 const wxPalette& palette,
60 const wxGLContext *other /* for sharing display lists */
61 )
62 {
63 m_window = win;
64
65 m_hDC = win->GetHDC();
66
67 m_glContext = wglCreateContext((HDC) m_hDC);
68 wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" );
69
70 if( other != 0 )
71 wglShareLists( other->m_glContext, m_glContext );
72
73 wglMakeCurrent((HDC) m_hDC, m_glContext);
74 }
75
76 wxGLContext::~wxGLContext()
77 {
78 if (m_glContext)
79 {
80 wglMakeCurrent(NULL, NULL);
81 wglDeleteContext(m_glContext);
82 }
83 }
84
85 void wxGLContext::SwapBuffers()
86 {
87 if (m_glContext)
88 {
89 wglMakeCurrent((HDC) m_hDC, m_glContext);
90 ::SwapBuffers((HDC) m_hDC); //blits the backbuffer into DC
91 }
92 }
93
94 void wxGLContext::SetCurrent()
95 {
96 if (m_glContext)
97 {
98 wglMakeCurrent((HDC) m_hDC, m_glContext);
99 }
100
101 /*
102 setupPixelFormat(hDC);
103 setupPalette(hDC);
104 */
105 }
106
107 void wxGLContext::SetColour(const char *colour)
108 {
109 float r = 0.0;
110 float g = 0.0;
111 float b = 0.0;
112 wxColour *col = wxTheColourDatabase->FindColour(colour);
113 if (col)
114 {
115 r = (float)(col->Red()/256.0);
116 g = (float)(col->Green()/256.0);
117 b = (float)(col->Blue()/256.0);
118 glColor3f( r, g, b);
119 }
120 }
121
122
123 /*
124 * wxGLCanvas implementation
125 */
126
127 IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow)
128
129 BEGIN_EVENT_TABLE(wxGLCanvas, wxScrolledWindow)
130 EVT_SIZE(wxGLCanvas::OnSize)
131 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
132 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
133 END_EVENT_TABLE()
134
135 wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id,
136 const wxPoint& pos, const wxSize& size, long style, const wxString& name,
137 int *attribList /* not used yet! */, const wxPalette& palette):
138 wxScrolledWindow()
139 {
140 m_glContext = (wxGLContext*) NULL;
141
142 bool ret = Create(parent, id, pos, size, style, name);
143
144 if ( ret )
145 {
146 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
147 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
148 }
149
150 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
151
152 SetupPixelFormat();
153 SetupPalette(palette);
154
155 m_glContext = new wxGLContext(TRUE, this, palette);
156 }
157
158 wxGLCanvas::wxGLCanvas( wxWindow *parent,
159 const wxGLContext *shared, wxWindowID id,
160 const wxPoint& pos, const wxSize& size, long style, const wxString& name,
161 int *attribList, const wxPalette& palette )
162 : wxScrolledWindow()
163 {
164 m_glContext = (wxGLContext*) NULL;
165
166 bool ret = Create(parent, id, pos, size, style, name);
167
168 if ( ret )
169 {
170 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
171 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
172 }
173
174 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
175
176 SetupPixelFormat();
177 SetupPalette(palette);
178
179 m_glContext = new wxGLContext(TRUE, this, palette, shared );
180 }
181
182 // Not very usefull for wxMSW, but this is to be wxGTK compliant
183
184 wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id,
185 const wxPoint& pos, const wxSize& size, long style, const wxString& name,
186 int *attribList, const wxPalette& palette ):
187 wxScrolledWindow()
188 {
189 m_glContext = (wxGLContext*) NULL;
190
191 bool ret = Create(parent, id, pos, size, style, name);
192
193 if ( ret )
194 {
195 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
196 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
197 }
198
199 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
200
201 SetupPixelFormat();
202 SetupPalette(palette);
203
204 wxGLContext *sharedContext=0;
205 if (shared) sharedContext=shared->GetContext();
206 m_glContext = new wxGLContext(TRUE, this, palette, sharedContext );
207 }
208
209 wxGLCanvas::~wxGLCanvas()
210 {
211 if (m_glContext)
212 delete m_glContext;
213
214 ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC);
215 }
216
217 // Replaces wxWindow::Create functionality, since we need to use a different window class
218 bool wxGLCanvas::Create(wxWindow *parent, wxWindowID id,
219 const wxPoint& pos, const wxSize& size, long style, const wxString& name)
220 {
221 static bool registeredGLCanvasClass = FALSE;
222
223 // We have to register a special window class because we need
224 // the CS_OWNDC style for GLCanvas.
225
226 /*
227 From Angel Popov <jumpo@bitex.com>
228
229 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
230 how this problem can be fixed:
231
232 "There are 5 common DCs available in Win95. These are aquired when you call
233 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
234 OWNDC flagged windows do not get their DC from the common DC pool, the issue
235 is they require 800 bytes each from the limited 64Kb local heap for GDI."
236
237 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
238 do), Win95 will actually "steal" it from you. MakeCurrent fails,
239 apparently, because Windows re-assigns the HDC to a different window. The
240 only way to prevent this, the only reliable means, is to set CS_OWNDC."
241 */
242
243 if (!registeredGLCanvasClass)
244 {
245 WNDCLASS wndclass;
246
247 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
248
249 // the fields which are common to all classes
250 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
251 wndclass.cbClsExtra = 0;
252 wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for?
253 wndclass.hInstance = wxhInstance;
254 wndclass.hIcon = (HICON) NULL;
255 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
256 wndclass.lpszMenuName = NULL;
257
258 // Register the GLCanvas class name
259 wndclass.hbrBackground = (HBRUSH)NULL;
260 wndclass.lpszClassName = wxGLCanvasClassName;
261 wndclass.style = styleNormal;
262
263 if ( !RegisterClass(&wndclass) )
264 {
265 wxLogLastError("RegisterClass(wxGLCanvasClass)");
266
267 return FALSE;
268 }
269 registeredGLCanvasClass = TRUE;
270 }
271
272 wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
273
274 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
275 return FALSE;
276
277 parent->AddChild(this);
278
279 DWORD msflags = 0;
280 if ( style & wxBORDER )
281 msflags |= WS_BORDER;
282 if ( style & wxTHICK_FRAME )
283 msflags |= WS_THICKFRAME;
284
285 msflags |= WS_CHILD | WS_VISIBLE;
286 if ( style & wxCLIP_CHILDREN )
287 msflags |= WS_CLIPCHILDREN;
288
289 bool want3D;
290 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
291
292 // Even with extended styles, need to combine with WS_BORDER
293 // for them to look right.
294 if ( want3D || (m_windowStyle & wxSIMPLE_BORDER) || (m_windowStyle & wxRAISED_BORDER ) ||
295 (m_windowStyle & wxSUNKEN_BORDER) || (m_windowStyle & wxDOUBLE_BORDER))
296 {
297 msflags |= WS_BORDER;
298 }
299
300 // calculate the value to return from WM_GETDLGCODE handler
301 if ( GetWindowStyleFlag() & wxWANTS_CHARS )
302 {
303 // want everything: i.e. all keys and WM_CHAR message
304 m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS |
305 DLGC_WANTTAB | DLGC_WANTMESSAGE;
306 }
307
308 MSWCreate(m_windowId, parent, wxGLCanvasClassName, this, NULL,
309 pos.x, pos.y,
310 WidthDefault(size.x), HeightDefault(size.y),
311 msflags, NULL, exStyle);
312
313 return TRUE;
314
315 }
316
317 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
318 {
319 PIXELFORMATDESCRIPTOR pfd = {
320 sizeof(PIXELFORMATDESCRIPTOR), /* size */
321 1, /* version */
322 PFD_SUPPORT_OPENGL |
323 PFD_DRAW_TO_WINDOW |
324 PFD_DOUBLEBUFFER, /* support double-buffering */
325 PFD_TYPE_RGBA, /* color type */
326 16, /* prefered color depth */
327 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
328 0, /* no alpha buffer */
329 0, /* alpha bits (ignored) */
330 0, /* no accumulation buffer */
331 0, 0, 0, 0, /* accum bits (ignored) */
332 16, /* depth buffer */
333 0, /* no stencil buffer */
334 0, /* no auxiliary buffers */
335 PFD_MAIN_PLANE, /* main layer */
336 0, /* reserved */
337 0, 0, 0, /* no layer, visible, damage masks */
338 };
339 int pixelFormat;
340
341 pixelFormat = ChoosePixelFormat((HDC) m_hDC, &pfd);
342 if (pixelFormat == 0) {
343 MessageBox(WindowFromDC((HDC) m_hDC), "ChoosePixelFormat failed.", "Error",
344 MB_ICONERROR | MB_OK);
345 exit(1);
346 }
347
348 if (SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) != TRUE) {
349 MessageBox(WindowFromDC((HDC) m_hDC), "SetPixelFormat failed.", "Error",
350 MB_ICONERROR | MB_OK);
351 exit(1);
352 }
353 }
354
355 void wxGLCanvas::SetupPalette(const wxPalette& palette)
356 {
357 int pixelFormat = GetPixelFormat((HDC) m_hDC);
358 PIXELFORMATDESCRIPTOR pfd;
359
360 DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
361
362 if (pfd.dwFlags & PFD_NEED_PALETTE)
363 {
364 }
365 else
366 {
367 return;
368 }
369
370 m_palette = palette;
371
372 if ( !m_palette.Ok() )
373 {
374 m_palette = CreateDefaultPalette();
375 }
376
377 if (m_palette.Ok())
378 {
379 SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE);
380 RealizePalette((HDC) m_hDC);
381 }
382 }
383
384 wxPalette wxGLCanvas::CreateDefaultPalette()
385 {
386 PIXELFORMATDESCRIPTOR pfd;
387 int paletteSize;
388 int pixelFormat = GetPixelFormat((HDC) m_hDC);
389
390 DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
391
392 paletteSize = 1 << pfd.cColorBits;
393
394 LOGPALETTE* pPal =
395 (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
396 pPal->palVersion = 0x300;
397 pPal->palNumEntries = paletteSize;
398
399 /* build a simple RGB color palette */
400 {
401 int redMask = (1 << pfd.cRedBits) - 1;
402 int greenMask = (1 << pfd.cGreenBits) - 1;
403 int blueMask = (1 << pfd.cBlueBits) - 1;
404 int i;
405
406 for (i=0; i<paletteSize; ++i) {
407 pPal->palPalEntry[i].peRed =
408 (((i >> pfd.cRedShift) & redMask) * 255) / redMask;
409 pPal->palPalEntry[i].peGreen =
410 (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
411 pPal->palPalEntry[i].peBlue =
412 (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
413 pPal->palPalEntry[i].peFlags = 0;
414 }
415 }
416
417 HPALETTE hPalette = CreatePalette(pPal);
418 free(pPal);
419
420 wxPalette palette;
421 palette.SetHPALETTE((WXHPALETTE) hPalette);
422
423 return palette;
424 }
425
426 void wxGLCanvas::SwapBuffers()
427 {
428 if (m_glContext)
429 m_glContext->SwapBuffers();
430 }
431
432 void wxGLCanvas::OnSize(wxSizeEvent& event)
433 {
434 int width, height;
435 GetClientSize(& width, & height);
436
437 if (m_glContext)
438 {
439 m_glContext->SetCurrent();
440
441 glViewport(0, 0, (GLint)width, (GLint)height);
442 glMatrixMode(GL_PROJECTION);
443 glLoadIdentity();
444 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
445 glMatrixMode(GL_MODELVIEW);
446 }
447 }
448
449 void wxGLCanvas::SetCurrent()
450 {
451 if (m_glContext)
452 {
453 m_glContext->SetCurrent();
454 }
455 }
456
457 void wxGLCanvas::SetColour(const char *colour)
458 {
459 if (m_glContext)
460 m_glContext->SetColour(colour);
461 }
462
463 // TODO: Have to have this called by parent frame (?)
464 // So we need wxFrame to call OnQueryNewPalette for all children...
465 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
466 {
467 /* realize palette if this is the current window */
468 if ( GetPalette()->Ok() ) {
469 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
470 ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
471 ::RealizePalette((HDC) GetHDC());
472 Refresh();
473 event.SetPaletteRealized(TRUE);
474 }
475 else
476 event.SetPaletteRealized(FALSE);
477 }
478
479 // I think this doesn't have to be propagated to child windows.
480 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
481 {
482 /* realize palette if this is *not* the current window */
483 if ( GetPalette() &&
484 GetPalette()->Ok() && (this != event.GetChangedWindow()) )
485 {
486 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
487 ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
488 ::RealizePalette((HDC) GetHDC());
489 Refresh();
490 }
491 }
492
493 /* Give extensions proper function names. */
494
495 /* EXT_vertex_array */
496 void glArrayElementEXT(GLint i)
497 {
498 }
499
500 void glColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
501 {
502 }
503
504 void glDrawArraysEXT(GLenum mode, GLint first, GLsizei count)
505 {
506 #ifdef GL_EXT_vertex_array
507 static PFNGLDRAWARRAYSEXTPROC proc = 0;
508
509 if ( !proc )
510 {
511 proc = (PFNGLDRAWARRAYSEXTPROC) wglGetProcAddress("glDrawArraysEXT");
512 }
513
514 if ( proc )
515 (* proc) (mode, first, count);
516 #endif
517 }
518
519 void glEdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *pointer)
520 {
521 }
522
523 void glGetPointervEXT(GLenum pname, GLvoid* *params)
524 {
525 }
526
527 void glIndexPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
528 {
529 }
530
531 void glNormalPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
532 {
533 #ifdef GL_EXT_vertex_array
534 static PFNGLNORMALPOINTEREXTPROC proc = 0;
535
536 if ( !proc )
537 {
538 proc = (PFNGLNORMALPOINTEREXTPROC) wglGetProcAddress("glNormalPointerEXT");
539 }
540
541 if ( proc )
542 (* proc) (type, stride, count, pointer);
543 #endif
544 }
545
546 void glTexCoordPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
547 {
548 }
549
550 void glVertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
551 {
552 #ifdef GL_EXT_vertex_array
553 static PFNGLVERTEXPOINTEREXTPROC proc = 0;
554
555 if ( !proc )
556 {
557 proc = (PFNGLVERTEXPOINTEREXTPROC) wglGetProcAddress("glVertexPointerEXT");
558 }
559
560 if ( proc )
561 (* proc) (size, type, stride, count, pointer);
562 #endif
563 }
564
565 /* EXT_color_subtable */
566 void glColorSubtableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *table)
567 {
568 }
569
570 /* EXT_color_table */
571 void glColorTableEXT(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table)
572 {
573 }
574
575 void glCopyColorTableEXT(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width)
576 {
577 }
578
579 void glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *table)
580 {
581 }
582
583 void glGetColorTableParamaterfvEXT(GLenum target, GLenum pname, GLfloat *params)
584 {
585 }
586
587 void glGetColorTavleParameterivEXT(GLenum target, GLenum pname, GLint *params)
588 {
589 }
590
591 /* SGI_compiled_vertex_array */
592 void glLockArraysSGI(GLint first, GLsizei count)
593 {
594 }
595
596 void glUnlockArraysSGI()
597 {
598 }
599
600
601 /* SGI_cull_vertex */
602 void glCullParameterdvSGI(GLenum pname, GLdouble* params)
603 {
604 }
605
606 void glCullParameterfvSGI(GLenum pname, GLfloat* params)
607 {
608 }
609
610 /* SGI_index_func */
611 void glIndexFuncSGI(GLenum func, GLclampf ref)
612 {
613 }
614
615 /* SGI_index_material */
616 void glIndexMaterialSGI(GLenum face, GLenum mode)
617 {
618 }
619
620 /* WIN_swap_hint */
621 void glAddSwapHintRectWin(GLint x, GLint y, GLsizei width, GLsizei height)
622 {
623 }
624
625 #endif
626 // wxUSE_GLCANVAS