// Copyright (C) 2014 Patryk Nadrowski // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in Irrlicht.h #include "CNSOGLManager.h" #ifdef _IRR_COMPILE_WITH_NSOGL_MANAGER_ #include #include "os.h" namespace irr { namespace video { CNSOGLManager::CNSOGLManager() : PrimaryContext(SExposedVideoData(0)), PixelFormat(nil) { #ifdef _DEBUG setDebugName("CNSOGLManager"); #endif } CNSOGLManager::~CNSOGLManager() { } bool CNSOGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& videodata) { Params = params; return true; } void CNSOGLManager::terminate() { } bool CNSOGLManager::generateSurface() { if (Params.DriverType == video::EDT_OPENGL) { int alphaSize = Params.WithAlphaChannel ? 4 : 0; int depthSize = Params.ZBufferBits; if (Params.WithAlphaChannel && Params.Bits == 32) alphaSize = 8; NSOpenGLPixelFormatAttribute Attribs[] = { NSOpenGLPFANoRecovery, NSOpenGLPFAAccelerated, NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, static_cast(depthSize), NSOpenGLPFAColorSize, Params.Bits, NSOpenGLPFAAlphaSize, static_cast(alphaSize), NSOpenGLPFASampleBuffers, 1, NSOpenGLPFASamples, Params.AntiAlias, NSOpenGLPFAStencilSize, static_cast(Params.Stencilbuffer ? 1 : 0), //NSOpenGLPFAFullScreen, 0 }; u32 Steps = 6; // Choose the best pixel format. do { switch (Steps) { case 6: // decrease step. --Steps; break; case 5: // samples if (Attribs[12] > 2) --Attribs[12]; else { Attribs[10] = 0; Attribs[12] = 0; --Steps; } break; case 4: // alpha if (Attribs[8]) { Attribs[8] = 0; if (Params.AntiAlias) { Attribs[10] = 1; Attribs[12] = Params.AntiAlias; Steps = 5; } } else --Steps; break; case 3: // stencil if (Attribs[14]) { Attribs[14] = 0; if (Params.AntiAlias) { Attribs[10] = 1; Attribs[12] = Params.AntiAlias; Steps = 5; } } else --Steps; break; case 2: // depth size if (Attribs[4] > 16) { Attribs[4] = Attribs[4] - 8; } else --Steps; break; case 1: // buffer size if (Attribs[6] > 16) { Attribs[6] = Attribs[6] - 8; } else --Steps; break; default: os::Printer::log("Could not get pixel format."); return false; } PixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:Attribs]; } while (PixelFormat == nil); if (Params.AntiAlias && !Attribs[10]) os::Printer::log("No multisampling."); if (Params.WithAlphaChannel && !Attribs[8]) os::Printer::log("No alpha."); if (Params.Stencilbuffer && !Attribs[14]) os::Printer::log("No stencil buffer."); if (Params.ZBufferBits > Attribs[4]) os::Printer::log("No full depth buffer."); if (Params.Bits > Attribs[6]) os::Printer::log("No full color buffer."); } return true; } void CNSOGLManager::destroySurface() { [PixelFormat release]; PixelFormat = nil; } bool CNSOGLManager::generateContext() { NSOpenGLContext* Context = [[NSOpenGLContext alloc] initWithFormat:PixelFormat shareContext:nil]; GLint Vsync = Params.Vsync ? 1 : 0; [Context setValues:&Vsync forParameter:NSOpenGLCPSwapInterval]; if (Context == nil) { os::Printer::log("Could not create OpenGL context.", ELL_ERROR); return false; } // set exposed data CurrentContext.OpenGLOSX.Context = Context; if (!PrimaryContext.OpenGLOSX.Context) PrimaryContext.OpenGLOSX.Context = CurrentContext.OpenGLOSX.Context; return true; } const SExposedVideoData& CNSOGLManager::getContext() const { return CurrentContext; } bool CNSOGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero) { //TODO: handle restorePrimaryOnZero if (videoData.OpenGLOSX.Context) { if ((NSOpenGLContext*)videoData.OpenGLOSX.Context != [NSOpenGLContext currentContext]) { [(NSOpenGLContext*)videoData.OpenGLOSX.Context makeCurrentContext]; CurrentContext = videoData; } } // set back to main context else { if ((NSOpenGLContext*)PrimaryContext.OpenGLOSX.Context != [NSOpenGLContext currentContext]) { [(NSOpenGLContext*)PrimaryContext.OpenGLOSX.Context makeCurrentContext]; CurrentContext = PrimaryContext; } } return true; } void CNSOGLManager::destroyContext() { if (CurrentContext.OpenGLOSX.Context) { if (PrimaryContext.OpenGLOSX.Context == CurrentContext.OpenGLOSX.Context) PrimaryContext.OpenGLOSX.Context = nil; [(NSOpenGLContext*)CurrentContext.OpenGLOSX.Context makeCurrentContext]; [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context clearDrawable]; [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context release]; [NSOpenGLContext clearCurrentContext]; CurrentContext.OpenGLOSX.Context = nil; } } // It appears that there is no separate GL proc address getter on OSX. // https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_entrypts/opengl_entrypts.html void* CNSOGLManager::getProcAddress(const std::string &procName) { NSSymbol symbol = NULL; // Allocate a buffer for the name, an underscore prefix, and a cstring terminator. std::string mangledName = "_" + procName; if (NSIsSymbolNameDefined(mangledName.c_str())) symbol = NSLookupAndBindSymbol(mangledName.c_str()); return symbol ? NSAddressOfSymbol(symbol) : NULL; } bool CNSOGLManager::swapBuffers() { [(NSOpenGLContext*)CurrentContext.OpenGLOSX.Context flushBuffer]; return true; } } } #endif