1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/iphone/glcanvas.mm
3 // Purpose: wxGLCanvas, for using OpenGL with wxWidgets under iPhone
4 // Author: Stefan Csomor
7 // RCS-ID: $Id: glcanvas.cpp 54129 2008-06-11 19:30:52Z SC $
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
22 #if defined(__BORLANDC__)
28 #include "wx/glcanvas.h"
33 #include "wx/settings.h"
36 #include "wx/osx/private.h"
38 #import <OpenGLES/EAGL.h>
39 #import <OpenGLES/EAGLDrawable.h>
40 #import <QuartzCore/QuartzCore.h>
42 // a lot of the code is from the OpenGL ES Template
44 // can be turned on for ES 2.0 only
45 #define USE_DEPTH_BUFFER 0
47 @interface wxUICustomOpenGLView : UIView
52 /* The pixel dimensions of the backbuffer */
56 /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
57 GLuint viewRenderbuffer, viewFramebuffer;
59 /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
60 GLuint depthRenderbuffer;
63 - (BOOL) createFramebuffer;
64 - (void) destroyFramebuffer;
65 - (id) initWithFrame:(CGRect) rect;
69 @implementation wxUICustomOpenGLView
72 return [CAEAGLLayer class];
77 static BOOL initialized = NO;
81 wxOSXIPhoneClassAddWXMethods( self );
85 - (id) initWithFrame:(CGRect)rect
87 if ( !(self=[super initWithFrame:rect]) )
99 - (BOOL)createFramebuffer {
101 glGenFramebuffersOES(1, &viewFramebuffer);
102 glGenRenderbuffersOES(1, &viewRenderbuffer);
103 glEnable(GL_CULL_FACE);
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);
110 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
111 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
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);
120 if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
121 NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
129 - (void)destroyFramebuffer {
131 glDeleteFramebuffersOES(1, &viewFramebuffer);
133 glDeleteRenderbuffersOES(1, &viewRenderbuffer);
134 viewRenderbuffer = 0;
136 if(depthRenderbuffer) {
137 glDeleteRenderbuffersOES(1, &depthRenderbuffer);
138 depthRenderbuffer = 0;
142 - (void) setContext:(EAGLContext*) ctx {
144 [EAGLContext setCurrentContext:ctx];
146 CGRect newRect = [self frame];
147 if ( /* (CGRectEqualToRect(newRect, oldRect) == NO && ![self isHidden] && newRect.size.width > 0 && newRect.size.height > 0 )
148 || */ viewFramebuffer == 0 )
150 [self destroyFramebuffer];
151 [self createFramebuffer];
154 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
157 - (void) swapBuffers {
158 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
159 [context presentRenderbuffer:GL_RENDERBUFFER_OES];
162 - (void)layoutSubviews {
163 [EAGLContext setCurrentContext:context];
164 [self destroyFramebuffer];
165 [self createFramebuffer];
171 WXGLContext WXGLCreateContext( WXGLPixelFormat pixelFormat, WXGLContext shareContext )
173 WXGLContext context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
175 // [[EAGLContext alloc] initWithFormat:pixelFormat shareContext: shareContext];
177 wxFAIL_MSG("NSOpenGLContext creation failed");
181 void WXGLDestroyContext( WXGLContext context )
189 WXGLContext WXGLGetCurrentContext()
191 return [EAGLContext currentContext];
194 bool WXGLSetCurrentContext(WXGLContext context)
196 [EAGLContext setCurrentContext:context];
200 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat )
205 [pixelFormat release];
211 WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList)
214 NSOpenGLPixelFormatAttribute data[512];
215 const NSOpenGLPixelFormatAttribute defaultAttribs[] =
217 NSOpenGLPFADoubleBuffer,
218 NSOpenGLPFAMinimumPolicy,
219 NSOpenGLPFAColorSize,(NSOpenGLPixelFormatAttribute)8,
220 NSOpenGLPFAAlphaSize,(NSOpenGLPixelFormatAttribute)0,
221 NSOpenGLPFADepthSize,(NSOpenGLPixelFormatAttribute)8,
222 (NSOpenGLPixelFormatAttribute)nil
225 const NSOpenGLPixelFormatAttribute *attribs;
228 attribs = defaultAttribs;
233 data[p++] = NSOpenGLPFAMinimumPolicy; // make _SIZE tags behave more like GLX
235 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
237 switch ( attribList[arg++] )
240 //data[p++] = AGL_RGBA;
243 case WX_GL_BUFFER_SIZE:
244 //data[p++] = AGL_BUFFER_SIZE;
245 //data[p++] = attribList[arg++];
249 //data[p++]=AGL_LEVEL;
250 //data[p++]=attribList[arg++];
253 case WX_GL_DOUBLEBUFFER:
254 data[p++] = NSOpenGLPFADoubleBuffer;
258 data[p++] = NSOpenGLPFAStereo;
261 case WX_GL_AUX_BUFFERS:
262 data[p++] = NSOpenGLPFAAuxBuffers;
263 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
267 data[p++] = NSOpenGLPFAColorSize;
268 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
271 case WX_GL_MIN_GREEN:
272 //data[p++] = AGL_GREEN_SIZE;
273 //data[p++] = attribList[arg++];
277 //data[p++] = AGL_BLUE_SIZE;
278 //data[p++] = attribList[arg++];
281 case WX_GL_MIN_ALPHA:
282 data[p++] = NSOpenGLPFAAlphaSize;
283 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
286 case WX_GL_DEPTH_SIZE:
287 data[p++] = NSOpenGLPFADepthSize;
288 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
291 case WX_GL_STENCIL_SIZE:
292 data[p++] = NSOpenGLPFAStencilSize;
293 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
296 case WX_GL_MIN_ACCUM_RED:
297 data[p++] = NSOpenGLPFAAccumSize;
298 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
301 case WX_GL_MIN_ACCUM_GREEN:
302 //data[p++] = AGL_ACCUM_GREEN_SIZE;
303 //data[p++] = attribList[arg++];
306 case WX_GL_MIN_ACCUM_BLUE:
307 //data[p++] = AGL_ACCUM_BLUE_SIZE;
308 //data[p++] = attribList[arg++];
311 case WX_GL_MIN_ACCUM_ALPHA:
312 //data[p++] = AGL_ACCUM_ALPHA_SIZE;
313 //data[p++] = attribList[arg++];
316 case WX_GL_SAMPLE_BUFFERS:
317 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
319 if ( !attribList[arg++] )
325 data[p++] = NSOpenGLPFASampleBuffers;
326 if ( (data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]) == true )
328 // don't use software fallback
329 data[p++] = NSOpenGLPFANoRecovery;
334 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
336 if ( !attribList[arg++] )
342 data[p++] = NSOpenGLPFASamples;
343 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
348 data[p] = (NSOpenGLPixelFormatAttribute)nil;
353 return [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute*) attribs];
358 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
363 wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) win.GetPeer()->GetWXWidget();
364 [v setContext:m_glContext];
368 #define USE_SEPARATE_VIEW 1
370 bool wxGLCanvas::Create(wxWindow *parent,
375 const wxString& name,
376 const int *attribList,
377 const wxPalette& WXUNUSED(palette))
380 m_glFormat = WXGLChoosePixelFormat(attribList);
384 #if USE_SEPARATE_VIEW
385 m_macIsUserPane = false ;
388 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
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];
400 m_peer = new wxWidgetIPhoneImpl( this, v );
402 MacPostControlCreate(pos, size) ;
407 wxGLCanvas::~wxGLCanvas()
410 WXGLDestroyPixelFormat(m_glFormat);
413 bool wxGLCanvas::SwapBuffers()
415 WXGLContext context = WXGLGetCurrentContext();
416 wxCHECK_MSG(context, false, wxT("should have current context"));
418 wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) m_peer->GetWXWidget();
424 #endif // wxUSE_GLCANVAS