]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/glcanvas.cpp
correction to last commit: don't test unsetenv() return value, it's void under Darwin
[wxWidgets.git] / src / mac / carbon / glcanvas.cpp
CommitLineData
dc3065a5 1///////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/mac/carbon/glcanvas.cpp
77ffb593 3// Purpose: wxGLCanvas, for using OpenGL with wxWidgets under Macintosh
a31a5f85 4// Author: Stefan Csomor
0a67a93b 5// Modified by:
a31a5f85 6// Created: 1998-01-01
0a67a93b 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
e4db172a 9// Licence: wxWindows licence
dc3065a5
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
0a67a93b 19
0a67a93b
SC
20#include "wx/wxprec.h"
21
22#if defined(__BORLANDC__)
e4db172a 23 #pragma hdrstop
0a67a93b
SC
24#endif
25
0a67a93b
SC
26#if wxUSE_GLCANVAS
27
e4db172a
WS
28#include "wx/glcanvas.h"
29
0a67a93b 30#ifndef WX_PRECOMP
e4db172a
WS
31 #include "wx/frame.h"
32 #include "wx/log.h"
9eddec69 33 #include "wx/settings.h"
0a67a93b
SC
34#endif
35
0a67a93b
SC
36#include "wx/mac/uma.h"
37
3a5ff9b1
SC
38#include "wx/mac/private.h"
39
dc3065a5
VZ
40// ----------------------------------------------------------------------------
41// helper functions
42// ----------------------------------------------------------------------------
0a67a93b 43
dc3065a5 44static void wxLogAGLError(const char *func)
0a67a93b 45{
dc3065a5 46 const int err = aglGetError();
e4db172a 47
dc3065a5
VZ
48 wxLogError(_("OpenGL function \"%s\" failed: %s (error %d)"),
49 func, aglErrorString(err), err);
50}
e4db172a 51
dc3065a5
VZ
52// ============================================================================
53// implementation
54// ============================================================================
e4db172a 55
dc3065a5
VZ
56// ----------------------------------------------------------------------------
57// wxGLContext
58// ----------------------------------------------------------------------------
0a67a93b 59
dc3065a5 60wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext *other)
0a67a93b 61{
dc3065a5
VZ
62 m_aglContext = aglCreateContext(win->GetAGLPixelFormat(),
63 other ? other->m_aglContext : NULL);
64 if ( !m_aglContext )
65 wxLogAGLError("aglCreateContext");
0a67a93b
SC
66}
67
dc3065a5 68wxGLContext::~wxGLContext()
0a67a93b 69{
dc3065a5 70 if ( m_aglContext )
e40298d5 71 {
dc3065a5
VZ
72 // it's ok to pass the current context to this function
73 if ( !aglDestroyContext(m_aglContext) )
74 wxLogAGLError("aglDestroyContext");
e40298d5 75 }
0a67a93b
SC
76}
77
dc3065a5 78void wxGLContext::SetCurrent(const wxGLCanvas& win) const
0a67a93b 79{
dc3065a5
VZ
80 if ( !m_aglContext )
81 return;
0a67a93b 82
dc3065a5
VZ
83 AGLDrawable drawable = (AGLDrawable)UMAGetWindowPort(
84 MAC_WXHWND(win.MacGetTopLevelWindowRef()));
85 if ( !aglSetDrawable(m_aglContext, drawable) )
86 wxLogAGLError("aglSetDrawable");
0a67a93b 87
dc3065a5
VZ
88 if ( !aglSetCurrentContext(m_aglContext) )
89 wxLogAGLError("aglSetCurrentContext");
0a67a93b 90
dc3065a5
VZ
91 wx_const_cast(wxGLCanvas&, win).SetViewport();
92}
0a67a93b 93
dc3065a5
VZ
94// ----------------------------------------------------------------------------
95// wxGLCanvas
96// ----------------------------------------------------------------------------
0a67a93b 97
4660d7e5 98IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
0a67a93b 99
4660d7e5 100BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
0a67a93b
SC
101 EVT_SIZE(wxGLCanvas::OnSize)
102END_EVENT_TABLE()
103
dc3065a5
VZ
104wxGLCanvas::wxGLCanvas(wxWindow *parent,
105 wxWindowID id,
106 const int *attribList,
107 const wxPoint& pos,
108 const wxSize& size,
109 long style,
110 const wxString& name,
111 const wxPalette& palette)
0a67a93b 112{
dc3065a5 113 Create(parent, id, pos, size, style, name, attribList, palette);
0a67a93b
SC
114}
115
dc3065a5
VZ
116#if WXWIN_COMPATIBILITY_2_8
117
118wxGLCanvas::wxGLCanvas(wxWindow *parent,
119 wxWindowID id,
120 const wxPoint& pos,
121 const wxSize& size,
122 long style,
123 const wxString& name,
124 const int *attribList,
125 const wxPalette& palette)
0a67a93b 126{
dc3065a5
VZ
127 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
128 m_glContext = new wxGLContext(this);
0a67a93b
SC
129}
130
dc3065a5
VZ
131wxGLCanvas::wxGLCanvas(wxWindow *parent,
132 const wxGLContext *shared,
133 wxWindowID id,
134 const wxPoint& pos,
135 const wxSize& size,
136 long style,
137 const wxString& name,
138 const int *attribList,
139 const wxPalette& palette)
0a67a93b 140{
dc3065a5
VZ
141 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
142 m_glContext = new wxGLContext(this, shared);
0a67a93b
SC
143}
144
dc3065a5
VZ
145wxGLCanvas::wxGLCanvas(wxWindow *parent,
146 const wxGLCanvas *shared,
147 wxWindowID id,
148 const wxPoint& pos,
149 const wxSize& size,
150 long style,
151 const wxString& name,
152 const int *attribList,
153 const wxPalette& palette)
0a67a93b 154{
dc3065a5
VZ
155 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
156 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
0a67a93b
SC
157}
158
dc3065a5
VZ
159#endif // WXWIN_COMPATIBILITY_2_8
160
16506231 161static AGLPixelFormat ChoosePixelFormat(const int *attribList)
0a67a93b 162{
0a67a93b 163 GLint data[512];
dc3065a5
VZ
164 const GLint defaultAttribs[] =
165 {
166 AGL_RGBA,
e4db172a 167 AGL_DOUBLEBUFFER,
dc3065a5 168 AGL_MINIMUM_POLICY, // never choose less than requested
e40298d5 169 AGL_DEPTH_SIZE, 1, // use largest available depth buffer
e4db172a
WS
170 AGL_RED_SIZE, 1,
171 AGL_GREEN_SIZE, 1,
172 AGL_BLUE_SIZE, 1,
173 AGL_ALPHA_SIZE, 0,
dc3065a5
VZ
174 AGL_NONE
175 };
176
177 const GLint *attribs;
178 if ( !attribList )
0a67a93b 179 {
e40298d5 180 attribs = defaultAttribs;
0a67a93b
SC
181 }
182 else
183 {
dc3065a5 184 unsigned p = 0;
e40298d5 185 data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX
dc3065a5
VZ
186
187 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
0a67a93b 188 {
dc3065a5 189 switch ( attribList[arg++] )
e40298d5 190 {
dc3065a5
VZ
191 case WX_GL_RGBA:
192 data[p++] = AGL_RGBA;
193 break;
194
195 case WX_GL_BUFFER_SIZE:
196 data[p++] = AGL_BUFFER_SIZE;
197 data[p++] = attribList[arg++];
198 break;
199
200 case WX_GL_LEVEL:
201 data[p++]=AGL_LEVEL;
202 data[p++]=attribList[arg++];
203 break;
204
205 case WX_GL_DOUBLEBUFFER:
206 data[p++] = AGL_DOUBLEBUFFER;
207 break;
208
209 case WX_GL_STEREO:
210 data[p++] = AGL_STEREO;
211 break;
212
213 case WX_GL_AUX_BUFFERS:
214 data[p++] = AGL_AUX_BUFFERS;
215 data[p++] = attribList[arg++];
216 break;
217
218 case WX_GL_MIN_RED:
219 data[p++] = AGL_RED_SIZE;
220 data[p++] = attribList[arg++];
221 break;
222
223 case WX_GL_MIN_GREEN:
224 data[p++] = AGL_GREEN_SIZE;
225 data[p++] = attribList[arg++];
226 break;
227
228 case WX_GL_MIN_BLUE:
229 data[p++] = AGL_BLUE_SIZE;
230 data[p++] = attribList[arg++];
231 break;
232
233 case WX_GL_MIN_ALPHA:
234 data[p++] = AGL_ALPHA_SIZE;
235 data[p++] = attribList[arg++];
236 break;
237
238 case WX_GL_DEPTH_SIZE:
239 data[p++] = AGL_DEPTH_SIZE;
240 data[p++] = attribList[arg++];
241 break;
242
243 case WX_GL_STENCIL_SIZE:
244 data[p++] = AGL_STENCIL_SIZE;
245 data[p++] = attribList[arg++];
246 break;
247
248 case WX_GL_MIN_ACCUM_RED:
249 data[p++] = AGL_ACCUM_RED_SIZE;
250 data[p++] = attribList[arg++];
251 break;
252
253 case WX_GL_MIN_ACCUM_GREEN:
254 data[p++] = AGL_ACCUM_GREEN_SIZE;
255 data[p++] = attribList[arg++];
256 break;
257
258 case WX_GL_MIN_ACCUM_BLUE:
259 data[p++] = AGL_ACCUM_BLUE_SIZE;
260 data[p++] = attribList[arg++];
261 break;
262
263 case WX_GL_MIN_ACCUM_ALPHA:
264 data[p++] = AGL_ACCUM_ALPHA_SIZE;
265 data[p++] = attribList[arg++];
266 break;
e40298d5 267 }
e4db172a 268 }
dc3065a5
VZ
269
270 data[p] = AGL_NONE;
e4db172a 271
e40298d5 272 attribs = data;
0a67a93b 273 }
e4db172a 274
16506231
GD
275 return aglChoosePixelFormat(NULL, 0, attribs);
276}
277
dc3065a5
VZ
278bool wxGLCanvas::Create(wxWindow *parent,
279 wxWindowID id,
280 const wxPoint& pos,
281 const wxSize& size,
282 long style,
283 const wxString& name,
284 const int *attribList,
285 const wxPalette& WXUNUSED(palette))
16506231 286{
dc3065a5
VZ
287 m_needsUpdate = false;
288 m_macCanvasIsShown = false;
e4db172a 289
dc3065a5
VZ
290 m_aglFormat = ChoosePixelFormat(attribList);
291 if ( !m_aglFormat )
292 return false;
e4db172a 293
dc3065a5
VZ
294 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
295 return false;
296
297 m_macCanvasIsShown = true;
e4db172a 298
0a67a93b
SC
299 return true;
300}
301
dc3065a5 302wxGLCanvas::~wxGLCanvas()
0a67a93b 303{
dc3065a5
VZ
304 if ( m_aglFormat )
305 aglDestroyPixelFormat(m_aglFormat);
0a67a93b
SC
306}
307
dc3065a5 308void wxGLCanvas::SwapBuffers()
0a67a93b 309{
dc3065a5
VZ
310 AGLContext context = aglGetCurrentContext();
311 wxCHECK_RET( context, _T("should have current context") );
312
313 aglSwapBuffers(context);
0a67a93b
SC
314}
315
316void wxGLCanvas::SetViewport()
317{
dc3065a5
VZ
318 if ( !m_needsUpdate )
319 return;
e4db172a 320
dc3065a5
VZ
321 m_needsUpdate = false;
322
323 AGLContext context = aglGetCurrentContext();
324 if ( !context )
325 return;
326
327 // viewport is initially set to entire port, adjust it to just this window
328 int x = 0,
329 y = 0;
330 MacClientToRootWindow(&x , &y);
331
332 int width, height;
333 GetClientSize(&width, &height);
334
335 Rect bounds;
336 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds);
e4db172a 337
3a5ff9b1 338#if 0
dc3065a5
VZ
339 // TODO in case we adopt point vs pixel coordinates, this will make the conversion
340 HIRect hiRect = CGRectMake( x, y, width, height );
341 HIRectConvert( &hiRect, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
342 HIRect hiBounds = CGRectMake( 0, 0, bounds.right - bounds.left , bounds.bottom - bounds.top );
343 HIRectConvert( &hiBounds, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
344 GLint parms[4];
345 parms[0] = hiRect.origin.x;
346 parms[1] = hiBounds.size.height - (hiRect.origin.y + hiRect.size.height);
347 parms[2] = hiRect.size.width;
348 parms[3] = hiRect.size.height;
3a5ff9b1 349#else
dc3065a5
VZ
350 GLint parms[4];
351 parms[0] = x;
352 parms[1] = bounds.bottom - bounds.top - ( y + height );
353 parms[2] = width;
354 parms[3] = height;
3a5ff9b1 355#endif
0a67a93b 356
dc3065a5
VZ
357 // move the buffer rect out of sight if we're hidden
358 if ( !m_macCanvasIsShown )
359 parms[0] += 20000;
a3bf4a62 360
dc3065a5 361 if ( !aglSetInteger(context, AGL_BUFFER_RECT, parms) )
dc3065a5 362 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
1be2473f 363
eea05623
VZ
364 if ( !aglEnable(context, AGL_BUFFER_RECT) )
365 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
366
1be2473f
VZ
367 if ( !aglUpdateContext(context) )
368 wxLogAGLError("aglUpdateContext");
0a67a93b
SC
369}
370
dc3065a5 371void wxGLCanvas::OnSize(wxSizeEvent& event)
a3bf4a62 372{
dc3065a5
VZ
373 MacUpdateView();
374 event.Skip();
a3bf4a62
SC
375}
376
dc3065a5 377void wxGLCanvas::MacUpdateView()
0a67a93b 378{
dc3065a5
VZ
379 m_needsUpdate = true;
380 Refresh(false);
0a67a93b
SC
381}
382
dc3065a5 383void wxGLCanvas::MacSuperChangedPosition()
0a67a93b 384{
dc3065a5
VZ
385 MacUpdateView();
386 wxWindow::MacSuperChangedPosition();
0a67a93b
SC
387}
388
dc3065a5 389void wxGLCanvas::MacTopLevelWindowChangedPosition()
ab89a5b5 390{
dc3065a5
VZ
391 MacUpdateView();
392 wxWindow::MacTopLevelWindowChangedPosition();
ab89a5b5
SC
393}
394
e4db172a 395void wxGLCanvas::MacVisibilityChanged()
ab89a5b5 396{
dc3065a5 397 if ( MacIsReallyShown() != m_macCanvasIsShown )
ab89a5b5 398 {
dc3065a5
VZ
399 m_macCanvasIsShown = !m_macCanvasIsShown;
400 MacUpdateView();
ab89a5b5 401 }
dc3065a5
VZ
402
403 wxWindowMac::MacVisibilityChanged();
ab89a5b5 404}
16506231 405
dc3065a5 406// ----------------------------------------------------------------------------
16506231 407// wxGLApp
dc3065a5 408// ----------------------------------------------------------------------------
16506231 409
dc3065a5 410bool wxGLApp::InitGLVisual(const int *attribList)
16506231
GD
411{
412 AGLPixelFormat fmt = ChoosePixelFormat(attribList);
dc3065a5 413 if ( !fmt )
bf44306e 414 return false;
16506231 415
dc3065a5
VZ
416 aglDestroyPixelFormat(fmt);
417 return true;
16506231
GD
418}
419
0a67a93b 420#endif // wxUSE_GLCANVAS