diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 73a897d94f..b198428c0c 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 }; @@ -1096,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 @@ -1229,7 +1223,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..cc465b11b4 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; @@ -1263,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 ); @@ -2807,12 +2814,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 +3000,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 +3080,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 +3195,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..545f7d8559 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -4149,189 +4149,265 @@ 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 lightStage = -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 ) + if ( stages[ i ].type == stageType_t::ST_DIFFUSEMAP ) + { + if ( diffuseStage != -1 ) { - return collapsibleStages; + Log::Warn( "more than one diffuse map stage in shader '%s'", shader.name ); } - - if ( activeStages[ i ]->type == stageType_t::ST_DIFFUSEMAP && !collapsibleStages.diffuseStage ) + else { - collapsibleStages.diffuseStage = activeStages[ i ]; + diffuseStage = i; } - else if ( activeStages[ i ]->type == stageType_t::ST_NORMALMAP && !collapsibleStages.normalStage ) + } + else if ( stages[ i ].type == stageType_t::ST_NORMALMAP ) + { + if ( normalStage != -1 ) + { + Log::Warn( "more than one normal map stage in shader '%s'", shader.name ); + } + else { - collapsibleStages.normalStage = activeStages[ i ]; + normalStage = i; } - else if ( activeStages[ i ]->type == stageType_t::ST_SPECULARMAP && !collapsibleStages.specularStage ) + } + else if ( stages[ i ].type == stageType_t::ST_SPECULARMAP ) + { + if ( specularStage != -1 ) { - collapsibleStages.specularStage = activeStages[ i ]; + Log::Warn( "more than one specular map stage in shader '%s'", shader.name ); } - else if ( activeStages[ i ]->type == stageType_t::ST_MATERIALMAP && !collapsibleStages.materialStage ) + else { - collapsibleStages.materialStage = activeStages[ i ]; + specularStage = i; } - else if ( activeStages[ i ]->type == stageType_t::ST_REFLECTIONMAP && !collapsibleStages.reflectionStage ) + } + else if ( stages[ i ].type == stageType_t::ST_MATERIALMAP ) + { + if ( materialStage != -1 ) { - collapsibleStages.reflectionStage = activeStages[ i ]; + Log::Warn( "more than one material map stage in shader '%s'", shader.name ); } - else if ( activeStages[ i ]->type == stageType_t::ST_GLOWMAP && !collapsibleStages.glowStage ) + else { - collapsibleStages.glowStage = activeStages[ i ]; + materialStage = 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_REFLECTIONMAP ) { - 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 ( reflectionStage != -1 ) + { + Log::Warn( "more than one reflection map stage in shader '%s'", shader.name ); + } + else + { + reflectionStage = i; + } } - - // try to merge diffuse/normal/specular - else if ( stages3.diffuseStage && stages3.normalStage && stages3.specularStage ) + else if ( stages[ i ].type == stageType_t::ST_LIGHTMAP ) { - 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 ( lightStage != -1 ) + { + Log::Warn( "more than one light map stage in shader '%s'", shader.name ); + } + else + { + lightStage = 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 + || lightStage != -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; + } + // always test for this stage before glow stage + if ( lightStage != -1 ) + { + // “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 ) + { + // 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; + */ + } + } } - ++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 +5466,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 "; }