tge/engine/platformMacCarb/macCarbOGLVideo.cc
2017-04-17 06:17:10 -06:00

820 lines
28 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//
// Portions taken from OpenGL Full Screen.c sample from Apple Computer, Inc.
// (that's where many of the lead helper functions originated from, but code
// has been significantly changed & revised.)
//-----------------------------------------------------------------------------
#include "platformMacCarb/platformMacCarb.h"
#include "platformMacCarb/platformGL.h"
#include "platformMacCarb/maccarbOGLVideo.h"
#include "console/console.h"
#include "math/mPoint.h"
#include "platform/event.h"
#include "platform/gameInterface.h"
#include "console/consoleInternal.h"
#include "console/ast.h"
#include "core/fileStream.h"
#include "platformMacCarb/macCarbUtil.h"
#include "platformMacCarb/macCarbEvents.h"
#include "dgl/dgl.h"
// TODO: Card Profiling code isn't doing anything.
AGLContext agl_ctx;
//-----------------------------------------------------------------------------------------
// prototypes and globals -- !!!!!!TBD - globals should mostly go away, into platState.
//-----------------------------------------------------------------------------------------
GLenum dumpAGLDebugStr (void);
GLenum dumpGLDebugStr (void);
void dumpPixelFormatList(AGLPixelFormat fmt);
#pragma mark -
//-----------------------------------------------------------------------------------------
// if error dump agl errors to debugger string, return error
//-----------------------------------------------------------------------------------------
GLenum dumpAGLDebugStr (void)
{
GLenum err = aglGetError();
if (err != AGL_NO_ERROR)
Con::errorf ((char *)aglErrorString(err));
return err;
}
//-----------------------------------------------------------------------------------------
// if error dump gl errors to debugger string, return error
//-----------------------------------------------------------------------------------------
GLenum dumpGLDebugStr (void)
{
GLenum err = glGetError();
if (GL_NO_ERROR != err)
Con::errorf ((char *)gluErrorString(err));
return err;
}
#pragma mark -
//-----------------------------------------------------------------------------------------
// Creates a dummy AGL context, so that naughty objects that call OpenGL before the window
// exists will not crash the game.
// If for some reason we fail to get a default contet, assert -- something's very wrong.
//-----------------------------------------------------------------------------------------
void initDummyAgl(void)
{
short i = 0;
GLint attrib[64];
AGLPixelFormat fmt;
AGLContext ctx;
// clear the existing agl context
if(platState.ctx != NULL)
aglDestroyContext(platState.ctx);
platState.ctx = NULL;
agl_ctx = NULL;
// set up an attribute array for the pixel format.
attrib [i++] = AGL_RGBA; // red green blue and alpha
attrib [i++] = AGL_DOUBLEBUFFER; // double buffered
attrib [i++] = AGL_NONE; // terminate the list.
// choose a pixel format that works for any current display device, and matches
// the attributes above as closely as possible.
fmt = aglChoosePixelFormat(NULL, 0, attrib);
dumpAGLDebugStr ();
AssertFatal(fmt, "Could not find a valid default pixel format in initDummyAgl()");
dumpPixelFormatList(fmt);
// create an agl context. NULL = don't share resouces with any other context.
ctx = aglCreateContext (fmt, NULL);
dumpAGLDebugStr ();
AssertFatal(ctx, "Could not create a default agl context in initDummyAgl()");
// make gl calls go to our dummy context
if (!aglSetCurrentContext (ctx))
{
dumpAGLDebugStr ();
AssertFatal(false,"Could not set a default agl context as the current context.");
}
// pixel format is no longer needed once the context has been created
aglDestroyPixelFormat(fmt);
platState.ctx = ctx;
agl_ctx = ctx; // maintain up aglMacro.h context
}
GDHandle allDevs[32];
U32 nAllDevs;
AGLPixelFormat findValidPixelFormat(bool fullscreen, U32 bpp, U32 samples, bool recovery = true)
{
AssertWarn(bpp==16 || bpp==32 || bpp==0, "An unusual bit depth was requested in findValidPixelFormat(). clamping to 16|32");
if(bpp)
bpp = bpp > 16 ? 32 : 16;
AssertWarn(samples <= 6, "An unusual multisample depth was requested in findValidPixelFormat(). clamping to 0...6");
samples = samples > 6 ? 6 : samples;
// create an agl pixel format
int i = 0;
GLint attr[64];
AGLPixelFormat fmt;
// basic hardware accelerated format options
attr[i++] = AGL_RGBA; // red green blue and alpha format
attr[i++] = AGL_DOUBLEBUFFER; // double buffered format
attr[i++] = AGL_ACCELERATED; // ask for hardware acceleration
attr[i++] = AGL_NO_RECOVERY; // prohibit use of a software rendering fallback
// request fullscreen capable format if needed
if(fullscreen)
attr[i++] = AGL_FULLSCREEN;
if(bpp != 0)
{
// native pixel formats are argb 1555 & argb 8888.
U32 colorbits = 0;
U32 alphabits = 0;
if(bpp == 16)
{
colorbits = 5; // ARGB 1555
alphabits = 1;
}
else if(bpp == 32)
colorbits = alphabits = 8; // ARGB 8888
attr[i++] = AGL_DEPTH_SIZE;
attr[i++] = bpp;
attr[i++] = AGL_PIXEL_SIZE;
attr[i++] = bpp;
attr[i++] = AGL_RED_SIZE;
attr[i++] = colorbits;
attr[i++] = AGL_GREEN_SIZE;
attr[i++] = colorbits;
attr[i++] = AGL_BLUE_SIZE;
attr[i++] = colorbits;
attr[i++] = AGL_ALPHA_SIZE;
attr[i++] = alphabits;
}
if(samples != 0)
{
attr[i++] = AGL_SAMPLE_BUFFERS_ARB; // number of multisample buffers
attr[i++] = 1; // currently only 1 is supported
attr[i++] = AGL_SAMPLES_ARB; // number of samples per pixel
attr[i++] = samples + samples % 2; // must be 2, 4, 6 ...
}
attr[i++] = AGL_NONE; // null-terminate the list
fmt = aglChoosePixelFormat(&platState.hDisplay, 1, attr);
dumpAGLDebugStr();
if(!fmt && recovery)
{
// recovery.
// first try ignoring samples. then try ignoring the bit depth.
// we'll try the following order:
// specified bit depth, specified multisample depth
// specified bit depth, lower/no multisample
// any bit depth, specified multisample depth
// any bit depth, lower/no multisample
// downgrade multisample, trying for a valid format
for(int fewerSamples = samples - 1; !fmt && fewerSamples >=0; fewerSamples--)
{
Con::errorf("error selecting pixel format, trying again with %s, bpp=%i, multisample level=%i",
fullscreen ? "fullscreen" : "windowed", bpp, fewerSamples);
fmt = findValidPixelFormat(fullscreen, bpp, fewerSamples, false);
}
// allow any bit depth, send in requested multisample level, and ALLOW RECOVERY.
// if this attempt fails, we'll hit the above 'downgrade multisample' block in the recursion.
if(!fmt && bpp != 0)
{
Con::warnf("error selecting pixel format, trying again with %s, bpp=%i, multisample level=%i",
fullscreen ? "fullscreen" : "windowed", 0, samples);
fmt = findValidPixelFormat(fullscreen, 0, samples, true);
}
}
return fmt;
}
void dumpPixelFormat(AGLPixelFormat fmt)
{
Con::printf(" ------------------------------------------------------------");
Con::printf("Describing pixel format 0x%x", fmt);
GLint val;
#define DumpAGLPixelFormatAttr(attr) \
aglDescribePixelFormat(fmt, AGL_##attr, &val); \
dumpAGLDebugStr(); \
Con::printf(" %20s %4i", #attr ,val);
DumpAGLPixelFormatAttr(ALL_RENDERERS);
DumpAGLPixelFormatAttr(BUFFER_SIZE);
DumpAGLPixelFormatAttr(LEVEL);
DumpAGLPixelFormatAttr(RGBA);
DumpAGLPixelFormatAttr(DOUBLEBUFFER)
DumpAGLPixelFormatAttr(STEREO);
DumpAGLPixelFormatAttr(AUX_BUFFERS);
DumpAGLPixelFormatAttr(GREEN_SIZE);
DumpAGLPixelFormatAttr(RED_SIZE);
DumpAGLPixelFormatAttr(BLUE_SIZE);
DumpAGLPixelFormatAttr(ALPHA_SIZE);
DumpAGLPixelFormatAttr(DEPTH_SIZE);
DumpAGLPixelFormatAttr(STENCIL_SIZE);
DumpAGLPixelFormatAttr(ACCUM_RED_SIZE);
DumpAGLPixelFormatAttr(ACCUM_GREEN_SIZE);
DumpAGLPixelFormatAttr(ACCUM_BLUE_SIZE);
DumpAGLPixelFormatAttr(ACCUM_ALPHA_SIZE);
DumpAGLPixelFormatAttr(PIXEL_SIZE);
DumpAGLPixelFormatAttr(MINIMUM_POLICY);
DumpAGLPixelFormatAttr(MAXIMUM_POLICY);
DumpAGLPixelFormatAttr(OFFSCREEN);
DumpAGLPixelFormatAttr(FULLSCREEN);
DumpAGLPixelFormatAttr(SAMPLE_BUFFERS_ARB);
DumpAGLPixelFormatAttr(SAMPLES_ARB);
DumpAGLPixelFormatAttr(AUX_DEPTH_STENCIL);
DumpAGLPixelFormatAttr(COLOR_FLOAT);
DumpAGLPixelFormatAttr(MULTISAMPLE);
DumpAGLPixelFormatAttr(SUPERSAMPLE);
DumpAGLPixelFormatAttr(SAMPLE_ALPHA);
#undef DumpAGLPixelFormatAttr
Con::printf(" ------------------------------------------------------------");
}
void dumpPixelFormatList(AGLPixelFormat fmt)
{
Con::printf("Dumping list of pixel formats:");
while(fmt!=NULL)
{
dumpPixelFormat(fmt);
fmt = aglNextPixelFormat(fmt);
}
}
#pragma mark -
//------------------------------------------------------------------------------
OpenGLDevice::OpenGLDevice()
{
// Set the device name:
mDeviceName = "OpenGL";
// macs games are not generally full screen only
mFullScreenOnly = false;
}
//------------------------------------------------------------------------------
void OpenGLDevice::initDevice()
{
// pick a monitor to run on
enumMonitors();
// choose a monitor at save it in the plat state
platState.hDisplay = chooseMonitor();
platState.cgDisplay = MacCarbGetCGDisplayFromQDDisplay(platState.hDisplay);
// figure out & cache what Resolution's this card-monitor combo can support
enumDisplayModes(platState.cgDisplay);
}
//------------------------------------------------------------------------------
// Fill Vector<Resolution> mResoultionList with list of supported modes
//------------------------------------------------------------------------------
bool OpenGLDevice::enumDisplayModes(CGDirectDisplayID display)
{
mResolutionList.clear();
// get the display, and the list of all available modes.
CFArrayRef modeArray = CGDisplayAvailableModes(display);
if(!modeArray)
{
// we're probably in headless mode. still, best not to leave the list emtpy.
Resolution headless( 640, 480, 32 );
mResolutionList.push_back( headless );
return false;
}
int len = CFArrayGetCount(modeArray);
for(int i=0; i < len; i++)
{
// get this mode.
CFNumberRef num;
int width, height, bpp;
CFDictionaryRef mode = (CFDictionaryRef) CFArrayGetValueAtIndex(modeArray,i);
// get width
num = CFDictionaryGetValue( mode, kCGDisplayWidth );
CFNumberGetValue(num, kCFNumberLongType,&width);
// get height
num = CFDictionaryGetValue( mode, kCGDisplayHeight );
CFNumberGetValue(num, kCFNumberLongType,&height);
// get bpp
num = CFDictionaryGetValue( mode, kCGDisplayBitsPerPixel );
CFNumberGetValue(num, kCFNumberLongType,&bpp);
// add to the list
if( bpp != 8 )
{
Resolution newRes( width, height, bpp );
mResolutionList.push_back( newRes );
}
}
// // fill it with some standard sizes for a machine, just to have them available.
// Point sizes[4] = {{640,480},{800,600},{1024,768},{1280,1024}};
// for(int i=0; i<4; i++)
// {
// // Point is { short v, short h }, so we have to reverse the h and v here, sorry for any confusion.
// Resolution newRes16( sizes[i].v, sizes[i].h, 16 );
// Resolution newRes32( sizes[i].v, sizes[i].h, 32 );
// mResolutionList.push_back( newRes16 );
// mResolutionList.push_back( newRes32 );
// }
return true;
}
//------------------------------------------------------------------------------
// Fill mMonitorList with list of supported modes
// Guaranteed to include at least the main device.
//------------------------------------------------------------------------------
bool OpenGLDevice::enumMonitors()
{
// DMGetFirstScreenDevice() et al are deprecated as of 10.4, but we need them
// for AGL, which operates on GDHandle's for displays.
// As far as I know, you can get a CGDirectDisplayID from a GDHandle,
// but not the other way around.
mMonitorList.clear();
GDHandle dev = DMGetFirstScreenDevice( true );
nAllDevs = 0;
while( dev )
{
Con::printf( " active displays = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
mMonitorList.push_back(dev);
allDevs[nAllDevs++] = dev;
dev = DMGetNextScreenDevice( dev, true);
}
return true;
}
//------------------------------------------------------------------------------
// Chooses a monitor based on $pref, on the results of tors(), & on the
// current window's screen.
//------------------------------------------------------------------------------
GDHandle OpenGLDevice::chooseMonitor()
{
// TODO: choose monitor based on which one contains most of the window.
// NOTE: do not call cleanup before calling choose, or we won't have a window to consider.
AssertFatal(!mMonitorList.empty(), "Cannot choose a monitor if the list is empty!");
U32 monNum = Con::getIntVariable("$pref::Video::monitorNum", 0);
if(monNum >= mMonitorList.size())
{
Con::errorf("invalid monitor number %i", monNum);
monNum = 0;
Con::setIntVariable("$pref::Video::monitorNum", 0);
}
Con::printf("using display 0x%x", mMonitorList[monNum]);
return mMonitorList[monNum];
}
//------------------------------------------------------------------------------
// Activate
// this is called once, as a result of createCanvas() in scripts.
// dumps OpenGL driver info for the current screen
// creates an initial window via setScreenMode
bool OpenGLDevice::activate( U32 width, U32 height, U32 bpp, bool fullScreen )
{
Con::printf( " OpenGLDevice activating..." );
// Never unload a code module. This makes destroying & recreating contexts faster.
aglConfigure(AGL_RETAIN_RENDERERS, GL_TRUE);
// gets opengl rendering capabilities of the screen pointed to by platState.hDisplay
// sets up dgl with the capabilities info, & reports opengl status.
getGLCapabilities();
// Create the window or capture fullscreen
if(!setScreenMode( width, height, bpp, fullScreen, true, false ))
return false;
// set the displayDevice pref to "OpenGL"
Con::setVariable( "$pref::Video::displayDevice", mDeviceName );
// set vertical sync now because it doesnt need setting every time we setScreenMode()
setVerticalSync( !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ));
return true;
}
//------------------------------------------------------------------------------
// returns TRUE if textures need resurrecting in future...
//------------------------------------------------------------------------------
bool OpenGLDevice::cleanupContextAndWindow()
{
bool needResurrect = false;
Con::printf( "Cleaning up the display device..." );
// Delete the rendering context and it's specific data.
if (platState.ctx)
{
// The OpenGL texture handles are specific to each context.
// We'll need to get new ones for a new context, so kill the texture manager to clear 'em.
if (!Video::smNeedResurrect)
{
Con::printf( "Killing the texture manager..." );
Game->textureKill();
needResurrect = true;
}
// make the agl context not-current, which stops openGL calls from going anywhere.
Con::printf( "Clearing the current AGL context..." );
aglSetCurrentContext(NULL);
#if defined(USE_AGL_MACRO)
agl_ctx = NULL; // maintain aglMacro.h context
#endif
// detatch the agl context from it's window
Con::printf( "Clearing the current drawable..." );
aglSetDrawable(platState.ctx, NULL);
// delete the context
Con::printf( "Deleting the rendering context..." );
aglDestroyContext(platState.ctx);
// clear our handle to the context
platState.ctx = NULL;
}
// delete the app window if it exists
if ( platState.appWindow )
{
Con::printf( "Destroying the window..." );
MacCarbFadeAndReleaseWindow(platState.appWindow);
platState.appWindow = NULL;
}
// clear the Resolution state, so setScreenMode() will know not to early-out.
smCurrentRes = Resolution(0,0,0);
return(needResurrect);
}
//------------------------------------------------------------------------------
void OpenGLDevice::shutdown()
{
Con::printf( "Shutting down the OpenGL display device..." );
// clean up the context, the window, and kill the texture manager
cleanupContextAndWindow();
}
//------------------------------------------------------------------------------
// This is the real workhorse function of the DisplayDevice...
//
bool OpenGLDevice::setScreenMode( U32 width, U32 height, U32 bpp, bool fullScreen, bool forceIt, bool repaint )
{
Con::printf(" set screen mode %i x %i x %i, %s, %s, %s",width, height, bpp,
fullScreen ? "fullscreen" : "windowed",
forceIt ? "force it" : "dont force it",
repaint ? "repaint" : "dont repaint"
);
// validation, early outs --------------------------------------------------
// sanity check. some scripts are liable to pass in bad values.
if(!bpp)
bpp = platState.desktopBitsPixel;
Resolution newRes = Resolution(width, height, bpp);
// if no values changing and we're not forcing a change, kick out. prevents thrashing.
if(!forceIt && smIsFullScreen == fullScreen && smCurrentRes == newRes)
return(true);
// we have a new context, this is now safe to do:
// delete any contexts or windows that exist, and kill the texture manager.
bool needResurrect = cleanupContextAndWindow();
Con::printf( ">> Attempting to change display settings to %s %dx%dx%d...",
fullScreen?"fullscreen":"windowed", newRes.w, newRes.h, newRes.bpp );
// monitor selection -------------------------------------------------------
// set our preferred monitor. default is the screen that has the menu bar.
GDHandle prevDisplay = platState.hDisplay;
platState.hDisplay = chooseMonitor();
platState.cgDisplay = MacCarbGetCGDisplayFromQDDisplay(platState.hDisplay);
AssertFatal(platState.hDisplay,"We chose a null monitor? Panic!");
// if we're changing screens, we must know what the new one is capable of
if(prevDisplay != platState.hDisplay)
{
enumDisplayModes(platState.cgDisplay);
getGLCapabilities();
}
// create an agl rendering context ------------------------------------------
AGLPixelFormat fmt = NULL;
AGLContext ctx = NULL;
// select pixel format. fall back to more generic options until we get something.
fmt = findValidPixelFormat(fullScreen, bpp, 0);
AssertFatal(fmt, "We utterly failed to choose a valid AGL pixel format.");
// print out the pixel format list we got.
//dumpPixelFormatList(fmt);
// create the agl rendering context
ctx = aglCreateContext(fmt, NULL);
dumpAGLDebugStr();
AssertISV( ctx, "We could not create a valid AGL rendering context.");
if(!ctx)
return false;
// format is not needed once we have a context.
aglDestroyPixelFormat(fmt);
if(fullScreen && platState.captureDisplay)
{
// capture main display & go to full screen mode
// TODO: allow frequency selection?
aglSetFullScreen(ctx, newRes.w, newRes.h, 0, 0);
dumpAGLDebugStr();
Con::printf("set AGL fullscreen");
MacCarbShowMenuBar(false);
}
else
{
// create a window, get it's drawable, and attach our context to the window
bool isFullscreenWindow = (fullScreen && !platState.captureDisplay);
platState.appWindow = MacCarbCreateOpenGLWindow( platState.hDisplay, newRes.w, newRes.h, isFullscreenWindow );
if(!platState.appWindow)
{
Con::errorf("OpenGLDevice::setScreenMode - Failed to create a new window!");
return false;
}
CGrafPtr drawable = GetWindowPort(platState.appWindow);
aglSetDrawable(ctx, drawable);
dumpAGLDebugStr();
Con::printf("Set up AGL windowed support");
}
// send opengl commands to this context.
aglSetCurrentContext(ctx);
#if defined(USE_AGL_MACRO)
agl_ctx = ctx; // maintain aglMacro.h context
#endif
// save the context
platState.ctx = ctx;
// clear out garbage from the gl window.
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT );
Con::printf("Cleared gl buffers");
// set opengl options & other options ---------------------------------------
// ensure data is packed tightly in memory. this defaults to 4.
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// TODO: set gl arb multisample enable & hint
dglSetFSAASamples(gFSAASamples);
// set vertical sync
setVerticalSync(!Con::getBoolVariable( "$pref::Video::disableVerticalSync" ));
// set torque variables ----------------------------------------------------
// save window size for dgl
Platform::setWindowSize( newRes.w, newRes.h );
// update smIsFullScreen and pref
smIsFullScreen = fullScreen;
Con::setBoolVariable( "$pref::Video::fullScreen", smIsFullScreen );
// save resolution
smCurrentRes = newRes;
// save resolution to prefs
char buf[32];
if(fullScreen)
{
dSprintf( buf, sizeof(buf), "%d %d %d", newRes.w, newRes.h, newRes.bpp);
Con::setVariable("$pref::Video::resolution", buf);
}
else
{
dSprintf( buf, sizeof(buf), "%d %d", newRes.w, newRes.h);
Con::setVariable("$pref::Video::windowedRes", buf);
}
// fade the window into existance, asynchronously
if(platState.appWindow)
MacCarbFadeInWindow(platState.appWindow);
// begin rendering again ----------------------------------------------------
if( needResurrect )
{
// Reload the textures gl names
Con::printf( "Resurrecting the texture manager..." );
Game->textureResurrect();
}
// reattach the event handlers to the new window.
MacCarbRemoveCarbonEventHandlers();
MacCarbInstallCarbonEventHandlers();
if( repaint )
Con::evaluate( "resetCanvas();" );
return true;
}
//------------------------------------------------------------------------------
void OpenGLDevice::swapBuffers()
{
if (platState.ctx)
aglSwapBuffers(platState.ctx);
#if defined(TORQUE_DEBUG)
if(gOutlineEnabled)
glClear(GL_COLOR_BUFFER_BIT);
#endif
}
//------------------------------------------------------------------------------
const char* OpenGLDevice::getDriverInfo()
{
// Prepare some driver info for the console:
const char* vendorString = (const char*) glGetString( GL_VENDOR );
const char* rendererString = (const char*) glGetString( GL_RENDERER );
const char* versionString = (const char*) glGetString( GL_VERSION );
const char* extensionsString = (const char*) glGetString( GL_EXTENSIONS );
U32 bufferLen = ( vendorString ? dStrlen( vendorString ) : 0 )
+ ( rendererString ? dStrlen( rendererString ) : 0 )
+ ( versionString ? dStrlen( versionString ) : 0 )
+ ( extensionsString ? dStrlen( extensionsString ) : 0 )
+ 4;
char* returnString = Con::getReturnBuffer( bufferLen );
dSprintf( returnString, bufferLen, "%s\t%s\t%s\t%s",
( vendorString ? vendorString : "" ),
( rendererString ? rendererString : "" ),
( versionString ? versionString : "" ),
( extensionsString ? extensionsString : "" ) );
return( returnString );
}
typedef struct MacCarbGamma
{
F32 r, g, b;
F32 scale;
};
static MacCarbGamma _MacGamma;
//------------------------------------------------------------------------------
bool OpenGLDevice::getGammaCorrection(F32 &g)
{
// rgb gamma exponents
CGGammaValue red,green,blue;
// rgb min & max gamma. we'll ignore these for the present.
CGGammaValue rm, rx, gm, gx, bm, bx;
// grab the gamma values
CGDirectDisplayID display = platState.cgDisplay;
CGGetDisplayTransferByFormula(display, &rm, &rx, &red, &gm, &gx, &green, &bm, &bx, &blue);
// save the original gamma vals, and the current scale.
static bool once = true;
if(once)
{
once = false;
_MacGamma.r = red;
_MacGamma.g = green;
_MacGamma.b = blue;
_MacGamma.scale = 1.0;
}
g = _MacGamma.scale;
return true;
}
//------------------------------------------------------------------------------
bool OpenGLDevice::setGammaCorrection(F32 g)
{
// revert to default colorsync settings if g approaches 1.0
F32 epsilon = 0.01f;
if( mFabs(g - 1.0) <= epsilon )
{
CGDisplayRestoreColorSyncSettings();
return false;
}
// rgb gamma exponents
CGGammaValue red,green,blue;
// rgb min & max gamma. we'll ignore these for the present.
CGGammaValue rm, rx, gm, gx, bm, bx;
CGGetDisplayTransferByFormula(platState.cgDisplay, &rm, &rx, &red, &gm, &gx, &green, &bm, &bx, &blue);
// scale the original gamma values.
red = _MacGamma.r * g;
green = _MacGamma.g * g;
blue = _MacGamma.b * g;
_MacGamma.scale = g;
// set the gamma.
CGSetDisplayTransferByFormula(platState.cgDisplay, rm, rx, red, gm, gx, green, bm, bx, blue);
return true;
}
//------------------------------------------------------------------------------
bool OpenGLDevice::setVerticalSync( bool on )
{
if (!platState.ctx)
return false;
bool ret = aglSetInteger(platState.ctx, AGL_SWAP_INTERVAL, (GLint*)&on);
return ret;
}
//------------------------------------------------------------------------------
DisplayDevice* OpenGLDevice::create()
{
// set up a dummy default agl context.
// this will be replaced later with the window's context,
// but we need agl_ctx to be valid at all times,
// since some things try to make gl calls before the device is activated.
initDummyAgl();
// create the DisplayDevice
OpenGLDevice* newOGLDevice = new OpenGLDevice();
// gather monitor & resolution info
// delegated out to initDevice() in case the display config changes.
newOGLDevice->initDevice();
return newOGLDevice;
}
#pragma mark -
Resolution Video::getDesktopResolution()
{
Resolution res;
Rect r = (**platState.hDisplay).gdRect;
res.w = r.right - r.left;
res.h = r.bottom - r.top;
res.bpp = (**(**platState.hDisplay).gdPMap).pixelSize;
platState.desktopWidth = res.w;
platState.desktopHeight = res.h;
platState.desktopBitsPixel = res.bpp;
return res;
}
#pragma mark -
ConsoleFunction( dumpDisplayIDs, void, 1,1, "")
{
Con::errorf("=-== Dumping display ids =-==");
GDHandle dev = GetMainDevice();
Con::printf("main display GetMainDevice = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
dev = DMGetFirstScreenDevice( true );
Con::printf( "first active display = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
while( ( dev = DMGetNextScreenDevice( dev, true)) != NULL)
{
Con::printf( " active displays = 0x%x CGDisplayID = 0x%x", dev, MacCarbGetCGDisplayFromQDDisplay(dev));
}
CGDirectDisplayID mainid = CGMainDisplayID();
Con::printf("main display CGMainDisplayID = 0x%x", mainid);
CGDirectDisplayID lastDisplay, displayArray[64] ;
CGDisplayCount numDisplays ;
CGGetActiveDisplayList( 64, displayArray, &numDisplays );
for(int i=0; i< numDisplays; i++)
{
mainid = displayArray[i];
Con::printf(" CG active display list CGMainDisplayID = 0x%x", mainid);
}
}