From 0b510f173eccc5ca07b2c9fbb587107cc6aacb3f Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 19 Nov 2019 17:43:03 +0200 Subject: [PATCH] QmlDesigner: Implement selection box to 3D edit view Change-Id: Ib0b13ecd7946e3b7da8ed06d4f5965e06e51a152 Fixes: QDS-1210 Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../qml/qmlpuppet/mockfiles/EditView3D.qml | 5 + .../qml/qmlpuppet/mockfiles/IconGizmo.qml | 2 +- .../qml/qmlpuppet/mockfiles/LightGizmo.qml | 14 +- .../qml/qmlpuppet/mockfiles/SelectionBox.qml | 65 ++++++ .../qml2puppet/editor3d/editor3d.pri | 6 +- .../editor3d/selectionboxgeometry.cpp | 216 ++++++++++++++++++ .../editor3d/selectionboxgeometry.h | 79 +++++++ .../qt5informationnodeinstanceserver.cpp | 2 + share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc | 1 + src/tools/qml2puppet/CMakeLists.txt | 1 + src/tools/qml2puppet/qml2puppet.qbs | 2 + 11 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp create mode 100644 share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index da5a5a4950d..3ce3c5deabe 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -200,6 +200,11 @@ Window { step: 50 } + SelectionBox { + view3D: editView + targetNode: viewWindow.selectedNode + } + PointLight { id: editLight visible: showEditLight diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml index ea6c17a1c3e..ebc52a126aa 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml @@ -84,7 +84,7 @@ Node { anchors.fill: parent cached: true source: iconImage - color: transparent + color: "transparent" opacity: 0.6 } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml index de6deefb943..6e321f8398a 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml @@ -29,11 +29,13 @@ import QtQuick3D 1.0 IconGizmo { id: lightGizmo - iconSource: targetNode instanceof DirectionalLight - ? "qrc:///qtquickplugin/mockfiles/images/directional_light_gradient.png" - : targetNode instanceof AreaLight - ? "qrc:///qtquickplugin/mockfiles/images/area_light_gradient.png" - : "qrc:///qtquickplugin/mockfiles/images/point_light_gradient.png" + iconSource: targetNode + ? targetNode instanceof DirectionalLight + ? "qrc:///qtquickplugin/mockfiles/images/directional_light_gradient.png" + : targetNode instanceof AreaLight + ? "qrc:///qtquickplugin/mockfiles/images/area_light_gradient.png" + : "qrc:///qtquickplugin/mockfiles/images/point_light_gradient.png" + : "qrc:///qtquickplugin/mockfiles/images/point_light_gradient.png" - overlayColor: targetNode.color + overlayColor: targetNode ? targetNode.color : "transparent" } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml new file mode 100644 index 00000000000..6465cab2b78 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/SelectionBox.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 +import SelectionBoxGeometry 1.0 + +Node { + id: selectionBox + + property View3D view3D + property Node targetNode: null + + SelectionBoxGeometry { + id: selectionBoxGeometry + name: "Selection Box of 3D Edit View" + view3D: selectionBox.view3D + targetNode: selectionBox.targetNode + rootNode: selectionBox + } + + Model { + id: selectionBoxModel + geometry: selectionBoxGeometry + + scale: selectionBox.targetNode ? selectionBox.targetNode.scale : Qt.vector3d(1, 1, 1) + rotation: selectionBox.targetNode ? selectionBox.targetNode.rotation : Qt.vector3d(0, 0, 0) + position: selectionBox.targetNode ? selectionBox.targetNode.position : Qt.vector3d(0, 0, 0) + pivot: selectionBox.targetNode ? selectionBox.targetNode.pivot : Qt.vector3d(0, 0, 0) + orientation: selectionBox.targetNode ? selectionBox.targetNode.orientation : Node.LeftHanded + rotationOrder: selectionBox.targetNode ? selectionBox.targetNode.rotationOrder : Node.YXZ + + visible: selectionBox.targetNode && selectionBox.targetNode instanceof Model + + materials: [ + DefaultMaterial { + emissiveColor: "#e5009e" + lighting: DefaultMaterial.NoLighting + cullingMode: Material.DisableCulling + } + ] + } +} diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri index 60046015986..7b515e7a60c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/editor3d.pri @@ -1,9 +1,11 @@ HEADERS += $$PWD/generalhelper.h \ $$PWD/mousearea3d.h \ $$PWD/camerageometry.h \ - $$PWD/gridgeometry.h + $$PWD/gridgeometry.h \ + $$PWD/selectionboxgeometry.h SOURCES += $$PWD/generalhelper.cpp \ $$PWD/mousearea3d.cpp \ $$PWD/camerageometry.cpp \ - $$PWD/gridgeometry.cpp + $$PWD/gridgeometry.cpp \ + $$PWD/selectionboxgeometry.cpp diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp new file mode 100644 index 00000000000..452d924427e --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#ifdef QUICK3D_MODULE + +#include "selectionboxgeometry.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { +namespace Internal { + +SelectionBoxGeometry::SelectionBoxGeometry() + : QQuick3DGeometry() +{ +} + +SelectionBoxGeometry::~SelectionBoxGeometry() +{ +} + +QQuick3DNode *SelectionBoxGeometry::targetNode() const +{ + return m_targetNode; +} + +QQuick3DNode *SelectionBoxGeometry::rootNode() const +{ + return m_rootNode; +} + +QQuick3DViewport *SelectionBoxGeometry::view3D() const +{ + return m_view3D; +} + +void SelectionBoxGeometry::setTargetNode(QQuick3DNode *targetNode) +{ + if (m_targetNode == targetNode) + return; + + if (m_targetNode) + m_targetNode->disconnect(this); + m_targetNode = targetNode; + + if (auto model = qobject_cast(m_targetNode)) { + QObject::connect(model, &QQuick3DModel::sourceChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + QObject::connect(model, &QQuick3DModel::geometryChanged, + this, &SelectionBoxGeometry::update, Qt::QueuedConnection); + } + + emit targetNodeChanged(); + update(); +} + +void SelectionBoxGeometry::setRootNode(QQuick3DNode *rootNode) +{ + if (m_rootNode == rootNode) + return; + + m_rootNode = rootNode; + + emit rootNodeChanged(); + update(); +} + +void SelectionBoxGeometry::setView3D(QQuick3DViewport *view) +{ + if (m_view3D == view) + return; + + m_view3D = view; + + emit view3DChanged(); + update(); +} + +QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphObject *node) +{ + node = QQuick3DGeometry::updateSpatialNode(node); + QSSGRenderGeometry *geometry = static_cast(node); + + geometry->clear(); + + QByteArray vertexData; + QByteArray indexData; + + QVector3D minBounds(-100.f, -100.f, -100.f); + QVector3D maxBounds(100.f, 100.f, 100.f); + QVector3D extents; + + if (m_targetNode) { + auto rootPriv = QQuick3DObjectPrivate::get(m_rootNode); + auto targetPriv = QQuick3DObjectPrivate::get(m_targetNode); + auto rootRN = static_cast(rootPriv->spatialNode); + auto targetRN = static_cast(targetPriv->spatialNode); + if (rootRN && targetRN) { + // Explicitly set local transform of root node to target node parent's global transform + // to avoid having to reparent the selection box. This has to be done directly on render + // nodes. + targetRN->parent->calculateGlobalVariables(); + QMatrix4x4 m = targetRN->parent->globalTransform; + rootRN->localTransform = m; + rootRN->markDirty(QSSGRenderNode::TransformDirtyFlag::TransformNotDirty); + rootRN->calculateGlobalVariables(); + } + if (auto modelNode = qobject_cast(m_targetNode)) { + auto nodePriv = QQuick3DObjectPrivate::get(m_targetNode); + if (auto renderModel = static_cast(nodePriv->spatialNode)) { + QWindow *window = static_cast(m_view3D->window()); + if (window) { + auto context = QSSGRenderContextInterface::getRenderContextInterface( + quintptr(window)); + if (!context.isNull()) { + auto bufferManager = context->bufferManager(); + QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager); + QVector3D center = bounds.center(); + extents = bounds.extents(); + minBounds = center - extents; + maxBounds = center + extents; + } + } + } + } + } + + // Adjust bounds to reduce targetNode pixels obscuring the selection box + extents /= 1000.f; + minBounds -= extents; + maxBounds += extents; + + fillVertexData(vertexData, indexData, minBounds, maxBounds); + + geometry->addAttribute(QSSGRenderGeometry::Attribute::PositionSemantic, 0, + QSSGRenderGeometry::Attribute::ComponentType::F32Type); + geometry->addAttribute(QSSGRenderGeometry::Attribute::IndexSemantic, 0, + QSSGRenderGeometry::Attribute::ComponentType::U16Type); + geometry->setStride(12); + geometry->setVertexData(vertexData); + geometry->setIndexData(indexData); + geometry->setPrimitiveType(QSSGRenderGeometry::Lines); + geometry->setBounds(minBounds, maxBounds); + + return node; +} + +void SelectionBoxGeometry::fillVertexData(QByteArray &vertexData, QByteArray &indexData, + const QVector3D &minBounds, const QVector3D &maxBounds) +{ + const int vertexSize = int(sizeof(float)) * 8 * 3; // 8 vertices, 3 floats/vert + vertexData.resize(vertexSize); + const int indexSize = int(sizeof(quint16)) * 12 * 2; // 12 lines, 2 vert/line + indexData.resize(indexSize); + + auto dataPtr = reinterpret_cast(vertexData.data()); + auto indexPtr = reinterpret_cast(indexData.data()); + + *dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = maxBounds.z(); + *dataPtr++ = maxBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = maxBounds.y(); *dataPtr++ = minBounds.z(); + *dataPtr++ = minBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z(); + *dataPtr++ = maxBounds.x(); *dataPtr++ = minBounds.y(); *dataPtr++ = minBounds.z(); + + *indexPtr++ = 0; *indexPtr++ = 1; + *indexPtr++ = 1; *indexPtr++ = 2; + *indexPtr++ = 2; *indexPtr++ = 3; + *indexPtr++ = 3; *indexPtr++ = 0; + + *indexPtr++ = 0; *indexPtr++ = 4; + *indexPtr++ = 1; *indexPtr++ = 5; + *indexPtr++ = 2; *indexPtr++ = 6; + *indexPtr++ = 3; *indexPtr++ = 7; + + *indexPtr++ = 4; *indexPtr++ = 5; + *indexPtr++ = 5; *indexPtr++ = 6; + *indexPtr++ = 6; *indexPtr++ = 7; + *indexPtr++ = 7; *indexPtr++ = 4; +} + +} +} + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h new file mode 100644 index 00000000000..afe5efd8cf0 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/selectionboxgeometry.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#ifdef QUICK3D_MODULE + +#include +#include +#include + +namespace QmlDesigner { +namespace Internal { + +class SelectionBoxGeometry : public QQuick3DGeometry +{ + Q_OBJECT + Q_PROPERTY(QQuick3DNode *targetNode READ targetNode WRITE setTargetNode NOTIFY targetNodeChanged) + Q_PROPERTY(QQuick3DNode *rootNode READ rootNode WRITE setRootNode NOTIFY rootNodeChanged) + Q_PROPERTY(QQuick3DViewport *view3D READ view3D WRITE setView3D NOTIFY view3DChanged) + +public: + SelectionBoxGeometry(); + ~SelectionBoxGeometry() override; + + QQuick3DNode *targetNode() const; + QQuick3DNode *rootNode() const; + QQuick3DViewport *view3D() const; + +public Q_SLOTS: + void setTargetNode(QQuick3DNode *targetNode); + void setRootNode(QQuick3DNode *rootNode); + void setView3D(QQuick3DViewport *view); + +Q_SIGNALS: + void targetNodeChanged(); + void rootNodeChanged(); + void view3DChanged(); + +protected: + QSSGRenderGraphObject *updateSpatialNode(QSSGRenderGraphObject *node) override; + +private: + void fillVertexData(QByteArray &vertexData, QByteArray &indexData, + const QVector3D &minBounds, const QVector3D &maxBounds); + + QQuick3DNode *m_targetNode = nullptr; + QQuick3DViewport *m_view3D = nullptr; + QQuick3DNode *m_rootNode = nullptr; +}; + +} +} + +QML_DECLARE_TYPE(QmlDesigner::Internal::SelectionBoxGeometry) + +#endif // QUICK3D_MODULE diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 9aa90bfad0f..fabb2a67cc8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -66,6 +66,7 @@ #include "../editor3d/mousearea3d.h" #include "../editor3d/camerageometry.h" #include "../editor3d/gridgeometry.h" +#include "../editor3d/selectionboxgeometry.h" #include @@ -110,6 +111,7 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) qmlRegisterType("MouseArea3D", 1, 0, "MouseArea3D"); qmlRegisterType("CameraGeometry", 1, 0, "CameraGeometry"); qmlRegisterType("GridGeometry", 1, 0, "GridGeometry"); + qmlRegisterType("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry"); #endif QQmlComponent component(engine, QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml")); diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index fa07a2ff117..f27f93e0d45 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -26,6 +26,7 @@ mockfiles/ToolBarButton.qml mockfiles/RotateGizmo.qml mockfiles/RotateRing.qml + mockfiles/SelectionBox.qml mockfiles/meshes/arrow.mesh mockfiles/meshes/scalerod.mesh mockfiles/meshes/ring.mesh diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt index 2954059971c..1859bebe98f 100644 --- a/src/tools/qml2puppet/CMakeLists.txt +++ b/src/tools/qml2puppet/CMakeLists.txt @@ -112,6 +112,7 @@ extend_qtc_executable(qml2puppet mousearea3d.cpp mousearea3d.h camerageometry.cpp camerageometry.h gridgeometry.cpp gridgeometry.h + selectionboxgeometry.cpp selectionboxgeometry.h ) extend_qtc_executable(qml2puppet diff --git a/src/tools/qml2puppet/qml2puppet.qbs b/src/tools/qml2puppet/qml2puppet.qbs index 8e7ac853317..fe42083d6e2 100644 --- a/src/tools/qml2puppet/qml2puppet.qbs +++ b/src/tools/qml2puppet/qml2puppet.qbs @@ -205,6 +205,8 @@ QtcTool { "editor3d/camerageometry.h", "editor3d/gridgeometry.cpp", "editor3d/gridgeometry.h", + "editor3d/selectionboxgeometry.cpp", + "editor3d/selectionboxgeometry.h", "qml2puppetmain.cpp", ] }