forked from qt-creator/qt-creator
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:
@@ -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(
|
connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] {
|
||||||
m_shadersCodeEditor.get(),
|
setRootVertexShader(m_shadersCodeEditor->vertexValue());
|
||||||
&EffectShadersCodeEditor::vertexValueChanged,
|
|
||||||
this,
|
|
||||||
[this] {
|
|
||||||
setVertexShader(m_shadersCodeEditor->vertexValue());
|
|
||||||
setHasUnsavedChanges(true);
|
setHasUnsavedChanges(true);
|
||||||
|
rebakeIfLiveUpdateMode();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
m_shadersCodeEditor.get(),
|
m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] {
|
||||||
&EffectShadersCodeEditor::fragmentValueChanged,
|
setRootFragmentShader(m_shadersCodeEditor->fragmentValue());
|
||||||
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);
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user