diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index a858389947..f9beb9a05f 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -59,14 +59,19 @@ static void ComputeDynamics( shaderStage_t* pStage ) { // TODO: Move color and texMatrices stuff to a compute shader pStage->colorDynamic = false; switch ( pStage->rgbGen ) { - case colorGen_t::CGEN_IDENTITY_LIGHTING: case colorGen_t::CGEN_IDENTITY: case colorGen_t::CGEN_ONE_MINUS_VERTEX: - case colorGen_t::CGEN_VERTEX: - case colorGen_t::CGEN_CONST: default: - break; + case colorGen_t::CGEN_IDENTITY_LIGHTING: + /* Historically CGEN_IDENTITY_LIGHTING was done this way: + + tess.svars.color = Color::White * tr.identityLight; + But tr.identityLight is always 1.0f in Dæmon engine + as the as the overbright bit implementation is fully + software. */ + case colorGen_t::CGEN_VERTEX: + case colorGen_t::CGEN_CONST: case colorGen_t::CGEN_ENTITY: case colorGen_t::CGEN_ONE_MINUS_ENTITY: { diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 1508b6bb6d..6ef7a0a48b 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -2897,7 +2897,6 @@ GLShader_cameraEffects::GLShader_cameraEffects( GLShaderManager *manager ) : GLShader( "cameraEffects", ATTR_POSITION | ATTR_TEXCOORD, manager ), u_ColorMap3D( this ), u_CurrentMap( this ), - u_GlobalLightFactor( this ), u_ColorModulate( this ), u_TextureMatrix( this ), u_ModelViewProjectionMatrix( this ), diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 80c5054a67..e53b8119a2 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -3536,21 +3536,6 @@ class u_Time : } }; -class u_GlobalLightFactor : - GLUniform1f -{ -public: - u_GlobalLightFactor( GLShader *shader ) : - GLUniform1f( shader, "u_GlobalLightFactor" ) - { - } - - void SetUniform_GlobalLightFactor( float value ) - { - this->SetValue( value ); - } -}; - class GLDeformStage : public u_Time { @@ -4474,7 +4459,6 @@ class GLShader_cameraEffects : public GLShader, public u_ColorMap3D, public u_CurrentMap, - public u_GlobalLightFactor, public u_ColorModulate, public u_TextureMatrix, public u_ModelViewProjectionMatrix, diff --git a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl index 56874c6644..f4b4fbcfd6 100644 --- a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl +++ b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl @@ -29,7 +29,6 @@ uniform sampler3D u_ColorMap3D; #endif uniform vec4 u_ColorModulate; -uniform float u_GlobalLightFactor; // 1 / tr.identityLight uniform float u_InverseGamma; IN(smooth) vec2 var_TexCoords; @@ -56,7 +55,6 @@ void main() vec2 st = gl_FragCoord.st / r_FBufSize; vec4 color = texture2D(u_CurrentMap, st); - color *= u_GlobalLightFactor; if( u_Tonemap ) { color.rgb = TonemapLottes( color.rgb * u_TonemapExposure ); diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 0e3c749abe..133f2dfba6 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -3350,7 +3350,6 @@ void RB_CameraPostFX() // enable shader, set arrays gl_cameraEffectsShader->BindProgram( 0 ); - gl_cameraEffectsShader->SetUniform_GlobalLightFactor( 1.0f / tr.identityLight ); 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 14e9d3dd75..ad2cf25bfa 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -74,7 +74,10 @@ static void R_ColorShiftLightingBytes( byte bytes[ 4 ] ) backward compatible with this bug for diagnostic purpose and fair comparison with other buggy engines. */ - ASSERT_LT( tr.overbrightBits, tr.mapOverBrightBits ); + if ( tr.mapOverBrightBits == 0 ) + { + return; + } /* Shift the color data based on overbright range. @@ -91,7 +94,7 @@ static void R_ColorShiftLightingBytes( byte bytes[ 4 ] ) what hardware overbright bit feature was not doing, but this implementation is entirely software. */ - int shift = tr.mapOverBrightBits - tr.overbrightBits; + int shift = tr.mapOverBrightBits; // shift the data based on overbright range int r = bytes[ 0 ] << shift; @@ -117,7 +120,10 @@ static void R_ColorShiftLightingBytes( byte bytes[ 4 ] ) static void R_ColorShiftLightingBytesCompressed( byte bytes[ 8 ] ) { - ASSERT_LT( tr.overbrightBits, tr.mapOverBrightBits ); + if ( tr.mapOverBrightBits == 0 ) + { + return; + } // color shift the endpoint colors in the dxt block unsigned short rgb565 = bytes[1] << 8 | bytes[0]; @@ -158,7 +164,7 @@ R_ProcessLightmap */ void R_ProcessLightmap( byte *bytes, int width, int height, int bits ) { - if ( tr.overbrightBits >= tr.mapOverBrightBits ) + if ( tr.mapOverBrightBits == 0 ) { return; } @@ -662,7 +668,7 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName ) lightMapBuffer[( index * 4 ) + 2 ] = buf_p[( ( x + ( y * internalLightMapSize ) ) * 3 ) + 2 ]; lightMapBuffer[( index * 4 ) + 3 ] = 255; - if ( tr.overbrightBits < tr.mapOverBrightBits ) + if ( tr.legacyOverBrightClamping ) { R_ColorShiftLightingBytes( &lightMapBuffer[( index * 4 ) + 0 ] ); } @@ -1023,7 +1029,7 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf, in cv->verts[ i ].lightColor = Color::Adapt( verts[ i ].color ); - if ( tr.overbrightBits < tr.mapOverBrightBits ) + if ( tr.legacyOverBrightClamping ) { R_ColorShiftLightingBytes( cv->verts[ i ].lightColor.ToArray() ); } @@ -1233,7 +1239,7 @@ static void ParseMesh( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf ) points[ i ].lightColor = Color::Adapt( verts[ i ].color ); - if ( tr.overbrightBits < tr.mapOverBrightBits ) + if ( tr.legacyOverBrightClamping ) { R_ColorShiftLightingBytes( points[ i ].lightColor.ToArray() ); } @@ -1360,7 +1366,7 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, bspSurface_t *surf, cv->verts[ i ].lightColor = Color::Adapt( verts[ i ].color ); - if ( tr.overbrightBits < tr.mapOverBrightBits ) + if ( tr.legacyOverBrightClamping ) { R_ColorShiftLightingBytes( cv->verts[ i ].lightColor.ToArray() ); } @@ -3883,7 +3889,14 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) out->fogParms = shader->fogParms; out->color = Color::Adapt( shader->fogParms.color ); - out->color *= tr.identityLight; + + /* Historically it was done: + + out->color *= tr.identityLight; + + But tr.identityLight is always 1.0f in Dæmon engine + as the as the overbright bit implementation is fully + software. */ out->color.SetAlpha( 1 ); @@ -4099,7 +4112,7 @@ void R_LoadLightGrid( lump_t *l ) tmpDirected[ 2 ] = in->directed[ 2 ]; tmpDirected[ 3 ] = 255; - if ( tr.overbrightBits < tr.mapOverBrightBits ) + if ( tr.legacyOverBrightClamping ) { R_ColorShiftLightingBytes( tmpAmbient ); R_ColorShiftLightingBytes( tmpDirected ); @@ -4359,6 +4372,24 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities ) tr.mapOverBrightBits = Math::Clamp( atof( value ), 0.0, 3.0 ); continue; } + + if ( !Q_stricmp( keyname, "overbrightClamping" ) ) + { + if ( !Q_stricmp( value, "0" ) ) + { + tr.legacyOverBrightClamping = false; + } + else if ( !Q_stricmp( value, "1" ) ) + { + tr.legacyOverBrightClamping = true; + } + else + { + Log::Warn( "invalid value for worldspawn key overbrightClamping" ); + } + + continue; + } } // check for deluxe mapping provided by NetRadiant's q3map2 @@ -5039,15 +5070,11 @@ void RE_LoadWorldMap( const char *name ) // try will not look at the partially loaded version tr.world = nullptr; - // It's probably a mistake if any of these lighting parameters are actually - // used before a map is loaded. - tr.worldLightMapping = false; // set by R_LoadLightmaps - tr.worldDeluxeMapping = false; // set by R_LoadEntities - tr.worldHDR_RGBE = false; // set by R_LoadEntities - tr.mapOverBrightBits = r_overbrightDefaultExponent.Get(); // maybe set by R_LoadEntities - tr.overbrightBits = std::min( tr.mapOverBrightBits, r_overbrightBits.Get() ); // set by RE_LoadWorldMap - tr.mapLightFactor = 1.0f; // set by RE_LoadWorldMap - tr.identityLight = 1.0f; // set by RE_LoadWorldMap + // tr.worldDeluxeMapping will be set by R_LoadLightmaps() + tr.worldLightMapping = false; + // tr.worldDeluxeMapping will be set by R_LoadEntities() + tr.worldDeluxeMapping = false; + tr.worldHDR_RGBE = false; s_worldData = {}; Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) ); @@ -5095,9 +5122,6 @@ void RE_LoadWorldMap( const char *name ) } R_LoadEntities( &header->lumps[ LUMP_ENTITIES ], externalEntities ); - // Now we can set this after checking a possible worldspawn value for mapOverbrightBits - tr.overbrightBits = std::min( tr.mapOverBrightBits, r_overbrightBits.Get() ); - R_LoadShaders( &header->lumps[ LUMP_SHADERS ] ); R_LoadLightmaps( &header->lumps[ LUMP_LIGHTMAPS ], name ); @@ -5135,6 +5159,7 @@ void RE_LoadWorldMap( const char *name ) tr.worldLight = tr.lightMode; tr.modelLight = lightMode_t::FULLBRIGHT; tr.modelDeluxe = deluxeMode_t::NONE; + tr.mapLightFactor = 1.0f; // Use fullbright lighting for everything if the world is fullbright. if ( tr.worldLight != lightMode_t::FULLBRIGHT ) @@ -5206,19 +5231,11 @@ void RE_LoadWorldMap( const char *name ) } } - /* Set GLSL overbright parameters if the lighting mode is not fullbright. */ - if ( tr.lightMode != lightMode_t::FULLBRIGHT ) + /* Set GLSL overbright parameters if the legacy clamped overbright isn't used + and the lighting mode is not fullbright. */ + if ( !tr.legacyOverBrightClamping && tr.lightMode != lightMode_t::FULLBRIGHT ) { - if ( r_overbrightQ3.Get() ) - { - // light factor is applied to entire color buffer; identityLight can be used to cancel it - tr.identityLight = 1.0f / float( 1 << tr.overbrightBits ); - } - else - { - // light factor is applied wherever a precomputed light is sampled - tr.mapLightFactor = float( 1 << tr.overbrightBits ); - } + tr.mapLightFactor = pow( 2, tr.mapOverBrightBits ); } tr.worldLoaded = true; diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 4b608e7487..381265293a 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -1853,7 +1853,7 @@ image_t *R_FindImageFile( const char *imageName, imageParams_t &imageParams ) return nullptr; } - if ( imageParams.bits & IF_LIGHTMAP ) + if ( imageParams.bits & IF_LIGHTMAP && tr.legacyOverBrightClamping ) { R_ProcessLightmap( *pic, width, height, imageParams.bits ); } @@ -3054,11 +3054,16 @@ void R_InitImages() tr.lightmaps.reserve( 128 ); tr.deluxemaps.reserve( 128 ); - /* - **** Map overbright bits **** - Lightmaps and vertex light colors are notionally scaled up by a factor of - pow(2, tr.mapOverBrightBits). This is a good idea because we would like a bright light - to make a texture brighter than its original diffuse image. + /* 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 @@ -3084,41 +3089,32 @@ void R_InitImages() require to set a different default than what Unvanquished requires. - **** r_overbrightBits **** - Although lightmaps are scaled up by pow(2, tr.overbrightBits), the actual ceiling for lightmap - values is pow(2, tr.overbrightBits). tr.overbrightBits may - be less than tr.mapOverbrightBits. This is a STUPID configuration because then you are - just throwing away 1 or bits of precision from the lightmap. But it was used for many games. - - The excess (tr.mapOverbrightBits - tr.overbrightBits) bits of scaling are done to the lightmap - before uploading it. If some component exceeds 1, the color is proportionally downscaled until - the max component is 1. - - Quake 3 and vanilla Tremulous used these default cvar values: - r_overbrightBits - 1 - r_mapOverBrightBits - 2 - - So the same as Daemon. But if the game was not running in fullscreen mode or the system was - not detected as supporting hardware gamma control, tr.overbrightBit would be set to 0. - Tremfusion shipped with r_overbrightBits 0 and r_ignorehwgamma 1, either of which forces - tr.overbrightBits to 0, making it the same as the vanilla client's windowed mode. - - **** How Quake 3 originally implemented overbright **** - When hardware overbright was on (tr.overbrightBits = 1), the color buffer notionally ranged - from 0 to 2, rather than 0 to 1. So a buffer with 8-bit colors only had 7 bits of - output precision (all values 128+ produced the same output), but the extra bit was useful - for intermediate values during blending. The rescaling was effected by using the hardware - gamma ramp, which affected the whole monitor (or whole system). - Shaders for materials that were not illuminated by any precomputed lighting could use - CGEN_IDENTITY_LIGHTING to multiply by tr.identityLight, which would cancel out the - rescaling so that the material looked the same regardless of tr.overbrightBits. - - In Daemon tr.identityLight is usually 1, so any distincion between - CGEN_IDENTITY/CGEN_IDENTITY_LIGHTING is ignored. But if you set the cvar r_overbrightQ3, - which emulates Quake 3's technique of brightening the whole color buffer, it will be used. - - For even more information, see https://github.com/DaemonEngine/Daemon/issues/1542. - */ + 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 d734da5641..7156dcf52d 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -92,11 +92,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 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::Range> r_overbrightBits("r_overbrightBits", "clamp lightmap colors to 2^x", Cvar::NONE, 1, 0, 3); - - // also set r_highPrecisionRendering 0 for an even more authentic q3 experience - Cvar::Cvar r_overbrightQ3("r_overbrightQ3", "brighten entire color buffer like Quake 3 (incompatible with newer assets)", Cvar::NONE, false); - + 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::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 ); @@ -1189,8 +1185,7 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p 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_overbrightBits ); - Cvar::Latch( r_overbrightQ3 ); + Cvar::Latch( r_overbrightDefaultClamp ); Cvar::Latch( r_overbrightIgnoreMapSettings ); Cvar::Latch( r_lightMode ); Cvar::Latch( r_colorGrading ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 4bee0e9c9b..ed59f14404 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -825,7 +825,7 @@ enum class shaderProfilerRenderSubGroupsMode { enum class colorGen_t { CGEN_BAD, - CGEN_IDENTITY_LIGHTING, // Always (1,1,1,1) in Dæmon engine, unless you set r_overbrightQ3. + CGEN_IDENTITY_LIGHTING, // Always (1,1,1,1) in Dæmon engine as the overbright bit implementation is fully software. CGEN_IDENTITY, // always (1,1,1,1) CGEN_ENTITY, // grabbed from entity's modulate field CGEN_ONE_MINUS_ENTITY, // grabbed from 1 - entity.modulate @@ -2809,16 +2809,12 @@ enum class shaderProfilerRenderSubGroupsMode { viewParms_t viewParms; - // Brightness scaling: roughly speaking, a lightmap value of x will be interpreted as - // min(x * pow(2, mapOverBrightBits), pow(2, overbrightBits)) - // (but when a component hits the max allowed value, others are scaled down to keep the "same color") + // r_overbrightDefaultExponent, but can be overridden by mapper using the worldspawn int mapOverBrightBits; - // min(r_overbrightBits.Get(), mapOverBrightBits) - int overbrightBits; - // pow(2, overbrightBits), unless r_overbrightQ3 is on + // pow(2, mapOverbrightBits) float mapLightFactor; - // 1/pow(2, overbrightBits) if r_overbrightQ3 is on - float identityLight; + // May have to be true on some legacy maps: clamp and normalize multiplied colors. + bool legacyOverBrightClamping; orientationr_t orientation; // for current entity @@ -2942,8 +2938,7 @@ enum class shaderProfilerRenderSubGroupsMode { extern cvar_t *r_realtimeLightingCastShadows; extern cvar_t *r_precomputedLighting; extern Cvar::Cvar r_overbrightDefaultExponent; - extern Cvar::Range> r_overbrightBits; - extern Cvar::Cvar r_overbrightQ3; + extern Cvar::Cvar r_overbrightDefaultClamp; extern Cvar::Cvar r_overbrightIgnoreMapSettings; extern Cvar::Range> r_lightMode; extern Cvar::Cvar r_colorGrading; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index faff8eaff6..19dd45a2fc 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -846,10 +846,12 @@ void Render_generic3D( shaderStage_t *pStage ) colorGen_t rgbGen = SetRgbGen( pStage ); alphaGen_t alphaGen = SetAlphaGen( pStage ); + // Here, it's safe to multiply the overbright factor for vertex lighting into the color gen` + // since the `generic` fragment shader only takes a single input color. `lightMapping` on the + // hand needs to know the real diffuse color, hence the separate u_LightFactor. bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP && tess.bspSurface; const bool styleLightMap = pStage->type == stageType_t::ST_STYLELIGHTMAP || pStage->type == stageType_t::ST_STYLECOLORMAP; - gl_genericShader->SetUniform_ColorModulateColorGen( - rgbGen, alphaGen, mayUseVertexOverbright, /*useMapLightFactor=*/ styleLightMap); + gl_genericShader->SetUniform_ColorModulateColorGen( rgbGen, alphaGen, mayUseVertexOverbright, styleLightMap ); // u_Color gl_genericShader->SetUniform_Color( tess.svars.color ); @@ -2319,15 +2321,21 @@ void Tess_ComputeColor( shaderStage_t *pStage ) // rgbGen switch ( pStage->rgbGen ) { - case colorGen_t::CGEN_IDENTITY_LIGHTING: - tess.svars.color = Color::Color(tr.identityLight, tr.identityLight, tr.identityLight); - break; - case colorGen_t::CGEN_IDENTITY: case colorGen_t::CGEN_ONE_MINUS_VERTEX: default: + case colorGen_t::CGEN_IDENTITY_LIGHTING: + /* Historically CGEN_IDENTITY_LIGHTING was done this way: + + tess.svars.color = Color::White * tr.identityLight; + + But tr.identityLight is always 1.0f in Dæmon engine + as the as the overbright bit implementation is fully + software. */ + { tess.svars.color = Color::White; break; + } case colorGen_t::CGEN_VERTEX: { diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index d24cb13b61..eeac8658df 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -4836,7 +4836,7 @@ static void CollapseStages() bool rgbGen_identity = stages[ i ].rgbGen == colorGen_t::CGEN_IDENTITY - || ( stages[ i ].rgbGen == colorGen_t::CGEN_IDENTITY_LIGHTING && !r_overbrightQ3.Get() ); + || stages[ i ].rgbGen == colorGen_t::CGEN_IDENTITY_LIGHTING; bool alphaGen_identity = stages[ i ].alphaGen == alphaGen_t::AGEN_IDENTITY;