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