]> git.saurik.com Git - wxWidgets.git/blame - utils/glcanvas/win/glcanvas.cpp
Added comments explaining my recent changes
[wxWidgets.git] / utils / glcanvas / win / glcanvas.cpp
CommitLineData
6a1120ad
JS
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
87b501f0
JS
26#include <wx/msw/private.h>
27
6a1120ad
JS
28#include "glcanvas.h"
29
87b501f0
JS
30wxChar wxGLCanvasClassName[] = wxT("wxGLCanvasClass");
31
3135f4a7 32LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
87b501f0
JS
33 WPARAM wParam, LPARAM lParam);
34
6a1120ad
JS
35/*
36 * GLContext implementation
37 */
38
089e55d6 39wxGLContext::wxGLContext(bool isRGB, wxGLCanvas *win, const wxPalette& palette)
6a1120ad
JS
40{
41 m_window = win;
42
089e55d6 43 m_hDC = win->GetHDC();
6a1120ad
JS
44
45 m_glContext = wglCreateContext((HDC) m_hDC);
089e55d6
RR
46 wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" );
47
6a1120ad
JS
48 wglMakeCurrent((HDC) m_hDC, m_glContext);
49}
50
3135f4a7
RD
51wxGLContext::wxGLContext(
52 bool isRGB, wxGLCanvas *win,
089e55d6
RR
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
6a1120ad
JS
70wxGLContext::~wxGLContext()
71{
72 if (m_glContext)
73 {
74 wglMakeCurrent(NULL, NULL);
089e55d6 75 wglDeleteContext(m_glContext);
6a1120ad 76 }
6a1120ad
JS
77}
78
79void 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
88void 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
101void 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
089e55d6
RR
116
117/*
118 * wxGLCanvas implementation
119 */
120
121IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow)
122
123BEGIN_EVENT_TABLE(wxGLCanvas, wxScrolledWindow)
124 EVT_SIZE(wxGLCanvas::OnSize)
125 EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged)
126 EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette)
127END_EVENT_TABLE()
128
129wxGLCanvas::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):
f6081a04 132 wxScrolledWindow()
089e55d6 133{
f6081a04 134 m_glContext = (wxGLContext*) NULL;
089e55d6 135
f6081a04
JS
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
bd1b0b3e 144 m_hDC = (WXHDC) ::GetDC((HWND) GetHWND());
f6081a04
JS
145
146 SetupPixelFormat();
147 SetupPalette(palette);
148
149 m_glContext = new wxGLContext(TRUE, this, palette);
089e55d6 150}
87b501f0 151
3135f4a7 152wxGLCanvas::wxGLCanvas( wxWindow *parent,
089e55d6
RR
153 const wxGLContext *shared, wxWindowID id,
154 const wxPoint& pos, const wxSize& size, long style, const wxString& name,
87b501f0
JS
155 int *attribList, const wxPalette& palette )
156 : wxScrolledWindow()
3135f4a7 157{
bd1b0b3e 158 m_glContext = (wxGLContext*) NULL;
f6081a04 159
bd1b0b3e 160 bool ret = Create(parent, id, pos, size, style, name);
089e55d6 161
87b501f0
JS
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);
089e55d6 172
87b501f0 173 m_glContext = new wxGLContext(TRUE, this, palette, shared );
089e55d6
RR
174}
175
bd1b0b3e
SB
176// Not very usefull for wxMSW, but this is to be wxGTK compliant
177
178wxGLCanvas::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
089e55d6
RR
203wxGLCanvas::~wxGLCanvas()
204{
205 if (m_glContext)
206 delete m_glContext;
207
208 ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC);
209}
210
87b501f0
JS
211// Replaces wxWindow::Create functionality, since we need to use a different window class
212bool 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/*
8aaef284
JS
221 From Angel Popov <jumpo@bitex.com>
222
87b501f0
JS
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 }
8aaef284 263 registeredGLCanvasClass = TRUE;
87b501f0
JS
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
089e55d6 311void wxGLCanvas::SetupPixelFormat() // (HDC hDC)
6a1120ad
JS
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
089e55d6 349void wxGLCanvas::SetupPalette(const wxPalette& palette)
6a1120ad
JS
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
089e55d6 378wxPalette wxGLCanvas::CreateDefaultPalette()
6a1120ad
JS
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
6a1120ad
JS
420void wxGLCanvas::SwapBuffers()
421{
422 if (m_glContext)
423 m_glContext->SwapBuffers();
424}
425
426void 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
443void wxGLCanvas::SetCurrent()
444{
445 if (m_glContext)
446 {
447 m_glContext->SetCurrent();
448 }
449}
450
451void 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...
459void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event)
460{
461 /* realize palette if this is the current window */
089e55d6
RR
462 if ( GetPalette()->Ok() ) {
463 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
464 ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
465 ::RealizePalette((HDC) GetHDC());
6a1120ad
JS
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.
474void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event)
475{
476 /* realize palette if this is *not* the current window */
089e55d6
RR
477 if ( GetPalette() &&
478 GetPalette()->Ok() && (this != event.GetChangedWindow()) )
6a1120ad 479 {
089e55d6
RR
480 ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE());
481 ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE);
482 ::RealizePalette((HDC) GetHDC());
6a1120ad
JS
483 Refresh();
484 }
485}
486
487/* Give extensions proper function names. */
488
489/* EXT_vertex_array */
490void glArrayElementEXT(GLint i)
491{
492}
493
494void glColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
495{
496}
497
498void 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
513void glEdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *pointer)
514{
515}
516
517void glGetPointervEXT(GLenum pname, GLvoid* *params)
518{
519}
520
521void glIndexPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
522{
523}
524
525void 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
540void glTexCoordPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer)
541{
542}
543
544void 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 */
560void glColorSubtableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *table)
561{
562}
563
564/* EXT_color_table */
565void glColorTableEXT(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table)
566{
567}
568
569void glCopyColorTableEXT(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width)
570{
571}
572
573void glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *table)
574{
575}
576
577void glGetColorTableParamaterfvEXT(GLenum target, GLenum pname, GLfloat *params)
578{
579}
580
581void glGetColorTavleParameterivEXT(GLenum target, GLenum pname, GLint *params)
582{
583}
584
585/* SGI_compiled_vertex_array */
586void glLockArraysSGI(GLint first, GLsizei count)
587{
588}
589
590void glUnlockArraysSGI()
591{
592}
593
594
595/* SGI_cull_vertex */
596void glCullParameterdvSGI(GLenum pname, GLdouble* params)
597{
598}
599
600void glCullParameterfvSGI(GLenum pname, GLfloat* params)
601{
602}
603
604/* SGI_index_func */
605void glIndexFuncSGI(GLenum func, GLclampf ref)
606{
607}
608
609/* SGI_index_material */
610void glIndexMaterialSGI(GLenum face, GLenum mode)
611{
612}
613
614/* WIN_swap_hint */
615void glAddSwapHintRectWin(GLint x, GLint y, GLsizei width, GLsizei height)
616{
617}
618