aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/effectcomposer/effectcomposermodel.h
blob: 14ef09e8a97a56e3abf876f008c58b3cf01b670b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#pragma once

#include "shaderfeatures.h"

#include <utils/filepath.h>

#include <QAbstractListModel>
#include <QFileSystemWatcher>
#include <QMap>
#include <QRegularExpression>
#include <QSet>
#include <QTemporaryFile>
#include <QTimer>

namespace ProjectExplorer {
class Target;
}

namespace Utils {
class Process;
}

namespace EffectComposer {

class CompositionNode;
class Uniform;

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 EffectComposerModel : public QAbstractListModel
{
    Q_OBJECT

    Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
    Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged)
    Q_PROPERTY(bool hasUnsavedChanges MEMBER m_hasUnsavedChanges WRITE setHasUnsavedChanges NOTIFY hasUnsavedChangesChanged)
    Q_PROPERTY(bool shadersUpToDate READ shadersUpToDate WRITE setShadersUpToDate NOTIFY shadersUpToDateChanged)
    Q_PROPERTY(bool isEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged)
    Q_PROPERTY(bool hasValidTarget READ hasValidTarget WRITE setHasValidTarget NOTIFY hasValidTargetChanged)
    Q_PROPERTY(QString currentComposition READ currentComposition WRITE setCurrentComposition NOTIFY currentCompositionChanged)

public:
    EffectComposerModel(QObject *parent = nullptr);

    QHash<int, QByteArray> roleNames() const override;
    int rowCount(const QModelIndex & parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role) override;

    void setEffectsTypePrefix(const QString &prefix);

    bool isEmpty() const { return m_isEmpty; }
    void setIsEmpty(bool val);

    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(bool clearName = false);
    Q_INVOKABLE void assignToSelected();
    Q_INVOKABLE QString getUniqueEffectName() const;
    Q_INVOKABLE bool nameExists(const QString &name) const;

    bool shadersUpToDate() const;
    void setShadersUpToDate(bool newShadersUpToDate);

    bool isEnabled() const;
    void setIsEnabled(bool enabled);

    bool hasValidTarget() const;
    void setHasValidTarget(bool validTarget);

    QString fragmentShader() const;
    void setFragmentShader(const QString &newFragmentShader);

    QString vertexShader() const;
    void setVertexShader(const QString &newVertexShader);

    Q_INVOKABLE QString qmlComponentString() const;

    Q_INVOKABLE void updateQmlComponent();

    Q_INVOKABLE void resetEffectError(int type);
    Q_INVOKABLE void setEffectError(const QString &errorMessage, int type = -1, int lineNumber = -1);

    Q_INVOKABLE void saveComposition(const QString &name);

    void openComposition(const QString &path);

    QString currentComposition() const;
    void setCurrentComposition(const QString &newCurrentComposition);

    bool hasUnsavedChanges() const;
    void setHasUnsavedChanges(bool val);

    QStringList uniformNames() const;

    Q_INVOKABLE bool isDependencyNode(int index) const;

signals:
    void isEmptyChanged();
    void selectedIndexChanged(int idx);
    void effectErrorChanged();
    void shadersUpToDateChanged();
    void isEnabledChanged();
    void hasValidTargetChanged();
    void shadersBaked();
    void currentCompositionChanged();
    void nodesChanged();
    void resourcesSaved(const QByteArray &type, const Utils::FilePath &path);
    void hasUnsavedChangesChanged();
    void assignToSelectedTriggered(const QString &effectPath);
    void removePropertiesFromScene(QSet<QByteArray> props, const QString &typeName);

private:
    enum Roles {
        NameRole = Qt::UserRole + 1,
        EnabledRole,
        UniformsRole,
        Dependency
    };

    enum ErrorTypes {
        ErrorCommon = -1,
        ErrorQMLParsing,
        ErrorVert,
        ErrorFrag,
        ErrorQMLRuntime,
        ErrorPreprocessor
    };

    bool isValidIndex(int idx) const;

    const QList<Uniform *> allUniforms() const;

    const QString getBufUniform();
    const QString getVSUniforms();
    const QString getFSUniforms();

    QString detectErrorMessage(const QString &errorMessage);
    EffectError effectError() const;

    QString valueAsString(const Uniform &uniform);
    QString valueAsBinding(const Uniform &uniform);
    QString valueAsVariable(const Uniform &uniform);
    QString getImageElementName(const Uniform &uniform, bool localFiles);
    const QString getConstVariables();
    const QString getDefineProperties();
    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 handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader, bool preview);
    QString stripFileFromURL(const QString &urlString) const;
    QString getQmlEffectString();

    void updateCustomUniforms();
    void createFiles();
    void bakeShaders();
    void saveResources(const QString &name);

    QString getQmlImagesString(bool localFiles);
    QString getQmlComponentString(bool localFiles);
    QString getGeneratedMessage() const;
    QString getDesignerSpecifics() const;

    void connectCompositionNode(CompositionNode *node);
    void updateExtraMargin();
    QSet<QByteArray> getExposedProperties(const QByteArray &qmlContent);

    QList<CompositionNode *> m_nodes;

    int m_selectedIndex = -1;
    bool m_isEmpty = false;  // Init to false to force initial bake after setup
    bool m_hasUnsavedChanges = false;
    // True when shaders haven't changed since last baking
    bool m_shadersUpToDate = true;
    int m_remainingQsbTargets = 0;
    QMap<int, EffectError> m_effectErrors;
    ShaderFeatures m_shaderFeatures;
    QStringList m_shaderVaryingVariables;
    QString m_fragmentShader;
    QString m_vertexShader;
    QStringList m_defaultRootVertexShader;
    QStringList m_defaultRootFragmentShader;
    // Temp files to store shaders sources and binary data
    QTemporaryFile m_fragmentSourceFile;
    QTemporaryFile m_vertexSourceFile;
    QString m_fragmentSourceFilename;
    QString m_vertexSourceFilename;
    QString m_fragmentShaderFilename;
    QString m_vertexShaderFilename;
    QString m_fragmentShaderPreviewFilename;
    QString m_vertexShaderPreviewFilename;
    // 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;
    QString m_qmlComponentString;
    bool m_loadComponentImages = true;
    bool m_isEnabled = true;
    bool m_hasValidTarget = false;
    QString m_currentComposition;
    QTimer m_rebakeTimer;
    int m_extraMargin = 0;
    QString m_effectTypePrefix;

    const QRegularExpression m_spaceReg = QRegularExpression("\\s+");
};

} // namespace EffectComposer