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