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