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 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(
261 MAC_WXHWND(win
.MacGetTopLevelWindowRef()));
263 GLint bufnummer
= win
.GetAglBufferName();
264 aglSetInteger(m_glContext
, AGL_BUFFER_NAME
, &bufnummer
);
265 //win.SetLastContext(m_glContext);
267 const_cast<wxGLCanvas
&>(win
).SetViewport();
269 if ( !aglSetDrawable(m_glContext
, drawable
) )
271 wxLogAGLError("aglSetDrawable");
275 return WXGLSetCurrentContext(m_glContext
);
278 // ----------------------------------------------------------------------------
280 // ----------------------------------------------------------------------------
284 sharing contexts under AGL is not straightforward, to quote from
286 http://lists.apple.com/archives/mac-opengl/2003/Jan/msg00402.html :
288 In Carbon OpenGL (AGL) you would use call aglSetInteger to setup a
289 buffer name and attached each context to that same name. From AGL
294 ctx1 = aglCreateContext...
295 aglSetInteger(ctx1, AGL_BUFFER_NAME, &id); // create name
296 aglAttachDrawable (ctx1,...); // create surface with associated with
298 ctx2 = aglCreateContext...
299 aglSetInteger(ctx2, AGL_BUFFER_NAME, &id); // uses previously created name
300 aglAttachDrawable (ctx2, ...); // uses existing surface with existing name
304 params contains one value: a non-negative integer name of the surface to be
305 associated to be with the current context. If this value is non-zero, and a
306 surface of this name is not associated to this drawable, a new surface with
307 this name is created and associated with the context when
308 aglSetDrawable is called subsequently. If this is a previously allocated
309 buffer name within the namespace of the current window (e.g., drawable),
310 that previously allocated surface is associated with the context (e.g., no
311 new surface is created) and the subsequent call to aglSetDrawable will
312 attach that surface. This allows multiple contexts to be attached to a single
313 surface. Using the default buffer name zero, returns to one surface per
318 so what I'm doing is to have a dummy aglContext attached to a wxGLCanvas,
319 assign it a buffer number
323 bool wxGLCanvas::Create(wxWindow
*parent
,
328 const wxString
& name
,
329 const int *attribList
,
330 const wxPalette
& WXUNUSED(palette
))
332 m_needsUpdate
= false;
333 m_macCanvasIsShown
= false;
335 m_glFormat
= WXGLChoosePixelFormat(attribList
);
339 if ( !wxWindow::Create(parent
, id
, pos
, size
, style
, name
) )
342 m_dummyContext
= WXGLCreateContext(m_glFormat
, NULL
);
344 static GLint gCurrentBufferName
= 1;
345 m_bufferName
= gCurrentBufferName
++;
346 aglSetInteger (m_dummyContext
, AGL_BUFFER_NAME
, &m_bufferName
);
348 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(MAC_WXHWND(MacGetTopLevelWindowRef()));
349 aglSetDrawable(m_dummyContext
, drawable
);
351 m_macCanvasIsShown
= true;
356 wxGLCanvas::~wxGLCanvas()
359 WXGLDestroyPixelFormat(m_glFormat
);
361 if ( m_dummyContext
)
362 WXGLDestroyContext(m_dummyContext
);
365 bool wxGLCanvas::SwapBuffers()
367 WXGLContext context
= WXGLGetCurrentContext();
368 wxCHECK_MSG(context
, false, wxT("should have current context"));
370 aglSwapBuffers(context
);
374 void wxGLCanvas::SetViewport()
376 if ( !m_needsUpdate
)
379 m_needsUpdate
= false;
381 // AGLContext context = aglGetCurrentContext();
385 // viewport is initially set to entire port, adjust it to just this window
388 MacClientToRootWindow(&x
, &y
);
391 GetClientSize(&width
, &height
);
394 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds
);
398 parms
[1] = bounds
.bottom
- bounds
.top
- ( y
+ height
);
402 // move the buffer rect out of sight if we're hidden
403 if ( !m_macCanvasIsShown
)
406 if ( !aglSetInteger(m_dummyContext
, AGL_BUFFER_RECT
, parms
) )
407 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
409 if ( !aglEnable(m_dummyContext
, AGL_BUFFER_RECT
) )
410 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
412 if ( !aglUpdateContext(m_dummyContext
) )
413 wxLogAGLError("aglUpdateContext");
416 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
422 void wxGLCanvas::MacUpdateView()
424 m_needsUpdate
= true;
428 void wxGLCanvas::MacSuperChangedPosition()
432 wxWindow::MacSuperChangedPosition();
435 void wxGLCanvas::MacTopLevelWindowChangedPosition()
438 wxWindow::MacTopLevelWindowChangedPosition();
441 void wxGLCanvas::MacVisibilityChanged()
443 if ( IsShownOnScreen() != m_macCanvasIsShown
)
445 m_macCanvasIsShown
= !m_macCanvasIsShown
;
449 wxWindowMac::MacVisibilityChanged();
452 #endif // wxUSE_GLCANVAS