diff --git a/src/plugins/qmldesigner/components/effectmaker/compositionnode.cpp b/src/plugins/qmldesigner/components/effectmaker/compositionnode.cpp index eb2e7b3b322..d0e3c6c53cd 100644 --- a/src/plugins/qmldesigner/components/effectmaker/compositionnode.cpp +++ b/src/plugins/qmldesigner/components/effectmaker/compositionnode.cpp @@ -44,6 +44,21 @@ QStringList CompositionNode::requiredNodes() const return m_requiredNodes; } +bool CompositionNode::isEnabled() const +{ + return m_isEnabled; +} + +void CompositionNode::setIsEnabled(bool newIsEnabled) +{ + m_isEnabled = newIsEnabled; +} + +CompositionNode::NodeType CompositionNode::type() const +{ + return m_type; +} + void CompositionNode::parse(const QString &qenPath) { QFile qenFile(qenPath); diff --git a/src/plugins/qmldesigner/components/effectmaker/compositionnode.h b/src/plugins/qmldesigner/components/effectmaker/compositionnode.h index 2b2864efb97..dfca7fa0221 100644 --- a/src/plugins/qmldesigner/components/effectmaker/compositionnode.h +++ b/src/plugins/qmldesigner/components/effectmaker/compositionnode.h @@ -17,6 +17,12 @@ class CompositionNode : public QObject Q_PROPERTY(QObject *nodeUniformsModel READ uniformsModel NOTIFY uniformsModelChanged) public: + enum NodeType { + SourceNode = 0, + DestinationNode, + CustomNode + }; + CompositionNode(const QString &qenPath); QString fragmentCode() const; @@ -27,6 +33,11 @@ public: QStringList requiredNodes() const; + NodeType type() const; + + bool isEnabled() const; + void setIsEnabled(bool newIsEnabled); + signals: void uniformsModelChanged(); @@ -34,10 +45,12 @@ private: void parse(const QString &qenPath); QString m_name; + NodeType m_type = CustomNode; QString m_fragmentCode; QString m_vertexCode; QString m_description; QStringList m_requiredNodes; + bool m_isEnabled; EffectMakerUniformsModel m_unifomrsModel; }; diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp index b122a4e8530..76c9c572ff7 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.cpp @@ -112,7 +112,7 @@ const QString EffectMakerModel::getVSUniforms() const QString EffectMakerModel::getFSUniforms() { - QList uniforms = allUniforms(); + const QList uniforms = allUniforms(); QString s; s += "#version 440\n"; s += '\n'; @@ -227,4 +227,224 @@ void EffectMakerModel::resetEffectError(int type) } } +const QString EffectMakerModel::getDefineProperties() +{ + // TODO + + return QString(); +} + +const QString EffectMakerModel::getConstVariables() +{ + // TODO + + return QString(); +} + +int EffectMakerModel::getTagIndex(const QStringList &code, const QString &tag) +{ + Q_UNUSED(code) + Q_UNUSED(tag) + + // TODO + return 0; +} + +QString EffectMakerModel::processVertexRootLine(const QString &line) +{ + Q_UNUSED(line) + + // TODO + return QString(); +} + +QString EffectMakerModel:: processFragmentRootLine(const QString &line) +{ + Q_UNUSED(line) + + // TODO + return QString(); +} + +QStringList EffectMakerModel::getDefaultRootVertexShader() +{ + // TODO + return {}; +} + +QStringList EffectMakerModel::getDefaultRootFragmentShader() +{ + // TODO + return {}; +} + +QStringList EffectMakerModel::removeTagsFromCode(const QStringList &codeLines) +{ + Q_UNUSED(codeLines) + + // TODO + return {}; +} + +QString EffectMakerModel::removeTagsFromCode(const QString &code) +{ + Q_UNUSED(code) + + // TODO + return QString(); +} + +QString EffectMakerModel::getCustomShaderVaryings(bool outState) +{ + Q_UNUSED(outState) + + // TODO + return QString(); +} + +QString EffectMakerModel::generateVertexShader(bool includeUniforms) +{ + QString s; + + if (includeUniforms) + s += getVSUniforms(); + + // Remove tags when not generating for features check + const bool removeTags = includeUniforms; + + s += getDefineProperties(); + s += getConstVariables(); + + // When the node is complete, add shader code in correct nodes order + // split to root and main parts + QString s_root; + QString s_main; + QStringList s_sourceCode; + m_shaderVaryingVariables.clear(); + for (const CompositionNode *n : std::as_const(m_nodes)) { + if (!n->vertexCode().isEmpty() && n->isEnabled()) { + if (n->type() == CompositionNode::NodeType::SourceNode) { + s_sourceCode = n->vertexCode().split('\n'); + } else if (n->type() == CompositionNode::NodeType::CustomNode) { + const QStringList vertexCode = n->vertexCode().split('\n'); + int mainIndex = getTagIndex(vertexCode, QStringLiteral("main")); + int line = 0; + for (const QString &ss : vertexCode) { + if (mainIndex == -1 || line > mainIndex) + s_main += QStringLiteral(" ") + ss + '\n'; + else if (line < mainIndex) + s_root += processVertexRootLine(ss); + line++; + } + } + } + } + + if (s_sourceCode.isEmpty()) { + // If source nodes doesn't contain any code, use default one + s_sourceCode << getDefaultRootVertexShader(); + } + + if (removeTags) { + s_sourceCode = removeTagsFromCode(s_sourceCode); + s_root = removeTagsFromCode(s_root); + s_main = removeTagsFromCode(s_main); + } + + s += getCustomShaderVaryings(true); + s += s_root + '\n'; + + int nodesIndex = getTagIndex(s_sourceCode, QStringLiteral("nodes")); + int line = 0; + for (const QString &ss : std::as_const(s_sourceCode)) + s += (line++ == nodesIndex) ? s_main : ss + '\n'; + + return s; +} + +QString EffectMakerModel::generateFragmentShader(bool includeUniforms) +{ + QString s; + + if (includeUniforms) + s += getFSUniforms(); + + // Remove tags when not generating for features check + const bool removeTags = includeUniforms; + + s += getDefineProperties(); + s += getConstVariables(); + + // When the node is complete, add shader code in correct nodes order + // split to root and main parts + QString s_root; + QString s_main; + QStringList s_sourceCode; + for (const CompositionNode *n : std::as_const(m_nodes)) { + if (!n->fragmentCode().isEmpty() && n->isEnabled()) { + if (n->type() == CompositionNode::NodeType::SourceNode) { + s_sourceCode = n->fragmentCode().split('\n'); + } else if (n->type() == CompositionNode::NodeType::CustomNode) { + const QStringList fragmentCode = n->fragmentCode().split('\n'); + int mainIndex = getTagIndex(fragmentCode, QStringLiteral("main")); + int line = 0; + for (const QString &ss : fragmentCode) { + if (mainIndex == -1 || line > mainIndex) + s_main += QStringLiteral(" ") + ss + '\n'; + else if (line < mainIndex) + s_root += processFragmentRootLine(ss); + line++; + } + } + } + } + + if (s_sourceCode.isEmpty()) { + // If source nodes doesn't contain any code, use default one + s_sourceCode << getDefaultRootFragmentShader(); + } + + if (removeTags) { + s_sourceCode = removeTagsFromCode(s_sourceCode); + s_root = removeTagsFromCode(s_root); + s_main = removeTagsFromCode(s_main); + } + + s += getCustomShaderVaryings(false); + s += s_root + '\n'; + + int nodesIndex = getTagIndex(s_sourceCode, QStringLiteral("nodes")); + int line = 0; + for (const QString &ss : std::as_const(s_sourceCode)) + s += (line++ == nodesIndex) ? s_main : ss + '\n'; + + return s; +} + +void EffectMakerModel::bakeShaders() +{ + resetEffectError(ErrorPreprocessor); + if (m_vertexShader == generateVertexShader() && m_fragmentShader == generateFragmentShader()) { + setShadersUpToDate(true); + return; + } + + setShadersUpToDate(false); + + // TODO: Compilation starts here +} + +bool EffectMakerModel::shadersUpToDate() const +{ + return m_shadersUpToDate; +} + +void EffectMakerModel::setShadersUpToDate(bool UpToDate) +{ + if (m_shadersUpToDate == UpToDate) + return; + m_shadersUpToDate = UpToDate; + emit shadersUpToDateChanged(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h index 741647a1425..71a58455499 100644 --- a/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h +++ b/src/plugins/qmldesigner/components/effectmaker/effectmakermodel.h @@ -18,6 +18,7 @@ struct EffectError { Q_PROPERTY(QString message MEMBER m_message) Q_PROPERTY(int line MEMBER m_line) Q_PROPERTY(int type MEMBER m_type) + public: QString m_message; int m_line = -1; @@ -30,6 +31,7 @@ class EffectMakerModel : public QAbstractListModel Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged) + Q_PROPERTY(bool shadersUpToDate READ shadersUpToDate WRITE setShadersUpToDate NOTIFY shadersUpToDateChanged) public: EffectMakerModel(QObject *parent = nullptr); @@ -44,10 +46,14 @@ public: Q_INVOKABLE void removeNode(int idx); + bool shadersUpToDate() const; + void setShadersUpToDate(bool newShadersUpToDate); + signals: void isEmptyChanged(); void selectedIndexChanged(int idx); void effectErrorChanged(); + void shadersUpToDateChanged(); private: enum Roles { @@ -55,6 +61,15 @@ private: UniformsRole }; + enum ErrorTypes { + ErrorCommon = -1, + ErrorQMLParsing, + ErrorVert, + ErrorFrag, + ErrorQMLRuntime, + ErrorPreprocessor + }; + bool isValidIndex(int idx) const; const QList allUniforms(); @@ -68,14 +83,31 @@ private: void setEffectError(const QString &errorMessage, int type, int lineNumber); void resetEffectError(int type); + const QString getDefineProperties(); + const QString getConstVariables(); + int getTagIndex(const QStringList &code, const QString &tag); + QString processVertexRootLine(const QString &line); + QString processFragmentRootLine(const QString &line); + QStringList getDefaultRootVertexShader(); + QStringList getDefaultRootFragmentShader(); + QStringList removeTagsFromCode(const QStringList &codeLines); + QString removeTagsFromCode(const QString &code); + QString getCustomShaderVaryings(bool outState); + QString generateVertexShader(bool includeUniforms = true); + QString generateFragmentShader(bool includeUniforms = true); + void bakeShaders(); + QList m_nodes; int m_selectedIndex = -1; bool m_isEmpty = true; - + // True when shaders haven't changed since last baking + bool m_shadersUpToDate = true; QMap m_effectErrors; - ShaderFeatures m_shaderFeatures; + QStringList m_shaderVaryingVariables; + QString m_fragmentShader; + QString m_vertexShader; }; } // namespace QmlDesigner