1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL with wxWidgets under Macintosh
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
22 #if defined(__BORLANDC__)
28 #include "wx/glcanvas.h"
33 #include "wx/settings.h"
36 #include "wx/osx/uma.h"
38 #include "wx/osx/private.h"
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 static void wxLogAGLError(const char *func
)
47 const int err
= aglGetError();
49 wxLogError(_("OpenGL function \"%s\" failed: %s (error %d)"),
50 func
, aglErrorString(err
), err
);
53 // ============================================================================
55 // ============================================================================
57 // ----------------------------------------------------------------------------
58 // low level implementation routines
59 // ----------------------------------------------------------------------------
61 WXGLContext
WXGLCreateContext( WXGLPixelFormat pixelFormat
, WXGLContext shareContext
)
63 WXGLContext context
= aglCreateContext(pixelFormat
, shareContext
);
65 wxLogAGLError("aglCreateContext");
69 void WXGLDestroyContext( WXGLContext context
)
73 if ( !aglDestroyContext(context
) )
75 wxLogAGLError("aglDestroyContext");
80 WXGLContext
WXGLGetCurrentContext()
82 return aglGetCurrentContext();
85 bool WXGLSetCurrentContext(WXGLContext context
)
87 if ( !aglSetCurrentContext(context
) )
89 wxLogAGLError("aglSetCurrentContext");
96 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat
)
100 aglDestroyPixelFormat(pixelFormat
);
104 WXGLPixelFormat
WXGLChoosePixelFormat(const int *attribList
)
107 const GLint defaultAttribs
[] =
111 AGL_MINIMUM_POLICY
, // never choose less than requested
112 AGL_DEPTH_SIZE
, 1, // use largest available depth buffer
120 const GLint
*attribs
;
123 attribs
= defaultAttribs
;
128 data
[p
++] = AGL_MINIMUM_POLICY
; // make _SIZE tags behave more like GLX
130 for ( unsigned arg
= 0; attribList
[arg
] !=0 && p
< WXSIZEOF(data
); )
132 switch ( attribList
[arg
++] )
135 data
[p
++] = AGL_RGBA
;
138 case WX_GL_BUFFER_SIZE
:
139 data
[p
++] = AGL_BUFFER_SIZE
;
140 data
[p
++] = attribList
[arg
++];
145 data
[p
++]=attribList
[arg
++];
148 case WX_GL_DOUBLEBUFFER
:
149 data
[p
++] = AGL_DOUBLEBUFFER
;
153 data
[p
++] = AGL_STEREO
;
156 case WX_GL_AUX_BUFFERS
:
157 data
[p
++] = AGL_AUX_BUFFERS
;
158 data
[p
++] = attribList
[arg
++];
162 data
[p
++] = AGL_RED_SIZE
;
163 data
[p
++] = attribList
[arg
++];
166 case WX_GL_MIN_GREEN
:
167 data
[p
++] = AGL_GREEN_SIZE
;
168 data
[p
++] = attribList
[arg
++];
172 data
[p
++] = AGL_BLUE_SIZE
;
173 data
[p
++] = attribList
[arg
++];
176 case WX_GL_MIN_ALPHA
:
177 data
[p
++] = AGL_ALPHA_SIZE
;
178 data
[p
++] = attribList
[arg
++];
181 case WX_GL_DEPTH_SIZE
:
182 data
[p
++] = AGL_DEPTH_SIZE
;
183 data
[p
++] = attribList
[arg
++];
186 case WX_GL_STENCIL_SIZE
:
187 data
[p
++] = AGL_STENCIL_SIZE
;
188 data
[p
++] = attribList
[arg
++];
191 case WX_GL_MIN_ACCUM_RED
:
192 data
[p
++] = AGL_ACCUM_RED_SIZE
;
193 data
[p
++] = attribList
[arg
++];
196 case WX_GL_MIN_ACCUM_GREEN
:
197 data
[p
++] = AGL_ACCUM_GREEN_SIZE
;
198 data
[p
++] = attribList
[arg
++];
201 case WX_GL_MIN_ACCUM_BLUE
:
202 data
[p
++] = AGL_ACCUM_BLUE_SIZE
;
203 data
[p
++] = attribList
[arg
++];
206 case WX_GL_MIN_ACCUM_ALPHA
:
207 data
[p
++] = AGL_ACCUM_ALPHA_SIZE
;
208 data
[p
++] = attribList
[arg
++];
211 case WX_GL_SAMPLE_BUFFERS
:
212 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
214 if ( !attribList
[arg
++] )
220 data
[p
++] = AGL_SAMPLE_BUFFERS_ARB
;
221 if ( (data
[p
++] = attribList
[arg
++]) == true )
223 // don't use software fallback
224 data
[p
++] = AGL_NO_RECOVERY
;
229 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
231 if ( !attribList
[arg
++] )
237 data
[p
++] = AGL_SAMPLES_ARB
;
238 data
[p
++] = attribList
[arg
++];
248 return aglChoosePixelFormat(NULL
, 0, attribs
);
251 // ----------------------------------------------------------------------------
253 // ----------------------------------------------------------------------------
255 bool wxGLContext::SetCurrent(const wxGLCanvas
& win
) const
260 GLint bufnummer
= win
.GetAglBufferName();
261 aglSetInteger(m_glContext
, AGL_BUFFER_NAME
, &bufnummer
);
262 //win.SetLastContext(m_glContext);
264 const_cast<wxGLCanvas
&>(win
).SetViewport();
267 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
268 if ( UMAGetSystemVersion() >= 0x1050 )
270 aglSetWindowRef(m_glContext
, win
.MacGetTopLevelWindowRef());
275 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(
276 MAC_WXHWND(win
.MacGetTopLevelWindowRef()));
278 if ( !aglSetDrawable(m_glContext
, drawable
) )
280 wxLogAGLError("aglSetDrawable");
285 return WXGLSetCurrentContext(m_glContext
);
288 // ----------------------------------------------------------------------------
290 // ----------------------------------------------------------------------------
294 sharing contexts under AGL is not straightforward, to quote from
296 http://lists.apple.com/archives/mac-opengl/2003/Jan/msg00402.html :
298 In Carbon OpenGL (AGL) you would use call aglSetInteger to setup a
299 buffer name and attached each context to that same name. From AGL
304 ctx1 = aglCreateContext...
305 aglSetInteger(ctx1, AGL_BUFFER_NAME, &id); // create name
306 aglAttachDrawable (ctx1,...); // create surface with associated with
308 ctx2 = aglCreateContext...
309 aglSetInteger(ctx2, AGL_BUFFER_NAME, &id); // uses previously created name
310 aglAttachDrawable (ctx2, ...); // uses existing surface with existing name
314 params contains one value: a non-negative integer name of the surface to be
315 associated to be with the current context. If this value is non-zero, and a
316 surface of this name is not associated to this drawable, a new surface with
317 this name is created and associated with the context when
318 aglSetDrawable is called subsequently. If this is a previously allocated
319 buffer name within the namespace of the current window (e.g., drawable),
320 that previously allocated surface is associated with the context (e.g., no
321 new surface is created) and the subsequent call to aglSetDrawable will
322 attach that surface. This allows multiple contexts to be attached to a single
323 surface. Using the default buffer name zero, returns to one surface per
328 so what I'm doing is to have a dummy aglContext attached to a wxGLCanvas,
329 assign it a buffer number
333 bool wxGLCanvas::Create(wxWindow
*parent
,
338 const wxString
& name
,
339 const int *attribList
,
340 const wxPalette
& WXUNUSED(palette
))
342 m_needsUpdate
= false;
343 m_macCanvasIsShown
= false;
345 m_glFormat
= WXGLChoosePixelFormat(attribList
);
349 if ( !wxWindow::Create(parent
, id
, pos
, size
, style
, name
) )
352 m_dummyContext
= WXGLCreateContext(m_glFormat
, NULL
);
354 static GLint gCurrentBufferName
= 1;
355 m_bufferName
= gCurrentBufferName
++;
356 aglSetInteger (m_dummyContext
, AGL_BUFFER_NAME
, &m_bufferName
);
358 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
359 if ( UMAGetSystemVersion() >= 0x1050 )
361 aglSetWindowRef(m_dummyContext
, MacGetTopLevelWindowRef());
366 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(MAC_WXHWND(MacGetTopLevelWindowRef()));
367 aglSetDrawable(m_dummyContext
, drawable
);
370 m_macCanvasIsShown
= true;
375 wxGLCanvas::~wxGLCanvas()
378 WXGLDestroyPixelFormat(m_glFormat
);
380 if ( m_dummyContext
)
381 WXGLDestroyContext(m_dummyContext
);
384 bool wxGLCanvas::SwapBuffers()
386 WXGLContext context
= WXGLGetCurrentContext();
387 wxCHECK_MSG(context
, false, wxT("should have current context"));
389 aglSwapBuffers(context
);
393 void wxGLCanvas::SetViewport()
395 if ( !m_needsUpdate
)
398 m_needsUpdate
= false;
400 // AGLContext context = aglGetCurrentContext();
404 // viewport is initially set to entire port, adjust it to just this window
407 MacClientToRootWindow(&x
, &y
);
410 GetClientSize(&width
, &height
);
413 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds
);
417 parms
[1] = bounds
.bottom
- bounds
.top
- ( y
+ height
);
421 // move the buffer rect out of sight if we're hidden
422 if ( !m_macCanvasIsShown
)
425 if ( !aglSetInteger(m_dummyContext
, AGL_BUFFER_RECT
, parms
) )
426 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
428 if ( !aglEnable(m_dummyContext
, AGL_BUFFER_RECT
) )
429 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
431 if ( !aglUpdateContext(m_dummyContext
) )
432 wxLogAGLError("aglUpdateContext");
435 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
441 void wxGLCanvas::MacUpdateView()
443 m_needsUpdate
= true;
447 void wxGLCanvas::MacSuperChangedPosition()
451 wxWindow::MacSuperChangedPosition();
454 void wxGLCanvas::MacTopLevelWindowChangedPosition()
457 wxWindow::MacTopLevelWindowChangedPosition();
460 void wxGLCanvas::MacVisibilityChanged()
462 if ( IsShownOnScreen() != m_macCanvasIsShown
)
464 m_macCanvasIsShown
= !m_macCanvasIsShown
;
468 wxWindowMac::MacVisibilityChanged();
471 #endif // wxUSE_GLCANVAS