]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/glcanvas.cpp
OSXTimer for all variants
[wxWidgets.git] / src / osx / carbon / glcanvas.cpp
CommitLineData
489468fe
SC
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/mac/carbon/glcanvas.cpp
3// Purpose: wxGLCanvas, for using OpenGL with wxWidgets under Macintosh
4// Author: Stefan Csomor
5// Modified by:
6// Created: 1998-01-01
7// RCS-ID: $Id$
8// Copyright: (c) Stefan Csomor
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#if defined(__BORLANDC__)
23 #pragma hdrstop
24#endif
25
26#if wxUSE_GLCANVAS
27
28#include "wx/glcanvas.h"
29
30#ifndef WX_PRECOMP
31 #include "wx/frame.h"
32 #include "wx/log.h"
33 #include "wx/settings.h"
34#endif
35
1f0c8f31 36#include "wx/osx/uma.h"
489468fe 37
1f0c8f31 38#include "wx/osx/private.h"
489468fe
SC
39
40// ----------------------------------------------------------------------------
41// helper functions
42// ----------------------------------------------------------------------------
43
44static void wxLogAGLError(const char *func)
45{
46 const int err = aglGetError();
47
48 wxLogError(_("OpenGL function \"%s\" failed: %s (error %d)"),
49 func, aglErrorString(err), err);
50}
51
52// ============================================================================
53// implementation
54// ============================================================================
55
56// ----------------------------------------------------------------------------
57// wxGLContext
58// ----------------------------------------------------------------------------
59
60wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext *other)
61{
62 m_aglContext = aglCreateContext(win->GetAGLPixelFormat(),
63 other ? other->m_aglContext : NULL);
64 if ( !m_aglContext )
65 wxLogAGLError("aglCreateContext");
66}
67
68wxGLContext::~wxGLContext()
69{
70 if ( m_aglContext )
71 {
72 // it's ok to pass the current context to this function
73 if ( !aglDestroyContext(m_aglContext) )
74 wxLogAGLError("aglDestroyContext");
75 }
76}
77
78bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
79{
80 if ( !m_aglContext )
81 return false;
82
83 AGLDrawable drawable = (AGLDrawable)GetWindowPort(
84 MAC_WXHWND(win.MacGetTopLevelWindowRef()));
85 if ( !aglSetDrawable(m_aglContext, drawable) )
86 {
87 wxLogAGLError("aglSetDrawable");
88 return false;
89 }
90
91 if ( !aglSetCurrentContext(m_aglContext) )
92 {
93 wxLogAGLError("aglSetCurrentContext");
94 return false;
95 }
96
97 wx_const_cast(wxGLCanvas&, win).SetViewport();
98 return true;
99}
100
101// ----------------------------------------------------------------------------
102// wxGLCanvas
103// ----------------------------------------------------------------------------
104
105IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
106
107BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
108 EVT_SIZE(wxGLCanvas::OnSize)
109END_EVENT_TABLE()
110
111wxGLCanvas::wxGLCanvas(wxWindow *parent,
112 wxWindowID id,
113 const int *attribList,
114 const wxPoint& pos,
115 const wxSize& size,
116 long style,
117 const wxString& name,
118 const wxPalette& palette)
119{
120 Create(parent, id, pos, size, style, name, attribList, palette);
121}
122
123#if WXWIN_COMPATIBILITY_2_8
124
125wxGLCanvas::wxGLCanvas(wxWindow *parent,
126 wxWindowID id,
127 const wxPoint& pos,
128 const wxSize& size,
129 long style,
130 const wxString& name,
131 const int *attribList,
132 const wxPalette& palette)
133{
134 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
135 m_glContext = new wxGLContext(this);
136}
137
138wxGLCanvas::wxGLCanvas(wxWindow *parent,
139 const wxGLContext *shared,
140 wxWindowID id,
141 const wxPoint& pos,
142 const wxSize& size,
143 long style,
144 const wxString& name,
145 const int *attribList,
146 const wxPalette& palette)
147{
148 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
149 m_glContext = new wxGLContext(this, shared);
150}
151
152wxGLCanvas::wxGLCanvas(wxWindow *parent,
153 const wxGLCanvas *shared,
154 wxWindowID id,
155 const wxPoint& pos,
156 const wxSize& size,
157 long style,
158 const wxString& name,
159 const int *attribList,
160 const wxPalette& palette)
161{
162 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
163 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
164}
165
166#endif // WXWIN_COMPATIBILITY_2_8
167
168/* static */
169bool wxGLCanvasBase::IsExtensionSupported(const char *extension)
170{
171 // we need a valid context to query for extensions.
172 const GLint defaultAttribs[] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_NONE };
173 AGLPixelFormat fmt = aglChoosePixelFormat(NULL, 0, defaultAttribs);
174 AGLContext ctx = aglCreateContext(fmt, NULL);
175 if ( !ctx )
176 return false;
177
178 wxString extensions = wxString::FromAscii(glGetString(GL_EXTENSIONS));
179
180 aglDestroyPixelFormat(fmt);
181 aglDestroyContext(ctx);
182
183 return IsExtensionInList(extensions, extension);
184}
185
186/* static */
187bool wxGLCanvas::IsAGLMultiSampleAvailable()
188{
189 static int s_isMultiSampleAvailable = -1;
190 if ( s_isMultiSampleAvailable == -1 )
191 s_isMultiSampleAvailable = IsExtensionSupported("GL_ARB_multisample");
192
193 return s_isMultiSampleAvailable != 0;
194}
195
196static AGLPixelFormat ChoosePixelFormat(const int *attribList)
197{
198 GLint data[512];
199 const GLint defaultAttribs[] =
200 {
201 AGL_RGBA,
202 AGL_DOUBLEBUFFER,
203 AGL_MINIMUM_POLICY, // never choose less than requested
204 AGL_DEPTH_SIZE, 1, // use largest available depth buffer
205 AGL_RED_SIZE, 1,
206 AGL_GREEN_SIZE, 1,
207 AGL_BLUE_SIZE, 1,
208 AGL_ALPHA_SIZE, 0,
209 AGL_NONE
210 };
211
212 const GLint *attribs;
213 if ( !attribList )
214 {
215 attribs = defaultAttribs;
216 }
217 else
218 {
219 unsigned p = 0;
220 data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX
221
222 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
223 {
224 switch ( attribList[arg++] )
225 {
226 case WX_GL_RGBA:
227 data[p++] = AGL_RGBA;
228 break;
229
230 case WX_GL_BUFFER_SIZE:
231 data[p++] = AGL_BUFFER_SIZE;
232 data[p++] = attribList[arg++];
233 break;
234
235 case WX_GL_LEVEL:
236 data[p++]=AGL_LEVEL;
237 data[p++]=attribList[arg++];
238 break;
239
240 case WX_GL_DOUBLEBUFFER:
241 data[p++] = AGL_DOUBLEBUFFER;
242 break;
243
244 case WX_GL_STEREO:
245 data[p++] = AGL_STEREO;
246 break;
247
248 case WX_GL_AUX_BUFFERS:
249 data[p++] = AGL_AUX_BUFFERS;
250 data[p++] = attribList[arg++];
251 break;
252
253 case WX_GL_MIN_RED:
254 data[p++] = AGL_RED_SIZE;
255 data[p++] = attribList[arg++];
256 break;
257
258 case WX_GL_MIN_GREEN:
259 data[p++] = AGL_GREEN_SIZE;
260 data[p++] = attribList[arg++];
261 break;
262
263 case WX_GL_MIN_BLUE:
264 data[p++] = AGL_BLUE_SIZE;
265 data[p++] = attribList[arg++];
266 break;
267
268 case WX_GL_MIN_ALPHA:
269 data[p++] = AGL_ALPHA_SIZE;
270 data[p++] = attribList[arg++];
271 break;
272
273 case WX_GL_DEPTH_SIZE:
274 data[p++] = AGL_DEPTH_SIZE;
275 data[p++] = attribList[arg++];
276 break;
277
278 case WX_GL_STENCIL_SIZE:
279 data[p++] = AGL_STENCIL_SIZE;
280 data[p++] = attribList[arg++];
281 break;
282
283 case WX_GL_MIN_ACCUM_RED:
284 data[p++] = AGL_ACCUM_RED_SIZE;
285 data[p++] = attribList[arg++];
286 break;
287
288 case WX_GL_MIN_ACCUM_GREEN:
289 data[p++] = AGL_ACCUM_GREEN_SIZE;
290 data[p++] = attribList[arg++];
291 break;
292
293 case WX_GL_MIN_ACCUM_BLUE:
294 data[p++] = AGL_ACCUM_BLUE_SIZE;
295 data[p++] = attribList[arg++];
296 break;
297
298 case WX_GL_MIN_ACCUM_ALPHA:
299 data[p++] = AGL_ACCUM_ALPHA_SIZE;
300 data[p++] = attribList[arg++];
301 break;
302
303 case WX_GL_SAMPLE_BUFFERS:
304 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
305 {
306 if ( !attribList[arg++] )
307 break;
308
309 return false;
310 }
311
312 data[p++] = AGL_SAMPLE_BUFFERS_ARB;
313 if ( (data[p++] = attribList[arg++]) == true )
314 {
315 // don't use software fallback
316 data[p++] = AGL_NO_RECOVERY;
317 }
318 break;
319
320 case WX_GL_SAMPLES:
321 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
322 {
323 if ( !attribList[arg++] )
324 break;
325
326 return false;
327 }
328
329 data[p++] = AGL_SAMPLES_ARB;
330 data[p++] = attribList[arg++];
331 break;
332 }
333 }
334
335 data[p] = AGL_NONE;
336
337 attribs = data;
338 }
339
340 return aglChoosePixelFormat(NULL, 0, attribs);
341}
342
343bool wxGLCanvas::Create(wxWindow *parent,
344 wxWindowID id,
345 const wxPoint& pos,
346 const wxSize& size,
347 long style,
348 const wxString& name,
349 const int *attribList,
350 const wxPalette& WXUNUSED(palette))
351{
352 m_needsUpdate = false;
353 m_macCanvasIsShown = false;
354
355 m_aglFormat = ChoosePixelFormat(attribList);
356 if ( !m_aglFormat )
357 return false;
358
359 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
360 return false;
361
362 m_macCanvasIsShown = true;
363
364 return true;
365}
366
367wxGLCanvas::~wxGLCanvas()
368{
369 if ( m_aglFormat )
370 aglDestroyPixelFormat(m_aglFormat);
371}
372
373/* static */
374bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
375{
376 AGLPixelFormat aglFormat = ChoosePixelFormat(attribList);
377
378 if ( !aglFormat )
379 return false;
380
381 aglDestroyPixelFormat(aglFormat);
382
383 return true;
384}
385
386bool wxGLCanvas::SwapBuffers()
387{
388 AGLContext context = aglGetCurrentContext();
389 wxCHECK_MSG(context, false, _T("should have current context"));
390
391 aglSwapBuffers(context);
392 return true;
393}
394
395void wxGLCanvas::SetViewport()
396{
397 if ( !m_needsUpdate )
398 return;
399
400 m_needsUpdate = false;
401
402 AGLContext context = aglGetCurrentContext();
403 if ( !context )
404 return;
405
406 // viewport is initially set to entire port, adjust it to just this window
407 int x = 0,
408 y = 0;
409 MacClientToRootWindow(&x , &y);
410
411 int width, height;
412 GetClientSize(&width, &height);
413
414 Rect bounds;
415 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds);
416
417#if 0
418 // TODO in case we adopt point vs pixel coordinates, this will make the conversion
419 HIRect hiRect = CGRectMake( x, y, width, height );
420 HIRectConvert( &hiRect, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
421 HIRect hiBounds = CGRectMake( 0, 0, bounds.right - bounds.left , bounds.bottom - bounds.top );
422 HIRectConvert( &hiBounds, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
423 GLint parms[4];
424 parms[0] = hiRect.origin.x;
425 parms[1] = hiBounds.size.height - (hiRect.origin.y + hiRect.size.height);
426 parms[2] = hiRect.size.width;
427 parms[3] = hiRect.size.height;
428#else
429 GLint parms[4];
430 parms[0] = x;
431 parms[1] = bounds.bottom - bounds.top - ( y + height );
432 parms[2] = width;
433 parms[3] = height;
434#endif
435
436 // move the buffer rect out of sight if we're hidden
437 if ( !m_macCanvasIsShown )
438 parms[0] += 20000;
439
440 if ( !aglSetInteger(context, AGL_BUFFER_RECT, parms) )
441 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
442
443 if ( !aglEnable(context, AGL_BUFFER_RECT) )
444 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
445
446 if ( !aglUpdateContext(context) )
447 wxLogAGLError("aglUpdateContext");
448}
449
450void wxGLCanvas::OnSize(wxSizeEvent& event)
451{
452 MacUpdateView();
453 event.Skip();
454}
455
456void wxGLCanvas::MacUpdateView()
457{
458 m_needsUpdate = true;
459 Refresh(false);
460}
461
462void wxGLCanvas::MacSuperChangedPosition()
463{
464 MacUpdateView();
465 wxWindow::MacSuperChangedPosition();
466}
467
468void wxGLCanvas::MacTopLevelWindowChangedPosition()
469{
470 MacUpdateView();
471 wxWindow::MacTopLevelWindowChangedPosition();
472}
473
474void wxGLCanvas::MacVisibilityChanged()
475{
476 if ( IsShownOnScreen() != m_macCanvasIsShown )
477 {
478 m_macCanvasIsShown = !m_macCanvasIsShown;
479 MacUpdateView();
480 }
481
482 wxWindowMac::MacVisibilityChanged();
483}
484
485// ----------------------------------------------------------------------------
486// wxGLApp
487// ----------------------------------------------------------------------------
488
489bool wxGLApp::InitGLVisual(const int *attribList)
490{
491 AGLPixelFormat fmt = ChoosePixelFormat(attribList);
492 if ( !fmt )
493 return false;
494
495 aglDestroyPixelFormat(fmt);
496 return true;
497}
498
499#endif // wxUSE_GLCANVAS