]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/glcanvas.cpp
guard code for mac / quickdraw
[wxWidgets.git] / src / mac / 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
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #if defined(__BORLANDC__)
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_GLCANVAS
27
28 #include "wx/glcanvas.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/frame.h"
32 #include "wx/log.h"
33 #include "wx/settings.h"
34 #endif
35
36 #include "wx/mac/uma.h"
37
38 #include "wx/mac/private.h"
39
40 // ----------------------------------------------------------------------------
41 // helper functions
42 // ----------------------------------------------------------------------------
43
44 static void wxLogAGLError(const char *func)
45 {
46 const int err = aglGetError();
47
48 wxLogError(_("OpenGL function \"%s\" failed: %s (error %d)"),
49 func, aglErrorString(err), err);
50 }
51
52 // ============================================================================
53 // implementation
54 // ============================================================================
55
56 // ----------------------------------------------------------------------------
57 // wxGLContext
58 // ----------------------------------------------------------------------------
59
60 wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext *other)
61 {
62 m_aglContext = aglCreateContext(win->GetAGLPixelFormat(),
63 other ? other->m_aglContext : NULL);
64 if ( !m_aglContext )
65 wxLogAGLError("aglCreateContext");
66 }
67
68 wxGLContext::~wxGLContext()
69 {
70 if ( m_aglContext )
71 {
72 // it's ok to pass the current context to this function
73 if ( !aglDestroyContext(m_aglContext) )
74 wxLogAGLError("aglDestroyContext");
75 }
76 }
77
78 void wxGLContext::SetCurrent(const wxGLCanvas& win) const
79 {
80 if ( !m_aglContext )
81 return;
82
83 AGLDrawable drawable = (AGLDrawable)UMAGetWindowPort(
84 MAC_WXHWND(win.MacGetTopLevelWindowRef()));
85 if ( !aglSetDrawable(m_aglContext, drawable) )
86 wxLogAGLError("aglSetDrawable");
87
88 if ( !aglSetCurrentContext(m_aglContext) )
89 wxLogAGLError("aglSetCurrentContext");
90
91 wx_const_cast(wxGLCanvas&, win).SetViewport();
92 }
93
94 // ----------------------------------------------------------------------------
95 // wxGLCanvas
96 // ----------------------------------------------------------------------------
97
98 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
99
100 BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
101 EVT_SIZE(wxGLCanvas::OnSize)
102 END_EVENT_TABLE()
103
104 wxGLCanvas::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)
112 {
113 Create(parent, id, pos, size, style, name, attribList, palette);
114 }
115
116 #if WXWIN_COMPATIBILITY_2_8
117
118 wxGLCanvas::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)
126 {
127 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
128 m_glContext = new wxGLContext(this);
129 }
130
131 wxGLCanvas::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)
140 {
141 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
142 m_glContext = new wxGLContext(this, shared);
143 }
144
145 wxGLCanvas::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)
154 {
155 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
156 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
157 }
158
159 #endif // WXWIN_COMPATIBILITY_2_8
160
161 static AGLPixelFormat ChoosePixelFormat(const int *attribList)
162 {
163 GLint data[512];
164 const GLint defaultAttribs[] =
165 {
166 AGL_RGBA,
167 AGL_DOUBLEBUFFER,
168 AGL_MINIMUM_POLICY, // never choose less than requested
169 AGL_DEPTH_SIZE, 1, // use largest available depth buffer
170 AGL_RED_SIZE, 1,
171 AGL_GREEN_SIZE, 1,
172 AGL_BLUE_SIZE, 1,
173 AGL_ALPHA_SIZE, 0,
174 AGL_NONE
175 };
176
177 const GLint *attribs;
178 if ( !attribList )
179 {
180 attribs = defaultAttribs;
181 }
182 else
183 {
184 unsigned p = 0;
185 data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX
186
187 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
188 {
189 switch ( attribList[arg++] )
190 {
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;
267 }
268 }
269
270 data[p] = AGL_NONE;
271
272 attribs = data;
273 }
274
275 return aglChoosePixelFormat(NULL, 0, attribs);
276 }
277
278 bool 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))
286 {
287 m_needsUpdate = false;
288 m_macCanvasIsShown = false;
289
290 m_aglFormat = ChoosePixelFormat(attribList);
291 if ( !m_aglFormat )
292 return false;
293
294 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
295 return false;
296
297 m_macCanvasIsShown = true;
298
299 return true;
300 }
301
302 wxGLCanvas::~wxGLCanvas()
303 {
304 if ( m_aglFormat )
305 aglDestroyPixelFormat(m_aglFormat);
306 }
307
308 void wxGLCanvas::SwapBuffers()
309 {
310 AGLContext context = aglGetCurrentContext();
311 wxCHECK_RET( context, _T("should have current context") );
312
313 aglSwapBuffers(context);
314 }
315
316 void wxGLCanvas::SetViewport()
317 {
318 if ( !m_needsUpdate )
319 return;
320
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);
337
338 #if 0
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;
349 #else
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;
355 #endif
356
357 // move the buffer rect out of sight if we're hidden
358 if ( !m_macCanvasIsShown )
359 parms[0] += 20000;
360
361 if ( !aglSetInteger(context, AGL_BUFFER_RECT, parms) )
362 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
363
364 if ( !aglEnable(context, AGL_BUFFER_RECT) )
365 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
366
367 if ( !aglUpdateContext(context) )
368 wxLogAGLError("aglUpdateContext");
369 }
370
371 void wxGLCanvas::OnSize(wxSizeEvent& event)
372 {
373 MacUpdateView();
374 event.Skip();
375 }
376
377 void wxGLCanvas::MacUpdateView()
378 {
379 m_needsUpdate = true;
380 Refresh(false);
381 }
382
383 void wxGLCanvas::MacSuperChangedPosition()
384 {
385 MacUpdateView();
386 wxWindow::MacSuperChangedPosition();
387 }
388
389 void wxGLCanvas::MacTopLevelWindowChangedPosition()
390 {
391 MacUpdateView();
392 wxWindow::MacTopLevelWindowChangedPosition();
393 }
394
395 void wxGLCanvas::MacVisibilityChanged()
396 {
397 if ( MacIsReallyShown() != m_macCanvasIsShown )
398 {
399 m_macCanvasIsShown = !m_macCanvasIsShown;
400 MacUpdateView();
401 }
402
403 wxWindowMac::MacVisibilityChanged();
404 }
405
406 // ----------------------------------------------------------------------------
407 // wxGLApp
408 // ----------------------------------------------------------------------------
409
410 bool wxGLApp::InitGLVisual(const int *attribList)
411 {
412 AGLPixelFormat fmt = ChoosePixelFormat(attribList);
413 if ( !fmt )
414 return false;
415
416 aglDestroyPixelFormat(fmt);
417 return true;
418 }
419
420 #endif // wxUSE_GLCANVAS