forked from qt-creator/qt-creator
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:
@@ -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))
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user