2023-10-03 20:37:00 +02:00
|
|
|
// 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
|
|
|
|
{
|
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
CNSOGLManager::CNSOGLManager() :
|
|
|
|
PrimaryContext(SExposedVideoData(0)), PixelFormat(nil)
|
2023-10-03 20:37:00 +02:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
setDebugName("CNSOGLManager");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
CNSOGLManager::~CNSOGLManager()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
bool CNSOGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata)
|
2023-10-03 20:37:00 +02:00
|
|
|
{
|
|
|
|
Params = params;
|
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
return true;
|
2023-10-03 20:37:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CNSOGLManager::terminate()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CNSOGLManager::generateSurface()
|
|
|
|
{
|
2024-03-20 19:35:52 +01:00
|
|
|
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.");
|
2023-10-03 20:37:00 +02:00
|
|
|
}
|
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
return true;
|
2023-10-03 20:37:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CNSOGLManager::destroySurface()
|
|
|
|
{
|
2024-03-20 19:35:52 +01:00
|
|
|
[PixelFormat release];
|
|
|
|
PixelFormat = nil;
|
2023-10-03 20:37:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CNSOGLManager::generateContext()
|
|
|
|
{
|
2024-03-20 19:35:52 +01:00
|
|
|
NSOpenGLContext *Context = [[NSOpenGLContext alloc] initWithFormat:PixelFormat shareContext:nil];
|
2023-10-03 20:37:00 +02:00
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
GLint Vsync = Params.Vsync ? 1 : 0;
|
|
|
|
[Context setValues:&Vsync forParameter:NSOpenGLCPSwapInterval];
|
2023-10-03 20:37:00 +02:00
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
if (Context == nil) {
|
2023-10-03 20:37:00 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
const SExposedVideoData &CNSOGLManager::getContext() const
|
2023-10-03 20:37:00 +02:00
|
|
|
{
|
|
|
|
return CurrentContext;
|
|
|
|
}
|
|
|
|
|
2024-03-20 19:35:52 +01:00
|
|
|
bool CNSOGLManager::activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero)
|
2023-10-03 20:37:00 +02:00
|
|
|
{
|
2024-03-20 19:35:52 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2023-10-03 20:37:00 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CNSOGLManager::destroyContext()
|
|
|
|
{
|
2024-03-20 19:35:52 +01:00
|
|
|
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];
|
2023-10-03 20:37:00 +02:00
|
|
|
[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
|
2024-03-20 19:35:52 +01:00
|
|
|
void *CNSOGLManager::getProcAddress(const std::string &procName)
|
2023-10-03 20:37:00 +02:00
|
|
|
{
|
|
|
|
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()
|
|
|
|
{
|
2024-03-20 19:35:52 +01:00
|
|
|
[(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context flushBuffer];
|
2023-10-03 20:37:00 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|