//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=====================================================================================// #include #include "mathlib/bumpvects.h" #include "colorspace.h" #include "materialsystem_global.h" #include "IHardwareConfigInternal.h" #include "materialsystem/materialsystem_config.h" // NOTE: This has to be the last file included #include "tier0/memdbgon.h" //static float texLightToLinear[256]; // texlight (0..255) to linear (0..4) static float textureToLinear[256]; // texture (0..255) to linear (0..1) static int linearToTexture[1024]; // linear (0..1) to texture (0..255) static int linearToScreen[1024]; // linear (0..1) to gamma corrected vertex light (0..255) float g_LinearToVertex[4096]; // linear (0..4) to screen corrected vertex space (0..1?) static int linearToLightmap[4096]; // linear (0..4) to screen corrected texture value (0..255) void ColorSpace::SetGamma( float screenGamma, float texGamma, float overbright, bool allowCheats, bool linearFrameBuffer ) { int i, inf; float g1, g3; float g; float brightness = 0.0f; // This used to be configurable. . hardcode to 0.0 if( linearFrameBuffer ) { screenGamma = 1.0f; } g = screenGamma; // clamp values to prevent cheating in multiplayer if( !allowCheats ) { if (brightness > 2.0f) brightness = 2.0f; if (g < 1.8f) g = 1.8f; } if (g > 3.0) g = 3.0; g = 1.0f / g; g1 = texGamma * g; // pow( textureColor, g1 ) converts from on-disk texture space to framebuffer space if (brightness <= 0.0f) { g3 = 0.125; } else if (brightness > 1.0f) { g3 = 0.05f; } else { g3 = 0.125f - (brightness * brightness) * 0.075f; } for (i=0 ; i<1024 ; i++) { float f; f = i / 1023.0f; // 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 * pow ( f, g ) ); if (inf < 0) inf = 0; if (inf > 255) inf = 255; linearToScreen[i] = inf; } for (i=0 ; i<256 ; i++) { // convert from nonlinear texture space (0..255) to linear space (0..1) textureToLinear[i] = ( float )pow( i / 255.0f, texGamma ); } for (i=0 ; i<1024 ; i++) { // convert from linear space (0..1) to nonlinear texture space (0..255) linearToTexture[i] = ( int )( pow( i / 1023.0f, 1.0f / texGamma ) * 255 ); } #if 0 for (i=0 ; i<256 ; i++) { float f; // convert from nonlinear lightmap space (0..255) to linear space (0..4) f = ( float )( (i / 255.0f) * sqrt( 4 ) ); f = f * f; texLightToLinear[i] = f; } #endif float f, overbrightFactor; // Can't do overbright without texcombine // UNDONE: Add GAMMA ramp to rectify this if ( !HardwareConfig() ) { overbright = 1.0f; } if ( overbright == 2.0 ) { overbrightFactor = 0.5; } else if ( overbright == 4.0 ) { overbrightFactor = 0.25; } else { overbrightFactor = 1.0; } for (i=0 ; i<4096 ; i++) { // convert from linear 0..4 (x1024) to screen corrected vertex space (0..1?) f = ( float )pow ( i/1024.0f, 1.0f / screenGamma ); g_LinearToVertex[i] = f * overbrightFactor; if (g_LinearToVertex[i] > 1) g_LinearToVertex[i] = 1; linearToLightmap[i] = ( int )( f * 255 * overbrightFactor ); if (linearToLightmap[i] > 255) linearToLightmap[i] = 255; } } // convert texture to linear 0..1 value float ColorSpace::TextureToLinear( int c ) { if (c < 0) return 0; if (c > 255) return 1.0f; return textureToLinear[c]; } // convert texture to linear 0..1 value int ColorSpace::LinearToTexture( float f ) { int i; i = ( int )( f * 1023.0f ); // assume 0..1 range if (i < 0) i = 0; if (i > 1023) i = 1023; return linearToTexture[i]; } float ColorSpace::TexLightToLinear( int c, int exponent ) { // return texLightToLinear[ c ]; // optimize me return ( float )c * ( float )pow( 2.0f, exponent ) * ( 1.0f / 255.0f ); } // converts 0..1 linear value to screen gamma (0..255) int ColorSpace::LinearToScreenGamma( float f ) { int i; i = ( int )( f * 1023.0f ); // assume 0..1 range if (i < 0) i = 0; if (i > 1023) i = 1023; return linearToScreen[i]; } uint16 ColorSpace::LinearFloatToCorrectedShort( float in ) { uint16 out; in = MIN( in * 4096.0, 65535.0 ); out = (uint16) MAX( in, 0.0f ); return out; }