]> git.saurik.com Git - wxWidgets.git/blob - utils/glcanvas/win/glcanvas.cpp
wxGTK::wxSpinCtrl API synchronised with wxMSW
[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 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(parent, id, pos, size, style, name)
133 {
134 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
135
136 SetupPixelFormat();
137 SetupPalette(palette);
138
139 m_glContext = new wxGLContext(TRUE, this, palette);
140 }
141
142 wxGLCanvas::wxGLCanvas( wxWindow *parent,
143 const wxGLContext *shared, wxWindowID id,
144 const wxPoint& pos, const wxSize& size, long style, const wxString& name,
145 int *attribList, const wxPalette& palette )
146 : wxScrolledWindow()
147 // : wxScrolledWindow(parent, id, pos, size, style, name)
148 {
149 bool ret = Create(parent, id, pos, size, style, name);
150
151 if ( ret )
152 {
153 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
154 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
155 }
156
157 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
158
159 SetupPixelFormat();
160 SetupPalette(palette);
161
162 m_glContext = new wxGLContext(TRUE, this, palette, shared );
163 }
164
165 wxGLCanvas::~wxGLCanvas()
166 {
167 if (m_glContext)
168 delete m_glContext;
169
170 ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC);
171 }
172
173 // Replaces wxWindow::Create functionality, since we need to use a different window class
174 bool wxGLCanvas::Create(wxWindow *parent, wxWindowID id,
175 const wxPoint& pos, const wxSize& size, long style, const wxString& name)
176 {
177 static bool registeredGLCanvasClass = FALSE;
178
179 // We have to register a special window class because we need
180 // the CS_OWNDC style for GLCanvas.
181
182 /*
183 Here are two snips from a dicussion in the OpenGL Gamedev list that explains
184 how this problem can be fixed:
185
186 "There are 5 common DCs available in Win95. These are aquired when you call
187 GetDC or GetDCEx from a window that does _not_ have the OWNDC flag.
188 OWNDC flagged windows do not get their DC from the common DC pool, the issue
189 is they require 800 bytes each from the limited 64Kb local heap for GDI."
190
191 "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps
192 do), Win95 will actually "steal" it from you. MakeCurrent fails,
193 apparently, because Windows re-assigns the HDC to a different window. The
194 only way to prevent this, the only reliable means, is to set CS_OWNDC."
195 */
196
197 if (!registeredGLCanvasClass)
198 {
199 WNDCLASS wndclass;
200
201 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC;
202
203 // the fields which are common to all classes
204 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
205 wndclass.cbClsExtra = 0;
206 wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for?
207 wndclass.hInstance = wxhInstance;
208 wndclass.hIcon = (HICON) NULL;
209 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
210 wndclass.lpszMenuName = NULL;
211
212 // Register the GLCanvas class name
213 wndclass.hbrBackground = (HBRUSH)NULL;
214 wndclass.lpszClassName = wxGLCanvasClassName;
215 wndclass.style = styleNormal;
216
217 if ( !RegisterClass(&wndclass) )
218 {
219 wxLogLastError("RegisterClass(wxGLCanvasClass)");
220
221 return FALSE;
222 }
223 }
224
225 wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
226
227 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
228 return FALSE;
229
230 parent->AddChild(this);
231
232 DWORD msflags = 0;
233 if ( style & wxBORDER )
234 msflags |= WS_BORDER;
235 if ( style & wxTHICK_FRAME )
236 msflags |= WS_THICKFRAME;
237
238 msflags |= WS_CHILD | WS_VISIBLE;
239 if ( style & wxCLIP_CHILDREN )
240 msflags |= WS_CLIPCHILDREN;
241
242 bool want3D;
243 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
244
245 // Even with extended styles, need to combine with WS_BORDER
246 // for them to look right.
247 if ( want3D || (m_windowStyle & wxSIMPLE_BORDER) || (m_windowStyle & wxRAISED_BORDER ) ||
248 (m_windowStyle & wxSUNKEN_BORDER) || (m_windowStyle & wxDOUBLE_BORDER))
249 {
250 msflags |= WS_BORDER;
251 }
252
253 // calculate the value to return from WM_GETDLGCODE handler
254 if ( GetWindowStyleFlag() & wxWANTS_CHARS )
255 {
256 // want everything: i.e. all keys and WM_CHAR message
257 m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS |
258 DLGC_WANTTAB | DLGC_WANTMESSAGE;
259 }
260
261 MSWCreate(m_windowId, parent, wxGLCanvasClassName, this, NULL,
262 pos.x, pos.y,
263 WidthDefault(size.x), HeightDefault(size.y),
264 msflags, NULL, exStyle);
265
266 return TRUE;
267
268 }
269
270 void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
271 {
272 PIXELFORMATDESCRIPTOR pfd = {
273 sizeof(PIXELFORMATDESCRIPTOR), /* size */
274 1, /* version */
275 PFD_SUPPORT_OPENGL |
276 PFD_DRAW_TO_WINDOW |
277 PFD_DOUBLEBUFFER, /* support double-buffering */
278 PFD_TYPE_RGBA, /* color type */
279 16, /* prefered color depth */
280 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
281 0, /* no alpha buffer */
282 0, /* alpha bits (ignored) */
283 0, /* no accumulation buffer */
284 0, 0, 0, 0, /* accum bits (ignored) */
285 16, /* depth buffer */
286 0, /* no stencil buffer */
287 0, /* no auxiliary buffers */
288 PFD_MAIN_PLANE, /* main layer */
289 0, /* reserved */
290 0, 0, 0, /* no layer, visible, damage masks */
291 };
292 int pixelFormat;
293
294 pixelFormat = ChoosePixelFormat((HDC) m_hDC, &pfd);
295 if (pixelFormat == 0) {
296 MessageBox(WindowFromDC((HDC) m_hDC), "ChoosePixelFormat failed.", "Error",
297 MB_ICONERROR | MB_OK);
298 exit(1);
299 }
300
301 if (SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) != TRUE) {
302 MessageBox(WindowFromDC((HDC) m_hDC), "SetPixelFormat failed.", "Error",
303 MB_ICONERROR | MB_OK);
304 exit(1);
305 }
306 }
307
308 void wxGLCanvas::SetupPalette(const wxPalette& palette)
309 {
310 int pixelFormat = GetPixelFormat((HDC) m_hDC);
311 PIXELFORMATDESCRIPTOR pfd;
312
313 DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
314
315 if (pfd.dwFlags & PFD_NEED_PALETTE)
316 {
317 }
318 else
319 {
320 return;
321 }
322
323 m_palette = palette;
324
325 if ( !m_palette.Ok() )
326 {
327 m_palette = CreateDefaultPalette();
328 }
329
330 if (m_palette.Ok())
331 {
332 SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE);
333 RealizePalette((HDC) m_hDC);
334 }
335 }
336
337 wxPalette wxGLCanvas::CreateDefaultPalette()
338 {
339 PIXELFORMATDESCRIPTOR pfd;
340 int paletteSize;
341 int pixelFormat = GetPixelFormat((HDC) m_hDC);
342
343 DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
344
345 paletteSize = 1 << pfd.cColorBits;
346
347 LOGPALETTE* pPal =
348 (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY));
349 pPal->palVersion = 0x300;
350 pPal->palNumEntries = paletteSize;
351
352 /* build a simple RGB color palette */
353 {
354 int redMask = (1 << pfd.cRedBits) - 1;
355 int greenMask = (1 << pfd.cGreenBits) - 1;
356 int blueMask = (1 << pfd.cBlueBits) - 1;
357 int i;
358
359 for (i=0; i<paletteSize; ++i) {
360 pPal->palPalEntry[i].peRed =
361 (((i >> pfd.cRedShift) & redMask) * 255) / redMask;
362 pPal->palPalEntry[i].peGreen =
363 (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
364 pPal->palPalEntry[i].peBlue =
365 (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask;
366 pPal->palPalEntry[i].peFlags = 0;
367 }
368 }
369
370 HPALETTE hPalette = CreatePalette(pPal);
371 free(pPal);
372
373 wxPalette palette;
374 palette.SetHPALETTE((WXHPALETTE) hPalette);
375
376 return palette;
377 }
378
379 void wxGLCanvas::SwapBuffers()
380 {
381 if (m_glContext)
382 m_glContext->SwapBuffers();
383 }
384
385 void wxGLCanvas::OnSize(wxSizeEvent& event)
386 {
387 int width, height;
388 GetClientSize(& width, & height);
389
390 if (m_glContext)
391 {
392 m_glContext->SetCurrent();
393
394 glViewport(0, 0, (GLint)width, (GLint)height);
395 glMatrixMode(GL_PROJECTION);
396 glLoadIdentity();
397 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 );
398 glMatrixMode(GL_MODELVIEW);
399 }
400 }
401
402 void wxGLCanvas::SetCurrent()
403 {
404 if (m_glContext)
405 {
406 m_glContext->SetCurrent();
407 }
408 }
409
410 void wxGLCanvas::SetColour(const char *colour)
411 {
412 if (m_glContext)
413 m_glContext->SetColour(colour);
414 }
415
416 // TODO: Have to have this called by parent frame (?)
417 // So we need wxFrame to call OnQueryNewPalette for all children...
418 void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
419 {
420 /* realize palette if this is the current window */
421 if ( GetPalette()->Ok() ) {
422 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
423 ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
424 ::RealizePalette((HDC) GetHDC());
425 Refresh();
426 event.SetPaletteRealized(TRUE);
427 }
428 else
429 event.SetPaletteRealized(FALSE);
430 }
431
432 // I think this doesn't have to be propagated to child windows.
433 void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
434 {
435 /* realize palette if this is *not* the current window */
436 if ( GetPalette() &&
437 GetPalette()->Ok() && (this != event.GetChangedWindow()) )
438 {
439 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
440 ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
441 ::RealizePalette((HDC) GetHDC());
442 Refresh();
443 }
444 }
445
446 /* Give extensions proper function names. */
447
448 /* EXT_vertex_array */
449 void glArrayElementEXT(GLint i)
450 {
451 }
452
453 void glColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
454 {
455 }
456
457 void glDrawArraysEXT(GLenum mode, GLint first, GLsizei count)
458 {
459 #ifdef GL_EXT_vertex_array
460 static PFNGLDRAWARRAYSEXTPROC proc = 0;
461
462 if ( !proc )
463 {
464 proc = (PFNGLDRAWARRAYSEXTPROC) wglGetProcAddress("glDrawArraysEXT");
465 }
466
467 if ( proc )
468 (* proc) (mode, first, count);
469 #endif
470 }
471
472 void glEdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *pointer)
473 {
474 }
475
476 void glGetPointervEXT(GLenum pname, GLvoid* *params)
477 {
478 }
479
480 void glIndexPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
481 {
482 }
483
484 void glNormalPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
485 {
486 #ifdef GL_EXT_vertex_array
487 static PFNGLNORMALPOINTEREXTPROC proc = 0;
488
489 if ( !proc )
490 {
491 proc = (PFNGLNORMALPOINTEREXTPROC) wglGetProcAddress("glNormalPointerEXT");
492 }
493
494 if ( proc )
495 (* proc) (type, stride, count, pointer);
496 #endif
497 }
498
499 void glTexCoordPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
500 {
501 }
502
503 void glVertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
504 {
505 #ifdef GL_EXT_vertex_array
506 static PFNGLVERTEXPOINTEREXTPROC proc = 0;
507
508 if ( !proc )
509 {
510 proc = (PFNGLVERTEXPOINTEREXTPROC) wglGetProcAddress("glVertexPointerEXT");
511 }
512
513 if ( proc )
514 (* proc) (size, type, stride, count, pointer);
515 #endif
516 }
517
518 /* EXT_color_subtable */
519 void glColorSubtableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *table)
520 {
521 }
522
523 /* EXT_color_table */
524 void glColorTableEXT(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table)
525 {
526 }
527
528 void glCopyColorTableEXT(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width)
529 {
530 }
531
532 void glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *table)
533 {
534 }
535
536 void glGetColorTableParamaterfvEXT(GLenum target, GLenum pname, GLfloat *params)
537 {
538 }
539
540 void glGetColorTavleParameterivEXT(GLenum target, GLenum pname, GLint *params)
541 {
542 }
543
544 /* SGI_compiled_vertex_array */
545 void glLockArraysSGI(GLint first, GLsizei count)
546 {
547 }
548
549 void glUnlockArraysSGI()
550 {
551 }
552
553
554 /* SGI_cull_vertex */
555 void glCullParameterdvSGI(GLenum pname, GLdouble* params)
556 {
557 }
558
559 void glCullParameterfvSGI(GLenum pname, GLfloat* params)
560 {
561 }
562
563 /* SGI_index_func */
564 void glIndexFuncSGI(GLenum func, GLclampf ref)
565 {
566 }
567
568 /* SGI_index_material */
569 void glIndexMaterialSGI(GLenum face, GLenum mode)
570 {
571 }
572
573 /* WIN_swap_hint */
574 void glAddSwapHintRectWin(GLint x, GLint y, GLsizei width, GLsizei height)
575 {
576 }
577