1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/iphone/glcanvas.mm
3 // Purpose: wxGLCanvas, for using OpenGL with wxWidgets under iPhone
4 // Author: Stefan Csomor
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 #include "wx/wxprec.h"
21 #if defined(__BORLANDC__)
27 #include "wx/glcanvas.h"
32 #include "wx/settings.h"
35 #include "wx/osx/private.h"
37 #import <OpenGLES/EAGL.h>
38 #import <OpenGLES/EAGLDrawable.h>
39 #import <QuartzCore/QuartzCore.h>
41 // a lot of the code is from the OpenGL ES Template
43 // can be turned on for ES 2.0 only
44 #define USE_DEPTH_BUFFER 0
46 @interface wxUICustomOpenGLView : UIView
51 /* The pixel dimensions of the backbuffer */
55 /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
56 GLuint viewRenderbuffer, viewFramebuffer;
58 /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
59 GLuint depthRenderbuffer;
62 - (BOOL) createFramebuffer;
63 - (void) destroyFramebuffer;
64 - (id) initWithFrame:(CGRect) rect;
68 @implementation wxUICustomOpenGLView
71 return [CAEAGLLayer class];
76 static BOOL initialized = NO;
80 wxOSXIPhoneClassAddWXMethods( self );
84 - (id) initWithFrame:(CGRect)rect
86 if ( !(self=[super initWithFrame:rect]) )
98 - (BOOL)createFramebuffer {
100 glGenFramebuffersOES(1, &viewFramebuffer);
101 glGenRenderbuffersOES(1, &viewRenderbuffer);
102 glEnable(GL_CULL_FACE);
104 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
105 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
106 [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
107 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
109 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
110 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
112 if (USE_DEPTH_BUFFER) {
113 glGenRenderbuffersOES(1, &depthRenderbuffer);
114 glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
115 glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
116 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
119 if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
120 NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
128 - (void)destroyFramebuffer {
130 glDeleteFramebuffersOES(1, &viewFramebuffer);
132 glDeleteRenderbuffersOES(1, &viewRenderbuffer);
133 viewRenderbuffer = 0;
135 if(depthRenderbuffer) {
136 glDeleteRenderbuffersOES(1, &depthRenderbuffer);
137 depthRenderbuffer = 0;
141 - (void) setContext:(EAGLContext*) ctx {
143 [EAGLContext setCurrentContext:ctx];
145 if ( viewFramebuffer == 0 )
147 [self destroyFramebuffer];
148 [self createFramebuffer];
151 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
154 - (void) swapBuffers {
155 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
156 [context presentRenderbuffer:GL_RENDERBUFFER_OES];
159 - (void)layoutSubviews {
160 [EAGLContext setCurrentContext:context];
161 [self destroyFramebuffer];
162 [self createFramebuffer];
168 WXGLContext WXGLCreateContext( WXGLPixelFormat pixelFormat, WXGLContext shareContext )
170 WXGLContext context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
172 // [[EAGLContext alloc] initWithFormat:pixelFormat shareContext: shareContext];
174 wxFAIL_MSG("NSOpenGLContext creation failed");
178 void WXGLDestroyContext( WXGLContext context )
186 WXGLContext WXGLGetCurrentContext()
188 return [EAGLContext currentContext];
191 bool WXGLSetCurrentContext(WXGLContext context)
193 [EAGLContext setCurrentContext:context];
197 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat )
202 [pixelFormat release];
208 WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList)
211 NSOpenGLPixelFormatAttribute data[512];
212 const NSOpenGLPixelFormatAttribute defaultAttribs[] =
214 NSOpenGLPFADoubleBuffer,
215 NSOpenGLPFAMinimumPolicy,
216 NSOpenGLPFAColorSize,(NSOpenGLPixelFormatAttribute)8,
217 NSOpenGLPFAAlphaSize,(NSOpenGLPixelFormatAttribute)0,
218 NSOpenGLPFADepthSize,(NSOpenGLPixelFormatAttribute)8,
219 (NSOpenGLPixelFormatAttribute)nil
222 const NSOpenGLPixelFormatAttribute *attribs;
225 attribs = defaultAttribs;
230 data[p++] = NSOpenGLPFAMinimumPolicy; // make _SIZE tags behave more like GLX
232 for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
234 switch ( attribList[arg++] )
237 //data[p++] = AGL_RGBA;
240 case WX_GL_BUFFER_SIZE:
241 //data[p++] = AGL_BUFFER_SIZE;
242 //data[p++] = attribList[arg++];
246 //data[p++]=AGL_LEVEL;
247 //data[p++]=attribList[arg++];
250 case WX_GL_DOUBLEBUFFER:
251 data[p++] = NSOpenGLPFADoubleBuffer;
255 data[p++] = NSOpenGLPFAStereo;
258 case WX_GL_AUX_BUFFERS:
259 data[p++] = NSOpenGLPFAAuxBuffers;
260 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
264 data[p++] = NSOpenGLPFAColorSize;
265 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
268 case WX_GL_MIN_GREEN:
269 //data[p++] = AGL_GREEN_SIZE;
270 //data[p++] = attribList[arg++];
274 //data[p++] = AGL_BLUE_SIZE;
275 //data[p++] = attribList[arg++];
278 case WX_GL_MIN_ALPHA:
279 data[p++] = NSOpenGLPFAAlphaSize;
280 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
283 case WX_GL_DEPTH_SIZE:
284 data[p++] = NSOpenGLPFADepthSize;
285 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
288 case WX_GL_STENCIL_SIZE:
289 data[p++] = NSOpenGLPFAStencilSize;
290 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
293 case WX_GL_MIN_ACCUM_RED:
294 data[p++] = NSOpenGLPFAAccumSize;
295 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
298 case WX_GL_MIN_ACCUM_GREEN:
299 //data[p++] = AGL_ACCUM_GREEN_SIZE;
300 //data[p++] = attribList[arg++];
303 case WX_GL_MIN_ACCUM_BLUE:
304 //data[p++] = AGL_ACCUM_BLUE_SIZE;
305 //data[p++] = attribList[arg++];
308 case WX_GL_MIN_ACCUM_ALPHA:
309 //data[p++] = AGL_ACCUM_ALPHA_SIZE;
310 //data[p++] = attribList[arg++];
313 case WX_GL_SAMPLE_BUFFERS:
314 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
316 if ( !attribList[arg++] )
322 data[p++] = NSOpenGLPFASampleBuffers;
323 if ( (data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]) == true )
325 // don't use software fallback
326 data[p++] = NSOpenGLPFANoRecovery;
331 if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
333 if ( !attribList[arg++] )
339 data[p++] = NSOpenGLPFASamples;
340 data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
345 data[p] = (NSOpenGLPixelFormatAttribute)nil;
350 return [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute*) attribs];
355 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
360 wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) win.GetPeer()->GetWXWidget();
361 [v setContext:m_glContext];
365 #define USE_SEPARATE_VIEW 1
367 bool wxGLCanvas::Create(wxWindow *parent,
372 const wxString& name,
373 const int *attribList,
374 const wxPalette& WXUNUSED(palette))
377 m_glFormat = WXGLChoosePixelFormat(attribList);
381 #if USE_SEPARATE_VIEW
385 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
388 #if USE_SEPARATE_VIEW
389 CGRect r = wxOSXGetFrameForControl( this, pos , size ) ;
390 wxUICustomOpenGLView* v = [[wxUICustomOpenGLView alloc] initWithFrame:r];
391 CAEAGLLayer* eaglLayer = (CAEAGLLayer*) v.layer;
392 eaglLayer.opaque = YES;
393 eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
394 [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
395 kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
397 SetPeer(new wxWidgetIPhoneImpl( this, v ));
399 MacPostControlCreate(pos, size) ;
404 wxGLCanvas::~wxGLCanvas()
407 WXGLDestroyPixelFormat(m_glFormat);
410 bool wxGLCanvas::SwapBuffers()
412 WXGLContext context = WXGLGetCurrentContext();
413 wxCHECK_MSG(context, false, wxT("should have current context"));
415 wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) GetPeer()->GetWXWidget();
421 #endif // wxUSE_GLCANVAS