// Copyright (C) 2015 Patryk Nadrowski // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in Irrlicht.h #include "CEAGLManager.h" #ifdef _IRR_COMPILE_WITH_EAGL_MANAGER_ #include "irrString.h" #include "os.h" #import #import #if defined(_IRR_COMPILE_WITH_OGLES1_) #include #include #elif defined(_IRR_COMPILE_WITH_OGLES2_) #include #include #endif namespace irr { namespace video { struct SEAGLManagerDataStorage { SEAGLManagerDataStorage() : Layer(0), Context(0) { } CAEAGLLayer* Layer; EAGLContext* Context; }; CEAGLManager::CEAGLManager() : IContextManager(), Configured(false), DataStorage(0) { #ifdef _DEBUG setDebugName("CEAGLManager"); #endif DataStorage = new SEAGLManagerDataStorage(); } CEAGLManager::~CEAGLManager() { destroyContext(); destroySurface(); terminate(); delete static_cast(DataStorage); } bool CEAGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data) { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); if (dataStorage->Layer != nil) return true; Params = params; Data = data; UIView* view = (__bridge UIView*)data.OpenGLiOS.View; if (view == nil || ![[view layer] isKindOfClass:[CAEAGLLayer class]]) { os::Printer::log("Could not get EAGL display."); return false; } dataStorage->Layer = (CAEAGLLayer*)[view layer]; return true; } void CEAGLManager::terminate() { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); [EAGLContext setCurrentContext:0]; destroySurface(); if (dataStorage->Layer != nil) dataStorage->Layer = 0; } bool CEAGLManager::generateSurface() { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); CAEAGLLayer* layer = dataStorage->Layer; if (layer == nil) return false; if (Configured) return true; NSDictionary* attribs = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, (Params.Bits > 16) ? kEAGLColorFormatRGBA8 : kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil]; [layer setOpaque:(Params.WithAlphaChannel) ? YES : NO]; [layer setDrawableProperties:attribs]; Configured = true; return true; } void CEAGLManager::destroySurface() { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); CAEAGLLayer* layer = dataStorage->Layer; if (layer == nil) return; [layer setOpaque:NO]; [layer setDrawableProperties:nil]; Configured = false; } bool CEAGLManager::generateContext() { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); if (dataStorage->Context != nil || !Configured) return false; EAGLRenderingAPI OpenGLESVersion = kEAGLRenderingAPIOpenGLES2; switch (Params.DriverType) { case EDT_OGLES1: OpenGLESVersion = kEAGLRenderingAPIOpenGLES1; break; case EDT_OGLES2: OpenGLESVersion = kEAGLRenderingAPIOpenGLES2; break; default: break; } dataStorage->Context = [[EAGLContext alloc] initWithAPI:OpenGLESVersion]; if (dataStorage->Context == nil) { os::Printer::log("Could not create EAGL context.", ELL_ERROR); return false; } Data.OpenGLiOS.Context = (__bridge void*)dataStorage->Context; os::Printer::log("EAGL context created with OpenGLESVersion: ", core::stringc(static_cast(OpenGLESVersion)), ELL_DEBUG); return true; } void CEAGLManager::destroyContext() { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); [dataStorage->Context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:nil]; if (FrameBuffer.BufferID != 0) { glDeleteFramebuffersOES(1, &FrameBuffer.BufferID); FrameBuffer.BufferID = 0; } if (FrameBuffer.ColorBuffer != 0) { glDeleteRenderbuffersOES(1, &FrameBuffer.ColorBuffer); FrameBuffer.ColorBuffer = 0; } if (FrameBuffer.DepthBuffer != 0) { glDeleteRenderbuffersOES(1, &FrameBuffer.DepthBuffer); FrameBuffer.DepthBuffer = 0; } [EAGLContext setCurrentContext:0]; if (dataStorage->Context != nil) dataStorage->Context = 0; Data.OpenGLiOS.Context = 0; } bool CEAGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); EAGLContext* context = dataStorage->Context; bool status = false; if (context != nil) { status = ([EAGLContext currentContext] == context || [EAGLContext setCurrentContext:context]); } if (status) { if (FrameBuffer.ColorBuffer == 0) { glGenRenderbuffersOES(1, &FrameBuffer.ColorBuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer); [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:dataStorage->Layer]; } if (FrameBuffer.DepthBuffer == 0) { GLenum depth = (Params.ZBufferBits >= 24) ? GL_DEPTH_COMPONENT24_OES : GL_DEPTH_COMPONENT16_OES; glGenRenderbuffersOES(1, &FrameBuffer.DepthBuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.DepthBuffer); glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depth, Params.WindowSize.Width, Params.WindowSize.Height); } if (FrameBuffer.BufferID == 0) { glGenFramebuffersOES(1, &FrameBuffer.BufferID); glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer.BufferID); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, FrameBuffer.DepthBuffer); } glBindFramebufferOES(GL_FRAMEBUFFER_OES, FrameBuffer.BufferID); } else { os::Printer::log("Could not make EGL context current."); } return status; } const SExposedVideoData& CEAGLManager::getContext() const { return Data; } bool CEAGLManager::swapBuffers() { SEAGLManagerDataStorage* dataStorage = static_cast(DataStorage); EAGLContext* context = dataStorage->Context; bool status = false; if (context != nil && context == [EAGLContext currentContext]) { glBindRenderbufferOES(GL_RENDERBUFFER_OES, FrameBuffer.ColorBuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; status = true; } return status; } } } #endif