/* =========================================================================== Return to Castle Wolfenstein multiplayer GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”). RTCW MP Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. RTCW MP Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RTCW MP Source Code. If not, see . In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ // $Header$ #import #import // for interpreting the kCGDisplayIOFlags element of the display mode #import "macosx_display.h" #include "tr_local.h" #import "macosx_local.h" NSDictionary *Sys_GetMatchingDisplayMode( qboolean allowStretchedModes ) { NSArray *displayModes; NSDictionary *mode; unsigned int modeIndex, modeCount, bestModeIndex; int verbose; cvar_t *cMinFreq, *cMaxFreq; int minFreq, maxFreq; unsigned int colorDepth; verbose = r_verbose->integer; colorDepth = r_colorbits->integer; if ( colorDepth < 16 || !r_fullscreen->integer ) { colorDepth = [[glw_state.desktopMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue]; } cMinFreq = ri.Cvar_Get( "r_minDisplayRefresh", "0", CVAR_ARCHIVE ); cMaxFreq = ri.Cvar_Get( "r_maxDisplayRefresh", "0", CVAR_ARCHIVE ); if ( cMinFreq && cMaxFreq && cMinFreq->integer && cMaxFreq->integer && cMinFreq->integer > cMaxFreq->integer ) { ri.Error( ERR_FATAL, "r_minDisplayRefresh must be less than or equal to r_maxDisplayRefresh" ); } minFreq = cMinFreq ? cMinFreq->integer : 0; maxFreq = cMaxFreq ? cMaxFreq->integer : 0; displayModes = (NSArray *)CGDisplayAvailableModes( glw_state.display ); if ( !displayModes ) { ri.Error( ERR_FATAL, "CGDisplayAvailableModes returned NULL -- 0x%0x is an invalid display", glw_state.display ); } modeCount = [displayModes count]; if ( verbose ) { ri.Printf( PRINT_ALL, "%d modes avaliable\n", modeCount ); ri.Printf( PRINT_ALL, "Current mode is %s\n", [[(id)CGDisplayCurrentMode( glw_state.display ) description] cString] ); } // Default to the current desktop mode bestModeIndex = 0xFFFFFFFF; for ( modeIndex = 0; modeIndex < modeCount; ++modeIndex ) { id object; int refresh; mode = [displayModes objectAtIndex: modeIndex]; if ( verbose ) { ri.Printf( PRINT_ALL, " mode %d -- %s\n", modeIndex, [[mode description] cString] ); } // Make sure we get the right size object = [mode objectForKey: (id)kCGDisplayWidth]; if ([[mode objectForKey : (id)kCGDisplayWidth] intValue] != glConfig.vidWidth || [[mode objectForKey : (id)kCGDisplayHeight] intValue] != glConfig.vidHeight ) { if ( verbose ) { ri.Printf( PRINT_ALL, " -- bad size\n" ); } continue; } if ( !allowStretchedModes ) { if ([[mode objectForKey : (id)kCGDisplayIOFlags] intValue] & kDisplayModeStretchedFlag ) { if ( verbose ) { ri.Printf( PRINT_ALL, " -- stretched modes disallowed\n" ); } continue; } } // Make sure that our frequency restrictions are observed refresh = [[mode objectForKey: (id)kCGDisplayRefreshRate] intValue]; if ( minFreq && refresh < minFreq ) { if ( verbose ) { ri.Printf( PRINT_ALL, " -- refresh too low\n" ); } continue; } if ( maxFreq && refresh > maxFreq ) { if ( verbose ) { ri.Printf( PRINT_ALL, " -- refresh too high\n" ); } continue; } if ([[mode objectForKey : (id)kCGDisplayBitsPerPixel] intValue] != colorDepth ) { if ( verbose ) { ri.Printf( PRINT_ALL, " -- bad depth\n" ); } continue; } bestModeIndex = modeIndex; if ( verbose ) { ri.Printf( PRINT_ALL, " -- OK\n", bestModeIndex ); } } if ( verbose ) { ri.Printf( PRINT_ALL, " bestModeIndex = %d\n", bestModeIndex ); } if ( bestModeIndex == 0xFFFFFFFF ) { ri.Printf( PRINT_ALL, "No suitable display mode available.\n" ); return nil; } return [displayModes objectAtIndex : bestModeIndex]; } #define MAX_DISPLAYS 128 void Sys_GetGammaTable( glwgamma_t *table ) { CGTableCount tableSize = 512; CGDisplayErr err; table->tableSize = tableSize; if ( table->red ) { free( table->red ); } table->red = malloc( tableSize * sizeof( *table->red ) ); if ( table->green ) { free( table->green ); } table->green = malloc( tableSize * sizeof( *table->green ) ); if ( table->blue ) { free( table->blue ); } table->blue = malloc( tableSize * sizeof( *table->blue ) ); // TJW: We _could_ loop here if we get back the same size as our table, increasing the table size. err = CGGetDisplayTransferByTable( table->display, tableSize, table->red, table->green, table->blue, &table->tableSize ); if ( err != CGDisplayNoErr ) { Com_Printf( "GLimp_Init: CGGetDisplayTransferByTable returned %d.\n", err ); table->tableSize = 0; } } void Sys_SetGammaTable( glwgamma_t *table ) { } void Sys_StoreGammaTables() { // Store the original gamma for all monitors so that we can fade and unfade them all CGDirectDisplayID displays[MAX_DISPLAYS]; CGDisplayCount displayIndex; CGDisplayErr err; err = CGGetActiveDisplayList( MAX_DISPLAYS, displays, &glw_state.displayCount ); if ( err != CGDisplayNoErr ) { Sys_Error( "Cannot get display list -- CGGetActiveDisplayList returned %d.\n", err ); } glw_state.originalDisplayGammaTables = calloc( glw_state.displayCount, sizeof( *glw_state.originalDisplayGammaTables ) ); for ( displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++ ) { glwgamma_t *table; table = &glw_state.originalDisplayGammaTables[displayIndex]; table->display = displays[displayIndex]; Sys_GetGammaTable( table ); } } // This isn't a mathematically correct fade, but we don't care that much. void Sys_SetScreenFade( glwgamma_t *table, float fraction ) { CGTableCount tableSize; CGGammaValue *red, *blue, *green; CGTableCount gammaIndex; if ( !glConfig.deviceSupportsGamma ) { return; } if ( !( tableSize = table->tableSize ) ) { // we couldn't get the table for this display for some reason return; } // Com_Printf("0x%08x %f\n", table->display, fraction); red = glw_state.tempTable.red; green = glw_state.tempTable.green; blue = glw_state.tempTable.blue; if ( glw_state.tempTable.tableSize < tableSize ) { glw_state.tempTable.tableSize = tableSize; red = realloc( red, sizeof( *red ) * tableSize ); green = realloc( green, sizeof( *green ) * tableSize ); blue = realloc( blue, sizeof( *blue ) * tableSize ); glw_state.tempTable.red = red; glw_state.tempTable.green = green; glw_state.tempTable.blue = blue; } for ( gammaIndex = 0; gammaIndex < table->tableSize; gammaIndex++ ) { red[gammaIndex] = table->red[gammaIndex] * fraction; blue[gammaIndex] = table->blue[gammaIndex] * fraction; green[gammaIndex] = table->green[gammaIndex] * fraction; } CGSetDisplayTransferByTable( table->display, table->tableSize, red, green, blue ); } // Fades all the active displays at the same time. #define FADE_DURATION 0.5 void Sys_FadeScreens() { CGDisplayCount displayIndex; int stepIndex; glwgamma_t *table; NSTimeInterval start, current; float time; if ( !glConfig.deviceSupportsGamma ) { return; } Com_Printf( "Fading all displays\n" ); start = [NSDate timeIntervalSinceReferenceDate]; time = 0.0; while ( time != FADE_DURATION ) { current = [NSDate timeIntervalSinceReferenceDate]; time = current - start; if ( time > FADE_DURATION ) { time = FADE_DURATION; } for ( displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++ ) { table = &glw_state.originalDisplayGammaTables[displayIndex]; Sys_SetScreenFade( table, 1.0 - time / FADE_DURATION ); } } } void Sys_FadeScreen( CGDirectDisplayID display ) { CGDisplayCount displayIndex; glwgamma_t *table; int stepIndex; if ( !glConfig.deviceSupportsGamma ) { return; } Com_Printf( "Fading display 0x%08x\n", display ); for ( displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++ ) { if ( display == glw_state.originalDisplayGammaTables[displayIndex].display ) { NSTimeInterval start, current; float time; start = [NSDate timeIntervalSinceReferenceDate]; time = 0.0; table = &glw_state.originalDisplayGammaTables[displayIndex]; while ( time != FADE_DURATION ) { current = [NSDate timeIntervalSinceReferenceDate]; time = current - start; if ( time > FADE_DURATION ) { time = FADE_DURATION; } Sys_SetScreenFade( table, 1.0 - time / FADE_DURATION ); } return; } } Com_Printf( "Unable to find display to fade it\n" ); } void Sys_UnfadeScreens() { CGDisplayCount displayIndex; int stepIndex; glwgamma_t *table; NSTimeInterval start, current; float time; if ( !glConfig.deviceSupportsGamma ) { return; } Com_Printf( "Unfading all displays\n" ); start = [NSDate timeIntervalSinceReferenceDate]; time = 0.0; while ( time != FADE_DURATION ) { current = [NSDate timeIntervalSinceReferenceDate]; time = current - start; if ( time > FADE_DURATION ) { time = FADE_DURATION; } for ( displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++ ) { table = &glw_state.originalDisplayGammaTables[displayIndex]; Sys_SetScreenFade( table, time / FADE_DURATION ); } } } void Sys_UnfadeScreen( CGDirectDisplayID display, glwgamma_t *table ) { CGDisplayCount displayIndex; int stepIndex; if ( !glConfig.deviceSupportsGamma ) { return; } Com_Printf( "Unfading display 0x%08x\n", display ); if ( table ) { CGTableCount i; Com_Printf( "Given table:\n" ); for ( i = 0; i < table->tableSize; i++ ) { Com_Printf( " %f %f %f\n", table->red[i], table->blue[i], table->green[i] ); } } // Search for the original gamma table for the display if ( !table ) { for ( displayIndex = 0; displayIndex < glw_state.displayCount; displayIndex++ ) { if ( display == glw_state.originalDisplayGammaTables[displayIndex].display ) { table = &glw_state.originalDisplayGammaTables[displayIndex]; break; } } } if ( table ) { NSTimeInterval start, current; float time; start = [NSDate timeIntervalSinceReferenceDate]; time = 0.0; while ( time != FADE_DURATION ) { current = [NSDate timeIntervalSinceReferenceDate]; time = current - start; if ( time > FADE_DURATION ) { time = FADE_DURATION; } Sys_SetScreenFade( table, time / FADE_DURATION ); } return; } Com_Printf( "Unable to find display to unfade it\n" ); }