//----------------------------------------------------------------------------- // 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 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); } }