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 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat
)
94 aglDestroyPixelFormat(pixelFormat
);
98 WXGLPixelFormat
WXGLChoosePixelFormat(const int *attribList
)
101 const GLint defaultAttribs
[] =
105 AGL_MINIMUM_POLICY
, // never choose less than requested
106 AGL_DEPTH_SIZE
, 1, // use largest available depth buffer
114 const GLint
*attribs
;
117 attribs
= defaultAttribs
;
122 data
[p
++] = AGL_MINIMUM_POLICY
; // make _SIZE tags behave more like GLX
124 for ( unsigned arg
= 0; attribList
[arg
] !=0 && p
< WXSIZEOF(data
); )
126 switch ( attribList
[arg
++] )
129 data
[p
++] = AGL_RGBA
;
132 case WX_GL_BUFFER_SIZE
:
133 data
[p
++] = AGL_BUFFER_SIZE
;
134 data
[p
++] = attribList
[arg
++];
139 data
[p
++]=attribList
[arg
++];
142 case WX_GL_DOUBLEBUFFER
:
143 data
[p
++] = AGL_DOUBLEBUFFER
;
147 data
[p
++] = AGL_STEREO
;
150 case WX_GL_AUX_BUFFERS
:
151 data
[p
++] = AGL_AUX_BUFFERS
;
152 data
[p
++] = attribList
[arg
++];
156 data
[p
++] = AGL_RED_SIZE
;
157 data
[p
++] = attribList
[arg
++];
160 case WX_GL_MIN_GREEN
:
161 data
[p
++] = AGL_GREEN_SIZE
;
162 data
[p
++] = attribList
[arg
++];
166 data
[p
++] = AGL_BLUE_SIZE
;
167 data
[p
++] = attribList
[arg
++];
170 case WX_GL_MIN_ALPHA
:
171 data
[p
++] = AGL_ALPHA_SIZE
;
172 data
[p
++] = attribList
[arg
++];
175 case WX_GL_DEPTH_SIZE
:
176 data
[p
++] = AGL_DEPTH_SIZE
;
177 data
[p
++] = attribList
[arg
++];
180 case WX_GL_STENCIL_SIZE
:
181 data
[p
++] = AGL_STENCIL_SIZE
;
182 data
[p
++] = attribList
[arg
++];
185 case WX_GL_MIN_ACCUM_RED
:
186 data
[p
++] = AGL_ACCUM_RED_SIZE
;
187 data
[p
++] = attribList
[arg
++];
190 case WX_GL_MIN_ACCUM_GREEN
:
191 data
[p
++] = AGL_ACCUM_GREEN_SIZE
;
192 data
[p
++] = attribList
[arg
++];
195 case WX_GL_MIN_ACCUM_BLUE
:
196 data
[p
++] = AGL_ACCUM_BLUE_SIZE
;
197 data
[p
++] = attribList
[arg
++];
200 case WX_GL_MIN_ACCUM_ALPHA
:
201 data
[p
++] = AGL_ACCUM_ALPHA_SIZE
;
202 data
[p
++] = attribList
[arg
++];
205 case WX_GL_SAMPLE_BUFFERS
:
206 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
208 if ( !attribList
[arg
++] )
214 data
[p
++] = AGL_SAMPLE_BUFFERS_ARB
;
215 if ( (data
[p
++] = attribList
[arg
++]) == true )
217 // don't use software fallback
218 data
[p
++] = AGL_NO_RECOVERY
;
223 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
225 if ( !attribList
[arg
++] )
231 data
[p
++] = AGL_SAMPLES_ARB
;
232 data
[p
++] = attribList
[arg
++];
242 return aglChoosePixelFormat(NULL
, 0, attribs
);
245 // ----------------------------------------------------------------------------
247 // ----------------------------------------------------------------------------
249 bool wxGLContext::SetCurrent(const wxGLCanvas
& win
) const
254 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(
255 MAC_WXHWND(win
.MacGetTopLevelWindowRef()));
257 GLint bufnummer
= win
.GetAglBufferName();
258 aglSetInteger(m_glContext
, AGL_BUFFER_NAME
, &bufnummer
);
259 //win.SetLastContext(m_glContext);
261 wx_const_cast(wxGLCanvas
&, win
).SetViewport();
263 if ( !aglSetDrawable(m_glContext
, drawable
) )
265 wxLogAGLError("aglSetDrawable");
269 if ( !aglSetCurrentContext(m_glContext
) )
271 wxLogAGLError("aglSetCurrentContext");
277 // ----------------------------------------------------------------------------
279 // ----------------------------------------------------------------------------
283 sharing contexts under AGL is not straightforward, to quote from
285 http://lists.apple.com/archives/mac-opengl/2003/Jan/msg00402.html :
287 In Carbon OpenGL (AGL) you would use call aglSetInteger to setup a
288 buffer name and attached each context to that same name. From AGL
293 ctx1 = aglCreateContext...
294 aglSetInteger(ctx1, AGL_BUFFER_NAME, &id); // create name
295 aglAttachDrawable (ctx1,...); // create surface with associated with
297 ctx2 = aglCreateContext...
298 aglSetInteger(ctx2, AGL_BUFFER_NAME, &id); // uses previously created name
299 aglAttachDrawable (ctx2, ...); // uses existing surface with existing name
303 params contains one value: a non-negative integer name of the surface to be
304 associated to be with the current context. If this value is non-zero, and a
305 surface of this name is not associated to this drawable, a new surface with
306 this name is created and associated with the context when
307 aglSetDrawable is called subsequently. If this is a previously allocated
308 buffer name within the namespace of the current window (e.g., drawable),
309 that previously allocated surface is associated with the context (e.g., no
310 new surface is created) and the subsequent call to aglSetDrawable will
311 attach that surface. This allows multiple contexts to be attached to a single
312 surface. Using the default buffer name zero, returns to one surface per
317 so what I'm doing is to have a dummy aglContext attached to a wxGLCanvas,
318 assign it a buffer number
322 bool wxGLCanvas::Create(wxWindow
*parent
,
327 const wxString
& name
,
328 const int *attribList
,
329 const wxPalette
& WXUNUSED(palette
))
331 m_needsUpdate
= false;
332 m_macCanvasIsShown
= false;
334 m_glFormat
= WXGLChoosePixelFormat(attribList
);
338 if ( !wxWindow::Create(parent
, id
, pos
, size
, style
, name
) )
341 m_dummyContext
= WXGLCreateContext(m_glFormat
, NULL
);
343 static GLint gCurrentBufferName
= 1;
344 m_bufferName
= gCurrentBufferName
++;
345 aglSetInteger (m_dummyContext
, AGL_BUFFER_NAME
, &m_bufferName
);
347 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(MAC_WXHWND(MacGetTopLevelWindowRef()));
348 aglSetDrawable(m_dummyContext
, drawable
);
350 m_macCanvasIsShown
= true;
355 wxGLCanvas::~wxGLCanvas()
358 WXGLDestroyPixelFormat(m_glFormat
);
360 if ( m_dummyContext
)
361 WXGLDestroyContext(m_dummyContext
);
364 void wxGLCanvas::SetViewport()
366 if ( !m_needsUpdate
)
369 m_needsUpdate
= false;
371 // AGLContext context = aglGetCurrentContext();
375 // viewport is initially set to entire port, adjust it to just this window
378 MacClientToRootWindow(&x
, &y
);
381 GetClientSize(&width
, &height
);
384 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds
);
388 parms
[1] = bounds
.bottom
- bounds
.top
- ( y
+ height
);
392 // move the buffer rect out of sight if we're hidden
393 if ( !m_macCanvasIsShown
)
396 if ( !aglSetInteger(m_dummyContext
, AGL_BUFFER_RECT
, parms
) )
397 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
399 if ( !aglEnable(m_dummyContext
, AGL_BUFFER_RECT
) )
400 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
402 if ( !aglUpdateContext(m_dummyContext
) )
403 wxLogAGLError("aglUpdateContext");
406 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
412 void wxGLCanvas::MacUpdateView()
414 m_needsUpdate
= true;
418 void wxGLCanvas::MacSuperChangedPosition()
422 wxWindow::MacSuperChangedPosition();
425 void wxGLCanvas::MacTopLevelWindowChangedPosition()
428 wxWindow::MacTopLevelWindowChangedPosition();
431 void wxGLCanvas::MacVisibilityChanged()
433 if ( IsShownOnScreen() != m_macCanvasIsShown
)
435 m_macCanvasIsShown
= !m_macCanvasIsShown
;
439 wxWindowMac::MacVisibilityChanged();
442 #endif // wxUSE_GLCANVAS