| /**************************************************************************** |
| ** |
| ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| |
| #include <QtTest/QtTest> |
| |
| #include <QtGui/private/qshadergraph_p.h> |
| |
| namespace |
| { |
| QShaderNodePort createPort(QShaderNodePort::Direction portDirection, const QString &portName) |
| { |
| auto port = QShaderNodePort(); |
| port.direction = portDirection; |
| port.name = portName; |
| return port; |
| } |
| |
| QShaderNode createNode(const QVector<QShaderNodePort> &ports, const QStringList &layers = QStringList()) |
| { |
| auto node = QShaderNode(); |
| node.setUuid(QUuid::createUuid()); |
| node.setLayers(layers); |
| for (const auto &port : ports) |
| node.addPort(port); |
| return node; |
| } |
| |
| QShaderGraph::Edge createEdge(const QUuid &sourceUuid, const QString &sourceName, |
| const QUuid &targetUuid, const QString &targetName, |
| const QStringList &layers = QStringList()) |
| { |
| auto edge = QShaderGraph::Edge(); |
| edge.sourceNodeUuid = sourceUuid; |
| edge.sourcePortName = sourceName; |
| edge.targetNodeUuid = targetUuid; |
| edge.targetPortName = targetName; |
| edge.layers = layers; |
| return edge; |
| } |
| |
| QShaderGraph::Statement createStatement(const QShaderNode &node, |
| const QVector<int> &inputs = QVector<int>(), |
| const QVector<int> &outputs = QVector<int>()) |
| { |
| auto statement = QShaderGraph::Statement(); |
| statement.node = node; |
| statement.inputs = inputs; |
| statement.outputs = outputs; |
| return statement; |
| } |
| |
| void debugStatement(const QString &prefix, const QShaderGraph::Statement &statement) |
| { |
| qDebug() << prefix << statement.inputs << statement.uuid().toString() << statement.outputs; |
| } |
| |
| void dumpStatementsIfNeeded(const QVector<QShaderGraph::Statement> &statements, const QVector<QShaderGraph::Statement> &expected) |
| { |
| if (statements != expected) { |
| for (int i = 0; i < qMax(statements.size(), expected.size()); i++) { |
| qDebug() << "----" << i << "----"; |
| if (i < statements.size()) |
| debugStatement("A:", statements.at(i)); |
| if (i < expected.size()) |
| debugStatement("E:", expected.at(i)); |
| qDebug() << "-----------"; |
| } |
| } |
| } |
| } |
| |
| class tst_QShaderGraph : public QObject |
| { |
| Q_OBJECT |
| private slots: |
| void shouldHaveEdgeDefaultState(); |
| void shouldTestEdgesEquality_data(); |
| void shouldTestEdgesEquality(); |
| void shouldManipulateStatementMembers(); |
| void shouldTestStatementsEquality_data(); |
| void shouldTestStatementsEquality(); |
| void shouldFindIndexFromPortNameInStatements_data(); |
| void shouldFindIndexFromPortNameInStatements(); |
| void shouldManageNodeList(); |
| void shouldManageEdgeList(); |
| void shouldSerializeGraphForCodeGeneration(); |
| void shouldHandleUnboundPortsDuringGraphSerialization(); |
| void shouldSurviveCyclesDuringGraphSerialization(); |
| void shouldDealWithEdgesJumpingOverLayers(); |
| void shouldGenerateDifferentStatementsDependingOnActiveLayers(); |
| }; |
| |
| void tst_QShaderGraph::shouldHaveEdgeDefaultState() |
| { |
| // GIVEN |
| auto edge = QShaderGraph::Edge(); |
| |
| // THEN |
| QVERIFY(edge.sourceNodeUuid.isNull()); |
| QVERIFY(edge.sourcePortName.isEmpty()); |
| QVERIFY(edge.targetNodeUuid.isNull()); |
| QVERIFY(edge.targetPortName.isEmpty()); |
| } |
| |
| void tst_QShaderGraph::shouldTestEdgesEquality_data() |
| { |
| QTest::addColumn<QShaderGraph::Edge>("left"); |
| QTest::addColumn<QShaderGraph::Edge>("right"); |
| QTest::addColumn<bool>("expected"); |
| |
| const auto sourceUuid1 = QUuid::createUuid(); |
| const auto sourceUuid2 = QUuid::createUuid(); |
| const auto targetUuid1 = QUuid::createUuid(); |
| const auto targetUuid2 = QUuid::createUuid(); |
| |
| QTest::newRow("Equals") << createEdge(sourceUuid1, "foo", targetUuid1, "bar") |
| << createEdge(sourceUuid1, "foo", targetUuid1, "bar") |
| << true; |
| QTest::newRow("SourceUuid") << createEdge(sourceUuid1, "foo", targetUuid1, "bar") |
| << createEdge(sourceUuid2, "foo", targetUuid1, "bar") |
| << false; |
| QTest::newRow("SourceName") << createEdge(sourceUuid1, "foo", targetUuid1, "bar") |
| << createEdge(sourceUuid1, "bleh", targetUuid1, "bar") |
| << false; |
| QTest::newRow("TargetUuid") << createEdge(sourceUuid1, "foo", targetUuid1, "bar") |
| << createEdge(sourceUuid1, "foo", targetUuid2, "bar") |
| << false; |
| QTest::newRow("TargetName") << createEdge(sourceUuid1, "foo", targetUuid1, "bar") |
| << createEdge(sourceUuid1, "foo", targetUuid1, "bleh") |
| << false; |
| } |
| |
| void tst_QShaderGraph::shouldTestEdgesEquality() |
| { |
| // GIVEN |
| QFETCH(QShaderGraph::Edge, left); |
| QFETCH(QShaderGraph::Edge, right); |
| |
| // WHEN |
| const auto equal = (left == right); |
| const auto notEqual = (left != right); |
| |
| // THEN |
| QFETCH(bool, expected); |
| QCOMPARE(equal, expected); |
| QCOMPARE(notEqual, !expected); |
| } |
| |
| void tst_QShaderGraph::shouldManipulateStatementMembers() |
| { |
| // GIVEN |
| auto statement = QShaderGraph::Statement(); |
| |
| // THEN (default state) |
| QVERIFY(statement.inputs.isEmpty()); |
| QVERIFY(statement.outputs.isEmpty()); |
| QVERIFY(statement.node.uuid().isNull()); |
| QVERIFY(statement.uuid().isNull()); |
| |
| // WHEN |
| const auto node = createNode({}); |
| statement.node = node; |
| |
| // THEN |
| QCOMPARE(statement.uuid(), node.uuid()); |
| |
| // WHEN |
| statement.node = QShaderNode(); |
| |
| // THEN |
| QVERIFY(statement.uuid().isNull()); |
| } |
| |
| void tst_QShaderGraph::shouldTestStatementsEquality_data() |
| { |
| QTest::addColumn<QShaderGraph::Statement>("left"); |
| QTest::addColumn<QShaderGraph::Statement>("right"); |
| QTest::addColumn<bool>("expected"); |
| |
| const auto node1 = createNode({}); |
| const auto node2 = createNode({}); |
| |
| QTest::newRow("EqualNodes") << createStatement(node1, {1, 2}, {3, 4}) |
| << createStatement(node1, {1, 2}, {3, 4}) |
| << true; |
| QTest::newRow("EqualInvalids") << createStatement(QShaderNode(), {1, 2}, {3, 4}) |
| << createStatement(QShaderNode(), {1, 2}, {3, 4}) |
| << true; |
| QTest::newRow("Nodes") << createStatement(node1, {1, 2}, {3, 4}) |
| << createStatement(node2, {1, 2}, {3, 4}) |
| << false; |
| QTest::newRow("Inputs") << createStatement(node1, {1, 2}, {3, 4}) |
| << createStatement(node1, {1, 2, 0}, {3, 4}) |
| << false; |
| QTest::newRow("Outputs") << createStatement(node1, {1, 2}, {3, 4}) |
| << createStatement(node1, {1, 2}, {3, 0, 4}) |
| << false; |
| } |
| |
| void tst_QShaderGraph::shouldTestStatementsEquality() |
| { |
| // GIVEN |
| QFETCH(QShaderGraph::Statement, left); |
| QFETCH(QShaderGraph::Statement, right); |
| |
| // WHEN |
| const auto equal = (left == right); |
| const auto notEqual = (left != right); |
| |
| // THEN |
| QFETCH(bool, expected); |
| QCOMPARE(equal, expected); |
| QCOMPARE(notEqual, !expected); |
| } |
| |
| void tst_QShaderGraph::shouldFindIndexFromPortNameInStatements_data() |
| { |
| QTest::addColumn<QShaderGraph::Statement>("statement"); |
| QTest::addColumn<QString>("portName"); |
| QTest::addColumn<int>("expectedInputIndex"); |
| QTest::addColumn<int>("expectedOutputIndex"); |
| |
| const auto inputNodeStatement = createStatement(createNode({ |
| createPort(QShaderNodePort::Output, "input") |
| })); |
| const auto outputNodeStatement = createStatement(createNode({ |
| createPort(QShaderNodePort::Input, "output") |
| })); |
| const auto functionNodeStatement = createStatement(createNode({ |
| createPort(QShaderNodePort::Input, "input1"), |
| createPort(QShaderNodePort::Output, "output1"), |
| createPort(QShaderNodePort::Input, "input2"), |
| createPort(QShaderNodePort::Output, "output2"), |
| createPort(QShaderNodePort::Output, "output3"), |
| createPort(QShaderNodePort::Input, "input3") |
| })); |
| |
| QTest::newRow("Invalid") << QShaderGraph::Statement() << "foo" << -1 << -1; |
| QTest::newRow("InputNodeWrongName") << inputNodeStatement << "foo" << -1 << -1; |
| QTest::newRow("InputNodeExistingName") << inputNodeStatement << "input" << -1 << 0; |
| QTest::newRow("OutputNodeWrongName") << outputNodeStatement << "foo" << -1 << -1; |
| QTest::newRow("OutputNodeExistingName") << outputNodeStatement << "output" << 0 << -1; |
| QTest::newRow("FunctionNodeWrongName") << functionNodeStatement << "foo" << -1 << -1; |
| QTest::newRow("FunctionNodeInput1") << functionNodeStatement << "input1" << 0 << -1; |
| QTest::newRow("FunctionNodeOutput1") << functionNodeStatement << "output1" << -1 << 0; |
| QTest::newRow("FunctionNodeInput2") << functionNodeStatement << "input2" << 1 << -1; |
| QTest::newRow("FunctionNodeOutput2") << functionNodeStatement << "output2" << -1 << 1; |
| QTest::newRow("FunctionNodeInput3") << functionNodeStatement << "input3" << 2 << -1; |
| QTest::newRow("FunctionNodeOutput3") << functionNodeStatement << "output3" << -1 << 2; |
| } |
| |
| void tst_QShaderGraph::shouldFindIndexFromPortNameInStatements() |
| { |
| // GIVEN |
| QFETCH(QShaderGraph::Statement, statement); |
| QFETCH(QString, portName); |
| QFETCH(int, expectedInputIndex); |
| QFETCH(int, expectedOutputIndex); |
| |
| // WHEN |
| const auto inputIndex = statement.portIndex(QShaderNodePort::Input, portName); |
| const auto outputIndex = statement.portIndex(QShaderNodePort::Output, portName); |
| |
| // THEN |
| QCOMPARE(inputIndex, expectedInputIndex); |
| QCOMPARE(outputIndex, expectedOutputIndex); |
| } |
| |
| void tst_QShaderGraph::shouldManageNodeList() |
| { |
| // GIVEN |
| const auto node1 = createNode({createPort(QShaderNodePort::Output, "node1")}); |
| const auto node2 = createNode({createPort(QShaderNodePort::Output, "node2")}); |
| |
| auto graph = QShaderGraph(); |
| |
| // THEN (default state) |
| QVERIFY(graph.nodes().isEmpty()); |
| |
| // WHEN |
| graph.addNode(node1); |
| |
| // THEN |
| QCOMPARE(graph.nodes().size(), 1); |
| QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid()); |
| QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name); |
| |
| // WHEN |
| graph.addNode(node2); |
| |
| // THEN |
| QCOMPARE(graph.nodes().size(), 2); |
| QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid()); |
| QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name); |
| QCOMPARE(graph.nodes().at(1).uuid(), node2.uuid()); |
| QCOMPARE(graph.nodes().at(1).ports().at(0).name, node2.ports().at(0).name); |
| |
| |
| // WHEN |
| graph.removeNode(node2); |
| |
| // THEN |
| QCOMPARE(graph.nodes().size(), 1); |
| QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid()); |
| QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name); |
| |
| // WHEN |
| graph.addNode(node2); |
| |
| // THEN |
| QCOMPARE(graph.nodes().size(), 2); |
| QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid()); |
| QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name); |
| QCOMPARE(graph.nodes().at(1).uuid(), node2.uuid()); |
| QCOMPARE(graph.nodes().at(1).ports().at(0).name, node2.ports().at(0).name); |
| |
| // WHEN |
| const auto node1bis = [node1] { |
| auto res = node1; |
| auto port = res.ports().at(0); |
| port.name = QStringLiteral("node1bis"); |
| res.addPort(port); |
| return res; |
| }(); |
| graph.addNode(node1bis); |
| |
| // THEN |
| QCOMPARE(graph.nodes().size(), 2); |
| QCOMPARE(graph.nodes().at(0).uuid(), node2.uuid()); |
| QCOMPARE(graph.nodes().at(0).ports().at(0).name, node2.ports().at(0).name); |
| QCOMPARE(graph.nodes().at(1).uuid(), node1bis.uuid()); |
| QCOMPARE(graph.nodes().at(1).ports().at(0).name, node1bis.ports().at(0).name); |
| } |
| |
| void tst_QShaderGraph::shouldManageEdgeList() |
| { |
| // GIVEN |
| const auto edge1 = createEdge(QUuid::createUuid(), "foo", QUuid::createUuid(), "bar"); |
| const auto edge2 = createEdge(QUuid::createUuid(), "baz", QUuid::createUuid(), "boo"); |
| |
| auto graph = QShaderGraph(); |
| |
| // THEN (default state) |
| QVERIFY(graph.edges().isEmpty()); |
| |
| // WHEN |
| graph.addEdge(edge1); |
| |
| // THEN |
| QCOMPARE(graph.edges().size(), 1); |
| QCOMPARE(graph.edges().at(0), edge1); |
| |
| // WHEN |
| graph.addEdge(edge2); |
| |
| // THEN |
| QCOMPARE(graph.edges().size(), 2); |
| QCOMPARE(graph.edges().at(0), edge1); |
| QCOMPARE(graph.edges().at(1), edge2); |
| |
| |
| // WHEN |
| graph.removeEdge(edge2); |
| |
| // THEN |
| QCOMPARE(graph.edges().size(), 1); |
| QCOMPARE(graph.edges().at(0), edge1); |
| |
| // WHEN |
| graph.addEdge(edge2); |
| |
| // THEN |
| QCOMPARE(graph.edges().size(), 2); |
| QCOMPARE(graph.edges().at(0), edge1); |
| QCOMPARE(graph.edges().at(1), edge2); |
| |
| // WHEN |
| graph.addEdge(edge1); |
| |
| // THEN |
| QCOMPARE(graph.edges().size(), 2); |
| QCOMPARE(graph.edges().at(0), edge1); |
| QCOMPARE(graph.edges().at(1), edge2); |
| } |
| |
| void tst_QShaderGraph::shouldSerializeGraphForCodeGeneration() |
| { |
| // GIVEN |
| const auto input1 = createNode({ |
| createPort(QShaderNodePort::Output, "input1Value") |
| }); |
| const auto input2 = createNode({ |
| createPort(QShaderNodePort::Output, "input2Value") |
| }); |
| const auto output1 = createNode({ |
| createPort(QShaderNodePort::Input, "output1Value") |
| }); |
| const auto output2 = createNode({ |
| createPort(QShaderNodePort::Input, "output2Value") |
| }); |
| const auto function1 = createNode({ |
| createPort(QShaderNodePort::Input, "function1Input"), |
| createPort(QShaderNodePort::Output, "function1Output") |
| }); |
| const auto function2 = createNode({ |
| createPort(QShaderNodePort::Input, "function2Input1"), |
| createPort(QShaderNodePort::Input, "function2Input2"), |
| createPort(QShaderNodePort::Output, "function2Output") |
| }); |
| const auto function3 = createNode({ |
| createPort(QShaderNodePort::Input, "function3Input1"), |
| createPort(QShaderNodePort::Input, "function3Input2"), |
| createPort(QShaderNodePort::Output, "function3Output1"), |
| createPort(QShaderNodePort::Output, "function3Output2") |
| }); |
| |
| const auto graph = [=] { |
| auto res = QShaderGraph(); |
| res.addNode(input1); |
| res.addNode(input2); |
| res.addNode(output1); |
| res.addNode(output2); |
| res.addNode(function1); |
| res.addNode(function2); |
| res.addNode(function3); |
| res.addEdge(createEdge(input1.uuid(), "input1Value", function1.uuid(), "function1Input")); |
| res.addEdge(createEdge(input1.uuid(), "input1Value", function2.uuid(), "function2Input1")); |
| res.addEdge(createEdge(input2.uuid(), "input2Value", function2.uuid(), "function2Input2")); |
| res.addEdge(createEdge(function1.uuid(), "function1Output", function3.uuid(), "function3Input1")); |
| res.addEdge(createEdge(function2.uuid(), "function2Output", function3.uuid(), "function3Input2")); |
| res.addEdge(createEdge(function3.uuid(), "function3Output1", output1.uuid(), "output1Value")); |
| res.addEdge(createEdge(function3.uuid(), "function3Output2", output2.uuid(), "output2Value")); |
| return res; |
| }(); |
| |
| // WHEN |
| const auto statements = graph.createStatements(); |
| |
| // THEN |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(input2, {}, {1}) |
| << createStatement(input1, {}, {0}) |
| << createStatement(function2, {0, 1}, {3}) |
| << createStatement(function1, {0}, {2}) |
| << createStatement(function3, {2, 3}, {4, 5}) |
| << createStatement(output2, {5}, {}) |
| << createStatement(output1, {4}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| |
| void tst_QShaderGraph::shouldHandleUnboundPortsDuringGraphSerialization() |
| { |
| // GIVEN |
| const auto input = createNode({ |
| createPort(QShaderNodePort::Output, "input") |
| }); |
| const auto unboundInput = createNode({ |
| createPort(QShaderNodePort::Output, "unbound") |
| }); |
| const auto output = createNode({ |
| createPort(QShaderNodePort::Input, "output") |
| }); |
| const auto unboundOutput = createNode({ |
| createPort(QShaderNodePort::Input, "unbound") |
| }); |
| const auto function = createNode({ |
| createPort(QShaderNodePort::Input, "functionInput1"), |
| createPort(QShaderNodePort::Input, "functionInput2"), |
| createPort(QShaderNodePort::Input, "functionInput3"), |
| createPort(QShaderNodePort::Output, "functionOutput1"), |
| createPort(QShaderNodePort::Output, "functionOutput2"), |
| createPort(QShaderNodePort::Output, "functionOutput3") |
| }); |
| |
| const auto graph = [=] { |
| auto res = QShaderGraph(); |
| res.addNode(input); |
| res.addNode(unboundInput); |
| res.addNode(output); |
| res.addNode(unboundOutput); |
| res.addNode(function); |
| res.addEdge(createEdge(input.uuid(), "input", function.uuid(), "functionInput2")); |
| res.addEdge(createEdge(function.uuid(), "functionOutput2", output.uuid(), "output")); |
| return res; |
| }(); |
| |
| // WHEN |
| const auto statements = graph.createStatements(); |
| |
| // THEN |
| // Note that no edge leads to the unbound input |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(input, {}, {0}) |
| << createStatement(function, {-1, 0, -1}, {2, 3, 4}) |
| << createStatement(unboundOutput, {-1}, {}) |
| << createStatement(output, {3}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| |
| void tst_QShaderGraph::shouldSurviveCyclesDuringGraphSerialization() |
| { |
| // GIVEN |
| const auto input = createNode({ |
| createPort(QShaderNodePort::Output, "input") |
| }); |
| const auto output = createNode({ |
| createPort(QShaderNodePort::Input, "output") |
| }); |
| const auto function1 = createNode({ |
| createPort(QShaderNodePort::Input, "function1Input1"), |
| createPort(QShaderNodePort::Input, "function1Input2"), |
| createPort(QShaderNodePort::Output, "function1Output") |
| }); |
| const auto function2 = createNode({ |
| createPort(QShaderNodePort::Input, "function2Input"), |
| createPort(QShaderNodePort::Output, "function2Output") |
| }); |
| const auto function3 = createNode({ |
| createPort(QShaderNodePort::Input, "function3Input"), |
| createPort(QShaderNodePort::Output, "function3Output") |
| }); |
| |
| const auto graph = [=] { |
| auto res = QShaderGraph(); |
| res.addNode(input); |
| res.addNode(output); |
| res.addNode(function1); |
| res.addNode(function2); |
| res.addNode(function3); |
| res.addEdge(createEdge(input.uuid(), "input", function1.uuid(), "function1Input1")); |
| res.addEdge(createEdge(function1.uuid(), "function1Output", function2.uuid(), "function2Input")); |
| res.addEdge(createEdge(function2.uuid(), "function2Output", function3.uuid(), "function3Input")); |
| res.addEdge(createEdge(function3.uuid(), "function3Output", function1.uuid(), "function1Input2")); |
| res.addEdge(createEdge(function2.uuid(), "function2Output", output.uuid(), "output")); |
| return res; |
| }(); |
| |
| // WHEN |
| const auto statements = graph.createStatements(); |
| |
| // THEN |
| // Obviously will lead to a compile failure later on since it cuts everything beyond the cycle |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(output, {2}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| |
| void tst_QShaderGraph::shouldDealWithEdgesJumpingOverLayers() |
| { |
| // GIVEN |
| const auto worldPosition = createNode({ |
| createPort(QShaderNodePort::Output, "worldPosition") |
| }); |
| const auto texture = createNode({ |
| createPort(QShaderNodePort::Output, "texture") |
| }); |
| const auto texCoord = createNode({ |
| createPort(QShaderNodePort::Output, "texCoord") |
| }); |
| const auto lightIntensity = createNode({ |
| createPort(QShaderNodePort::Output, "lightIntensity") |
| }); |
| const auto exposure = createNode({ |
| createPort(QShaderNodePort::Output, "exposure") |
| }); |
| const auto fragColor = createNode({ |
| createPort(QShaderNodePort::Input, "fragColor") |
| }); |
| const auto sampleTexture = createNode({ |
| createPort(QShaderNodePort::Input, "sampler"), |
| createPort(QShaderNodePort::Input, "coord"), |
| createPort(QShaderNodePort::Output, "color") |
| }); |
| const auto lightFunction = createNode({ |
| createPort(QShaderNodePort::Input, "baseColor"), |
| createPort(QShaderNodePort::Input, "position"), |
| createPort(QShaderNodePort::Input, "lightIntensity"), |
| createPort(QShaderNodePort::Output, "outputColor") |
| }); |
| const auto exposureFunction = createNode({ |
| createPort(QShaderNodePort::Input, "inputColor"), |
| createPort(QShaderNodePort::Input, "exposure"), |
| createPort(QShaderNodePort::Output, "outputColor") |
| }); |
| |
| const auto graph = [=] { |
| auto res = QShaderGraph(); |
| |
| res.addNode(worldPosition); |
| res.addNode(texture); |
| res.addNode(texCoord); |
| res.addNode(lightIntensity); |
| res.addNode(exposure); |
| res.addNode(fragColor); |
| res.addNode(sampleTexture); |
| res.addNode(lightFunction); |
| res.addNode(exposureFunction); |
| |
| res.addEdge(createEdge(texture.uuid(), "texture", sampleTexture.uuid(), "sampler")); |
| res.addEdge(createEdge(texCoord.uuid(), "texCoord", sampleTexture.uuid(), "coord")); |
| |
| res.addEdge(createEdge(worldPosition.uuid(), "worldPosition", lightFunction.uuid(), "position")); |
| res.addEdge(createEdge(sampleTexture.uuid(), "color", lightFunction.uuid(), "baseColor")); |
| res.addEdge(createEdge(lightIntensity.uuid(), "lightIntensity", lightFunction.uuid(), "lightIntensity")); |
| |
| res.addEdge(createEdge(lightFunction.uuid(), "outputColor", exposureFunction.uuid(), "inputColor")); |
| res.addEdge(createEdge(exposure.uuid(), "exposure", exposureFunction.uuid(), "exposure")); |
| |
| res.addEdge(createEdge(exposureFunction.uuid(), "outputColor", fragColor.uuid(), "fragColor")); |
| |
| return res; |
| }(); |
| |
| // WHEN |
| const auto statements = graph.createStatements(); |
| |
| // THEN |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(texCoord, {}, {2}) |
| << createStatement(texture, {}, {1}) |
| << createStatement(lightIntensity, {}, {3}) |
| << createStatement(sampleTexture, {1, 2}, {5}) |
| << createStatement(worldPosition, {}, {0}) |
| << createStatement(exposure, {}, {4}) |
| << createStatement(lightFunction, {5, 0, 3}, {6}) |
| << createStatement(exposureFunction, {6, 4}, {7}) |
| << createStatement(fragColor, {7}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| |
| void tst_QShaderGraph::shouldGenerateDifferentStatementsDependingOnActiveLayers() |
| { |
| // GIVEN |
| const auto texCoord = createNode({ |
| createPort(QShaderNodePort::Output, "texCoord") |
| }, { |
| "diffuseTexture", |
| "normalTexture" |
| }); |
| const auto diffuseUniform = createNode({ |
| createPort(QShaderNodePort::Output, "color") |
| }, {"diffuseUniform"}); |
| const auto diffuseTexture = createNode({ |
| createPort(QShaderNodePort::Input, "coord"), |
| createPort(QShaderNodePort::Output, "color") |
| }, {"diffuseTexture"}); |
| const auto normalUniform = createNode({ |
| createPort(QShaderNodePort::Output, "normal") |
| }, {"normalUniform"}); |
| const auto normalTexture = createNode({ |
| createPort(QShaderNodePort::Input, "coord"), |
| createPort(QShaderNodePort::Output, "normal") |
| }, {"normalTexture"}); |
| const auto lightFunction = createNode({ |
| createPort(QShaderNodePort::Input, "color"), |
| createPort(QShaderNodePort::Input, "normal"), |
| createPort(QShaderNodePort::Output, "output") |
| }); |
| const auto fragColor = createNode({ |
| createPort(QShaderNodePort::Input, "fragColor") |
| }); |
| |
| const auto graph = [=] { |
| auto res = QShaderGraph(); |
| |
| res.addNode(texCoord); |
| res.addNode(diffuseUniform); |
| res.addNode(diffuseTexture); |
| res.addNode(normalUniform); |
| res.addNode(normalTexture); |
| res.addNode(lightFunction); |
| res.addNode(fragColor); |
| |
| res.addEdge(createEdge(diffuseUniform.uuid(), "color", lightFunction.uuid(), "color", {"diffuseUniform"})); |
| res.addEdge(createEdge(texCoord.uuid(), "texCoord", diffuseTexture.uuid(), "coord", {"diffuseTexture"})); |
| res.addEdge(createEdge(diffuseTexture.uuid(), "color", lightFunction.uuid(), "color", {"diffuseTexture"})); |
| |
| res.addEdge(createEdge(normalUniform.uuid(), "normal", lightFunction.uuid(), "normal", {"normalUniform"})); |
| res.addEdge(createEdge(texCoord.uuid(), "texCoord", normalTexture.uuid(), "coord", {"normalTexture"})); |
| res.addEdge(createEdge(normalTexture.uuid(), "normal", lightFunction.uuid(), "normal", {"normalTexture"})); |
| |
| res.addEdge(createEdge(lightFunction.uuid(), "output", fragColor.uuid(), "fragColor")); |
| |
| return res; |
| }(); |
| |
| { |
| // WHEN |
| const auto statements = graph.createStatements({"diffuseUniform", "normalUniform"}); |
| |
| // THEN |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(normalUniform, {}, {1}) |
| << createStatement(diffuseUniform, {}, {0}) |
| << createStatement(lightFunction, {0, 1}, {2}) |
| << createStatement(fragColor, {2}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| |
| { |
| // WHEN |
| const auto statements = graph.createStatements({"diffuseUniform", "normalTexture"}); |
| |
| // THEN |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(texCoord, {}, {0}) |
| << createStatement(normalTexture, {0}, {2}) |
| << createStatement(diffuseUniform, {}, {1}) |
| << createStatement(lightFunction, {1, 2}, {3}) |
| << createStatement(fragColor, {3}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| |
| { |
| // WHEN |
| const auto statements = graph.createStatements({"diffuseTexture", "normalUniform"}); |
| |
| // THEN |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(texCoord, {}, {0}) |
| << createStatement(normalUniform, {}, {2}) |
| << createStatement(diffuseTexture, {0}, {1}) |
| << createStatement(lightFunction, {1, 2}, {3}) |
| << createStatement(fragColor, {3}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| |
| { |
| // WHEN |
| const auto statements = graph.createStatements({"diffuseTexture", "normalTexture"}); |
| |
| // THEN |
| const auto expected = QVector<QShaderGraph::Statement>() |
| << createStatement(texCoord, {}, {0}) |
| << createStatement(normalTexture, {0}, {2}) |
| << createStatement(diffuseTexture, {0}, {1}) |
| << createStatement(lightFunction, {1, 2}, {3}) |
| << createStatement(fragColor, {3}, {}); |
| dumpStatementsIfNeeded(statements, expected); |
| QCOMPARE(statements, expected); |
| } |
| } |
| |
| QTEST_MAIN(tst_QShaderGraph) |
| |
| #include "tst_qshadergraph.moc" |