From a0d76216c058df17da4727fd555c5a4980640fb2 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Fri, 15 Mar 2019 21:32:28 +0100 Subject: [PATCH 1/3] tr_shader: revamp stage collapse --- src/engine/renderer/tr_local.h | 21 +-- src/engine/renderer/tr_shade.cpp | 26 +-- src/engine/renderer/tr_shader.cpp | 298 +++++++++++++++--------------- 3 files changed, 158 insertions(+), 187 deletions(-) diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 73a897d94f..d1043c3952 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1043,13 +1043,9 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) ST_HEATHAZEMAP, // heatHaze post process effect ST_LIQUIDMAP, ST_LIGHTMAP, - ST_COLLAPSE_lighting_DB, // diffusemap + bumpmap - ST_COLLAPSE_lighting_DBG, // diffusemap + bumpmap + glowmap - ST_COLLAPSE_lighting_DBS, // diffusemap + bumpmap + specularmap - ST_COLLAPSE_lighting_DBSG, // diffusemap + bumpmap + specularmap + glowmap - ST_COLLAPSE_lighting_DBM, // diffusemap + bumpmap + materialmap - ST_COLLAPSE_lighting_DBMG, // diffusemap + bumpmap + materialmap + glowmap - ST_COLLAPSE_reflection_CB, // color cubemap + bumpmap + ST_COLLAPSE_lighting_PHONG, // diffusemap + opt:normalmap + opt:glowmap + opt:specularmap + ST_COLLAPSE_lighting_PBR, // diffusemap + opt:normalmap + opt:glowmap + materialmap + ST_COLLAPSE_reflection_CB, // color cubemap + normalmap // light shader stage types ST_ATTENUATIONMAP_XY, @@ -1060,12 +1056,8 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) { COLLAPSE_none, COLLAPSE_genericMulti, - COLLAPSE_lighting_DB, - COLLAPSE_lighting_DBG, - COLLAPSE_lighting_DBS, - COLLAPSE_lighting_DBSG, - COLLAPSE_lighting_DBM, - COLLAPSE_lighting_DBMG, + COLLAPSE_lighting_PHONG, + COLLAPSE_lighting_PBR, COLLAPSE_reflection_CB, COLLAPSE_color_lightmap }; @@ -1229,7 +1221,8 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) float portalRange; // distance to fog out at bool isPortal; - collapseType_t collapseType; + collapseType_t lightingCollapseType; + collapseType_t reflectCollapseType; int collapseTextureEnv; // 0, GL_MODULATE, GL_ADD (FIXME: put in stage) cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 56665610cd..6a1132537d 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -700,9 +700,8 @@ static void Render_generic( int stage ) } static bool hasMaterialMapping( shader_t *shader ) { - switch( shader->collapseType ) { - case collapseType_t::COLLAPSE_lighting_DBM: - case collapseType_t::COLLAPSE_lighting_DBMG: + switch( shader->lightingCollapseType ) { + case collapseType_t::COLLAPSE_lighting_PBR: return true; default: return false; @@ -2807,12 +2806,8 @@ void Tess_StageIteratorGeneric() } case stageType_t::ST_DIFFUSEMAP: - case stageType_t::ST_COLLAPSE_lighting_DBSG: - case stageType_t::ST_COLLAPSE_lighting_DBG: - case stageType_t::ST_COLLAPSE_lighting_DB: - case stageType_t::ST_COLLAPSE_lighting_DBS: - case stageType_t::ST_COLLAPSE_lighting_DBM: - case stageType_t::ST_COLLAPSE_lighting_DBMG: + case stageType_t::ST_COLLAPSE_lighting_PHONG: + case stageType_t::ST_COLLAPSE_lighting_PBR: { { if ( r_precomputedLighting->integer || r_vertexLighting->integer ) @@ -2997,10 +2992,7 @@ void Tess_StageIteratorDepthFill() } case stageType_t::ST_DIFFUSEMAP: - case stageType_t::ST_COLLAPSE_lighting_DBSG: - case stageType_t::ST_COLLAPSE_lighting_DBG: - case stageType_t::ST_COLLAPSE_lighting_DB: - case stageType_t::ST_COLLAPSE_lighting_DBS: + case stageType_t::ST_COLLAPSE_lighting_PHONG: { Render_depthFill( stage ); break; @@ -3080,10 +3072,7 @@ void Tess_StageIteratorShadowFill() case stageType_t::ST_LIGHTMAP: case stageType_t::ST_DIFFUSEMAP: - case stageType_t::ST_COLLAPSE_lighting_DBSG: - case stageType_t::ST_COLLAPSE_lighting_DBG: - case stageType_t::ST_COLLAPSE_lighting_DB: - case stageType_t::ST_COLLAPSE_lighting_DBS: + case stageType_t::ST_COLLAPSE_lighting_PHONG: { Render_shadowFill( stage ); break; @@ -3198,8 +3187,7 @@ void Tess_StageIteratorLighting() switch ( diffuseStage->type ) { case stageType_t::ST_DIFFUSEMAP: - case stageType_t::ST_COLLAPSE_lighting_DB: - case stageType_t::ST_COLLAPSE_lighting_DBS: + case stageType_t::ST_COLLAPSE_lighting_PHONG: if ( light->l.rlType == refLightType_t::RL_OMNI ) { Render_forwardLighting_DBS_omni( diffuseStage, attenuationXYStage, attenuationZStage, light ); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 56326cd5bc..01df113313 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -4149,189 +4149,183 @@ static void CollapseStages() return; } - collapseType_t tmpCollapseType = shader.collapseType; - shaderStage_t* activeStages[ MAX_SHADER_STAGES ]; - int numActiveStages = 0; - for (shaderStage_t& stage : stages) { - if (stage.active) { - activeStages[numActiveStages++] = &stage; - } - } - int stagesWritten = 0; + int diffuseStage = -1; + int normalStage = -1; + int specularStage = -1; + int materialStage = -1; + int reflectionStage = -1; + int glowStage = -1; - for ( int j = 0; j < numActiveStages; ) + for ( int i = 0; i < MAX_SHADER_STAGES; i++ ) { - struct CollapsibleStages { - const shaderStage_t* diffuseStage = nullptr; - const shaderStage_t* normalStage = nullptr; - const shaderStage_t* specularStage = nullptr; - const shaderStage_t* materialStage = nullptr; - const shaderStage_t* reflectionStage = nullptr; - const shaderStage_t* glowStage = nullptr; - }; - auto FindStages = [&activeStages, numActiveStages](CollapsibleStages collapsibleStages, int i) { - if ( i >= numActiveStages ) - { - return collapsibleStages; - } - - if ( activeStages[ i ]->type == stageType_t::ST_DIFFUSEMAP && !collapsibleStages.diffuseStage ) + if ( stages[ i ].type == stageType_t::ST_DIFFUSEMAP ) + { + if ( diffuseStage != -1 ) { - collapsibleStages.diffuseStage = activeStages[ i ]; + Log::Warn( "more than one diffuse map stage in shader '%s'", shader.name ); } - else if ( activeStages[ i ]->type == stageType_t::ST_NORMALMAP && !collapsibleStages.normalStage ) + else { - collapsibleStages.normalStage = activeStages[ i ]; + diffuseStage = i; } - else if ( activeStages[ i ]->type == stageType_t::ST_SPECULARMAP && !collapsibleStages.specularStage ) + } + else if ( stages[ i ].type == stageType_t::ST_NORMALMAP ) + { + if ( normalStage != -1 ) { - collapsibleStages.specularStage = activeStages[ i ]; + Log::Warn( "more than one normal map stage in shader '%s'", shader.name ); } - else if ( activeStages[ i ]->type == stageType_t::ST_MATERIALMAP && !collapsibleStages.materialStage ) + else { - collapsibleStages.materialStage = activeStages[ i ]; + normalStage = i; } - else if ( activeStages[ i ]->type == stageType_t::ST_REFLECTIONMAP && !collapsibleStages.reflectionStage ) + } + else if ( stages[ i ].type == stageType_t::ST_SPECULARMAP ) + { + if ( specularStage != -1 ) { - collapsibleStages.reflectionStage = activeStages[ i ]; + Log::Warn( "more than one specular map stage in shader '%s'", shader.name ); } - else if ( activeStages[ i ]->type == stageType_t::ST_GLOWMAP && !collapsibleStages.glowStage ) + else { - collapsibleStages.glowStage = activeStages[ i ]; + specularStage = i; } - return collapsibleStages; - }; - CollapsibleStages stages1 = FindStages(CollapsibleStages(), j); - CollapsibleStages stages2 = FindStages(stages1, j + 1); - CollapsibleStages stages3 = FindStages(stages2, j + 2); - CollapsibleStages stages4 = FindStages(stages3, j + 3); - - // try to merge diffuse/normal/specular/glow - if ( stages4.diffuseStage && stages4.normalStage && stages4.specularStage && stages4.glowStage ) - { - tmpCollapseType = collapseType_t::COLLAPSE_lighting_DBSG; - - shaderStage_t tmpStage = *stages4.diffuseStage; - tmpStage.type = stageType_t::ST_COLLAPSE_lighting_DBSG; - tmpStage.bundle[ TB_NORMALMAP ] = stages4.normalStage->bundle[ 0 ]; - tmpStage.bundle[ TB_SPECULARMAP ] = stages4.specularStage->bundle[ 0 ]; - tmpStage.specularExponentMin = stages4.specularStage->specularExponentMin; - tmpStage.specularExponentMax = stages4.specularStage->specularExponentMax; - tmpStage.bundle[ TB_GLOWMAP ] = stages4.glowStage->bundle[ 0 ]; - - stages[stagesWritten++] = tmpStage; - j += 4; } - - // try to merge diffuse/normal/material/glow - else if ( stages4.diffuseStage && stages4.normalStage && stages4.materialStage && stages4.glowStage ) + else if ( stages[ i ].type == stageType_t::ST_MATERIALMAP ) { - tmpCollapseType = collapseType_t::COLLAPSE_lighting_DBMG; - - shaderStage_t tmpStage = *stages4.diffuseStage; - tmpStage.type = stageType_t::ST_COLLAPSE_lighting_DBMG; - tmpStage.bundle[ TB_NORMALMAP ] = stages4.normalStage->bundle[ 0 ]; - tmpStage.bundle[ TB_MATERIALMAP ] = stages4.materialStage->bundle[ 0 ]; - tmpStage.bundle[ TB_GLOWMAP ] = stages4.glowStage->bundle[ 0 ]; - - stages[stagesWritten++] = tmpStage; - j += 4; + if ( materialStage != -1 ) + { + Log::Warn( "more than one material map stage in shader '%s'", shader.name ); + } + else + { + materialStage = i; + } } - - // try to merge diffuse/normal/specular - else if ( stages3.diffuseStage && stages3.normalStage && stages3.specularStage ) + else if ( stages[ i ].type == stageType_t::ST_REFLECTIONMAP ) { - tmpCollapseType = collapseType_t::COLLAPSE_lighting_DBS; - - shaderStage_t tmpStage = *stages3.diffuseStage; - tmpStage.type = stageType_t::ST_COLLAPSE_lighting_DBS; - tmpStage.bundle[ TB_NORMALMAP ] = stages3.normalStage->bundle[ 0 ]; - tmpStage.bundle[ TB_SPECULARMAP ] = stages3.specularStage->bundle[ 0 ]; - tmpStage.specularExponentMin = stages3.specularStage->specularExponentMin; - tmpStage.specularExponentMax = stages3.specularStage->specularExponentMax; - - stages[stagesWritten++] = tmpStage; - j += 3; + if ( reflectionStage != -1 ) + { + Log::Warn( "more than one reflection map stage in shader '%s'", shader.name ); + } + else + { + reflectionStage = i; + } } - - // try to merge diffuse/normal/material - else if ( stages3.diffuseStage && stages3.normalStage && stages3.materialStage ) + else if ( stages[ i ].type == stageType_t::ST_GLOWMAP ) { - tmpCollapseType = collapseType_t::COLLAPSE_lighting_DBM; - - shaderStage_t tmpStage = *stages3.diffuseStage; - tmpStage.type = stageType_t::ST_COLLAPSE_lighting_DBM; - tmpStage.bundle[ TB_NORMALMAP ] = stages3.normalStage->bundle[ 0 ]; - tmpStage.bundle[ TB_MATERIALMAP ] = stages3.materialStage->bundle[ 0 ]; - - stages[stagesWritten++] = tmpStage; - j += 3; + if ( glowStage != -1 ) + { + Log::Warn( "more than one glow map stage in shader '%s'", shader.name ); + } + else + { + glowStage = i; + } } + } - // try to merge diffuse/normal/glow - else if ( stages3.diffuseStage && stages3.normalStage && stages3.glowStage ) - { - tmpCollapseType = collapseType_t::COLLAPSE_lighting_DBG; - - shaderStage_t tmpStage = *stages3.diffuseStage; - tmpStage.type = stageType_t::ST_COLLAPSE_lighting_DBG; - tmpStage.bundle[ TB_NORMALMAP ] = stages3.normalStage->bundle[ 0 ]; - tmpStage.bundle[ TB_GLOWMAP ] = stages3.glowStage->bundle[ 0 ]; + // note that same stage can be merged twice + // like the normal stage being merged in both + // reflection stage and diffuse stage - stages[stagesWritten++] = tmpStage; - j += 3; - } + if ( reflectionStage != -1 && normalStage != -1 ) + { + // note that if uncollapsed reflectionStage had to be merged in another stage + // it would have to be backed-up somewhere - // try to merge diffuse/normal - else if ( stages2.diffuseStage && stages2.normalStage ) - { - tmpCollapseType = collapseType_t::COLLAPSE_lighting_DB; + Log::Debug("found reflection collapsable stage in shader '%s':", shader.name); + shader.reflectCollapseType = collapseType_t::COLLAPSE_reflection_CB; + stages[ reflectionStage ].type = stageType_t::ST_COLLAPSE_reflection_CB; - shaderStage_t tmpStage = *stages2.diffuseStage; - tmpStage.type = stageType_t::ST_COLLAPSE_lighting_DB; - tmpStage.bundle[ TB_NORMALMAP ] = stages2.normalStage->bundle[ 0 ]; + // merge with reflection stage + stages[ reflectionStage ].bundle[ TB_NORMALMAP ] = stages[ normalStage ].bundle[ 0 ]; + // disable since it's merged + stages[ normalStage ].active = false; + } - stages[stagesWritten++] = tmpStage; - j += 2; - } + if ( diffuseStage != -1 + && ( specularStage != -1 + || normalStage != -1 + || materialStage != -1 + || glowStage != -1 ) ) + { + // note that if uncollapsed diffuseStage had to be merged in another stage + // it would have to be backed-up somewhere - // try to merge env/normal - else if ( stages2.reflectionStage && stages2.normalStage ) + if ( specularStage != -1 && materialStage != -1 ) { - tmpCollapseType = collapseType_t::COLLAPSE_reflection_CB; - - shaderStage_t tmpStage = *stages2.reflectionStage; - tmpStage.type = stageType_t::ST_COLLAPSE_reflection_CB; - tmpStage.bundle[ TB_NORMALMAP ] = stages2.normalStage->bundle[ 0 ]; - - stages[stagesWritten++] = tmpStage; - j += 2; + Log::Warn("Supposedly you shouldn't have both specularMap and materialMap (in shader '%s')?", shader.name); } - - // if there was no merge option just copy stage else { - if ( &stages[stagesWritten] != activeStages[j] ) { - stages[stagesWritten] = *activeStages[j]; + if ( materialStage != -1 ) + { + Log::Debug("found PBR lighting collapsable stage in shader '%s'", shader.name); + shader.lightingCollapseType = collapseType_t::COLLAPSE_lighting_PBR; + stages[ diffuseStage ].type = stageType_t::ST_COLLAPSE_lighting_PBR; + } + else + { + Log::Debug("found Phong lighting collapsable stage in shader '%s'", shader.name); + shader.lightingCollapseType = collapseType_t::COLLAPSE_lighting_PHONG; + stages[ diffuseStage ].type = stageType_t::ST_COLLAPSE_lighting_PHONG; + } + + if ( normalStage != -1 ) + { + // merge with diffuse stage + stages[ diffuseStage ].bundle[ TB_NORMALMAP ] = stages[ normalStage ].bundle[ 0 ]; + // disable since it's merged + stages[ normalStage ].active = false; + } + if ( specularStage != -1 ) + { + // merge with diffuse stage + stages[ diffuseStage ].bundle[ TB_SPECULARMAP ] = stages[ specularStage ].bundle[ 0 ]; + stages[ diffuseStage ].specularExponentMin = stages[ specularStage ].specularExponentMin; + stages[ diffuseStage ].specularExponentMax = stages[ specularStage ].specularExponentMax; + // disable since it's merged + stages[ specularStage ].active = false; + } + if ( materialStage != -1 ) + { + // merge with diffuse stage + stages[ diffuseStage ].bundle[ TB_MATERIALMAP ] = stages[ materialStage ].bundle[ 0 ]; + // disable since it's merged + stages[ materialStage ].active = false; + } + if ( glowStage != -1 ) + { + // merge with diffuse stage + stages[ diffuseStage ].bundle[ TB_GLOWMAP ] = stages[ glowStage ].bundle[ 0 ]; + // disable since it's merged + stages[ glowStage ].active = false; } - ++stagesWritten; - j += 1; } + } - if ( stages4.specularStage && stages4.materialStage ) + // move all active stages at beginning + // note that the 'active' field is also used + // instead of numStages in some code that runs later + int numActiveStages = 0; + for ( int i = 0; i < MAX_SHADER_STAGES; i++ ) + { + // for every active stage, swap it with the + // inactive stage that has the smaller index + // at this time + if ( stages[ i ].active ) { - Log::Warn("Supposedly you shouldn't have both specularMap and materialMap (in shader '%s')?", shader.name); + // swap stages + shaderStage_t tmpStage = stages [ i ]; + stages[ i ] = stages [ numActiveStages ]; + stages [ numActiveStages ] = tmpStage; + numActiveStages++; } } - shader.numStages = stagesWritten; - // FIXME: This seems stupid since there can be any number of collapse types. - shader.collapseType = tmpCollapseType; - - // The 'active' field is still used instead of numStages in some code that runs later. - for ( int i = stagesWritten; i < MAX_SHADER_STAGES; i++ ) { - stages[i].active = false; - } + shader.numStages = numActiveStages; } // *INDENT-ON* @@ -5390,19 +5384,15 @@ void R_ShaderList_f() break; } - if ( shader->collapseType == collapseType_t::COLLAPSE_lighting_DB ) - { - str += "lighting_DB "; - } - else if ( shader->collapseType == collapseType_t::COLLAPSE_lighting_DBS ) + if ( shader->lightingCollapseType == collapseType_t::COLLAPSE_lighting_PHONG ) { - str += "lighting_DBS "; + str += "lighting_PHONG "; } - else if ( shader->collapseType == collapseType_t::COLLAPSE_lighting_DBM ) + else if ( shader->lightingCollapseType == collapseType_t::COLLAPSE_lighting_PBR ) { - str += "lighting_DBM "; + str += "lighting_PBR "; } - else if ( shader->collapseType == collapseType_t::COLLAPSE_reflection_CB ) + else if ( shader->reflectCollapseType == collapseType_t::COLLAPSE_reflection_CB ) { str += "reflection_CB "; } From d03d324106d9fcdb30f73289123a111cbfa0767b Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Fri, 15 Mar 2019 22:48:21 +0100 Subject: [PATCH 2/3] tr_shader: merge legacy lightmap stage into diffusestage - avoid double shadowing - avoid to paint shadow over glowmap --- src/engine/renderer/tr_shader.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 01df113313..21e12c86c7 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -4154,6 +4154,7 @@ static void CollapseStages() int specularStage = -1; int materialStage = -1; int reflectionStage = -1; + int lightStage = -1; int glowStage = -1; for ( int i = 0; i < MAX_SHADER_STAGES; i++ ) @@ -4213,6 +4214,17 @@ static void CollapseStages() reflectionStage = i; } } + else if ( stages[ i ].type == stageType_t::ST_LIGHTMAP ) + { + if ( lightStage != -1 ) + { + Log::Warn( "more than one light map stage in shader '%s'", shader.name ); + } + else + { + lightStage = i; + } + } else if ( stages[ i ].type == stageType_t::ST_GLOWMAP ) { if ( glowStage != -1 ) @@ -4249,6 +4261,7 @@ static void CollapseStages() && ( specularStage != -1 || normalStage != -1 || materialStage != -1 + || lightStage != -1 || glowStage != -1 ) ) { // note that if uncollapsed diffuseStage had to be merged in another stage @@ -4296,6 +4309,12 @@ static void CollapseStages() // disable since it's merged stages[ materialStage ].active = false; } + if ( lightStage != -1 ) + { + // TODO: investigate how to pass rgbGen/alphaGen to implicit lightmap stage + // disable to not paint it over implicit lightmap stage and glow map + stages[ lightStage ].active = false; + } if ( glowStage != -1 ) { // merge with diffuse stage From 650bb3f40be260eb3f8f1909b8803f9027a6fe65 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Wed, 20 Mar 2019 09:54:48 +0100 Subject: [PATCH 3/3] tr_shader: do not collapse custom light stage and glow map if a custome light stage is found, - do not collapse light stage with diffuse stage - do not collapse glow stage with diffuse stage - ensure diffuse < light < glow --- src/engine/renderer/tr_local.h | 2 + src/engine/renderer/tr_shade.cpp | 8 ++++ src/engine/renderer/tr_shader.cpp | 77 ++++++++++++++++++++++++++++--- 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index d1043c3952..b198428c0c 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1088,6 +1088,8 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) bool tcGen_Environment; bool tcGen_Lightmap; + bool disableImplicitLightmap; + Color::Color32Bit constantColor; // for CGEN_CONST and AGEN_CONST uint32_t stateBits; // GLS_xxxx mask diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 6a1132537d..cc465b11b4 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -1262,6 +1262,14 @@ static void Render_lightMapping( int stage, bool asColorMap, bool normalMapping, GL_BindToTMU( 4, tr.blackImage ); } + // do not paintover lightmap + // as a standalone lightmap stage + // will do later + if ( pStage->disableImplicitLightmap ) + { + whiteLight = true; + } + // bind u_LightMap BindLightMap( 3, whiteLight ); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 21e12c86c7..545f7d8559 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -4309,18 +4309,81 @@ static void CollapseStages() // disable since it's merged stages[ materialStage ].active = false; } + // always test for this stage before glow stage if ( lightStage != -1 ) { - // TODO: investigate how to pass rgbGen/alphaGen to implicit lightmap stage - // disable to not paint it over implicit lightmap stage and glow map - stages[ lightStage ].active = false; + // “blendFunc filter” is same as “blendFunc GL_DST_COLOR GL_ZERO” and the default + if ( ( stages[ lightStage ].stateBits & GLS_SRCBLEND_BITS ) == GLS_SRCBLEND_DST_COLOR + && ( stages[ lightStage ].stateBits & GLS_DSTBLEND_BITS ) == GLS_DSTBLEND_ZERO ) + { + // common lightmap stage + // disable to not paint it over implicit light stage and glow map + stages[ lightStage ].active = false; + } + else + { + // custom lightmap stage, disable the implicit light stage and keep + // this one uncollapsed + Log::Debug("found custom lightmap stage in '%s' shader, not collapsing", shader.name); + stages[ diffuseStage ].disableImplicitLightmap = true; + } } + // always test for this stage after light stage if ( glowStage != -1 ) { - // merge with diffuse stage - stages[ diffuseStage ].bundle[ TB_GLOWMAP ] = stages[ glowStage ].bundle[ 0 ]; - // disable since it's merged - stages[ glowStage ].active = false; + // if there is no custom light stage, collapse to the diffuse stage + // that will relie on the implicit light stage + if ( !stages[ diffuseStage ].disableImplicitLightmap ) + { + // merge with diffuse stage + stages[ diffuseStage ].bundle[ TB_GLOWMAP ] = stages[ glowStage ].bundle[ 0 ]; + // disable since it's merged + stages[ glowStage ].active = false; + } + // if there is a custom light stage, keep the glow stage uncollapsed + // and makes sure the diffuse stage precedes the light stage + // and the light stages precedes the glow stage + else + { + Log::Debug("found glow map with custom lightmap stage in '%s' shader, not collapsing", shader.name); + stages[ glowStage ].type = stageType_t::ST_COLORMAP; + stages[ glowStage ].bundle[ TB_COLORMAP ] = stages[ glowStage ].bundle[ 0 ]; + + // we can't be there without collapsing an already found + // diffuse stage that is then not using -1 index + // and since we are there because glow stage is found + // there is no need to secure it more + if ( glowStage < diffuseStage ) + { + // swap stages + shaderStage_t tmpStage = stages [ diffuseStage ]; + stages[ diffuseStage ] = stages [ glowStage ]; + stages [ glowStage ] = tmpStage; + + // swap stage indexes + int tmp = diffuseStage; + diffuseStage = glowStage; + glowStage = tmp; + } + // part of that code is not run if lightStage does not exist + // since disableImplicitLightmap is set when a custom lightStage + // exists and non-existent lightStage has -1 index so it can't + // be smaller than glowStage index, so no need to secure it more + if ( glowStage < lightStage ) + { + // swap stages + shaderStage_t tmpStage = stages [ lightStage ]; + stages[ lightStage ] = stages [ glowStage ]; + stages [ glowStage ] = tmpStage; + + // no need to swap indexes at this point + /* + int tmp = lightStage; + lightStage = glowStage; + glowStage = tmp; + */ + } + } } } }