diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNodeUniform.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNodeUniform.qml index 8dc3b75c9b5..bfe0d3e3b78 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNodeUniform.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNodeUniform.qml @@ -17,24 +17,30 @@ Item { visible: !uniformUseCustomValue Component.onCompleted: { - if (uniformType === "int") + if (uniformType === "int") { valueLoader.source = "ValueInt.qml" - else if (uniformType === "vec2") + } else if (uniformType === "vec2") { valueLoader.source = "ValueVec2.qml" - else if (uniformType === "vec3") + } else if (uniformType === "vec3") { valueLoader.source = "ValueVec3.qml" - else if (uniformType === "vec4") + } else if (uniformType === "vec4") { valueLoader.source = "ValueVec4.qml" - else if (uniformType === "bool") + } else if (uniformType === "bool") { valueLoader.source = "ValueBool.qml" - else if (uniformType === "color") + } else if (uniformType === "color") { valueLoader.source = "ValueColor.qml" - else if (uniformType === "sampler2D") + } else if (uniformType === "sampler2D") { valueLoader.source = "ValueImage.qml" - else if (uniformType === "define") - valueLoader.source = "ValueDefine.qml" - else + } else if (uniformType === "define") { + if (uniformControlType === "int") + valueLoader.source = "ValueInt.qml" + else if (uniformControlType === "bool") + valueLoader.source = "ValueBool.qml" + else + valueLoader.source = "ValueDefine.qml" + } else { valueLoader.source = "ValueFloat.qml" + } } RowLayout { diff --git a/src/plugins/effectcomposer/compositionnode.cpp b/src/plugins/effectcomposer/compositionnode.cpp index b63258e0af3..108eb5801d8 100644 --- a/src/plugins/effectcomposer/compositionnode.cpp +++ b/src/plugins/effectcomposer/compositionnode.cpp @@ -130,6 +130,10 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c m_unifomrsModel.addUniform(uniform); m_uniforms.append(uniform); g_propertyData.insert(uniform->name(), uniform->value()); + if (uniform->type() == Uniform::Type::Define) { + // Changing defines requires rebaking the shaders + connect(uniform, &Uniform::uniformValueChanged, this, &CompositionNode::rebakeRequested); + } } // Seek through code to get tags diff --git a/src/plugins/effectcomposer/compositionnode.h b/src/plugins/effectcomposer/compositionnode.h index 589954ec871..b3348bb38fc 100644 --- a/src/plugins/effectcomposer/compositionnode.h +++ b/src/plugins/effectcomposer/compositionnode.h @@ -56,6 +56,7 @@ signals: void uniformsModelChanged(); void isEnabledChanged(); void isDepencyChanged(); + void rebakeRequested(); private: void parse(const QString &effectName, const QString &qenPath, const QJsonObject &json); diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index ffa63a03536..9a3b8ca0afc 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -49,6 +49,8 @@ static bool writeToFile(const QByteArray &buf, const QString &filename, FileType EffectComposerModel::EffectComposerModel(QObject *parent) : QAbstractListModel{parent} { + m_rebakeTimer.setSingleShot(true); + connect(&m_rebakeTimer, &QTimer::timeout, this, &EffectComposerModel::bakeShaders); } QHash EffectComposerModel::roleNames() const @@ -107,10 +109,7 @@ void EffectComposerModel::addNode(const QString &nodeQenPath) { beginResetModel(); auto *node = new CompositionNode({}, nodeQenPath); - connect(qobject_cast(node->uniformsModel()), - &EffectComposerUniformsModel::dataChanged, this, [this] { - setHasUnsavedChanges(true); - }); + connectCompositionNode(node); const QList requiredNodes = node->requiredNodes(); if (requiredNodes.size() > 0) { @@ -122,10 +121,7 @@ void EffectComposerModel::addNode(const QString &nodeQenPath) const QString path = EffectUtils::nodesSourcesPath() + "/common/" + requiredId + ".qen"; auto requiredNode = new CompositionNode({}, path); - connect(qobject_cast(requiredNode->uniformsModel()), - &EffectComposerUniformsModel::dataChanged, this, [this] { - setHasUnsavedChanges(true); - }); + connectCompositionNode(requiredNode); requiredNode->setRefCount(1); m_nodes.prepend(requiredNode); } @@ -167,6 +163,7 @@ void EffectComposerModel::moveNode(int fromIdx, int toIdx) void EffectComposerModel::removeNode(int idx) { beginResetModel(); + m_rebakeTimer.stop(); CompositionNode *node = m_nodes.takeAt(idx); const QStringList reqNodes = node->requiredNodes(); @@ -193,6 +190,7 @@ void EffectComposerModel::removeNode(int idx) void EffectComposerModel::clear(bool clearName) { beginResetModel(); + m_rebakeTimer.stop(); qDeleteAll(m_nodes); m_nodes.clear(); endResetModel(); @@ -418,7 +416,7 @@ void EffectComposerModel::setEffectError(const QString &errorMessage, int type, Q_EMIT effectErrorChanged(); } -QString variantAsDataString(const Uniform::Type type, const QVariant &variant) +QString variantAsDataString(const Uniform::Type type, const Uniform::Type controlType, const QVariant &variant) { QString s; switch (type) { @@ -470,7 +468,12 @@ QString variantAsDataString(const Uniform::Type type, const QVariant &variant) } case Uniform::Type::Sampler: case Uniform::Type::Define: { - s = variant.toString(); + if (controlType == Uniform::Type::Int) + s = QString::number(variant.toInt()); + else if (controlType == Uniform::Type::Bool) + s = variant.toBool() ? QString("true") : QString("false"); + else + s = variant.toString(); break; } } @@ -495,16 +498,23 @@ QJsonObject nodeToJson(const CompositionNode &node) uniformObject.insert("name", QString(uniform->name())); QString type = Uniform::stringFromType(uniform->type()); uniformObject.insert("type", type); + if (uniform->type() == Uniform::Type::Define) { + QString controlType = Uniform::stringFromType(uniform->controlType()); + if (controlType != type) + uniformObject.insert("controlType", controlType); + } if (!uniform->displayName().isEmpty()) uniformObject.insert("displayName", QString(uniform->displayName())); - QString value = variantAsDataString(uniform->type(), uniform->value()); + QString value = variantAsDataString(uniform->type(), uniform->controlType(), + uniform->value()); if (uniform->type() == Uniform::Type::Sampler) value = QFileInfo(value).fileName(); uniformObject.insert("value", value); - QString defaultValue = variantAsDataString(uniform->type(), uniform->defaultValue()); + QString defaultValue = variantAsDataString(uniform->type(), uniform->controlType(), + uniform->defaultValue()); if (uniform->type() == Uniform::Type::Sampler) { defaultValue = QFileInfo(value).fileName(); if (uniform->enableMipmap()) @@ -517,9 +527,14 @@ QJsonObject nodeToJson(const CompositionNode &node) || uniform->type() == Uniform::Type::Int || uniform->type() == Uniform::Type::Vec2 || uniform->type() == Uniform::Type::Vec3 - || uniform->type() == Uniform::Type::Vec4) { - uniformObject.insert("minValue", variantAsDataString(uniform->type(), uniform->minValue())); - uniformObject.insert("maxValue", variantAsDataString(uniform->type(), uniform->maxValue())); + || uniform->type() == Uniform::Type::Vec4 + || uniform->controlType() == Uniform::Type::Int) { + uniformObject.insert("minValue", variantAsDataString(uniform->type(), + uniform->controlType(), + uniform->minValue())); + uniformObject.insert("maxValue", variantAsDataString(uniform->type(), + uniform->controlType(), + uniform->maxValue())); } if (!uniform->customValue().isEmpty()) uniformObject.insert("customValue", uniform->customValue()); @@ -754,10 +769,7 @@ void EffectComposerModel::openComposition(const QString &path) for (const auto &nodeElement : nodesArray) { auto *node = new CompositionNode(effectName, {}, nodeElement.toObject()); - connect(qobject_cast(node->uniformsModel()), - &EffectComposerUniformsModel::dataChanged, this, [this] { - setHasUnsavedChanges(true); - }); + connectCompositionNode(node); m_nodes.append(node); const QStringList reqIds = node->requiredNodes(); for (const QString &reqId : reqIds) @@ -922,6 +934,10 @@ QString EffectComposerModel::valueAsString(const Uniform &uniform) } else if (uniform.type() == Uniform::Type::Color) { return QString("\"%1\"").arg(uniform.value().toString()); } else if (uniform.type() == Uniform::Type::Define) { + if (uniform.controlType() == Uniform::Type::Int) + return QString::number(uniform.value().toInt()); + else if (uniform.controlType() == Uniform::Type::Bool) + return uniform.value().toBool() ? QString("1") : QString("0"); return uniform.value().toString(); } else { qWarning() << QString("Unhandled const variable type: %1").arg(int(uniform.type())).toLatin1(); @@ -1020,10 +1036,8 @@ const QString EffectComposerModel::getDefineProperties() QString s; for (Uniform *uniform : uniforms) { // TODO: Check if uniform is already added. - if (uniform->type() == Uniform::Type::Define) { - QString defineValue = uniform->value().toString(); - s += QString("#define %1 %2\n").arg(uniform->name(), defineValue); - } + if (uniform->type() == Uniform::Type::Define) + s += QString("#define %1 %2\n").arg(uniform->name(), valueAsString(*uniform)); } if (!s.isEmpty()) s += '\n'; @@ -1620,6 +1634,18 @@ QString EffectComposerModel::getQmlComponentString(bool localFiles) return s; } +void EffectComposerModel::connectCompositionNode(CompositionNode *node) +{ + connect(qobject_cast(node->uniformsModel()), + &EffectComposerUniformsModel::dataChanged, this, [this] { + setHasUnsavedChanges(true); + }); + connect(node, &CompositionNode::rebakeRequested, this, [this] { + // This can come multiple times in a row in response to property changes, so let's buffer it + m_rebakeTimer.start(200); + }); +} + QString EffectComposerModel::currentComposition() const { return m_currentComposition; diff --git a/src/plugins/effectcomposer/effectcomposermodel.h b/src/plugins/effectcomposer/effectcomposermodel.h index e8c7a5c61db..c0eb76f0b94 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.h +++ b/src/plugins/effectcomposer/effectcomposermodel.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace ProjectExplorer { class Target; @@ -172,6 +173,8 @@ private: QString getQmlImagesString(bool localFiles); QString getQmlComponentString(bool localFiles); + void connectCompositionNode(CompositionNode *node); + QList m_nodes; int m_selectedIndex = -1; @@ -206,6 +209,7 @@ private: bool m_loadComponentImages = true; bool m_isEnabled = true; QString m_currentComposition; + QTimer m_rebakeTimer; const QRegularExpression m_spaceReg = QRegularExpression("\\s+"); }; diff --git a/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp b/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp index e547883b9dd..9d8c1a31a72 100644 --- a/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp +++ b/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp @@ -26,6 +26,7 @@ QHash EffectComposerUniformsModel::roleNames() const roles[MinValueRole] = "uniformMinValue"; roles[MaxValueRole] = "uniformMaxValue"; roles[TypeRole] = "uniformType"; + roles[ControlTypeRole] = "uniformControlType"; roles[UseCustomValueRole] = "uniformUseCustomValue"; return roles; } diff --git a/src/plugins/effectcomposer/effectcomposeruniformsmodel.h b/src/plugins/effectcomposer/effectcomposeruniformsmodel.h index 3e2d44c6260..f60c016ed09 100644 --- a/src/plugins/effectcomposer/effectcomposeruniformsmodel.h +++ b/src/plugins/effectcomposer/effectcomposeruniformsmodel.h @@ -37,6 +37,7 @@ private: MaxValueRole, MinValueRole, TypeRole, + ControlTypeRole, UseCustomValueRole }; diff --git a/src/plugins/effectcomposer/uniform.cpp b/src/plugins/effectcomposer/uniform.cpp index e8fd77d631f..4c8b994388e 100644 --- a/src/plugins/effectcomposer/uniform.cpp +++ b/src/plugins/effectcomposer/uniform.cpp @@ -22,6 +22,7 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS m_name = propObj.value("name").toString(); m_description = propObj.value("description").toString(); m_type = Uniform::typeFromString(propObj.value("type").toString()); + m_controlType = m_type; defaultValue = propObj.value("defaultValue").toString(); m_displayName = propObj.value("displayName").toString(); @@ -44,6 +45,12 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS g_propertyData[mipmapProperty] = m_enableMipmap; } + if (m_type == Type::Define) { + QString controlType = propObj.value("controlType").toString(); + if (!controlType.isEmpty()) + m_controlType = Uniform::typeFromString(controlType); + } + m_customValue = propObj.value("customValue").toString(); m_useCustomValue = getBoolValue(propObj.value("useCustomValue"), false); @@ -61,12 +68,22 @@ Uniform::Type Uniform::type() const return m_type; } +Uniform::Type Uniform::controlType() const +{ + return m_controlType; +} + // String representation of the type for qml QString Uniform::typeName() const { return Uniform::stringFromType(m_type); } +QString Uniform::controlTypeName() const +{ + return Uniform::stringFromType(m_controlType); +} + QVariant Uniform::value() const { return m_value; @@ -216,6 +233,13 @@ QVariant Uniform::getInitializedVariant(bool maxValue) return maxValue ? QVector4D(1.0, 1.0, 1.0, 1.0) : QVector4D(0.0, 0.0, 0.0, 0.0); case Uniform::Type::Color: return maxValue ? QColor::fromRgbF(1.0f, 1.0f, 1.0f, 1.0f) : QColor::fromRgbF(0.0f, 0.0f, 0.0f, 0.0f); + case Uniform::Type::Define: + if (m_controlType == Uniform::Type::Bool) + return maxValue ? true : false; + else if (m_controlType == Uniform::Type::Int) + return maxValue ? 100 : 0; + else + return QVariant(); default: return QVariant(); } @@ -262,7 +286,10 @@ QVariant Uniform::valueStringToVariant(const QString &value) variant = value; break; case Uniform::Type::Define: - variant = value; + if (m_controlType == Uniform::Type::Bool) + variant = (value == "true"); + else + variant = value; break; } diff --git a/src/plugins/effectcomposer/uniform.h b/src/plugins/effectcomposer/uniform.h index 83f15224aec..09081248c54 100644 --- a/src/plugins/effectcomposer/uniform.h +++ b/src/plugins/effectcomposer/uniform.h @@ -20,6 +20,7 @@ class Uniform : public QObject Q_PROPERTY(QString uniformName MEMBER m_displayName CONSTANT) Q_PROPERTY(QString uniformType READ typeName CONSTANT) + Q_PROPERTY(QString uniformControlType READ controlTypeName CONSTANT) Q_PROPERTY(QString uniformDescription READ description CONSTANT) Q_PROPERTY(QVariant uniformValue READ value WRITE setValue NOTIFY uniformValueChanged) Q_PROPERTY(QVariant uniformBackendValue READ backendValue NOTIFY uniformBackendValueChanged) @@ -45,7 +46,9 @@ public: Uniform(const QString &effectName, const QJsonObject &props, const QString &qenPath); Type type() const; + Type controlType() const; QString typeName() const; + QString controlTypeName() const; QVariant value() const; void setValue(const QVariant &newValue); @@ -90,6 +93,7 @@ private: QString m_qenPath; Type m_type; + Type m_controlType; QVariant m_value; QVariant m_defaultValue; QVariant m_minValue;