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