EffectComposer: Save composition's root shaders to the qep file

Shaders of the root are saved as `vertexCode` and `fragmentCode`
into the root of the qep file.

Task-number: QDS-13852
Fixes: QDS-13832
Change-Id: I71ff4d21400d01be999463d1ac5da13eb70c5f69
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2024-10-17 11:32:54 +03:00
parent 867343465d
commit eea998da9a
2 changed files with 89 additions and 66 deletions

View File

@@ -59,11 +59,12 @@ EffectComposerModel::EffectComposerModel(QObject *parent)
QHash<int, QByteArray> EffectComposerModel::roleNames() const QHash<int, QByteArray> EffectComposerModel::roleNames() const
{ {
QHash<int, QByteArray> roles; static const QHash<int, QByteArray> roles = {
roles[NameRole] = "nodeName"; {NameRole, "nodeName"},
roles[EnabledRole] = "nodeEnabled"; {EnabledRole, "nodeEnabled"},
roles[UniformsRole] = "nodeUniformsModel"; {UniformsRole, "nodeUniformsModel"},
roles[Dependency] = "isDependency"; {Dependency, "isDependency"},
};
return roles; return roles;
} }
@@ -207,6 +208,8 @@ void EffectComposerModel::clear(bool clearName)
if (clearName) { if (clearName) {
setCurrentComposition(""); setCurrentComposition("");
setCompositionPath(""); setCompositionPath("");
resetRootFragmentShader();
resetRootVertexShader();
} }
setHasUnsavedChanges(!m_currentComposition.isEmpty()); setHasUnsavedChanges(!m_currentComposition.isEmpty());
@@ -253,8 +256,6 @@ void EffectComposerModel::setFragmentShader(const QString &newFragmentShader)
return; return;
m_fragmentShader = newFragmentShader; m_fragmentShader = newFragmentShader;
rebakeIfLiveUpdateMode();
} }
QString EffectComposerModel::vertexShader() const QString EffectComposerModel::vertexShader() const
@@ -268,8 +269,40 @@ void EffectComposerModel::setVertexShader(const QString &newVertexShader)
return; return;
m_vertexShader = newVertexShader; m_vertexShader = newVertexShader;
}
rebakeIfLiveUpdateMode(); void EffectComposerModel::setRootFragmentShader(const QString &shader)
{
m_rootFragmentShader = shader;
}
void EffectComposerModel::resetRootFragmentShader()
{
static const QString defaultRootFragmentShader = {
"void main() {\n"
" fragColor = texture(iSource, texCoord);\n"
" @nodes\n"
" fragColor = fragColor * qt_Opacity;\n"
"}\n"};
setRootFragmentShader(defaultRootFragmentShader);
}
void EffectComposerModel::setRootVertexShader(const QString &shader)
{
m_rootVertexShader = shader;
}
void EffectComposerModel::resetRootVertexShader()
{
static const QString defaultRootVertexShader = {
"void main() {\n"
" texCoord = qt_MultiTexCoord0;\n"
" fragCoord = qt_Vertex.xy;\n"
" vec2 vertCoord = qt_Vertex.xy;\n"
" @nodes\n"
" gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);\n"
"}\n"};
setRootVertexShader(defaultRootVertexShader);
} }
QString EffectComposerModel::qmlComponentString() const QString EffectComposerModel::qmlComponentString() const
@@ -978,9 +1011,19 @@ void EffectComposerModel::saveComposition(const QString &name)
nodesArray.append(nodeObject); nodesArray.append(nodeObject);
} }
auto toJsonArray = [](const QString &code) -> QJsonArray {
return QJsonArray::fromStringList(code.split('\n'));
};
if (!nodesArray.isEmpty()) if (!nodesArray.isEmpty())
json.insert("nodes", nodesArray); json.insert("nodes", nodesArray);
if (!m_rootVertexShader.isEmpty())
json.insert("vertexCode", toJsonArray(m_rootVertexShader));
if (!m_rootFragmentShader.isEmpty())
json.insert("fragmentCode", toJsonArray(m_rootFragmentShader));
QJsonObject rootJson; QJsonObject rootJson;
rootJson.insert("QEP", json); rootJson.insert("QEP", json);
QJsonDocument jsonDoc(rootJson); QJsonDocument jsonDoc(rootJson);
@@ -1009,25 +1052,20 @@ void EffectComposerModel::openMainShadersCodeEditor()
if (!m_shadersCodeEditor) { if (!m_shadersCodeEditor) {
m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr<EffectShadersCodeEditor>( m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr<EffectShadersCodeEditor>(
currentComposition()); currentComposition());
m_shadersCodeEditor->setFragmentValue(generateFragmentShader(true)); m_shadersCodeEditor->setFragmentValue(m_rootFragmentShader);
m_shadersCodeEditor->setVertexValue(generateVertexShader(true)); m_shadersCodeEditor->setVertexValue(m_rootVertexShader);
connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] {
setRootVertexShader(m_shadersCodeEditor->vertexValue());
setHasUnsavedChanges(true);
rebakeIfLiveUpdateMode();
});
connect( connect(
m_shadersCodeEditor.get(), m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] {
&EffectShadersCodeEditor::vertexValueChanged, setRootFragmentShader(m_shadersCodeEditor->fragmentValue());
this,
[this] {
setVertexShader(m_shadersCodeEditor->vertexValue());
setHasUnsavedChanges(true);
});
connect(
m_shadersCodeEditor.get(),
&EffectShadersCodeEditor::fragmentValueChanged,
this,
[this] {
setFragmentShader(m_shadersCodeEditor->fragmentValue());
setHasUnsavedChanges(true); setHasUnsavedChanges(true);
rebakeIfLiveUpdateMode();
}); });
connect( connect(
@@ -1090,6 +1128,23 @@ void EffectComposerModel::openComposition(const QString &path)
return; return;
} }
auto toCodeBlock = [](const QJsonValue &jsonValue) -> QString {
if (!jsonValue.isArray())
return {};
QString code;
const QJsonArray array = jsonValue.toArray();
for (const QJsonValue &lineValue : array) {
if (lineValue.isString())
code += lineValue.toString() + '\n';
}
return code;
};
setRootVertexShader(toCodeBlock(json["vertexCode"]));
setRootFragmentShader(toCodeBlock(json["fragmentCode"]));
if (json.contains("nodes") && json["nodes"].isArray()) { if (json.contains("nodes") && json["nodes"].isArray()) {
beginResetModel(); beginResetModel();
QHash<QString, int> refCounts; QHash<QString, int> refCounts;
@@ -1486,32 +1541,6 @@ QString EffectComposerModel::processFragmentRootLine(const QString &line)
return output; return output;
} }
QStringList EffectComposerModel::getDefaultRootVertexShader()
{
if (m_defaultRootVertexShader.isEmpty()) {
m_defaultRootVertexShader << "void main() {";
m_defaultRootVertexShader << " texCoord = qt_MultiTexCoord0;";
m_defaultRootVertexShader << " fragCoord = qt_Vertex.xy;";
m_defaultRootVertexShader << " vec2 vertCoord = qt_Vertex.xy;";
m_defaultRootVertexShader << " @nodes";
m_defaultRootVertexShader << " gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);";
m_defaultRootVertexShader << "}";
}
return m_defaultRootVertexShader;
}
QStringList EffectComposerModel::getDefaultRootFragmentShader()
{
if (m_defaultRootFragmentShader.isEmpty()) {
m_defaultRootFragmentShader << "void main() {";
m_defaultRootFragmentShader << " fragColor = texture(iSource, texCoord);";
m_defaultRootFragmentShader << " @nodes";
m_defaultRootFragmentShader << " fragColor = fragColor * qt_Opacity;";
m_defaultRootFragmentShader << "}";
}
return m_defaultRootFragmentShader;
}
// Remove all post-processing tags ("@tag") from the code. // Remove all post-processing tags ("@tag") from the code.
// Except "@nodes" tag as that is handled later. // Except "@nodes" tag as that is handled later.
QStringList EffectComposerModel::removeTagsFromCode(const QStringList &codeLines) QStringList EffectComposerModel::removeTagsFromCode(const QStringList &codeLines)
@@ -1574,7 +1603,7 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms)
// split to root and main parts // split to root and main parts
QString s_root; QString s_root;
QString s_main; QString s_main;
QStringList s_sourceCode; QStringList s_sourceCode = m_rootVertexShader.split('\n');
m_shaderVaryingVariables.clear(); m_shaderVaryingVariables.clear();
for (const CompositionNode *n : std::as_const(m_nodes)) { for (const CompositionNode *n : std::as_const(m_nodes)) {
if (!n->vertexCode().isEmpty() && n->isEnabled()) { if (!n->vertexCode().isEmpty() && n->isEnabled()) {
@@ -1591,11 +1620,6 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms)
} }
} }
if (s_sourceCode.isEmpty()) {
// If source nodes doesn't contain any code, use default one
s_sourceCode << getDefaultRootVertexShader();
}
if (removeTags) { if (removeTags) {
s_sourceCode = removeTagsFromCode(s_sourceCode); s_sourceCode = removeTagsFromCode(s_sourceCode);
s_root = removeTagsFromCode(s_root); s_root = removeTagsFromCode(s_root);
@@ -1630,7 +1654,7 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms)
// split to root and main parts // split to root and main parts
QString s_root; QString s_root;
QString s_main; QString s_main;
QStringList s_sourceCode; QStringList s_sourceCode = m_rootFragmentShader.split('\n');
for (const CompositionNode *n : std::as_const(m_nodes)) { for (const CompositionNode *n : std::as_const(m_nodes)) {
if (!n->fragmentCode().isEmpty() && n->isEnabled()) { if (!n->fragmentCode().isEmpty() && n->isEnabled()) {
const QStringList fragmentCode = n->fragmentCode().split('\n'); const QStringList fragmentCode = n->fragmentCode().split('\n');
@@ -1646,11 +1670,6 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms)
} }
} }
if (s_sourceCode.isEmpty()) {
// If source nodes doesn't contain any code, use default one
s_sourceCode << getDefaultRootFragmentShader();
}
if (removeTags) { if (removeTags) {
s_sourceCode = removeTagsFromCode(s_sourceCode); s_sourceCode = removeTagsFromCode(s_sourceCode);
s_root = removeTagsFromCode(s_root); s_root = removeTagsFromCode(s_root);

View File

@@ -93,6 +93,12 @@ public:
QString vertexShader() const; QString vertexShader() const;
void setVertexShader(const QString &newVertexShader); void setVertexShader(const QString &newVertexShader);
void setRootFragmentShader(const QString &shader);
void resetRootFragmentShader();
void setRootVertexShader(const QString &shader);
void resetRootVertexShader();
Q_INVOKABLE QString qmlComponentString() const; Q_INVOKABLE QString qmlComponentString() const;
Q_INVOKABLE void updateQmlComponent(); Q_INVOKABLE void updateQmlComponent();
@@ -172,8 +178,6 @@ private:
int getTagIndex(const QStringList &code, const QString &tag); int getTagIndex(const QStringList &code, const QString &tag);
QString processVertexRootLine(const QString &line); QString processVertexRootLine(const QString &line);
QString processFragmentRootLine(const QString &line); QString processFragmentRootLine(const QString &line);
QStringList getDefaultRootVertexShader();
QStringList getDefaultRootFragmentShader();
QStringList removeTagsFromCode(const QStringList &codeLines); QStringList removeTagsFromCode(const QStringList &codeLines);
QString removeTagsFromCode(const QString &code); QString removeTagsFromCode(const QString &code);
QString getCustomShaderVaryings(bool outState); QString getCustomShaderVaryings(bool outState);
@@ -212,8 +216,8 @@ private:
QStringList m_shaderVaryingVariables; QStringList m_shaderVaryingVariables;
QString m_fragmentShader; QString m_fragmentShader;
QString m_vertexShader; QString m_vertexShader;
QStringList m_defaultRootVertexShader; QString m_rootVertexShader;
QStringList m_defaultRootFragmentShader; QString m_rootFragmentShader;
// Temp files to store shaders sources and binary data // Temp files to store shaders sources and binary data
QTemporaryDir m_shaderDir; QTemporaryDir m_shaderDir;
QString m_fragmentSourceFilename; QString m_fragmentSourceFilename;