]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/glcanvas.cpp
Added automatic dialog scrolling ability
[wxWidgets.git] / src / mac / carbon / glcanvas.cpp
CommitLineData
dc3065a5 1///////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/mac/carbon/glcanvas.cpp
77ffb593 3// Purpose: wxGLCanvas, for using OpenGL with wxWidgets under Macintosh
a31a5f85 4// Author: Stefan Csomor
0a67a93b 5// Modified by:
a31a5f85 6// Created: 1998-01-01
0a67a93b 7// RCS-ID: $Id$
a31a5f85 8// Copyright: (c) Stefan Csomor
e4db172a 9// Licence: wxWindows licence
dc3065a5
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
0a67a93b 19
0a67a93b
SC
20#include "wx/wxprec.h"
21
22#if defined(__BORLANDC__)
e4db172a 23 #pragma hdrstop
0a67a93b
SC
24#endif
25
0a67a93b
SC
26#if wxUSE_GLCANVAS
27
e4db172a
WS
28#include "wx/glcanvas.h"
29
0a67a93b 30#ifndef WX_PRECOMP
e4db172a
WS
31 #include "wx/frame.h"
32 #include "wx/log.h"
9eddec69 33 #include "wx/settings.h"
0a67a93b
SC
34#endif
35
0a67a93b
SC
36#include "wx/mac/uma.h"
37
3a5ff9b1
SC
38#include "wx/mac/private.h"
39
dc3065a5
VZ
40// ----------------------------------------------------------------------------
41// helper functions
42// ----------------------------------------------------------------------------
0a67a93b 43
dc3065a5 44static void wxLogAGLError(const char *func)
0a67a93b 45{
dc3065a5 46 const int err = aglGetError();
e4db172a 47
dc3065a5
VZ
48 wxLogError(_("OpenGL function \"%s\" failed: %s (error %d)"),
49 func, aglErrorString(err), err);
50}
e4db172a 51
dc3065a5
VZ
52// ============================================================================
53// implementation
54// ============================================================================
e4db172a 55
dc3065a5
VZ
56// ----------------------------------------------------------------------------
57// wxGLContext
58// ----------------------------------------------------------------------------
0a67a93b 59
dc3065a5 60wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext *other)
0a67a93b 61{
dc3065a5
VZ
62 m_aglContext = aglCreateContext(win->GetAGLPixelFormat(),
63 other ? other->m_aglContext : NULL);
64 if ( !m_aglContext )
65 wxLogAGLError("aglCreateContext");
0a67a93b
SC
66}
67
dc3065a5 68wxGLContext::~wxGLContext()
0a67a93b 69{
dc3065a5 70 if ( m_aglContext )
e40298d5 71 {
dc3065a5
VZ
72 // it's ok to pass the current context to this function
73 if ( !aglDestroyContext(m_aglContext) )
74 wxLogAGLError("aglDestroyContext");
e40298d5 75 }
0a67a93b
SC
76}
77
50ccc908 78bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
0a67a93b 79{
dc3065a5 80 if ( !m_aglContext )
50ccc908 81 return false;
0a67a93b 82
7fc641af 83 AGLDrawable drawable = (AGLDrawable)GetWindowPort(
dc3065a5
VZ
84 MAC_WXHWND(win.MacGetTopLevelWindowRef()));
85 if ( !aglSetDrawable(m_aglContext, drawable) )
50ccc908 86 {
dc3065a5 87 wxLogAGLError("aglSetDrawable");
50ccc908
PC
88 return false;
89 }
0a67a93b 90
dc3065a5 91 if ( !aglSetCurrentContext(m_aglContext) )
50ccc908 92 {
dc3065a5 93 wxLogAGLError("aglSetCurrentContext");
50ccc908
PC
94 return false;
95 }
0a67a93b 96
dc3065a5 97 wx_const_cast(wxGLCanvas&, win).SetViewport();
50ccc908 98 return true;
dc3065a5 99}
0a67a93b 100
dc3065a5
VZ
101// ----------------------------------------------------------------------------
102// wxGLCanvas
103// ----------------------------------------------------------------------------
0a67a93b 104
4660d7e5 105IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
0a67a93b 106
4660d7e5 107BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
0a67a93b
SC
108 EVT_SIZE(wxGLCanvas::OnSize)
109END_EVENT_TABLE()
110
dc3065a5
VZ
111wxGLCanvas::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)
0a67a93b 119{
dc3065a5 120 Create(parent, id, pos, size, style, name, attribList, palette);
0a67a93b
SC
121}
122
dc3065a5
VZ
123#if WXWIN_COMPATIBILITY_2_8
124
125wxGLCanvas::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)
0a67a93b 133{
dc3065a5
VZ
134 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
135 m_glContext = new wxGLContext(this);
0a67a93b
SC
136}
137
dc3065a5
VZ
138wxGLCanvas::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)
0a67a93b 147{
dc3065a5
VZ
148 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
149 m_glContext = new wxGLContext(this, shared);
0a67a93b
SC
150}
151
dc3065a5
VZ
152wxGLCanvas::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)
0a67a93b 161{
dc3065a5
VZ
162 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
163 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
0a67a93b
SC
164}
165
dc3065a5
VZ
166#endif // WXWIN_COMPATIBILITY_2_8
167
16506231 168static AGLPixelFormat ChoosePixelFormat(const int *attribList)
0a67a93b 169{
0a67a93b 170 GLint data[512];
dc3065a5
VZ
171 const GLint defaultAttribs[] =
172 {
173 AGL_RGBA,
e4db172a 174 AGL_DOUBLEBUFFER,
dc3065a5 175 AGL_MINIMUM_POLICY, // never choose less than requested
e40298d5 176 AGL_DEPTH_SIZE, 1, // use largest available depth buffer
e4db172a
WS
177 AGL_RED_SIZE, 1,
178 AGL_GREEN_SIZE, 1,
179 AGL_BLUE_SIZE, 1,
180 AGL_ALPHA_SIZE, 0,
dc3065a5
VZ
181 AGL_NONE
182 };
183
184 const GLint *attribs;
185 if ( !attribList )
0a67a93b 186 {
e40298d5 187 attribs = defaultAttribs;
0a67a93b
SC
188 }
189 else
190 {
dc3065a5 191 unsigned p = 0;
e40298d5 192 data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX
dc3065a5
VZ
193
194 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
0a67a93b 195 {
dc3065a5 196 switch ( attribList[arg++] )
e40298d5 197 {
dc3065a5
VZ
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;
e40298d5 274 }
e4db172a 275 }
dc3065a5
VZ
276
277 data[p] = AGL_NONE;
e4db172a 278
e40298d5 279 attribs = data;
0a67a93b 280 }
e4db172a 281
16506231
GD
282 return aglChoosePixelFormat(NULL, 0, attribs);
283}
284
dc3065a5
VZ
285bool 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))
16506231 293{
dc3065a5
VZ
294 m_needsUpdate = false;
295 m_macCanvasIsShown = false;
e4db172a 296
dc3065a5
VZ
297 m_aglFormat = ChoosePixelFormat(attribList);
298 if ( !m_aglFormat )
299 return false;
e4db172a 300
dc3065a5
VZ
301 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
302 return false;
303
304 m_macCanvasIsShown = true;
e4db172a 305
0a67a93b
SC
306 return true;
307}
308
dc3065a5 309wxGLCanvas::~wxGLCanvas()
0a67a93b 310{
dc3065a5
VZ
311 if ( m_aglFormat )
312 aglDestroyPixelFormat(m_aglFormat);
0a67a93b
SC
313}
314
50ccc908 315bool wxGLCanvas::SwapBuffers()
0a67a93b 316{
dc3065a5 317 AGLContext context = aglGetCurrentContext();
50ccc908 318 wxCHECK_MSG(context, false, _T("should have current context"));
dc3065a5
VZ
319
320 aglSwapBuffers(context);
50ccc908 321 return true;
0a67a93b
SC
322}
323
324void wxGLCanvas::SetViewport()
325{
dc3065a5
VZ
326 if ( !m_needsUpdate )
327 return;
e4db172a 328
dc3065a5
VZ
329 m_needsUpdate = false;
330
331 AGLContext context = aglGetCurrentContext();
332 if ( !context )
333 return;
334
335 // viewport is initially set to entire port, adjust it to just this window
336 int x = 0,
337 y = 0;
338 MacClientToRootWindow(&x , &y);
339
340 int width, height;
341 GetClientSize(&width, &height);
342
343 Rect bounds;
344 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds);
e4db172a 345
3a5ff9b1 346#if 0
dc3065a5
VZ
347 // TODO in case we adopt point vs pixel coordinates, this will make the conversion
348 HIRect hiRect = CGRectMake( x, y, width, height );
349 HIRectConvert( &hiRect, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
350 HIRect hiBounds = CGRectMake( 0, 0, bounds.right - bounds.left , bounds.bottom - bounds.top );
351 HIRectConvert( &hiBounds, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
352 GLint parms[4];
353 parms[0] = hiRect.origin.x;
354 parms[1] = hiBounds.size.height - (hiRect.origin.y + hiRect.size.height);
355 parms[2] = hiRect.size.width;
356 parms[3] = hiRect.size.height;
3a5ff9b1 357#else
dc3065a5
VZ
358 GLint parms[4];
359 parms[0] = x;
360 parms[1] = bounds.bottom - bounds.top - ( y + height );
361 parms[2] = width;
362 parms[3] = height;
3a5ff9b1 363#endif
0a67a93b 364
dc3065a5
VZ
365 // move the buffer rect out of sight if we're hidden
366 if ( !m_macCanvasIsShown )
367 parms[0] += 20000;
a3bf4a62 368
dc3065a5 369 if ( !aglSetInteger(context, AGL_BUFFER_RECT, parms) )
dc3065a5 370 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
1be2473f 371
eea05623
VZ
372 if ( !aglEnable(context, AGL_BUFFER_RECT) )
373 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
374
1be2473f
VZ
375 if ( !aglUpdateContext(context) )
376 wxLogAGLError("aglUpdateContext");
0a67a93b
SC
377}
378
dc3065a5 379void wxGLCanvas::OnSize(wxSizeEvent& event)
a3bf4a62 380{
dc3065a5
VZ
381 MacUpdateView();
382 event.Skip();
a3bf4a62
SC
383}
384
dc3065a5 385void wxGLCanvas::MacUpdateView()
0a67a93b 386{
dc3065a5
VZ
387 m_needsUpdate = true;
388 Refresh(false);
0a67a93b
SC
389}
390
dc3065a5 391void wxGLCanvas::MacSuperChangedPosition()
0a67a93b 392{
dc3065a5
VZ
393 MacUpdateView();
394 wxWindow::MacSuperChangedPosition();
0a67a93b
SC
395}
396
dc3065a5 397void wxGLCanvas::MacTopLevelWindowChangedPosition()
ab89a5b5 398{
dc3065a5
VZ
399 MacUpdateView();
400 wxWindow::MacTopLevelWindowChangedPosition();
ab89a5b5
SC
401}
402
e4db172a 403void wxGLCanvas::MacVisibilityChanged()
ab89a5b5 404{
dc3065a5 405 if ( MacIsReallyShown() != m_macCanvasIsShown )
ab89a5b5 406 {
dc3065a5
VZ
407 m_macCanvasIsShown = !m_macCanvasIsShown;
408 MacUpdateView();
ab89a5b5 409 }
dc3065a5
VZ
410
411 wxWindowMac::MacVisibilityChanged();
ab89a5b5 412}
16506231 413
dc3065a5 414// ----------------------------------------------------------------------------
16506231 415// wxGLApp
dc3065a5 416// ----------------------------------------------------------------------------
16506231 417
dc3065a5 418bool wxGLApp::InitGLVisual(const int *attribList)
16506231
GD
419{
420 AGLPixelFormat fmt = ChoosePixelFormat(attribList);
dc3065a5 421 if ( !fmt )
bf44306e 422 return false;
16506231 423
dc3065a5
VZ
424 aglDestroyPixelFormat(fmt);
425 return true;
16506231
GD
426}
427
0a67a93b 428#endif // wxUSE_GLCANVAS