diff --git a/src.cmake b/src.cmake index 4d3d2b5f7b..c9e042126a 100644 --- a/src.cmake +++ b/src.cmake @@ -158,6 +158,7 @@ set(GLSLSOURCELIST ${ENGINE_DIR}/renderer/glsl_source/blur_vp.glsl ${ENGINE_DIR}/renderer/glsl_source/cameraEffects_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/cameraEffects_vp.glsl + ${ENGINE_DIR}/renderer/glsl_source/colorSpace.glsl ${ENGINE_DIR}/renderer/glsl_source/computeLight_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/contrast_fp.glsl ${ENGINE_DIR}/renderer/glsl_source/contrast_vp.glsl diff --git a/src/common/Color.h b/src/common/Color.h index 8c98ebc74c..5b46c947ef 100644 --- a/src/common/Color.h +++ b/src/common/Color.h @@ -38,6 +38,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Compiler.h" #include "Math.h" +#define convertFromSRGB( v ) v <= 0.04045f ? v * (1.0f / 12.92f) : pow((v + 0.055f) * (1.0f / 1.055f), 2.4f) + namespace Color { /* @@ -256,6 +258,20 @@ class BasicColor data_[ 3 ] = v; } + CONSTEXPR_FUNCTION_RELAXED component_type ConvertFromSRGB( component_type v ) NOEXCEPT + { + float f = float( v ) / 255.0f; + f = convertFromSRGB( f ); + return component_type( f * 255 ); + } + + CONSTEXPR_FUNCTION_RELAXED void ConvertFromSRGB() NOEXCEPT + { + SetRed( ConvertFromSRGB( Red() ) ); + SetGreen( ConvertFromSRGB( Green() ) ); + SetBlue( ConvertFromSRGB( Blue() ) ); + } + CONSTEXPR_FUNCTION_RELAXED BasicColor& operator*=( float factor ) NOEXCEPT { *this = *this * factor; diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 18c4520811..03b0c85575 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -157,6 +157,9 @@ void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, boo Tess_ComputeColor( pStage ); gl_genericShaderMaterial->SetUniform_Color( tess.svars.color ); + // u_LinearizeTexture + gl_genericShaderMaterial->SetUniform_LinearizeTexture( pStage->linearizeTexture ); + bool hasDepthFade = pStage->hasDepthFade; if ( hasDepthFade ) { gl_genericShaderMaterial->SetUniform_DepthScale( pStage->depthFadeValue ); @@ -190,6 +193,9 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, // u_AlphaThreshold gl_lightMappingShaderMaterial->SetUniform_AlphaTest( pStage->stateBits ); + // u_LinearizeTexture + gl_lightMappingShaderMaterial->SetUniform_LinearizeTexture( pStage->linearizeTexture ); + // HeightMap if ( pStage->enableReliefMapping ) { float depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_reliefDepthScale->value ); @@ -267,6 +273,9 @@ void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, gl_skyboxShaderMaterial->SetUniform_AlphaTest( GLS_ATEST_NONE ); gl_skyboxShaderMaterial->WriteUniformsToBuffer( materials ); + + // u_LinearizeTexture + gl_skyboxShaderMaterial->SetUniform_LinearizeTexture( pStage->linearizeTexture ); } void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { @@ -359,6 +368,8 @@ void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, boo materials += pStage->bufferOffset; gl_fogQuake3ShaderMaterial->WriteUniformsToBuffer( materials ); + + gl_fogQuake3ShaderMaterial->SetUniform_LinearizeTexture( tr.worldLinearizeTexture ); } /* diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 058ca81543..597acd1c9f 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -802,6 +802,11 @@ static std::string GenEngineConstants() { AddConst( str, "r_RimExponent", r_rimExponent->value ); } + if ( r_cheapSRGB.Get() ) + { + AddDefine( str, "r_cheapSRGB", 1 ); + } + if ( r_showLightTiles->integer ) { AddDefine( str, "r_showLightTiles", 1 ); @@ -2261,6 +2266,7 @@ GLShader_generic::GLShader_generic( GLShaderManager *manager ) : u_AlphaThreshold( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), + u_LinearizeTexture( this ), u_ColorModulateColorGen( this ), u_Color( this ), u_Bones( this ), @@ -2293,6 +2299,7 @@ GLShader_genericMaterial::GLShader_genericMaterial( GLShaderManager* manager ) : u_AlphaThreshold( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), + u_LinearizeTexture( this ), u_ColorModulateColorGen( this ), u_Color( this ), u_DepthScale( this ), @@ -2334,6 +2341,7 @@ GLShader_lightMapping::GLShader_lightMapping( GLShaderManager *manager ) : u_ViewOrigin( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), + u_LinearizeTexture( this ), u_Bones( this ), u_VertexInterpolation( this ), u_ReliefDepthScale( this ), @@ -2402,6 +2410,7 @@ GLShader_lightMappingMaterial::GLShader_lightMappingMaterial( GLShaderManager* m u_ViewOrigin( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), + u_LinearizeTexture( this ), u_ReliefDepthScale( this ), u_ReliefOffsetBias( this ), u_NormalScale( this ), @@ -2712,6 +2721,7 @@ GLShader_skybox::GLShader_skybox( GLShaderManager *manager ) : u_CloudHeight( this ), u_UseCloudMap( this ), u_AlphaThreshold( this ), + u_LinearizeTexture( this ), u_ModelViewProjectionMatrix( this ) { } @@ -2730,6 +2740,7 @@ GLShader_skyboxMaterial::GLShader_skyboxMaterial( GLShaderManager* manager ) : u_CloudHeight( this ), u_UseCloudMap( this ), u_AlphaThreshold( this ), + u_LinearizeTexture( this ), u_ModelViewProjectionMatrix( this ) {} @@ -2743,6 +2754,7 @@ GLShader_fogQuake3::GLShader_fogQuake3( GLShaderManager *manager ) : u_FogMap( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), + u_LinearizeTexture( this ), u_ColorGlobal( this ), u_Bones( this ), u_VertexInterpolation( this ), @@ -2765,6 +2777,7 @@ GLShader_fogQuake3Material::GLShader_fogQuake3Material( GLShaderManager* manager u_FogMap( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), + u_LinearizeTexture( this ), u_ColorGlobal( this ), u_FogDistanceVector( this ), u_FogDepthVector( this ), @@ -2782,6 +2795,7 @@ GLShader_fogGlobal::GLShader_fogGlobal( GLShaderManager *manager ) : u_DepthMap( this ), u_ModelViewProjectionMatrix( this ), u_UnprojectMatrix( this ), + u_LinearizeTexture( this ), u_Color( this ), u_FogDistanceVector( this ) { @@ -2896,7 +2910,8 @@ GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) : u_ColorModulate( this ), u_TextureMatrix( this ), u_ModelViewProjectionMatrix( this ), - u_InverseGamma( this ) + u_InverseGamma( this ), + u_DelinearizeScreen( this ) { } diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index e75a0c6d59..831392eda1 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -2806,6 +2806,36 @@ class u_ShadowTexelSize : } }; +class u_LinearizeTexture : + GLUniform1i +{ +public: + u_LinearizeTexture( GLShader *shader ) : + GLUniform1i( shader, "u_LinearizeTexture" ) + { + } + + void SetUniform_LinearizeTexture( const int value ) + { + this->SetValue( value ); + } +}; + +class u_DelinearizeScreen : + GLUniform1i +{ +public: + u_DelinearizeScreen( GLShader *shader ) : + GLUniform1i( shader, "u_DelinearizeScreen" ) + { + } + + void SetUniform_DelinearizeScreen( const int value ) + { + this->SetValue( value ); + } +}; + class u_ShadowBlur : GLUniform1f { @@ -3834,6 +3864,7 @@ class GLShader_generic : public u_AlphaThreshold, public u_ModelMatrix, public u_ModelViewProjectionMatrix, + public u_LinearizeTexture, public u_ColorModulateColorGen, public u_Color, public u_Bones, @@ -3863,6 +3894,7 @@ class GLShader_genericMaterial : public u_AlphaThreshold, public u_ModelMatrix, public u_ModelViewProjectionMatrix, + public u_LinearizeTexture, public u_ColorModulateColorGen, public u_Color, public u_DepthScale, @@ -3901,6 +3933,7 @@ class GLShader_lightMapping : public u_ViewOrigin, public u_ModelMatrix, public u_ModelViewProjectionMatrix, + public u_LinearizeTexture, public u_Bones, public u_VertexInterpolation, public u_ReliefDepthScale, @@ -3952,6 +3985,7 @@ class GLShader_lightMappingMaterial : public u_ViewOrigin, public u_ModelMatrix, public u_ModelViewProjectionMatrix, + public u_LinearizeTexture, public u_ReliefDepthScale, public u_ReliefOffsetBias, public u_NormalScale, @@ -4195,6 +4229,7 @@ class GLShader_skybox : public u_CloudHeight, public u_UseCloudMap, public u_AlphaThreshold, + public u_LinearizeTexture, public u_ModelViewProjectionMatrix { public: @@ -4210,6 +4245,7 @@ class GLShader_skyboxMaterial : public u_CloudHeight, public u_UseCloudMap, public u_AlphaThreshold, + public u_LinearizeTexture, public u_ModelViewProjectionMatrix { public: GLShader_skyboxMaterial( GLShaderManager* manager ); @@ -4221,6 +4257,7 @@ class GLShader_fogQuake3 : public u_FogMap, public u_ModelMatrix, public u_ModelViewProjectionMatrix, + public u_LinearizeTexture, public u_ColorGlobal, public u_Bones, public u_VertexInterpolation, @@ -4241,6 +4278,7 @@ class GLShader_fogQuake3Material : public u_FogMap, public u_ModelMatrix, public u_ModelViewProjectionMatrix, + public u_LinearizeTexture, public u_ColorGlobal, public u_FogDistanceVector, public u_FogDepthVector, @@ -4257,6 +4295,7 @@ class GLShader_fogGlobal : public u_DepthMap, public u_ModelViewProjectionMatrix, public u_UnprojectMatrix, + public u_LinearizeTexture, public u_Color, public u_FogDistanceVector { @@ -4354,7 +4393,8 @@ class GLShader_cameraEffects : public u_ColorModulate, public u_TextureMatrix, public u_ModelViewProjectionMatrix, - public u_InverseGamma + public u_InverseGamma, + public u_DelinearizeScreen { public: GLShader_cameraEffects( GLShaderManager *manager ); diff --git a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl index e58b37bbd9..d798a36b04 100644 --- a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl +++ b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl @@ -22,8 +22,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* cameraEffects_fp.glsl */ +#insert colorSpace + uniform sampler2D u_CurrentMap; +uniform bool u_DelinearizeScreen; #if defined(r_colorGrading) uniform sampler3D u_ColorMap3D; #endif @@ -42,6 +45,8 @@ void main() vec4 color = texture2D(u_CurrentMap, st); + convertToSRGB(color.rgb, u_DelinearizeScreen); + color = clamp(color, 0.0, 1.0); #if defined(r_colorGrading) diff --git a/src/engine/renderer/glsl_source/colorSpace.glsl b/src/engine/renderer/glsl_source/colorSpace.glsl new file mode 100644 index 0000000000..884b24e620 --- /dev/null +++ b/src/engine/renderer/glsl_source/colorSpace.glsl @@ -0,0 +1,107 @@ +#define SRGB_MIX + +uniform int u_LinearizeTexture; + +void convertFromSRGB(inout vec3 color, in bool condition) { + if (condition) + { + #if defined(r_cheapSRGB) + float gamma = 2.2; + color = pow(color, vec3(gamma)); + + #elif defined(SRGB_NAIVE) + // (((c) <= 0.04045f) ? (c) * (1.0f / 12.92f) : (float)pow(((c) + 0.055f)*(1.0f/1.055f), 2.4f)) + + float threshold = 0.0031308f; + + color.r = color.r <= threshold ? color.r * (1.0f / 12.92f) : pow((color.r + 0.055f) * (1.0f / 1.055f), 2.4f); + color.g = color.g <= threshold ? color.g * (1.0f / 12.92f) : pow((color.g + 0.055f) * (1.0f / 1.055f), 2.4f); + color.b = color.b <= threshold ? color.b * (1.0f / 12.92f) : pow((color.b + 0.055f) * (1.0f / 1.055f), 2.4f); + #elif defined(SRGB_FBOOL) + float threshold = 0.0031308f; + + vec3 yes = vec3(float(color.r <= threshold), float(color.g <= threshold), float(color.b <= threshold)); + vec3 no = yes * -1.0f + 1.0f; + + vec3 low = color * (1.0f / 12.92f); + vec3 high = pow((color + 0.055f) * (1.0f / 1.055f), vec3(2.4f)); + + color = (yes * low) + (no * high); + #elif defined(SRGB_BOOL) + float threshold = 0.0031308f; + + bvec3 yes = bvec3(color.r <= threshold, color.g <= threshold, color.b <= threshold); + bvec3 no = bvec3(!yes.x, !yes.y, !yes.z); + + vec3 low = color * (1.0f / 12.92f); + vec3 high = pow((color + 0.055f) * (1.0f / 1.055f), vec3(2.4f)); + + color = (float(yes) * low) + (float(no) * high); + #elif defined(SRGB_MIX) + float threshold = 0.0031308f; + + bvec3 cutoff = lessThan(color, vec3(threshold)); + vec3 low = color / vec3(12.92f); + vec3 high = pow((color + vec3(0.055f)) / vec3(1.055f), vec3(2.4f)); + + color = mix(high, low, cutoff); + #else + #error undefined SRGB computation + #endif + } +} + +void convertFromSRGB(inout vec3 color, in int condition) { + convertFromSRGB(color, condition != 0); +} + +void convertToSRGB(inout vec3 color, in bool condition) { + if (condition) + { + #if defined(r_cheapSRGB) + float gamma = 2.2; + color = pow(color, vec3(1/gamma)); + #elif defined(SRGB_NAIVE) + // (((c) < 0.0031308f) ? (c) * 12.92f : 1.055f * (float)pow((c), 1.0f/2.4f) - 0.055f) + float threshold = 0.0031308f; + + color.r = color.r < threshold ? color.r * 12.92f : 1.055f * pow(color.r, 1.0f / 2.4f) - 0.055f; + color.g = color.g < threshold ? color.g * 12.92f : 1.055f * pow(color.g, 1.0f / 2.4f) - 0.055f; + color.b = color.b < threshold ? color.b * 12.92f : 1.055f * pow(color.b, 1.0f / 2.4f) - 0.055f; + #elif defined(SRGB_FBOOL) + float threshold = 0.0031308f; + + vec3 yes = vec3(float(color.r < threshold), float(color.g < threshold), float(color.b < threshold)); + vec3 no = yes * -1.0f + 1.0f; + + vec3 low = color * 12.92f; + vec3 high = pow(color, vec3(1.0f / 2.4f)) - 0.055f; + + color = (yes * low) + (no * high); + #elif defined(SRGB_BOOL) + float threshold = 0.0031308f; + + bvec3 yes = bvec3(color.r < threshold, color.g < threshold, color.b < threshold); + bvec3 no = bvec3(!yes.x, !yes.y, !yes.z); + + vec3 low = color * 12.92f; + vec3 high = pow(color, vec3(1.0f / 2.4f)) - 0.055f; + + color = (float(yes) * low) + (float(no) * high); + #elif defined(SRGB_MIX) + float threshold = 0.0031308f; + + bvec3 cutoff = lessThan(color, vec3(threshold)); + vec3 low = vec3(12.92f) * color; + vec3 high = vec3(1.055f) * pow(color, vec3(1.0f / 2.4f)) - vec3(0.055f); + + color = mix(high, low, cutoff); + #else + #error undefined SRGB computation + #endif + } +} + +void convertToSRGB(inout vec3 color, in int condition) { + convertToSRGB(color, condition != 0); +} diff --git a/src/engine/renderer/glsl_source/fogGlobal_fp.glsl b/src/engine/renderer/glsl_source/fogGlobal_fp.glsl index 24076a159b..8169df758d 100644 --- a/src/engine/renderer/glsl_source/fogGlobal_fp.glsl +++ b/src/engine/renderer/glsl_source/fogGlobal_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* fogGlobal_fp.glsl */ +#insert colorSpace + uniform sampler2D u_ColorMap; // fog texture uniform sampler2D u_DepthMap; @@ -52,5 +54,7 @@ void main() vec4 color = texture2D(u_ColorMap, st); + convertFromSRGB(color.rgb, u_LinearizeTexture); + outputColor = unpackUnorm4x8( u_Color ) * color; } diff --git a/src/engine/renderer/glsl_source/fogQuake3_fp.glsl b/src/engine/renderer/glsl_source/fogQuake3_fp.glsl index ab31ca9fb3..4581d19f53 100644 --- a/src/engine/renderer/glsl_source/fogQuake3_fp.glsl +++ b/src/engine/renderer/glsl_source/fogQuake3_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* fogQuake3_fp.glsl */ +#insert colorSpace + #define FOGQUAKE3_GLSL uniform sampler2D u_FogMap; @@ -40,6 +42,8 @@ void main() color *= var_Color; + convertFromSRGB(color.rgb, u_LinearizeTexture); + outputColor = color; #if 0 diff --git a/src/engine/renderer/glsl_source/generic_fp.glsl b/src/engine/renderer/glsl_source/generic_fp.glsl index 2de327152a..8d5bcd2612 100644 --- a/src/engine/renderer/glsl_source/generic_fp.glsl +++ b/src/engine/renderer/glsl_source/generic_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* generic_fp.glsl */ +#insert colorSpace + #define GENERIC_GLSL uniform sampler2D u_ColorMap; @@ -63,6 +65,10 @@ void main() return; } +#if !defined(GENERIC_2D) + convertFromSRGB(color.rgb, u_LinearizeTexture); +#endif + #if defined(USE_DEPTH_FADE) float depth = texture2D(u_DepthMap, gl_FragCoord.xy / r_FBufSize).x; float fadeDepth = 0.5 * var_FadeDepth.x / var_FadeDepth.y + 0.5; diff --git a/src/engine/renderer/glsl_source/lightMapping_fp.glsl b/src/engine/renderer/glsl_source/lightMapping_fp.glsl index 84af19f6ef..d066a335b0 100644 --- a/src/engine/renderer/glsl_source/lightMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_fp.glsl @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* lightMapping_fp.glsl */ #insert common +#insert colorSpace #insert computeLight_fp #insert reliefMapping_fp @@ -101,7 +102,7 @@ void main() vec4 diffuse = texture2D(u_DiffuseMap, texCoords); // Apply vertex blend operation like: alphaGen vertex. - diffuse *= var_Color; + diffuse.a *= var_Color.a; if(abs(diffuse.a + u_AlphaThreshold) <= 1.0) { @@ -109,6 +110,18 @@ void main() return; } + /* HACK: emulate three-bits bitfield + even: no color map linearization (first bit) + less than 2: no light map linearization (second bit) + positive: no material map linearization (extra bit) */ + bool linearizeColorMap = bool(u_LinearizeTexture % 2); + bool linearizeLightMap = abs(u_LinearizeTexture) > 1; + bool linearizeMaterialMap = u_LinearizeTexture < 0; + + convertFromSRGB(diffuse.rgb, linearizeColorMap); + + diffuse.rgb *= var_Color.rgb; + // Compute normal in world space from normalmap. #if defined(r_normalMapping) vec3 normal = NormalInWorldSpace(texCoords, tangentToWorldMatrix, u_NormalMap); @@ -119,6 +132,8 @@ void main() #if defined(r_specularMapping) || defined(r_physicalMapping) // Compute the material term. vec4 material = texture2D(u_MaterialMap, texCoords); + + convertFromSRGB(material.rgb, linearizeMaterialMap); #elif ( defined(r_realtimeLighting) && r_realtimeLightingRenderer == 1 )\ || defined( USE_DELUXE_MAPPING ) || defined(USE_GRID_DELUXE_MAPPING ) // The computeDynamicLights function requires this variable to exist. @@ -152,12 +167,22 @@ void main() vec3 lightColor = texture2D(u_LightMap, var_TexLight).rgb; lightColor *= lightFactor; + convertFromSRGB(lightColor, linearizeLightMap); + color.rgb = vec3(0.0); #else // Compute light color from lightgrid. vec3 ambientColor, lightColor; ReadLightGrid(texture3D(u_LightGrid1, lightGridPos), lightFactor, ambientColor, lightColor); + #if defined(r_cheapSRGB) + /* The light grid conversion from sRGB is done in C++ code + when loading it, meaning it's done before interpolation. */ + #else + convertFromSRGB(lightColor, linearizeLightMap); + convertFromSRGB(ambientColor, linearizeLightMap); + #endif + color.rgb = ambientColor * r_AmbientScale * diffuse.rgb; #endif @@ -215,6 +240,8 @@ void main() // Blend glow map. vec3 glow = texture2D(u_GlowMap, texCoords).rgb; + convertFromSRGB(glow, linearizeColorMap); + color.rgb += glow; #endif diff --git a/src/engine/renderer/glsl_source/skybox_fp.glsl b/src/engine/renderer/glsl_source/skybox_fp.glsl index 4a4bd38250..d199383bbd 100644 --- a/src/engine/renderer/glsl_source/skybox_fp.glsl +++ b/src/engine/renderer/glsl_source/skybox_fp.glsl @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA /* skybox_fp.glsl */ +#insert colorSpace + #define SKYBOX_GLSL const float radiusWorld = 4096.0; // Value used by quake 3 skybox code @@ -78,5 +80,7 @@ void main() return; } + convertFromSRGB(color.rgb, u_LinearizeTexture); + outputColor = color; } diff --git a/src/engine/renderer/shaders.cpp b/src/engine/renderer/shaders.cpp index 01951f06c7..c0fa084350 100644 --- a/src/engine/renderer/shaders.cpp +++ b/src/engine/renderer/shaders.cpp @@ -10,6 +10,7 @@ #include "blur_vp.glsl.h" #include "cameraEffects_fp.glsl.h" #include "cameraEffects_vp.glsl.h" +#include "colorSpace.glsl.h" #include "computeLight_fp.glsl.h" #include "contrast_fp.glsl.h" #include "contrast_vp.glsl.h" @@ -72,6 +73,7 @@ std::unordered_map shadermap({ { "cameraEffects_fp.glsl", std::string(reinterpret_cast(cameraEffects_fp_glsl), sizeof(cameraEffects_fp_glsl)) }, { "cameraEffects_vp.glsl", std::string(reinterpret_cast(cameraEffects_vp_glsl), sizeof(cameraEffects_vp_glsl)) }, { "computeLight_fp.glsl", std::string(reinterpret_cast(computeLight_fp_glsl), sizeof(computeLight_fp_glsl)) }, + { "colorSpace.glsl", std::string(reinterpret_cast(colorSpace_glsl), sizeof(colorSpace_glsl)) }, { "contrast_fp.glsl", std::string(reinterpret_cast(contrast_fp_glsl), sizeof(contrast_fp_glsl)) }, { "contrast_vp.glsl", std::string(reinterpret_cast(contrast_vp_glsl), sizeof(contrast_vp_glsl)) }, { "common.glsl", std::string( reinterpret_cast< const char* >( common_glsl ), sizeof( common_glsl ) ) }, diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 72c040ab27..5d8f35cabf 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -2980,6 +2980,9 @@ void RB_RenderGlobalFog() // go back to the world modelview matrix backEnd.orientation = backEnd.viewParms.world; + // u_LinearizeTexture + gl_fogGlobalShader->SetUniform_LinearizeTexture( tr.worldLinearizeTexture ); + { fog_t *fog; @@ -3328,6 +3331,9 @@ void RB_CameraPostFX() // enable shader, set arrays gl_cameraEffectsShader->BindProgram( 0 ); + // u_DelinearizeScreen + gl_cameraEffectsShader->SetUniform_DelinearizeScreen( tr.worldLinearizeTexture ); + gl_cameraEffectsShader->SetUniform_ColorModulate( backEnd.viewParms.gradingWeights ); gl_cameraEffectsShader->SetUniform_InverseGamma( 1.0 / r_gamma->value ); diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index be7529506f..65d8d890ac 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -1027,6 +1027,10 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf, in cv->verts[ i ].lightColor = Color::Adapt( verts[ i ].color ); + if ( tr.worldLinearizeLightMap ) + { + cv->verts[ i ].lightColor.ConvertFromSRGB(); + } if ( tr.legacyOverBrightClamping ) { @@ -4150,6 +4154,20 @@ void R_LoadLightGrid( lump_t *l ) { ambientColor[ j ] = tmpAmbient[ j ] * ( 1.0f / 255.0f ); directedColor[ j ] = tmpDirected[ j ] * ( 1.0f / 255.0f ); + + if ( tr.worldLinearizeLightMap ) + { + if ( r_cheapSRGB.Get() ) + { + ambientColor[ j ] = convertFromSRGB( ambientColor[ j ] ); + directedColor[ j ] = convertFromSRGB( directedColor[ j ] ); + } + else + { + /* When not cheap, the light grid conversion from sRGB is done + in GLSL code after interpolation. */ + } + } } // standard spherical coordinates to cartesian coordinates conversion @@ -4283,6 +4301,13 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities ) p = w->entityString; + bool hasMapOverBrightBits = false; + int mapOverBrightBits = 0; + + bool hasSRGBtex = false; + bool hasSRGBcolor = false; + bool hasSRGBlight = false; + // only parse the world spawn while ( true ) { @@ -4385,7 +4410,8 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities ) // check for mapOverBrightBits override if ( !Q_stricmp( keyname, "mapOverBrightBits" ) ) { - tr.mapOverBrightBits = Math::Clamp( atof( value ), 0.0, 3.0 ); + hasMapOverBrightBits = true; + mapOverBrightBits = Math::Clamp( atof( value ), 0.0, 3.0 ); continue; } @@ -4420,6 +4446,54 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities ) tr.worldDeluxeMapping = glConfig2.deluxeMapping; } + s = strstr( value, "-sRGB" ); + + if ( s && ( s[5] == ' ' || s[5] == '\0' ) ) + { + hasSRGBtex = true; + hasSRGBcolor = true; + hasSRGBlight = true; + } + + s = strstr( value, "-nosRGB" ); + + if ( s && ( s[5] == ' ' || s[5] == '\0' ) ) + { + hasSRGBtex = false; + hasSRGBcolor = false; + hasSRGBlight = true; + } + + if ( strstr( value, "-sRGBlight" ) ) + { + hasSRGBlight = true; + } + + if ( strstr( value, "-nosRGBlight" ) ) + { + hasSRGBlight = false; + } + + if ( strstr( value, "-sRGBcolor" ) ) + { + hasSRGBcolor = true; + } + + if ( strstr( value, "-nosRGBcolor" ) ) + { + hasSRGBcolor = false; + } + + if ( strstr( value, "-sRGBtex" ) ) + { + hasSRGBtex = true; + } + + if ( strstr( value, "-nosRGBtex" ) ) + { + hasSRGBtex = false; + } + continue; } @@ -4437,6 +4511,87 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities ) continue; } } + + /* These are the values expected by the rest of the renderer + (esp. tr_bsp), used for "gamma correction of the map". + Both were set to 0 if we had neither COMPAT_ET nor COMPAT_Q3, + it may be interesting to remember. + + Quake 3 and Tremulous values: + + tr.overbrightBits = 1; + tr.mapOverBrightBits = 2; + tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); + + Wolfenstein: Enemy Territory values: + + tr.overbrightBits = 0; + tr.mapOverBrightBits = 2; + tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); + + Games like Quake 3 and Tremulous require tr.mapOverBrightBits + to be set to 2. Because this engine is primarily maintained for + Unvanquished and needs to keep compatibility with legacy Tremulous + maps, this value is set to 2. + + Games like True Combat: Elite (Wolf:ET mod) or Urban Terror 4 + (Quake 3 mod) require tr.mapOverBrightBits to be set to 0. + + The mapOverBrightBits value will be read as map entity key + by R_LoadEntities() in tr_bsp, making possible to override + the default value and properly render a map with another + value than the default one. + + If this key is missing in map entity lump, there is no way + to know the required value for mapOverBrightBits when loading + a BSP, one may rely on arena files to do some guessing when + loading foreign maps and games ported to the Dæmon engine may + require to set a different default than what Unvanquished + requires. + + Using a non-zero value for tr.mapOverBrightBits turns light + non-linear and makes deluxe mapping buggy though. + + Mappers may port and fix maps by multiplying the lights by 2.5 + and set the mapOverBrightBits key to 0 in map entities lump. + + In legacy engines, tr.overbrightBits was non-zero when + hardware overbright bits were enabled, zero when disabled. + This engine do not implement hardware overbright bit, so + this is always zero, and we can remove it and simplify all + the computations making use of it. + + Because tr.overbrightBits is always 0, tr.identityLight is + always 1.0f. We can entirely remove it. */ + + if ( hasSRGBlight ) + { + Log::Debug("map features lights in sRGB colorspace" ); + tr.worldLinearizeLightMap = true; + } + + if ( hasSRGBcolor && hasSRGBtex ) + { + Log::Debug("map features lights computed with linear colors and textures" ); + tr.worldLinearizeTexture = true; + + /* The forceLegacyMapOverBrightClamping is only compatible and purposed + for legacy maps without color linearization. */ + tr.legacyOverBrightClamping = false; + + tr.mapOverBrightBits = r_overbrightDefaultLinearExponent.Get(); + } + else + { + tr.legacyOverBrightClamping = r_overbrightDefaultLegacyClamp.Get(); + + tr.mapOverBrightBits = r_overbrightDefaultLegacyExponent.Get(); + } + + if ( !r_overbrightIgnoreMapSettings.Get() && hasMapOverBrightBits ) + { + tr.mapOverBrightBits = mapOverBrightBits; + } } /* @@ -5091,6 +5246,8 @@ void RE_LoadWorldMap( const char *name ) // tr.worldDeluxeMapping will be set by R_LoadEntities() tr.worldDeluxeMapping = false; tr.worldHDR_RGBE = false; + tr.worldLinearizeTexture = false; + tr.worldLinearizeLightMap = false; s_worldData = {}; Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) ); diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 381265293a..5a2b5952ce 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -3054,68 +3054,6 @@ void R_InitImages() tr.lightmaps.reserve( 128 ); tr.deluxemaps.reserve( 128 ); - /* These are the values expected by the rest of the renderer - (esp. tr_bsp), used for "gamma correction of the map". - Both were set to 0 if we had neither COMPAT_ET nor COMPAT_Q3, - it may be interesting to remember. - - Quake 3 and Tremulous values: - - tr.overbrightBits = 0; // Software implementation. - tr.mapOverBrightBits = 2; // Quake 3 default. - tr.identityLight = 1.0f / ( 1 << tr.overbrightBits ); - - Games like Quake 3 and Tremulous require tr.mapOverBrightBits - to be set to 2. Because this engine is primarily maintained for - Unvanquished and needs to keep compatibility with legacy Tremulous - maps, this value is set to 2. - - Games like True Combat: Elite (Wolf:ET mod) or Urban Terror 4 - (Quake 3 mod) require tr.mapOverBrightBits to be set to 0. - - For some reasons the Wolf:ET engine sets this to 0 by default - but the game sets it to 2 (and requires it to be 2 for maps - looking as expected). - - The mapOverBrightBits value will be read as map entity key - by R_LoadEntities() in tr_bsp, making possible to override - the default value and properly render a map with another - value than the default one. - - If this key is missing in map entity lump, there is no way - to know the required value for mapOverBrightBits when loading - a BSP, one may rely on arena files to do some guessing when - loading foreign maps and games ported to the Dæmon engine may - require to set a different default than what Unvanquished - requires. - - Using a non-zero value for tr.mapOverBrightBits turns light - non-linear and makes deluxe mapping buggy though. - - Mappers may port and fix maps by multiplying the lights by 2.5 - and set the mapOverBrightBits key to 0 in map entities lump. - - It will be possible to assume tr.mapOverBrightBits is 0 when - loading maps compiled with sRGB lightmaps as there is no - legacy map using sRGB lightmap yet, and then we will be - able to avoid the need to explicitly set mapOverBrightBits - to 0 in map entities. It will be required to assume that - tr.mapOverBrightBits is 0 when loading maps compiled with - sRGB lightmaps because otherwise the color shift computation - will break the light computation, not only the deluxe one. - - In legacy engines, tr.overbrightBits was non-zero when - hardware overbright bits were enabled, zero when disabled. - This engine do not implement hardware overbright bit, so - this is always zero, and we can remove it and simplify all - the computations making use of it. - - Because tr.overbrightBits is always 0, tr.identityLight is - always 1.0f. We can entirely remove it. */ - - tr.mapOverBrightBits = r_overbrightDefaultExponent.Get(); - tr.legacyOverBrightClamping = r_overbrightDefaultClamp.Get(); - // create default texture and white texture R_CreateBuiltinImages(); } diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index ae01cd72f6..eeee9a543c 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -92,9 +92,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::NONE, 4, 1, MAX_REF_LIGHTS / 16 ); cvar_t *r_realtimeLightingCastShadows; cvar_t *r_precomputedLighting; - Cvar::Cvar r_overbrightDefaultExponent("r_overbrightDefaultExponent", "default map light color shift (multiply by 2^x)", Cvar::NONE, 2); - Cvar::Cvar r_overbrightDefaultClamp("r_overbrightDefaultClamp", "clamp lightmap colors to 1 (in absence of map worldspawn value)", Cvar::NONE, false); - Cvar::Cvar r_overbrightIgnoreMapSettings("r_overbrightIgnoreMapSettings", "force usage of r_overbrightDefaultClamp / r_overbrightDefaultExponent, ignoring worldspawn", Cvar::NONE, false); + Cvar::Cvar r_overbrightDefaultLegacyExponent("r_overbrightDefaultLegacyExponent", "default map light color shift for legacy maps (multiply by 2^x)", Cvar::NONE, 2); + Cvar::Cvar r_overbrightDefaultLinearExponent("r_overbrightDefaultLinearExponent", "default map light color shift for maps with linear colorspace (multiply by 2^x)", Cvar::NONE, 1); + Cvar::Cvar r_overbrightDefaultLegacyClamp("r_overbrightDefaultLegacyClamp", "clamp legacy lightmap colors to 1 (in absence of map worldspawn value)", Cvar::NONE, false); + Cvar::Cvar r_overbrightIgnoreMapSettings("r_overbrightIgnoreMapSettings", "force usage of r_overbrightDefaultLegacyClamp / r_overbrightDefaultLegacyExponent / r_overbrightDefaultLinearExponent, ignoring worldspawn", Cvar::NONE, false); Cvar::Range> r_lightMode("r_lightMode", "lighting mode: 0: fullbright (cheat), 1: vertex light, 2: grid light (cheat), 3: light map", Cvar::NONE, Util::ordinal(lightMode_t::MAP), Util::ordinal(lightMode_t::FULLBRIGHT), Util::ordinal(lightMode_t::MAP)); Cvar::Cvar r_colorGrading( "r_colorGrading", "Use color grading", Cvar::NONE, true ); Cvar::Cvar r_preferBindlessTextures( "r_preferBindlessTextures", "use bindless textures even when material system is off", Cvar::NONE, false ); @@ -203,6 +204,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvar_t *r_rimExponent; Cvar::Cvar r_highPrecisionRendering("r_highPrecisionRendering", "use high precision frame buffers for rendering and blending", Cvar::NONE, true); + Cvar::Cvar r_cheapSRGB("r_cheapSRGB", "use cheap sRGB computation when converting images", Cvar::NONE, false); cvar_t *r_gamma; cvar_t *r_lockpvs; @@ -1168,8 +1170,9 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_subdivisions = Cvar_Get( "r_subdivisions", "4", CVAR_LATCH ); r_realtimeLightingCastShadows = Cvar_Get( "r_realtimeLightingCastShadows", "1", 0 ); r_precomputedLighting = Cvar_Get( "r_precomputedLighting", "1", CVAR_CHEAT | CVAR_LATCH ); - Cvar::Latch( r_overbrightDefaultExponent ); - Cvar::Latch( r_overbrightDefaultClamp ); + Cvar::Latch( r_overbrightDefaultLegacyExponent ); + Cvar::Latch( r_overbrightDefaultLinearExponent ); + Cvar::Latch( r_overbrightDefaultLegacyClamp ); Cvar::Latch( r_overbrightIgnoreMapSettings ); Cvar::Latch( r_lightMode ); Cvar::Latch( r_colorGrading ); @@ -1290,6 +1293,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p AssertCvarRange( r_rimExponent, 0.5, 8.0, false ); Cvar::Latch( r_highPrecisionRendering ); + Cvar::Latch( r_cheapSRGB ); r_drawBuffer = Cvar_Get( "r_drawBuffer", "GL_BACK", CVAR_CHEAT ); r_lockpvs = Cvar_Get( "r_lockpvs", "0", CVAR_CHEAT ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 201f142a0a..2fc17085f2 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1123,6 +1123,7 @@ enum class shaderProfilerRenderSubGroupsMode { bool dpMaterial; + int linearizeTexture; // Core renderer (code path for when only OpenGL Core is available, or compatible OpenGL 2). stageRenderer_t colorRenderer; @@ -2731,6 +2732,8 @@ enum class shaderProfilerRenderSubGroupsMode { bool worldLightMapping; bool worldDeluxeMapping; bool worldHDR_RGBE; + bool worldLinearizeTexture; + bool worldLinearizeLightMap; lightMode_t lightMode; lightMode_t worldLight; @@ -2826,7 +2829,7 @@ enum class shaderProfilerRenderSubGroupsMode { viewParms_t viewParms; - // r_overbrightDefaultExponent, but can be overridden by mapper using the worldspawn + // r_overbrightDefault[Linear/Legacy]Exponent, but can be overridden by mapper using the worldspawn int mapOverBrightBits; // pow(2, mapOverbrightBits) float mapLightFactor; @@ -2956,8 +2959,9 @@ enum class shaderProfilerRenderSubGroupsMode { extern Cvar::Range> r_realtimeLightLayers; extern cvar_t *r_realtimeLightingCastShadows; extern cvar_t *r_precomputedLighting; - extern Cvar::Cvar r_overbrightDefaultExponent; - extern Cvar::Cvar r_overbrightDefaultClamp; + extern Cvar::Cvar r_overbrightDefaultLinearExponent; + extern Cvar::Cvar r_overbrightDefaultLegacyExponent; + extern Cvar::Cvar r_overbrightDefaultLegacyClamp; extern Cvar::Cvar r_overbrightIgnoreMapSettings; extern Cvar::Range> r_lightMode; extern Cvar::Cvar r_colorGrading; @@ -3025,6 +3029,7 @@ enum class shaderProfilerRenderSubGroupsMode { extern cvar_t *r_rimExponent; extern Cvar::Cvar r_highPrecisionRendering; + extern Cvar::Cvar r_cheapSRGB; extern cvar_t *r_logFile; // number of frames to emit GL logs diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index aa02565b4a..d30f939221 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -334,6 +334,14 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit light->l.color[ 1 ] = g; light->l.color[ 2 ] = b; + // Linearize dynamic lights. + if ( tr.worldLinearizeTexture ) + { + light->l.color[ 0 ] = convertFromSRGB( light->l.color[ 0 ] ); + light->l.color[ 1 ] = convertFromSRGB( light->l.color[ 1 ] ); + light->l.color[ 2 ] = convertFromSRGB( light->l.color[ 2 ] ); + } + light->l.inverseShadows = (flags & REF_INVERSE_DLIGHT) != 0; light->l.noShadows = !r_realtimeLightingCastShadows->integer && !light->l.inverseShadows; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 88891a0757..6fdd309c08 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -860,6 +860,9 @@ void Render_generic3D( shaderStage_t *pStage ) gl_genericShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); + // u_LinearizeTexture + gl_genericShader->SetUniform_LinearizeTexture( pStage->linearizeTexture ); + // u_Bones if ( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning ) { @@ -1033,6 +1036,9 @@ void Render_lightMapping( shaderStage_t *pStage ) gl_lightMappingShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); + // u_LinearizeTexture + gl_lightMappingShader->SetUniform_LinearizeTexture( pStage->linearizeTexture ); + if ( glConfig2.realtimeLighting && r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { @@ -1960,6 +1966,9 @@ void Render_skybox( shaderStage_t *pStage ) GL_BindToTMU( 0, pStage->bundle[TB_COLORMAP].image[0] ) ); + // u_LinearizeTexture + gl_skyboxShader->SetUniform_LinearizeTexture( pStage->linearizeTexture ); + // u_AlphaThreshold gl_skyboxShader->SetUniform_AlphaTest( GLS_ATEST_NONE ); @@ -2268,6 +2277,9 @@ void Render_fog( shaderStage_t* pStage ) gl_fogQuake3Shader->BindProgram( 0 ); + // u_LinearizeTexture + gl_fogQuake3Shader->SetUniform_LinearizeTexture( tr.worldLinearizeTexture ); + gl_fogQuake3Shader->SetUniform_FogDistanceVector( fogDistanceVector ); gl_fogQuake3Shader->SetUniform_FogDepthVector( fogDepthVector ); gl_fogQuake3Shader->SetUniform_FogEyeT( eyeT ); @@ -2422,6 +2434,11 @@ void Tess_ComputeColor( shaderStage_t *pStage ) { rgb = Math::Clamp( RB_EvalExpression( &pStage->rgbExp, 1.0 ), 0.0f, 1.0f ); + if ( tr.worldLinearizeTexture ) + { + rgb = convertFromSRGB ( rgb ); + } + tess.svars.color = Color::White * rgb; break; } @@ -2450,6 +2467,13 @@ void Tess_ComputeColor( shaderStage_t *pStage ) blue = Math::Clamp( RB_EvalExpression( &pStage->blueExp, 1.0 ), 0.0f, 1.0f ); } + if ( tr.worldLinearizeTexture ) + { + red = convertFromSRGB ( red ); + green = convertFromSRGB ( green ); + blue = convertFromSRGB ( blue ); + } + tess.svars.color.SetRed( red ); tess.svars.color.SetGreen( green ); tess.svars.color.SetBlue( blue ); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 4f6ea8e370..9f0b5097e9 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -4757,6 +4757,15 @@ static bool ParseShader( const char *_text ) return true; } +static int packLinearizeTexture( bool linearizeColorMap, bool linearizeMaterialMap, bool linearizeLightMap ) +{ + /* HACK: emulate three-bits bitfield + even: no color map linearization (first bit) + less than 2: no light map linearization (second bit) + positive: no material map linearization (extra bit) */ + return ( int(linearizeColorMap) + ( 2 * int(linearizeLightMap) ) ) * ( linearizeMaterialMap ? -1 : 1 ); +} + /* ======================================================================================== @@ -5299,6 +5308,31 @@ static void FinishStages() stage->hasHeightMapInNormalMap = stage->hasHeightMapInNormalMap && ( stage->enableNormalMapping || stage->enableReliefMapping ); + switch ( stage->type ) + { + case stageType_t::ST_COLORMAP: + case stageType_t::ST_COLLAPSE_COLORMAP: + case stageType_t::ST_SKYBOXMAP: + stage->linearizeTexture = tr.worldLinearizeTexture; + break; + case stageType_t::ST_STYLELIGHTMAP: + case stageType_t::ST_STYLECOLORMAP: + stage->linearizeTexture = tr.worldLinearizeLightMap; + break; + case stageType_t::ST_LIGHTMAP: + stage->linearizeTexture = packLinearizeTexture( false, false, tr.worldLinearizeLightMap ); + break; + case stageType_t::ST_DIFFUSEMAP: + case stageType_t::ST_COLLAPSE_DIFFUSEMAP: + stage->linearizeTexture = packLinearizeTexture( + tr.worldLinearizeTexture, + hasMaterialMap && stage->collapseType == collapseType_t::COLLAPSE_PHONG, + tr.worldLinearizeLightMap ); + break; + default: + break; + } + // Bind fallback textures if required. if ( !stage->enableNormalMapping && !( stage->enableReliefMapping && stage->hasHeightMapInNormalMap) ) { diff --git a/src/engine/renderer/tr_sky.cpp b/src/engine/renderer/tr_sky.cpp index de1c39eb4f..29960ee9c2 100644 --- a/src/engine/renderer/tr_sky.cpp +++ b/src/engine/renderer/tr_sky.cpp @@ -102,6 +102,9 @@ void Tess_StageIteratorSky() gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); + // u_LinearizeTexture + gl_skyboxShader->SetUniform_LinearizeTexture( tr.worldLinearizeTexture ); + gl_skyboxShader->SetRequiredVertexPointers(); // draw the outer skybox @@ -161,6 +164,9 @@ void Tess_StageIteratorSky() // u_AlphaThreshold gl_skyboxShader->SetUniform_AlphaTest( pStage->stateBits ); + // u_LinearizeTexture + gl_skyboxShader->SetUniform_LinearizeTexture( tr.worldLinearizeTexture ); + GL_State( pStage->stateBits ); switch ( pStage->type ) {