From dc42b62ddf3fbd41bf5b16922e77de6bb6cdaafc Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 7 Dec 2023 18:32:55 +0200 Subject: [PATCH] Effect Maker: Enable helper nodes Helper nodes are nodes that another node depends on and are added automatically when the depending node is added. Helper nodes are placed before all other nodes. Helper nodes that do not contain any properties are not shown. Helper nodes keep reference count and are removed when last referring node is removed. Task-number: QDS-11193 Change-Id: I036019afb1414ec6e98b2f949a18bd217753a910 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/BlurHelper.qml | 68 ++++++++++++ .../EffectCompositionNode.qml | 8 +- .../effectMakerQmlSources/EffectMaker.qml | 3 +- .../EffectMakerPreview.qml | 7 ++ .../effectmakernew/compositionnode.cpp | 53 ++++++++- src/plugins/effectmakernew/compositionnode.h | 13 ++- .../effectmakernew/effectmakermodel.cpp | 103 ++++++++++++++++-- src/plugins/effectmakernew/effectmakermodel.h | 9 +- .../effectmakernew/effectmakernodesmodel.cpp | 14 +-- .../effectmakernew/effectmakerwidget.cpp | 6 + src/plugins/effectmakernew/effectutils.cpp | 11 ++ src/plugins/effectmakernew/effectutils.h | 2 + 12 files changed, 264 insertions(+), 33 deletions(-) create mode 100644 share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml new file mode 100644 index 00000000000..e68a0bc8a25 --- /dev/null +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml @@ -0,0 +1,68 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: BSD-3-Clause + +// This file should match the BlurHelper.qml in qtquickdesigner repository, except for shader paths + +import QtQuick + +Item { + id: rootItem + property alias blurSrc1: blurredItemSource1 + property alias blurSrc2: blurredItemSource2 + property alias blurSrc3: blurredItemSource3 + property alias blurSrc4: blurredItemSource4 + property alias blurSrc5: blurredItemSource5 + + component BlurItem: ShaderEffect { + property vector2d offset: Qt.vector2d((1.0 + rootItem.blurMultiplier) / width, + (1.0 + rootItem.blurMultiplier) / height) + visible: false + layer.enabled: true + layer.smooth: true + vertexShader: g_propertyData.blur_vs_path + fragmentShader: g_propertyData.blur_fs_path + } + + QtObject { + id: priv + property bool useBlurItem1: true + property bool useBlurItem2: rootItem.blurMax > 2 + property bool useBlurItem3: rootItem.blurMax > 8 + property bool useBlurItem4: rootItem.blurMax > 16 + property bool useBlurItem5: rootItem.blurMax > 32 + } + + BlurItem { + id: blurredItemSource1 + property Item src: priv.useBlurItem1 ? source : null + // Size of the first blurred item is by default half of the source. + // Increase for quality and decrease for performance & more blur. + readonly property int blurItemSize: 8 + width: src ? Math.ceil(src.width / 16) * blurItemSize : 0 + height: src ? Math.ceil(src.height / 16) * blurItemSize : 0 + } + BlurItem { + id: blurredItemSource2 + property Item src: priv.useBlurItem2 ? blurredItemSource1 : null + width: blurredItemSource1.width * 0.5 + height: blurredItemSource1.height * 0.5 + } + BlurItem { + id: blurredItemSource3 + property Item src: priv.useBlurItem3 ? blurredItemSource2 : null + width: blurredItemSource2.width * 0.5 + height: blurredItemSource2.height * 0.5 + } + BlurItem { + id: blurredItemSource4 + property Item src: priv.useBlurItem4 ? blurredItemSource3 : null + width: blurredItemSource3.width * 0.5 + height: blurredItemSource3.height * 0.5 + } + BlurItem { + id: blurredItemSource5 + property Item src: priv.useBlurItem5 ? blurredItemSource4 : null + width: blurredItemSource4.width * 0.5 + height: blurredItemSource4.height * 0.5 + } +} diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml index cf9c3d668b0..2ccaeaf36c3 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml @@ -17,16 +17,17 @@ HelperWidgets.Section { caption: nodeName category: "EffectMaker" - draggable: true + draggable: !isDependency fillBackground: true - showCloseButton: true + showCloseButton: !isDependency closeButtonToolTip: qsTr("Remove") + visible: repeater.count > 0 || !isDependency onCloseButtonClicked: { EffectMakerBackend.effectMakerModel.removeNode(root.modelIndex) } - showEyeButton: true + showEyeButton: !isDependency eyeEnabled: nodeEnabled eyeButtonToolTip: qsTr("Enable/Disable Node") @@ -38,6 +39,7 @@ HelperWidgets.Section { spacing: 10 Repeater { + id: repeater model: nodeUniformsModel EffectCompositionNodeUniform { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 81be29f9ae2..d3ccb36a749 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -213,7 +213,8 @@ Item { currItem.y = root.secsY[i] } } else if (i < root.moveFromIdx) { - if (root.draggedSec.y < currItem.y + (currItem.height - root.draggedSec.height) * .5) { + if (!repeater.model.isDependencyNode(i) + && root.draggedSec.y < currItem.y + (currItem.height - root.draggedSec.height) * .5) { currItem.y = root.secsY[i] + root.draggedSec.height root.moveToIdx = Math.min(root.moveToIdx, i) } else { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml index 4636159f481..ea0b2d12954 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml @@ -194,6 +194,13 @@ Column { } } + BlurHelper { + id: blurHelper + anchors.fill: parent + property int blurMax: g_propertyData.blur_helper_max_level ? g_propertyData.blur_helper_max_level : 64 + property real blurMultiplier: g_propertyData.blurMultiplier ? g_propertyData.blurMultiplier : 0 + } + Item { id: componentParent width: source.width diff --git a/src/plugins/effectmakernew/compositionnode.cpp b/src/plugins/effectmakernew/compositionnode.cpp index 8cd5bda971e..9520e50d050 100644 --- a/src/plugins/effectmakernew/compositionnode.cpp +++ b/src/plugins/effectmakernew/compositionnode.cpp @@ -14,7 +14,8 @@ namespace EffectMaker { -CompositionNode::CompositionNode(const QString &effectName, const QString &qenPath, const QJsonObject &jsonObject) +CompositionNode::CompositionNode(const QString &effectName, const QString &qenPath, + const QJsonObject &jsonObject) { QJsonObject json; if (jsonObject.isEmpty()) { @@ -58,6 +59,11 @@ QString CompositionNode::description() const return m_description; } +QString CompositionNode::id() const +{ + return m_id; +} + QObject *CompositionNode::uniformsModel() { return &m_unifomrsModel; @@ -81,6 +87,11 @@ void CompositionNode::setIsEnabled(bool newIsEnabled) } } +bool CompositionNode::isDependency() const +{ + return m_refCount > 0; +} + CompositionNode::NodeType CompositionNode::type() const { return m_type; @@ -102,6 +113,13 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray()); m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray()); + m_id = json.value("id").toString(); + if (m_id.isEmpty() && !qenPath.isEmpty()) { + QString fileName = qenPath.split('/').last(); + fileName.chop(4); // remove ".qen" + m_id = fileName; + } + // parse properties QJsonArray jsonProps = json.value("properties").toArray(); for (const auto /*QJsonValueRef*/ &prop : jsonProps) { @@ -118,8 +136,7 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c for (const QString &codeLine : std::as_const(shaderCodeLines)) { QString trimmedLine = codeLine.trimmed(); if (trimmedLine.startsWith("@requires")) { - // Get the required node, remove "@requires" - QString l = trimmedLine.sliced(9).trimmed(); + // Get the required node, remove "@requires " QString nodeName = trimmedLine.sliced(10); if (!nodeName.isEmpty() && !m_requiredNodes.contains(nodeName)) m_requiredNodes << nodeName; @@ -132,6 +149,36 @@ QList CompositionNode::uniforms() const return m_uniforms; } +int CompositionNode::incRefCount() +{ + ++m_refCount; + + if (m_refCount == 1) + emit isDepencyChanged(); + + return m_refCount; +} + +int CompositionNode::decRefCount() +{ + --m_refCount; + + if (m_refCount == 0) + emit isDepencyChanged(); + + return m_refCount; +} + +void CompositionNode::setRefCount(int count) +{ + bool notifyChange = (m_refCount > 0 && count == 0) || (m_refCount <= 0 && count > 0); + + m_refCount = count; + + if (notifyChange) + emit isDepencyChanged(); +} + QString CompositionNode::name() const { return m_name; diff --git a/src/plugins/effectmakernew/compositionnode.h b/src/plugins/effectmakernew/compositionnode.h index 4736f1d8afa..04f5dd5c02b 100644 --- a/src/plugins/effectmakernew/compositionnode.h +++ b/src/plugins/effectmakernew/compositionnode.h @@ -15,7 +15,8 @@ class CompositionNode : public QObject Q_OBJECT Q_PROPERTY(QString nodeName MEMBER m_name CONSTANT) - Q_PROPERTY(bool nodeEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged) + Q_PROPERTY(bool nodeEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged) + Q_PROPERTY(bool isDependency READ isDependency NOTIFY isDepencyChanged) Q_PROPERTY(QObject *nodeUniformsModel READ uniformsModel NOTIFY uniformsModelChanged) public: @@ -30,6 +31,7 @@ public: QString fragmentCode() const; QString vertexCode() const; QString description() const; + QString id() const; QObject *uniformsModel(); @@ -40,13 +42,20 @@ public: bool isEnabled() const; void setIsEnabled(bool newIsEnabled); + bool isDependency() const; + QString name() const; QList uniforms() const; + int incRefCount(); + int decRefCount(); + void setRefCount(int count); + signals: void uniformsModelChanged(); void isEnabledChanged(); + void isDepencyChanged(); private: void parse(const QString &effectName, const QString &qenPath, const QJsonObject &json); @@ -57,7 +66,9 @@ private: QString m_vertexCode; QString m_description; QStringList m_requiredNodes; + QString m_id; bool m_isEnabled = true; + int m_refCount = 0; QList m_uniforms; diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index e13e2e39a9a..fbb439ff17d 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -4,6 +4,8 @@ #include "effectmakermodel.h" #include "compositionnode.h" +#include "effectutils.h" +#include "propertyhandler.h" #include "syntaxhighlighterdata.h" #include "uniform.h" @@ -58,6 +60,7 @@ QHash EffectMakerModel::roleNames() const roles[NameRole] = "nodeName"; roles[EnabledRole] = "nodeEnabled"; roles[UniformsRole] = "nodeUniformsModel"; + roles[Dependency] = "isDependency"; return roles; } @@ -104,14 +107,29 @@ void EffectMakerModel::setIsEmpty(bool val) void EffectMakerModel::addNode(const QString &nodeQenPath) { - beginInsertRows({}, m_nodes.size(), m_nodes.size()); - auto *node = new CompositionNode("", nodeQenPath); + beginResetModel(); + auto *node = new CompositionNode({}, nodeQenPath); connect(qobject_cast(node->uniformsModel()), &EffectMakerUniformsModel::dataChanged, this, [this] { - setHasUnsavedChanges(true); - }); + setHasUnsavedChanges(true); + }); + + const QList requiredNodes = node->requiredNodes(); + if (requiredNodes.size() > 0) { + for (const QString &requiredId : requiredNodes) { + if (auto reqNode = findNodeById(requiredId)) { + reqNode->incRefCount(); + continue; + } + + const QString path = EffectUtils::nodesSourcesPath() + "/common/" + requiredId + ".qen"; + auto requiredNode = new CompositionNode({}, path); + requiredNode->setRefCount(1); + m_nodes.prepend(requiredNode); + } + } m_nodes.append(node); - endInsertRows(); + endResetModel(); setIsEmpty(false); @@ -121,6 +139,15 @@ void EffectMakerModel::addNode(const QString &nodeQenPath) emit nodesChanged(); } +CompositionNode *EffectMakerModel::findNodeById(const QString &id) const +{ + for (CompositionNode *node : std::as_const(m_nodes)) { + if (node->id() == id) + return node; + } + return {}; +} + void EffectMakerModel::moveNode(int fromIdx, int toIdx) { if (fromIdx == toIdx) @@ -137,10 +164,20 @@ void EffectMakerModel::moveNode(int fromIdx, int toIdx) void EffectMakerModel::removeNode(int idx) { - beginRemoveRows({}, idx, idx); + beginResetModel(); CompositionNode *node = m_nodes.takeAt(idx); + + const QStringList reqNodes = node->requiredNodes(); + for (const QString &reqId : reqNodes) { + CompositionNode *depNode = findNodeById(reqId); + if (depNode && depNode->decRefCount() <= 0) { + m_nodes.removeOne(depNode); + delete depNode; + } + } + delete node; - endRemoveRows(); + endResetModel(); if (m_nodes.isEmpty()) setIsEmpty(true); @@ -442,6 +479,8 @@ QJsonObject nodeToJson(const CompositionNode &node) nodeObject.insert("description", node.description()); nodeObject.insert("enabled", node.isEnabled()); nodeObject.insert("version", 1); + nodeObject.insert("id", node.id()); + // Add properties QJsonArray propertiesArray; const QList uniforms = node.uniforms(); @@ -549,7 +588,17 @@ QString EffectMakerModel::getQmlEffectString() s += '\n'; } - //TODO: Blue stuff goes here + if (m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) { + s += " BlurHelper {\n"; + s += " id: blurHelper\n"; + s += " anchors.fill: parent\n"; + int blurMax = 32; + if (g_propertyData.contains("BLUR_HELPER_MAX_LEVEL")) + blurMax = g_propertyData["BLUR_HELPER_MAX_LEVEL"].toInt(); + s += QString(" property int blurMax: %1\n").arg(blurMax); + s += " property real blurMultiplier: rootItem.blurMultiplier\n"; + s += " }\n"; + } s += getQmlComponentString(true); s += "}\n"; @@ -643,18 +692,30 @@ void EffectMakerModel::openComposition(const QString &path) } if (json.contains("nodes") && json["nodes"].isArray()) { + beginResetModel(); + QHash refCounts; const QJsonArray nodesArray = json["nodes"].toArray(); + for (const auto &nodeElement : nodesArray) { - beginInsertRows({}, m_nodes.size(), m_nodes.size()); - auto *node = new CompositionNode(effectName, "", nodeElement.toObject()); + auto *node = new CompositionNode(effectName, {}, nodeElement.toObject()); connect(qobject_cast(node->uniformsModel()), &EffectMakerUniformsModel::dataChanged, this, [this] { setHasUnsavedChanges(true); }); m_nodes.append(node); - endInsertRows(); + const QStringList reqIds = node->requiredNodes(); + for (const QString &reqId : reqIds) + ++refCounts[reqId]; } + for (auto it = refCounts.cbegin(), end = refCounts.cend(); it != end; ++it) { + CompositionNode *depNode = findNodeById(it.key()); + if (depNode) + depNode->setRefCount(it.value()); + } + + endResetModel(); + setIsEmpty(m_nodes.isEmpty()); bakeShaders(); } @@ -748,6 +809,19 @@ void EffectMakerModel::saveResources(const QString &name) } } + if (m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) { + QString blurHelperFilename("BlurHelper.qml"); + QString blurFsFilename("bluritems.frag.qsb"); + QString blurVsFilename("bluritems.vert.qsb"); + QString blurHelperPath(EffectUtils::nodesSourcesPath() + "/common/"); + sources.append(blurHelperPath + blurHelperFilename); + sources.append(blurHelperPath + blurFsFilename); + sources.append(blurHelperPath + blurVsFilename); + dests.append(blurHelperFilename); + dests.append(blurFsFilename); + dests.append(blurVsFilename); + } + for (int i = 0; i < sources.count(); ++i) { Utils::FilePath source = Utils::FilePath::fromString(sources[i]); Utils::FilePath target = Utils::FilePath::fromString(effectsResPath + dests[i]); @@ -1505,6 +1579,13 @@ QStringList EffectMakerModel::uniformNames() const return usedList; } +bool EffectMakerModel::isDependencyNode(int index) const +{ + if (m_nodes.size() > index) + return m_nodes[index]->isDependency(); + return false; +} + void EffectMakerModel::updateQmlComponent() { // Clear possible QML runtime errors diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 7f73ed4cdca..a25a4e40913 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -7,10 +7,10 @@ #include +#include #include #include #include -#include #include namespace ProjectExplorer { @@ -62,6 +62,8 @@ public: void addNode(const QString &nodeQenPath); + CompositionNode *findNodeById(const QString &id) const; + Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); Q_INVOKABLE void clear(); @@ -96,6 +98,8 @@ public: QStringList uniformNames() const; + Q_INVOKABLE bool isDependencyNode(int index) const; + signals: void isEmptyChanged(); void selectedIndexChanged(int idx); @@ -112,7 +116,8 @@ private: enum Roles { NameRole = Qt::UserRole + 1, EnabledRole, - UniformsRole + UniformsRole, + Dependency }; enum ErrorTypes { diff --git a/src/plugins/effectmakernew/effectmakernodesmodel.cpp b/src/plugins/effectmakernew/effectmakernodesmodel.cpp index c6773faa090..7f35e935ba9 100644 --- a/src/plugins/effectmakernew/effectmakernodesmodel.cpp +++ b/src/plugins/effectmakernew/effectmakernodesmodel.cpp @@ -2,8 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "effectmakernodesmodel.h" - -#include +#include "effectutils.h" #include #include @@ -41,21 +40,12 @@ QVariant EffectMakerNodesModel::data(const QModelIndex &index, int role) const return m_categories.at(index.row())->property(roleNames().value(role)); } -QString EffectMakerNodesModel::nodesSourcesPath() const -{ -#ifdef SHARE_QML_PATH - if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) - return QLatin1String(SHARE_QML_PATH) + "/effectMakerNodes"; -#endif - return Core::ICore::resourcePath("qmldesigner/effectMakerNodes").toString(); -} - void EffectMakerNodesModel::loadModel() { if (m_modelLoaded) return; - auto nodesPath = Utils::FilePath::fromString(nodesSourcesPath()); + auto nodesPath = Utils::FilePath::fromString(EffectUtils::nodesSourcesPath()); if (!nodesPath.exists()) { qWarning() << __FUNCTION__ << "Effects not found."; diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index db549501f37..5151c0568ca 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -7,6 +7,7 @@ #include "effectmakermodel.h" #include "effectmakernodesmodel.h" #include "effectmakerview.h" +#include "effectutils.h" #include "propertyhandler.h" //#include "qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h" @@ -61,6 +62,7 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); QmlDesigner::Theme::setupTheme(m_quickWidget->engine()); m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); + m_quickWidget->engine()->addImportPath(EffectUtils::nodesSourcesPath() + "/common"); m_quickWidget->setClearColor(QmlDesigner::Theme::getColor( QmlDesigner::Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); @@ -76,6 +78,10 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) m_quickWidget->rootContext()->setContextProperty("g_propertyData", &g_propertyData); + QString blurPath = "file:" + EffectUtils::nodesSourcesPath() + "/common/"; + g_propertyData.insert(QString("blur_vs_path"), QString(blurPath + "bluritems.vert.qsb")); + g_propertyData.insert(QString("blur_fs_path"), QString(blurPath + "bluritems.frag.qsb")); + auto map = m_quickWidget->registerPropertyMap("EffectMakerBackend"); map->setProperties({{"effectMakerNodesModel", QVariant::fromValue(m_effectMakerNodesModel.data())}, {"effectMakerModel", QVariant::fromValue(m_effectMakerModel.data())}, diff --git a/src/plugins/effectmakernew/effectutils.cpp b/src/plugins/effectmakernew/effectutils.cpp index 8e2bb625431..a0159c520da 100644 --- a/src/plugins/effectmakernew/effectutils.cpp +++ b/src/plugins/effectmakernew/effectutils.cpp @@ -3,6 +3,8 @@ #include "effectutils.h" +#include + #include namespace EffectMaker { @@ -20,5 +22,14 @@ QString EffectUtils::codeFromJsonArray(const QJsonArray &codeArray) return codeString; } +QString EffectUtils::nodesSourcesPath() +{ +#ifdef SHARE_QML_PATH + if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/effectMakerNodes"; +#endif + return Core::ICore::resourcePath("qmldesigner/effectMakerNodes").toString(); +} + } // namespace EffectMaker diff --git a/src/plugins/effectmakernew/effectutils.h b/src/plugins/effectmakernew/effectutils.h index e3de9312dce..eede7952c5c 100644 --- a/src/plugins/effectmakernew/effectutils.h +++ b/src/plugins/effectmakernew/effectutils.h @@ -15,6 +15,8 @@ public: EffectUtils() = delete; static QString codeFromJsonArray(const QJsonArray &codeArray); + + static QString nodesSourcesPath(); }; } // namespace EffectMaker