aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2024-05-07 13:41:14 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2024-05-21 09:45:30 +0000
commit14e0196442a85ea0b90d4d0769696fff6bf40270 (patch)
treeb8e6aca7c1b314024f5d7a5d9ecfed559bbcfa44
parent872c4bf092bf5b7e8a563d3c841af0f8c6808739 (diff)
Show 3D import preview
Show preview of 3D import in item library import dialog when importing a single 3D asset. Fixes: QDS-11111 Change-Id: I13135be1e931cbee034ca8a89654c0827b937bdf Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
-rw-r--r--src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h1
-rw-r--r--src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h3
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt2
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp56
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h32
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp47
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h28
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp211
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h29
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui86
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp109
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h36
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp4
-rw-r--r--src/plugins/qmldesigner/settingspage.cpp3
-rw-r--r--src/tools/qml2puppet/CMakeLists.txt1
-rw-r--r--src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp9
-rw-r--r--src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h8
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp3
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp186
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h46
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp4
21 files changed, 832 insertions, 72 deletions
diff --git a/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h b/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h
index 1e8d82e632b..b0012f3eb24 100644
--- a/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h
+++ b/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h
@@ -18,6 +18,7 @@ public:
ActiveSceneChanged,
ActiveSplitChanged,
RenderModelNodePreviewImage,
+ Import3DPreviewImage,
Import3DSupport,
NodeAtPos,
BakeLightsProgress,
diff --git a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h
index 3fdd7bf6cc5..06df0f79754 100644
--- a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h
+++ b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h
@@ -55,7 +55,8 @@ enum class View3DActionType {
EditCameraRotation,
EditCameraMove,
EditCameraStopAllMoves,
- SetLastSceneEnvData
+ SetLastSceneEnvData,
+ Import3dUpdatePreviewImage
};
constexpr bool isNanotraceEnabled()
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index 2d67fa360f7..039918f91c2 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -741,6 +741,8 @@ extend_qtc_plugin(QmlDesigner
assetimportupdatetreeitemdelegate.cpp assetimportupdatetreeitemdelegate.h
assetimportupdatetreemodel.cpp assetimportupdatetreemodel.h
assetimportupdatetreeview.cpp assetimportupdatetreeview.h
+ import3dcanvas.cpp import3dcanvas.h
+ import3dconnectionmanager.cpp import3dconnectionmanager.h
itemlibrary.qrc
itemlibraryconstants.h
itemlibraryimageprovider.cpp itemlibraryimageprovider.h
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp
new file mode 100644
index 00000000000..87014cbe603
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "import3dcanvas.h"
+
+#include <QImage>
+#include <QLinearGradient>
+#include <QPainter>
+
+namespace QmlDesigner {
+
+static QImage createGradientImage(int width, int height) {
+ QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
+
+ QLinearGradient gradient(0, 0, 0, height);
+ gradient.setColorAt(0, QColor(0x999999));
+ gradient.setColorAt(1, QColor(0x222222));
+
+ QPainter painter(&image);
+ painter.fillRect(0, 0, width, height, gradient);
+
+ return image;
+}
+
+Import3dCanvas::Import3dCanvas(QWidget *parent)
+ : QWidget(parent)
+{
+}
+
+void Import3dCanvas::updateRenderImage(const QImage &img)
+{
+ m_image = img;
+ update();
+}
+
+void Import3dCanvas::paintEvent([[maybe_unused]] QPaintEvent *e)
+{
+ QWidget::paintEvent(e);
+
+ QPainter painter(this);
+
+ if (m_image.isNull()) {
+ QImage image = createGradientImage(width(), height());
+ painter.drawImage(rect(), image, QRect(0, 0, image.width(), image.height()));
+ } else {
+ painter.drawImage(rect(), m_image, QRect(0, 0, m_image.width(), m_image.height()));
+ }
+}
+
+void Import3dCanvas::resizeEvent(QResizeEvent *)
+{
+ emit requestImageUpdate();
+}
+
+
+}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h
new file mode 100644
index 00000000000..22bcc04d70f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include <QEvent>
+#include <QImage>
+#include <QPointer>
+#include <QWidget>
+
+namespace QmlDesigner {
+
+class Import3dCanvas : public QWidget
+{
+ Q_OBJECT
+
+public:
+ Import3dCanvas(QWidget *parent);
+
+ void updateRenderImage(const QImage &img);
+
+signals:
+ void requestImageUpdate();
+
+protected:
+ void paintEvent(QPaintEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
+
+private:
+ QImage m_image;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp
new file mode 100644
index 00000000000..4c455e3c6d2
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "import3dconnectionmanager.h"
+
+#include <imagecontainer.h>
+#include <puppettocreatorcommand.h>
+
+#include <QImage>
+
+namespace QmlDesigner {
+
+Import3dConnectionManager::Import3dConnectionManager()
+{
+ connections().clear(); // Remove default interactive puppets
+ connections().emplace_back("Import 3D", "import3dmode");
+}
+
+void Import3dConnectionManager::setPreviewImageCallback(ImageCallback callback)
+{
+ m_previewImageCallback = std::move(callback);
+}
+
+void Import3dConnectionManager::dispatchCommand(const QVariant &command,
+ ConnectionManagerInterface::Connection &connection)
+{
+ static const int commandType = QMetaType::type("PuppetToCreatorCommand");
+
+ if (command.typeId() == commandType) {
+ auto cmd = command.value<PuppetToCreatorCommand>();
+ switch (cmd.type()) {
+ case PuppetToCreatorCommand::Import3DPreviewImage: {
+ ImageContainer container = qvariant_cast<ImageContainer>(cmd.data());
+ QImage image = container.image();
+ if (!image.isNull())
+ m_previewImageCallback(image);
+ break;
+ }
+ default:
+ break;
+ }
+ } else {
+ InteractiveConnectionManager::dispatchCommand(command, connection);
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h
new file mode 100644
index 00000000000..458d612ad2d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "interactiveconnectionmanager.h"
+
+QT_FORWARD_DECLARE_CLASS(QImage)
+
+namespace QmlDesigner {
+
+class Import3dConnectionManager : public InteractiveConnectionManager
+{
+public:
+ using ImageCallback = std::function<void(const QImage &)>;
+
+ Import3dConnectionManager();
+
+ void setPreviewImageCallback(ImageCallback callback);
+
+protected:
+ void dispatchCommand(const QVariant &command, Connection &connection) override;
+
+private:
+ ImageCallback m_previewImageCallback;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
index 2c690726029..4e49cd2b807 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
@@ -4,15 +4,19 @@
#include "itemlibraryassetimportdialog.h"
#include "ui_itemlibraryassetimportdialog.h"
+#include "import3dcanvas.h"
+#include "import3dconnectionmanager.h"
+
#include <model.h>
#include <model/modelutils.h>
+#include <nodeinstanceview.h>
#include <nodemetainfo.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
+#include <rewriterview.h>
#include <variantproperty.h>
#include <theme.h>
-#include <utils/filepath.h>
#include <utils/outputformatter.h>
#include <projectexplorer/project.h>
@@ -74,9 +78,10 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
const QStringList &importFiles, const QString &defaulTargetDirectory,
const QVariantMap &supportedExts, const QVariantMap &supportedOpts,
const QJsonObject &defaultOpts, const QSet<QString> &preselectedFilesForOverwrite,
- QWidget *parent)
+ AbstractView *view, QWidget *parent)
: QDialog(parent)
, ui(new Ui::ItemLibraryAssetImportDialog)
+ , m_view(view)
, m_importer(this)
, m_preselectedFilesForOverwrite(preselectedFilesForOverwrite)
{
@@ -107,11 +112,9 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
if (m_quick3DFiles.size() != importFiles.size())
addWarning("Cannot import 3D and other assets simultaneously. Skipping non-3D assets.");
- ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Import"));
- connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked,
- this, &ItemLibraryAssetImportDialog::onImport);
+ connect(ui->importButton, &QPushButton::clicked, this, &ItemLibraryAssetImportDialog::onImport);
- ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ ui->importButton->setDefault(true);
ui->advancedSettingsButton->setStyleSheet(
"QPushButton#advancedSettingsButton {background-color: transparent}");
@@ -210,10 +213,14 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
ui->tabWidget->setCurrentIndex(0);
}
- connect(ui->buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked,
+ connect(ui->closeButton, &QPushButton::clicked,
this, &ItemLibraryAssetImportDialog::onClose);
+ connect(ui->acceptButton, &QPushButton::clicked,
+ this, &ItemLibraryAssetImportDialog::onAccept);
connect(ui->tabWidget, &QTabWidget::currentChanged,
this, &ItemLibraryAssetImportDialog::updateUi);
+ connect(canvas(), &Import3dCanvas::requestImageUpdate,
+ this, &ItemLibraryAssetImportDialog::onRequestImageUpdate);
connect(&m_importer, &ItemLibraryAssetImporter::errorReported,
this, &ItemLibraryAssetImportDialog::addError);
@@ -227,6 +234,8 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
this, &ItemLibraryAssetImportDialog::onImportFinished);
connect(&m_importer, &ItemLibraryAssetImporter::progressChanged,
this, &ItemLibraryAssetImportDialog::setImportProgress);
+ connect(&m_importer, &ItemLibraryAssetImporter::importReadyForPreview,
+ this, &ItemLibraryAssetImportDialog::onImportReadyForPreview);
addInfo(tr("Select import options and press \"Import\" to import the following files:"));
for (const auto &file : std::as_const(m_quick3DFiles))
@@ -240,10 +249,12 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
{
+ cleanupPreviewPuppet();
delete ui;
}
-void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode,
+void ItemLibraryAssetImportDialog::updateImport(AbstractView *view,
+ const ModelNode &updateNode,
const QVariantMap &supportedExts,
const QVariantMap &supportedOpts)
{
@@ -332,7 +343,8 @@ void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode,
{sourceInfo.absoluteFilePath()},
node.model()->fileUrl().toLocalFile(),
supportedExts, supportedOpts, options,
- preselectedFiles, Core::ICore::dialogParent());
+ preselectedFiles, view,
+ Core::ICore::dialogParent());
importDlg->show();
} else {
@@ -829,6 +841,140 @@ bool ItemLibraryAssetImportDialog::isHiddenOption(const QString &id)
return hiddenOptions.contains(id);
}
+void ItemLibraryAssetImportDialog::startPreview()
+{
+ cleanupPreviewPuppet();
+
+ // Preview is done via custom QML file added into the temporary folder of the preview
+ QString previewQml =
+R"(
+import QtQuick
+import QtQuick3D
+
+Rectangle {
+ id: root
+ width: %1
+ height: %2
+
+ property string sceneModelName: "%3"
+ property alias view3d: view3d
+ property string extents
+
+ gradient: Gradient {
+ GradientStop { position: 1.0; color: "#222222" }
+ GradientStop { position: 0.0; color: "#999999" }
+ }
+
+ View3D {
+ id: view3d
+ anchors.fill: parent
+ camera: viewCamera
+
+ environment: SceneEnvironment {
+ antialiasingMode: SceneEnvironment.MSAA
+ antialiasingQuality: SceneEnvironment.VeryHigh
+ }
+
+ PerspectiveCamera {
+ id: viewCamera
+ z: 600
+ y: 600
+ x: 600
+ eulerRotation.x: -45
+ eulerRotation.y: -45
+ clipFar: 100000
+ clipNear: 10
+ }
+
+ DirectionalLight {
+ rotation: viewCamera.rotation
+ }
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ color: "white"
+ text: root.extents
+ font.pixelSize: 14
+ }
+}
+)";
+
+ QSize size = canvas()->size();
+ previewQml = previewQml.arg(size.width()).arg(size.height()).arg(m_previewCompName);
+
+ m_previewFile.writeFileContents(previewQml.toUtf8());
+
+ if (!m_previewFile.exists()) {
+ addWarning("Failed to write preview file.");
+ return;
+ }
+
+ m_connectionManager = new Import3dConnectionManager;
+ m_rewriterView = new RewriterView{m_view->externalDependencies(), RewriterView::Amend};
+ m_nodeInstanceView = new NodeInstanceView{*m_connectionManager, m_view->externalDependencies()};
+
+#ifdef QDS_USE_PROJECTSTORAGE
+ m_model = m_view->model()->createModel("Item");
+#else
+ m_model = QmlDesigner::Model::create("QtQuick/Item", 2, 1);
+ m_model->setFileUrl(m_previewFile.toUrl());
+#endif
+
+ auto textDocument = std::make_unique<QTextDocument>(previewQml);
+ auto modifier = std::make_unique<NotIndentingTextEditModifier>(textDocument.get(),
+ QTextCursor{textDocument.get()});
+ m_rewriterView->setTextModifier(modifier.get());
+ m_model->setRewriterView(m_rewriterView);
+
+ if (!m_rewriterView->errors().isEmpty()) {
+ addWarning("Preview scene creation failed.");
+ cleanupPreviewPuppet();
+ return;
+ }
+
+ m_nodeInstanceView->setTarget(m_view->nodeInstanceView()->target());
+
+ auto previewImageCallback = [this](const QImage &image) {
+ canvas()->updateRenderImage(image);
+ };
+
+ auto crashCallback = [&] {
+ addWarning("Preview process crashed.");
+ cleanupPreviewPuppet();
+ };
+
+ m_connectionManager->setPreviewImageCallback(std::move(previewImageCallback));
+ m_nodeInstanceView->setCrashCallback(std::move(crashCallback));
+
+ m_model->setNodeInstanceView(m_nodeInstanceView);
+}
+
+void ItemLibraryAssetImportDialog::cleanupPreviewPuppet()
+{
+ if (m_model) {
+ m_model->setNodeInstanceView({});
+ m_model->setRewriterView({});
+ m_model.reset();
+ }
+
+ if (m_nodeInstanceView)
+ m_nodeInstanceView->setCrashCallback({});
+
+ if (m_connectionManager)
+ m_connectionManager->setPreviewImageCallback({});
+
+ delete m_rewriterView;
+ delete m_nodeInstanceView;
+ delete m_connectionManager;
+}
+
+Import3dCanvas *ItemLibraryAssetImportDialog::canvas()
+{
+ return ui->import3dcanvas;
+}
+
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
{
m_dialogHeight = event->size().height();
@@ -837,8 +983,8 @@ void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
{
- ui->buttonBox->button(QDialogButtonBox::Close)->setEnabled(true);
- ui->buttonBox->button(QDialogButtonBox::Close)->setText(importing ? tr("Cancel") : tr("Close"));
+ ui->closeButton->setEnabled(true);
+ ui->closeButton->setText(importing ? tr("Cancel") : tr("Close"));
}
void ItemLibraryAssetImportDialog::addError(const QString &error, const QString &srcPath)
@@ -860,14 +1006,19 @@ void ItemLibraryAssetImportDialog::addInfo(const QString &info, const QString &s
void ItemLibraryAssetImportDialog::onImport()
{
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ ui->acceptButton->setEnabled(false);
+ ui->importButton->setEnabled(false);
setCloseButtonState(true);
ui->progressBar->setValue(0);
if (!m_quick3DFiles.isEmpty()) {
- m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
- m_importOptions, m_extToImportOptionsMap,
- m_preselectedFilesForOverwrite);
+ if (!m_previewCompName.isEmpty()) {
+ m_importer.reImportQuick3D(m_previewCompName, m_importOptions);
+ } else {
+ m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
+ m_importOptions, m_extToImportOptionsMap,
+ m_preselectedFilesForOverwrite);
+ }
}
}
@@ -881,10 +1032,28 @@ void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &t
ui->progressBar->setValue(value);
}
+void ItemLibraryAssetImportDialog::onImportReadyForPreview(const QString &path, const QString &compName)
+{
+ m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
+ m_previewCompName = compName;
+ QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
+
+ ui->acceptButton->setEnabled(true);
+ ui->importButton->setEnabled(true);
+
+ addInfo(tr("Generating import preview for %1.").arg(compName));
+}
+
+void ItemLibraryAssetImportDialog::onRequestImageUpdate()
+{
+ if (m_nodeInstanceView)
+ m_nodeInstanceView->view3DAction(View3DActionType::Import3dUpdatePreviewImage, canvas()->size());
+}
+
void ItemLibraryAssetImportDialog::onImportNearlyFinished()
{
// Canceling import is no longer doable
- ui->buttonBox->button(QDialogButtonBox::Close)->setEnabled(false);
+ ui->closeButton->setEnabled(false);
}
void ItemLibraryAssetImportDialog::onImportFinished()
@@ -920,6 +1089,16 @@ void ItemLibraryAssetImportDialog::onClose()
}
}
+void ItemLibraryAssetImportDialog::onAccept()
+{
+ cleanupPreviewPuppet();
+
+ ui->importButton->setEnabled(false);
+ ui->acceptButton->setEnabled(false);
+
+ m_importer.finalizeQuick3DImport();
+}
+
void ItemLibraryAssetImportDialog::toggleAdvanced()
{
m_advancedMode = !m_advancedMode;
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
index c5da4782325..efbd189c2fd 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
@@ -3,14 +3,19 @@
#pragma once
#include "itemlibraryassetimporter.h"
-#include "modelnode.h"
+
+#include <modelnode.h>
+
+#include <utils/filepath.h>
#include <QDialog>
#include <QJsonObject>
+#include <QPointer>
#include <QSet>
QT_BEGIN_NAMESPACE
class QGridLayout;
+class QPushButton;
QT_END_NAMESPACE
namespace Utils {
@@ -19,6 +24,10 @@ class OutputFormatter;
namespace QmlDesigner {
class ItemLibraryAssetImporter;
+class Import3dCanvas;
+class Import3dConnectionManager;
+class NodeInstanceView;
+class RewriterView;
namespace Ui {
class ItemLibraryAssetImportDialog;
@@ -35,10 +44,12 @@ public:
const QVariantMap &supportedOpts,
const QJsonObject &defaultOpts,
const QSet<QString> &preselectedFilesForOverwrite,
+ AbstractView *view,
QWidget *parent = nullptr);
~ItemLibraryAssetImportDialog();
- static void updateImport(const ModelNode &updateNode,
+ static void updateImport(AbstractView *view,
+ const ModelNode &updateNode,
const QVariantMap &supportedExts,
const QVariantMap &supportedOpts);
@@ -55,9 +66,12 @@ private:
void onImport();
void setImportProgress(int value, const QString &text);
+ void onImportReadyForPreview(const QString &path, const QString &compName);
+ void onRequestImageUpdate();
void onImportNearlyFinished();
void onImportFinished();
void onClose();
+ void onAccept();
void toggleAdvanced();
void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
@@ -69,8 +83,19 @@ private:
bool isSimpleOption(const QString &id);
bool isHiddenOption(const QString &id);
+ void startPreview();
+ void cleanupPreviewPuppet();
+ Import3dCanvas *canvas();
+
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
Utils::OutputFormatter *m_outputFormatter = nullptr;
+ QPointer<Import3dConnectionManager> m_connectionManager;
+ QPointer<NodeInstanceView> m_nodeInstanceView;
+ QPointer<RewriterView> m_rewriterView;
+ QPointer<AbstractView> m_view;
+ ModelPointer m_model;
+ Utils::FilePath m_previewFile;
+ QString m_previewCompName;
struct OptionsData
{
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
index 081bc36a3d3..a35875a5eb7 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
@@ -6,15 +6,15 @@
<rect>
<x>0</x>
<y>0</y>
- <width>630</width>
+ <width>1100</width>
<height>350</height>
</rect>
</property>
<property name="windowTitle">
<string>Asset Import</string>
</property>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
@@ -24,6 +24,12 @@
<verstretch>2</verstretch>
</sizepolicy>
</property>
+ <property name="minimumSize">
+ <size>
+ <width>550</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="currentIndex">
<number>0</number>
</property>
@@ -98,6 +104,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="text">
<string/>
</property>
@@ -111,16 +123,74 @@
</widget>
</item>
<item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="standardButtons">
- <set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="importButton">
+ <property name="text">
+ <string>Import</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="acceptButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Accept</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
</layout>
</item>
+ <item>
+ <widget class="Import3dCanvas" name="import3dcanvas" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>300</height>
+ </size>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>Import3dCanvas</class>
+ <extends>QWidget</extends>
+ <header>import3dcanvas.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
index ed1f8041e9c..010d00a970a 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
@@ -21,6 +21,7 @@
#include <utils/algorithm.h>
#include <utils/async.h>
+#include <utils/filepath.h>
#include <utils/qtcassert.h>
#include <QApplication>
@@ -58,8 +59,6 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &preselectedFilesForOverwrite)
{
- if (m_isImporting)
- cancelImport();
reset();
m_isImporting = true;
@@ -92,6 +91,53 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
}
}
+void ItemLibraryAssetImporter::reImportQuick3D(const QString &assetName,
+ const QVector<QJsonObject> &options)
+{
+ if (!assetName.isEmpty() && !m_parseData.contains(assetName)) {
+ addError(tr("Attempted to reimport non-existing asset: %1").arg(assetName));
+ return;
+ }
+
+ ParseData &pd = m_parseData[assetName];
+ // Change outDir just in case reimport generates different files
+ QDir oldDir = pd.outDir;
+ QString assetFolder = generateAssetFolderName(pd.assetName);
+ pd.outDir.cdUp();
+ pd.outDir.mkpath(assetFolder);
+
+ if (!pd.outDir.cd(assetFolder)) {
+ addError(tr("Could not access temporary asset directory: \"%1\".")
+ .arg(pd.outDir.filePath(assetFolder)));
+ return;
+ }
+
+ if (oldDir.absolutePath().contains(tempDirNameBase()))
+ oldDir.removeRecursively();
+
+ m_isImporting = false;
+ m_cancelled = false;
+
+ m_puppetProcess.reset();
+ m_requiredImports.clear();
+ m_currentImportId = 0;
+ m_puppetQueue.clear();
+
+ for (ParseData &pd : m_parseData)
+ pd.importId = -1;
+
+ pd.options = options[pd.optionsIndex];
+ pd.importId = 1;
+
+ m_importFiles.remove(assetName);
+
+ m_importIdToAssetNameMap.clear();
+ m_importIdToAssetNameMap[pd.importId] = assetName;
+
+ m_puppetQueue.append(pd.importId);
+ startNextImportProcess();
+}
+
bool ItemLibraryAssetImporter::isImporting() const
{
return m_isImporting;
@@ -104,19 +150,19 @@ void ItemLibraryAssetImporter::cancelImport()
notifyFinished();
}
-void ItemLibraryAssetImporter::addError(const QString &errMsg, const QString &srcPath) const
+void ItemLibraryAssetImporter::addError(const QString &errMsg, const QString &srcPath)
{
qCDebug(importerLog) << "Error: "<< errMsg << srcPath;
emit errorReported(errMsg, srcPath);
}
-void ItemLibraryAssetImporter::addWarning(const QString &warningMsg, const QString &srcPath) const
+void ItemLibraryAssetImporter::addWarning(const QString &warningMsg, const QString &srcPath)
{
qCDebug(importerLog) << "Warning: " << warningMsg << srcPath;
emit warningReported(warningMsg, srcPath);
}
-void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &srcPath) const
+void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &srcPath)
{
qCDebug(importerLog) << "Info: " << infoMsg << srcPath;
emit infoReported(infoMsg, srcPath);
@@ -127,8 +173,8 @@ void ItemLibraryAssetImporter::importProcessFinished([[maybe_unused]] int exitCo
{
m_puppetProcess.reset();
- if (m_parseData.contains(m_currentImportId)) {
- const ParseData &pd = m_parseData[m_currentImportId];
+ if (m_importIdToAssetNameMap.contains(m_currentImportId)) {
+ const ParseData &pd = m_parseData[m_importIdToAssetNameMap[m_currentImportId]];
QString errStr;
if (exitStatus == QProcess::ExitStatus::CrashExit) {
errStr = tr("Import process crashed.");
@@ -151,11 +197,12 @@ void ItemLibraryAssetImporter::importProcessFinished([[maybe_unused]] int exitCo
addError(tr("Asset import process failed: \"%1\".")
.arg(pd.sourceInfo.absoluteFilePath()));
addError(errStr);
- m_parseData.remove(m_currentImportId);
+ m_parseData.remove(m_importIdToAssetNameMap[m_currentImportId]);
+ m_importIdToAssetNameMap.remove(m_currentImportId);
}
}
- int finishedCount = m_parseData.size() - m_puppetQueue.size();
+ int finishedCount = m_importIdToAssetNameMap.size() - m_puppetQueue.size();
if (!m_puppetQueue.isEmpty())
startNextImportProcess();
@@ -163,7 +210,7 @@ void ItemLibraryAssetImporter::importProcessFinished([[maybe_unused]] int exitCo
notifyProgress(100);
QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport);
} else {
- notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size()))));
+ notifyProgress(int(100. * (double(finishedCount) / double(m_importIdToAssetNameMap.size()))));
}
}
@@ -179,7 +226,7 @@ void ItemLibraryAssetImporter::reset()
m_cancelled = false;
delete m_tempDir;
- m_tempDir = new QTemporaryDir;
+ m_tempDir = new QTemporaryDir(QDir::tempPath() + tempDirNameBase());
m_importFiles.clear();
m_overwrittenImports.clear();
m_puppetProcess.reset();
@@ -187,6 +234,7 @@ void ItemLibraryAssetImporter::reset()
m_requiredImports.clear();
m_currentImportId = 0;
m_puppetQueue.clear();
+ m_importIdToAssetNameMap.clear();
}
void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
@@ -208,9 +256,11 @@ void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
int index = extToImportOptionsMap.value(QFileInfo(file).suffix());
ParseData pd;
pd.options = options[index];
+ pd.optionsIndex = index;
if (preParseQuick3DAsset(file, pd, preselectedFilesForOverwrite)) {
pd.importId = ++m_importIdCounter;
- m_parseData.insert(pd.importId, pd);
+ m_importIdToAssetNameMap[pd.importId] = pd.assetName;
+ m_parseData.insert(pd.assetName, pd);
}
notifyProgress(qRound(++count * quota), progressTitle);
}
@@ -239,7 +289,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa
pd.targetDirPath = pd.targetDir.filePath(pd.assetName);
- if (pd.outDir.exists(pd.assetName)) {
+ if (m_parseData.contains(pd.assetName)) {
addWarning(tr("Skipped import of duplicate asset: \"%1\".").arg(pd.assetName));
return false;
}
@@ -288,11 +338,12 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa
}
}
- pd.outDir.mkpath(pd.assetName);
+ QString assetFolder = generateAssetFolderName(pd.assetName);
+ pd.outDir.mkpath(assetFolder);
- if (!pd.outDir.cd(pd.assetName)) {
+ if (!pd.outDir.cd(assetFolder)) {
addError(tr("Could not access temporary asset directory: \"%1\".")
- .arg(pd.outDir.filePath(pd.assetName)));
+ .arg(pd.outDir.filePath(assetFolder)));
return false;
}
return true;
@@ -425,7 +476,7 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
// Copy the original asset into a subdirectory
assetFiles.insert(sourcePath, sourceSceneTargetFilePath(pd));
- m_importFiles.insert(assetFiles);
+ m_importFiles.insert(pd.assetName, assetFiles);
}
void ItemLibraryAssetImporter::copyImportedFiles()
@@ -500,6 +551,12 @@ void ItemLibraryAssetImporter::keepUiAlive() const
QApplication::processEvents();
}
+QString ItemLibraryAssetImporter::generateAssetFolderName(const QString &assetName) const
+{
+ static int counter = 0;
+ return assetName + "_QDS_" + QString::number(counter++);
+}
+
ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAssetOverwrite(const QString &assetName)
{
const QString title = tr("Overwrite Existing Asset?");
@@ -534,7 +591,8 @@ void ItemLibraryAssetImporter::startNextImportProcess()
if (model && view) {
bool done = false;
while (!m_puppetQueue.isEmpty() && !done) {
- const ParseData pd = m_parseData.value(m_puppetQueue.takeLast());
+ const ParseData pd = m_parseData.value(
+ m_importIdToAssetNameMap.value(m_puppetQueue.takeLast()));
QStringList puppetArgs;
QJsonDocument optDoc(pd.options);
@@ -557,7 +615,8 @@ void ItemLibraryAssetImporter::startNextImportProcess()
} else {
addError(tr("Failed to start import 3D asset process."),
pd.sourceInfo.absoluteFilePath());
- m_parseData.remove(pd.importId);
+ const QString assetName = m_importIdToAssetNameMap.take(pd.importId);
+ m_parseData.remove(assetName);
m_puppetProcess.reset();
}
}
@@ -573,8 +632,16 @@ void ItemLibraryAssetImporter::postImport()
postParseQuick3DAsset(pd);
}
- if (!isCancelled())
- finalizeQuick3DImport();
+ if (!isCancelled()) {
+ // TODO: Currently we only support import preview for single imports
+ if (m_parseData.size() != 1) {
+ finalizeQuick3DImport();
+ } else {
+ const ParseData &pd = m_parseData[m_parseData.keys().first()];
+ const QString importedComponentName = pd.assetName;
+ emit importReadyForPreview(pd.outDir.absolutePath(), importedComponentName);
+ }
+ }
}
void ItemLibraryAssetImporter::finalizeQuick3DImport()
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
index 8ad7b5a2dec..abe96909514 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
@@ -2,8 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
-#include "import.h"
-
#include <qprocessuniqueptr.h>
#include <QSet>
@@ -35,20 +33,28 @@ public:
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &preselectedFilesForOverwrite);
+ void reImportQuick3D(const QString &assetName, const QVector<QJsonObject> &options);
+
bool isImporting() const;
void cancelImport();
bool isCancelled() const;
- void addError(const QString &errMsg, const QString &srcPath = {}) const;
- void addWarning(const QString &warningMsg, const QString &srcPath = {}) const;
- void addInfo(const QString &infoMsg, const QString &srcPath = {}) const;
+ void addError(const QString &errMsg, const QString &srcPath = {});
+ void addWarning(const QString &warningMsg, const QString &srcPath = {});
+ void addInfo(const QString &infoMsg, const QString &srcPath = {});
+
+ QString previewFileName() const { return "QDSImport3dPreviewScene.qml"; }
+ QString tempDirNameBase() const { return "/qds3dimport"; }
+
+ void finalizeQuick3DImport();
signals:
- void errorReported(const QString &, const QString &) const;
- void warningReported(const QString &, const QString &) const;
- void infoReported(const QString &, const QString &) const;
- void progressChanged(int value, const QString &text) const;
- void importNearlyFinished() const;
+ void errorReported(const QString &, const QString &);
+ void warningReported(const QString &, const QString &);
+ void infoReported(const QString &, const QString &);
+ void progressChanged(int value, const QString &text);
+ void importReadyForPreview(const QString &path, const QString &compName);
+ void importNearlyFinished();
void importFinished();
private slots:
@@ -63,7 +69,8 @@ private:
QFileInfo sourceInfo;
QString assetName;
QString originalAssetName;
- int importId;
+ int importId = -1;
+ int optionsIndex = -1;
};
void notifyFinished();
@@ -79,6 +86,7 @@ private:
void notifyProgress(int value, const QString &text);
void notifyProgress(int value);
void keepUiAlive() const;
+ QString generateAssetFolderName(const QString &assetName) const;
enum class OverwriteResult {
Skip,
@@ -89,10 +97,9 @@ private:
OverwriteResult confirmAssetOverwrite(const QString &assetName);
void startNextImportProcess();
void postImport();
- void finalizeQuick3DImport();
QString sourceSceneTargetFilePath(const ParseData &pd);
- QSet<QHash<QString, QString>> m_importFiles;
+ QHash<QString, QHash<QString, QString>> m_importFiles; // Key: asset name
QHash<QString, QStringList> m_overwrittenImports;
bool m_isImporting = false;
bool m_cancelled = false;
@@ -101,7 +108,8 @@ private:
QProcessUniquePointer m_puppetProcess;
int m_importIdCounter = 0;
int m_currentImportId = 0;
- QHash<int, ParseData> m_parseData;
+ QHash<int, QString> m_importIdToAssetNameMap;
+ QHash<QString, ParseData> m_parseData; // Key: asset name
QString m_progressTitle;
QStringList m_requiredImports;
QList<int> m_puppetQueue;
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
index feff523b9c6..e4f4ffcd9c6 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
@@ -164,7 +164,7 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap)
auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir,
m_importableExtensions3DMap,
m_importOptions3DMap, {}, {},
- Core::ICore::dialogParent());
+ this, Core::ICore::dialogParent());
int result = importDlg->exec();
return result == QDialog::Accepted ? AddFilesResult::succeeded() : AddFilesResult::cancelled();
@@ -198,7 +198,7 @@ void ItemLibraryView::customNotification(const AbstractView *view, const QString
const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{
if (identifier == "UpdateImported3DAsset" && nodeList.size() > 0) {
- ItemLibraryAssetImportDialog::updateImport(nodeList[0],
+ ItemLibraryAssetImportDialog::updateImport(this, nodeList[0],
m_importableExtensions3DMap,
m_importOptions3DMap);
diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp
index 17c75a02853..df17f005a21 100644
--- a/src/plugins/qmldesigner/settingspage.cpp
+++ b/src/plugins/qmldesigner/settingspage.cpp
@@ -39,7 +39,8 @@ namespace Internal {
static QStringList puppetModes()
{
- static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode", "bakelightsmode"};
+ static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode",
+ "bakelightsmode", "import3dmode"};
return puppetModeList;
}
diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt
index 36ca6293d43..e77887adcca 100644
--- a/src/tools/qml2puppet/CMakeLists.txt
+++ b/src/tools/qml2puppet/CMakeLists.txt
@@ -140,6 +140,7 @@ extend_qtc_executable(qml2puppet
qmltransitionnodeinstance.cpp qmltransitionnodeinstance.h
qt3dpresentationnodeinstance.cpp qt3dpresentationnodeinstance.h
qt5bakelightsnodeinstanceserver.cpp qt5bakelightsnodeinstanceserver.h
+ qt5import3dnodeinstanceserver.cpp qt5import3dnodeinstanceserver.h
qt5informationnodeinstanceserver.cpp qt5informationnodeinstanceserver.h
qt5nodeinstanceclientproxy.cpp qt5nodeinstanceclientproxy.h
qt5nodeinstanceserver.cpp qt5nodeinstanceserver.h
diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
index d4f79fdabdd..1ccea6049c8 100644
--- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
@@ -462,9 +462,9 @@ QVector4D GeneralHelper::approachNode(
// a selection box for bound calculations to work. This is used to focus the view for
// various preview image generations, where doing things asynchronously is not good
// and recalculating bounds for every frame is not a problem.
-void GeneralHelper::calculateNodeBoundsAndFocusCamera(
- QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort,
- float defaultLookAtDistance, bool closeUp)
+QVector3D GeneralHelper::calculateNodeBoundsAndFocusCamera(
+ QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort,
+ float defaultLookAtDistance, bool closeUp)
{
QVector3D minBounds;
QVector3D maxBounds;
@@ -505,8 +505,9 @@ void GeneralHelper::calculateNodeBoundsAndFocusCamera(
perspectiveCamera->setClipNear(minDist * 0.99);
perspectiveCamera->setClipFar(maxDist * 1.01);
}
-
}
+
+ return extents;
}
// Aligns any cameras found in nodes list to a camera.
diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h
index 50eaba68ebb..996a06488f4 100644
--- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h
+++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h
@@ -72,9 +72,11 @@ public:
bool closeUp = false);
Q_INVOKABLE QVector4D approachNode(QQuick3DCamera *camera, float defaultLookAtDistance,
QObject *node, QQuick3DViewport *viewPort);
- Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node,
- QQuick3DViewport *viewPort,
- float defaultLookAtDistance, bool closeUp);
+ Q_INVOKABLE QVector3D calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera,
+ QQuick3DNode *node,
+ QQuick3DViewport *viewPort,
+ float defaultLookAtDistance,
+ bool closeUp);
Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes);
Q_INVOKABLE QVector4D alignView(QQuick3DCamera *camera, const QVariant &nodes,
const QVector3D &lookAtPoint, float defaultLookAtDistance);
diff --git a/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp b/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp
index 9815d21ac47..9e3cdac151e 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp
@@ -6,6 +6,7 @@
#include "qt5bakelightsnodeinstanceserver.h"
#include "qt5captureimagenodeinstanceserver.h"
#include "qt5capturepreviewnodeinstanceserver.h"
+#include "qt5import3dnodeinstanceserver.h"
#include "qt5informationnodeinstanceserver.h"
#include "qt5rendernodeinstanceserver.h"
@@ -173,6 +174,8 @@ std::unique_ptr<NodeInstanceServer> createNodeInstanceServer(
return std::make_unique<Qt5PreviewNodeInstanceServer>(nodeInstanceClient);
else if (serverName == "bakelightsmode")
return std::make_unique<Qt5BakeLightsNodeInstanceServer>(nodeInstanceClient);
+ else if (serverName == "import3dmode")
+ return std::make_unique<Qt5Import3dNodeInstanceServer>(nodeInstanceClient);
return {};
}
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp
new file mode 100644
index 00000000000..b5afa949ec2
--- /dev/null
+++ b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.cpp
@@ -0,0 +1,186 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "qt5import3dnodeinstanceserver.h"
+
+#include "createscenecommand.h"
+#include "view3dactioncommand.h"
+
+#include "imagecontainer.h"
+#include "nodeinstanceclientinterface.h"
+#include "puppettocreatorcommand.h"
+
+#include <QFileInfo>
+#include <QLocale>
+#include <QQmlComponent>
+#include <QQmlEngine>
+
+#include <QQmlProperty>
+
+#include <private/qquick3dnode_p.h>
+#include <private/qquick3dviewport_p.h>
+#include <private/qquickdesignersupport_p.h>
+
+namespace QmlDesigner {
+
+Qt5Import3dNodeInstanceServer::Qt5Import3dNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
+ Qt5NodeInstanceServer(nodeInstanceClient)
+{
+ setSlowRenderTimerInterval(100000000);
+ setRenderTimerInterval(20);
+
+#ifdef QUICK3D_MODULE
+ m_generalHelper = new Internal::GeneralHelper();
+ QObject::connect(m_generalHelper, &Internal::GeneralHelper::requestRender, this, [this]() {
+ startRenderTimer();
+ });
+#endif
+}
+
+Qt5Import3dNodeInstanceServer::~Qt5Import3dNodeInstanceServer()
+{
+ cleanup();
+}
+
+void Qt5Import3dNodeInstanceServer::createScene(const CreateSceneCommand &command)
+{
+ initializeView();
+ registerFonts(command.resourceUrl);
+ setTranslationLanguage(command.language);
+ setupScene(command);
+ startRenderTimer();
+}
+
+void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DActionCommand &command)
+{
+ switch (command.type()) {
+ case View3DActionType::Import3dUpdatePreviewImage: {
+ QObject *obj = rootItem();
+ if (obj) {
+ QSize size = command.value().toSize();
+ QQmlProperty wProp(obj, "width", context());
+ QQmlProperty hProp(obj, "height", context());
+ wProp.write(size.width());
+ hProp.write(size.height());
+ resizeCanvasToRootItem();
+
+ startRenderTimer();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void Qt5Import3dNodeInstanceServer::startRenderTimer()
+{
+ if (timerId() != 0)
+ killTimer(timerId());
+
+ int timerId = startTimer(renderTimerInterval());
+
+ setTimerId(timerId);
+}
+
+void Qt5Import3dNodeInstanceServer::cleanup()
+{
+#ifdef QUICK3D_MODULE
+ delete m_previewNode;
+ delete m_generalHelper;
+#endif
+}
+
+void Qt5Import3dNodeInstanceServer::finish()
+{
+ cleanup();
+}
+
+void Qt5Import3dNodeInstanceServer::collectItemChangesAndSendChangeCommands()
+{
+ static bool inFunction = false;
+
+ if (!rootNodeInstance().holdsGraphical())
+ return;
+
+ if (!inFunction) {
+ inFunction = true;
+
+ QQuickDesignerSupport::polishItems(quickWindow());
+
+ render();
+
+ inFunction = false;
+ }
+}
+
+void Qt5Import3dNodeInstanceServer::render()
+{
+#ifdef QUICK3D_MODULE
+ ++m_renderCount;
+
+ if (m_renderCount == 1) {
+ QObject *obj = rootItem();
+ QQmlProperty viewProp(obj, "view3d", context());
+ QObject *viewObj = viewProp.read().value<QObject *>();
+ m_view3D = qobject_cast<QQuick3DViewport *>(viewObj);
+ if (m_view3D) {
+ QQmlProperty sceneModelNameProp(obj, "sceneModelName", context());
+ QString sceneModelName = sceneModelNameProp.read().toString();
+ QFileInfo fi(fileUrl().toLocalFile());
+ QString compPath = fi.absolutePath() + '/' + sceneModelName + ".qml";
+ QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous);
+ m_previewNode = qobject_cast<QQuick3DNode *>(comp.create(context()));
+ if (m_previewNode) {
+ engine()->setObjectOwnership(m_previewNode, QJSEngine::CppOwnership);
+ m_previewNode->setParent(m_view3D);
+ m_view3D->setImportScene(m_previewNode);
+ }
+ }
+ }
+
+ // Render scene once to ensure geometries are intialized so bounds calculations work correctly
+ if (m_renderCount == 2 && m_view3D) {
+ QVector3D extents =
+ m_generalHelper->calculateNodeBoundsAndFocusCamera(m_view3D->camera(), m_previewNode,
+ m_view3D, 1040, false);
+ auto getExtentStr = [&extents](int idx) -> QString {
+ int prec = 0;
+ float val = extents[idx];
+ while (val < 100.f) {
+ ++prec;
+ val *= 10.f;
+ }
+ // Strip unnecessary zeroes after decimal separator
+ if (prec > 0) {
+ QString checkStr = QString::number(extents[idx], 'f', prec);
+ while (prec > 0 && (checkStr.last(1) == "0" || checkStr.last(1) == ".")) {
+ --prec;
+ checkStr.chop(1);
+ }
+ }
+ QString retval = QLocale().toString(extents[idx], 'f', prec);
+ return retval;
+ };
+ QQmlProperty extentsProp(rootItem(), "extents", context());
+ extentsProp.write(tr("Dimensions: %1 x %2 x %3").arg(getExtentStr(0))
+ .arg(getExtentStr(1))
+ .arg(getExtentStr(2)));
+ }
+
+ rootNodeInstance().updateDirtyNodeRecursive();
+ QImage renderImage = grabWindow();
+
+ if (m_renderCount >= 2) {
+ ImageContainer imgContainer(0, renderImage, m_renderCount);
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::Import3DPreviewImage,
+ QVariant::fromValue(imgContainer)});
+ slowDownRenderTimer(); // No more renders needed for now
+ }
+#else
+ slowDownRenderTimer();
+#endif
+}
+
+} // namespace QmlDesigner
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h
new file mode 100644
index 00000000000..bc3506ea3c0
--- /dev/null
+++ b/src/tools/qml2puppet/qml2puppet/instances/qt5import3dnodeinstanceserver.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "generalhelper.h"
+#include "qt5nodeinstanceserver.h"
+
+QT_BEGIN_NAMESPACE
+class QQuick3DNode;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+class Qt5Import3dNodeInstanceServer : public Qt5NodeInstanceServer
+{
+ Q_OBJECT
+public:
+ explicit Qt5Import3dNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient);
+
+public:
+ virtual ~Qt5Import3dNodeInstanceServer();
+
+ void createScene(const CreateSceneCommand &command) override;
+ void view3DAction(const View3DActionCommand &command) override;
+
+ void render();
+
+protected:
+ void collectItemChangesAndSendChangeCommands() override;
+ void startRenderTimer() override;
+
+private:
+ void finish();
+ void cleanup();
+
+ int m_renderCount = 0;
+
+#ifdef QUICK3D_MODULE
+ QQuick3DViewport *m_view3D = nullptr;
+ Internal::GeneralHelper *m_generalHelper = nullptr;
+ QQuick3DNode *m_previewNode = nullptr;
+#endif
+};
+
+} // namespace QmlDesigner
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp
index f4d01d28db4..c11899e0ec9 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp
@@ -10,6 +10,7 @@
#include "qt5captureimagenodeinstanceserver.h"
#include "qt5capturepreviewnodeinstanceserver.h"
#include "qt5informationnodeinstanceserver.h"
+#include "qt5import3dnodeinstanceserver.h"
#include "qt5previewnodeinstanceserver.h"
#include "qt5rendernodeinstanceserver.h"
#include "qt5testnodeinstanceserver.h"
@@ -70,6 +71,9 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
} else if (QCoreApplication::arguments().at(2) == QLatin1String("bakelightsmode")) {
setNodeInstanceServer(std::make_unique<Qt5BakeLightsNodeInstanceServer>(this));
initializeSocket();
+ } else if (QCoreApplication::arguments().at(2) == QLatin1String("import3dmode")) {
+ setNodeInstanceServer(std::make_unique<Qt5Import3dNodeInstanceServer>(this));
+ initializeSocket();
}
}