1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/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 void WXGLSwapBuffers( WXGLContext context
)
82 aglSwapBuffers(context
);
85 WXGLContext
WXGLGetCurrentContext()
87 return aglGetCurrentContext();
90 bool WXGLSetCurrentContext(WXGLContext context
)
92 if ( !aglSetCurrentContext(context
) )
94 wxLogAGLError("aglSetCurrentContext");
101 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat
)
105 aglDestroyPixelFormat(pixelFormat
);
109 WXGLPixelFormat
WXGLChoosePixelFormat(const int *attribList
)
112 const GLint defaultAttribs
[] =
116 AGL_MINIMUM_POLICY
, // never choose less than requested
117 AGL_DEPTH_SIZE
, 1, // use largest available depth buffer
125 const GLint
*attribs
;
128 attribs
= defaultAttribs
;
133 data
[p
++] = AGL_MINIMUM_POLICY
; // make _SIZE tags behave more like GLX
135 for ( unsigned arg
= 0; attribList
[arg
] !=0 && p
< WXSIZEOF(data
); )
137 switch ( attribList
[arg
++] )
140 data
[p
++] = AGL_RGBA
;
143 case WX_GL_BUFFER_SIZE
:
144 data
[p
++] = AGL_BUFFER_SIZE
;
145 data
[p
++] = attribList
[arg
++];
150 data
[p
++]=attribList
[arg
++];
153 case WX_GL_DOUBLEBUFFER
:
154 data
[p
++] = AGL_DOUBLEBUFFER
;
158 data
[p
++] = AGL_STEREO
;
161 case WX_GL_AUX_BUFFERS
:
162 data
[p
++] = AGL_AUX_BUFFERS
;
163 data
[p
++] = attribList
[arg
++];
167 data
[p
++] = AGL_RED_SIZE
;
168 data
[p
++] = attribList
[arg
++];
171 case WX_GL_MIN_GREEN
:
172 data
[p
++] = AGL_GREEN_SIZE
;
173 data
[p
++] = attribList
[arg
++];
177 data
[p
++] = AGL_BLUE_SIZE
;
178 data
[p
++] = attribList
[arg
++];
181 case WX_GL_MIN_ALPHA
:
182 data
[p
++] = AGL_ALPHA_SIZE
;
183 data
[p
++] = attribList
[arg
++];
186 case WX_GL_DEPTH_SIZE
:
187 data
[p
++] = AGL_DEPTH_SIZE
;
188 data
[p
++] = attribList
[arg
++];
191 case WX_GL_STENCIL_SIZE
:
192 data
[p
++] = AGL_STENCIL_SIZE
;
193 data
[p
++] = attribList
[arg
++];
196 case WX_GL_MIN_ACCUM_RED
:
197 data
[p
++] = AGL_ACCUM_RED_SIZE
;
198 data
[p
++] = attribList
[arg
++];
201 case WX_GL_MIN_ACCUM_GREEN
:
202 data
[p
++] = AGL_ACCUM_GREEN_SIZE
;
203 data
[p
++] = attribList
[arg
++];
206 case WX_GL_MIN_ACCUM_BLUE
:
207 data
[p
++] = AGL_ACCUM_BLUE_SIZE
;
208 data
[p
++] = attribList
[arg
++];
211 case WX_GL_MIN_ACCUM_ALPHA
:
212 data
[p
++] = AGL_ACCUM_ALPHA_SIZE
;
213 data
[p
++] = attribList
[arg
++];
216 case WX_GL_SAMPLE_BUFFERS
:
217 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
219 if ( !attribList
[arg
++] )
225 data
[p
++] = AGL_SAMPLE_BUFFERS_ARB
;
226 if ( (data
[p
++] = attribList
[arg
++]) == true )
228 // don't use software fallback
229 data
[p
++] = AGL_NO_RECOVERY
;
234 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
236 if ( !attribList
[arg
++] )
242 data
[p
++] = AGL_SAMPLES_ARB
;
243 data
[p
++] = attribList
[arg
++];
253 return aglChoosePixelFormat(NULL
, 0, attribs
);
256 // ----------------------------------------------------------------------------
258 // ----------------------------------------------------------------------------
260 bool wxGLContext::SetCurrent(const wxGLCanvas
& win
) const
265 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(
266 MAC_WXHWND(win
.MacGetTopLevelWindowRef()));
268 GLint bufnummer
= win
.GetAglBufferName();
269 aglSetInteger(m_glContext
, AGL_BUFFER_NAME
, &bufnummer
);
270 //win.SetLastContext(m_glContext);
272 const_cast<wxGLCanvas
&>(win
).SetViewport();
274 if ( !aglSetDrawable(m_glContext
, drawable
) )
276 wxLogAGLError("aglSetDrawable");
280 return WXGLSetCurrentContext(m_glContext
);
283 // ----------------------------------------------------------------------------
285 // ----------------------------------------------------------------------------
289 sharing contexts under AGL is not straightforward, to quote from
291 http://lists.apple.com/archives/mac-opengl/2003/Jan/msg00402.html :
293 In Carbon OpenGL (AGL) you would use call aglSetInteger to setup a
294 buffer name and attached each context to that same name. From AGL
299 ctx1 = aglCreateContext...
300 aglSetInteger(ctx1, AGL_BUFFER_NAME, &id); // create name
301 aglAttachDrawable (ctx1,...); // create surface with associated with
303 ctx2 = aglCreateContext...
304 aglSetInteger(ctx2, AGL_BUFFER_NAME, &id); // uses previously created name
305 aglAttachDrawable (ctx2, ...); // uses existing surface with existing name
309 params contains one value: a non-negative integer name of the surface to be
310 associated to be with the current context. If this value is non-zero, and a
311 surface of this name is not associated to this drawable, a new surface with
312 this name is created and associated with the context when
313 aglSetDrawable is called subsequently. If this is a previously allocated
314 buffer name within the namespace of the current window (e.g., drawable),
315 that previously allocated surface is associated with the context (e.g., no
316 new surface is created) and the subsequent call to aglSetDrawable will
317 attach that surface. This allows multiple contexts to be attached to a single
318 surface. Using the default buffer name zero, returns to one surface per
323 so what I'm doing is to have a dummy aglContext attached to a wxGLCanvas,
324 assign it a buffer number
328 bool wxGLCanvas::Create(wxWindow
*parent
,
333 const wxString
& name
,
334 const int *attribList
,
335 const wxPalette
& WXUNUSED(palette
))
337 m_needsUpdate
= false;
338 m_macCanvasIsShown
= false;
340 m_glFormat
= WXGLChoosePixelFormat(attribList
);
344 if ( !wxWindow::Create(parent
, id
, pos
, size
, style
, name
) )
347 m_dummyContext
= WXGLCreateContext(m_glFormat
, NULL
);
349 static GLint gCurrentBufferName
= 1;
350 m_bufferName
= gCurrentBufferName
++;
351 aglSetInteger (m_dummyContext
, AGL_BUFFER_NAME
, &m_bufferName
);
353 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(MAC_WXHWND(MacGetTopLevelWindowRef()));
354 aglSetDrawable(m_dummyContext
, drawable
);
356 m_macCanvasIsShown
= true;
361 wxGLCanvas::~wxGLCanvas()
364 WXGLDestroyPixelFormat(m_glFormat
);
366 if ( m_dummyContext
)
367 WXGLDestroyContext(m_dummyContext
);
370 void wxGLCanvas::SetViewport()
372 if ( !m_needsUpdate
)
375 m_needsUpdate
= false;
377 // AGLContext context = aglGetCurrentContext();
381 // viewport is initially set to entire port, adjust it to just this window
384 MacClientToRootWindow(&x
, &y
);
387 GetClientSize(&width
, &height
);
390 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds
);
394 parms
[1] = bounds
.bottom
- bounds
.top
- ( y
+ height
);
398 // move the buffer rect out of sight if we're hidden
399 if ( !m_macCanvasIsShown
)
402 if ( !aglSetInteger(m_dummyContext
, AGL_BUFFER_RECT
, parms
) )
403 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
405 if ( !aglEnable(m_dummyContext
, AGL_BUFFER_RECT
) )
406 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
408 if ( !aglUpdateContext(m_dummyContext
) )
409 wxLogAGLError("aglUpdateContext");
412 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
418 void wxGLCanvas::MacUpdateView()
420 m_needsUpdate
= true;
424 void wxGLCanvas::MacSuperChangedPosition()
428 wxWindow::MacSuperChangedPosition();
431 void wxGLCanvas::MacTopLevelWindowChangedPosition()
434 wxWindow::MacTopLevelWindowChangedPosition();
437 void wxGLCanvas::MacVisibilityChanged()
439 if ( IsShownOnScreen() != m_macCanvasIsShown
)
441 m_macCanvasIsShown
= !m_macCanvasIsShown
;
445 wxWindowMac::MacVisibilityChanged();
448 #endif // wxUSE_GLCANVAS