irrlicht/source/Irrlicht/CNSOGLManager.mm

257 lines
7.0 KiB
Plaintext

// 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 <mach-o/dyld.h>
#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<NSOpenGLPixelFormatAttribute>(depthSize),
NSOpenGLPFAColorSize, Params.Bits,
NSOpenGLPFAAlphaSize, static_cast<NSOpenGLPixelFormatAttribute>(alphaSize),
NSOpenGLPFASampleBuffers, 1,
NSOpenGLPFASamples, Params.AntiAlias,
NSOpenGLPFAStencilSize, static_cast<NSOpenGLPixelFormatAttribute>(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