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