From 77a1d5000cac024e7c7504fc8b1fe5a494991410 Mon Sep 17 00:00:00 2001 From: codereader Date: Fri, 2 Apr 2021 08:36:52 +0200 Subject: [PATCH] #5567: Frob stage detection code --- libs/materials/FrobStageSetup.h | 105 +++++++++++++++++- .../ui/materials/editor/MaterialEditor.cpp | 5 + test/Materials.cpp | 12 ++ 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/libs/materials/FrobStageSetup.h b/libs/materials/FrobStageSetup.h index adab45adfe..cafba581c3 100644 --- a/libs/materials/FrobStageSetup.h +++ b/libs/materials/FrobStageSetup.h @@ -6,19 +6,122 @@ namespace shaders { +/** + * Helper class handling the two default frob stages on TDM materials. + * The two frob stages look like this: + * + * // Blend _white stage + * { + * if ( parm11 > 0 ) + * blend gl_dst_color, gl_one + * map _white + * rgb 0.40 * parm11 + * } + * + * // Additive blend of the material's diffuse map + * { + * if ( parm11 > 0 ) + * blend add + * map textures/numbers/0 + * rgb 0.15 * parm11 + * } + */ class FrobStageSetup { public: - static bool IsPresent(const MaterialPtr& material) + static bool HasWhiteBlendStage(const MaterialPtr& material) { + for (const auto& layer : material->getAllLayers()) + { + // if ( parm11 > 0 ) + if (!layer->getConditionExpression() || layer->getConditionExpression()->getExpressionString() != "(parm11 > 0.0)") + { + continue; + } + + // blend gl_dst_color, gl_one + if (layer->getBlendFuncStrings().first != "gl_dst_color" || layer->getBlendFuncStrings().second != "gl_one") + { + continue; + } + + // map _white + if (!layer->getMapExpression() || layer->getMapExpression()->getExpressionString() != "_white") + { + continue; + } + + // rgb 0.40 * parm11 + auto rgb = layer->getColourExpression(IShaderLayer::COMP_RGB); + + if (rgb && rgb->getExpressionString() == "0.4 * parm11") + { + return true; + } + } + + return false; + } + + static bool HasAdditiveDiffuseStage(const MaterialPtr& material) + { + auto diffuse = GetDiffuseMap(material); + + if (diffuse.empty()) return false; + for (const auto& layer : material->getAllLayers()) + { + // if ( parm11 > 0 ) + if (!layer->getConditionExpression() || layer->getConditionExpression()->getExpressionString() != "(parm11 > 0.0)") + { + continue; + } + + // blend add + if (layer->getBlendFuncStrings().first != "add" || !layer->getBlendFuncStrings().second.empty()) + { + continue; + } + + // map + if (!layer->getMapExpression() || layer->getMapExpression()->getExpressionString() != diffuse) + { + continue; + } + + // rgb 0.15 * parm11 + auto rgb = layer->getColourExpression(IShaderLayer::COMP_RGB); + + if (rgb && rgb->getExpressionString() == "0.15 * parm11") + { + return true; + } + } return false; } + // Checks whether the default frob stages are present on this material + static bool IsPresent(const MaterialPtr& material) + { + if (!material) return false; + + auto diffuse = GetDiffuseMap(material); + + return !diffuse.empty() && HasWhiteBlendStage(material) && HasAdditiveDiffuseStage(material); + } + private: static std::string GetDiffuseMap(const MaterialPtr& material) { + for (const auto& layer : material->getAllLayers()) + { + if (layer->getType() == IShaderLayer::DIFFUSE && layer->getMapExpression()) + { + return layer->getMapExpression()->getExpressionString(); + } + } + return std::string(); } }; diff --git a/radiant/ui/materials/editor/MaterialEditor.cpp b/radiant/ui/materials/editor/MaterialEditor.cpp index b5250529dc..5d2e05eb8f 100644 --- a/radiant/ui/materials/editor/MaterialEditor.cpp +++ b/radiant/ui/materials/editor/MaterialEditor.cpp @@ -24,6 +24,7 @@ #include "wxutil/dataview/ResourceTreeViewToolbar.h" #include "wxutil/dataview/TreeViewItemStyle.h" #include "wxutil/Bitmap.h" +#include "materials/FrobStageSetup.h" #include #include "gamelib.h" #include "string/join.h" @@ -1610,7 +1611,11 @@ void MaterialEditor::updateBasicFrobStageControls() auto addFrob = getControl("BasicAddFrobStages"); auto removeFrob = getControl("BasicRemoveFrobStages"); + bool hasFrobStages = shaders::FrobStageSetup::IsPresent(_material); + bool materialCanBeModified = _material && GlobalMaterialManager().materialCanBeModified(_material->getName()); + addFrob->Enable(materialCanBeModified && !hasFrobStages); + removeFrob->Enable(materialCanBeModified && hasFrobStages); } void MaterialEditor::updateBasicImagePreview() diff --git a/test/Materials.cpp b/test/Materials.cpp index e5a99832df..f8f6b7f677 100644 --- a/test/Materials.cpp +++ b/test/Materials.cpp @@ -1406,21 +1406,33 @@ TEST_F(MaterialsTest, MaterialFrobStageDetection) { auto material = GlobalMaterialManager().getMaterial("textures/parsertest/frobstage_present1"); EXPECT_TRUE(shaders::FrobStageSetup::IsPresent(material)); + EXPECT_TRUE(shaders::FrobStageSetup::HasAdditiveDiffuseStage(material)); + EXPECT_TRUE(shaders::FrobStageSetup::HasWhiteBlendStage(material)); material = GlobalMaterialManager().getMaterial("textures/parsertest/frobstage_missing1"); EXPECT_FALSE(shaders::FrobStageSetup::IsPresent(material)); + EXPECT_FALSE(shaders::FrobStageSetup::HasAdditiveDiffuseStage(material)); + EXPECT_FALSE(shaders::FrobStageSetup::HasWhiteBlendStage(material)); material = GlobalMaterialManager().getMaterial("textures/parsertest/frobstage_missing2"); EXPECT_FALSE(shaders::FrobStageSetup::IsPresent(material)); + EXPECT_FALSE(shaders::FrobStageSetup::HasAdditiveDiffuseStage(material)); + EXPECT_TRUE(shaders::FrobStageSetup::HasWhiteBlendStage(material)); material = GlobalMaterialManager().getMaterial("textures/parsertest/frobstage_missing3"); EXPECT_FALSE(shaders::FrobStageSetup::IsPresent(material)); + EXPECT_TRUE(shaders::FrobStageSetup::HasAdditiveDiffuseStage(material)); + EXPECT_FALSE(shaders::FrobStageSetup::HasWhiteBlendStage(material)); material = GlobalMaterialManager().getMaterial("textures/parsertest/frobstage_missing4"); EXPECT_FALSE(shaders::FrobStageSetup::IsPresent(material)); + EXPECT_FALSE(shaders::FrobStageSetup::HasAdditiveDiffuseStage(material)); + EXPECT_TRUE(shaders::FrobStageSetup::HasWhiteBlendStage(material)); material = GlobalMaterialManager().getMaterial("textures/parsertest/frobstage_missing5"); EXPECT_FALSE(shaders::FrobStageSetup::IsPresent(material)); + EXPECT_FALSE(shaders::FrobStageSetup::HasAdditiveDiffuseStage(material)); + EXPECT_TRUE(shaders::FrobStageSetup::HasWhiteBlendStage(material)); } }