From 96dfdfc0b7ac4a3d9ee314cbe51ca221e84c4a33 Mon Sep 17 00:00:00 2001 From: Amr Essam Date: Thu, 19 Oct 2023 16:39:21 +0300 Subject: [PATCH] QmlDesigner: Fix some parsing issues in effect maker Task-number: QDS-10987 Change-Id: Ifeb42f9e04ba39ddaa45a03b60eb12ce1652c61a Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../effectMakerQmlSources/EffectMaker.qml | 6 ++ .../EffectMakerPreview.qml | 3 + .../effectmakernew/compositionnode.cpp | 2 +- .../effectmakernew/effectmakermodel.cpp | 88 ++++++++++++++++++- src/plugins/effectmakernew/effectmakermodel.h | 8 ++ src/plugins/effectmakernew/uniform.cpp | 21 +++-- src/plugins/effectmakernew/uniform.h | 3 +- 7 files changed, 117 insertions(+), 14 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 56fcdcf5a30..7bc23c9c1f3 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -32,6 +32,12 @@ Item { EffectMakerPreview { mainRoot: root + + FrameAnimation { + id: previewFrameTimer + running: true + paused: false // TODO: from the toolbar + } } Rectangle { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml index 03d587e8195..0e686964971 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml @@ -12,6 +12,9 @@ import EffectMakerBackend Column { id: root + property real animatedTime: 0 //TODO get from animator + property int animatedFrame: 0 //TODO get from animator + width: parent.width required property Item mainRoot diff --git a/src/plugins/effectmakernew/compositionnode.cpp b/src/plugins/effectmakernew/compositionnode.cpp index 8952a29f3ad..a57ac74e94f 100644 --- a/src/plugins/effectmakernew/compositionnode.cpp +++ b/src/plugins/effectmakernew/compositionnode.cpp @@ -102,7 +102,7 @@ void CompositionNode::parse(const QString &qenPath) // parse properties QJsonArray jsonProps = json.value("properties").toArray(); for (const auto /*QJsonValueRef*/ &prop : jsonProps) { - const auto uniform = new Uniform(prop.toObject()); + const auto uniform = new Uniform(prop.toObject(), qenPath); m_unifomrsModel.addUniform(uniform); g_propertyData.insert(uniform->name(), uniform->value()); } diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 6dbe9a78674..e3d8017d01f 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -60,6 +60,20 @@ EffectMakerModel::EffectMakerModel(QObject *parent) m_vertexShaderFilename = m_vertexShaderFile.fileName(); m_fragmentShaderFilename = m_fragmentShaderFile.fileName(); } + + connect(&m_fileWatcher, &Utils::FileSystemWatcher::fileChanged, this, [this]() { + // Update component with images not set. + m_loadComponentImages = false; + updateQmlComponent(); + // Then enable component images with a longer delay than + // the component updating delay. This way Image elements + // will reload the changed image files. + const int enableImagesDelay = 200; + QTimer::singleShot(enableImagesDelay, this, [this]() { + m_loadComponentImages = true; + updateQmlComponent(); + } ); + }); } QHash EffectMakerModel::roleNames() const @@ -734,6 +748,7 @@ void EffectMakerModel::handleQsbProcessExit(Utils::Process *qsbProcess, const QS --m_remainingQsbTargets; const QString errStr = qsbProcess->errorString(); + auto std = qsbProcess->stdErr(); if (!errStr.isEmpty()) qWarning() << QString("Failed to generate QSB file for: %1 %2").arg(shader, errStr); @@ -891,12 +906,47 @@ void EffectMakerModel::setShadersUpToDate(bool UpToDate) emit shadersUpToDateChanged(); } +// Returns name for image mipmap property. +// e.g. "myImage" -> "myImageMipmap". +QString EffectMakerModel::mipmapPropertyName(const QString &name) const +{ + QString simplifiedName = name.simplified(); + simplifiedName = simplifiedName.remove(' '); + simplifiedName += "Mipmap"; + return simplifiedName; +} + QString EffectMakerModel::getQmlImagesString(bool localFiles) { - Q_UNUSED(localFiles) - - // TODO - return QString(); + QString imagesString; + const QList uniforms = allUniforms(); + for (Uniform *uniform : uniforms) { + if (uniform->type() == Uniform::Type::Sampler) { + QString imagePath = uniform->value().toString(); + if (imagePath.isEmpty()) + continue; + imagesString += " Image {\n"; + QString simplifiedName = getImageElementName(*uniform); + imagesString += QString(" id: %1\n").arg(simplifiedName); + imagesString += " anchors.fill: parent\n"; + // File paths are absolute, return as local when requested + if (localFiles) { + QFileInfo fi(imagePath); + imagePath = fi.fileName(); + } + if (m_loadComponentImages) + imagesString += QString(" source: \"%1\"\n").arg(imagePath); + if (!localFiles) { + QString mipmapProperty = mipmapPropertyName(uniform->name()); + imagesString += QString(" mipmap: g_propertyData.%1\n").arg(mipmapProperty); + } else if (uniform->enableMipmap()) { + imagesString += " mipmap: true\n"; + } + imagesString += " visible: false\n"; + imagesString += " }\n"; + } + } + return imagesString; } QString EffectMakerModel::getQmlComponentString(bool localFiles) @@ -971,5 +1021,35 @@ void EffectMakerModel::updateQmlComponent() m_qmlComponentString = getQmlComponentString(false); } +// Removes "file:" from the URL path. +// So e.g. "file:///C:/myimages/steel1.jpg" -> "C:/myimages/steel1.jpg" +QString EffectMakerModel::stripFileFromURL(const QString &urlString) const +{ + QUrl url(urlString); + QString filePath = (url.scheme() == QStringLiteral("file")) ? url.toLocalFile() : url.toString(); + return filePath; +} + +void EffectMakerModel::updateImageWatchers() +{ + const QList uniforms = allUniforms(); + for (Uniform *uniform : uniforms) { + if (uniform->type() == Uniform::Type::Sampler) { + // Watch all image properties files + QString imagePath = stripFileFromURL(uniform->value().toString()); + if (imagePath.isEmpty()) + continue; + m_fileWatcher.addFile(imagePath, Utils::FileSystemWatcher::WatchAllChanges); + } + } +} + +void EffectMakerModel::clearImageWatchers() +{ + const auto watchedFiles = m_fileWatcher.files(); + if (!watchedFiles.isEmpty()) + m_fileWatcher.removeFiles(watchedFiles); +} + } // namespace EffectMaker diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 1cd68e70a72..77f3df5577e 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -6,7 +6,9 @@ #include "shaderfeatures.h" #include +#include +#include #include #include #include @@ -132,10 +134,14 @@ private: QString generateVertexShader(bool includeUniforms = true); QString generateFragmentShader(bool includeUniforms = true); void handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader); + QString stripFileFromURL(const QString &urlString) const; + void updateImageWatchers(); + void clearImageWatchers(); void updateCustomUniforms(); void bakeShaders(); + QString mipmapPropertyName(const QString &name) const; QString getQmlImagesString(bool localFiles); QString getQmlComponentString(bool localFiles); @@ -169,6 +175,8 @@ private: // Used in preview QML, at ShaderEffect component of the file QString m_previewEffectPropertiesString; QString m_qmlComponentString; + bool m_loadComponentImages = true; + Utils::FileSystemWatcher m_fileWatcher; const QRegularExpression m_spaceReg = QRegularExpression("\\s+"); }; diff --git a/src/plugins/effectmakernew/uniform.cpp b/src/plugins/effectmakernew/uniform.cpp index 4901b6bbb6e..d658383eeea 100644 --- a/src/plugins/effectmakernew/uniform.cpp +++ b/src/plugins/effectmakernew/uniform.cpp @@ -4,6 +4,7 @@ #include "uniform.h" #include +#include "propertyhandler.h" #include #include @@ -11,7 +12,8 @@ namespace EffectMaker { -Uniform::Uniform(const QJsonObject &propObj) +Uniform::Uniform(const QJsonObject &propObj, const QString &qenPath) : + m_qenPath(qenPath) { QString value, defaultValue, minValue, maxValue; @@ -31,6 +33,7 @@ Uniform::Uniform(const QJsonObject &propObj) m_enableMipmap = getBoolValue(propObj.value("enableMipmap"), false); // Update the mipmap property QString mipmapProperty = mipmapPropertyName(m_name); + g_propertyData[mipmapProperty] = m_enableMipmap; } if (propObj.contains("value")) { value = propObj.value("value").toString(); @@ -164,9 +167,13 @@ bool Uniform::getBoolValue(const QJsonValue &jsonValue, bool defaultValue) // Used with sampler types QString Uniform::getResourcePath(const QString &value) const { - Q_UNUSED(value) - //TODO - return {}; + QString filePath = value; + QDir dir(m_qenPath); + dir.cdUp(); + QString absPath = dir.absoluteFilePath(filePath); + absPath = QDir::cleanPath(absPath); + absPath = QUrl::fromLocalFile(absPath).toString(); + return absPath; } // Validation and setting values @@ -263,10 +270,8 @@ QString Uniform::stringFromType(Uniform::Type type) return "vec2"; else if (type == Type::Vec3) return "vec3"; - else if (type == Type::Vec4) + else if (type == Type::Vec4 || type == Type::Color) return "vec4"; - else if (type == Type::Color) - return "color"; else if (type == Type::Sampler) return "sampler2D"; else if (type == Type::Define) @@ -292,7 +297,7 @@ Uniform::Type Uniform::typeFromString(const QString &typeString) return Uniform::Type::Vec4; else if (typeString == "color") return Uniform::Type::Color; - else if (typeString == "sampler2D") + else if (typeString == "image") return Uniform::Type::Sampler; else if (typeString == "define") return Uniform::Type::Define; diff --git a/src/plugins/effectmakernew/uniform.h b/src/plugins/effectmakernew/uniform.h index 7bad706cb3e..1fe2530cacd 100644 --- a/src/plugins/effectmakernew/uniform.h +++ b/src/plugins/effectmakernew/uniform.h @@ -42,7 +42,7 @@ public: Define }; - Uniform(const QJsonObject &props); + Uniform(const QJsonObject &props, const QString &qenPath); Type type() const; QString typeName() const; @@ -87,6 +87,7 @@ private: QVariant getInitializedVariant(bool maxValue); QVariant valueStringToVariant(const QString &value); + QString m_qenPath; Type m_type; QVariant m_value; QVariant m_defaultValue;