src/video/uikit/SDL_uikitopenglview.m
author Alex Szpakowski <slime73@gmail.com>
Wed, 23 Jul 2014 21:55:42 -0300
branchiOS-improvements
changeset 9502 933ed557b7c1
parent 9501 574db299498f
child 9510 e19faa3b5d88
permissions -rw-r--r--
Fixed SDL_SetWindowFullscreen on iOS for the last time, hopefully.

Fixed iOS version checking code.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.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 #include "SDL_uikitvideo.h"
    30 
    31 
    32 @implementation SDL_uikitopenglview {
    33 
    34     /* OpenGL names for the renderbuffer and framebuffers used to render to this view */
    35     GLuint viewRenderbuffer, viewFramebuffer;
    36 
    37     /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */
    38     GLuint depthRenderbuffer;
    39 
    40     /* format of depthRenderbuffer */
    41     GLenum depthBufferFormat;
    42 
    43     id displayLink;
    44     int animationInterval;
    45     void (*animationCallback)(void*);
    46     void *animationCallbackParam;
    47 
    48 }
    49 
    50 @synthesize context;
    51 
    52 @synthesize backingWidth;
    53 @synthesize backingHeight;
    54 
    55 + (Class)layerClass
    56 {
    57     return [CAEAGLLayer class];
    58 }
    59 
    60 - (id)initWithFrame:(CGRect)frame
    61               scale:(CGFloat)scale
    62       retainBacking:(BOOL)retained
    63               rBits:(int)rBits
    64               gBits:(int)gBits
    65               bBits:(int)bBits
    66               aBits:(int)aBits
    67           depthBits:(int)depthBits
    68         stencilBits:(int)stencilBits
    69                sRGB:(BOOL)sRGB
    70        majorVersion:(int)majorVersion
    71          shareGroup:(EAGLSharegroup*)shareGroup
    72 {
    73     if ((self = [super initWithFrame:frame])) {
    74         const BOOL useStencilBuffer = (stencilBits != 0);
    75         const BOOL useDepthBuffer = (depthBits != 0);
    76         NSString *colorFormat = nil;
    77 
    78         self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    79         self.autoresizesSubviews = YES;
    80 
    81         /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES
    82            versions, and this allows us to handle future OpenGL ES versions.
    83          */
    84         EAGLRenderingAPI api = majorVersion;
    85 
    86         context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup];
    87         if (!context || ![EAGLContext setCurrentContext:context]) {
    88             [self release];
    89             SDL_SetError("OpenGL ES %d not supported", majorVersion);
    90             return nil;
    91         }
    92 
    93         if (sRGB && UIKit_IsSystemVersionAtLeast(@"7.0")) {
    94              /* sRGB EAGL drawable support was added in iOS 7 */
    95             colorFormat = kEAGLColorFormatSRGBA8;
    96         } else if (rBits >= 8 && gBits >= 8 && bBits >= 8) {
    97             /* if user specifically requests rbg888 or some color format higher than 16bpp */
    98             colorFormat = kEAGLColorFormatRGBA8;
    99         } else {
   100             /* default case (faster) */
   101             colorFormat = kEAGLColorFormatRGB565;
   102         }
   103 
   104         /* Get the layer */
   105         CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
   106 
   107         eaglLayer.opaque = YES;
   108         eaglLayer.drawableProperties = @{
   109             kEAGLDrawablePropertyRetainedBacking: @(retained),
   110             kEAGLDrawablePropertyColorFormat: colorFormat
   111         };
   112 
   113         /* Set the appropriate scale (for retina display support) */
   114         self.contentScaleFactor = scale;
   115 
   116         /* Create the color Renderbuffer Object */
   117         glGenRenderbuffersOES(1, &viewRenderbuffer);
   118         glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
   119 
   120         if (![context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:eaglLayer]) {
   121             [self release];
   122             SDL_SetError("Failed creating OpenGL ES drawable");
   123             return nil;
   124         }
   125 
   126         /* Create the Framebuffer Object */
   127         glGenFramebuffersOES(1, &viewFramebuffer);
   128         glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
   129 
   130         /* attach the color renderbuffer to the FBO */
   131         glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
   132 
   133         glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
   134         glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
   135 
   136         if ((useDepthBuffer) || (useStencilBuffer)) {
   137             if (useStencilBuffer) {
   138                 /* Apparently you need to pack stencil and depth into one buffer. */
   139                 depthBufferFormat = GL_DEPTH24_STENCIL8_OES;
   140             } else if (useDepthBuffer) {
   141                 /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */
   142                 depthBufferFormat = GL_DEPTH_COMPONENT24_OES;
   143             }
   144 
   145             glGenRenderbuffersOES(1, &depthRenderbuffer);
   146             glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
   147             glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
   148             if (useDepthBuffer) {
   149                 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
   150             }
   151             if (useStencilBuffer) {
   152                 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
   153             }
   154         }
   155 
   156         if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
   157             [self release];
   158             SDL_SetError("Failed creating OpenGL ES framebuffer");
   159             return nil;
   160         }
   161 
   162         glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
   163     }
   164 
   165     return self;
   166 }
   167 
   168 - (void)updateFrame
   169 {
   170     glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
   171     glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
   172     glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0);
   173     glDeleteRenderbuffersOES(1, &viewRenderbuffer);
   174 
   175     glGenRenderbuffersOES(1, &viewRenderbuffer);
   176     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
   177     [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
   178     glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
   179 
   180     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
   181     glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
   182 
   183     if (depthRenderbuffer != 0) {
   184         glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
   185         glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
   186     }
   187 
   188     glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
   189 }
   190 
   191 - (void)setAnimationCallback:(int)interval
   192     callback:(void (*)(void*))callback
   193     callbackParam:(void*)callbackParam
   194 {
   195     [self stopAnimation];
   196 
   197     animationInterval = interval;
   198     animationCallback = callback;
   199     animationCallbackParam = callbackParam;
   200 
   201     if (animationCallback) {
   202         [self startAnimation];
   203     }
   204 }
   205 
   206 - (void)startAnimation
   207 {
   208     displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)];
   209     [displayLink setFrameInterval:animationInterval];
   210     [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
   211 }
   212 
   213 - (void)stopAnimation
   214 {
   215     [displayLink invalidate];
   216     displayLink = nil;
   217 }
   218 
   219 - (void)doLoop:(CADisplayLink*)sender
   220 {
   221     /* Don't run the game loop while a messagebox is up */
   222     if (!UIKit_ShowingMessageBox()) {
   223         animationCallback(animationCallbackParam);
   224     }
   225 }
   226 
   227 - (void)setCurrentContext
   228 {
   229     [EAGLContext setCurrentContext:context];
   230 }
   231 
   232 
   233 - (void)swapBuffers
   234 {
   235     /* viewRenderbuffer should always be bound here. Code that binds something
   236         else is responsible for rebinding viewRenderbuffer, to reduce
   237         duplicate state changes. */
   238     [context presentRenderbuffer:GL_RENDERBUFFER_OES];
   239 }
   240 
   241 
   242 - (void)layoutSubviews
   243 {
   244     [super layoutSubviews];
   245 
   246     [EAGLContext setCurrentContext:context];
   247     [self updateFrame];
   248 }
   249 
   250 - (void)destroyFramebuffer
   251 {
   252     if (viewFramebuffer != 0) {
   253         glDeleteFramebuffersOES(1, &viewFramebuffer);
   254         viewFramebuffer = 0;
   255     }
   256 
   257     if (viewRenderbuffer != 0) {
   258         glDeleteRenderbuffersOES(1, &viewRenderbuffer);
   259         viewRenderbuffer = 0;
   260     }
   261 
   262     if (depthRenderbuffer != 0) {
   263         glDeleteRenderbuffersOES(1, &depthRenderbuffer);
   264         depthRenderbuffer = 0;
   265     }
   266 }
   267 
   268 
   269 - (void)dealloc
   270 {
   271     [self destroyFramebuffer];
   272     if ([EAGLContext currentContext] == context) {
   273         [EAGLContext setCurrentContext:nil];
   274     }
   275     [context release];
   276     [super dealloc];
   277 }
   278 
   279 @end
   280 
   281 #endif /* SDL_VIDEO_DRIVER_UIKIT */
   282 
   283 /* vi: set ts=4 sw=4 expandtab: */