diff --git a/radiantcore/shaders/Doom3ShaderLayer.cpp b/radiantcore/shaders/Doom3ShaderLayer.cpp index a6affcddd3..db5382a2d8 100644 --- a/radiantcore/shaders/Doom3ShaderLayer.cpp +++ b/radiantcore/shaders/Doom3ShaderLayer.cpp @@ -224,17 +224,18 @@ const IShaderExpression::Ptr& Doom3ShaderLayer::getColourExpression(ColourCompon case COMP_ALPHA: return _expressionSlots[Expression::ColourAlpha].expression; case COMP_RGB: - // Select if all RGB are using the same expression - if (_expressionSlots[Expression::ColourRed].expression == _expressionSlots[Expression::ColourGreen].expression && - _expressionSlots[Expression::ColourGreen].expression == _expressionSlots[Expression::ColourBlue].expression) + // Select if all RGB components are using equivalent expressions + if (_expressionSlots.expressionsAreEquivalent(Expression::ColourRed, Expression::ColourGreen) && + _expressionSlots.expressionsAreEquivalent(Expression::ColourGreen, Expression::ColourBlue)) { return _expressionSlots[Expression::ColourRed].expression; } break; case COMP_RGBA: - if (_expressionSlots[Expression::ColourRed].expression == _expressionSlots[Expression::ColourGreen].expression && - _expressionSlots[Expression::ColourGreen].expression == _expressionSlots[Expression::ColourBlue].expression && - _expressionSlots[Expression::ColourBlue].expression == _expressionSlots[Expression::ColourAlpha].expression) + // Select if all RGBA components are using equivalent expressions + if (_expressionSlots.expressionsAreEquivalent(Expression::ColourRed, Expression::ColourGreen) && + _expressionSlots.expressionsAreEquivalent(Expression::ColourGreen, Expression::ColourBlue) && + _expressionSlots.expressionsAreEquivalent(Expression::ColourBlue, Expression::ColourAlpha)) { return _expressionSlots[Expression::ColourRed].expression; } diff --git a/radiantcore/shaders/ExpressionSlots.cpp b/radiantcore/shaders/ExpressionSlots.cpp index ec7a26af5b..c31daf444a 100644 --- a/radiantcore/shaders/ExpressionSlots.cpp +++ b/radiantcore/shaders/ExpressionSlots.cpp @@ -79,6 +79,24 @@ void ExpressionSlots::assignFromString(IShaderLayer::Expression::Slot slot, cons assign(slot, expression, defaultRegisterIndex); } +bool ExpressionSlots::expressionsAreEquivalent(IShaderLayer::Expression::Slot slotA, IShaderLayer::Expression::Slot slotB) const +{ + auto a = at(slotA); + auto b = at(slotB); + + if (a.expression == b.expression) + { + return true; + } + + if (a.expression && b.expression) + { + return a.expression->getExpressionString() == b.expression->getExpressionString(); + } + + return false; +} + bool ExpressionSlots::registerIsShared(std::size_t index) const { std::size_t useCount = 0; diff --git a/radiantcore/shaders/ExpressionSlots.h b/radiantcore/shaders/ExpressionSlots.h index bfc39a8c3e..355027eb28 100644 --- a/radiantcore/shaders/ExpressionSlots.h +++ b/radiantcore/shaders/ExpressionSlots.h @@ -41,6 +41,11 @@ class ExpressionSlots : // Parsing failures of non-empty strings will not change the slot void assignFromString(IShaderLayer::Expression::Slot slot, const std::string& expression, std::size_t defaultRegisterIndex); + // Returns true if the two given slots are equipped with equivalent expressions + // (i.e. are reference-equal or using the same string representation) + // This also returns true if both slots are empty + bool expressionsAreEquivalent(IShaderLayer::Expression::Slot slotA, IShaderLayer::Expression::Slot slotB) const; + private: // Returns true if the given register index is in use by more than one expression bool registerIsShared(std::size_t index) const; diff --git a/test/Materials.cpp b/test/Materials.cpp index 7aaca314e0..762f997cf9 100644 --- a/test/Materials.cpp +++ b/test/Materials.cpp @@ -1082,4 +1082,82 @@ TEST_F(MaterialsTest, MaterialParserStageFlags) } } +TEST_F(MaterialsTest, MaterialParserStageVertexColours) +{ + auto material = GlobalMaterialManager().getMaterial("textures/parsertest/vertexcolours/none"); + EXPECT_EQ(material->getAllLayers().at(0)->getVertexColourMode(), IShaderLayer::VERTEX_COLOUR_NONE); + + material = GlobalMaterialManager().getMaterial("textures/parsertest/vertexcolours/vertexcolour"); + EXPECT_EQ(material->getAllLayers().at(1)->getVertexColourMode(), IShaderLayer::VERTEX_COLOUR_INVERSE_MULTIPLY); + EXPECT_EQ(material->getAllLayers().at(0)->getVertexColourMode(), IShaderLayer::VERTEX_COLOUR_MULTIPLY); + + material = GlobalMaterialManager().getMaterial("textures/parsertest/vertexcolours/colourcomponents"); + + // Stage 1: Red + EXPECT_EQ(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_RED)->getExpressionString(), "0.5"); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_GREEN)); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_BLUE)); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_ALPHA)); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_RGB)); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_RGBA)); + + // Stage 2: Green + EXPECT_EQ(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_GREEN)->getExpressionString(), "0.4"); + EXPECT_FALSE(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_RED)); + EXPECT_FALSE(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_BLUE)); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_ALPHA)); + EXPECT_FALSE(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_RGB)); + EXPECT_FALSE(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_RGBA)); + + // Stage 3: Blue + EXPECT_EQ(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_BLUE)->getExpressionString(), "0.3"); + EXPECT_FALSE(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_RED)); + EXPECT_FALSE(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_GREEN)); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_ALPHA)); + EXPECT_FALSE(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_RGB)); + EXPECT_FALSE(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_RGBA)); + + // Stage 4: Alpha + EXPECT_EQ(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_ALPHA)->getExpressionString(), "0.2"); + EXPECT_FALSE(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_RED)); + EXPECT_FALSE(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_GREEN)); + EXPECT_FALSE(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_BLUE)); + EXPECT_FALSE(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_RGB)); + EXPECT_FALSE(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_RGBA)); + + material = GlobalMaterialManager().getMaterial("textures/parsertest/vertexcolours/combinations"); + + // Stage 1: RGB the same, alpha is different + EXPECT_EQ(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_RED)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_GREEN)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_BLUE)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_ALPHA)->getExpressionString(), "time"); + EXPECT_EQ(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_RGB)->getExpressionString(), "0.5"); + EXPECT_FALSE(material->getAllLayers().at(0)->getColourExpression(IShaderLayer::COMP_RGBA)); + + // Stage 2: RGBA all the same + EXPECT_EQ(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_RED)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_GREEN)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_BLUE)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_ALPHA)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_RGB)->getExpressionString(), "0.5"); + EXPECT_EQ(material->getAllLayers().at(1)->getColourExpression(IShaderLayer::COMP_RGBA)->getExpressionString(), "0.5"); + + // Stage 3: RGB overridden by red + EXPECT_EQ(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_RED)->getExpressionString(), "0.4"); + EXPECT_EQ(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_GREEN)->getExpressionString(), "0.3"); + EXPECT_EQ(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_BLUE)->getExpressionString(), "0.3"); + EXPECT_FALSE(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_ALPHA)); + EXPECT_FALSE(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_RGB)); + EXPECT_FALSE(material->getAllLayers().at(2)->getColourExpression(IShaderLayer::COMP_RGBA)); + + // Stage 4: RGBA overridden by alpha + EXPECT_EQ(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_RED)->getExpressionString(), "0.2"); + EXPECT_EQ(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_GREEN)->getExpressionString(), "0.2"); + EXPECT_EQ(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_BLUE)->getExpressionString(), "0.2"); + EXPECT_EQ(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_ALPHA)->getExpressionString(), "time"); + EXPECT_EQ(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_RGB)->getExpressionString(), "0.2"); + EXPECT_FALSE(material->getAllLayers().at(3)->getColourExpression(IShaderLayer::COMP_RGBA)); +} + } diff --git a/test/resources/tdm/materials/parsertest.mtr b/test/resources/tdm/materials/parsertest.mtr index ab1a6d743c..a6be547fab 100644 --- a/test/resources/tdm/materials/parsertest.mtr +++ b/test/resources/tdm/materials/parsertest.mtr @@ -765,3 +765,78 @@ textures/parsertest/stageflags/maskEverything maskDepth } } + +textures/parsertest/vertexcolours/none +{ + diffusemap _white +} + +textures/parsertest/vertexcolours/vertexcolour +{ + { + blend diffusemap + map _white + vertexColor + } + { + blend diffusemap + map _white + inverseVertexColor + } +} + +textures/parsertest/vertexcolours/colourcomponents +{ + { + blend diffusemap + map _white + red 0.5 + } + { + blend diffusemap + map _white + green 0.4 + } + { + blend diffusemap + map _white + blue 0.3 + } + { + blend diffusemap + map _white + alpha 0.2 + } +} + +textures/parsertest/vertexcolours/combinations +{ + { + blend diffusemap + map _white + red 0.5 + green 0.5 + blue 0.5 + alpha time // alpha is different + } + { + blend diffusemap + map _white + red 0.5 + green 0.5 + blue 0.5 + alpha 0.5 + } + { + blend diffusemap + map _white + rgb 0.3 + red 0.4 + } + { + blend diffusemap + map _white + rgba 0.2 + alpha time + } +}