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