forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -18,6 +18,7 @@ public:
|
||||
ActiveSceneChanged,
|
||||
ActiveSplitChanged,
|
||||
RenderModelNodePreviewImage,
|
||||
Import3DPreviewImage,
|
||||
Import3DSupport,
|
||||
NodeAtPos,
|
||||
BakeLightsProgress,
|
||||
|
@@ -55,7 +55,8 @@ enum class View3DActionType {
|
||||
EditCameraRotation,
|
||||
EditCameraMove,
|
||||
EditCameraStopAllMoves,
|
||||
SetLastSceneEnvData
|
||||
SetLastSceneEnvData,
|
||||
Import3dUpdatePreviewImage
|
||||
};
|
||||
|
||||
constexpr bool isNanotraceEnabled()
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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;
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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>
|
||||
|
@@ -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()
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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);
|
||||
|
@@ -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 {};
|
||||
}
|
||||
|
@@ -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
|
@@ -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
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user