]> git.saurik.com Git - wxWidgets.git/blob - src/osx/iphone/glcanvas.mm
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / osx / iphone / glcanvas.mm
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/iphone/glcanvas.mm
3 // Purpose: wxGLCanvas, for using OpenGL with wxWidgets under iPhone
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/osx/private.h"
37
38 #import <OpenGLES/EAGL.h>
39 #import <OpenGLES/EAGLDrawable.h>
40 #import <QuartzCore/QuartzCore.h>
41
42 // a lot of the code is from the OpenGL ES Template
43
44 // can be turned on for ES 2.0 only
45 #define USE_DEPTH_BUFFER 0
46
47 @interface wxUICustomOpenGLView : UIView
48 {
49 CGRect oldRect;
50 EAGLContext* context;
51
52 /* The pixel dimensions of the backbuffer */
53 GLint backingWidth;
54 GLint backingHeight;
55
56 /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
57 GLuint viewRenderbuffer, viewFramebuffer;
58
59 /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
60 GLuint depthRenderbuffer;
61 }
62
63 - (BOOL) createFramebuffer;
64 - (void) destroyFramebuffer;
65 - (id) initWithFrame:(CGRect) rect;
66
67 @end
68
69 @implementation wxUICustomOpenGLView
70
71 + (Class)layerClass {
72 return [CAEAGLLayer class];
73 }
74
75 + (void)initialize
76 {
77 static BOOL initialized = NO;
78 if (!initialized)
79 {
80 initialized = YES;
81 wxOSXIPhoneClassAddWXMethods( self );
82 }
83 }
84
85 - (id) initWithFrame:(CGRect)rect
86 {
87 if ( !(self=[super initWithFrame:rect]) )
88 return nil;
89
90 oldRect = rect;
91 return self;
92 }
93
94 - (BOOL)isOpaque
95 {
96 return YES;
97 }
98
99 - (BOOL)createFramebuffer {
100
101 glGenFramebuffersOES(1, &viewFramebuffer);
102 glGenRenderbuffersOES(1, &viewRenderbuffer);
103 glEnable(GL_CULL_FACE);
104
105 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
106 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
107 [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
108 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
109
110 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
111 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
112
113 if (USE_DEPTH_BUFFER) {
114 glGenRenderbuffersOES(1, &depthRenderbuffer);
115 glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
116 glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
117 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
118 }
119
120 if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
121 NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
122 return NO;
123 }
124
125 return YES;
126 }
127
128
129 - (void)destroyFramebuffer {
130
131 glDeleteFramebuffersOES(1, &viewFramebuffer);
132 viewFramebuffer = 0;
133 glDeleteRenderbuffersOES(1, &viewRenderbuffer);
134 viewRenderbuffer = 0;
135
136 if(depthRenderbuffer) {
137 glDeleteRenderbuffersOES(1, &depthRenderbuffer);
138 depthRenderbuffer = 0;
139 }
140 }
141
142 - (void) setContext:(EAGLContext*) ctx {
143 context = ctx;
144 [EAGLContext setCurrentContext:ctx];
145 #if 0
146 CGRect newRect = [self frame];
147 if ( /* (CGRectEqualToRect(newRect, oldRect) == NO && ![self isHidden] && newRect.size.width > 0 && newRect.size.height > 0 )
148 || */ viewFramebuffer == 0 )
149 {
150 [self destroyFramebuffer];
151 [self createFramebuffer];
152 }
153 #endif
154 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
155 }
156
157 - (void) swapBuffers {
158 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
159 [context presentRenderbuffer:GL_RENDERBUFFER_OES];
160 }
161
162 - (void)layoutSubviews {
163 [EAGLContext setCurrentContext:context];
164 [self destroyFramebuffer];
165 [self createFramebuffer];
166 }
167
168 @end
169
170
171 WXGLContext WXGLCreateContext( WXGLPixelFormat pixelFormat, WXGLContext shareContext )
172 {
173 WXGLContext context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
174
175 // [[EAGLContext alloc] initWithFormat:pixelFormat shareContext: shareContext];
176 if ( !context )
177 wxFAIL_MSG("NSOpenGLContext creation failed");
178 return context ;
179 }
180
181 void WXGLDestroyContext( WXGLContext context )
182 {
183 if ( context )
184 {
185 [context release];
186 }
187 }
188
189 WXGLContext WXGLGetCurrentContext()
190 {
191 return [EAGLContext currentContext];
192 }
193
194 bool WXGLSetCurrentContext(WXGLContext context)
195 {
196 [EAGLContext setCurrentContext:context];
197 return true;
198 }
199
200 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat )
201 {
202 /*
203 if ( pixelFormat )
204 {
205 [pixelFormat release];
206 }
207 */
208 }
209
210
211 WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList)
212 {
213 #if 0
214 NSOpenGLPixelFormatAttribute data[512];
215 const NSOpenGLPixelFormatAttribute defaultAttribs[] =
216 {
217 NSOpenGLPFADoubleBuffer,
218 NSOpenGLPFAMinimumPolicy,
219 NSOpenGLPFAColorSize,(NSOpenGLPixelFormatAttribute)8,
220 NSOpenGLPFAAlphaSize,(NSOpenGLPixelFormatAttribute)0,
221 NSOpenGLPFADepthSize,(NSOpenGLPixelFormatAttribute)8,
222 (NSOpenGLPixelFormatAttribute)nil
223 };
224
225 const NSOpenGLPixelFormatAttribute *attribs;
226 if ( !attribList )
227 {
228 attribs = defaultAttribs;
229 }
230 else
231 {
232 unsigned p = 0;
233 data[p++] = NSOpenGLPFAMinimumPolicy; // make _SIZE tags behave more like GLX
234
235 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
236 {
237 switch ( attribList[arg++] )
238 {
239 case WX_GL_RGBA:
240 //data[p++] = AGL_RGBA;
241 break;
242
243 case WX_GL_BUFFER_SIZE:
244 //data[p++] = AGL_BUFFER_SIZE;
245 //data[p++] = attribList[arg++];
246 break;
247
248 case WX_GL_LEVEL:
249 //data[p++]=AGL_LEVEL;
250 //data[p++]=attribList[arg++];
251 break;
252
253 case WX_GL_DOUBLEBUFFER:
254 data[p++] = NSOpenGLPFADoubleBuffer;
255 break;
256
257 case WX_GL_STEREO:
258 data[p++] = NSOpenGLPFAStereo;
259 break;
260
261 case WX_GL_AUX_BUFFERS:
262 data[p++] = NSOpenGLPFAAuxBuffers;
263 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
264 break;
265
266 case WX_GL_MIN_RED:
267 data[p++] = NSOpenGLPFAColorSize;
268 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
269 break;
270
271 case WX_GL_MIN_GREEN:
272 //data[p++] = AGL_GREEN_SIZE;
273 //data[p++] = attribList[arg++];
274 break;
275
276 case WX_GL_MIN_BLUE:
277 //data[p++] = AGL_BLUE_SIZE;
278 //data[p++] = attribList[arg++];
279 break;
280
281 case WX_GL_MIN_ALPHA:
282 data[p++] = NSOpenGLPFAAlphaSize;
283 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
284 break;
285
286 case WX_GL_DEPTH_SIZE:
287 data[p++] = NSOpenGLPFADepthSize;
288 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
289 break;
290
291 case WX_GL_STENCIL_SIZE:
292 data[p++] = NSOpenGLPFAStencilSize;
293 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
294 break;
295
296 case WX_GL_MIN_ACCUM_RED:
297 data[p++] = NSOpenGLPFAAccumSize;
298 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
299 break;
300
301 case WX_GL_MIN_ACCUM_GREEN:
302 //data[p++] = AGL_ACCUM_GREEN_SIZE;
303 //data[p++] = attribList[arg++];
304 break;
305
306 case WX_GL_MIN_ACCUM_BLUE:
307 //data[p++] = AGL_ACCUM_BLUE_SIZE;
308 //data[p++] = attribList[arg++];
309 break;
310
311 case WX_GL_MIN_ACCUM_ALPHA:
312 //data[p++] = AGL_ACCUM_ALPHA_SIZE;
313 //data[p++] = attribList[arg++];
314 break;
315
316 case WX_GL_SAMPLE_BUFFERS:
317 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
318 {
319 if ( !attribList[arg++] )
320 break;
321
322 return false;
323 }
324
325 data[p++] = NSOpenGLPFASampleBuffers;
326 if ( (data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]) == true )
327 {
328 // don't use software fallback
329 data[p++] = NSOpenGLPFANoRecovery;
330 }
331 break;
332
333 case WX_GL_SAMPLES:
334 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
335 {
336 if ( !attribList[arg++] )
337 break;
338
339 return false;
340 }
341
342 data[p++] = NSOpenGLPFASamples;
343 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
344 break;
345 }
346 }
347
348 data[p] = (NSOpenGLPixelFormatAttribute)nil;
349
350 attribs = data;
351 }
352
353 return [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute*) attribs];
354 #endif
355 return NULL;
356 }
357
358 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
359 {
360 if ( !m_glContext )
361 return false;
362
363 wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) win.GetPeer()->GetWXWidget();
364 [v setContext:m_glContext];
365 return true;
366 }
367
368 #define USE_SEPARATE_VIEW 1
369
370 bool wxGLCanvas::Create(wxWindow *parent,
371 wxWindowID id,
372 const wxPoint& pos,
373 const wxSize& size,
374 long style,
375 const wxString& name,
376 const int *attribList,
377 const wxPalette& WXUNUSED(palette))
378 {
379 /*
380 m_glFormat = WXGLChoosePixelFormat(attribList);
381 if ( !m_glFormat )
382 return false;
383 */
384 #if USE_SEPARATE_VIEW
385 DontCreatePeer();
386 #endif
387
388 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
389 return false;
390
391 #if USE_SEPARATE_VIEW
392 CGRect r = wxOSXGetFrameForControl( this, pos , size ) ;
393 wxUICustomOpenGLView* v = [[wxUICustomOpenGLView alloc] initWithFrame:r];
394 CAEAGLLayer* eaglLayer = (CAEAGLLayer*) v.layer;
395 eaglLayer.opaque = YES;
396 eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
397 [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
398 kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
399
400 SetPeer(new wxWidgetIPhoneImpl( this, v ));
401
402 MacPostControlCreate(pos, size) ;
403 #endif
404 return true;
405 }
406
407 wxGLCanvas::~wxGLCanvas()
408 {
409 if ( m_glFormat )
410 WXGLDestroyPixelFormat(m_glFormat);
411 }
412
413 bool wxGLCanvas::SwapBuffers()
414 {
415 WXGLContext context = WXGLGetCurrentContext();
416 wxCHECK_MSG(context, false, wxT("should have current context"));
417
418 wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) GetPeer()->GetWXWidget();
419 [v swapBuffers];
420 return true;
421 }
422
423
424 #endif // wxUSE_GLCANVAS