SDL_uikitopenglview.m (8269B)
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 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 shareGroup:(EAGLSharegroup*)shareGroup 51{ 52 depthBufferFormat = 0; 53 54 if ((self = [super initWithFrame:frame])) { 55 const BOOL useStencilBuffer = (stencilBits != 0); 56 const BOOL useDepthBuffer = (depthBits != 0); 57 NSString *colorFormat = nil; 58 59 /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES 60 versions, and this allows us to handle future OpenGL ES versions. 61 */ 62 EAGLRenderingAPI api = majorVersion; 63 64 if (rBits == 8 && gBits == 8 && bBits == 8) { 65 /* if user specifically requests rbg888 or some color format higher than 16bpp */ 66 colorFormat = kEAGLColorFormatRGBA8; 67 } else { 68 /* default case (faster) */ 69 colorFormat = kEAGLColorFormatRGB565; 70 } 71 72 /* Get the layer */ 73 CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; 74 75 eaglLayer.opaque = YES; 76 eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: 77 [NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil]; 78 79 context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup]; 80 if (!context || ![EAGLContext setCurrentContext:context]) { 81 [self release]; 82 SDL_SetError("OpenGL ES %d not supported", majorVersion); 83 return nil; 84 } 85 86 /* Set the appropriate scale (for retina display support) */ 87 self.contentScaleFactor = scale; 88 89 /* create the buffers */ 90 glGenFramebuffersOES(1, &viewFramebuffer); 91 glGenRenderbuffersOES(1, &viewRenderbuffer); 92 93 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); 94 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); 95 [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; 96 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); 97 98 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); 99 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); 100 101 if ((useDepthBuffer) || (useStencilBuffer)) { 102 if (useStencilBuffer) { 103 /* Apparently you need to pack stencil and depth into one buffer. */ 104 depthBufferFormat = GL_DEPTH24_STENCIL8_OES; 105 } else if (useDepthBuffer) { 106 /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */ 107 depthBufferFormat = GL_DEPTH_COMPONENT24_OES; 108 } 109 110 glGenRenderbuffersOES(1, &depthRenderbuffer); 111 glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); 112 glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight); 113 if (useDepthBuffer) { 114 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); 115 } 116 if (useStencilBuffer) { 117 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); 118 } 119 } 120 121 if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { 122 return NO; 123 } 124 125 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); 126 /* end create buffers */ 127 128 self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); 129 self.autoresizesSubviews = YES; 130 } 131 return self; 132} 133 134- (void)updateFrame 135{ 136 glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); 137 glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0); 138 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0); 139 glDeleteRenderbuffersOES(1, &viewRenderbuffer); 140 141 glGenRenderbuffersOES(1, &viewRenderbuffer); 142 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); 143 [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; 144 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); 145 146 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); 147 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); 148 149 if (depthRenderbuffer != 0) { 150 glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); 151 glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight); 152 } 153 154 glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); 155} 156 157- (void)setAnimationCallback:(int)interval 158 callback:(void (*)(void*))callback 159 callbackParam:(void*)callbackParam 160{ 161 [self stopAnimation]; 162 163 animationInterval = interval; 164 animationCallback = callback; 165 animationCallbackParam = callbackParam; 166 167 if (animationCallback) 168 [self startAnimation]; 169} 170 171- (void)startAnimation 172{ 173 displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)]; 174 [displayLink setFrameInterval:animationInterval]; 175 [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 176} 177 178- (void)stopAnimation 179{ 180 [displayLink invalidate]; 181 displayLink = nil; 182} 183 184- (void)doLoop:(CADisplayLink*)sender 185{ 186 /* Don't run the game loop while a messagebox is up */ 187 if (!UIKit_ShowingMessageBox()) { 188 animationCallback(animationCallbackParam); 189 } 190} 191 192- (void)setCurrentContext 193{ 194 [EAGLContext setCurrentContext:context]; 195} 196 197 198- (void)swapBuffers 199{ 200 /* viewRenderbuffer should always be bound here. Code that binds something 201 else is responsible for rebinding viewRenderbuffer, to reduce 202 duplicate state changes. */ 203 [context presentRenderbuffer:GL_RENDERBUFFER_OES]; 204} 205 206 207- (void)layoutSubviews 208{ 209 [EAGLContext setCurrentContext:context]; 210 [self updateFrame]; 211} 212 213- (void)destroyFramebuffer 214{ 215 glDeleteFramebuffersOES(1, &viewFramebuffer); 216 viewFramebuffer = 0; 217 glDeleteRenderbuffersOES(1, &viewRenderbuffer); 218 viewRenderbuffer = 0; 219 220 if (depthRenderbuffer) { 221 glDeleteRenderbuffersOES(1, &depthRenderbuffer); 222 depthRenderbuffer = 0; 223 } 224} 225 226 227- (void)dealloc 228{ 229 [self destroyFramebuffer]; 230 if ([EAGLContext currentContext] == context) { 231 [EAGLContext setCurrentContext:nil]; 232 } 233 [context release]; 234 [super dealloc]; 235} 236 237@end 238 239#endif /* SDL_VIDEO_DRIVER_UIKIT */ 240 241/* vi: set ts=4 sw=4 expandtab: */