src/video/uikit/SDL_uikitopenglview.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 14 Jul 2013 11:28:44 -0700
changeset 7776 d4a39491577f
parent 7423 dfe7ad02f008
child 7784 70b305e09b4e
permissions -rw-r--r--
Added the platform specific messagebox function to the video function list
slouken@2765
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 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
icculus@7423
    50
      shareGroup:(EAGLSharegroup*)shareGroup
slouken@2765
    51
{
icculus@5527
    52
    depthBufferFormat = 0;
icculus@5527
    53
icculus@6022
    54
    if ((self = [super initWithFrame:frame])) {
icculus@6022
    55
        const BOOL useStencilBuffer = (stencilBits != 0);
icculus@6022
    56
        const BOOL useDepthBuffer = (depthBits != 0);
icculus@6022
    57
        NSString *colorFormat = nil;
icculus@6022
    58
icculus@6022
    59
        if (rBits == 8 && gBits == 8 && bBits == 8) {
icculus@6022
    60
            /* if user specifically requests rbg888 or some color format higher than 16bpp */
icculus@6022
    61
            colorFormat = kEAGLColorFormatRGBA8;
icculus@6022
    62
        } else {
icculus@6022
    63
            /* default case (faster) */
icculus@6022
    64
            colorFormat = kEAGLColorFormatRGB565;
icculus@6021
    65
        }
kees@6001
    66
icculus@6022
    67
        /* Get the layer */
slouken@5129
    68
        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
kees@6001
    69
slouken@5129
    70
        eaglLayer.opaque = YES;
slouken@5129
    71
        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
slouken@5129
    72
                                        [NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil];
kees@6001
    73
slouken@5209
    74
        if (majorVersion > 1) {
icculus@7423
    75
            context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:shareGroup];
slouken@5209
    76
        } else {
icculus@7423
    77
            context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:shareGroup];
slouken@5209
    78
        }
slouken@5129
    79
        if (!context || ![EAGLContext setCurrentContext:context]) {
slouken@5129
    80
            [self release];
slouken@6179
    81
            SDL_SetError("OpenGL ES %d not supported", majorVersion);
slouken@5129
    82
            return nil;
slouken@5129
    83
        }
kees@6001
    84
tim@6267
    85
        /* Set the appropriate scale (for retina display support) */
slouken@6164
    86
        if ([self respondsToSelector:@selector(contentScaleFactor)])
tim@6267
    87
            self.contentScaleFactor = scale;
slouken@6085
    88
slouken@5129
    89
        /* create the buffers */
slouken@5129
    90
        glGenFramebuffersOES(1, &viewFramebuffer);
slouken@5129
    91
        glGenRenderbuffersOES(1, &viewRenderbuffer);
kees@6001
    92
slouken@5129
    93
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
slouken@5129
    94
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
slouken@5129
    95
        [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
slouken@5129
    96
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
kees@6001
    97
slouken@5129
    98
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
slouken@5129
    99
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
icculus@5527
   100
icculus@6021
   101
        if ((useDepthBuffer) || (useStencilBuffer)) {
icculus@6021
   102
            if (useStencilBuffer) {
icculus@6022
   103
                /* Apparently you need to pack stencil and depth into one buffer. */
icculus@6021
   104
                depthBufferFormat = GL_DEPTH24_STENCIL8_OES;
icculus@6022
   105
            } else if (useDepthBuffer) {
icculus@6022
   106
                /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */
icculus@6022
   107
                depthBufferFormat = GL_DEPTH_COMPONENT24_OES;
icculus@6021
   108
            }
icculus@6022
   109
slouken@5129
   110
            glGenRenderbuffersOES(1, &depthRenderbuffer);
slouken@5129
   111
            glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
slouken@5129
   112
            glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
icculus@6021
   113
            if (useDepthBuffer) {
icculus@6021
   114
                glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
icculus@6021
   115
            }
icculus@6021
   116
            if (useStencilBuffer) {
icculus@6021
   117
                glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
icculus@6021
   118
            }
slouken@5129
   119
        }
kees@6001
   120
kees@6003
   121
        if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
slouken@5129
   122
            return NO;
slouken@5129
   123
        }
slouken@5129
   124
        /* end create buffers */
slouken@5130
   125
slouken@6435
   126
        self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
slouken@6435
   127
        self.autoresizesSubviews = YES;
slouken@5129
   128
    }
slouken@5129
   129
    return self;
slouken@2765
   130
}
slouken@2765
   131
kees@6003
   132
- (void)updateFrame
kees@6003
   133
{
icculus@5527
   134
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
icculus@5527
   135
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);
icculus@5527
   136
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0);
icculus@5527
   137
    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
icculus@5527
   138
icculus@5527
   139
    glGenRenderbuffersOES(1, &viewRenderbuffer);
icculus@5527
   140
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
icculus@5527
   141
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
kees@6001
   142
    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
icculus@5527
   143
icculus@5527
   144
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
icculus@5527
   145
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
icculus@5527
   146
icculus@5527
   147
    if (depthRenderbuffer != 0) {
icculus@5527
   148
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
icculus@5527
   149
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight);
icculus@5527
   150
    }
icculus@5527
   151
}
icculus@5527
   152
slouken@6342
   153
- (void)setAnimationCallback:(int)interval
slouken@6342
   154
    callback:(void (*)(void*))callback
slouken@6342
   155
    callbackParam:(void*)callbackParam
slouken@6342
   156
{
slouken@6342
   157
    [self stopAnimation];
slouken@6342
   158
slouken@6342
   159
    animationInterval = interval;
slouken@6342
   160
    animationCallback = callback;
slouken@6342
   161
    animationCallbackParam = callbackParam;
slouken@6342
   162
slouken@6342
   163
    if (animationCallback)
slouken@6342
   164
        [self startAnimation];
slouken@6342
   165
}
slouken@6342
   166
slouken@6342
   167
- (void)startAnimation
slouken@6342
   168
{
slouken@7191
   169
    /* CADisplayLink is API new to iPhone SDK 3.1.
slouken@7191
   170
     * Compiling against earlier versions will result in a warning, but can be dismissed
slouken@7191
   171
     * if the system version runtime check for CADisplayLink exists in -initWithCoder:.
slouken@7191
   172
     */
slouken@6342
   173
    displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(doLoop:)];
slouken@6342
   174
    [displayLink setFrameInterval:animationInterval];
slouken@6342
   175
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
slouken@6342
   176
}
slouken@6342
   177
slouken@6342
   178
- (void)stopAnimation
slouken@6342
   179
{
slouken@6342
   180
    [displayLink invalidate];
slouken@6342
   181
    displayLink = nil;
slouken@6342
   182
}
slouken@6342
   183
slouken@6342
   184
- (void)doLoop:(id)sender
slouken@6342
   185
{
slouken@7191
   186
    /* Don't run the game loop while a messagebox is up */
slouken@6686
   187
    if (!UIKit_ShowingMessageBox()) {
slouken@6686
   188
        animationCallback(animationCallbackParam);
slouken@6686
   189
    }
slouken@6342
   190
}
slouken@6342
   191
kees@6003
   192
- (void)setCurrentContext
kees@6003
   193
{
slouken@5129
   194
    [EAGLContext setCurrentContext:context];
slouken@2765
   195
}
slouken@2765
   196
slouken@2765
   197
kees@6003
   198
- (void)swapBuffers
kees@6003
   199
{
slouken@5129
   200
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
slouken@5129
   201
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
slouken@2765
   202
}
slouken@2765
   203
slouken@2765
   204
kees@6003
   205
- (void)layoutSubviews
kees@6003
   206
{
slouken@5129
   207
    [EAGLContext setCurrentContext:context];
slouken@6435
   208
    [self updateFrame];
slouken@2765
   209
}
slouken@2765
   210
kees@6003
   211
- (void)destroyFramebuffer
kees@6003
   212
{
slouken@5129
   213
    glDeleteFramebuffersOES(1, &viewFramebuffer);
slouken@5129
   214
    viewFramebuffer = 0;
slouken@5129
   215
    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
slouken@5129
   216
    viewRenderbuffer = 0;
kees@6001
   217
slouken@5129
   218
    if (depthRenderbuffer) {
slouken@5129
   219
        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
slouken@5129
   220
        depthRenderbuffer = 0;
slouken@5129
   221
    }
slouken@2765
   222
}
slouken@2765
   223
slouken@2765
   224
kees@6003
   225
- (void)dealloc
kees@6003
   226
{
slouken@5129
   227
    [self destroyFramebuffer];
slouken@5129
   228
    if ([EAGLContext currentContext] == context) {
slouken@5129
   229
        [EAGLContext setCurrentContext:nil];
slouken@5129
   230
    }
kees@6001
   231
    [context release];
slouken@5129
   232
    [super dealloc];
slouken@2765
   233
}
slouken@2765
   234
slouken@2859
   235
@end
slouken@5132
   236
slouken@6044
   237
#endif /* SDL_VIDEO_DRIVER_UIKIT */
slouken@6044
   238
slouken@5132
   239
/* vi: set ts=4 sw=4 expandtab: */