]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/glcanvas.cpp
Finally fixed control scrolling
[wxWidgets.git] / src / mac / carbon / glcanvas.cpp
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/mac/uma.h"
37
38 #include "wx/mac/private.h"
39
40 // ----------------------------------------------------------------------------
41 // helper functions
42 // ----------------------------------------------------------------------------
43
44 static 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 // ----------------------------------------------------------------------------
57 // wxGLContext
58 // ----------------------------------------------------------------------------
59
60 wxGLContext::wxGLContext(wxGLCanvas *win, const wxGLContext *other)
61 {
62 m_aglContext = aglCreateContext(win->GetAGLPixelFormat(),
63 other ? other->m_aglContext : NULL);
64 if ( !m_aglContext )
65 wxLogAGLError("aglCreateContext");
66
67 return;
68 if ( !aglEnable(m_aglContext, AGL_BUFFER_RECT) )
69 wxLogAGLError("aglEnable(AGL_BUFFER_RECT)");
70 }
71
72 wxGLContext::~wxGLContext()
73 {
74 if ( m_aglContext )
75 {
76 // it's ok to pass the current context to this function
77 if ( !aglDestroyContext(m_aglContext) )
78 wxLogAGLError("aglDestroyContext");
79 }
80 }
81
82 void wxGLContext::SetCurrent(const wxGLCanvas& win) const
83 {
84 if ( !m_aglContext )
85 return;
86
87 AGLDrawable drawable = (AGLDrawable)UMAGetWindowPort(
88 MAC_WXHWND(win.MacGetTopLevelWindowRef()));
89 if ( !aglSetDrawable(m_aglContext, drawable) )
90 wxLogAGLError("aglSetDrawable");
91
92 if ( !aglSetCurrentContext(m_aglContext) )
93 wxLogAGLError("aglSetCurrentContext");
94
95 wx_const_cast(wxGLCanvas&, win).SetViewport();
96 }
97
98 // ----------------------------------------------------------------------------
99 // wxGLCanvas
100 // ----------------------------------------------------------------------------
101
102 IMPLEMENT_CLASS(wxGLCanvas, wxWindow)
103
104 BEGIN_EVENT_TABLE(wxGLCanvas, wxWindow)
105 EVT_SIZE(wxGLCanvas::OnSize)
106 END_EVENT_TABLE()
107
108 wxGLCanvas::wxGLCanvas(wxWindow *parent,
109 wxWindowID id,
110 const int *attribList,
111 const wxPoint& pos,
112 const wxSize& size,
113 long style,
114 const wxString& name,
115 const wxPalette& palette)
116 {
117 Create(parent, id, pos, size, style, name, attribList, palette);
118 }
119
120 #if WXWIN_COMPATIBILITY_2_8
121
122 wxGLCanvas::wxGLCanvas(wxWindow *parent,
123 wxWindowID id,
124 const wxPoint& pos,
125 const wxSize& size,
126 long style,
127 const wxString& name,
128 const int *attribList,
129 const wxPalette& palette)
130 {
131 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
132 m_glContext = new wxGLContext(this);
133 }
134
135 wxGLCanvas::wxGLCanvas(wxWindow *parent,
136 const wxGLContext *shared,
137 wxWindowID id,
138 const wxPoint& pos,
139 const wxSize& size,
140 long style,
141 const wxString& name,
142 const int *attribList,
143 const wxPalette& palette)
144 {
145 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
146 m_glContext = new wxGLContext(this, shared);
147 }
148
149 wxGLCanvas::wxGLCanvas(wxWindow *parent,
150 const wxGLCanvas *shared,
151 wxWindowID id,
152 const wxPoint& pos,
153 const wxSize& size,
154 long style,
155 const wxString& name,
156 const int *attribList,
157 const wxPalette& palette)
158 {
159 if ( Create(parent, id, pos, size, style, name, attribList, palette) )
160 m_glContext = new wxGLContext(this, shared ? shared->m_glContext : NULL);
161 }
162
163 #endif // WXWIN_COMPATIBILITY_2_8
164
165 static AGLPixelFormat ChoosePixelFormat(const int *attribList)
166 {
167 GLint data[512];
168 const GLint defaultAttribs[] =
169 {
170 AGL_RGBA,
171 AGL_DOUBLEBUFFER,
172 AGL_MINIMUM_POLICY, // never choose less than requested
173 AGL_DEPTH_SIZE, 1, // use largest available depth buffer
174 AGL_RED_SIZE, 1,
175 AGL_GREEN_SIZE, 1,
176 AGL_BLUE_SIZE, 1,
177 AGL_ALPHA_SIZE, 0,
178 AGL_NONE
179 };
180
181 const GLint *attribs;
182 if ( !attribList )
183 {
184 attribs = defaultAttribs;
185 }
186 else
187 {
188 unsigned p = 0;
189 data[p++] = AGL_MINIMUM_POLICY; // make _SIZE tags behave more like GLX
190
191 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
192 {
193 switch ( attribList[arg++] )
194 {
195 case WX_GL_RGBA:
196 data[p++] = AGL_RGBA;
197 break;
198
199 case WX_GL_BUFFER_SIZE:
200 data[p++] = AGL_BUFFER_SIZE;
201 data[p++] = attribList[arg++];
202 break;
203
204 case WX_GL_LEVEL:
205 data[p++]=AGL_LEVEL;
206 data[p++]=attribList[arg++];
207 break;
208
209 case WX_GL_DOUBLEBUFFER:
210 data[p++] = AGL_DOUBLEBUFFER;
211 break;
212
213 case WX_GL_STEREO:
214 data[p++] = AGL_STEREO;
215 break;
216
217 case WX_GL_AUX_BUFFERS:
218 data[p++] = AGL_AUX_BUFFERS;
219 data[p++] = attribList[arg++];
220 break;
221
222 case WX_GL_MIN_RED:
223 data[p++] = AGL_RED_SIZE;
224 data[p++] = attribList[arg++];
225 break;
226
227 case WX_GL_MIN_GREEN:
228 data[p++] = AGL_GREEN_SIZE;
229 data[p++] = attribList[arg++];
230 break;
231
232 case WX_GL_MIN_BLUE:
233 data[p++] = AGL_BLUE_SIZE;
234 data[p++] = attribList[arg++];
235 break;
236
237 case WX_GL_MIN_ALPHA:
238 data[p++] = AGL_ALPHA_SIZE;
239 data[p++] = attribList[arg++];
240 break;
241
242 case WX_GL_DEPTH_SIZE:
243 data[p++] = AGL_DEPTH_SIZE;
244 data[p++] = attribList[arg++];
245 break;
246
247 case WX_GL_STENCIL_SIZE:
248 data[p++] = AGL_STENCIL_SIZE;
249 data[p++] = attribList[arg++];
250 break;
251
252 case WX_GL_MIN_ACCUM_RED:
253 data[p++] = AGL_ACCUM_RED_SIZE;
254 data[p++] = attribList[arg++];
255 break;
256
257 case WX_GL_MIN_ACCUM_GREEN:
258 data[p++] = AGL_ACCUM_GREEN_SIZE;
259 data[p++] = attribList[arg++];
260 break;
261
262 case WX_GL_MIN_ACCUM_BLUE:
263 data[p++] = AGL_ACCUM_BLUE_SIZE;
264 data[p++] = attribList[arg++];
265 break;
266
267 case WX_GL_MIN_ACCUM_ALPHA:
268 data[p++] = AGL_ACCUM_ALPHA_SIZE;
269 data[p++] = attribList[arg++];
270 break;
271 }
272 }
273
274 data[p] = AGL_NONE;
275
276 attribs = data;
277 }
278
279 return aglChoosePixelFormat(NULL, 0, attribs);
280 }
281
282 bool wxGLCanvas::Create(wxWindow *parent,
283 wxWindowID id,
284 const wxPoint& pos,
285 const wxSize& size,
286 long style,
287 const wxString& name,
288 const int *attribList,
289 const wxPalette& WXUNUSED(palette))
290 {
291 m_needsUpdate = false;
292 m_macCanvasIsShown = false;
293
294 m_aglFormat = ChoosePixelFormat(attribList);
295 if ( !m_aglFormat )
296 return false;
297
298 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
299 return false;
300
301 m_macCanvasIsShown = true;
302
303 return true;
304 }
305
306 wxGLCanvas::~wxGLCanvas()
307 {
308 if ( m_aglFormat )
309 aglDestroyPixelFormat(m_aglFormat);
310 }
311
312 void wxGLCanvas::SwapBuffers()
313 {
314 AGLContext context = aglGetCurrentContext();
315 wxCHECK_RET( context, _T("should have current context") );
316
317 aglSwapBuffers(context);
318 }
319
320 void wxGLCanvas::SetViewport()
321 {
322 if ( !m_needsUpdate )
323 return;
324
325 m_needsUpdate = false;
326
327 AGLContext context = aglGetCurrentContext();
328 if ( !context )
329 return;
330
331 // viewport is initially set to entire port, adjust it to just this window
332 int x = 0,
333 y = 0;
334 MacClientToRootWindow(&x , &y);
335
336 int width, height;
337 GetClientSize(&width, &height);
338
339 Rect bounds;
340 GetWindowPortBounds(MAC_WXHWND(MacGetTopLevelWindowRef()) , &bounds);
341
342 #if 0
343 // TODO in case we adopt point vs pixel coordinates, this will make the conversion
344 HIRect hiRect = CGRectMake( x, y, width, height );
345 HIRectConvert( &hiRect, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
346 HIRect hiBounds = CGRectMake( 0, 0, bounds.right - bounds.left , bounds.bottom - bounds.top );
347 HIRectConvert( &hiBounds, kHICoordSpace72DPIGlobal, NULL, kHICoordSpaceScreenPixel, NULL);
348 GLint parms[4];
349 parms[0] = hiRect.origin.x;
350 parms[1] = hiBounds.size.height - (hiRect.origin.y + hiRect.size.height);
351 parms[2] = hiRect.size.width;
352 parms[3] = hiRect.size.height;
353 #else
354 GLint parms[4];
355 parms[0] = x;
356 parms[1] = bounds.bottom - bounds.top - ( y + height );
357 parms[2] = width;
358 parms[3] = height;
359 #endif
360
361 // move the buffer rect out of sight if we're hidden
362 if ( !m_macCanvasIsShown )
363 parms[0] += 20000;
364
365 if ( !aglSetInteger(context, AGL_BUFFER_RECT, parms) )
366 wxLogAGLError("aglSetInteger(AGL_BUFFER_RECT)");
367
368 if ( !aglUpdateContext(context) )
369 wxLogAGLError("aglUpdateContext");
370 }
371
372 void wxGLCanvas::OnSize(wxSizeEvent& event)
373 {
374 MacUpdateView();
375 event.Skip();
376 }
377
378 void wxGLCanvas::MacUpdateView()
379 {
380 m_needsUpdate = true;
381 Refresh(false);
382 }
383
384 void wxGLCanvas::MacSuperChangedPosition()
385 {
386 MacUpdateView();
387 wxWindow::MacSuperChangedPosition();
388 }
389
390 void wxGLCanvas::MacTopLevelWindowChangedPosition()
391 {
392 MacUpdateView();
393 wxWindow::MacTopLevelWindowChangedPosition();
394 }
395
396 void wxGLCanvas::MacVisibilityChanged()
397 {
398 if ( MacIsReallyShown() != m_macCanvasIsShown )
399 {
400 m_macCanvasIsShown = !m_macCanvasIsShown;
401 MacUpdateView();
402 }
403
404 wxWindowMac::MacVisibilityChanged();
405 }
406
407 // ----------------------------------------------------------------------------
408 // wxGLApp
409 // ----------------------------------------------------------------------------
410
411 bool wxGLApp::InitGLVisual(const int *attribList)
412 {
413 AGLPixelFormat fmt = ChoosePixelFormat(attribList);
414 if ( !fmt )
415 return false;
416
417 aglDestroyPixelFormat(fmt);
418 return true;
419 }
420
421 #endif // wxUSE_GLCANVAS