]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/glcanvas.cpp
graphics context additions and merging graphics bitmap additions from Kevin O.
[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 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
79 {
80 if ( !m_aglContext )
81 return false;
82
83 AGLDrawable drawable = (AGLDrawable)GetWindowPort(
84 MAC_WXHWND(win.MacGetTopLevelWindowRef()));
85 if ( !aglSetDrawable(m_aglContext, drawable) )
86 {
87 wxLogAGLError("aglSetDrawable");
88 return false;
89 }
90
91 if ( !aglSetCurrentContext(m_aglContext) )
92 {
93 wxLogAGLError("aglSetCurrentContext");
94 return false;
95 }
96
97 wx_const_cast(wxGLCanvas&, win).SetViewport();
98 return true;
99 }
100
101 // ----------------------------------------------------------------------------
102 // wxGLCanvas
103 // ----------------------------------------------------------------------------
104
105 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
106
107 BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
108 EVT_SIZE(wxGLCanvas::OnSize)
109 END_EVENT_TABLE()
110
111 wxGLCanvas::wxGLCanvas(wxWindow *parent,
112 wxWindowID id,
113 const int *attribList,
114 const wxPoint& pos,
115 const wxSize& size,
116 long style,
117 const wxString& name,
118 const wxPalette& palette)
119 {
120 Create(parent, id, pos, size, style, name, attribList, palette);
121 }
122
123 #if WXWIN_COMPATIBILITY_2_8
124
125 wxGLCanvas::wxGLCanvas(wxWindow *parent,
126 wxWindowID id,
127 const wxPoint& pos,
128 const wxSize& size,
129 long style,
130 const wxString& name,
131 const int *attribList,
132 const wxPalette& palette)
133 {
134 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
135 m_glContext = new wxGLContext(this);
136 }
137
138 wxGLCanvas::wxGLCanvas(wxWindow *parent,
139 const wxGLContext *shared,
140 wxWindowID id,
141 const wxPoint& pos,
142 const wxSize& size,
143 long style,
144 const wxString& name,
145 const int *attribList,
146 const wxPalette& palette)
147 {
148 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
149 m_glContext = new wxGLContext(this, shared);
150 }
151
152 wxGLCanvas::wxGLCanvas(wxWindow *parent,
153 const wxGLCanvas *shared,
154 wxWindowID id,
155 const wxPoint& pos,
156 const wxSize& size,
157 long style,
158 const wxString& name,
159 const int *attribList,
160 const wxPalette& palette)
161 {
162 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
163 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
164 }
165
166 #endif // WXWIN_COMPATIBILITY_2_8
167
168 static AGLPixelFormat ChoosePixelFormat(const int *attribList)
169 {
170 GLint data[512];
171 const GLint defaultAttribs[] =
172 {
173 AGL_RGBA,
174 AGL_DOUBLEBUFFER,
175 AGL_MINIMUM_POLICY, // never choose less than requested
176 AGL_DEPTH_SIZE, 1, // use largest available depth buffer
177 AGL_RED_SIZE, 1,
178 AGL_GREEN_SIZE, 1,
179 AGL_BLUE_SIZE, 1,
180 AGL_ALPHA_SIZE, 0,
181 AGL_NONE
182 };
183
184 const GLint *attribs;
185 if ( !attribList )
186 {
187 attribs = defaultAttribs;
188 }
189 else
190 {
191 unsigned p = 0;
192 data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX
193
194 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
195 {
196 switch ( attribList[arg++] )
197 {
198 case WX_GL_RGBA:
199 data[p++] = AGL_RGBA;
200 break;
201
202 case WX_GL_BUFFER_SIZE:
203 data[p++] = AGL_BUFFER_SIZE;
204 data[p++] = attribList[arg++];
205 break;
206
207 case WX_GL_LEVEL:
208 data[p++]=AGL_LEVEL;
209 data[p++]=attribList[arg++];
210 break;
211
212 case WX_GL_DOUBLEBUFFER:
213 data[p++] = AGL_DOUBLEBUFFER;
214 break;
215
216 case WX_GL_STEREO:
217 data[p++] = AGL_STEREO;
218 break;
219
220 case WX_GL_AUX_BUFFERS:
221 data[p++] = AGL_AUX_BUFFERS;
222 data[p++] = attribList[arg++];
223 break;
224
225 case WX_GL_MIN_RED:
226 data[p++] = AGL_RED_SIZE;
227 data[p++] = attribList[arg++];
228 break;
229
230 case WX_GL_MIN_GREEN:
231 data[p++] = AGL_GREEN_SIZE;
232 data[p++] = attribList[arg++];
233 break;
234
235 case WX_GL_MIN_BLUE:
236 data[p++] = AGL_BLUE_SIZE;
237 data[p++] = attribList[arg++];
238 break;
239
240 case WX_GL_MIN_ALPHA:
241 data[p++] = AGL_ALPHA_SIZE;
242 data[p++] = attribList[arg++];
243 break;
244
245 case WX_GL_DEPTH_SIZE:
246 data[p++] = AGL_DEPTH_SIZE;
247 data[p++] = attribList[arg++];
248 break;
249
250 case WX_GL_STENCIL_SIZE:
251 data[p++] = AGL_STENCIL_SIZE;
252 data[p++] = attribList[arg++];
253 break;
254
255 case WX_GL_MIN_ACCUM_RED:
256 data[p++] = AGL_ACCUM_RED_SIZE;
257 data[p++] = attribList[arg++];
258 break;
259
260 case WX_GL_MIN_ACCUM_GREEN:
261 data[p++] = AGL_ACCUM_GREEN_SIZE;
262 data[p++] = attribList[arg++];
263 break;
264
265 case WX_GL_MIN_ACCUM_BLUE:
266 data[p++] = AGL_ACCUM_BLUE_SIZE;
267 data[p++] = attribList[arg++];
268 break;
269
270 case WX_GL_MIN_ACCUM_ALPHA:
271 data[p++] = AGL_ACCUM_ALPHA_SIZE;
272 data[p++] = attribList[arg++];
273 break;
274 }
275 }
276
277 data[p] = AGL_NONE;
278
279 attribs = data;
280 }
281
282 return aglChoosePixelFormat(NULL, 0, attribs);
283 }
284
285 bool wxGLCanvas::Create(wxWindow *parent,
286 wxWindowID id,
287 const wxPoint& pos,
288 const wxSize& size,
289 long style,
290 const wxString& name,
291 const int *attribList,
292 const wxPalette& WXUNUSED(palette))
293 {
294 m_needsUpdate = false;
295 m_macCanvasIsShown = false;
296
297 m_aglFormat = ChoosePixelFormat(attribList);
298 if ( !m_aglFormat )
299 return false;
300
301 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
302 return false;
303
304 m_macCanvasIsShown = true;
305
306 return true;
307 }
308
309 wxGLCanvas::~wxGLCanvas()
310 {
311 if ( m_aglFormat )
312 aglDestroyPixelFormat(m_aglFormat);
313 }
314
315 /* static */
316 bool wxGLCanvasBase::IsDisplaySupported(const int *attribList)
317 {
318 AGLPixelFormat aglFormat = ChoosePixelFormat(attribList);
319
320 if ( !aglFormat )
321 return false;
322
323 aglDestroyPixelFormat(aglFormat);
324
325 return true;
326 }
327
328 bool wxGLCanvas::SwapBuffers()
329 {
330 AGLContext context = aglGetCurrentContext();
331 wxCHECK_MSG(context, false, _T("should have current context"));
332
333 aglSwapBuffers(context);
334 return true;
335 }
336
337 void wxGLCanvas::SetViewport()
338 {
339 if ( !m_needsUpdate )
340 return;
341
342 m_needsUpdate = false;
343
344 AGLContext context = aglGetCurrentContext();
345 if ( !context )
346 return;
347
348 // viewport is initially set to entire port, adjust it to just this window
349 int x = 0,
350 y = 0;
351 MacClientToRootWindow(&x , &y);
352
353 int width, height;
354 GetClientSize(&width, &height);
355
356 Rect bounds;
357 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds);
358
359 #if 0
360 // TODO in case we adopt point vs pixel coordinates, this will make the conversion
361 HIRect hiRect = CGRectMake( x, y, width, height );
362 HIRectConvert( &hiRect, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
363 HIRect hiBounds = CGRectMake( 0, 0, bounds.right - bounds.left , bounds.bottom - bounds.top );
364 HIRectConvert( &hiBounds, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
365 GLint parms[4];
366 parms[0] = hiRect.origin.x;
367 parms[1] = hiBounds.size.height - (hiRect.origin.y + hiRect.size.height);
368 parms[2] = hiRect.size.width;
369 parms[3] = hiRect.size.height;
370 #else
371 GLint parms[4];
372 parms[0] = x;
373 parms[1] = bounds.bottom - bounds.top - ( y + height );
374 parms[2] = width;
375 parms[3] = height;
376 #endif
377
378 // move the buffer rect out of sight if we're hidden
379 if ( !m_macCanvasIsShown )
380 parms[0] += 20000;
381
382 if ( !aglSetInteger(context, AGL_BUFFER_RECT, parms) )
383 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
384
385 if ( !aglEnable(context, AGL_BUFFER_RECT) )
386 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
387
388 if ( !aglUpdateContext(context) )
389 wxLogAGLError("aglUpdateContext");
390 }
391
392 void wxGLCanvas::OnSize(wxSizeEvent& event)
393 {
394 MacUpdateView();
395 event.Skip();
396 }
397
398 void wxGLCanvas::MacUpdateView()
399 {
400 m_needsUpdate = true;
401 Refresh(false);
402 }
403
404 void wxGLCanvas::MacSuperChangedPosition()
405 {
406 MacUpdateView();
407 wxWindow::MacSuperChangedPosition();
408 }
409
410 void wxGLCanvas::MacTopLevelWindowChangedPosition()
411 {
412 MacUpdateView();
413 wxWindow::MacTopLevelWindowChangedPosition();
414 }
415
416 void wxGLCanvas::MacVisibilityChanged()
417 {
418 if ( IsShownOnScreen() != m_macCanvasIsShown )
419 {
420 m_macCanvasIsShown = !m_macCanvasIsShown;
421 MacUpdateView();
422 }
423
424 wxWindowMac::MacVisibilityChanged();
425 }
426
427 // ----------------------------------------------------------------------------
428 // wxGLApp
429 // ----------------------------------------------------------------------------
430
431 bool wxGLApp::InitGLVisual(const int *attribList)
432 {
433 AGLPixelFormat fmt = ChoosePixelFormat(attribList);
434 if ( !fmt )
435 return false;
436
437 aglDestroyPixelFormat(fmt);
438 return true;
439 }
440
441 #endif // wxUSE_GLCANVAS