src/video/uikit/SDL_uikitopenglview.m
author Sam Lantinga
Sun, 25 Nov 2012 10:03:22 -0800
changeset 6686 45014250760c
parent 6435 6172658e3ce9
child 6885 700f1b25f77f
permissions -rw-r--r--
Don't run the game loop while a messagebox is up
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_UIKIT
    24 
    25 #include <QuartzCore/QuartzCore.h>
    26 #include <OpenGLES/EAGLDrawable.h>
    27 #include "SDL_uikitopenglview.h"
    28 #include "SDL_uikitmessagebox.h"
    29 
    30 
    31 @implementation SDL_uikitopenglview
    32 
    33 @synthesize context;
    34 
    35 + (Class)layerClass
    36 {
    37     return [CAEAGLLayer class];
    38 }
    39 
    40 - (id)initWithFrame:(CGRect)frame
    41       scale:(CGFloat)scale
    42       retainBacking:(BOOL)retained
    43       rBits:(int)rBits
    44       gBits:(int)gBits
    45       bBits:(int)bBits
    46       aBits:(int)aBits
    47       depthBits:(int)depthBits
    48       stencilBits:(int)stencilBits
    49       majorVersion:(int)majorVersion
    50 {
    51     depthBufferFormat = 0;
    52 
    53     if ((self = [super initWithFrame:frame])) {
    54         const BOOL useStencilBuffer = (stencilBits != 0);
    55         const BOOL useDepthBuffer = (depthBits != 0);
    56         NSString *colorFormat = nil;
    57 
    58         if (rBits == 8 && gBits == 8 && bBits == 8) {
    59             /* if user specifically requests rbg888 or some color format higher than 16bpp */
    60             colorFormat = kEAGLColorFormatRGBA8;
    61         } else {
    62             /* default case (faster) */
    63             colorFormat = kEAGLColorFormatRGB565;
    64         }
    65 
    66         /* Get the layer */
    67         CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
    68 
    69         eaglLayer.opaque = YES;
    70         eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
    71                                         [NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil];
    72 
    73         if (majorVersion > 1) {
    74             context = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES2];
    75         } else {
    76             context = [[EAGLContext alloc] initWithAPI: kEAGLRenderingAPIOpenGLES1];
    77         }
    78         if (!context || ![EAGLContext setCurrentContext:context]) {
    79             [self release];
    80             SDL_SetError("OpenGL ES %d not supported", majorVersion);
    81             return nil;
    82         }
    83 
    84         /* Set the appropriate scale (for retina display support) */
    85         if ([self respondsToSelector:@selector(contentScaleFactor)])
    86             self.contentScaleFactor = scale;
    87 
    88         /* create the buffers */
    89         glGenFramebuffersOES(1, &viewFramebuffer);
    90         glGenRenderbuffersOES(1, &viewRenderbuffer);
    91 
    92         glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
    93         glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
    94         [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
    95         glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
    96 
    97         glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    98         glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
    99 
   100         if ((useDepthBuffer) || (useStencilBuffer)) {
   101             if (useStencilBuffer) {
   102                 /* Apparently you need to pack stencil and depth into one buffer. */
   103                 depthBufferFormat = GL_DEPTH24_STENCIL8_OES;
   104             } else if (useDepthBuffer) {
   105                 /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */
   106                 depthBufferFormat = GL_DEPTH_COMPONENT24_OES;
   107             }
   108 
   109             glGenRenderbuffersOES(1, &depthRenderbuffer);
   110             glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
   111             glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
   112             if (useDepthBuffer) {
   113                 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
   114             }
   115             if (useStencilBuffer) {
   116                 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
   117             }
   118         }
   119 
   120         if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
   121             return NO;
   122         }
   123         /* end create buffers */
   124 
   125         self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
   126         self.autoresizesSubviews = YES;
   127     }
   128     return self;
   129 }
   130 
   131 - (void)updateFrame
   132 {
   133     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
   134     glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
   135     glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0);
   136     glDeleteRenderbuffersOES(1, &viewRenderbuffer);
   137 
   138     glGenRenderbuffersOES(1, &viewRenderbuffer);
   139     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
   140     [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
   141     glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
   142 
   143     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
   144     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
   145 
   146     if (depthRenderbuffer != 0) {
   147         glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
   148         glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
   149     }
   150 }
   151 
   152 - (void)setAnimationCallback:(int)interval
   153     callback:(void (*)(void*))callback
   154     callbackParam:(void*)callbackParam
   155 {
   156     [self stopAnimation];
   157 
   158     animationInterval = interval;
   159     animationCallback = callback;
   160     animationCallbackParam = callbackParam;
   161 
   162     if (animationCallback)
   163         [self startAnimation];
   164 }
   165 
   166 - (void)startAnimation
   167 {
   168     // CADisplayLink is API new to iPhone SDK 3.1. Compiling against earlier versions will result in a warning, but can be dismissed
   169     // if the system version runtime check for CADisplayLink exists in -initWithCoder:. 
   170     
   171     displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doLoop:)];
   172     [displayLink setFrameInterval:animationInterval];
   173     [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
   174 }
   175 
   176 - (void)stopAnimation
   177 {
   178     [displayLink invalidate];
   179     displayLink = nil;
   180 }
   181 
   182 - (void)doLoop:(id)sender
   183 {
   184     // Don't run the game loop while a messagebox is up
   185     if (!UIKit_ShowingMessageBox()) {
   186         animationCallback(animationCallbackParam);
   187     }
   188 }
   189 
   190 - (void)setCurrentContext
   191 {
   192     [EAGLContext setCurrentContext:context];
   193 }
   194 
   195 
   196 - (void)swapBuffers
   197 {
   198     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
   199     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
   200 }
   201 
   202 
   203 - (void)layoutSubviews
   204 {
   205     [EAGLContext setCurrentContext:context];
   206     [self updateFrame];
   207 }
   208 
   209 - (void)destroyFramebuffer
   210 {
   211     glDeleteFramebuffersOES(1, &viewFramebuffer);
   212     viewFramebuffer = 0;
   213     glDeleteRenderbuffersOES(1, &viewRenderbuffer);
   214     viewRenderbuffer = 0;
   215 
   216     if (depthRenderbuffer) {
   217         glDeleteRenderbuffersOES(1, &depthRenderbuffer);
   218         depthRenderbuffer = 0;
   219     }
   220 }
   221 
   222 
   223 - (void)dealloc
   224 {
   225     [self destroyFramebuffer];
   226     if ([EAGLContext currentContext] == context) {
   227         [EAGLContext setCurrentContext:nil];
   228     }
   229     [context release];
   230     [super dealloc];
   231 }
   232 
   233 @end
   234 
   235 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   236 
   237 /* vi: set ts=4 sw=4 expandtab: */