1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/glcanvas.cpp
3 // Purpose: wxGLCanvas, for using OpenGL with wxWidgets under Macintosh
4 // Author: Stefan Csomor
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 #include "wx/wxprec.h"
21 #if defined(__BORLANDC__)
27 #include "wx/glcanvas.h"
32 #include "wx/settings.h"
35 #include "wx/osx/uma.h"
37 #include "wx/osx/private.h"
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 static void wxLogAGLError(const char *func
)
46 const int err
= aglGetError();
48 wxLogError(_("OpenGL function \"%s\" failed: %s (error %d)"),
49 func
, aglErrorString(err
), err
);
52 // ============================================================================
54 // ============================================================================
56 // ----------------------------------------------------------------------------
57 // low level implementation routines
58 // ----------------------------------------------------------------------------
60 WXGLContext
WXGLCreateContext( WXGLPixelFormat pixelFormat
, WXGLContext shareContext
)
62 WXGLContext context
= aglCreateContext(pixelFormat
, shareContext
);
64 wxLogAGLError("aglCreateContext");
68 void WXGLDestroyContext( WXGLContext context
)
72 if ( !aglDestroyContext(context
) )
74 wxLogAGLError("aglDestroyContext");
79 WXGLContext
WXGLGetCurrentContext()
81 return aglGetCurrentContext();
84 bool WXGLSetCurrentContext(WXGLContext context
)
86 if ( !aglSetCurrentContext(context
) )
88 wxLogAGLError("aglSetCurrentContext");
95 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat
)
99 aglDestroyPixelFormat(pixelFormat
);
103 WXGLPixelFormat
WXGLChoosePixelFormat(const int *attribList
)
106 const GLint defaultAttribs
[] =
110 AGL_MINIMUM_POLICY
, // never choose less than requested
111 AGL_DEPTH_SIZE
, 1, // use largest available depth buffer
119 const GLint
*attribs
;
122 attribs
= defaultAttribs
;
127 data
[p
++] = AGL_MINIMUM_POLICY
; // make _SIZE tags behave more like GLX
129 for ( unsigned arg
= 0; attribList
[arg
] !=0 && p
< WXSIZEOF(data
); )
131 switch ( attribList
[arg
++] )
134 data
[p
++] = AGL_RGBA
;
137 case WX_GL_BUFFER_SIZE
:
138 data
[p
++] = AGL_BUFFER_SIZE
;
139 data
[p
++] = attribList
[arg
++];
144 data
[p
++]=attribList
[arg
++];
147 case WX_GL_DOUBLEBUFFER
:
148 data
[p
++] = AGL_DOUBLEBUFFER
;
152 data
[p
++] = AGL_STEREO
;
155 case WX_GL_AUX_BUFFERS
:
156 data
[p
++] = AGL_AUX_BUFFERS
;
157 data
[p
++] = attribList
[arg
++];
161 data
[p
++] = AGL_RED_SIZE
;
162 data
[p
++] = attribList
[arg
++];
165 case WX_GL_MIN_GREEN
:
166 data
[p
++] = AGL_GREEN_SIZE
;
167 data
[p
++] = attribList
[arg
++];
171 data
[p
++] = AGL_BLUE_SIZE
;
172 data
[p
++] = attribList
[arg
++];
175 case WX_GL_MIN_ALPHA
:
176 data
[p
++] = AGL_ALPHA_SIZE
;
177 data
[p
++] = attribList
[arg
++];
180 case WX_GL_DEPTH_SIZE
:
181 data
[p
++] = AGL_DEPTH_SIZE
;
182 data
[p
++] = attribList
[arg
++];
185 case WX_GL_STENCIL_SIZE
:
186 data
[p
++] = AGL_STENCIL_SIZE
;
187 data
[p
++] = attribList
[arg
++];
190 case WX_GL_MIN_ACCUM_RED
:
191 data
[p
++] = AGL_ACCUM_RED_SIZE
;
192 data
[p
++] = attribList
[arg
++];
195 case WX_GL_MIN_ACCUM_GREEN
:
196 data
[p
++] = AGL_ACCUM_GREEN_SIZE
;
197 data
[p
++] = attribList
[arg
++];
200 case WX_GL_MIN_ACCUM_BLUE
:
201 data
[p
++] = AGL_ACCUM_BLUE_SIZE
;
202 data
[p
++] = attribList
[arg
++];
205 case WX_GL_MIN_ACCUM_ALPHA
:
206 data
[p
++] = AGL_ACCUM_ALPHA_SIZE
;
207 data
[p
++] = attribList
[arg
++];
210 case WX_GL_SAMPLE_BUFFERS
:
211 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
213 if ( !attribList
[arg
++] )
219 data
[p
++] = AGL_SAMPLE_BUFFERS_ARB
;
220 if ( (data
[p
++] = attribList
[arg
++]) == true )
222 // don't use software fallback
223 data
[p
++] = AGL_NO_RECOVERY
;
228 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
230 if ( !attribList
[arg
++] )
236 data
[p
++] = AGL_SAMPLES_ARB
;
237 data
[p
++] = attribList
[arg
++];
247 return aglChoosePixelFormat(NULL
, 0, attribs
);
250 // ----------------------------------------------------------------------------
252 // ----------------------------------------------------------------------------
254 bool wxGLContext::SetCurrent(const wxGLCanvas
& win
) const
259 GLint bufnummer
= win
.GetAglBufferName();
260 aglSetInteger(m_glContext
, AGL_BUFFER_NAME
, &bufnummer
);
261 //win.SetLastContext(m_glContext);
263 const_cast<wxGLCanvas
&>(win
).SetViewport();
266 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
267 if ( UMAGetSystemVersion() >= 0x1050 )
269 aglSetWindowRef(m_glContext
, win
.MacGetTopLevelWindowRef());
274 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(
275 MAC_WXHWND(win
.MacGetTopLevelWindowRef()));
277 if ( !aglSetDrawable(m_glContext
, drawable
) )
279 wxLogAGLError("aglSetDrawable");
284 return WXGLSetCurrentContext(m_glContext
);
287 // ----------------------------------------------------------------------------
289 // ----------------------------------------------------------------------------
293 sharing contexts under AGL is not straightforward, to quote from
295 http://lists.apple.com/archives/mac-opengl/2003/Jan/msg00402.html :
297 In Carbon OpenGL (AGL) you would use call aglSetInteger to setup a
298 buffer name and attached each context to that same name. From AGL
303 ctx1 = aglCreateContext...
304 aglSetInteger(ctx1, AGL_BUFFER_NAME, &id); // create name
305 aglAttachDrawable (ctx1,...); // create surface with associated with
307 ctx2 = aglCreateContext...
308 aglSetInteger(ctx2, AGL_BUFFER_NAME, &id); // uses previously created name
309 aglAttachDrawable (ctx2, ...); // uses existing surface with existing name
313 params contains one value: a non-negative integer name of the surface to be
314 associated to be with the current context. If this value is non-zero, and a
315 surface of this name is not associated to this drawable, a new surface with
316 this name is created and associated with the context when
317 aglSetDrawable is called subsequently. If this is a previously allocated
318 buffer name within the namespace of the current window (e.g., drawable),
319 that previously allocated surface is associated with the context (e.g., no
320 new surface is created) and the subsequent call to aglSetDrawable will
321 attach that surface. This allows multiple contexts to be attached to a single
322 surface. Using the default buffer name zero, returns to one surface per
327 so what I'm doing is to have a dummy aglContext attached to a wxGLCanvas,
328 assign it a buffer number
332 bool wxGLCanvas::Create(wxWindow
*parent
,
337 const wxString
& name
,
338 const int *attribList
,
339 const wxPalette
& WXUNUSED(palette
))
341 m_needsUpdate
= false;
342 m_macCanvasIsShown
= false;
344 m_glFormat
= WXGLChoosePixelFormat(attribList
);
348 if ( !wxWindow::Create(parent
, id
, pos
, size
, style
, name
) )
351 m_dummyContext
= WXGLCreateContext(m_glFormat
, NULL
);
353 static GLint gCurrentBufferName
= 1;
354 m_bufferName
= gCurrentBufferName
++;
355 aglSetInteger (m_dummyContext
, AGL_BUFFER_NAME
, &m_bufferName
);
357 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
358 if ( UMAGetSystemVersion() >= 0x1050 )
360 aglSetWindowRef(m_dummyContext
, MacGetTopLevelWindowRef());
365 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(MAC_WXHWND(MacGetTopLevelWindowRef()));
366 aglSetDrawable(m_dummyContext
, drawable
);
369 m_macCanvasIsShown
= true;
374 wxGLCanvas::~wxGLCanvas()
377 WXGLDestroyPixelFormat(m_glFormat
);
379 if ( m_dummyContext
)
380 WXGLDestroyContext(m_dummyContext
);
383 bool wxGLCanvas::SwapBuffers()
385 WXGLContext context
= WXGLGetCurrentContext();
386 wxCHECK_MSG(context
, false, wxT("should have current context"));
388 aglSwapBuffers(context
);
392 void wxGLCanvas::SetViewport()
394 if ( !m_needsUpdate
)
397 m_needsUpdate
= false;
399 // AGLContext context = aglGetCurrentContext();
403 // viewport is initially set to entire port, adjust it to just this window
406 MacClientToRootWindow(&x
, &y
);
409 GetClientSize(&width
, &height
);
412 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds
);
416 parms
[1] = bounds
.bottom
- bounds
.top
- ( y
+ height
);
420 // move the buffer rect out of sight if we're hidden
421 if ( !m_macCanvasIsShown
)
424 if ( !aglSetInteger(m_dummyContext
, AGL_BUFFER_RECT
, parms
) )
425 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
427 if ( !aglEnable(m_dummyContext
, AGL_BUFFER_RECT
) )
428 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
430 if ( !aglUpdateContext(m_dummyContext
) )
431 wxLogAGLError("aglUpdateContext");
434 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
440 void wxGLCanvas::MacUpdateView()
442 m_needsUpdate
= true;
446 void wxGLCanvas::MacSuperChangedPosition()
450 wxWindow::MacSuperChangedPosition();
453 void wxGLCanvas::MacTopLevelWindowChangedPosition()
456 wxWindow::MacTopLevelWindowChangedPosition();
459 void wxGLCanvas::MacVisibilityChanged()
461 if ( IsShownOnScreen() != m_macCanvasIsShown
)
463 m_macCanvasIsShown
= !m_macCanvasIsShown
;
467 wxWindowMac::MacVisibilityChanged();
470 #endif // wxUSE_GLCANVAS