QmlDesigner: Add support for previewing multiple 3D imports

Imported items are shown on a list in import dialog and a preview is
generated for each. Options are also specified per-import rather
than applying to all imports.

Fixes: QDS-10806
Change-Id: I6be09880afc0f8886585c4e768da1197b46bc71a
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2024-05-28 17:48:47 +03:00
parent d3a0a497b0
commit b3a5d38a68
8 changed files with 356 additions and 129 deletions

View File

@@ -58,7 +58,9 @@ enum class View3DActionType {
EditCameraStopAllMoves,
SetLastSceneEnvData,
Import3dUpdatePreviewImage,
Import3dRotatePreviewModel
Import3dRotatePreviewModel,
Import3dAddPreviewModel,
Import3dSetCurrentPreviewModel
};
constexpr bool isNanotraceEnabled()

View File

@@ -239,20 +239,18 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
connect(ui->advancedSettingsButton, &QPushButton::clicked,
this, &ItemLibraryAssetImportDialog::toggleAdvanced);
connect(ui->importList, &QListWidget::currentRowChanged,
this, &ItemLibraryAssetImportDialog::onCurrentRowChanged);
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::updateUi);
if (m_quick3DFiles.size() != 1) {
addInfo(tr("Select import options and press \"Import\" to import the following files:"));
} else {
addInfo(tr("Importing:"));
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
}
addInfo(tr("Importing:"));
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
for (const auto &file : std::as_const(m_quick3DFiles))
addInfo(file);
updateImportButtonState();
m_updatingControlStates = false;
}
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
@@ -501,7 +499,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
QJsonValue value(optCheck->isChecked());
optObj.insert("value", value);
m_importOptions[optionsIndex].insert(optKey, optObj);
updateImportButtonState();
updatePreviewOptions();
});
} else {
// Simple options also exist in advanced, so don't connect simple controls directly
@@ -512,13 +510,13 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
QObject::connect(optCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
if (advCheck->isChecked() != optCheck->isChecked()) {
advCheck->setChecked(optCheck->isChecked());
updateImportButtonState();
updatePreviewOptions();
}
});
QObject::connect(advCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
if (advCheck->isChecked() != optCheck->isChecked()) {
optCheck->setChecked(advCheck->isChecked());
updateImportButtonState();
updatePreviewOptions();
}
});
}
@@ -555,7 +553,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
QJsonValue value(optSpin->value());
optObj.insert("value", value);
m_importOptions[optionsIndex].insert(optKey, optObj);
updateImportButtonState();
updatePreviewOptions();
});
} else {
auto *advSpin = qobject_cast<QDoubleSpinBox *>(
@@ -566,14 +564,14 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
this, [this, optSpin, advSpin] {
if (advSpin->value() != optSpin->value()) {
advSpin->setValue(optSpin->value());
updateImportButtonState();
updatePreviewOptions();
}
});
QObject::connect(advSpin, &QDoubleSpinBox::valueChanged,
this, [this, optSpin, advSpin] {
if (advSpin->value() != optSpin->value()) {
optSpin->setValue(advSpin->value());
updateImportButtonState();
updatePreviewOptions();
}
});
}
@@ -859,6 +857,15 @@ bool ItemLibraryAssetImportDialog::isHiddenOption(const QString &id)
return hiddenOptions.contains(id);
}
bool ItemLibraryAssetImportDialog::optionsChanged()
{
for (const ItemLibraryAssetImporter::PreviewData &data : std::as_const(m_previewData)) {
if (data.renderedOptions != data.currentOptions)
return true;
}
return false;
}
void ItemLibraryAssetImportDialog::startPreview()
{
cleanupPreviewPuppet();
@@ -877,7 +884,7 @@ Rectangle {
property alias sceneNode: sceneNode
property alias view3d: view3d
property string extents
property string sceneModelName: "%3"
property string sceneModelName
gradient: Gradient {
GradientStop { position: 1.0; color: "#222222" }
@@ -925,7 +932,7 @@ Rectangle {
)";
QSize size = canvas()->size();
previewQml = previewQml.arg(size.width()).arg(size.height()).arg(m_previewCompName);
previewQml = previewQml.arg(size.width()).arg(size.height());
m_previewFile.writeFileContents(previewQml.toUtf8());
@@ -998,6 +1005,31 @@ Import3dCanvas *ItemLibraryAssetImportDialog::canvas()
return ui->import3dcanvas;
}
void ItemLibraryAssetImportDialog::resetOptionControls()
{
const QString currentName = ui->importList->currentItem()->text();
if (!m_previewData.contains(currentName))
return;
m_updatingControlStates = true;
const ItemLibraryAssetImporter::PreviewData &data = m_previewData[currentName];
const QJsonObject options = data.currentOptions;
const QStringList optKeys = options.keys();
for (const QString &optKey : optKeys) {
QWidget *w = m_labelToControlWidgetMaps[data.optionsIndex].value(optKey);
const QJsonObject optObj = options.value(optKey).toObject();
const QJsonValue optValue = optObj.value("value");
if (auto *cb = qobject_cast<QCheckBox *>(w))
cb->setChecked(optValue.toBool());
else if (auto *spin = qobject_cast<QDoubleSpinBox *>(w))
spin->setValue(optValue.toDouble());
}
m_updatingControlStates = false;
updatePreviewOptions();
}
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
{
m_dialogHeight = event->size().height();
@@ -1010,9 +1042,20 @@ void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
ui->closeButton->setText(importing ? tr("Cancel") : tr("Close"));
}
void ItemLibraryAssetImportDialog::updateImportButtonState()
void ItemLibraryAssetImportDialog::updatePreviewOptions()
{
ui->importButton->setText(m_previewOptions == m_importOptions ? tr("Accept") : tr("Import"));
if (m_updatingControlStates)
return;
if (ui->importList->currentRow() >= 0) {
const QString assetName = ui->importList->currentItem()->text();
if (m_previewData.contains(assetName)) {
ItemLibraryAssetImporter::PreviewData &data = m_previewData[assetName];
data.currentOptions = m_importOptions[data.optionsIndex];
}
}
ui->importButton->setText(optionsChanged() ? tr("Import") : tr("Accept"));
}
void ItemLibraryAssetImportDialog::addError(const QString &error, const QString &srcPath)
@@ -1035,8 +1078,12 @@ void ItemLibraryAssetImportDialog::addInfo(const QString &info, const QString &s
void ItemLibraryAssetImportDialog::onImport()
{
ui->importButton->setEnabled(false);
ui->tabWidget->setEnabled(false);
if (!m_previewCompName.isEmpty() && m_previewOptions == m_importOptions) {
const ItemLibraryAssetImporter::PreviewData &data
= m_previewData.value(ui->importList->currentIndex().data().toString());
if (!data.name.isEmpty() && !optionsChanged()) {
cleanupPreviewPuppet();
m_importer.finalizeQuick3DImport();
return;
@@ -1046,8 +1093,13 @@ void ItemLibraryAssetImportDialog::onImport()
ui->progressBar->setValue(0);
if (!m_quick3DFiles.isEmpty()) {
if (!m_previewCompName.isEmpty()) {
m_importer.reImportQuick3D(m_previewCompName, m_importOptions);
if (!m_previewData.isEmpty()) {
QHash<QString , QJsonObject> importOptions;
for (const ItemLibraryAssetImporter::PreviewData &data : std::as_const(m_previewData)) {
if (data.renderedOptions != data.currentOptions)
importOptions.insert(data.name, data.currentOptions);
}
m_importer.reImportQuick3D(importOptions);
} else {
m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
m_importOptions, m_extToImportOptionsMap,
@@ -1066,19 +1118,50 @@ void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &t
ui->progressBar->setValue(value);
}
void ItemLibraryAssetImportDialog::onImportReadyForPreview(const QString &path, const QString &compName)
void ItemLibraryAssetImportDialog::onImportReadyForPreview(
const QString &path, const QList<ItemLibraryAssetImporter::PreviewData> &previewData)
{
addInfo(tr("Import is ready for preview."));
if (m_previewCompName.isEmpty())
addInfo(tr("Click \"Accept\" to finish the import or adjust options and click \"Import\" to import again."));
QStringList assetNames;
for (const ItemLibraryAssetImporter::PreviewData &data : previewData) {
m_previewData[data.name] = data;
assetNames.append(data.name);
m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
m_previewCompName = compName;
m_previewOptions = m_importOptions;
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
auto items = ui->importList->findItems(data.name, Qt::MatchExactly);
if (items.isEmpty())
ui->importList->addItem(data.name);
addInfo(tr("Import ready for preview: %1").arg(data.name));
}
if (m_firstImport) {
addInfo(tr("Click \"Accept\" to finish the import or adjust options and click \"Import\" to import again."));
m_firstImport = false;
}
if (m_previewFile.isEmpty()) {
m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
}
QTimer::singleShot(0, this, [this, assetNames]() {
if (!m_nodeInstanceView)
return;
for (const QString &assetName : std::as_const(assetNames)) {
const ItemLibraryAssetImporter::PreviewData &data = m_previewData.value(assetName);
if (!data.name.isEmpty()) {
QVariantHash msgData;
msgData.insert("name", data.name);
msgData.insert("folder", data.folderName);
m_nodeInstanceView->view3DAction(View3DActionType::Import3dAddPreviewModel, msgData);
}
}
});
ui->importButton->setEnabled(true);
updateImportButtonState();
ui->tabWidget->setEnabled(true);
updatePreviewOptions();
if (ui->importList->currentRow() < 0)
ui->importList->setCurrentRow(0);
}
void ItemLibraryAssetImportDialog::onRequestImageUpdate()
@@ -1119,6 +1202,27 @@ void ItemLibraryAssetImportDialog::onImportFinished()
}
}
void ItemLibraryAssetImportDialog::onCurrentRowChanged(int)
{
QTimer::singleShot(0, this, [this]() {
if (!m_nodeInstanceView)
return;
int row = ui->importList->currentRow();
QString compName;
if (row >= 0)
compName = ui->importList->item(row)->text();
m_nodeInstanceView->view3DAction(View3DActionType::Import3dSetCurrentPreviewModel, compName);
resetOptionControls();
if (m_previewData.contains(compName)) {
const ItemLibraryAssetImporter::PreviewData data = m_previewData[compName];
for (int i = 0; i < ui->tabWidget->count(); ++i)
ui->tabWidget->widget(i)->setVisible(i == data.optionsIndex);
ui->tabWidget->setCurrentIndex(data.optionsIndex);
}
});
}
void ItemLibraryAssetImportDialog::onClose()
{
ui->importButton->setEnabled(false);

View File

@@ -63,15 +63,17 @@ private slots:
private:
void setCloseButtonState(bool importing);
void updateImportButtonState();
void updatePreviewOptions();
void onImport();
void setImportProgress(int value, const QString &text);
void onImportReadyForPreview(const QString &path, const QString &compName);
void onImportReadyForPreview(const QString &path,
const QList<ItemLibraryAssetImporter::PreviewData> &previewData);
void onRequestImageUpdate();
void onRequestRotation(const QPointF &delta);
void onImportNearlyFinished();
void onImportFinished();
void onCurrentRowChanged(int row);
void onClose();
void doClose();
void toggleAdvanced();
@@ -84,10 +86,12 @@ private:
bool isSimpleGroup(const QString &id);
bool isSimpleOption(const QString &id);
bool isHiddenOption(const QString &id);
bool optionsChanged();
void startPreview();
void cleanupPreviewPuppet();
Import3dCanvas *canvas();
void resetOptionControls();
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
Utils::OutputFormatter *m_outputFormatter = nullptr;
@@ -96,8 +100,9 @@ private:
QPointer<RewriterView> m_rewriterView;
QPointer<AbstractView> m_view;
ModelPointer m_model;
QMap<QString, ItemLibraryAssetImporter::PreviewData> m_previewData;
Utils::FilePath m_previewFile;
QString m_previewCompName;
struct OptionsData
{
@@ -110,7 +115,6 @@ private:
QString m_quick3DImportPath;
ItemLibraryAssetImporter m_importer;
QVector<QJsonObject> m_importOptions;
QVector<QJsonObject> m_previewOptions;
QHash<QString, int> m_extToImportOptionsMap;
QSet<QString> m_preselectedFilesForOverwrite;
bool m_closeOnFinish = true;
@@ -120,5 +124,7 @@ private:
bool m_advancedMode = false;
int m_dialogHeight = 350;
bool m_explicitClose = false;
bool m_updatingControlStates = true;
bool m_firstImport = true;
};
}

View File

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>1100</width>
<width>1280</width>
<height>350</height>
</rect>
</property>
@@ -14,6 +14,42 @@
<string>Asset Import</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="listLabel">
<property name="text">
<string>Imported objects</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="importList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>

View File

@@ -91,50 +91,60 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
}
}
void ItemLibraryAssetImporter::reImportQuick3D(const QString &assetName,
const QVector<QJsonObject> &options)
void ItemLibraryAssetImporter::reImportQuick3D(const QHash<QString, QJsonObject> &importOptions)
{
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;
int importId = 1;
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);
if (importOptions.isEmpty()) {
addError(tr("Attempted to reimport no assets."));
cancelImport();
return;
}
const QStringList keys = importOptions.keys();
for (const QString &key : keys) {
if (!key.isEmpty() && !m_parseData.contains(key)) {
addError(tr("Attempted to reimport non-existing asset: %1").arg(key));
cancelImport();
return;
}
ParseData &pd = m_parseData[key];
// 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)));
cancelImport();
return;
}
if (oldDir.absolutePath().contains(tempDirNameBase()))
oldDir.removeRecursively();
for (ParseData &pd : m_parseData)
pd.importId = -1;
pd.options = importOptions[key];
pd.importId = importId++;
m_importFiles.remove(key);
m_importIdToAssetNameMap[pd.importId] = key;
m_puppetQueue.append(pd.importId);
}
startNextImportProcess();
}
@@ -386,10 +396,11 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
qmlInfo.append(".");
qmlInfo.append(pd.assetName);
qmlInfo.append('\n');
m_requiredImports.append(
QStringLiteral("%1.%2").arg(QmlDesignerPlugin::instance()->documentManager()
.generatedComponentUtils().import3dTypePrefix(),
pd.assetName));
const QString reqImp = QStringLiteral("%1.%2").arg(
QmlDesignerPlugin::instance()->documentManager()
.generatedComponentUtils().import3dTypePrefix(), pd.assetName);
if (!m_requiredImports.contains(reqImp))
m_requiredImports.append(reqImp);
while (qmlIt.hasNext()) {
qmlIt.next();
QFileInfo fi = QFileInfo(qmlIt.filePath());
@@ -633,14 +644,18 @@ void ItemLibraryAssetImporter::postImport()
}
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);
QList<PreviewData> dataList;
for (const QString &assetName : std::as_const(m_importIdToAssetNameMap)) {
const ParseData &pd = m_parseData[assetName];
PreviewData data;
data.name = pd.assetName;
data.folderName = pd.outDir.dirName();
data.renderedOptions = pd.options;
data.currentOptions = pd.options;
data.optionsIndex = pd.optionsIndex;
dataList.append(data);
}
emit importReadyForPreview(m_tempDir->path(), dataList);
}
}

View File

@@ -33,7 +33,7 @@ public:
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &preselectedFilesForOverwrite);
void reImportQuick3D(const QString &assetName, const QVector<QJsonObject> &options);
void reImportQuick3D(const QHash<QString, QJsonObject> &importOptions);
bool isImporting() const;
void cancelImport();
@@ -48,12 +48,21 @@ public:
void finalizeQuick3DImport();
struct PreviewData
{
int optionsIndex = 0;
QJsonObject renderedOptions;
QJsonObject currentOptions;
QString name;
QString folderName;
};
signals:
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 importReadyForPreview(const QString &path, const QList<PreviewData> &previewData);
void importNearlyFinished();
void importFinished();

View File

@@ -17,9 +17,12 @@
#include <QQmlProperty>
#include <private/qquickdesignersupport_p.h>
#ifdef QUICK3D_MODULE
#include <private/qquick3dnode_p.h>
#include <private/qquick3dviewport_p.h>
#include <private/qquickdesignersupport_p.h>
#endif
namespace QmlDesigner {
@@ -48,11 +51,24 @@ void Qt5Import3dNodeInstanceServer::createScene(const CreateSceneCommand &comman
registerFonts(command.resourceUrl);
setTranslationLanguage(command.language);
setupScene(command);
#ifdef QUICK3D_MODULE
QObject *obj = rootItem();
QQmlProperty viewProp(obj, "view3d", context());
QObject *viewObj = viewProp.read().value<QObject *>();
m_view3D = qobject_cast<QQuick3DViewport *>(viewObj);
if (m_view3D) {
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
m_sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
}
#endif
startRenderTimer();
}
void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DActionCommand &command)
{
#ifdef QUICK3D_MODULE
switch (command.type()) {
case View3DActionType::Import3dUpdatePreviewImage: {
QObject *obj = rootItem();
@@ -63,7 +79,6 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
wProp.write(size.width());
hProp.write(size.height());
resizeCanvasToRootItem();
startRenderTimer();
}
break;
@@ -72,18 +87,72 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
QObject *obj = rootItem();
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
if (sceneNode) {
if (sceneNode && m_previewData.contains(m_currentNode)) {
const PreviewData &data = m_previewData[m_currentNode];
QPointF delta = command.value().toPointF();
m_generalHelper->orbitCamera(m_view3D->camera(), m_view3D->camera()->eulerRotation(),
m_lookAt, {}, {float(delta.x()), float(delta.y()), 0.f});
data.lookAt, {}, {float(delta.x()), float(delta.y()), 0.f});
m_keepRendering = true;
startRenderTimer();
}
break;
}
case View3DActionType::Import3dAddPreviewModel: {
const QVariantHash cmd = command.value().toHash();
const QString name = cmd["name"].toString();
const QString folder = cmd["folder"].toString();
if (m_previewData.contains(name)) {
QQuick3DNode *node = m_previewData[name].node;
if (node) {
node->setParentItem({});
node->setParent({});
node->deleteLater();
}
}
PreviewData &data = m_previewData[name];
data.name = name;
data.lookAt = {};
QFileInfo fi(fileUrl().toLocalFile());
QString compPath = fi.absolutePath() + '/' + folder + '/' + name + ".qml";
QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous);
data.node = qobject_cast<QQuick3DNode *>(comp.create(context()));
if (data.node) {
engine()->setObjectOwnership(data.node, QJSEngine::CppOwnership);
data.node->setParentItem(m_sceneNode);
data.node->setParent(m_sceneNode);
}
if (m_currentNode == data.name) {
m_renderCount = 0;
startRenderTimer();
} else if (data.node) {
data.node->setVisible(false);
}
break;
}
case View3DActionType::Import3dSetCurrentPreviewModel: {
QString newName = command.value().toString();
if (m_previewData.contains(newName) && m_currentNode != newName) {
const PreviewData &newData = m_previewData[newName];
const PreviewData oldData = m_previewData.value(m_currentNode);
if (oldData.node)
oldData.node->setVisible(false);
if (newData.node)
newData.node->setVisible(true);
m_renderCount = 0;
m_currentNode = newName;
startRenderTimer();
}
break;
}
default:
break;
}
#endif
}
void Qt5Import3dNodeInstanceServer::startRenderTimer()
@@ -97,16 +166,13 @@ void Qt5Import3dNodeInstanceServer::startRenderTimer()
void Qt5Import3dNodeInstanceServer::cleanup()
{
#ifdef QUICK3D_MODULE
delete m_previewNode;
for (const PreviewData &data : std::as_const(m_previewData))
delete data.node;
m_previewData.clear();
delete m_generalHelper;
#endif
}
void Qt5Import3dNodeInstanceServer::finish()
{
cleanup();
}
void Qt5Import3dNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{
static bool inFunction = false;
@@ -130,53 +196,32 @@ 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());
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
if (sceneNode) {
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->setParentItem(sceneNode);
m_previewNode->setParent(sceneNode);
}
}
}
}
// Render scene at least once before calculating bounds to ensure geometries are intialized
if (m_renderCount == 2 && m_view3D && m_previewData.contains(m_currentNode)) {
PreviewData &data = m_previewData[m_currentNode];
m_generalHelper->calculateBoundsAndFocusCamera(m_view3D->camera(), data.node,
m_view3D, 1050, false, data.lookAt,
data.extents);
// Render scene once to ensure geometries are intialized so bounds calculations work correctly
if (m_renderCount == 2 && m_view3D) {
QVector3D extents;
m_generalHelper->calculateBoundsAndFocusCamera(m_view3D->camera(), m_previewNode,
m_view3D, 1050, false, m_lookAt, extents);
auto getExtentStr = [&extents](int idx) -> QString {
auto getExtentStr = [&data](int idx) -> QString {
int prec = 0;
float val = extents[idx];
float val = data.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);
QString checkStr = QString::number(data.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);
QString retval = QLocale().toString(data.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))

View File

@@ -3,12 +3,14 @@
#pragma once
#include "generalhelper.h"
#include "qt5nodeinstanceserver.h"
#ifdef QUICK3D_MODULE
#include "generalhelper.h"
QT_BEGIN_NAMESPACE
class QQuick3DNode;
QT_END_NAMESPACE
#endif
namespace QmlDesigner {
@@ -31,7 +33,6 @@ protected:
void startRenderTimer() override;
private:
void finish();
void cleanup();
int m_renderCount = 0;
@@ -40,8 +41,17 @@ private:
#ifdef QUICK3D_MODULE
QQuick3DViewport *m_view3D = nullptr;
Internal::GeneralHelper *m_generalHelper = nullptr;
QQuick3DNode *m_previewNode = nullptr;
QVector3D m_lookAt;
struct PreviewData
{
QString name;
QVector3D lookAt;
QVector3D extents;
QQuick3DNode *node = {};
};
QHash<QString, PreviewData> m_previewData;
QString m_currentNode;
QQuick3DNode *m_sceneNode = {};
#endif
};