forked from qt-creator/qt-creator
QmlDesigner: Add core uniforms and features for shaders
Task-number: QDS-10499 Change-Id: I12b39d29133accd012ac019def0c4a34ee84d8e5 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -723,6 +723,7 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
uniform.cpp uniform.h
|
uniform.cpp uniform.h
|
||||||
effectutils.cpp effectutils.h
|
effectutils.cpp effectutils.h
|
||||||
effectmakercontextobject.cpp effectmakercontextobject.h
|
effectmakercontextobject.cpp effectmakercontextobject.h
|
||||||
|
shaderfeatures.cpp shaderfeatures.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
|
@@ -84,6 +84,21 @@ void CompositionNode::parse(const QString &qenPath)
|
|||||||
QJsonArray jsonProps = json.value("properties").toArray();
|
QJsonArray jsonProps = json.value("properties").toArray();
|
||||||
for (const auto /*QJsonValueRef*/ &prop : jsonProps)
|
for (const auto /*QJsonValueRef*/ &prop : jsonProps)
|
||||||
m_unifomrsModel.addUniform(new Uniform(prop.toObject()));
|
m_unifomrsModel.addUniform(new Uniform(prop.toObject()));
|
||||||
|
|
||||||
|
// Seek through code to get tags
|
||||||
|
QStringList shaderCodeLines;
|
||||||
|
shaderCodeLines += m_vertexCode.split('\n');
|
||||||
|
shaderCodeLines += m_fragmentCode.split('\n');
|
||||||
|
for (const QString &codeLine : std::as_const(shaderCodeLines)) {
|
||||||
|
QString trimmedLine = codeLine.trimmed();
|
||||||
|
if (trimmedLine.startsWith("@requires")) {
|
||||||
|
// Get the required node, remove "@requires"
|
||||||
|
QString l = trimmedLine.sliced(9).trimmed();
|
||||||
|
QString nodeName = trimmedLine.sliced(10);
|
||||||
|
if (!nodeName.isEmpty() && !m_requiredNodes.contains(nodeName))
|
||||||
|
m_requiredNodes << nodeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include "effectmakermodel.h"
|
#include "effectmakermodel.h"
|
||||||
|
|
||||||
#include "compositionnode.h"
|
#include "compositionnode.h"
|
||||||
|
#include "uniform.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
@@ -54,4 +55,101 @@ void EffectMakerModel::removeNode(int idx)
|
|||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QList<Uniform *> EffectMakerModel::allUniforms()
|
||||||
|
{
|
||||||
|
QList<Uniform *> uniforms = {};
|
||||||
|
for (const auto &node : std::as_const(m_nodes))
|
||||||
|
uniforms.append(static_cast<EffectMakerUniformsModel *>(node->uniformsModel())->uniforms());
|
||||||
|
return uniforms;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString EffectMakerModel::getBufUniform()
|
||||||
|
{
|
||||||
|
QList<Uniform *> uniforms = allUniforms();
|
||||||
|
QString s;
|
||||||
|
s += "layout(std140, binding = 0) uniform buf {\n";
|
||||||
|
s += " mat4 qt_Matrix;\n";
|
||||||
|
s += " float qt_Opacity;\n";
|
||||||
|
if (m_shaderFeatures.enabled(ShaderFeatures::Time))
|
||||||
|
s += " float iTime;\n";
|
||||||
|
if (m_shaderFeatures.enabled(ShaderFeatures::Frame))
|
||||||
|
s += " int iFrame;\n";
|
||||||
|
if (m_shaderFeatures.enabled(ShaderFeatures::Resolution))
|
||||||
|
s += " vec3 iResolution;\n";
|
||||||
|
if (m_shaderFeatures.enabled(ShaderFeatures::Mouse))
|
||||||
|
s += " vec4 iMouse;\n";
|
||||||
|
for (const auto uniform : uniforms) {
|
||||||
|
// TODO: Check if uniform is already added.
|
||||||
|
if (uniform->type() != Uniform::Type::Sampler && uniform->type() != Uniform::Type::Define) {
|
||||||
|
QString type = Uniform::stringFromType(uniform->type());
|
||||||
|
QString props = " " + type + " " + uniform->name() + ";\n";
|
||||||
|
s += props;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s += "};\n";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString EffectMakerModel::getVSUniforms()
|
||||||
|
{
|
||||||
|
QString s;
|
||||||
|
s += "#version 440\n";
|
||||||
|
s += '\n';
|
||||||
|
s += "layout(location = 0) in vec4 qt_Vertex;\n";
|
||||||
|
s += "layout(location = 1) in vec2 qt_MultiTexCoord0;\n";
|
||||||
|
s += "layout(location = 0) out vec2 texCoord;\n";
|
||||||
|
if (m_shaderFeatures.enabled(ShaderFeatures::FragCoord))
|
||||||
|
s += "layout(location = 1) out vec2 fragCoord;\n";
|
||||||
|
s += '\n';
|
||||||
|
s += getBufUniform();
|
||||||
|
s += '\n';
|
||||||
|
s += "out gl_PerVertex { vec4 gl_Position; };\n";
|
||||||
|
s += '\n';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString EffectMakerModel::getFSUniforms()
|
||||||
|
{
|
||||||
|
QList<Uniform *> uniforms = allUniforms();
|
||||||
|
QString s;
|
||||||
|
s += "#version 440\n";
|
||||||
|
s += '\n';
|
||||||
|
s += "layout(location = 0) in vec2 texCoord;\n";
|
||||||
|
if (m_shaderFeatures.enabled(ShaderFeatures::FragCoord))
|
||||||
|
s += "layout(location = 1) in vec2 fragCoord;\n";
|
||||||
|
s += "layout(location = 0) out vec4 fragColor;\n";
|
||||||
|
s += '\n';
|
||||||
|
s += getBufUniform();
|
||||||
|
s += '\n';
|
||||||
|
|
||||||
|
bool usesSource = m_shaderFeatures.enabled(ShaderFeatures::Source);
|
||||||
|
if (usesSource)
|
||||||
|
s += "layout(binding = 1) uniform sampler2D iSource;\n";
|
||||||
|
|
||||||
|
// Add sampler uniforms
|
||||||
|
int bindingIndex = usesSource ? 2 : 1;
|
||||||
|
for (const auto uniform : uniforms) {
|
||||||
|
// TODO: Check if uniform is already added.
|
||||||
|
if (uniform->type() == Uniform::Type::Sampler) {
|
||||||
|
// Start index from 2, 1 is source item
|
||||||
|
QString props = QString("layout(binding = %1) uniform sampler2D %2")
|
||||||
|
.arg(bindingIndex).arg(uniform->name());
|
||||||
|
s += props + ";\n";
|
||||||
|
bindingIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s += '\n';
|
||||||
|
if (m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) {
|
||||||
|
const int blurItems = 5;
|
||||||
|
for (int i = 1; i <= blurItems; i++) {
|
||||||
|
QString props = QString("layout(binding = %1) uniform sampler2D iSourceBlur%2")
|
||||||
|
.arg(bindingIndex).arg(QString::number(i));
|
||||||
|
s += props + ";\n";
|
||||||
|
bindingIndex++;
|
||||||
|
}
|
||||||
|
s += '\n';
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -3,12 +3,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "shaderfeatures.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class CompositionNode;
|
class CompositionNode;
|
||||||
|
class Uniform;
|
||||||
|
|
||||||
class EffectMakerModel : public QAbstractListModel
|
class EffectMakerModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
@@ -42,10 +45,18 @@ private:
|
|||||||
|
|
||||||
bool isValidIndex(int idx) const;
|
bool isValidIndex(int idx) const;
|
||||||
|
|
||||||
|
const QList<Uniform *> allUniforms();
|
||||||
|
|
||||||
|
const QString getBufUniform();
|
||||||
|
const QString getVSUniforms();
|
||||||
|
const QString getFSUniforms();
|
||||||
|
|
||||||
QList<CompositionNode *> m_nodes;
|
QList<CompositionNode *> m_nodes;
|
||||||
|
|
||||||
int m_selectedIndex = -1;
|
int m_selectedIndex = -1;
|
||||||
bool m_isEmpty = true;
|
bool m_isEmpty = true;
|
||||||
|
|
||||||
|
ShaderFeatures m_shaderFeatures;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -67,4 +67,9 @@ void EffectMakerUniformsModel::addUniform(Uniform *uniform)
|
|||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Uniform *> EffectMakerUniformsModel::uniforms() const
|
||||||
|
{
|
||||||
|
return m_uniforms;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -25,6 +25,8 @@ public:
|
|||||||
|
|
||||||
void addUniform(Uniform *uniform);
|
void addUniform(Uniform *uniform);
|
||||||
|
|
||||||
|
QList<Uniform *> uniforms() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
NameRole = Qt::UserRole + 1,
|
NameRole = Qt::UserRole + 1,
|
||||||
|
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#include "shaderfeatures.h"
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
ShaderFeatures::ShaderFeatures()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Browse the shaders and check which features are used in them.
|
||||||
|
void ShaderFeatures::update(const QString &vs, const QString &fs, const QString &qml)
|
||||||
|
{
|
||||||
|
QStringList vsList = vs.split("\n");
|
||||||
|
QStringList fsList = fs.split("\n");
|
||||||
|
|
||||||
|
const QStringList code = vsList + fsList;
|
||||||
|
Features newFeatures = {};
|
||||||
|
m_gridMeshWidth = 1;
|
||||||
|
m_gridMeshHeight = 1;
|
||||||
|
for (const QString &line : code)
|
||||||
|
checkLine(line, newFeatures);
|
||||||
|
|
||||||
|
// iTime may also be used in QML side, without being used in shaders.
|
||||||
|
// In this case enable the time helpers creation.
|
||||||
|
if (qml.contains("iTime"))
|
||||||
|
newFeatures.setFlag(Time, true);
|
||||||
|
|
||||||
|
if (newFeatures != m_enabledFeatures)
|
||||||
|
m_enabledFeatures = newFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShaderFeatures::enabled(ShaderFeatures::Feature feature) const
|
||||||
|
{
|
||||||
|
return m_enabledFeatures.testFlag(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderFeatures::checkLine(const QString &line, Features &features)
|
||||||
|
{
|
||||||
|
if (line.contains("iTime"))
|
||||||
|
features.setFlag(Time, true);
|
||||||
|
|
||||||
|
if (line.contains("iFrame"))
|
||||||
|
features.setFlag(Frame, true);
|
||||||
|
|
||||||
|
if (line.contains("iResolution"))
|
||||||
|
features.setFlag(Resolution, true);
|
||||||
|
|
||||||
|
if (line.contains("iSource"))
|
||||||
|
features.setFlag(Source, true);
|
||||||
|
|
||||||
|
if (line.contains("iMouse"))
|
||||||
|
features.setFlag(Mouse, true);
|
||||||
|
|
||||||
|
if (line.contains("fragCoord"))
|
||||||
|
features.setFlag(FragCoord, true);
|
||||||
|
|
||||||
|
if (line.contains("@mesh")) {
|
||||||
|
// Get the mesh size, remove "@mesh"
|
||||||
|
QString l = line.trimmed().sliced(5);
|
||||||
|
QStringList list = l.split(QLatin1Char(','));
|
||||||
|
if (list.size() >= 2) {
|
||||||
|
int w = list.at(0).trimmed().toInt();
|
||||||
|
int h = list.at(1).trimmed().toInt();
|
||||||
|
// Set size to max values
|
||||||
|
m_gridMeshWidth = std::max(m_gridMeshWidth, w);
|
||||||
|
m_gridMeshHeight = std::max(m_gridMeshHeight, h);
|
||||||
|
}
|
||||||
|
// If is bigger than default (1, 1), set the feature
|
||||||
|
if (m_gridMeshWidth > 1 || m_gridMeshHeight > 1)
|
||||||
|
features.setFlag(GridMesh, true);
|
||||||
|
}
|
||||||
|
if (line.contains("@blursources"))
|
||||||
|
features.setFlag(BlurSources, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QFlags>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class ShaderFeatures
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Feature {
|
||||||
|
Time = 1 << 0,
|
||||||
|
Frame = 1 << 1,
|
||||||
|
Resolution = 1 << 2,
|
||||||
|
Source = 1 << 3,
|
||||||
|
Mouse = 1 << 4,
|
||||||
|
FragCoord = 1 << 5,
|
||||||
|
GridMesh = 1 << 6,
|
||||||
|
BlurSources = 1 << 7
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(Features, Feature)
|
||||||
|
|
||||||
|
ShaderFeatures();
|
||||||
|
void update(const QString &vs, const QString &fs, const QString &qml);
|
||||||
|
|
||||||
|
bool enabled(ShaderFeatures::Feature feature) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkLine(const QString &line, ShaderFeatures::Features &features);
|
||||||
|
ShaderFeatures::Features m_enabledFeatures;
|
||||||
|
int m_gridMeshWidth = 1;
|
||||||
|
int m_gridMeshHeight = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(ShaderFeatures::Features)
|
||||||
|
} // namespace QmlDesigner
|
@@ -261,7 +261,7 @@ QString Uniform::stringFromType(Uniform::Type type)
|
|||||||
else if (type == Type::Color)
|
else if (type == Type::Color)
|
||||||
return "color";
|
return "color";
|
||||||
else if (type == Type::Sampler)
|
else if (type == Type::Sampler)
|
||||||
return "image";
|
return "sampler2D";
|
||||||
else if (type == Type::Define)
|
else if (type == Type::Define)
|
||||||
return "define";
|
return "define";
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ Uniform::Type Uniform::typeFromString(const QString &typeString)
|
|||||||
return Uniform::Type::Vec4;
|
return Uniform::Type::Vec4;
|
||||||
else if (typeString == "color")
|
else if (typeString == "color")
|
||||||
return Uniform::Type::Color;
|
return Uniform::Type::Color;
|
||||||
else if (typeString == "image")
|
else if (typeString == "sampler2D")
|
||||||
return Uniform::Type::Sampler;
|
return Uniform::Type::Sampler;
|
||||||
else if (typeString == "define")
|
else if (typeString == "define")
|
||||||
return Uniform::Type::Define;
|
return Uniform::Type::Define;
|
||||||
|
@@ -68,6 +68,7 @@ public:
|
|||||||
|
|
||||||
static QString stringFromType(Uniform::Type type);
|
static QString stringFromType(Uniform::Type type);
|
||||||
static Uniform::Type typeFromString(const QString &typeString);
|
static Uniform::Type typeFromString(const QString &typeString);
|
||||||
|
static QString typeToUniform(Uniform::Type type);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void uniformValueChanged();
|
void uniformValueChanged();
|
||||||
|
Reference in New Issue
Block a user