diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index cfc4dafe..5ca07ef1 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2922,10 +2922,6 @@ void CL_InitLocal( void ) Cvar_RegisterVariable( &cl_maxframetime ); Cvar_RegisterVariable( &cl_fixmodelinterpolationartifacts ); - // these two added to shut up CS 1.5 about 'unknown' commands - Cvar_Get( "lightgamma", "1", FCVAR_ARCHIVE, "ambient lighting level (legacy, unused)" ); - Cvar_Get( "direct", "1", FCVAR_ARCHIVE, "direct lighting level (legacy, unused)" ); - // server commands Cmd_AddCommand ("noclip", NULL, "enable or disable no clipping mode" ); Cmd_AddCommand ("notarget", NULL, "notarget mode (monsters do not see you)" ); diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index 4004a305..5145d735 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -292,6 +292,8 @@ void SCR_MakeScreenShot( void ) viewsize = cls.envshot_viewsize; else viewsize = cl_envshot_size.value; + V_CheckGamma(); + switch( cls.scrshot_action ) { case scrshot_normal: diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index f3fa4ca3..79f0bf7f 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -347,6 +347,8 @@ qboolean V_PreRender( void ) return false; } + V_CheckGamma(); + ref.dllFuncs.R_BeginFrame( !cl.paused && ( cls.state == ca_active )); GL_UpdateSwapInterval( ); diff --git a/engine/client/gamma.c b/engine/client/gamma.c new file mode 100644 index 00000000..fc2490cb --- /dev/null +++ b/engine/client/gamma.c @@ -0,0 +1,214 @@ +/* +gamma.c - gamma routines +Copyright (C) 2011 Uncle Mike + +This program 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. + +This program 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. +*/ + +#include "common.h" +#include "client.h" +#include "xash3d_mathlib.h" +#include "enginefeatures.h" + +//----------------------------------------------------------------------------- +// Gamma conversion support +//----------------------------------------------------------------------------- +static byte texgammatable[256]; +static uint lightgammatable[1024]; +static uint lineargammatable[1024]; +static uint screengammatable[1024]; +static CVAR_DEFINE( v_direct, "direct", "0.9", 0, "direct studio lighting" ); +static CVAR_DEFINE( v_texgamma, "texgamma", "2.0", 0, "texgamma amount" ); +static CVAR_DEFINE( v_lightgamma, "lightgamma", "2.5", 0, "lightgamma amount" ); +static CVAR_DEFINE( v_brightness, "brightness", "0.0", FCVAR_ARCHIVE, "brightness factor" ); +static CVAR_DEFINE( v_gamma, "gamma", "2.5", FCVAR_ARCHIVE, "gamma amount" ); + +static void BuildGammaTable( const float gamma, const float brightness, const float texgamma, const float lightgamma ) +{ + float g1, g2, g3; + int i; + + if( gamma != 0.0 ) + g1 = 1.0 / gamma; + else g1 = 0.4; + + g2 = g1 * texgamma; + + if( brightness <= 0.0 ) + g3 = 0.125; + else if( brightness <= 1.0 ) + g3 = 0.125 - brightness * brightness * 0.075; + else + g3 = 0.05; + + for( i = 0; i < 256; i++ ) + { + double d = pow( i / 255.0, (double)g2 ); + int inf = d * 255.0; + texgammatable[i] = bound( 0, inf, 255 ); + } + + for( i = 0; i < 1024; i++ ) + { + double d; + float f = pow( i / 1023.0, (double)lightgamma ); + int inf; + + if( brightness > 1.0 ) + f *= brightness; + + if( f <= g3 ) + f = ( f / g3 ) * 0.125; + else + f = (( f - g3 ) / ( 1.0 - g3 )) * 0.875 + 0.125; + + d = pow( (double)f, (double)g1 ); // do not remove the cast, or tests fail + inf = d * 1023.0; + lightgammatable[i] = bound( 0, inf, 1023 ); + + // do these calculations in the same loop... + lineargammatable[i] = pow( i / 1023.0, (double)gamma ) * 1023.0; + screengammatable[i] = pow( i / 1023.0, 1.0 / gamma ) * 1023.0; + } +} + +static void V_ValidateGammaCvars( void ) +{ + if( Host_IsLocalGame( )) + return; + + if( v_gamma.value < 1.8f ) + Cvar_DirectSet( &v_gamma, "1.8" ); + else if( v_gamma.value > 3.0f ) + Cvar_DirectSet( &v_gamma, "3" ); + + if( v_texgamma.value < 1.8f ) + Cvar_DirectSet( &v_texgamma, "1.8" ); + else if( v_texgamma.value > 3.0f ) + Cvar_DirectSet( &v_texgamma, "3" ); + + if( v_lightgamma.value < 1.8f ) + Cvar_DirectSet( &v_lightgamma, "1.8" ); + else if( v_lightgamma.value > 3.0f ) + Cvar_DirectSet( &v_lightgamma, "3" ); + + if( v_brightness.value < 0.0f ) + Cvar_DirectSet( &v_brightness, "0" ); + else if( v_brightness.value > 2.0f ) + Cvar_DirectSet( &v_brightness, "2" ); +} + +void V_CheckGamma( void ) +{ + static qboolean dirty = false; + qboolean notify_refdll = false; + + // because these cvars were defined as archive + // but wasn't doing anything useful + // reset them into default values + // this might be removed after a while + if( v_direct.value == 1.0f || v_lightgamma.value == 1.0f ) + { + Cvar_DirectSet( &v_direct, "0.9" ); + Cvar_DirectSet( &v_lightgamma, "2.5" ); + } + + if( cls.scrshot_action == scrshot_envshot || cls.scrshot_action == scrshot_skyshot ) + { + dirty = true; // force recalculate next normal frame + BuildGammaTable( 1.8f, 0.0f, 2.0f, 2.5f ); + if( ref.initialized ) + ref.dllFuncs.R_GammaChanged( true ); + return; + } + + if( dirty || FBitSet( v_texgamma.flags|v_lightgamma.flags|v_brightness.flags|v_gamma.flags, FCVAR_CHANGED )) + { + V_ValidateGammaCvars(); + + dirty = false; + BuildGammaTable( v_gamma.value, v_brightness.value, v_texgamma.value, v_lightgamma.value ); + + // force refdll to recalculate lightmaps + notify_refdll = true; + + // unfortunately, recalculating textures isn't possible yet + ClearBits( v_texgamma.flags, FCVAR_CHANGED ); + ClearBits( v_lightgamma.flags, FCVAR_CHANGED ); + ClearBits( v_brightness.flags, FCVAR_CHANGED ); + ClearBits( v_gamma.flags, FCVAR_CHANGED ); + } + + if( notify_refdll && ref.initialized ) + ref.dllFuncs.R_GammaChanged( false ); +} + +void V_Init( void ) +{ + Cvar_RegisterVariable( &v_texgamma ); + Cvar_RegisterVariable( &v_lightgamma ); + Cvar_RegisterVariable( &v_brightness ); + Cvar_RegisterVariable( &v_gamma ); + Cvar_RegisterVariable( &v_direct ); + + // force gamma init + SetBits( v_gamma.flags, FCVAR_CHANGED ); + V_CheckGamma(); +} + +byte TextureToGamma( byte b ) +{ + if( FBitSet( host.features, ENGINE_LINEAR_GAMMA_SPACE )) + return b; + + return texgammatable[b]; +} + +byte LightToTexGamma( byte b ) +{ + if( FBitSet( host.features, ENGINE_LINEAR_GAMMA_SPACE )) + return b; + + // 255 << 2 is 1020, impossible to overflow + return lightgammatable[b << 2] >> 2; +} + +uint LightToTexGammaEx( uint b ) +{ + if( FBitSet( host.features, ENGINE_LINEAR_GAMMA_SPACE )) + return b; + + if( unlikely( b > ARRAYSIZE( lightgammatable ))) + return 0; + + return lightgammatable[b]; +} + +uint ScreenGammaTable( uint b ) +{ + if( FBitSet( host.features, ENGINE_LINEAR_GAMMA_SPACE )) + return b; + + if( unlikely( b > ARRAYSIZE( screengammatable ))) + return 0; + + return screengammatable[b]; +} + +uint LinearGammaTable( uint b ) +{ + if( FBitSet( host.features, ENGINE_LINEAR_GAMMA_SPACE )) + return b; + + if( unlikely( b > ARRAYSIZE( lineargammatable ))) + return 0; + return lineargammatable[b]; +} diff --git a/engine/client/ref_common.c b/engine/client/ref_common.c index f68519eb..89f1211b 100644 --- a/engine/client/ref_common.c +++ b/engine/client/ref_common.c @@ -178,25 +178,6 @@ static screenfade_t *pfnRefGetScreenFade( void ) return &clgame.fade; } -/* -=============== -R_DoResetGamma -gamma will be reset for -some type of screenshots -=============== -*/ -static qboolean R_DoResetGamma( void ) -{ - switch( cls.scrshot_action ) - { - case scrshot_envshot: - case scrshot_skyshot: - return true; - default: - return false; - } -} - static qboolean R_Init_Video_( const int type ) { host.apply_opengl_config = true; @@ -306,9 +287,11 @@ static ref_api_t gEngfuncs = SW_LockBuffer, SW_UnlockBuffer, - BuildGammaTable, LightToTexGamma, - R_DoResetGamma, + LightToTexGammaEx, + TextureToGamma, + ScreenGammaTable, + LinearGammaTable, CL_GetLightStyle, CL_GetDynamicLight, diff --git a/engine/client/vid_common.c b/engine/client/vid_common.c index 8038ff81..fcc29b92 100644 --- a/engine/client/vid_common.c +++ b/engine/client/vid_common.c @@ -22,8 +22,6 @@ GNU General Public License for more details. static CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" ); static CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" ); -static CVAR_DEFINE( vid_brightness, "brightness", "0.0", FCVAR_ARCHIVE, "brightness factor" ); -static CVAR_DEFINE( vid_gamma, "gamma", "2.5", FCVAR_ARCHIVE, "gamma amount" ); static CVAR_DEFINE_AUTO( vid_mode, "0", FCVAR_RENDERINFO, "current video mode index (used only for storage)" ); static CVAR_DEFINE_AUTO( vid_rotate, "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen rotation (0-3)" ); static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "pixel scale" ); @@ -36,19 +34,6 @@ CVAR_DEFINE( window_ypos, "_window_ypos", "-1", FCVAR_RENDERINFO, "window positi glwstate_t glw_state; -/* -================= -VID_StartupGamma -================= -*/ -void VID_StartupGamma( void ) -{ - BuildGammaTable( vid_gamma.value, vid_brightness.value ); - Con_Reportf( "VID_StartupGamma: gamma %g brightness %g\n", vid_gamma.value, vid_brightness.value ); - ClearBits( vid_brightness.flags, FCVAR_CHANGED ); - ClearBits( vid_gamma.flags, FCVAR_CHANGED ); -} - /* ================= VID_InitDefaultResolution @@ -224,8 +209,6 @@ void VID_Init( void ) Cvar_RegisterVariable( &vid_scale ); Cvar_RegisterVariable( &vid_fullscreen ); Cvar_RegisterVariable( &vid_maximized ); - Cvar_RegisterVariable( &vid_brightness ); - Cvar_RegisterVariable( &vid_gamma ); Cvar_RegisterVariable( &window_xpos ); Cvar_RegisterVariable( &window_ypos ); @@ -233,5 +216,6 @@ void VID_Init( void ) // but supported mode list is filled by backends, so numbers are not portable any more Cmd_AddRestrictedCommand( "vid_setmode", VID_Mode_f, "display video mode" ); + V_Init(); // init gamma R_Init(); // init renderer } diff --git a/engine/client/vid_common.h b/engine/client/vid_common.h index 1f052f43..fc0bc08e 100644 --- a/engine/client/vid_common.h +++ b/engine/client/vid_common.h @@ -46,6 +46,5 @@ void R_SaveVideoMode( int w, int h, int render_w, int render_h, qboolean maximiz void VID_SetDisplayTransform( int *render_w, int *render_h ); void VID_CheckChanges( void ); const char *VID_GetModeString( int vid_mode ); -void VID_StartupGamma( void ); #endif // VID_COMMON diff --git a/engine/common/common.h b/engine/common/common.h index f6a240e1..b73a66b2 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -812,8 +812,13 @@ void S_StopBackgroundTrack( void ); void S_StopAllSounds( qboolean ambient ); // gamma routines -void BuildGammaTable( float gamma, float brightness ); byte LightToTexGamma( byte b ); +byte TextureToGamma( byte ); +uint LightToTexGammaEx( uint ); +uint ScreenGammaTable( uint ); +uint LinearGammaTable( uint ); +void V_Init( void ); +void V_CheckGamma( void ); // // identification.c diff --git a/engine/common/gamma.c b/engine/common/gamma.c deleted file mode 100644 index aac4a6c4..00000000 --- a/engine/common/gamma.c +++ /dev/null @@ -1,78 +0,0 @@ -/* -gamma.c - gamma routines -Copyright (C) 2011 Uncle Mike - -This program 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. - -This program 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. -*/ - -#include "common.h" -#include "xash3d_mathlib.h" -#include "enginefeatures.h" - -//----------------------------------------------------------------------------- -// Gamma conversion support -//----------------------------------------------------------------------------- -static byte lightgammatable[256]; -static int lineargammatable[1024]; -static int screengammatable[1024]; - -void BuildGammaTable( float lightgamma, float brightness ) -{ - int i, inf; - float f, g, g1, g3; - - lightgamma = bound( 1.8f, lightgamma, 3.0f ); - brightness = bound( 0.0f, brightness, 10.0f ); - - if( brightness <= 0.0f ) - g3 = 0.125f; - else if( brightness > 1.0f ) - g3 = 0.05f; - else g3 = 0.125f - (brightness * brightness) * 0.075f; - - g = 1.0f / lightgamma; - g1 = GAMMA * g; - - for( i = 0; i < 256; i++ ) - { - f = pow( i / 255.f, GAMMA ); - - // scale up - if( brightness > 1.0f ) - f = f * brightness; - - // shift up - if( f <= g3 ) f = (f / g3) * 0.125f; - else f = 0.125f + ((f - g3) / (1.0f - g3)) * 0.875f; - - // convert linear space to desired gamma space - inf = (int)( 255.0f * pow( f, g )); - - lightgammatable[i] = bound( 0, inf, 255 ); - } - - for( i = 0; i < 1024; i++ ) - { - // convert from screen gamma space to linear space - lineargammatable[i] = 1023 * pow( i / 1023.0f, g1 ); - - // convert from linear gamma space to screen space - screengammatable[i] = 1023 * pow( i / 1023.0f, 1.0f / g1 ); - } -} - -byte LightToTexGamma( byte b ) -{ - if( FBitSet( host.features, ENGINE_LINEAR_GAMMA_SPACE )) - return b; - else - return lightgammatable[b]; -} diff --git a/engine/platform/dos/vid_dos.c b/engine/platform/dos/vid_dos.c index fe0ecf6a..833567ce 100644 --- a/engine/platform/dos/vid_dos.c +++ b/engine/platform/dos/vid_dos.c @@ -48,8 +48,6 @@ qboolean R_Init_Video( const int type ) { qboolean retval; - VID_StartupGamma(); - if( type != REF_SOFTWARE ) return false; /// glide??? diff --git a/engine/platform/linux/vid_fbdev.c b/engine/platform/linux/vid_fbdev.c index b6b0e16b..9a7e7aa0 100644 --- a/engine/platform/linux/vid_fbdev.c +++ b/engine/platform/linux/vid_fbdev.c @@ -51,8 +51,6 @@ qboolean R_Init_Video( const int type ) string fbdev = DEFAULT_FBDEV; fb.fd = -1; - VID_StartupGamma(); - if( type != REF_SOFTWARE ) return false; diff --git a/engine/platform/sdl/vid_sdl.c b/engine/platform/sdl/vid_sdl.c index 0a58353a..54ef7a89 100644 --- a/engine/platform/sdl/vid_sdl.c +++ b/engine/platform/sdl/vid_sdl.c @@ -843,13 +843,10 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode ) return false; GL_SetupAttributes(); // re-choose attributes } - - VID_StartupGamma(); } if( !GL_UpdateContext( )) - return false; - + return false; } #else // SDL_VERSION_ATLEAST( 2, 0, 0 ) diff --git a/engine/ref_api.h b/engine/ref_api.h index fbbefda6..4580522c 100644 --- a/engine/ref_api.h +++ b/engine/ref_api.h @@ -42,7 +42,8 @@ GNU General Public License for more details. // 6. Removed timing from ref_globals_t. // Renderers are supposed to migrate to ref_client_t/ref_host_t using PARM_GET_CLIENT_PTR and PARM_GET_HOST_PTR // Removed functions to get internal engine structions. Use PARM_GET_*_PTR instead. -#define REF_API_VERSION 6 +// 7. Gamma fixes. +#define REF_API_VERSION 7 #define TF_SKY (TF_SKYSIDE|TF_NOMIPMAP) @@ -404,9 +405,11 @@ typedef struct ref_api_s void (*SW_UnlockBuffer)( void ); // gamma - void (*BuildGammaTable)( float lightgamma, float brightness ); - byte (*LightToTexGamma)( byte color ); // software gamma support - qboolean (*R_DoResetGamma)( void ); + byte (*LightToTexGamma)( byte ); // software gamma support + uint (*LightToTexGammaEx)( uint ); // software gamma support + byte (*TextureToGamma)( byte ); + uint (*ScreenGammaTable)( uint ); + uint (*LinearGammaTable)( uint ); // renderapi lightstyle_t* (*GetLightStyle)( int number ); @@ -652,6 +655,8 @@ typedef int (*REFAPI)( int version, ref_interface_t *pFunctionTable, ref_api_t* #define ENGINE_SHARED_CVAR_LIST( f ) \ ENGINE_SHARED_CVAR_NAME( f, vid_gamma, gamma ) \ ENGINE_SHARED_CVAR_NAME( f, vid_brightness, brightness ) \ + ENGINE_SHARED_CVAR_NAME( f, v_lightgamma, lightgamma ) \ + ENGINE_SHARED_CVAR_NAME( f, v_direct, direct ) \ ENGINE_SHARED_CVAR( f, r_showtextures ) \ ENGINE_SHARED_CVAR( f, r_speeds ) \ ENGINE_SHARED_CVAR( f, r_fullbright ) \