summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJere Tuliniemi <jere.tuliniemi@qt.io>2019-02-07 15:40:47 +0200
committerJere Tuliniemi <jere.tuliniemi@qt.io>2019-02-13 09:16:07 +0000
commit0aa3c3a8cc47b4f2111085917cf61d90bafa332f (patch)
tree3204a86c966b41bb969d744c524534b1afc1656d
parentfd944d35bbfe866a779a590bd56f520b15ece15b (diff)
Port selection bounding boxes
Red bounding boxes are now drawn for selected objects. The model used for the bounding box is a temporary one causing unnecessary lines to be drawn. Bounding box calculation also can take time for models with large amount of vertices so that should be done before model selection in the future. Q3DSSelectionWidget name is used for the new widget handling the bounding boxes. The widget handling translation, scale and rotation is renamed Q3DSManipulationWidget. Task-number: QT3DS-3043 Change-Id: I243a22d5dc883c8719a66347173d54c75da267d5 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r--res/Selection.meshbin0 -> 892 bytes
-rw-r--r--src/Authoring/Studio/Qt3DStudio.pro6
-rw-r--r--src/Authoring/Studio/Render/Q3DSManipulationWidget.cpp363
-rw-r--r--src/Authoring/Studio/Render/Q3DSManipulationWidget.h87
-rw-r--r--src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp485
-rw-r--r--src/Authoring/Studio/Render/Q3DSSelectionWidget.h63
-rw-r--r--src/Authoring/Studio/Render/Q3DSTranslation.cpp100
-rw-r--r--src/Authoring/Studio/Render/Q3DSTranslation.h13
-rw-r--r--src/Authoring/Studio/Render/Q3DSVisualAidWidget.cpp21
-rw-r--r--src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp12
-rw-r--r--src/Authoring/Studio/Render/Q3DSWidgetUtils.h1
-rw-r--r--src/Authoring/Studio/Render/Q3DStudioRenderer.cpp4
-rw-r--r--src/Authoring/Studio/meshes.qrc1
13 files changed, 771 insertions, 385 deletions
diff --git a/res/Selection.mesh b/res/Selection.mesh
new file mode 100644
index 00000000..adbe1273
--- /dev/null
+++ b/res/Selection.mesh
Binary files differ
diff --git a/src/Authoring/Studio/Qt3DStudio.pro b/src/Authoring/Studio/Qt3DStudio.pro
index 8a25e039..28704bd3 100644
--- a/src/Authoring/Studio/Qt3DStudio.pro
+++ b/src/Authoring/Studio/Qt3DStudio.pro
@@ -268,7 +268,8 @@ HEADERS += \
Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.h \
Render/Q3DSSelectionWidget.h \
Render/Q3DSVisualAidWidget.h \
- Render/Q3DSWidgetUtils.h
+ Render/Q3DSWidgetUtils.h \
+ Render/Q3DSManipulationWidget.h
FORMS += \
MainFrm.ui \
@@ -440,7 +441,8 @@ SOURCES += \
Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.cpp \
Render/Q3DSSelectionWidget.cpp \
Render/Q3DSVisualAidWidget.cpp \
- Render/Q3DSWidgetUtils.cpp
+ Render/Q3DSWidgetUtils.cpp \
+ Render/Q3DSManipulationWidget.cpp
RESOURCES += \
MainFrm.qrc \
diff --git a/src/Authoring/Studio/Render/Q3DSManipulationWidget.cpp b/src/Authoring/Studio/Render/Q3DSManipulationWidget.cpp
new file mode 100644
index 00000000..5c76bae6
--- /dev/null
+++ b/src/Authoring/Studio/Render/Q3DSManipulationWidget.cpp
@@ -0,0 +1,363 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Q3DSManipulationWidget.h"
+#include "Q3DSWidgetUtils.h"
+#include <QtCore/qmath.h>
+#include <Qt3DCore/qtransform.h>
+#include "StudioPreferences.h"
+
+namespace Q3DStudio {
+
+bool Q3DSManipulationWidget::hasManipulators() const
+{
+ return m_manipulators.size() > 0;
+}
+
+bool Q3DSManipulationWidget::isXAxis(Q3DSGraphObject *obj) const
+{
+ if (m_type == ManipulationWidgetType::Rotation || m_manipulators.size() < 6)
+ return false;
+ return obj == m_manipulators[2];
+}
+
+bool Q3DSManipulationWidget::isYAxis(Q3DSGraphObject *obj) const
+{
+ if (m_type == ManipulationWidgetType::Rotation || m_manipulators.size() < 6)
+ return false;
+ return obj == m_manipulators[0];
+}
+
+bool Q3DSManipulationWidget::isZAxis(Q3DSGraphObject *obj) const
+{
+ if (m_type == ManipulationWidgetType::Rotation || m_manipulators.size() < 6)
+ return false;
+ return obj == m_manipulators[1];
+}
+
+bool Q3DSManipulationWidget::isXYPlane(Q3DSGraphObject *obj) const
+{
+ if (m_type == ManipulationWidgetType::Rotation || m_manipulators.size() < 6)
+ return false;
+ return obj == m_manipulators[4];
+}
+
+bool Q3DSManipulationWidget::isYZPlane(Q3DSGraphObject *obj) const
+{
+ if (m_type == ManipulationWidgetType::Rotation || m_manipulators.size() < 6)
+ return false;
+ return obj == m_manipulators[5];
+}
+
+bool Q3DSManipulationWidget::isZXPlane(Q3DSGraphObject *obj) const
+{
+ if (m_type == ManipulationWidgetType::Rotation || m_manipulators.size() < 6)
+ return false;
+ return obj == m_manipulators[3];
+}
+
+bool Q3DSManipulationWidget::isXYCircle(Q3DSGraphObject *obj) const
+{
+ if (m_type != ManipulationWidgetType::Rotation || m_manipulators.size() < 4)
+ return false;
+ return obj == m_manipulators[1];
+}
+
+bool Q3DSManipulationWidget::isYZCircle(Q3DSGraphObject *obj) const
+{
+ if (m_type != ManipulationWidgetType::Rotation || m_manipulators.size() < 4)
+ return false;
+ return obj == m_manipulators[2];
+}
+
+bool Q3DSManipulationWidget::isZXCircle(Q3DSGraphObject *obj) const
+{
+ if (m_type != ManipulationWidgetType::Rotation || m_manipulators.size() < 4)
+ return false;
+ return obj == m_manipulators[0];
+}
+
+bool Q3DSManipulationWidget::isCameraCircle(Q3DSGraphObject *obj) const
+{
+ if (m_type != ManipulationWidgetType::Rotation || m_manipulators.size() < 4)
+ return false;
+ return obj == m_manipulators[3];
+}
+
+void Q3DSManipulationWidget::setScale(Q3DSGraphObject *obj, const QVector3D &scale)
+{
+ for (int i = 0; i < m_manipulators.size(); ++i) {
+ if (m_manipulators[i] == obj) {
+ m_manipulatorScales[i] = scale;
+ break;
+ }
+ }
+}
+
+void Q3DSManipulationWidget::resetScale(Q3DSGraphObject *obj)
+{
+ for (int i = 0; i < m_manipulators.size(); ++i) {
+ if (m_manipulators[i] == obj) {
+ m_manipulatorScales[i] = QVector3D(1, 1, 1);
+ break;
+ }
+ }
+}
+
+void Q3DSManipulationWidget::setColor(Q3DSGraphObject *obj, const QColor &color)
+{
+ for (int i = 0; i < m_manipulators.size(); ++i) {
+ if (m_manipulators[i] == obj) {
+ Q3DSPropertyChangeList colorChange = { Q3DSPropertyChange::fromVariant(
+ QStringLiteral("color"), color) };
+ m_manipulatorMaterials[i]->applyPropertyChanges(colorChange);
+ m_manipulatorMaterials[i]->notifyPropertyChanges(colorChange);
+ break;
+ }
+ }
+}
+
+void Q3DSManipulationWidget::resetColor(Q3DSGraphObject *obj)
+{
+ for (int i = 0; i < m_manipulators.size(); ++i) {
+ if (m_manipulators[i] == obj) {
+ Q3DSPropertyChangeList colorChange = { Q3DSPropertyChange::fromVariant(
+ QStringLiteral("color"),
+ m_manipulatorColors[i]) };
+ m_manipulatorMaterials[i]->applyPropertyChanges(colorChange);
+ m_manipulatorMaterials[i]->notifyPropertyChanges(colorChange);
+ break;
+ }
+ }
+}
+
+void Q3DSManipulationWidget::setEyeballEnabled(bool value)
+{
+ for (auto &model : qAsConst(m_manipulators)) {
+ Q3DSPropertyChangeList list;
+ list.append(model->setEyeballEnabled(value));
+ model->notifyPropertyChanges(list);
+ }
+}
+
+void Q3DSManipulationWidget::createManipulator(Q3DSUipPresentation *presentation,
+ Q3DSLayerNode *layer, const QString &name,
+ const QString &mesh, const QColor &color,
+ const QVector3D &scale)
+{
+ const QString widgetMaterial = QStringLiteral(
+ "<MetaData>\n"
+ "<Property name=\"color\" type=\"Color\" default=\"1.0 0.0 0.0\" stage=\"fragment\" />\n"
+ "</MetaData>\n"
+ "<Shaders type=\"GLSL\" version=\"330\">\n"
+ "<Shader>\n"
+ "<VertexShader>\n"
+ "attribute vec3 attr_pos;\n"
+ "uniform mat4 modelViewProjection;\n"
+ "void main() {\n"
+ "gl_Position = modelViewProjection * vec4(attr_pos, 1.0);\n"
+ "</VertexShader>\n"
+ "<FragmentShader>\n"
+ "void main() {\n"
+ "fragOutput = vec4(color, 1.0);\n"
+ "</FragmentShader>\n"
+ "</Shader>\n"
+ "</Shaders>\n"
+ "<Passes><Pass></Pass></Passes>\n");
+
+ auto material = createWidgetCustomMaterial(presentation, name, widgetMaterial, color);
+ if (material) {
+ m_manipulatorMaterials.append(material);
+ m_manipulators.append(createWidgetModel(presentation, layer, name, mesh, scale));
+ m_manipulators.back()->appendChildNode(material);
+ m_manipulatorColors.append(color);
+ m_manipulatorScales.append(QVector3D(1, 1, 1));
+ }
+}
+
+void Q3DSManipulationWidget::createManipulators(Q3DSUipPresentation *presentation,
+ Q3DSLayerNode *layer, ManipulationWidgetType type)
+{
+ if (hasManipulators())
+ return;
+
+ m_type = type;
+ m_presentation = presentation;
+ if (m_type == ManipulationWidgetType::Translation) {
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetGreenPointer"),
+ QStringLiteral(":/res/GreenArrow.mesh"),
+ CStudioPreferences::GetYAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetBluePointer"),
+ QStringLiteral(":/res/BlueArrow.mesh"),
+ CStudioPreferences::GetZAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetRedPointer"),
+ QStringLiteral(":/res/RedArrow.mesh"),
+ CStudioPreferences::GetXAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetGreenCircle"),
+ QStringLiteral(":/res/GreenCircle.mesh"),
+ CStudioPreferences::GetYAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetBlueCircle"),
+ QStringLiteral(":/res/BlueCircle.mesh"),
+ CStudioPreferences::GetZAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetRedCircle"),
+ QStringLiteral(":/res/RedCircle.mesh"),
+ CStudioPreferences::GetXAxisColor(), QVector3D(50, 50, 50));
+ } else if (m_type == ManipulationWidgetType::Rotation) {
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetGreenCircle"),
+ QStringLiteral(":/res/GreenRotation.mesh"),
+ CStudioPreferences::GetYAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetBlueCircle"),
+ QStringLiteral(":/res/BlueRotation.mesh"),
+ CStudioPreferences::GetZAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetRedCircle"),
+ QStringLiteral(":/res/RedRotation.mesh"),
+ CStudioPreferences::GetXAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetGrayCircle"),
+ QStringLiteral(":/res/BlueRotation.mesh"),
+ QColor(Qt::gray), QVector3D(50, 50, 50));
+ } else if (m_type == ManipulationWidgetType::Scale) {
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetGreenPointer"),
+ QStringLiteral(":/res/GreenScale.mesh"),
+ CStudioPreferences::GetYAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetBluePointer"),
+ QStringLiteral(":/res/BlueScale.mesh"),
+ CStudioPreferences::GetZAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetRedPointer"),
+ QStringLiteral(":/res/RedScale.mesh"),
+ CStudioPreferences::GetXAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetGreenCircle"),
+ QStringLiteral(":/res/GreenCircle.mesh"),
+ CStudioPreferences::GetYAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetBlueCircle"),
+ QStringLiteral(":/res/BlueCircle.mesh"),
+ CStudioPreferences::GetZAxisColor(), QVector3D(50, 50, 50));
+ createManipulator(presentation, layer,
+ QStringLiteral("StudioManipulationWidgetRedCircle"),
+ QStringLiteral(":/res/RedCircle.mesh"),
+ CStudioPreferences::GetXAxisColor(), QVector3D(50, 50, 50));
+ }
+}
+
+void Q3DSManipulationWidget::destroyManipulators()
+{
+ for (auto &model : qAsConst(m_manipulators)) {
+ m_presentation->masterSlide()->removeObject(model);
+ m_presentation->unlinkObject(model);
+ delete model;
+ }
+
+ m_manipulators.clear();
+ m_manipulatorMaterials.clear();
+ m_manipulatorColors.clear();
+}
+
+void applyNodeProperties(Q3DSGraphObject *node, Q3DSCameraNode *camera, Q3DSLayerNode *layer,
+ const QSize &size, Q3DSModelNode *model, const QVector3D &modelScale) {
+ Q3DSNodeAttached *attached = node->attached<Q3DSNodeAttached>();
+ if (!attached)
+ return;
+
+ Qt3DCore::QTransform transform;
+ QMatrix4x4 globalMatrix = attached->globalTransform;
+ adjustRotationLeftToRight(&globalMatrix);
+ transform.setMatrix(globalMatrix);
+
+ QVector3D position = transform.translation();
+ position.setZ(-position.z());
+
+ Q3DSPropertyChangeList list;
+ list.append(model->setPosition(position));
+ list.append(model->setRotation(transform.rotation().toEulerAngles()));
+
+ float distance = 400.0f;
+ float fovScale = 2.0f;
+ if (!camera->orthographic()) {
+ distance = camera->position().distanceToPoint(position);
+ fovScale = 2.0f * float(qTan(qDegreesToRadians(qreal(camera->fov())) / 2.0));
+ }
+ float scale = 125.0f * camera->zoom() * fovScale;
+ float width = size.width();
+ float height = size.height();
+ if (layer->widthUnits() == Q3DSLayerNode::Units::Percent) {
+ width *= layer->width() * 0.01f;
+ height *= layer->height() * 0.01f;
+ } else {
+ width = layer->width();
+ height = layer->height();
+ }
+ float length = qSqrt(width * width + height * height);
+ scale /= length;
+ list.append(model->setScale(modelScale * scale * distance));
+ list.append(model->setEyeballEnabled(true));
+ model->notifyPropertyChanges(list);
+}
+
+void Q3DSManipulationWidget::applyProperties(Q3DSGraphObject *node, Q3DSCameraNode *camera,
+ Q3DSLayerNode *layer, const QSize &size)
+{
+ for (int i = 0; i < m_manipulators.size(); ++i) {
+ if (node->type() == Q3DSGraphObject::Model
+ || node->type() == Q3DSGraphObject::Alias
+ || node->type() == Q3DSGraphObject::Group
+ || node->type() == Q3DSGraphObject::Light
+ || node->type() == Q3DSGraphObject::Camera
+ || node->type() == Q3DSGraphObject::Text
+ || node->type() == Q3DSGraphObject::Component) {
+ applyNodeProperties(node, camera, layer, size, m_manipulators[i],
+ m_manipulatorScales[i]);
+ }
+ }
+
+ if (m_type == ManipulationWidgetType::Rotation && m_manipulators.size() >= 4) {
+ // The fourth model of the rotation widget has to look towards the camera
+ QQuaternion rotation = QQuaternion::fromDirection(
+ (camera->position() - m_manipulators[3]->position()).normalized(),
+ QVector3D(0, 1, 0));
+
+ Q3DSPropertyChangeList list;
+ list.append(m_manipulators[3]->setRotation(rotation.toEulerAngles()));
+ m_manipulators[3]->notifyPropertyChanges(list);
+ }
+}
+
+}
diff --git a/src/Authoring/Studio/Render/Q3DSManipulationWidget.h b/src/Authoring/Studio/Render/Q3DSManipulationWidget.h
new file mode 100644
index 00000000..aae5af0b
--- /dev/null
+++ b/src/Authoring/Studio/Render/Q3DSManipulationWidget.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DSMANIPULATIONWIDGET_H
+#define Q3DSMANIPULATIONWIDGET_H
+
+#include "q3dsruntime2api_p.h"
+
+namespace Q3DStudio {
+
+enum class ManipulationWidgetType
+{
+ Translation,
+ Rotation,
+ Scale
+};
+
+class Q3DSManipulationWidget
+{
+public:
+ bool hasManipulators() const;
+ bool isXAxis(Q3DSGraphObject *obj) const;
+ bool isYAxis(Q3DSGraphObject *obj) const;
+ bool isZAxis(Q3DSGraphObject *obj) const;
+ bool isXYPlane(Q3DSGraphObject *obj) const;
+ bool isYZPlane(Q3DSGraphObject *obj) const;
+ bool isZXPlane(Q3DSGraphObject *obj) const;
+ bool isXYCircle(Q3DSGraphObject *obj) const;
+ bool isYZCircle(Q3DSGraphObject *obj) const;
+ bool isZXCircle(Q3DSGraphObject *obj) const;
+ bool isCameraCircle(Q3DSGraphObject *obj) const;
+
+ void setScale(Q3DSGraphObject *obj, const QVector3D &scale);
+ void resetScale(Q3DSGraphObject *obj);
+ void setColor(Q3DSGraphObject *obj, const QColor &color);
+ void resetColor(Q3DSGraphObject *obj);
+ void setEyeballEnabled(bool value);
+
+ void createManipulators(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
+ ManipulationWidgetType type);
+ void destroyManipulators();
+
+ void applyProperties(Q3DSGraphObject *node, Q3DSCameraNode *camera, Q3DSLayerNode *layer,
+ const QSize &size);
+
+private:
+ ManipulationWidgetType m_type = ManipulationWidgetType::Translation;
+ Q3DSUipPresentation *m_presentation = nullptr;
+
+ QVector<Q3DSModelNode *> m_manipulators;
+ QVector<Q3DSCustomMaterialInstance *> m_manipulatorMaterials;
+ QVector<QColor> m_manipulatorColors;
+ QVector<QVector3D> m_manipulatorScales;
+
+ void createManipulator(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
+ const QString &name, const QString &mesh,
+ const QColor &color, const QVector3D &scale);
+};
+
+}
+
+#endif // Q3DSMANIPULATIONWIDGET_H
diff --git a/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp b/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp
index 6ce3e168..984da1c2 100644
--- a/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp
+++ b/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp
@@ -30,329 +30,246 @@
#include "Q3DSWidgetUtils.h"
#include <QtCore/qmath.h>
#include <Qt3DCore/qtransform.h>
+#include <Qt3DRender/qattribute.h>
+#include <Qt3DRender/qbuffer.h>
namespace Q3DStudio {
-bool Q3DSSelectionWidget::isCreated() const
+Q3DSSelectionWidget::BoundingBox Q3DSSelectionWidget::calculateLocalBoundingBox(
+ Q3DSModelNode *model)
{
- return m_models.size() > 0;
-}
-
-bool Q3DSSelectionWidget::isXAxis(Q3DSGraphObject *obj) const
-{
- if (m_type == SelectionWidgetType::Rotation || m_models.size() < 6)
- return false;
- return obj == m_models[2];
-}
-
-bool Q3DSSelectionWidget::isYAxis(Q3DSGraphObject *obj) const
-{
- if (m_type == SelectionWidgetType::Rotation || m_models.size() < 6)
- return false;
- return obj == m_models[0];
-}
-
-bool Q3DSSelectionWidget::isZAxis(Q3DSGraphObject *obj) const
-{
- if (m_type == SelectionWidgetType::Rotation || m_models.size() < 6)
- return false;
- return obj == m_models[1];
-}
-
-bool Q3DSSelectionWidget::isXYPlane(Q3DSGraphObject *obj) const
-{
- if (m_type == SelectionWidgetType::Rotation || m_models.size() < 6)
- return false;
- return obj == m_models[4];
-}
-
-bool Q3DSSelectionWidget::isYZPlane(Q3DSGraphObject *obj) const
-{
- if (m_type == SelectionWidgetType::Rotation || m_models.size() < 6)
- return false;
- return obj == m_models[5];
-}
-
-bool Q3DSSelectionWidget::isZXPlane(Q3DSGraphObject *obj) const
-{
- if (m_type == SelectionWidgetType::Rotation || m_models.size() < 6)
- return false;
- return obj == m_models[3];
-}
-
-bool Q3DSSelectionWidget::isXYCircle(Q3DSGraphObject *obj) const
-{
- if (m_type != SelectionWidgetType::Rotation || m_models.size() < 4)
- return false;
- return obj == m_models[1];
-}
-
-bool Q3DSSelectionWidget::isYZCircle(Q3DSGraphObject *obj) const
-{
- if (m_type != SelectionWidgetType::Rotation || m_models.size() < 4)
- return false;
- return obj == m_models[2];
-}
+ // TODO: Pre-calculate bounding boxes to prevent lag upon first selection
+ const QString srcPath = model->sourcePath();
+ if (m_boundingBoxCache.contains(srcPath))
+ return m_boundingBoxCache[srcPath];
+
+ BoundingBox box;
+
+ const MeshList meshList = model->mesh();
+ if (meshList.empty())
+ return box;
+
+ const auto boundingAttribute = meshList[0]->geometry()->boundingVolumePositionAttribute();
+ const auto data = boundingAttribute->buffer()->data();
+ const uint stride = boundingAttribute->byteStride();
+ const uint offset = boundingAttribute->byteOffset();
+ const uint size = boundingAttribute->vertexSize();
+ const Qt3DRender::QAttribute::VertexBaseType type = boundingAttribute->vertexBaseType();
+
+ if (type != Qt3DRender::QAttribute::VertexBaseType::Float || size != 3) {
+ // Other types and sizes are not handled at the moment
+ Q_ASSERT(false);
+ return box;
+ }
-bool Q3DSSelectionWidget::isZXCircle(Q3DSGraphObject *obj) const
-{
- if (m_type != SelectionWidgetType::Rotation || m_models.size() < 4)
- return false;
- return obj == m_models[0];
-}
+ for (uint i = 0; i < data.size(); i += stride) {
+ uint index = i + offset;
+ const float x = *reinterpret_cast<float *>(data.mid(index, 4).data());
+ const float y = *reinterpret_cast<float *>(data.mid(index + 4, 4).data());
+ const float z = *reinterpret_cast<float *>(data.mid(index + 8, 4).data());
+ if (box.min.x() > x)
+ box.min.setX(x);
+ if (box.min.y() > y)
+ box.min.setY(y);
+ if (box.min.z() > z)
+ box.min.setZ(z);
+
+ if (box.max.x() < x)
+ box.max.setX(x);
+ if (box.max.y() < y)
+ box.max.setY(y);
+ if (box.max.z() < z)
+ box.max.setZ(z);
+ }
-bool Q3DSSelectionWidget::isCameraCircle(Q3DSGraphObject *obj) const
-{
- if (m_type != SelectionWidgetType::Rotation || m_models.size() < 4)
- return false;
- return obj == m_models[3];
+ m_boundingBoxCache[srcPath] = box;
+ return box;
}
-void Q3DSSelectionWidget::setScale(Q3DSGraphObject *obj, const QVector3D &scale)
+Q3DSSelectionWidget::BoundingBox Q3DSSelectionWidget::calculateBoundingBox(
+ Q3DSGraphObject *graphObject)
{
- for (int i = 0; i < m_models.size(); ++i) {
- if (m_models[i] == obj) {
- m_scales[i] = scale;
- break;
- }
+ BoundingBox boundingBox;
+ if (graphObject->type() == Q3DSNode::Type::Model) {
+ boundingBox = calculateLocalBoundingBox(static_cast<Q3DSModelNode *>(graphObject));
+ } else if (graphObject->childCount() == 0
+ || graphObject->type() != Q3DSGraphObject::Type::Group) {
+ boundingBox.min = QVector3D(0, 0, 0);
+ boundingBox.max = QVector3D(0, 0, 0);
}
-}
-void Q3DSSelectionWidget::resetScale(Q3DSGraphObject *obj)
-{
- for (int i = 0; i < m_models.size(); ++i) {
- if (m_models[i] == obj) {
- m_scales[i] = QVector3D(1, 1, 1);
- break;
+ for (Q3DSGraphObject *child = graphObject->firstChild(); child != nullptr;
+ child = child->nextSibling()) {
+ Q3DSNode *childNode = static_cast<Q3DSNode *>(child);
+ BoundingBox childBB = calculateBoundingBox(child);
+ if ((childBB.max - childBB.min).length() > 0) {
+ QVector3D rotation = childNode->rotation();
+ QQuaternion quat;
+ if (childNode->orientation() == Q3DSNode::Orientation::LeftHanded) {
+ auto rotX = QQuaternion::fromAxisAndAngle(QVector3D(-1, 0, 0), rotation.x());
+ auto rotY = QQuaternion::fromAxisAndAngle(QVector3D(0, -1, 0), rotation.y());
+ auto rotZ = QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), rotation.z());
+ quat = rotY * rotX * rotZ;
+ } else {
+ auto rotX = QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), rotation.x());
+ auto rotY = QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), rotation.y());
+ auto rotZ = QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), rotation.z());
+ quat = rotZ * rotY * rotX;
+ }
+
+ rotateBoundingBox(childBB, quat);
+
+ const QVector3D scale = childNode->scale();
+ childBB.min *= scale;
+ childBB.max *= scale;
+
+ QVector3D position = childNode->position();
+ position.setZ(-position.z());
+ childBB.min += position;
+ childBB.max += position;
+
+ if (childBB.min.x() < boundingBox.min.x())
+ boundingBox.min.setX(childBB.min.x());
+ if (childBB.min.y() < boundingBox.min.y())
+ boundingBox.min.setY(childBB.min.y());
+ if (childBB.min.z() < boundingBox.min.z())
+ boundingBox.min.setZ(childBB.min.z());
+
+ if (childBB.max.x() > boundingBox.max.x())
+ boundingBox.max.setX(childBB.max.x());
+ if (childBB.max.y() > boundingBox.max.y())
+ boundingBox.max.setY(childBB.max.y());
+ if (childBB.max.z() > boundingBox.max.z())
+ boundingBox.max.setZ(childBB.max.z());
}
}
-}
-void Q3DSSelectionWidget::setColor(Q3DSGraphObject *obj, const QColor &color)
-{
- for (int i = 0; i < m_models.size(); ++i) {
- if (m_models[i] == obj) {
- Q3DSPropertyChangeList colorChange = { Q3DSPropertyChange::fromVariant(
- QStringLiteral("color"), color) };
- m_materials[i]->applyPropertyChanges(colorChange);
- m_materials[i]->notifyPropertyChanges(colorChange);
- break;
- }
- }
+ return boundingBox;
}
-void Q3DSSelectionWidget::resetColor(Q3DSGraphObject *obj)
+void Q3DSSelectionWidget::rotateBoundingBox(BoundingBox &box, const QQuaternion &rotation)
{
- for (int i = 0; i < m_models.size(); ++i) {
- if (m_models[i] == obj) {
- Q3DSPropertyChangeList colorChange = { Q3DSPropertyChange::fromVariant(
- QStringLiteral("color"), m_colors[i]) };
- m_materials[i]->applyPropertyChanges(colorChange);
- m_materials[i]->notifyPropertyChanges(colorChange);
- break;
- }
+ QVector3D points[8];
+ points[0] = QVector3D(box.min.x(), box.min.y(), box.min.z());
+ points[1] = QVector3D(box.max.x(), box.min.y(), box.min.z());
+ points[2] = QVector3D(box.max.x(), box.max.y(), box.min.z());
+ points[3] = QVector3D(box.min.x(), box.max.y(), box.min.z());
+ points[4] = QVector3D(box.max.x(), box.max.y(), box.max.z());
+ points[5] = QVector3D(box.min.x(), box.max.y(), box.max.z());
+ points[6] = QVector3D(box.min.x(), box.min.y(), box.max.z());
+ points[7] = QVector3D(box.max.x(), box.min.y(), box.max.z());
+ box.min = QVector3D(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max());
+ box.max = QVector3D(-std::numeric_limits<float>::max(),
+ -std::numeric_limits<float>::max(),
+ -std::numeric_limits<float>::max());
+ for (auto &point : points) {
+ point = rotation * point;
+
+ if (point.x() < box.min.x())
+ box.min.setX(point.x());
+ if (point.y() < box.min.y())
+ box.min.setY(point.y());
+ if (point.z() < box.min.z())
+ box.min.setZ(point.z());
+
+ if (point.x() > box.max.x())
+ box.max.setX(point.x());
+ if (point.y() > box.max.y())
+ box.max.setY(point.y());
+ if (point.z() > box.max.z())
+ box.max.setZ(point.z());
}
}
-void Q3DSSelectionWidget::setEyeballEnabled(bool value)
-{
- for (auto &model : qAsConst(m_models)) {
- Q3DSPropertyChangeList list;
- list.append(model->setEyeballEnabled(value));
- model->notifyPropertyChanges(list);
- }
-}
-void Q3DSSelectionWidget::createModel(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
- const QString &name, const QString &mesh,
- const QColor &color, const QVector3D &scale)
+void Q3DSSelectionWidget::select(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
+ Q3DSNode *node)
{
- const QString widgetMaterial = QStringLiteral(
- "<MetaData>\n"
- "<Property name=\"color\" type=\"Color\" default=\"1.0 0.0 0.0\" stage=\"fragment\" />\n"
- "</MetaData>\n"
- "<Shaders type=\"GLSL\" version=\"330\">\n"
- "<Shader>\n"
- "<VertexShader>\n"
- "attribute vec3 attr_pos;\n"
- "uniform mat4 modelViewProjection;\n"
- "void main() {\n"
- "gl_Position = modelViewProjection * vec4(attr_pos, 1.0);\n"
- "</VertexShader>\n"
- "<FragmentShader>\n"
- "void main() {\n"
- "fragOutput = vec4(color, 1.0);\n"
- "</FragmentShader>\n"
- "</Shader>\n"
- "</Shaders>\n"
- "<Passes><Pass></Pass></Passes>\n");
-
- auto material = createWidgetCustomMaterial(presentation, name, widgetMaterial, color);
- if (material) {
- m_materials.append(material);
- m_models.append(createWidgetModel(presentation, layer, name, mesh, scale));
- m_models.back()->appendChildNode(material);
- m_colors.append(color);
- m_scales.append(QVector3D(1, 1, 1));
+ for (auto &selection : qAsConst(m_selections)) {
+ for (auto &model : qAsConst(selection.models))
+ model->notifyPropertyChanges({ model->setEyeballEnabled(false) });
}
+ int index = 0;
+ selectRecursive(presentation, layer, node, index, 0);
}
-void Q3DSSelectionWidget::create(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
- SelectionWidgetType type)
+void Q3DSSelectionWidget::selectRecursive(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
+ Q3DSNode *node, int &index, int depth)
{
- if (isCreated())
+ if (depth > 1)
return;
- m_type = type;
- if (m_type == SelectionWidgetType::Translation) {
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetGreenPointer"),
- QStringLiteral(":/res/GreenArrow.mesh"),
- QColor(Qt::green), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetBluePointer"),
- QStringLiteral(":/res/BlueArrow.mesh"),
- QColor(Qt::blue), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetRedPointer"),
- QStringLiteral(":/res/RedArrow.mesh"),
- QColor(Qt::red), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetGreenCircle"),
- QStringLiteral(":/res/GreenCircle.mesh"),
- QColor(Qt::green), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetBlueCircle"),
- QStringLiteral(":/res/BlueCircle.mesh"),
- QColor(Qt::blue), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetRedCircle"),
- QStringLiteral(":/res/RedCircle.mesh"),
- QColor(Qt::red), QVector3D(50, 50, 50));
- } else if (m_type == SelectionWidgetType::Rotation) {
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetGreenCircle"),
- QStringLiteral(":/res/GreenRotation.mesh"),
- QColor(Qt::green), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetBlueCircle"),
- QStringLiteral(":/res/BlueRotation.mesh"),
- QColor(Qt::blue), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetRedCircle"),
- QStringLiteral(":/res/RedRotation.mesh"),
- QColor(Qt::red), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetGrayCircle"),
- QStringLiteral(":/res/BlueRotation.mesh"),
- QColor(Qt::gray), QVector3D(50, 50, 50));
- } else if (m_type == SelectionWidgetType::Scale) {
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetGreenPointer"),
- QStringLiteral(":/res/GreenScale.mesh"),
- QColor(Qt::green), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetBluePointer"),
- QStringLiteral(":/res/BlueScale.mesh"),
- QColor(Qt::blue), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetRedPointer"),
- QStringLiteral(":/res/RedScale.mesh"),
- QColor(Qt::red), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetGreenCircle"),
- QStringLiteral(":/res/GreenCircle.mesh"),
- QColor(Qt::green), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetBlueCircle"),
- QStringLiteral(":/res/BlueCircle.mesh"),
- QColor(Qt::blue), QVector3D(50, 50, 50));
- createModel(presentation, layer,
- QStringLiteral("StudioTranslationWidgetRedCircle"),
- QStringLiteral(":/res/RedCircle.mesh"),
- QColor(Qt::red), QVector3D(50, 50, 50));
+ if (node->type() != Q3DSGraphObject::Type::Model
+ && node->type() != Q3DSGraphObject::Type::Group) {
+ return;
}
-}
-void Q3DSSelectionWidget::destroy(Q3DSUipPresentation *presentation)
-{
- for (auto &model : qAsConst(m_models)) {
- presentation->masterSlide()->removeObject(model);
- presentation->unlinkObject(model);
- delete model;
+ if (m_selections[layer].nodes.size() == index)
+ m_selections[layer].nodes.resize(index + 1);
+ m_selections[layer].nodes[index] = node;
+
+ if (m_selections[layer].boundingBoxes.size() == index)
+ m_selections[layer].boundingBoxes.resize(index + 1);
+ m_selections[layer].boundingBoxes[index] = calculateBoundingBox(node);
+
+ if (m_selections[layer].models.size() == index) {
+ const QString name = QStringLiteral("StudioSelectionWidgetBoundingBox") + layer->id()
+ + QString::number(m_selections[layer].nodes.size());
+ auto model = createWidgetModel(presentation, layer, name,
+ QStringLiteral(":/res/Selection.mesh"),
+ QVector3D(1, 1, 1), true);
+ auto material = createWidgetDefaultMaterial(presentation, name, Qt::red);
+ model->appendChildNode(material);
+ m_selections[layer].models.resize(index + 1);
+ m_selections[layer].models[index] = model;
}
+ const auto model = m_selections[layer].models[index];
+ model->notifyPropertyChanges({ model->setEyeballEnabled(true) });
- m_models.clear();
- m_materials.clear();
- m_colors.clear();
-}
-
-void applyNodeProperties(Q3DSGraphObject *node, Q3DSCameraNode *camera, Q3DSLayerNode *layer,
- const QSize &size, Q3DSModelNode *model, const QVector3D &modelScale) {
- Q3DSNodeAttached *attached = node->attached<Q3DSNodeAttached>();
- if (!attached)
- return;
-
- Qt3DCore::QTransform transform;
- QMatrix4x4 globalMatrix = attached->globalTransform;
- adjustRotationLeftToRight(&globalMatrix);
- transform.setMatrix(globalMatrix);
+ index++;
- QVector3D position = transform.translation();
- position.setZ(-position.z());
-
- Q3DSPropertyChangeList list;
- list.append(model->setPosition(position));
- list.append(model->setRotation(transform.rotation().toEulerAngles()));
-
- float distance = 400.0f;
- float fovScale = 2.0f;
- if (!camera->orthographic()) {
- distance = camera->position().distanceToPoint(position);
- fovScale = 2.0f * float(qTan(qDegreesToRadians(qreal(camera->fov())) / 2.0));
- }
- float scale = 125.0f * camera->zoom() * fovScale;
- float width = size.width();
- float height = size.height();
- if (layer->widthUnits() == Q3DSLayerNode::Units::Percent) {
- width *= layer->width() * 0.01f;
- height *= layer->height() * 0.01f;
- } else {
- width = layer->width();
- height = layer->height();
+ for (Q3DSGraphObject *child = node->firstChild(); child != nullptr;
+ child = child->nextSibling()) {
+ selectRecursive(presentation, layer, static_cast<Q3DSNode *>(child), index, depth + 1);
}
- float length = qSqrt(width * width + height * height);
- scale /= length;
- list.append(model->setScale(modelScale * scale * distance));
- list.append(model->setEyeballEnabled(true));
- model->notifyPropertyChanges(list);
}
-void Q3DSSelectionWidget::applyProperties(Q3DSGraphObject *node, Q3DSCameraNode *camera,
- Q3DSLayerNode *layer, const QSize &size)
+void Q3DSSelectionWidget::update()
{
- for (int i = 0; i < m_models.size(); ++i) {
- if (node->type() == Q3DSGraphObject::Model
- || node->type() == Q3DSGraphObject::Alias
- || node->type() == Q3DSGraphObject::Group
- || node->type() == Q3DSGraphObject::Light
- || node->type() == Q3DSGraphObject::Camera
- || node->type() == Q3DSGraphObject::Text
- || node->type() == Q3DSGraphObject::Component) {
- applyNodeProperties(node, camera, layer, size, m_models[i], m_scales[i]);
+ for (auto &selection : qAsConst(m_selections)) {
+ for (int i = 0; i < selection.models.size(); ++i) {
+ auto node = selection.nodes[i];
+ auto model = selection.models[i];
+ auto boundingBox = selection.boundingBoxes[i];
+
+ QVector3D bbSize(qAbs(boundingBox.max.x() - boundingBox.min.x()),
+ qAbs(boundingBox.max.y() - boundingBox.min.y()),
+ qAbs(boundingBox.max.z() - boundingBox.min.z()));
+
+ if (bbSize.length() > 0) {
+ Q3DSNodeAttached *attached = node->attached<Q3DSNodeAttached>();
+ if (!attached)
+ continue;
+
+ Qt3DCore::QTransform transform;
+ QMatrix4x4 globalMatrix = attached->globalTransform;
+ globalMatrix.translate(boundingBox.min + bbSize / 2.0f);
+ adjustRotationLeftToRight(&globalMatrix);
+ transform.setMatrix(globalMatrix);
+
+ QVector3D position = transform.translation();
+ position.setZ(-position.z());
+
+ Q3DSPropertyChangeList list;
+ list.append(model->setPosition(position));
+ list.append(model->setRotation(transform.rotation().toEulerAngles()));
+ list.append(model->setScale(transform.scale() * bbSize * 0.5f));
+ model->notifyPropertyChanges(list);
+ }
}
}
-
- if (m_type == SelectionWidgetType::Rotation && m_models.size() >= 4) {
- // The fourth model of the rotation widget has to look towards the camera
- QQuaternion rotation = QQuaternion::fromDirection(
- (camera->position() - m_models[3]->position()).normalized(),
- QVector3D(0, 1, 0));
-
- Q3DSPropertyChangeList list;
- list.append(m_models[3]->setRotation(rotation.toEulerAngles()));
- m_models[3]->notifyPropertyChanges(list);
- }
}
}
diff --git a/src/Authoring/Studio/Render/Q3DSSelectionWidget.h b/src/Authoring/Studio/Render/Q3DSSelectionWidget.h
index 7ea5009b..c5fb260d 100644
--- a/src/Authoring/Studio/Render/Q3DSSelectionWidget.h
+++ b/src/Authoring/Studio/Render/Q3DSSelectionWidget.h
@@ -33,49 +33,40 @@
namespace Q3DStudio {
-enum class SelectionWidgetType
-{
- Translation,
- Rotation,
- Scale
-};
-
class Q3DSSelectionWidget
{
public:
- bool isCreated() const;
- bool isXAxis(Q3DSGraphObject *obj) const;
- bool isYAxis(Q3DSGraphObject *obj) const;
- bool isZAxis(Q3DSGraphObject *obj) const;
- bool isXYPlane(Q3DSGraphObject *obj) const;
- bool isYZPlane(Q3DSGraphObject *obj) const;
- bool isZXPlane(Q3DSGraphObject *obj) const;
- bool isXYCircle(Q3DSGraphObject *obj) const;
- bool isYZCircle(Q3DSGraphObject *obj) const;
- bool isZXCircle(Q3DSGraphObject *obj) const;
- bool isCameraCircle(Q3DSGraphObject *obj) const;
+ void select(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer, Q3DSNode *node);
+ void update();
- void setScale(Q3DSGraphObject *obj, const QVector3D &scale);
- void resetScale(Q3DSGraphObject *obj);
- void setColor(Q3DSGraphObject *obj, const QColor &color);
- void resetColor(Q3DSGraphObject *obj);
- void setEyeballEnabled(bool value);
+private:
+ Q3DSUipPresentation *m_presentation = nullptr;
- void create(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer, SelectionWidgetType type);
- void destroy(Q3DSUipPresentation *presentation);
- void applyProperties(Q3DSGraphObject *node, Q3DSCameraNode *camera, Q3DSLayerNode *layer,
- const QSize &size);
+ struct BoundingBox
+ {
+ QVector3D min = QVector3D(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max());
+ QVector3D max = QVector3D(-std::numeric_limits<float>::max(),
+ -std::numeric_limits<float>::max(),
+ -std::numeric_limits<float>::max());
+ };
-private:
- SelectionWidgetType m_type = SelectionWidgetType::Translation;
- QVector<Q3DSModelNode *> m_models;
- QVector<Q3DSCustomMaterialInstance *> m_materials;
- QVector<QColor> m_colors;
- QVector<QVector3D> m_scales;
+ struct Selection
+ {
+ QVector<Q3DSNode *> nodes;
+ QVector<Q3DSModelNode *> models;
+ QVector<BoundingBox> boundingBoxes;
+ };
+
+ QHash<QString, BoundingBox> m_boundingBoxCache;
+ QHash<Q3DSLayerNode *, Selection> m_selections;
- void createModel(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
- const QString &name, const QString &mesh,
- const QColor &color, const QVector3D &scale);
+ BoundingBox calculateLocalBoundingBox(Q3DSModelNode *model);
+ BoundingBox calculateBoundingBox(Q3DSGraphObject *graphObject);
+ void rotateBoundingBox(BoundingBox &box, const QQuaternion &rotation);
+ void selectRecursive(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer, Q3DSNode *node,
+ int &index, int depth);
};
}
diff --git a/src/Authoring/Studio/Render/Q3DSTranslation.cpp b/src/Authoring/Studio/Render/Q3DSTranslation.cpp
index 4f923e9e..c4c82825 100644
--- a/src/Authoring/Studio/Render/Q3DSTranslation.cpp
+++ b/src/Authoring/Studio/Render/Q3DSTranslation.cpp
@@ -393,7 +393,6 @@ static inline float makeNiceRotation(float inAngle)
return retval;
}
-
Q3DSTranslation::Q3DSTranslation(Q3DStudioRenderer &inRenderer,
const QSharedPointer<Q3DSUipPresentation> &presentation)
: m_studioRenderer(inRenderer)
@@ -620,17 +619,17 @@ QVector4D Q3DSTranslation::calculateWidgetArrowDrag(const QPoint &mousePos,
// Find the direction of the drag and the best plane to map against that is parallel
// to the direction vector
- if (m_selectionWidget.isXAxis(m_pickedWidget)) {
+ if (m_manipulationWidget.isXAxis(m_pickedWidget)) {
direction = getXAxis(m_dragNodeGlobalTransform);
plane1 = getYAxis(m_dragNodeGlobalTransform);
plane2 = getZAxis(m_dragNodeGlobalTransform);
distanceMultiplier = -1.f;
- } else if (m_selectionWidget.isYAxis(m_pickedWidget)) {
+ } else if (m_manipulationWidget.isYAxis(m_pickedWidget)) {
plane1 = getXAxis(m_dragNodeGlobalTransform);
direction = getYAxis(m_dragNodeGlobalTransform);
plane2 = getZAxis(m_dragNodeGlobalTransform);
distanceMultiplier = -1.f;
- } else if (m_selectionWidget.isZAxis(m_pickedWidget)) {
+ } else if (m_manipulationWidget.isZAxis(m_pickedWidget)) {
plane1 = getXAxis(m_dragNodeGlobalTransform);
plane2 = getYAxis(m_dragNodeGlobalTransform);
direction = getZAxis(m_dragNodeGlobalTransform);
@@ -1359,13 +1358,7 @@ void Q3DSTranslation::enableGradient()
}
}
-void Q3DSTranslation::disableSelectionWidget()
-{
- m_selectionWidget.destroy(m_presentation.data());
- m_selectedObject = nullptr;
-}
-
-void Q3DSTranslation::enableSelectionWidget(Qt3DSDMInstanceHandle instance)
+void Q3DSTranslation::selectObject(Qt3DSDMInstanceHandle instance)
{
Q3DSGraphObjectTranslator *translator = getOrCreateTranslator(instance);
if (!translator)
@@ -1373,6 +1366,23 @@ void Q3DSTranslation::enableSelectionWidget(Qt3DSDMInstanceHandle instance)
m_selectedObject = &translator->graphObject();
+ enableManipulationWidget();
+
+ const auto layer = layerForNode(m_selectedObject);
+ if (layer) {
+ m_selectionWidget.select(m_presentation.data(), layer,
+ static_cast<Q3DSNode *>(m_selectedObject));
+ }
+}
+
+void Q3DSTranslation::unselectObject()
+{
+ m_selectedObject = nullptr;
+ m_manipulationWidget.destroyManipulators();
+}
+
+void Q3DSTranslation::enableManipulationWidget()
+{
if (!m_selectedObject || (m_selectedObject->type() != Q3DSGraphObject::Model
&& m_selectedObject->type() != Q3DSGraphObject::Alias
&& m_selectedObject->type() != Q3DSGraphObject::Group
@@ -1380,7 +1390,7 @@ void Q3DSTranslation::enableSelectionWidget(Qt3DSDMInstanceHandle instance)
&& m_selectedObject->type() != Q3DSGraphObject::Camera
&& m_selectedObject->type() != Q3DSGraphObject::Text
&& m_selectedObject->type() != Q3DSGraphObject::Component)) {
- m_selectionWidget.setEyeballEnabled(false);
+ m_manipulationWidget.setEyeballEnabled(false);
}
updateForegroundLayerProperties();
@@ -1632,33 +1642,35 @@ void Q3DSTranslation::updateForegroundLayerProperties()
void Q3DSTranslation::updateSelectionWidgetProperties()
{
if (m_selectedObject) {
- if (!m_selectionWidget.isCreated()) {
+ if (!m_manipulationWidget.hasManipulators()) {
createSelectionWidget();
} else if (g_StudioApp.GetToolMode() != m_toolMode) {
- m_selectionWidget.destroy(m_presentation.data());
+ m_manipulationWidget.destroyManipulators();
createSelectionWidget();
}
- m_selectionWidget.setEyeballEnabled(false);
+ m_manipulationWidget.setEyeballEnabled(false);
if (m_foregroundPickingCamera) {
- m_selectionWidget.applyProperties(m_selectedObject, m_foregroundPickingCamera,
- m_foregroundLayer, m_size);
+ m_manipulationWidget.applyProperties(m_selectedObject, m_foregroundPickingCamera,
+ m_foregroundLayer, m_size);
}
}
+
+ m_selectionWidget.update();
}
void Q3DSTranslation::createSelectionWidget()
{
m_toolMode = g_StudioApp.GetToolMode();
if (m_toolMode == STUDIO_TOOLMODE_MOVE) {
- m_selectionWidget.create(m_presentation.data(), m_foregroundPickingLayer,
- SelectionWidgetType::Translation);
+ m_manipulationWidget.createManipulators(m_presentation.data(), m_foregroundPickingLayer,
+ ManipulationWidgetType::Translation);
} else if (m_toolMode == STUDIO_TOOLMODE_ROTATE) {
- m_selectionWidget.create(m_presentation.data(), m_foregroundPickingLayer,
- SelectionWidgetType::Rotation);
+ m_manipulationWidget.createManipulators(m_presentation.data(), m_foregroundPickingLayer,
+ ManipulationWidgetType::Rotation);
} else if (m_toolMode == STUDIO_TOOLMODE_SCALE) {
- m_selectionWidget.create(m_presentation.data(), m_foregroundPickingLayer,
- SelectionWidgetType::Scale);
+ m_manipulationWidget.createManipulators(m_presentation.data(), m_foregroundPickingLayer,
+ ManipulationWidgetType::Scale);
}
}
@@ -1703,7 +1715,7 @@ void Q3DSTranslation::prepareWidgetDrag(const QPoint &mousePos, Q3DSGraphObject
prepareDrag(mousePos);
m_pickedWidget = obj;
- m_selectionWidget.setColor(m_pickedWidget, Qt::yellow);
+ m_manipulationWidget.setColor(m_pickedWidget, Qt::yellow);
}
void Q3DSTranslation::endDrag(bool dragReset, CUpdateableDocumentEditor &inEditor)
@@ -1739,8 +1751,8 @@ void Q3DSTranslation::endDrag(bool dragReset, CUpdateableDocumentEditor &inEdito
void Q3DSTranslation::endPickWidget()
{
if (m_pickedWidget) {
- m_selectionWidget.resetColor(m_pickedWidget);
- m_selectionWidget.resetScale(m_pickedWidget);
+ m_manipulationWidget.resetColor(m_pickedWidget);
+ m_manipulationWidget.resetScale(m_pickedWidget);
}
m_pickedWidget = nullptr;
}
@@ -1817,16 +1829,17 @@ void Q3DSTranslation::translateAlongWidget(const QPoint &inMouseCoords,
Q3DSNode *node = m_dragTranslator->graphObject<Q3DSNode>();
- if (m_selectionWidget.isXAxis(m_pickedWidget) || m_selectionWidget.isYAxis(m_pickedWidget)
- || m_selectionWidget.isZAxis(m_pickedWidget)) {
+ if (m_manipulationWidget.isXAxis(m_pickedWidget)
+ || m_manipulationWidget.isYAxis(m_pickedWidget)
+ || m_manipulationWidget.isZAxis(m_pickedWidget)) {
m_currentDragState.t = calculateWidgetArrowDrag(mousePos).toVector3D();
} else {
QVector3D planeNormal;
- if (m_selectionWidget.isXYPlane(m_pickedWidget))
+ if (m_manipulationWidget.isXYPlane(m_pickedWidget))
planeNormal = getZAxis(m_dragNodeGlobalTransform);
- else if (m_selectionWidget.isYZPlane(m_pickedWidget))
+ else if (m_manipulationWidget.isYZPlane(m_pickedWidget))
planeNormal = getXAxis(m_dragNodeGlobalTransform);
- else if (m_selectionWidget.isZXPlane(m_pickedWidget))
+ else if (m_manipulationWidget.isZXPlane(m_pickedWidget))
planeNormal = getYAxis(m_dragNodeGlobalTransform);
m_currentDragState.t = mousePointToPlaneIntersection(
mousePos, m_dragCamera, node, m_beginDragState.t, planeNormal, false);
@@ -1907,16 +1920,17 @@ void Q3DSTranslation::scaleAlongWidget(const QPoint &inOriginalCoords, const QPo
Q3DSNode *node = m_dragTranslator->graphObject<Q3DSNode>();
QVector3D scaleVec(1.f, 1.f, 1.f);
- if (m_selectionWidget.isXAxis(m_pickedWidget) || m_selectionWidget.isYAxis(m_pickedWidget)
- || m_selectionWidget.isZAxis(m_pickedWidget)) {
+ if (m_manipulationWidget.isXAxis(m_pickedWidget)
+ || m_manipulationWidget.isYAxis(m_pickedWidget)
+ || m_manipulationWidget.isZAxis(m_pickedWidget)) {
float distance = calculateWidgetArrowDrag(mousePos).w();
float scaleAmount = distance / scaleRatio;
float magnitude = 1.f + scaleAmount;
- if (m_selectionWidget.isXAxis(m_pickedWidget))
+ if (m_manipulationWidget.isXAxis(m_pickedWidget))
scaleVec = QVector3D(magnitude, 1.f, 1.f);
- else if (m_selectionWidget.isYAxis(m_pickedWidget))
+ else if (m_manipulationWidget.isYAxis(m_pickedWidget))
scaleVec = QVector3D(1.f, magnitude, 1.f);
- else if (m_selectionWidget.isZAxis(m_pickedWidget))
+ else if (m_manipulationWidget.isZAxis(m_pickedWidget))
scaleVec = QVector3D(1.f, 1.f, magnitude);
} else {
float xScale = 1.f;
@@ -1924,7 +1938,7 @@ void Q3DSTranslation::scaleAlongWidget(const QPoint &inOriginalCoords, const QPo
float zScale = 1.f;
QVector3D planeNormal;
- if (m_selectionWidget.isXYPlane(m_pickedWidget)) {
+ if (m_manipulationWidget.isXYPlane(m_pickedWidget)) {
planeNormal = getZAxis(m_dragNodeGlobalTransform);
xScale = 1.f + calculateWidgetArrowDrag(
mousePos, planeNormal, getXAxis(m_dragNodeGlobalTransform)).w()
@@ -1933,7 +1947,7 @@ void Q3DSTranslation::scaleAlongWidget(const QPoint &inOriginalCoords, const QPo
mousePos, planeNormal, getYAxis(m_dragNodeGlobalTransform)).w()
/ -scaleRatio;
scaleVec = QVector3D(xScale, yScale, 1.f);
- } else if (m_selectionWidget.isYZPlane(m_pickedWidget)) {
+ } else if (m_manipulationWidget.isYZPlane(m_pickedWidget)) {
planeNormal = getXAxis(m_dragNodeGlobalTransform);
yScale = 1.f + calculateWidgetArrowDrag(
mousePos, planeNormal, getYAxis(m_dragNodeGlobalTransform)).w()
@@ -1942,7 +1956,7 @@ void Q3DSTranslation::scaleAlongWidget(const QPoint &inOriginalCoords, const QPo
mousePos, planeNormal, getZAxis(m_dragNodeGlobalTransform)).w()
/ scaleRatio;
scaleVec = QVector3D(1.f, yScale, zScale);
- } else if (m_selectionWidget.isZXPlane(m_pickedWidget)) {
+ } else if (m_manipulationWidget.isZXPlane(m_pickedWidget)) {
planeNormal = getYAxis(m_dragNodeGlobalTransform);
xScale = 1.f + calculateWidgetArrowDrag(
mousePos, planeNormal, getXAxis(m_dragNodeGlobalTransform)).w()
@@ -2110,13 +2124,13 @@ void Q3DSTranslation::rotateAlongWidget(const QPoint &inOriginalCoords,
flipZTranslation(origRay);
QVector3D planeNormal;
- if (m_selectionWidget.isXYCircle(m_pickedWidget))
+ if (m_manipulationWidget.isXYCircle(m_pickedWidget))
planeNormal = getZAxis(m_dragNodeGlobalTransform);
- else if (m_selectionWidget.isYZCircle(m_pickedWidget))
+ else if (m_manipulationWidget.isYZCircle(m_pickedWidget))
planeNormal = getXAxis(m_dragNodeGlobalTransform);
- else if (m_selectionWidget.isZXCircle(m_pickedWidget))
+ else if (m_manipulationWidget.isZXCircle(m_pickedWidget))
planeNormal = getYAxis(m_dragNodeGlobalTransform);
- else if (m_selectionWidget.isCameraCircle(m_pickedWidget))
+ else if (m_manipulationWidget.isCameraCircle(m_pickedWidget))
planeNormal = getZAxis(cameraMatrix);
flipZTranslation(planeNormal);
diff --git a/src/Authoring/Studio/Render/Q3DSTranslation.h b/src/Authoring/Studio/Render/Q3DSTranslation.h
index 4c43109d..3109a4e4 100644
--- a/src/Authoring/Studio/Render/Q3DSTranslation.h
+++ b/src/Authoring/Studio/Render/Q3DSTranslation.h
@@ -52,6 +52,7 @@
#include "foundation/Qt3DSOption.h"
#include "Q3DSEditCamera.h"
#include "Q3DSSelectionWidget.h"
+#include "Q3DSManipulationWidget.h"
#include "Q3DSVisualAidWidget.h"
#include "StudioEnums.h"
@@ -88,6 +89,9 @@ private:
void updateForegroundLayerProperties();
void updateSelectionWidgetProperties();
void createSelectionWidget();
+ void enableManipulationWidget();
+ void disableVisualAids();
+ void enableVisualAids();
struct TranslatorGetDirty
{
@@ -210,8 +214,9 @@ private:
long m_toolMode = STUDIO_TOOLMODE_MOVE;
Q3DSGraphObject *m_pickedWidget = nullptr;
QColor m_pickedWidgetColor;
- Q3DSSelectionWidget m_selectionWidget;
EditCameraTypes m_oldCameraType = EditCameraTypes::SceneCamera;
+ Q3DSManipulationWidget m_manipulationWidget;
+ Q3DSSelectionWidget m_selectionWidget;
QVector<Q3DSVisualAidWidget> m_visualAids;
quint64 m_visualAidIndex = 0;
@@ -258,10 +263,8 @@ public:
void enableForegroundLayer();
void disableGradient();
void enableGradient();
- void disableSelectionWidget();
- void enableSelectionWidget(qt3dsdm::Qt3DSDMInstanceHandle instance);
- void disableVisualAids();
- void enableVisualAids();
+ void selectObject(qt3dsdm::Qt3DSDMInstanceHandle instance);
+ void unselectObject();
void releaseTranslator(Q3DSGraphObjectTranslator *translator);
void clearDirtySet();
void markDirty(qt3dsdm::Qt3DSDMInstanceHandle instance);
diff --git a/src/Authoring/Studio/Render/Q3DSVisualAidWidget.cpp b/src/Authoring/Studio/Render/Q3DSVisualAidWidget.cpp
index 11a21293..c808b89e 100644
--- a/src/Authoring/Studio/Render/Q3DSVisualAidWidget.cpp
+++ b/src/Authoring/Studio/Render/Q3DSVisualAidWidget.cpp
@@ -126,7 +126,8 @@ Q3DSVisualAidWidget::Q3DSVisualAidWidget(Q3DSUipPresentation *presentation, Q3DS
"<Passes><Pass></Pass></Passes>\n");
if (m_type == VisualAidType::Camera) {
- const QString name = QStringLiteral("StudioFrustum") + QString::number(id);
+ const QString name = QStringLiteral("StudioVisualAidWidgetFrustum")
+ + QString::number(id);
m_wireframeMaterial = createWidgetCustomMaterial(presentation, name, cameraMaterial,
Qt::white, 0.25f);
if (m_wireframeMaterial) {
@@ -136,7 +137,8 @@ Q3DSVisualAidWidget::Q3DSVisualAidWidget(Q3DSUipPresentation *presentation, Q3DS
m_wireframe->appendChildNode(m_wireframeMaterial);
}
} else if (m_type == VisualAidType::DirectionalLight) {
- const QString name = QStringLiteral("StudioDirectionalLight") + QString::number(id);
+ const QString name = QStringLiteral("StudioVisualAidWidgetDirectionalLight")
+ + QString::number(id);
m_wireframeMaterial = createWidgetCustomMaterial(presentation, name, basicMaterial,
Qt::white, 0.25f);
if (m_wireframeMaterial) {
@@ -146,7 +148,8 @@ Q3DSVisualAidWidget::Q3DSVisualAidWidget(Q3DSUipPresentation *presentation, Q3DS
m_wireframe->appendChildNode(m_wireframeMaterial);
}
} else if (m_type == VisualAidType::PointLight) {
- const QString name = QStringLiteral("StudioPointLight") + QString::number(id);
+ const QString name = QStringLiteral("StudioVisualAidWidgetPointLight")
+ + QString::number(id);
m_wireframeMaterial = createWidgetCustomMaterial(presentation, name, basicMaterial,
Qt::white, 0.25f);
if (m_wireframeMaterial) {
@@ -156,7 +159,8 @@ Q3DSVisualAidWidget::Q3DSVisualAidWidget(Q3DSUipPresentation *presentation, Q3DS
m_wireframe->appendChildNode(m_wireframeMaterial);
}
} else if (m_type == VisualAidType::AreaLight) {
- const QString name = QStringLiteral("StudioAreaLight") + QString::number(id);
+ const QString name = QStringLiteral("StudioVisualAidWidgetAreaLight")
+ + QString::number(id);
m_wireframeMaterial = createWidgetCustomMaterial(presentation, name, basicMaterial,
Qt::white, 0.25f);
if (m_wireframeMaterial) {
@@ -167,7 +171,8 @@ Q3DSVisualAidWidget::Q3DSVisualAidWidget(Q3DSUipPresentation *presentation, Q3DS
}
}
- const QString iconName = QStringLiteral("StudioIcon") + QString::number(id);
+ const QString iconName = QStringLiteral("StudioVisualAidWidgetIcon")
+ + QString::number(id);
m_iconMaterial = createWidgetCustomMaterial(presentation, iconName, billboardMaterial,
Qt::white, 0.25f);
if (m_iconMaterial) {
@@ -185,10 +190,12 @@ Q3DSVisualAidWidget::Q3DSVisualAidWidget(Q3DSUipPresentation *presentation, Q3DS
m_iconMaterial->notifyPropertyChanges(imageChange);
}
- const QString colBoxName = QStringLiteral("StudioCollisionBox") + QString::number(id);
+ const QString colBoxName = QStringLiteral("StudioVisualAidWidgetCollisionBox")
+ + QString::number(id);
m_collisionBox = createWidgetModel(presentation, pickingLayer, colBoxName,
QStringLiteral("#Cube"), QVector3D(0.5f, 0.5f, 0.5f));
- m_collisionBox->appendChildNode(createWidgetDefaultMaterial(presentation, colBoxName));
+ m_collisionBox->appendChildNode(createWidgetDefaultMaterial(presentation, colBoxName,
+ Qt::white, 0.0f));
if (!isCreated()) {
destroy();
diff --git a/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp b/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp
index 4a02389a..96936816 100644
--- a/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp
+++ b/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp
@@ -41,7 +41,7 @@ void adjustRotationLeftToRight(QMatrix4x4 *m)
Q3DSModelNode *createWidgetModel(Q3DSUipPresentation *presentation, Q3DSLayerNode *layer,
const QString &name, const QString &mesh,
- const QVector3D &scale, bool wireframe = false)
+ const QVector3D &scale, bool wireframe)
{
Q3DSModelNode *model = presentation->newObject<Q3DSModelNode>(
(name + QLatin1Char('_')).toUtf8().constData());
@@ -101,12 +101,14 @@ Q3DSDefaultMaterial *createWidgetDefaultMaterial(Q3DSUipPresentation *presentati
const QColor &color,
float opacity)
{
- const QByteArray matName = (name + QLatin1String("Material_")).toUtf8();
- const QByteArray matId = '#' + matName;
+ const QByteArray matId = (name + QLatin1String("Material_")).toUtf8();
+ Q3DSPropertyChangeList list;
Q3DSDefaultMaterial *defMat = presentation->newObject<Q3DSDefaultMaterial>(matId);
- defMat->setDiffuse(color);
- defMat->setOpacity(opacity);
+ list.append(defMat->setDiffuse(color));
+ list.append(defMat->setOpacity(opacity * 100.0f));
+ list.append(defMat->setShaderLighting(Q3DSDefaultMaterial::ShaderLighting::NoShaderLighting));
+ defMat->notifyPropertyChanges(list);
return defMat;
}
diff --git a/src/Authoring/Studio/Render/Q3DSWidgetUtils.h b/src/Authoring/Studio/Render/Q3DSWidgetUtils.h
index a46af2da..f789ef2e 100644
--- a/src/Authoring/Studio/Render/Q3DSWidgetUtils.h
+++ b/src/Authoring/Studio/Render/Q3DSWidgetUtils.h
@@ -46,7 +46,6 @@ Q3DSDefaultMaterial *createWidgetDefaultMaterial(Q3DSUipPresentation *presentati
const QString &name,
const QColor &color = Qt::white,
float opacity = 1.0f);
-
}
#endif // Q3DSWIDGETUTILS_H
diff --git a/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp b/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
index 9deee4d8..a5398df5 100644
--- a/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
+++ b/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
@@ -1301,10 +1301,10 @@ void Q3DStudioRenderer::onSelectionChange(Q3DStudio::SSelectedValue selected)
if (!instances.empty()) {
for (auto &instance : instances) {
if (g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->IsInstance(instance))
- m_translation->enableSelectionWidget(instance);
+ m_translation->selectObject(instance);
}
} else {
- m_translation->disableSelectionWidget();
+ m_translation->unselectObject();
}
}
diff --git a/src/Authoring/Studio/meshes.qrc b/src/Authoring/Studio/meshes.qrc
index 24d91a4f..2f6250d4 100644
--- a/src/Authoring/Studio/meshes.qrc
+++ b/src/Authoring/Studio/meshes.qrc
@@ -18,5 +18,6 @@
<file alias="res/PointLight.mesh">../../../res/PointLight.mesh</file>
<file alias="res/AreaLight.mesh">../../../res/AreaLight.mesh</file>
<file alias="res/Icon.mesh">../../../res/Icon.mesh</file>
+ <file alias="res/Selection.mesh">../../../res/Selection.mesh</file>
</qresource>
</RCC>