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