forked from qt-creator/qt-creator
QmlDesigner: Allow rotation of 3D import preview
3D import preview can now be rotated using left mouse button and dragging the preview image. This causes camera to orbit around the previewed model, similar to rotation to 3D edit view orbit camera. Close/Cancel button logic was also improved. Fixes: QDS-12795 Change-Id: I0c7d1ad28f8fe779b9bedc4bf76be704078d91a6 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -56,7 +56,8 @@ enum class View3DActionType {
|
|||||||
EditCameraMove,
|
EditCameraMove,
|
||||||
EditCameraStopAllMoves,
|
EditCameraStopAllMoves,
|
||||||
SetLastSceneEnvData,
|
SetLastSceneEnvData,
|
||||||
Import3dUpdatePreviewImage
|
Import3dUpdatePreviewImage,
|
||||||
|
Import3dRotatePreviewModel
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr bool isNanotraceEnabled()
|
constexpr bool isNanotraceEnabled()
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QLinearGradient>
|
#include <QLinearGradient>
|
||||||
|
#include <QMouseEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
@@ -52,5 +53,30 @@ void Import3dCanvas::resizeEvent(QResizeEvent *)
|
|||||||
emit requestImageUpdate();
|
emit requestImageUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Import3dCanvas::mousePressEvent(QMouseEvent *e)
|
||||||
|
{
|
||||||
|
if (e->buttons() == Qt::LeftButton)
|
||||||
|
m_dragPos = e->position();
|
||||||
|
else
|
||||||
|
m_dragPos = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import3dCanvas::mouseReleaseEvent(QMouseEvent *)
|
||||||
|
{
|
||||||
|
m_dragPos = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Import3dCanvas::mouseMoveEvent(QMouseEvent *e)
|
||||||
|
{
|
||||||
|
if (m_dragPos.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QPointF curPos = e->position();
|
||||||
|
const QPointF delta = curPos - m_dragPos;
|
||||||
|
|
||||||
|
m_dragPos = curPos;
|
||||||
|
|
||||||
|
emit requestRotation(delta);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QPointer>
|
#include <QPointF>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
@@ -20,13 +20,18 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestImageUpdate();
|
void requestImageUpdate();
|
||||||
|
void requestRotation(const QPointF &delta);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QImage m_image;
|
QImage m_image;
|
||||||
|
QPointF m_dragPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -221,6 +221,8 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
|
|||||||
this, &ItemLibraryAssetImportDialog::updateUi);
|
this, &ItemLibraryAssetImportDialog::updateUi);
|
||||||
connect(canvas(), &Import3dCanvas::requestImageUpdate,
|
connect(canvas(), &Import3dCanvas::requestImageUpdate,
|
||||||
this, &ItemLibraryAssetImportDialog::onRequestImageUpdate);
|
this, &ItemLibraryAssetImportDialog::onRequestImageUpdate);
|
||||||
|
connect(canvas(), &Import3dCanvas::requestRotation,
|
||||||
|
this, &ItemLibraryAssetImportDialog::onRequestRotation);
|
||||||
|
|
||||||
connect(&m_importer, &ItemLibraryAssetImporter::errorReported,
|
connect(&m_importer, &ItemLibraryAssetImporter::errorReported,
|
||||||
this, &ItemLibraryAssetImportDialog::addError);
|
this, &ItemLibraryAssetImportDialog::addError);
|
||||||
@@ -856,9 +858,10 @@ Rectangle {
|
|||||||
width: %1
|
width: %1
|
||||||
height: %2
|
height: %2
|
||||||
|
|
||||||
property string sceneModelName: "%3"
|
property alias sceneNode: sceneNode
|
||||||
property alias view3d: view3d
|
property alias view3d: view3d
|
||||||
property string extents
|
property string extents
|
||||||
|
property string sceneModelName: "%3"
|
||||||
|
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
GradientStop { position: 1.0; color: "#222222" }
|
GradientStop { position: 1.0; color: "#222222" }
|
||||||
@@ -877,9 +880,9 @@ Rectangle {
|
|||||||
|
|
||||||
PerspectiveCamera {
|
PerspectiveCamera {
|
||||||
id: viewCamera
|
id: viewCamera
|
||||||
z: 600
|
|
||||||
y: 600
|
|
||||||
x: 600
|
x: 600
|
||||||
|
y: 600
|
||||||
|
z: 600
|
||||||
eulerRotation.x: -45
|
eulerRotation.x: -45
|
||||||
eulerRotation.y: -45
|
eulerRotation.y: -45
|
||||||
clipFar: 100000
|
clipFar: 100000
|
||||||
@@ -889,6 +892,10 @@ Rectangle {
|
|||||||
DirectionalLight {
|
DirectionalLight {
|
||||||
rotation: viewCamera.rotation
|
rotation: viewCamera.rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node {
|
||||||
|
id: sceneNode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
@@ -1041,7 +1048,8 @@ void ItemLibraryAssetImportDialog::onImportReadyForPreview(const QString &path,
|
|||||||
ui->acceptButton->setEnabled(true);
|
ui->acceptButton->setEnabled(true);
|
||||||
ui->importButton->setEnabled(true);
|
ui->importButton->setEnabled(true);
|
||||||
|
|
||||||
addInfo(tr("Generating import preview for %1.").arg(compName));
|
addInfo(tr("Import is ready for preview."));
|
||||||
|
addInfo(tr("Click \"Accept\" to finish the import or adjust options an click \"Import\" to import again."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::onRequestImageUpdate()
|
void ItemLibraryAssetImportDialog::onRequestImageUpdate()
|
||||||
@@ -1050,6 +1058,12 @@ void ItemLibraryAssetImportDialog::onRequestImageUpdate()
|
|||||||
m_nodeInstanceView->view3DAction(View3DActionType::Import3dUpdatePreviewImage, canvas()->size());
|
m_nodeInstanceView->view3DAction(View3DActionType::Import3dUpdatePreviewImage, canvas()->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemLibraryAssetImportDialog::onRequestRotation(const QPointF &delta)
|
||||||
|
{
|
||||||
|
if (m_nodeInstanceView)
|
||||||
|
m_nodeInstanceView->view3DAction(View3DActionType::Import3dRotatePreviewModel, delta);
|
||||||
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::onImportNearlyFinished()
|
void ItemLibraryAssetImportDialog::onImportNearlyFinished()
|
||||||
{
|
{
|
||||||
// Canceling import is no longer doable
|
// Canceling import is no longer doable
|
||||||
@@ -1063,18 +1077,28 @@ void ItemLibraryAssetImportDialog::onImportFinished()
|
|||||||
QString interruptStr = tr("Import interrupted.");
|
QString interruptStr = tr("Import interrupted.");
|
||||||
addError(interruptStr);
|
addError(interruptStr);
|
||||||
setImportProgress(0, interruptStr);
|
setImportProgress(0, interruptStr);
|
||||||
|
if (m_explicitClose)
|
||||||
|
QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::doClose);
|
||||||
} else {
|
} else {
|
||||||
QString doneStr = tr("Import done.");
|
QString doneStr = tr("Import done.");
|
||||||
addInfo(doneStr);
|
addInfo(doneStr);
|
||||||
setImportProgress(100, doneStr);
|
setImportProgress(100, doneStr);
|
||||||
if (m_closeOnFinish) {
|
if (m_closeOnFinish) {
|
||||||
// Add small delay to allow user to visually confirm import finishing
|
// Add small delay to allow user to visually confirm import finishing
|
||||||
QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::onClose);
|
QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::doClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::onClose()
|
void ItemLibraryAssetImportDialog::onClose()
|
||||||
|
{
|
||||||
|
ui->importButton->setEnabled(false);
|
||||||
|
ui->acceptButton->setEnabled(false);
|
||||||
|
m_explicitClose = true;
|
||||||
|
doClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemLibraryAssetImportDialog::doClose()
|
||||||
{
|
{
|
||||||
if (m_importer.isImporting()) {
|
if (m_importer.isImporting()) {
|
||||||
addInfo(tr("Canceling import."));
|
addInfo(tr("Canceling import."));
|
||||||
|
@@ -68,9 +68,11 @@ private:
|
|||||||
void setImportProgress(int value, const QString &text);
|
void setImportProgress(int value, const QString &text);
|
||||||
void onImportReadyForPreview(const QString &path, const QString &compName);
|
void onImportReadyForPreview(const QString &path, const QString &compName);
|
||||||
void onRequestImageUpdate();
|
void onRequestImageUpdate();
|
||||||
|
void onRequestRotation(const QPointF &delta);
|
||||||
void onImportNearlyFinished();
|
void onImportNearlyFinished();
|
||||||
void onImportFinished();
|
void onImportFinished();
|
||||||
void onClose();
|
void onClose();
|
||||||
|
void doClose();
|
||||||
void onAccept();
|
void onAccept();
|
||||||
void toggleAdvanced();
|
void toggleAdvanced();
|
||||||
|
|
||||||
@@ -116,5 +118,6 @@ private:
|
|||||||
OptionsData m_advancedData;
|
OptionsData m_advancedData;
|
||||||
bool m_advancedMode = false;
|
bool m_advancedMode = false;
|
||||||
int m_dialogHeight = 350;
|
int m_dialogHeight = 350;
|
||||||
|
bool m_explicitClose = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -462,17 +462,19 @@ QVector4D GeneralHelper::approachNode(
|
|||||||
// a selection box for bound calculations to work. This is used to focus the view for
|
// 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
|
// various preview image generations, where doing things asynchronously is not good
|
||||||
// and recalculating bounds for every frame is not a problem.
|
// and recalculating bounds for every frame is not a problem.
|
||||||
QVector3D GeneralHelper::calculateNodeBoundsAndFocusCamera(
|
void GeneralHelper::calculateBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node,
|
||||||
QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort,
|
QQuick3DViewport *viewPort,
|
||||||
float defaultLookAtDistance, bool closeUp)
|
float defaultLookAtDistance,
|
||||||
|
bool closeUp, QVector3D &lookAt,
|
||||||
|
QVector3D &extents)
|
||||||
{
|
{
|
||||||
QVector3D minBounds;
|
QVector3D minBounds;
|
||||||
QVector3D maxBounds;
|
QVector3D maxBounds;
|
||||||
|
|
||||||
getBounds(viewPort, node, minBounds, maxBounds);
|
getBounds(viewPort, node, minBounds, maxBounds);
|
||||||
|
|
||||||
QVector3D extents = maxBounds - minBounds;
|
extents = maxBounds - minBounds;
|
||||||
QVector3D lookAt = minBounds + (extents / 2.f);
|
lookAt = minBounds + (extents / 2.f);
|
||||||
float maxExtent = qSqrt(qreal(extents.x()) * qreal(extents.x())
|
float maxExtent = qSqrt(qreal(extents.x()) * qreal(extents.x())
|
||||||
+ qreal(extents.y()) * qreal(extents.y())
|
+ qreal(extents.y()) * qreal(extents.y())
|
||||||
+ qreal(extents.z()) * qreal(extents.z()));
|
+ qreal(extents.z()) * qreal(extents.z()));
|
||||||
@@ -506,8 +508,17 @@ QVector3D GeneralHelper::calculateNodeBoundsAndFocusCamera(
|
|||||||
perspectiveCamera->setClipFar(maxDist * 1.01);
|
perspectiveCamera->setClipFar(maxDist * 1.01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return extents;
|
void GeneralHelper::calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node,
|
||||||
|
QQuick3DViewport *viewPort,
|
||||||
|
float defaultLookAtDistance,
|
||||||
|
bool closeUp)
|
||||||
|
{
|
||||||
|
QVector3D extents;
|
||||||
|
QVector3D lookAt;
|
||||||
|
calculateBoundsAndFocusCamera(camera, node, viewPort, defaultLookAtDistance, closeUp,
|
||||||
|
lookAt, extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aligns any cameras found in nodes list to a camera.
|
// Aligns any cameras found in nodes list to a camera.
|
||||||
|
@@ -72,11 +72,12 @@ public:
|
|||||||
bool closeUp = false);
|
bool closeUp = false);
|
||||||
Q_INVOKABLE QVector4D approachNode(QQuick3DCamera *camera, float defaultLookAtDistance,
|
Q_INVOKABLE QVector4D approachNode(QQuick3DCamera *camera, float defaultLookAtDistance,
|
||||||
QObject *node, QQuick3DViewport *viewPort);
|
QObject *node, QQuick3DViewport *viewPort);
|
||||||
Q_INVOKABLE QVector3D calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera,
|
void calculateBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node,
|
||||||
QQuick3DNode *node,
|
QQuick3DViewport *viewPort, float defaultLookAtDistance,
|
||||||
QQuick3DViewport *viewPort,
|
bool closeUp, QVector3D &lookAt, QVector3D &extents);
|
||||||
float defaultLookAtDistance,
|
Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node,
|
||||||
bool closeUp);
|
QQuick3DViewport *viewPort,
|
||||||
|
float defaultLookAtDistance, bool closeUp);
|
||||||
Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes);
|
Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes);
|
||||||
Q_INVOKABLE QVector4D alignView(QQuick3DCamera *camera, const QVariant &nodes,
|
Q_INVOKABLE QVector4D alignView(QQuick3DCamera *camera, const QVariant &nodes,
|
||||||
const QVector3D &lookAtPoint, float defaultLookAtDistance);
|
const QVector3D &lookAtPoint, float defaultLookAtDistance);
|
||||||
|
@@ -258,6 +258,7 @@ protected:
|
|||||||
void setRenderTimerInterval(int timerInterval);
|
void setRenderTimerInterval(int timerInterval);
|
||||||
int renderTimerInterval() const;
|
int renderTimerInterval() const;
|
||||||
void setSlowRenderTimerInterval(int timerInterval);
|
void setSlowRenderTimerInterval(int timerInterval);
|
||||||
|
TimerMode timerMode() const { return m_timerMode; }
|
||||||
|
|
||||||
virtual void initializeView() = 0;
|
virtual void initializeView() = 0;
|
||||||
virtual void initializeAuxiliaryViews();
|
virtual void initializeAuxiliaryViews();
|
||||||
|
@@ -68,6 +68,19 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case View3DActionType::Import3dRotatePreviewModel: {
|
||||||
|
QObject *obj = rootItem();
|
||||||
|
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
|
||||||
|
auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
|
||||||
|
if (sceneNode) {
|
||||||
|
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});
|
||||||
|
m_keepRendering = true;
|
||||||
|
startRenderTimer();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -75,12 +88,10 @@ void Qt5Import3dNodeInstanceServer::view3DAction([[maybe_unused]] const View3DAc
|
|||||||
|
|
||||||
void Qt5Import3dNodeInstanceServer::startRenderTimer()
|
void Qt5Import3dNodeInstanceServer::startRenderTimer()
|
||||||
{
|
{
|
||||||
if (timerId() != 0)
|
if (m_keepRendering && timerMode() == TimerMode::NormalTimer)
|
||||||
killTimer(timerId());
|
return;
|
||||||
|
|
||||||
int timerId = startTimer(renderTimerInterval());
|
NodeInstanceServer::startRenderTimer();
|
||||||
|
|
||||||
setTimerId(timerId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5Import3dNodeInstanceServer::cleanup()
|
void Qt5Import3dNodeInstanceServer::cleanup()
|
||||||
@@ -126,24 +137,28 @@ void Qt5Import3dNodeInstanceServer::render()
|
|||||||
m_view3D = qobject_cast<QQuick3DViewport *>(viewObj);
|
m_view3D = qobject_cast<QQuick3DViewport *>(viewObj);
|
||||||
if (m_view3D) {
|
if (m_view3D) {
|
||||||
QQmlProperty sceneModelNameProp(obj, "sceneModelName", context());
|
QQmlProperty sceneModelNameProp(obj, "sceneModelName", context());
|
||||||
QString sceneModelName = sceneModelNameProp.read().toString();
|
QQmlProperty sceneNodeProp(obj, "sceneNode", context());
|
||||||
QFileInfo fi(fileUrl().toLocalFile());
|
auto sceneNode = sceneNodeProp.read().value<QQuick3DNode *>();
|
||||||
QString compPath = fi.absolutePath() + '/' + sceneModelName + ".qml";
|
if (sceneNode) {
|
||||||
QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous);
|
QString sceneModelName = sceneModelNameProp.read().toString();
|
||||||
m_previewNode = qobject_cast<QQuick3DNode *>(comp.create(context()));
|
QFileInfo fi(fileUrl().toLocalFile());
|
||||||
if (m_previewNode) {
|
QString compPath = fi.absolutePath() + '/' + sceneModelName + ".qml";
|
||||||
engine()->setObjectOwnership(m_previewNode, QJSEngine::CppOwnership);
|
QQmlComponent comp(engine(), compPath, QQmlComponent::PreferSynchronous);
|
||||||
m_previewNode->setParent(m_view3D);
|
m_previewNode = qobject_cast<QQuick3DNode *>(comp.create(context()));
|
||||||
m_view3D->setImportScene(m_previewNode);
|
if (m_previewNode) {
|
||||||
|
engine()->setObjectOwnership(m_previewNode, QJSEngine::CppOwnership);
|
||||||
|
m_previewNode->setParentItem(sceneNode);
|
||||||
|
m_previewNode->setParent(sceneNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render scene once to ensure geometries are intialized so bounds calculations work correctly
|
// Render scene once to ensure geometries are intialized so bounds calculations work correctly
|
||||||
if (m_renderCount == 2 && m_view3D) {
|
if (m_renderCount == 2 && m_view3D) {
|
||||||
QVector3D extents =
|
QVector3D extents;
|
||||||
m_generalHelper->calculateNodeBoundsAndFocusCamera(m_view3D->camera(), m_previewNode,
|
m_generalHelper->calculateBoundsAndFocusCamera(m_view3D->camera(), m_previewNode,
|
||||||
m_view3D, 1040, false);
|
m_view3D, 1050, false, m_lookAt, extents);
|
||||||
auto getExtentStr = [&extents](int idx) -> QString {
|
auto getExtentStr = [&extents](int idx) -> QString {
|
||||||
int prec = 0;
|
int prec = 0;
|
||||||
float val = extents[idx];
|
float val = extents[idx];
|
||||||
@@ -176,7 +191,11 @@ void Qt5Import3dNodeInstanceServer::render()
|
|||||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||||
{PuppetToCreatorCommand::Import3DPreviewImage,
|
{PuppetToCreatorCommand::Import3DPreviewImage,
|
||||||
QVariant::fromValue(imgContainer)});
|
QVariant::fromValue(imgContainer)});
|
||||||
slowDownRenderTimer(); // No more renders needed for now
|
|
||||||
|
if (!m_keepRendering)
|
||||||
|
slowDownRenderTimer();
|
||||||
|
|
||||||
|
m_keepRendering = false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
slowDownRenderTimer();
|
slowDownRenderTimer();
|
||||||
|
@@ -35,11 +35,13 @@ private:
|
|||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
int m_renderCount = 0;
|
int m_renderCount = 0;
|
||||||
|
bool m_keepRendering = false;
|
||||||
|
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
QQuick3DViewport *m_view3D = nullptr;
|
QQuick3DViewport *m_view3D = nullptr;
|
||||||
Internal::GeneralHelper *m_generalHelper = nullptr;
|
Internal::GeneralHelper *m_generalHelper = nullptr;
|
||||||
QQuick3DNode *m_previewNode = nullptr;
|
QQuick3DNode *m_previewNode = nullptr;
|
||||||
|
QVector3D m_lookAt;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user