From 3bb88c77bf9b7696029802a449205d7626f6285e Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Fri, 28 Apr 2017 00:22:35 -0700 Subject: [PATCH] Cleanup context handling and IOS API --- Kraken.xcodeproj/project.pbxproj | 18 +++ kraken/KRCamera.cpp | 5 +- kraken/KRCamera.h | 2 +- kraken/KRContext_ios.mm | 19 +-- kraken/KREngine.h | 4 +- kraken/KREngine.mm | 11 +- kraken/KRScene.cpp | 4 +- kraken/KRScene.h | 2 +- kraken_ios/KrakenView.h | 25 ++++ kraken_ios/KrakenView.mm | 201 +++++++++++++++++++++++++++++++ 10 files changed, 267 insertions(+), 24 deletions(-) create mode 100644 kraken_ios/KrakenView.h create mode 100644 kraken_ios/KrakenView.mm diff --git a/Kraken.xcodeproj/project.pbxproj b/Kraken.xcodeproj/project.pbxproj index 9fcf638..7fe3965 100755 --- a/Kraken.xcodeproj/project.pbxproj +++ b/Kraken.xcodeproj/project.pbxproj @@ -373,6 +373,10 @@ E45134B71746A4A300443C21 /* KRBehavior.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E45134B41746A4A300443C21 /* KRBehavior.cpp */; }; E45134B91746A4A300443C21 /* KRBehavior.h in Headers */ = {isa = PBXBuildFile; fileRef = E45134B51746A4A300443C21 /* KRBehavior.h */; settings = {ATTRIBUTES = (Public, ); }; }; E459040416C30CC5002B00A0 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E459040316C30CC5002B00A0 /* AudioUnit.framework */; }; + E45C3C351EB2E5710053A9D2 /* KrakenView.h in Headers */ = {isa = PBXBuildFile; fileRef = E45C3C331EB2E5710053A9D2 /* KrakenView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E45C3C361EB2E5710053A9D2 /* KrakenView.mm in Sources */ = {isa = PBXBuildFile; fileRef = E45C3C341EB2E5710053A9D2 /* KrakenView.mm */; }; + E45C3C391EB2F4A90053A9D2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E45C3C381EB2F4A90053A9D2 /* UIKit.framework */; }; + E45C3C3C1EB2F52E0053A9D2 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E45C3C3B1EB2F52E0053A9D2 /* QuartzCore.framework */; }; E45E03B118790DD1006DA23F /* PVRTArray.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A418790DD1006DA23F /* PVRTArray.h */; settings = {ATTRIBUTES = (Public, ); }; }; E45E03B218790DD1006DA23F /* PVRTDecompress.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A518790DD1006DA23F /* PVRTDecompress.h */; settings = {ATTRIBUTES = (Public, ); }; }; E45E03B318790DD1006DA23F /* PVRTError.h in Headers */ = {isa = PBXBuildFile; fileRef = E45E03A618790DD1006DA23F /* PVRTError.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -702,6 +706,10 @@ E45134B41746A4A300443C21 /* KRBehavior.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KRBehavior.cpp; sourceTree = ""; }; E45134B51746A4A300443C21 /* KRBehavior.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KRBehavior.h; sourceTree = ""; }; E459040316C30CC5002B00A0 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/AudioUnit.framework; sourceTree = DEVELOPER_DIR; }; + E45C3C331EB2E5710053A9D2 /* KrakenView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KrakenView.h; sourceTree = ""; }; + E45C3C341EB2E5710053A9D2 /* KrakenView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KrakenView.mm; sourceTree = ""; }; + E45C3C381EB2F4A90053A9D2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + E45C3C3B1EB2F52E0053A9D2 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; E45E03A418790DD1006DA23F /* PVRTArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTArray.h; sourceTree = ""; }; E45E03A518790DD1006DA23F /* PVRTDecompress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTDecompress.h; sourceTree = ""; }; E45E03A618790DD1006DA23F /* PVRTError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRTError.h; sourceTree = ""; }; @@ -935,6 +943,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E45C3C3C1EB2F52E0053A9D2 /* QuartzCore.framework in Frameworks */, + E45C3C391EB2F4A90053A9D2 /* UIKit.framework in Frameworks */, E4159B4319C575EB00622D1E /* Foundation.framework in Frameworks */, E4159B4219C575E500622D1E /* OpenGLES.framework in Frameworks */, E4159B4119C575DF00622D1E /* Accelerate.framework in Frameworks */, @@ -1586,6 +1596,8 @@ E48C527E19C570C50062E439 /* kraken.h */, E48C527D19C570C50062E439 /* Info.plist */, E491016813C99B9E0098455B /* Kraken-Prefix.pch */, + E45C3C331EB2E5710053A9D2 /* KrakenView.h */, + E45C3C341EB2E5710053A9D2 /* KrakenView.mm */, E4C8E50D16B9B5F80031DDCB /* Frameworks */, ); path = kraken_ios; @@ -1594,6 +1606,8 @@ E4C8E50D16B9B5F80031DDCB /* Frameworks */ = { isa = PBXGroup; children = ( + E45C3C3B1EB2F52E0053A9D2 /* QuartzCore.framework */, + E45C3C381EB2F4A90053A9D2 /* UIKit.framework */, E4F027F91698116000D4427D /* AudioToolbox.framework */, E41B6BA716BE436100B510EB /* CoreAudio.framework */, E491016413C99B9E0098455B /* Foundation.framework */, @@ -1767,6 +1781,7 @@ E4159B8A19C5760900622D1E /* KRRenderSettings.h in Headers */, E4159B8B19C5760900622D1E /* KRStockGeometry.h in Headers */, E4159B8C19C5760900622D1E /* KRStreamer.h in Headers */, + E45C3C351EB2E5710053A9D2 /* KrakenView.h in Headers */, E4159B8D19C5760900622D1E /* KRViewport.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2319,6 +2334,7 @@ E4159BC919C5762F00622D1E /* KRTriangle3.cpp in Sources */, E4159BCA19C5762F00622D1E /* KRResource.cpp in Sources */, E4159BCB19C5762F00622D1E /* KRResource+obj.cpp in Sources */, + E45C3C361EB2E5710053A9D2 /* KrakenView.mm in Sources */, E4159BCC19C5762F00622D1E /* KRBehavior.cpp in Sources */, E4159BCD19C5762F00622D1E /* KRContext.cpp in Sources */, E4159BCE19C5762F00622D1E /* KRContextObject.cpp in Sources */, @@ -2664,6 +2680,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -2703,6 +2720,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; diff --git a/kraken/KRCamera.cpp b/kraken/KRCamera.cpp index 26c0f91..e9a4f06 100755 --- a/kraken/KRCamera.cpp +++ b/kraken/KRCamera.cpp @@ -95,7 +95,7 @@ const std::string KRCamera::getSkyBox() const return m_skyBox; } -void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint renderBufferHeight) +void KRCamera::renderFrame(GLint defaultFBO, GLint renderBufferWidth, GLint renderBufferHeight) { // ----====---- Record timing information for measuring FPS ----====---- uint64_t current_time = m_pContext->getAbsoluteTimeMilliseconds(); @@ -104,9 +104,6 @@ void KRCamera::renderFrame(float deltaTime, GLint renderBufferWidth, GLint rende if(m_frame_times_filled < KRAKEN_FPS_AVERAGE_FRAME_COUNT) m_frame_times_filled++; } m_last_frame_start = current_time; - - GLint defaultFBO = -1; - GLDEBUG(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO)); createBuffers(renderBufferWidth, renderBufferHeight); diff --git a/kraken/KRCamera.h b/kraken/KRCamera.h index 60dc81a..7a0060a 100755 --- a/kraken/KRCamera.h +++ b/kraken/KRCamera.h @@ -55,7 +55,7 @@ public: KRCamera(KRScene &scene, std::string name); virtual ~KRCamera(); - void renderFrame(float deltaTime, GLint renderBufferWidth, GLint renderBufferHeight); + void renderFrame(GLint defaultFBO, GLint renderBufferWidth, GLint renderBufferHeight); KRRenderSettings settings; diff --git a/kraken/KRContext_ios.mm b/kraken/KRContext_ios.mm index 7a58a0a..ba311b7 100755 --- a/kraken/KRContext_ios.mm +++ b/kraken/KRContext_ios.mm @@ -15,26 +15,29 @@ EAGLContext *gRenderContext = nil; void KRContext::destroyDeviceContexts() { - [gStreamerContext release]; - [gRenderContext release]; } void KRContext::createDeviceContexts() { - gRenderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - gStreamerContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup: gStreamerContext.sharegroup]; - - // FIXME: need to add code check for iOS 7 and also this appears to cause crashing - - //gTextureStreamerContext.multiThreaded = TRUE; + if(!gRenderContext) { + gRenderContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + gStreamerContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup: gRenderContext.sharegroup]; + + // FIXME: need to add code check for iOS 7 and also this appears to cause crashing + + //gTextureStreamerContext.multiThreaded = TRUE; + } } void KRContext::activateStreamerContext() { + createDeviceContexts(); [EAGLContext setCurrentContext: gStreamerContext]; } void KRContext::activateRenderContext() { + createDeviceContexts(); [EAGLContext setCurrentContext: gRenderContext]; } + diff --git a/kraken/KREngine.h b/kraken/KREngine.h index 001d40b..97c6a3a 100755 --- a/kraken/KREngine.h +++ b/kraken/KREngine.h @@ -72,8 +72,8 @@ namespace kraken { -(void)setParameterValueWithName: (NSString *)name Value: (float)v; -(int)getParameterIndexWithName: (NSString *)name; -- (void)renderScene: (KRScene *)pScene WithDeltaTime: (float)deltaTime AndWidth: (int)width AndHeight: (int)height; -- (void)renderScene: (KRScene *)pScene WithDeltaTime: (float)deltaTime; +- (void)renderScene: (KRScene *)pScene WithDeltaTime: (float)deltaTime AndWidth: (int)width AndHeight: (int)height AndDefaultFBO: (GLint)defaultFBO; +//- (void)renderScene: (KRScene *)pScene WithDeltaTime: (float)deltaTime; - (void)setNearZ: (float)dNearZ; - (void)setFarZ: (float)dFarZ; diff --git a/kraken/KREngine.mm b/kraken/KREngine.mm index 4e3ff98..c0523a9 100755 --- a/kraken/KREngine.mm +++ b/kraken/KREngine.mm @@ -193,15 +193,16 @@ void kraken::set_debug_text(const std::string &print_text) return self; } -- (void)renderScene: (KRScene *)pScene WithDeltaTime: (float)deltaTime AndWidth: (int)width AndHeight: (int)height +- (void)renderScene: (KRScene *)pScene WithDeltaTime: (float)deltaTime AndWidth: (int)width AndHeight: (int)height AndDefaultFBO: (GLint)defaultFBO { KRCamera *camera = pScene->find("default_camera"); if(camera) { camera->settings = _settings; } - pScene->renderFrame(deltaTime, width, height); + pScene->renderFrame(defaultFBO, deltaTime, width, height); } +/* - (void)renderScene: (KRScene *)pScene WithDeltaTime: (float)deltaTime { GLint renderBufferWidth = 0, renderBufferHeight = 0; @@ -209,6 +210,7 @@ void kraken::set_debug_text(const std::string &print_text) GLDEBUG(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &renderBufferHeight)); [self renderScene:pScene WithDeltaTime:deltaTime AndWidth:renderBufferWidth AndHeight:renderBufferHeight]; } +*/ - (BOOL)loadShaders { @@ -250,11 +252,10 @@ void kraken::set_debug_text(const std::string &print_text) - (void)dealloc { - [_parameter_names release]; _parameter_names = nil; + _parameter_names = nil; if(_context) { delete _context; _context = NULL; } - [super dealloc]; } -(int)getParameterCount @@ -721,9 +722,7 @@ void kraken::set_debug_text(const std::string &print_text) - (void)setDebug_text:(NSString *)value { - [_debug_text release]; _debug_text = value; - [_debug_text retain]; _settings.m_debug_text = value.UTF8String; } diff --git a/kraken/KRScene.cpp b/kraken/KRScene.cpp index 911986f..e825b69 100755 --- a/kraken/KRScene.cpp +++ b/kraken/KRScene.cpp @@ -57,7 +57,7 @@ KRScene::~KRScene() { m_pRootNode = NULL; } -void KRScene::renderFrame(float deltaTime, int width, int height) { +void KRScene::renderFrame(GLint defaultFBO, float deltaTime, int width, int height) { getContext().startFrame(deltaTime); KRCamera *camera = find("default_camera"); if(camera == NULL) { @@ -73,7 +73,7 @@ void KRScene::renderFrame(float deltaTime, int width, int height) { getContext().getAudioManager()->setReverbMaxLength(camera->settings.siren_reverb_max_length); getContext().getTextureManager()->setMaxAnisotropy(camera->settings.max_anisotropy); - camera->renderFrame(deltaTime, width, height); + camera->renderFrame(defaultFBO, width, height); getContext().endFrame(deltaTime); physicsUpdate(deltaTime); } diff --git a/kraken/KRScene.h b/kraken/KRScene.h index fd747ef..1ddb757 100755 --- a/kraken/KRScene.h +++ b/kraken/KRScene.h @@ -70,7 +70,7 @@ public: bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo, unsigned int layer_mask); bool sphereCast(const KRVector3 &v0, const KRVector3 &v1, float radius, KRHitInfo &hitinfo, unsigned int layer_mask); - void renderFrame(float deltaTime, int width, int height); + void renderFrame(GLint defaultFBO, float deltaTime, int width, int height); void render(KRCamera *pCamera, unordered_map &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, bool new_frame); void render(KROctreeNode *pOctreeNode, unordered_map &visibleBounds, KRCamera *pCamera, std::vector &point_lights, std::vector &directional_lights, std::vector&spot_lights, const KRViewport &viewport, KRNode::RenderPass renderPass, std::vector &remainingOctrees, std::vector &remainingOctreesTestResults, std::vector &remainingOctreesTestResultsOnly, bool bOcclusionResultsPass, bool bOcclusionTestResultsOnly); diff --git a/kraken_ios/KrakenView.h b/kraken_ios/KrakenView.h new file mode 100644 index 0000000..8493533 --- /dev/null +++ b/kraken_ios/KrakenView.h @@ -0,0 +1,25 @@ +// +// KrakenView.h +// Kraken +// +// Created by Kearwood Gilbert on 2017-04-27. +// Copyright © 2017 Kearwood Software. All rights reserved. +// +class KRContext; +class KRScene; + +@protocol KrakenViewDelegate +@optional +- (void)preRender:(KRContext *)context withDeltaTime: (CFTimeInterval)deltaTime; +- (void)postRender:(KRContext *)context withDeltaTime: (CFTimeInterval)deltaTime; +@end + +@interface KrakenView : UIView + +@property (nonatomic, weak) IBOutlet id delegate; +@property (nonatomic, assign) KRScene *scene; + +- (void)startAnimation; +- (void)stopAnimation; + +@end diff --git a/kraken_ios/KrakenView.mm b/kraken_ios/KrakenView.mm new file mode 100644 index 0000000..8c21327 --- /dev/null +++ b/kraken_ios/KrakenView.mm @@ -0,0 +1,201 @@ +// +// KrakenView.m +// Kraken +// +// Created by Kearwood Gilbert on 2017-04-27. +// Copyright © 2017 Kearwood Software. All rights reserved. +// + +#import +#import +#import + +#import "KrakenView.h" +#import "KREngine-common.h" +#import "KREngine.h" + +@interface KrakenView() { + GLint framebufferWidth; + GLint framebufferHeight; + GLuint defaultFramebuffer; + GLuint colorRenderbuffer; + GLuint depthRenderbuffer; + + CFTimeInterval lastTimestamp; + + struct { + unsigned int preRender:1; + unsigned int postRender:1; + } delegateRespondsTo; +} + +@property (nonatomic, unsafe_unretained) CADisplayLink *__unsafe_unretained displayLink; +@property (nonatomic, strong) EAGLContext *context; + +@end + +@implementation KrakenView + + ++ (Class)layerClass +{ + return [CAEAGLLayer class]; +} + +- (id)initWithCoder:(NSCoder*)coder +{ + self = [super initWithCoder:coder]; + if (self) { + lastTimestamp = 0.0; + delegateRespondsTo.preRender = 0; + delegateRespondsTo.postRender = 0; + [self startAnimation]; + } + + return self; +} + +- (void)dealloc +{ + [self stopAnimation]; +} + +- (void)setDelegate:(id )aDelegate { + if (_delegate != aDelegate) { + _delegate = aDelegate; + + delegateRespondsTo.preRender = [_delegate respondsToSelector:@selector(preRender:withDeltaTime:)]; + delegateRespondsTo.postRender = [_delegate respondsToSelector:@selector(postRender:withDeltaTime:)]; + } +} + +- (void)startAnimation +{ + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.contentsScale = [[UIScreen mainScreen] scale]; + eaglLayer.opaque = TRUE; + eaglLayer.drawableProperties = @{ + kEAGLDrawablePropertyRetainedBacking: [NSNumber numberWithBool:FALSE], + kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8 + }; + KRContext::activateRenderContext(); + + //EAGLContext *aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + EAGLContext *aContext = [EAGLContext currentContext]; + if (!aContext) { + NSLog(@"Failed to create ES context"); + } else if (![EAGLContext setCurrentContext:aContext]) { + NSLog(@"Failed to set ES context current"); + } + + self.context = aContext; + + + + [self createFrameBuffer]; + + CADisplayLink *aDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawFrame)]; + [aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + self.displayLink = aDisplayLink; +} + +- (void)stopAnimation +{ + [self.displayLink invalidate]; + self.displayLink = nil; + + if (self.context) { + [EAGLContext setCurrentContext:self.context]; + + if (defaultFramebuffer) { + GLDEBUG(glDeleteFramebuffers(1, &defaultFramebuffer)); + defaultFramebuffer = 0; + } + + if (colorRenderbuffer) { + GLDEBUG(glDeleteRenderbuffers(1, &colorRenderbuffer)); + colorRenderbuffer = 0; + } + + if (depthRenderbuffer) { + GLDEBUG(glDeleteRenderbuffers(1, &depthRenderbuffer)); + depthRenderbuffer = 0; + } + + [EAGLContext setCurrentContext:nil]; + + self.context = nil; + } +} + +- (void)drawFrame +{ + CFTimeInterval timeStamp = self.displayLink.timestamp; + CFTimeInterval deltaTime; + if (lastTimestamp == 0.0) { + deltaTime = 0.0; + } else { + deltaTime = timeStamp - lastTimestamp; + } + lastTimestamp = timeStamp; + + KRContext *context = KREngine.sharedInstance.context; + + if (self.delegate && delegateRespondsTo.preRender) { + [self.delegate preRender:context withDeltaTime:deltaTime]; + } + + // ---- Render the Buffer ---- + [EAGLContext setCurrentContext:self.context]; + if (self.scene) { + GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer)); + [[KREngine sharedInstance] renderScene: self.scene WithDeltaTime: deltaTime AndWidth: framebufferWidth AndHeight: framebufferHeight AndDefaultFBO: defaultFramebuffer]; + } else { + GLDEBUG(glClearColor(0.0f, 0.0f, 1.0f, 1.0f)); + GLDEBUG(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + } + + // ---- Present the Buffer ---- + +#if GL_EXT_discard_framebuffer + GLenum attachments[2] = {GL_DEPTH_ATTACHMENT}; + GLDEBUG(glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments)); +#endif + + GLDEBUG(glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer)); + BOOL success = [self.context presentRenderbuffer:GL_RENDERBUFFER]; + + if (self.delegate && delegateRespondsTo.postRender) { + [self.delegate postRender:context withDeltaTime:deltaTime]; + } +} + +- (void)createFrameBuffer +{ + // Create default framebuffer object. + GLDEBUG(glGenFramebuffers(1, &defaultFramebuffer)); + GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer)); + + // Create color render buffer and allocate backing store. + GLDEBUG(glGenRenderbuffers(1, &colorRenderbuffer)); + GLDEBUG(glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer)); + [self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer]; + GLDEBUG(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth)); + GLDEBUG(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight)); + + // Attach color render buffer + GLDEBUG(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer)); + + // Create depth render buffer and allocate backing store. + GLDEBUG(glGenRenderbuffers(1, &depthRenderbuffer)); + GLDEBUG(glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer)); + GLDEBUG(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight)); + + // Attach depth render buffer + GLDEBUG(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer)); +} + +@end + +