The rounded corners look really dumb at this size.
[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 // Copyright:   (c) Stefan Csomor
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21 #if defined(__BORLANDC__)
22     #pragma hdrstop
23 #endif
24
25 #if wxUSE_GLCANVAS
26
27 #include "wx/glcanvas.h"
28
29 #ifndef WX_PRECOMP
30     #include "wx/frame.h"
31     #include "wx/log.h"
32     #include "wx/settings.h"
33 #endif
34
35 #include "wx/osx/private.h"
36
37 #import <OpenGLES/EAGL.h>
38 #import <OpenGLES/EAGLDrawable.h>
39 #import <QuartzCore/QuartzCore.h>
40
41 // a lot of the code is from the OpenGL ES Template
42
43 // can be turned on for ES 2.0 only
44 #define USE_DEPTH_BUFFER 0
45
46 @interface wxUICustomOpenGLView : UIView
47 {
48     CGRect oldRect;
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 - (id) initWithFrame:(CGRect) rect;
65
66 @end
67
68 @implementation wxUICustomOpenGLView
69
70 + (Class)layerClass {
71     return [CAEAGLLayer class];
72 }
73
74 + (void)initialize
75 {
76     static BOOL initialized = NO;
77     if (!initialized) 
78     {
79         initialized = YES;
80         wxOSXIPhoneClassAddWXMethods( self );
81     }
82 }
83
84 - (id) initWithFrame:(CGRect)rect
85 {
86     if ( !(self=[super initWithFrame:rect]) )
87         return nil;
88     
89     oldRect = rect;
90     return self;
91 }
92
93 - (BOOL)isOpaque
94 {
95     return YES;
96 }
97
98 - (BOOL)createFramebuffer {
99     
100     glGenFramebuffersOES(1, &viewFramebuffer);
101     glGenRenderbuffersOES(1, &viewRenderbuffer);
102     glEnable(GL_CULL_FACE);
103     
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);
108     
109     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
110     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
111     
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);
117     }
118     
119     if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
120         NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
121         return NO;
122     }
123     
124     return YES;
125 }
126
127
128 - (void)destroyFramebuffer {
129     
130     glDeleteFramebuffersOES(1, &viewFramebuffer);
131     viewFramebuffer = 0;
132     glDeleteRenderbuffersOES(1, &viewRenderbuffer);
133     viewRenderbuffer = 0;
134     
135     if(depthRenderbuffer) {
136         glDeleteRenderbuffersOES(1, &depthRenderbuffer);
137         depthRenderbuffer = 0;
138     }
139 }
140
141 - (void) setContext:(EAGLContext*) ctx {
142     context = ctx;
143     [EAGLContext setCurrentContext:ctx];
144
145     if ( viewFramebuffer == 0 )
146     {
147         [self destroyFramebuffer];
148         [self createFramebuffer];        
149     }
150
151     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
152 }
153  
154 - (void) swapBuffers {
155     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
156     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
157 }
158
159 - (void)layoutSubviews {
160     [EAGLContext setCurrentContext:context];
161     [self destroyFramebuffer];
162     [self createFramebuffer];
163 }
164
165 @end
166
167
168 WXGLContext WXGLCreateContext( WXGLPixelFormat pixelFormat, WXGLContext shareContext )
169 {
170     WXGLContext context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
171     
172     // [[EAGLContext alloc] initWithFormat:pixelFormat shareContext: shareContext];
173     if ( !context )
174         wxFAIL_MSG("NSOpenGLContext creation failed");
175     return context ;
176 }
177
178 void WXGLDestroyContext( WXGLContext context )
179 {
180     if ( context )
181     {
182         [context release];
183     }
184 }
185
186 WXGLContext WXGLGetCurrentContext()
187 {
188     return [EAGLContext currentContext];
189 }
190
191 bool WXGLSetCurrentContext(WXGLContext context)
192 {
193     [EAGLContext setCurrentContext:context];
194     return true;
195 }
196
197 void WXGLDestroyPixelFormat( WXGLPixelFormat pixelFormat )
198 {
199 /*
200     if ( pixelFormat )
201     {
202         [pixelFormat release];
203     }
204 */
205 }
206
207
208 WXGLPixelFormat WXGLChoosePixelFormat(const int *attribList)
209 {
210 #if 0
211     NSOpenGLPixelFormatAttribute data[512];
212     const NSOpenGLPixelFormatAttribute defaultAttribs[] =
213     {
214         NSOpenGLPFADoubleBuffer,
215         NSOpenGLPFAMinimumPolicy,
216         NSOpenGLPFAColorSize,(NSOpenGLPixelFormatAttribute)8,
217         NSOpenGLPFAAlphaSize,(NSOpenGLPixelFormatAttribute)0,
218         NSOpenGLPFADepthSize,(NSOpenGLPixelFormatAttribute)8,
219         (NSOpenGLPixelFormatAttribute)nil
220     };
221
222     const NSOpenGLPixelFormatAttribute *attribs;
223     if ( !attribList )
224     {
225         attribs = defaultAttribs;
226     }
227     else
228     {
229         unsigned p = 0;
230         data[p++] = NSOpenGLPFAMinimumPolicy; // make _SIZE tags behave more like GLX
231
232         for ( unsigned arg = 0; attribList[arg] !=0 && p < WXSIZEOF(data); )
233         {
234             switch ( attribList[arg++] )
235             {
236                 case WX_GL_RGBA:
237                     //data[p++] = AGL_RGBA;
238                     break;
239
240                 case WX_GL_BUFFER_SIZE:
241                     //data[p++] = AGL_BUFFER_SIZE;
242                     //data[p++] = attribList[arg++];
243                     break;
244
245                 case WX_GL_LEVEL:
246                     //data[p++]=AGL_LEVEL;
247                     //data[p++]=attribList[arg++];
248                     break;
249
250                 case WX_GL_DOUBLEBUFFER:
251                     data[p++] = NSOpenGLPFADoubleBuffer;
252                     break;
253
254                 case WX_GL_STEREO:
255                     data[p++] = NSOpenGLPFAStereo;
256                     break;
257
258                 case WX_GL_AUX_BUFFERS:
259                     data[p++] = NSOpenGLPFAAuxBuffers;
260                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
261                     break;
262
263                 case WX_GL_MIN_RED:
264                     data[p++] = NSOpenGLPFAColorSize;
265                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
266                     break;
267
268                 case WX_GL_MIN_GREEN:
269                     //data[p++] = AGL_GREEN_SIZE;
270                     //data[p++] = attribList[arg++];
271                     break;
272
273                 case WX_GL_MIN_BLUE:
274                     //data[p++] = AGL_BLUE_SIZE;
275                     //data[p++] = attribList[arg++];
276                     break;
277
278                 case WX_GL_MIN_ALPHA:
279                     data[p++] = NSOpenGLPFAAlphaSize;
280                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
281                     break;
282
283                 case WX_GL_DEPTH_SIZE:
284                     data[p++] = NSOpenGLPFADepthSize;
285                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
286                     break;
287
288                 case WX_GL_STENCIL_SIZE:
289                     data[p++] = NSOpenGLPFAStencilSize;
290                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
291                     break;
292
293                 case WX_GL_MIN_ACCUM_RED:
294                     data[p++] = NSOpenGLPFAAccumSize;
295                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
296                     break;
297
298                 case WX_GL_MIN_ACCUM_GREEN:
299                     //data[p++] = AGL_ACCUM_GREEN_SIZE;
300                     //data[p++] = attribList[arg++];
301                     break;
302
303                 case WX_GL_MIN_ACCUM_BLUE:
304                     //data[p++] = AGL_ACCUM_BLUE_SIZE;
305                     //data[p++] = attribList[arg++];
306                     break;
307
308                 case WX_GL_MIN_ACCUM_ALPHA:
309                     //data[p++] = AGL_ACCUM_ALPHA_SIZE;
310                     //data[p++] = attribList[arg++];
311                     break;
312
313                 case WX_GL_SAMPLE_BUFFERS:
314                     if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
315                     {
316                         if ( !attribList[arg++] )
317                             break;
318
319                         return false;
320                     }
321
322                     data[p++] = NSOpenGLPFASampleBuffers;
323                     if ( (data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++]) == true )
324                     {
325                         // don't use software fallback
326                         data[p++] = NSOpenGLPFANoRecovery;
327                     }
328                     break;
329
330                 case WX_GL_SAMPLES:
331                     if ( !wxGLCanvas::IsAGLMultiSampleAvailable() )
332                     {
333                         if ( !attribList[arg++] )
334                             break;
335
336                         return false;
337                     }
338
339                     data[p++] = NSOpenGLPFASamples;
340                     data[p++] = (NSOpenGLPixelFormatAttribute) attribList[arg++];
341                     break;
342             }
343         }
344
345         data[p] = (NSOpenGLPixelFormatAttribute)nil;
346
347         attribs = data;
348     }
349
350     return [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute*) attribs];
351 #endif
352     return NULL;
353 }
354
355 bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
356 {
357     if ( !m_glContext )
358         return false;  
359
360     wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) win.GetPeer()->GetWXWidget();
361     [v setContext:m_glContext];
362     return true;
363 }
364
365 #define USE_SEPARATE_VIEW 1
366
367 bool wxGLCanvas::Create(wxWindow *parent,
368                         wxWindowID id,
369                         const wxPoint& pos,
370                         const wxSize& size,
371                         long style,
372                         const wxString& name,
373                         const int *attribList,
374                         const wxPalette& WXUNUSED(palette))
375 {
376 /*
377     m_glFormat = WXGLChoosePixelFormat(attribList);
378     if ( !m_glFormat )
379         return false;
380 */
381 #if USE_SEPARATE_VIEW
382     DontCreatePeer();
383 #endif
384
385     if ( !wxWindow::Create(parent, id, pos, size, style, name) )
386         return false;
387
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];
396             
397     SetPeer(new wxWidgetIPhoneImpl( this, v ));
398
399     MacPostControlCreate(pos, size) ;
400 #endif
401     return true;
402 }
403
404 wxGLCanvas::~wxGLCanvas()
405 {
406     if ( m_glFormat )
407         WXGLDestroyPixelFormat(m_glFormat);
408 }
409
410 bool wxGLCanvas::SwapBuffers()
411 {
412     WXGLContext context = WXGLGetCurrentContext();
413     wxCHECK_MSG(context, false, wxT("should have current context"));
414
415     wxUICustomOpenGLView* v = (wxUICustomOpenGLView*) GetPeer()->GetWXWidget();
416     [v swapBuffers];
417     return true;
418 }
419
420
421 #endif // wxUSE_GLCANVAS