]>
git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/glcanvas.cpp
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"
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 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 wxGLContext::wxGLContext(wxGLCanvas
*win
, const wxGLContext
*other
)
62 m_aglContext
= aglCreateContext(win
->GetAGLPixelFormat(),
63 other
? other
->m_aglContext
: NULL
);
65 wxLogAGLError("aglCreateContext");
68 wxGLContext::~wxGLContext()
72 // it's ok to pass the current context to this function
73 if ( !aglDestroyContext(m_aglContext
) )
74 wxLogAGLError("aglDestroyContext");
78 bool wxGLContext::SetCurrent(const wxGLCanvas
& win
) const
83 AGLDrawable drawable
= (AGLDrawable
)GetWindowPort(
84 MAC_WXHWND(win
.MacGetTopLevelWindowRef()));
85 if ( !aglSetDrawable(m_aglContext
, drawable
) )
87 wxLogAGLError("aglSetDrawable");
91 if ( !aglSetCurrentContext(m_aglContext
) )
93 wxLogAGLError("aglSetCurrentContext");
97 wx_const_cast(wxGLCanvas
&, win
).SetViewport();
101 // ----------------------------------------------------------------------------
103 // ----------------------------------------------------------------------------
105 IMPLEMENT_CLASS(wxGLCanvas
, wxWindow
)
107 BEGIN_EVENT_TABLE(wxGLCanvas
, wxWindow
)
108 EVT_SIZE(wxGLCanvas::OnSize
)
111 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
113 const int *attribList
,
117 const wxString
& name
,
118 const wxPalette
& palette
)
120 Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
);
123 #if WXWIN_COMPATIBILITY_2_8
125 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
130 const wxString
& name
,
131 const int *attribList
,
132 const wxPalette
& palette
)
134 if ( Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
) )
135 m_glContext
= new wxGLContext(this);
138 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
139 const wxGLContext
*shared
,
144 const wxString
& name
,
145 const int *attribList
,
146 const wxPalette
& palette
)
148 if ( Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
) )
149 m_glContext
= new wxGLContext(this, shared
);
152 wxGLCanvas::wxGLCanvas(wxWindow
*parent
,
153 const wxGLCanvas
*shared
,
158 const wxString
& name
,
159 const int *attribList
,
160 const wxPalette
& palette
)
162 if ( Create(parent
, id
, pos
, size
, style
, name
, attribList
, palette
) )
163 m_glContext
= new wxGLContext(this, shared
? shared
->m_glContext
: NULL
);
166 #endif // WXWIN_COMPATIBILITY_2_8
169 bool wxGLCanvasBase::IsExtensionSupported(const char *extension
)
171 // we need a valid context to query for extensions.
172 const GLint defaultAttribs
[] = { AGL_RGBA
, AGL_DOUBLEBUFFER
, AGL_NONE
};
173 AGLPixelFormat fmt
= aglChoosePixelFormat(NULL
, 0, defaultAttribs
);
174 AGLContext ctx
= aglCreateContext(fmt
, NULL
);
178 wxString extensions
= wxString::FromAscii(glGetString(GL_EXTENSIONS
));
180 aglDestroyPixelFormat(fmt
);
181 aglDestroyContext(ctx
);
183 return IsExtensionInList(extensions
, extension
);
187 bool wxGLCanvas::IsAGLMultiSampleAvailable()
189 static int s_isMultiSampleAvailable
= -1;
190 if ( s_isMultiSampleAvailable
== -1 )
191 s_isMultiSampleAvailable
= IsExtensionSupported("GL_ARB_multisample");
193 return s_isMultiSampleAvailable
!= 0;
196 static AGLPixelFormat
ChoosePixelFormat(const int *attribList
)
199 const GLint defaultAttribs
[] =
203 AGL_MINIMUM_POLICY
, // never choose less than requested
204 AGL_DEPTH_SIZE
, 1, // use largest available depth buffer
212 const GLint
*attribs
;
215 attribs
= defaultAttribs
;
220 data
[p
++] = AGL_MINIMUM_POLICY
; // make _SIZE tags behave more like GLX
222 for ( unsigned arg
= 0; attribList
[arg
] !=0 && p
< WXSIZEOF(data
); )
224 switch ( attribList
[arg
++] )
227 data
[p
++] = AGL_RGBA
;
230 case WX_GL_BUFFER_SIZE
:
231 data
[p
++] = AGL_BUFFER_SIZE
;
232 data
[p
++] = attribList
[arg
++];
237 data
[p
++]=attribList
[arg
++];
240 case WX_GL_DOUBLEBUFFER
:
241 data
[p
++] = AGL_DOUBLEBUFFER
;
245 data
[p
++] = AGL_STEREO
;
248 case WX_GL_AUX_BUFFERS
:
249 data
[p
++] = AGL_AUX_BUFFERS
;
250 data
[p
++] = attribList
[arg
++];
254 data
[p
++] = AGL_RED_SIZE
;
255 data
[p
++] = attribList
[arg
++];
258 case WX_GL_MIN_GREEN
:
259 data
[p
++] = AGL_GREEN_SIZE
;
260 data
[p
++] = attribList
[arg
++];
264 data
[p
++] = AGL_BLUE_SIZE
;
265 data
[p
++] = attribList
[arg
++];
268 case WX_GL_MIN_ALPHA
:
269 data
[p
++] = AGL_ALPHA_SIZE
;
270 data
[p
++] = attribList
[arg
++];
273 case WX_GL_DEPTH_SIZE
:
274 data
[p
++] = AGL_DEPTH_SIZE
;
275 data
[p
++] = attribList
[arg
++];
278 case WX_GL_STENCIL_SIZE
:
279 data
[p
++] = AGL_STENCIL_SIZE
;
280 data
[p
++] = attribList
[arg
++];
283 case WX_GL_MIN_ACCUM_RED
:
284 data
[p
++] = AGL_ACCUM_RED_SIZE
;
285 data
[p
++] = attribList
[arg
++];
288 case WX_GL_MIN_ACCUM_GREEN
:
289 data
[p
++] = AGL_ACCUM_GREEN_SIZE
;
290 data
[p
++] = attribList
[arg
++];
293 case WX_GL_MIN_ACCUM_BLUE
:
294 data
[p
++] = AGL_ACCUM_BLUE_SIZE
;
295 data
[p
++] = attribList
[arg
++];
298 case WX_GL_MIN_ACCUM_ALPHA
:
299 data
[p
++] = AGL_ACCUM_ALPHA_SIZE
;
300 data
[p
++] = attribList
[arg
++];
303 case WX_GL_SAMPLE_BUFFERS
:
304 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
306 if ( !attribList
[arg
++] )
312 data
[p
++] = AGL_SAMPLE_BUFFERS_ARB
;
313 if ( (data
[p
++] = attribList
[arg
++]) == true )
315 // don't use software fallback
316 data
[p
++] = AGL_NO_RECOVERY
;
321 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
323 if ( !attribList
[arg
++] )
329 data
[p
++] = AGL_SAMPLES_ARB
;
330 data
[p
++] = attribList
[arg
++];
340 return aglChoosePixelFormat(NULL
, 0, attribs
);
343 bool wxGLCanvas::Create(wxWindow
*parent
,
348 const wxString
& name
,
349 const int *attribList
,
350 const wxPalette
& WXUNUSED(palette
))
352 m_needsUpdate
= false;
353 m_macCanvasIsShown
= false;
355 m_aglFormat
= ChoosePixelFormat(attribList
);
359 if ( !wxWindow::Create(parent
, id
, pos
, size
, style
, name
) )
362 m_macCanvasIsShown
= true;
367 wxGLCanvas::~wxGLCanvas()
370 aglDestroyPixelFormat(m_aglFormat
);
374 bool wxGLCanvasBase::IsDisplaySupported(const int *attribList
)
376 AGLPixelFormat aglFormat
= ChoosePixelFormat(attribList
);
381 aglDestroyPixelFormat(aglFormat
);
386 bool wxGLCanvas::SwapBuffers()
388 AGLContext context
= aglGetCurrentContext();
389 wxCHECK_MSG(context
, false, _T("should have current context"));
391 aglSwapBuffers(context
);
395 void wxGLCanvas::SetViewport()
397 if ( !m_needsUpdate
)
400 m_needsUpdate
= false;
402 AGLContext context
= aglGetCurrentContext();
406 // viewport is initially set to entire port, adjust it to just this window
409 MacClientToRootWindow(&x
, &y
);
412 GetClientSize(&width
, &height
);
415 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds
);
418 // TODO in case we adopt point vs pixel coordinates, this will make the conversion
419 HIRect hiRect
= CGRectMake( x
, y
, width
, height
);
420 HIRectConvert( &hiRect
, kHICoordSpace72DPIGlobal
, NULL
, kHICoordSpaceScreenPixel
, NULL
);
421 HIRect hiBounds
= CGRectMake( 0, 0, bounds
.right
- bounds
.left
, bounds
.bottom
- bounds
.top
);
422 HIRectConvert( &hiBounds
, kHICoordSpace72DPIGlobal
, NULL
, kHICoordSpaceScreenPixel
, NULL
);
424 parms
[0] = hiRect
.origin
.x
;
425 parms
[1] = hiBounds
.size
.height
- (hiRect
.origin
.y
+ hiRect
.size
.height
);
426 parms
[2] = hiRect
.size
.width
;
427 parms
[3] = hiRect
.size
.height
;
431 parms
[1] = bounds
.bottom
- bounds
.top
- ( y
+ height
);
436 // move the buffer rect out of sight if we're hidden
437 if ( !m_macCanvasIsShown
)
440 if ( !aglSetInteger(context
, AGL_BUFFER_RECT
, parms
) )
441 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
443 if ( !aglEnable(context
, AGL_BUFFER_RECT
) )
444 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
446 if ( !aglUpdateContext(context
) )
447 wxLogAGLError("aglUpdateContext");
450 void wxGLCanvas::OnSize(wxSizeEvent
& event
)
456 void wxGLCanvas::MacUpdateView()
458 m_needsUpdate
= true;
462 void wxGLCanvas::MacSuperChangedPosition()
465 wxWindow::MacSuperChangedPosition();
468 void wxGLCanvas::MacTopLevelWindowChangedPosition()
471 wxWindow::MacTopLevelWindowChangedPosition();
474 void wxGLCanvas::MacVisibilityChanged()
476 if ( IsShownOnScreen() != m_macCanvasIsShown
)
478 m_macCanvasIsShown
= !m_macCanvasIsShown
;
482 wxWindowMac::MacVisibilityChanged();
485 // ----------------------------------------------------------------------------
487 // ----------------------------------------------------------------------------
489 bool wxGLApp::InitGLVisual(const int *attribList
)
491 AGLPixelFormat fmt
= ChoosePixelFormat(attribList
);
495 aglDestroyPixelFormat(fmt
);
499 #endif // wxUSE_GLCANVAS