]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/glcanvas.cpp
avoid deferred show with Fluxbox, its support for _NET_REQUEST_FRAME_EXTENTS is broken
[wxWidgets.git] / src / osx / carbon / glcanvas.cpp
CommitLineData
489468fe
SC
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
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 80void WXGLSwapBuffers( WXGLContext context )
489468fe 81{
524c47aa 82 aglSwapBuffers(context);
489468fe
SC
83}
84
524c47aa 85WXGLContext WXGLGetCurrentContext()
489468fe 86{
524c47aa 87 return aglGetCurrentContext();
489468fe
SC
88}
89
b6ccc13c
VZ
90bool WXGLSetCurrentContext(WXGLContext context)
91{
92 if ( !aglSetCurrentContext(context) )
93 {
94 wxLogAGLError("aglSetCurrentContext");
95 return false;
96 }
97
98 return true;
99}
100
524c47aa 101void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat )
489468fe 102{
524c47aa
SC
103 if ( pixelFormat )
104 {
105 aglDestroyPixelFormat(pixelFormat);
106 }
489468fe
SC
107}
108
524c47aa 109WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList)
489468fe
SC
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
524c47aa
SC
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);
03647350 271
5c33522f 272 const_cast<wxGLCanvas&>(win).SetViewport();
524c47aa
SC
273
274 if ( !aglSetDrawable(m_glContext, drawable) )
275 {
276 wxLogAGLError("aglSetDrawable");
277 return false;
278 }
279
b6ccc13c 280 return WXGLSetCurrentContext(m_glContext);
524c47aa
SC
281}
282
283// ----------------------------------------------------------------------------
284// wxGLCanvas
285// ----------------------------------------------------------------------------
286
287/*
288
03647350 289sharing contexts under AGL is not straightforward, to quote from
524c47aa
SC
290
291http://lists.apple.com/archives/mac-opengl/2003/Jan/msg00402.html :
292
03647350
VZ
293In Carbon OpenGL (AGL) you would use call aglSetInteger to setup a
294buffer name and attached each context to that same name. From AGL
524c47aa
SC
295you can do:
296
297GLint id = 1;
298
299ctx1 = aglCreateContext...
300aglSetInteger(ctx1, AGL_BUFFER_NAME, &id); // create name
03647350 301aglAttachDrawable (ctx1,...); // create surface with associated with
524c47aa
SC
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/*
03647350 323so what I'm doing is to have a dummy aglContext attached to a wxGLCanvas,
524c47aa
SC
324assign it a buffer number
325*/
326
327
489468fe
SC
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
524c47aa
SC
340 m_glFormat = WXGLChoosePixelFormat(attribList);
341 if ( !m_glFormat )
489468fe
SC
342 return false;
343
344 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
345 return false;
346
524c47aa 347 m_dummyContext = WXGLCreateContext(m_glFormat, NULL);
489468fe 348
524c47aa
SC
349 static GLint gCurrentBufferName = 1;
350 m_bufferName = gCurrentBufferName++;
03647350
VZ
351 aglSetInteger (m_dummyContext, AGL_BUFFER_NAME, &m_bufferName);
352
524c47aa
SC
353 AGLDrawable drawable = (AGLDrawable)GetWindowPort(MAC_WXHWND(MacGetTopLevelWindowRef()));
354 aglSetDrawable(m_dummyContext, drawable);
489468fe 355
524c47aa 356 m_macCanvasIsShown = true;
489468fe
SC
357
358 return true;
359}
360
524c47aa 361wxGLCanvas::~wxGLCanvas()
489468fe 362{
524c47aa
SC
363 if ( m_glFormat )
364 WXGLDestroyPixelFormat(m_glFormat);
03647350 365
524c47aa
SC
366 if ( m_dummyContext )
367 WXGLDestroyContext(m_dummyContext);
489468fe
SC
368}
369
370void wxGLCanvas::SetViewport()
371{
372 if ( !m_needsUpdate )
373 return;
374
375 m_needsUpdate = false;
376
524c47aa
SC
377// AGLContext context = aglGetCurrentContext();
378// if ( !context )
379// return;
489468fe
SC
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
489468fe
SC
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;
489468fe
SC
397
398 // move the buffer rect out of sight if we're hidden
399 if ( !m_macCanvasIsShown )
400 parms[0] += 20000;
401
524c47aa 402 if ( !aglSetInteger(m_dummyContext, AGL_BUFFER_RECT, parms) )
489468fe
SC
403 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
404
524c47aa 405 if ( !aglEnable(m_dummyContext, AGL_BUFFER_RECT) )
489468fe
SC
406 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
407
524c47aa 408 if ( !aglUpdateContext(m_dummyContext) )
489468fe
SC
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();
524c47aa 427 SetViewport();
489468fe
SC
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
489468fe 448#endif // wxUSE_GLCANVAS