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