making sure we have an initial frame buffer, even though the first initial rootview...
[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
146     if ( viewFramebuffer == 0 )
147     {
148         [self destroyFramebuffer];
149         [self createFramebuffer];        
150     }
151
152     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
153 }
154  
155 - (void) swapBuffers {
156     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
157     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
158 }
159
160 - (void)layoutSubviews {
161     [EAGLContext setCurrentContext:context];
162     [self destroyFramebuffer];
163     [self createFramebuffer];
164 }
165
166 @end
167
168
169 WXGLContext WXGLCreateContext( WXGLPixelFormat pixelFormat, WXGLContext shareContext )
170 {
171     WXGLContext context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
172     
173     // [[EAGLContext alloc] initWithFormat:pixelFormat shareContext: shareContext];
174     if ( !context )
175         wxFAIL_MSG("NSOpenGLContext creation failed");
176     return context ;
177 }
178
179 void WXGLDestroyContext( WXGLContext context )
180 {
181     if ( context )
182     {
183         [context release];
184     }
185 }
186
187 WXGLContext WXGLGetCurrentContext()
188 {
189     return [EAGLContext currentContext];
190 }
191
192 bool WXGLSetCurrentContext(WXGLContext context)
193 {
194     [EAGLContext setCurrentContext:context];
195     return true;
196 }
197
198 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat )
199 {
200 /*
201     if ( pixelFormat )
202     {
203         [pixelFormat release];
204     }
205 */
206 }
207
208
209 WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList)
210 {
211 #if 0
212     NSOpenGLPixelFormatAttribute data[512];
213     const NSOpenGLPixelFormatAttribute defaultAttribs[] =
214     {
215         NSOpenGLPFADoubleBuffer,
216         NSOpenGLPFAMinimumPolicy,
217         NSOpenGLPFAColorSize,(NSOpenGLPixelFormatAttribute)8,
218         NSOpenGLPFAAlphaSize,(NSOpenGLPixelFormatAttribute)0,
219         NSOpenGLPFADepthSize,(NSOpenGLPixelFormatAttribute)8,
220         (NSOpenGLPixelFormatAttribute)nil
221     };
222
223     const NSOpenGLPixelFormatAttribute *attribs;
224     if ( !attribList )
225     {
226         attribs = defaultAttribs;
227     }
228     else
229     {
230         unsigned p = 0;
231         data[p++] = NSOpenGLPFAMinimumPolicy; // make _SIZE tags behave more like GLX
232
233         for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
234         {
235             switch ( attribList[arg++] )
236             {
237                 case WX_GL_RGBA:
238                     //data[p++] = AGL_RGBA;
239                     break;
240
241                 case WX_GL_BUFFER_SIZE:
242                     //data[p++] = AGL_BUFFER_SIZE;
243                     //data[p++] = attribList[arg++];
244                     break;
245
246                 case WX_GL_LEVEL:
247                     //data[p++]=AGL_LEVEL;
248                     //data[p++]=attribList[arg++];
249                     break;
250
251                 case WX_GL_DOUBLEBUFFER:
252                     data[p++] = NSOpenGLPFADoubleBuffer;
253                     break;
254
255                 case WX_GL_STEREO:
256                     data[p++] = NSOpenGLPFAStereo;
257                     break;
258
259                 case WX_GL_AUX_BUFFERS:
260                     data[p++] = NSOpenGLPFAAuxBuffers;
261                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
262                     break;
263
264                 case WX_GL_MIN_RED:
265                     data[p++] = NSOpenGLPFAColorSize;
266                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
267                     break;
268
269                 case WX_GL_MIN_GREEN:
270                     //data[p++] = AGL_GREEN_SIZE;
271                     //data[p++] = attribList[arg++];
272                     break;
273
274                 case WX_GL_MIN_BLUE:
275                     //data[p++] = AGL_BLUE_SIZE;
276                     //data[p++] = attribList[arg++];
277                     break;
278
279                 case WX_GL_MIN_ALPHA:
280                     data[p++] = NSOpenGLPFAAlphaSize;
281                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
282                     break;
283
284                 case WX_GL_DEPTH_SIZE:
285                     data[p++] = NSOpenGLPFADepthSize;
286                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
287                     break;
288
289                 case WX_GL_STENCIL_SIZE:
290                     data[p++] = NSOpenGLPFAStencilSize;
291                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
292                     break;
293
294                 case WX_GL_MIN_ACCUM_RED:
295                     data[p++] = NSOpenGLPFAAccumSize;
296                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
297                     break;
298
299                 case WX_GL_MIN_ACCUM_GREEN:
300                     //data[p++] = AGL_ACCUM_GREEN_SIZE;
301                     //data[p++] = attribList[arg++];
302                     break;
303
304                 case WX_GL_MIN_ACCUM_BLUE:
305                     //data[p++] = AGL_ACCUM_BLUE_SIZE;
306                     //data[p++] = attribList[arg++];
307                     break;
308
309                 case WX_GL_MIN_ACCUM_ALPHA:
310                     //data[p++] = AGL_ACCUM_ALPHA_SIZE;
311                     //data[p++] = attribList[arg++];
312                     break;
313
314                 case WX_GL_SAMPLE_BUFFERS:
315                     if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
316                     {
317                         if ( !attribList[arg++] )
318                             break;
319
320                         return false;
321                     }
322
323                     data[p++] = NSOpenGLPFASampleBuffers;
324                     if ( (data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]) == true )
325                     {
326                         // don't use software fallback
327                         data[p++] = NSOpenGLPFANoRecovery;
328                     }
329                     break;
330
331                 case WX_GL_SAMPLES:
332                     if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
333                     {
334                         if ( !attribList[arg++] )
335                             break;
336
337                         return false;
338                     }
339
340                     data[p++] = NSOpenGLPFASamples;
341                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
342                     break;
343             }
344         }
345
346         data[p] = (NSOpenGLPixelFormatAttribute)nil;
347
348         attribs = data;
349     }
350
351     return [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute*) attribs];
352 #endif
353     return NULL;
354 }
355
356 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
357 {
358     if ( !m_glContext )
359         return false;  
360
361     wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) win.GetPeer()->GetWXWidget();
362     [v setContext:m_glContext];
363     return true;
364 }
365
366 #define USE_SEPARATE_VIEW 1
367
368 bool wxGLCanvas::Create(wxWindow *parent,
369                         wxWindowID id,
370                         const wxPoint& pos,
371                         const wxSize& size,
372                         long style,
373                         const wxString& name,
374                         const int *attribList,
375                         const wxPalette& WXUNUSED(palette))
376 {
377 /*
378     m_glFormat = WXGLChoosePixelFormat(attribList);
379     if ( !m_glFormat )
380         return false;
381 */
382 #if USE_SEPARATE_VIEW
383     DontCreatePeer();
384 #endif
385
386     if ( !wxWindow::Create(parent, id, pos, size, style, name) )
387         return false;
388
389 #if USE_SEPARATE_VIEW
390     CGRect r = wxOSXGetFrameForControl( this, pos , size ) ;
391     wxUICustomOpenGLView* v = [[wxUICustomOpenGLView alloc] initWithFrame:r];
392     CAEAGLLayer* eaglLayer = (CAEAGLLayer*) v.layer;
393     eaglLayer.opaque = YES;
394     eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
395             [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, 
396             kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
397             
398     SetPeer(new wxWidgetIPhoneImpl( this, v ));
399
400     MacPostControlCreate(pos, size) ;
401 #endif
402     return true;
403 }
404
405 wxGLCanvas::~wxGLCanvas()
406 {
407     if ( m_glFormat )
408         WXGLDestroyPixelFormat(m_glFormat);
409 }
410
411 bool wxGLCanvas::SwapBuffers()
412 {
413     WXGLContext context = WXGLGetCurrentContext();
414     wxCHECK_MSG(context, false, wxT("should have current context"));
415
416     wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) GetPeer()->GetWXWidget();
417     [v swapBuffers];
418     return true;
419 }
420
421
422 #endif // wxUSE_GLCANVAS