// Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef EFFECTMANAGER_H #define EFFECTMANAGER_H #include #include #include #include #include #include "uniformmodel.h" #include "nodeview.h" #include "shaderfeatures.h" #include #include #include "addnodemodel.h" #include "applicationsettings.h" #include "codehelper.h" // The delay in ms to wait until updating the effect const int EFFECT_UPDATE_DELAY = 200; // This will be used for commandline arguments. extern QQmlPropertyMap g_argData; struct EffectError { Q_GADGET 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; int m_type = -1; }; class EffectManager : public QObject { Q_OBJECT Q_PROPERTY(UniformModel *uniformModel READ uniformModel WRITE setUniformModel NOTIFY uniformModelChanged) Q_PROPERTY(NodeView *nodeView READ nodeView WRITE setNodeView NOTIFY nodeViewChanged) Q_PROPERTY(CodeHelper *codeHelper READ codeHelper CONSTANT) Q_PROPERTY(QString fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged) Q_PROPERTY(QString vertexShader READ vertexShader WRITE setVertexShader NOTIFY vertexShaderChanged) Q_PROPERTY(QString fragmentShaderFilename READ fragmentShaderFilename WRITE setFragmentShaderFilename NOTIFY fragmentShaderFilenameChanged) Q_PROPERTY(QString vertexShaderFilename READ vertexShaderFilename WRITE setVertexShaderFilename NOTIFY vertexShaderFilenameChanged) Q_PROPERTY(QString qmlComponentString READ qmlComponentString WRITE setQmlComponentString NOTIFY qmlComponentStringChanged) Q_PROPERTY(EffectError effectError READ effectError NOTIFY effectErrorChanged) Q_PROPERTY(bool unsavedChanges READ unsavedChanges WRITE setUnsavedChanges NOTIFY unsavedChangesChanged) Q_PROPERTY(bool hasProjectFilename READ hasProjectFilename NOTIFY hasProjectFilenameChanged) Q_PROPERTY(QString projectName READ projectName NOTIFY projectNameChanged) Q_PROPERTY(QString projectFilename READ projectFilename NOTIFY projectFilenameChanged) Q_PROPERTY(QString projectDirectory READ projectDirectory NOTIFY projectDirectoryChanged) Q_PROPERTY(QString exportFilename READ exportFilename NOTIFY exportFilenameChanged) Q_PROPERTY(QString exportDirectory READ exportDirectory NOTIFY exportDirectoryChanged) Q_PROPERTY(int exportFlags READ exportFlags NOTIFY exportFlagsChanged) Q_PROPERTY(bool shadersUpToDate READ shadersUpToDate WRITE setShadersUpToDate NOTIFY shadersUpToDateChanged) Q_PROPERTY(bool autoPlayEffect READ autoPlayEffect WRITE setAutoPlayEffect NOTIFY autoPlayEffectChanged) Q_PROPERTY(AddNodeModel *addNodeModel READ addNodeModel NOTIFY addNodeModelChanged) Q_PROPERTY(QRect effectPadding READ effectPadding WRITE setEffectPadding NOTIFY effectPaddingChanged) Q_PROPERTY(QString effectHeadings READ effectHeadings WRITE setEffectHeadings NOTIFY effectHeadingsChanged) Q_PROPERTY(ApplicationSettings * settings READ settings NOTIFY settingsChanged) QML_ELEMENT public: explicit EffectManager(QObject *parent = nullptr); UniformModel *uniformModel() const; void setUniformModel(UniformModel *newUniformModel); CodeHelper *codeHelper() const; QString fragmentShader() const; void setFragmentShader(const QString &newFragmentShader); QString vertexShader() const; void setVertexShader(const QString &newVertexShader); bool unsavedChanges() const; void setUnsavedChanges(bool newUnsavedChanges); bool hasProjectFilename() const; QString projectFilename() const; QString projectName() const; void setProjectName(const QString &name); QString projectDirectory() const; QString exportFilename() const; QString exportDirectory() const; int exportFlags() const; NodeView *nodeView() const; void setNodeView(NodeView *newNodeView); EffectError effectError() const; const QString &fragmentShaderFilename() const; void setFragmentShaderFilename(const QString &newFragmentShaderFilename); const QString &vertexShaderFilename() const; void setVertexShaderFilename(const QString &newVertexShaderFilename); const QString &qmlComponentString() const; void setQmlComponentString(const QString &string); bool shadersUpToDate() const; void setShadersUpToDate(bool upToDate); bool autoPlayEffect() const; void setAutoPlayEffect(bool autoPlay); AddNodeModel *addNodeModel() const; const QRect &effectPadding() const; QString effectHeadings() const; ApplicationSettings *settings() const { return m_settings; } Q_INVOKABLE QString mipmapPropertyName(const QString &name) const; Q_INVOKABLE QString getSupportedImageFormatsFilter() const; Q_INVOKABLE int effectUpdateDelay() const { return EFFECT_UPDATE_DELAY; } public Q_SLOTS: QString generateVertexShader(bool includeUniforms = true); QString generateFragmentShader(bool includeUniforms = true); void updateQmlComponent(); void initialize(); NodesModel::Node loadEffectNode(const QString &filename); bool addEffectNode(const QString &filename, int startNodeId = -1, int endNodeId = -1); bool deleteEffectNodes(QList nodeIds); bool loadProject(const QUrl &filename); bool saveProject(const QUrl &filename = QString()); bool newProject(const QString &filepath, const QString &filename, bool clearNodeView, bool createProjectDir = false); void closeProject(); bool exportEffect(const QString &dirPath, const QString &filename, int exportFlags, int qsbVersionIndex); void cleanupProject(); void cleanupNodeView(bool initialize = true); bool saveSelectedNode(const QUrl &filename); void updateBakedShaderVersions(); void bakeShaders(bool forced = false); QString getHelpTextString(); void updateAddNodeData(); void showHideAddNodeGroup(const QString &groupName, bool show); void refreshAddNodesList(); void setEffectPadding(const QRect &newEffectPadding); void setEffectHeadings(const QString &newEffectHeadings); QString stripFileFromURL(const QString &urlString) const; QString addFileToURL(const QString &urlString) const; QString getDirectory(const QString &path, bool useFileScheme = true) const; QString getDefaultImagesDirectory(bool useFileScheme = true) const; void autoIndentCurrentCode(int codeTab, const QString &code); bool processKey(int codeTab, int keyCode, int modifiers, QQuickTextEdit *textEdit); void setEffectError(const QString &errorMessage, int type = -1, int lineNumber = -1); void resetEffectError(int type = -1); signals: void uniformModelChanged(); void fragmentShaderChanged(); void vertexShaderChanged(); void unsavedChangesChanged(); void hasProjectFilenameChanged(); void projectFilenameChanged(); void projectNameChanged(); void projectDirectoryChanged(); void exportFilenameChanged(); void exportDirectoryChanged(); void exportFlagsChanged(); void shadersBaked(); void nodeViewChanged(); void effectErrorChanged(); void fragmentShaderFilenameChanged(); void vertexShaderFilenameChanged(); void qmlComponentStringChanged(); void shadersUpToDateChanged(); void autoPlayEffectChanged(); void addNodeModelChanged(); void effectPaddingChanged(); void effectHeadingsChanged(); void settingsChanged(); private: friend class AddNodeModel; friend class ApplicationSettings; enum ExportFlags { QMLComponent = 1, QSBShaders = 2, TextShaders = 4, Images = 8, QRCFile = 16 }; enum ErrorTypes { ErrorCommon = -1, ErrorQMLParsing, ErrorVert, ErrorFrag, ErrorQMLRuntime, ErrorPreprocessor }; const QString getBufUniform(); const QString getFSUniforms(); const QString getVSUniforms(); const QString getDefineProperties(); const QString getConstVariables(); void updateCustomUniforms(); QString getQmlImagesString(bool localFiles); QString getQmlComponentString(bool localFiles); QString getQmlEffectString(); QStringList getDefaultRootVertexShader(); QStringList getDefaultRootFragmentShader(); QString processVertexRootLine(const QString &line); QString processFragmentRootLine(const QString &line); QString getCustomShaderVaryings(bool outState); QStringList removeTagsFromCode(const QStringList &codeLines); QString removeTagsFromCode(const QString &code); QString replaceOldTagsWithNew(const QString &code); QString detectErrorMessage(const QString &errorMessage); void doBakeShaders(); QFile resolveFileFromUrl(const QUrl &fileUrl); bool createNodeFromJson(const QJsonObject &rootJson, NodesModel::Node &node, bool fullNode, const QString &nodePath); bool addNodeIntoView(NodesModel::Node &node, int startNodeId = -1, int endNodeId = -1); bool addNodeConnection(int startNodeId, int endNodeId); int getTagIndex(const QStringList &code, const QString &tag); QJsonObject nodeToJson(const NodesModel::Node &node, bool simplified, const QString &nodePath); QString codeFromJsonArray(const QJsonArray &codeArray); QString absoluteToRelativePath(const QString &path, const QString &toPath = QString()); QString relativeToAbsolutePath(const QString &path, const QString &toPath = QString()); void updateImageWatchers(); void clearImageWatchers(); UniformModel *m_uniformModel = nullptr; UniformModel::UniformTable m_uniformTable; CodeHelper *m_codeHelper = nullptr; QString m_fragmentShader; QString m_vertexShader; QString m_qmlCode; // Used in exported QML, at root of the file QString m_exportedRootPropertiesString; // Used in exported QML, at ShaderEffect component of the file QString m_exportedEffectPropertiesString; // Used in preview QML, at ShaderEffect component of the file QString m_previewEffectPropertiesString; bool m_unsavedChanges = false; bool m_firstBake = true; // Full path of the project file QUrl m_projectFilename; // Path to where project file is located QString m_projectDirectory; // Exported effect name, without the prefixes QString m_exportFilename; // Path to where effect is exported QString m_exportDirectory; // Name of the project // E.g. "MyEffect" QString m_projectName; int m_exportFlags = QMLComponent | QSBShaders | Images; QTemporaryFile m_fragmentShaderFile; QTemporaryFile m_vertexShaderFile; ApplicationSettings *m_settings = nullptr; QShaderBaker m_baker; NodeView *m_nodeView = nullptr; QMap m_effectErrors; QString m_fragmentShaderFilename; QString m_vertexShaderFilename; QString m_qmlComponentString; QStringList m_defaultRootVertexShader; QStringList m_defaultRootFragmentShader; QTimer m_shaderBakerTimer; // True when shaders haven't changed since last baking bool m_shadersUpToDate = true; // When true, shaders are baked automatically after a // short delay when they change. bool m_autoPlayEffect = true; bool m_loadComponentImages = true; ShaderFeatures m_shaderFeatures; AddNodeModel *m_addNodeModel = nullptr; QStringList m_shaderVaryingVariables; QRect m_effectPadding; QString m_effectHeadings; QFileSystemWatcher m_fileWatcher; }; #endif // EFFECTMANAGER_H