Revision control
++ // 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 <QObject>
++ #include <QTemporaryFile>
++ #include <QTimer>
++ #include <QQmlPropertyMap>
++ #include <QFileSystemWatcher>
++ #include "uniformmodel.h"
++ #include "nodeview.h"
++ #include "shaderfeatures.h"
++ #include <rhi/qshaderbaker.h>
++ #include <QtQuick/private/qquicktextedit_p_p.h>
++ #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<int> nodeIds);
++ bool loadProject(const QUrl &filename);
++ bool saveProject(const QUrl &filename = {});
++ 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<int, EffectError> 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