]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/osx/carbon/glcanvas.cpp
Never overflow the output buffer in wxBase64Decode().
[wxWidgets.git] / src / osx / carbon / glcanvas.cpp
... / ...
CommitLineData
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/osx/uma.h"
37
38#include "wx/osx/private.h"
39#include <AGL/agl.h>
40
41// ----------------------------------------------------------------------------
42// helper functions
43// ----------------------------------------------------------------------------
44
45static void wxLogAGLError(const char *func)
46{
47 const int err = aglGetError();
48
49 wxLogError(_("OpenGL function \"%s\" failed: %s (error %d)"),
50 func, aglErrorString(err), err);
51}
52
53// ============================================================================
54// implementation
55// ============================================================================
56
57// ----------------------------------------------------------------------------
58// low level implementation routines
59// ----------------------------------------------------------------------------
60
61WXGLContext WXGLCreateContext( WXGLPixelFormat pixelFormat, WXGLContext shareContext )
62{
63 WXGLContext context = aglCreateContext(pixelFormat, shareContext);
64 if ( !context )
65 wxLogAGLError("aglCreateContext");
66 return context ;
67}
68
69void WXGLDestroyContext( WXGLContext context )
70{
71 if ( context )
72 {
73 if ( !aglDestroyContext(context) )
74 {
75 wxLogAGLError("aglDestroyContext");
76 }
77 }
78}
79
80void WXGLSwapBuffers( WXGLContext context )
81{
82 aglSwapBuffers(context);
83}
84
85WXGLContext WXGLGetCurrentContext()
86{
87 return aglGetCurrentContext();
88}
89
90bool WXGLSetCurrentContext(WXGLContext context)
91{
92 if ( !aglSetCurrentContext(context) )
93 {
94 wxLogAGLError("aglSetCurrentContext");
95 return false;
96 }
97
98 return true;
99}
100
101void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat )
102{
103 if ( pixelFormat )
104 {
105 aglDestroyPixelFormat(pixelFormat);
106 }
107}
108
109WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList)
110{
111 GLint data[512];
112 const GLint defaultAttribs[] =
113 {
114 AGL_RGBA,
115 AGL_DOUBLEBUFFER,
116 AGL_MINIMUM_POLICY, // never choose less than requested
117 AGL_DEPTH_SIZE, 1, // use largest available depth buffer
118 AGL_RED_SIZE, 1,
119 AGL_GREEN_SIZE, 1,
120 AGL_BLUE_SIZE, 1,
121 AGL_ALPHA_SIZE, 0,
122 AGL_NONE
123 };
124
125 const GLint *attribs;
126 if ( !attribList )
127 {
128 attribs = defaultAttribs;
129 }
130 else
131 {
132 unsigned p = 0;
133 data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX
134
135 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
136 {
137 switch ( attribList[arg++] )
138 {
139 case WX_GL_RGBA:
140 data[p++] = AGL_RGBA;
141 break;
142
143 case WX_GL_BUFFER_SIZE:
144 data[p++] = AGL_BUFFER_SIZE;
145 data[p++] = attribList[arg++];
146 break;
147
148 case WX_GL_LEVEL:
149 data[p++]=AGL_LEVEL;
150 data[p++]=attribList[arg++];
151 break;
152
153 case WX_GL_DOUBLEBUFFER:
154 data[p++] = AGL_DOUBLEBUFFER;
155 break;
156
157 case WX_GL_STEREO:
158 data[p++] = AGL_STEREO;
159 break;
160
161 case WX_GL_AUX_BUFFERS:
162 data[p++] = AGL_AUX_BUFFERS;
163 data[p++] = attribList[arg++];
164 break;
165
166 case WX_GL_MIN_RED:
167 data[p++] = AGL_RED_SIZE;
168 data[p++] = attribList[arg++];
169 break;
170
171 case WX_GL_MIN_GREEN:
172 data[p++] = AGL_GREEN_SIZE;
173 data[p++] = attribList[arg++];
174 break;
175
176 case WX_GL_MIN_BLUE:
177 data[p++] = AGL_BLUE_SIZE;
178 data[p++] = attribList[arg++];
179 break;
180
181 case WX_GL_MIN_ALPHA:
182 data[p++] = AGL_ALPHA_SIZE;
183 data[p++] = attribList[arg++];
184 break;
185
186 case WX_GL_DEPTH_SIZE:
187 data[p++] = AGL_DEPTH_SIZE;
188 data[p++] = attribList[arg++];
189 break;
190
191 case WX_GL_STENCIL_SIZE:
192 data[p++] = AGL_STENCIL_SIZE;
193 data[p++] = attribList[arg++];
194 break;
195
196 case WX_GL_MIN_ACCUM_RED:
197 data[p++] = AGL_ACCUM_RED_SIZE;
198 data[p++] = attribList[arg++];
199 break;
200
201 case WX_GL_MIN_ACCUM_GREEN:
202 data[p++] = AGL_ACCUM_GREEN_SIZE;
203 data[p++] = attribList[arg++];
204 break;
205
206 case WX_GL_MIN_ACCUM_BLUE:
207 data[p++] = AGL_ACCUM_BLUE_SIZE;
208 data[p++] = attribList[arg++];
209 break;
210
211 case WX_GL_MIN_ACCUM_ALPHA:
212 data[p++] = AGL_ACCUM_ALPHA_SIZE;
213 data[p++] = attribList[arg++];
214 break;
215
216 case WX_GL_SAMPLE_BUFFERS:
217 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
218 {
219 if ( !attribList[arg++] )
220 break;
221
222 return false;
223 }
224
225 data[p++] = AGL_SAMPLE_BUFFERS_ARB;
226 if ( (data[p++] = attribList[arg++]) == true )
227 {
228 // don't use software fallback
229 data[p++] = AGL_NO_RECOVERY;
230 }
231 break;
232
233 case WX_GL_SAMPLES:
234 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
235 {
236 if ( !attribList[arg++] )
237 break;
238
239 return false;
240 }
241
242 data[p++] = AGL_SAMPLES_ARB;
243 data[p++] = attribList[arg++];
244 break;
245 }
246 }
247
248 data[p] = AGL_NONE;
249
250 attribs = data;
251 }
252
253 return aglChoosePixelFormat(NULL, 0, attribs);
254}
255
256// ----------------------------------------------------------------------------
257// wxGLContext
258// ----------------------------------------------------------------------------
259
260bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
261{
262 if ( !m_glContext )
263 return false;
264
265 AGLDrawable drawable = (AGLDrawable)GetWindowPort(
266 MAC_WXHWND(win.MacGetTopLevelWindowRef()));
267
268 GLint bufnummer = win.GetAglBufferName();
269 aglSetInteger(m_glContext, AGL_BUFFER_NAME, &bufnummer);
270 //win.SetLastContext(m_glContext);
271
272 const_cast<wxGLCanvas&>(win).SetViewport();
273
274 if ( !aglSetDrawable(m_glContext, drawable) )
275 {
276 wxLogAGLError("aglSetDrawable");
277 return false;
278 }
279
280 return WXGLSetCurrentContext(m_glContext);
281}
282
283// ----------------------------------------------------------------------------
284// wxGLCanvas
285// ----------------------------------------------------------------------------
286
287/*
288
289sharing contexts under AGL is not straightforward, to quote from
290
291http://lists.apple.com/archives/mac-opengl/2003/Jan/msg00402.html :
292
293In Carbon OpenGL (AGL) you would use call aglSetInteger to setup a
294buffer name and attached each context to that same name. From AGL
295you can do:
296
297GLint id = 1;
298
299ctx1 = aglCreateContext...
300aglSetInteger(ctx1, AGL_BUFFER_NAME, &id); // create name
301aglAttachDrawable (ctx1,...); // create surface with associated with
302name (first time)
303ctx2 = aglCreateContext...
304aglSetInteger(ctx2, AGL_BUFFER_NAME, &id); // uses previously created name
305aglAttachDrawable (ctx2, ...); // uses existing surface with existing name
306
307AGL Docs say:
308AGL_BUFFER_NAME
309params contains one value: a non-negative integer name of the surface to be
310associated to be with the current context. If this value is non-zero, and a
311surface of this name is not associated to this drawable, a new surface with
312this name is created and associated with the context when
313aglSetDrawable is called subsequently. If this is a previously allocated
314buffer name within the namespace of the current window (e.g., drawable),
315that previously allocated surface is associated with the context (e.g., no
316new surface is created) and the subsequent call to aglSetDrawable will
317attach that surface. This allows multiple contexts to be attached to a single
318surface. Using the default buffer name zero, returns to one surface per
319context behavior.
320*/
321
322/*
323so what I'm doing is to have a dummy aglContext attached to a wxGLCanvas,
324assign it a buffer number
325*/
326
327
328bool wxGLCanvas::Create(wxWindow *parent,
329 wxWindowID id,
330 const wxPoint& pos,
331 const wxSize& size,
332 long style,
333 const wxString& name,
334 const int *attribList,
335 const wxPalette& WXUNUSED(palette))
336{
337 m_needsUpdate = false;
338 m_macCanvasIsShown = false;
339
340 m_glFormat = WXGLChoosePixelFormat(attribList);
341 if ( !m_glFormat )
342 return false;
343
344 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
345 return false;
346
347 m_dummyContext = WXGLCreateContext(m_glFormat, NULL);
348
349 static GLint gCurrentBufferName = 1;
350 m_bufferName = gCurrentBufferName++;
351 aglSetInteger (m_dummyContext, AGL_BUFFER_NAME, &m_bufferName);
352
353 AGLDrawable drawable = (AGLDrawable)GetWindowPort(MAC_WXHWND(MacGetTopLevelWindowRef()));
354 aglSetDrawable(m_dummyContext, drawable);
355
356 m_macCanvasIsShown = true;
357
358 return true;
359}
360
361wxGLCanvas::~wxGLCanvas()
362{
363 if ( m_glFormat )
364 WXGLDestroyPixelFormat(m_glFormat);
365
366 if ( m_dummyContext )
367 WXGLDestroyContext(m_dummyContext);
368}
369
370void wxGLCanvas::SetViewport()
371{
372 if ( !m_needsUpdate )
373 return;
374
375 m_needsUpdate = false;
376
377// AGLContext context = aglGetCurrentContext();
378// if ( !context )
379// return;
380
381 // viewport is initially set to entire port, adjust it to just this window
382 int x = 0,
383 y = 0;
384 MacClientToRootWindow(&x , &y);
385
386 int width, height;
387 GetClientSize(&width, &height);
388
389 Rect bounds;
390 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds);
391
392 GLint parms[4];
393 parms[0] = x;
394 parms[1] = bounds.bottom - bounds.top - ( y + height );
395 parms[2] = width;
396 parms[3] = height;
397
398 // move the buffer rect out of sight if we're hidden
399 if ( !m_macCanvasIsShown )
400 parms[0] += 20000;
401
402 if ( !aglSetInteger(m_dummyContext, AGL_BUFFER_RECT, parms) )
403 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
404
405 if ( !aglEnable(m_dummyContext, AGL_BUFFER_RECT) )
406 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
407
408 if ( !aglUpdateContext(m_dummyContext) )
409 wxLogAGLError("aglUpdateContext");
410}
411
412void wxGLCanvas::OnSize(wxSizeEvent& event)
413{
414 MacUpdateView();
415 event.Skip();
416}
417
418void wxGLCanvas::MacUpdateView()
419{
420 m_needsUpdate = true;
421 Refresh(false);
422}
423
424void wxGLCanvas::MacSuperChangedPosition()
425{
426 MacUpdateView();
427 SetViewport();
428 wxWindow::MacSuperChangedPosition();
429}
430
431void wxGLCanvas::MacTopLevelWindowChangedPosition()
432{
433 MacUpdateView();
434 wxWindow::MacTopLevelWindowChangedPosition();
435}
436
437void wxGLCanvas::MacVisibilityChanged()
438{
439 if ( IsShownOnScreen() != m_macCanvasIsShown )
440 {
441 m_macCanvasIsShown = !m_macCanvasIsShown;
442 MacUpdateView();
443 }
444
445 wxWindowMac::MacVisibilityChanged();
446}
447
448#endif // wxUSE_GLCANVAS