summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-02-25 17:46:47 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-03-04 13:07:56 +0000
commit567b488eefd0519eb0d33e66cfdae28559100e4e (patch)
tree0a688d74518128524bfada1da5e4565a7a54624a
parent845ca06f3c3c9cdaf17ffd75a0a1ebdc3d09a443 (diff)
Fit selected support
Also added an intermediate widget between glWidget and player window, which is always located at 0,0 to avoid glWidget bouncing around due to internal scroll range resets during geometry setting. Task-number: QT3DS-3072 Change-Id: Ife6b628f69d45b156f7c453f8cc3dd010ecedef2 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Antti Määttä <antti.maatta@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r--src/Authoring/Studio/Render/Q3DSEditCamera.cpp17
-rw-r--r--src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp180
-rw-r--r--src/Authoring/Studio/Render/Q3DSSelectionWidget.h15
-rw-r--r--src/Authoring/Studio/Render/Q3DSTranslation.cpp64
-rw-r--r--src/Authoring/Studio/Render/Q3DSTranslation.h2
-rw-r--r--src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp168
-rw-r--r--src/Authoring/Studio/Render/Q3DSWidgetUtils.h22
-rw-r--r--src/Authoring/Studio/Render/Q3DStudioRenderer.cpp11
-rw-r--r--src/Authoring/Studio/UI/Q3DSPlayerWnd.cpp84
-rw-r--r--src/Authoring/Studio/UI/Q3DSPlayerWnd.h6
-rw-r--r--src/Authoring/Studio/UI/SceneView.cpp38
-rw-r--r--src/Authoring/Studio/UI/SceneView.h1
12 files changed, 340 insertions, 268 deletions
diff --git a/src/Authoring/Studio/Render/Q3DSEditCamera.cpp b/src/Authoring/Studio/Render/Q3DSEditCamera.cpp
index b3937de8..cebec681 100644
--- a/src/Authoring/Studio/Render/Q3DSEditCamera.cpp
+++ b/src/Authoring/Studio/Render/Q3DSEditCamera.cpp
@@ -30,7 +30,7 @@
namespace Q3DStudio {
-static const qreal g_defaultRadius = qSin(qDegreesToRadians(g_editCameraFOV) / 2.) * 600.;
+static const qreal defaultEditCameraRadius = qSin(qDegreesToRadians(g_editCameraFOV) / 2.) * 600.;
QMatrix4x4 SEditCameraPersistentInformation::rotationMatrix() const
{
@@ -74,11 +74,18 @@ void SEditCameraPersistentInformation::applyToCamera(Q3DSCameraNode &camera,
if (m_cameraType == EditCameraTypes::Perspective) {
changeList.append(camera.setFov(g_editCameraFOV));
changeList.append(camera.setOrthographic(false));
+ changeList.append(camera.setZoom(1.f));
// Handle perspective zooming by adjusting the camera position, as scaling projection
// matrix after the fact doesn't work correctly for our purposes
- posAdjust *= zoomFactor(viewport);
+ qreal factor = zoomFactor(viewport);
+ if (factor > 1)
+ posAdjust *= float(factor);
+ else
+ posAdjust *= -1.f + (2.f * factor);
} else {
changeList.append(camera.setOrthographic(true));
+ // Orthogonal views can't zoom by adjusting position
+ changeList.append(camera.setZoom(zoomFactor(viewport)));
}
QVector3D pos = m_position - posAdjust;
@@ -94,10 +101,6 @@ void SEditCameraPersistentInformation::applyToCamera(Q3DSCameraNode &camera,
}
changeList.append(camera.setPosition(pos));
- if (m_cameraType != EditCameraTypes::Perspective) {
- // Orthogonal views can't zoom by adjusting position
- changeList.append(camera.setZoom(zoomFactor(viewport)));
- }
changeList.append(camera.setRotation(QVector3D(ry, rx, 0)));
if (!changeList.isEmpty())
@@ -111,7 +114,7 @@ qreal SEditCameraPersistentInformation::zoomFactor(const QSizeF &viewport) const
qreal theViewport = qMin(viewport.width(), viewport.height());
zoom = 2. * m_viewRadius / theViewport;
} else {
- zoom = m_viewRadius / g_defaultRadius;
+ zoom = m_viewRadius / defaultEditCameraRadius;
}
return zoom;
}
diff --git a/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp b/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp
index 36506a7e..af8122f9 100644
--- a/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp
+++ b/src/Authoring/Studio/Render/Q3DSSelectionWidget.cpp
@@ -29,150 +29,9 @@
#include "Q3DSSelectionWidget.h"
#include "Q3DSWidgetUtils.h"
#include <QtCore/qmath.h>
-#include <Qt3DCore/qtransform.h>
-#include <Qt3DRender/qattribute.h>
-#include <Qt3DRender/qbuffer.h>
namespace Q3DStudio {
-Q3DSSelectionWidget::BoundingBox Q3DSSelectionWidget::calculateLocalBoundingBox(
- Q3DSModelNode *model)
-{
- // 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;
- }
-
- 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);
- }
-
- m_boundingBoxCache[srcPath] = box;
- return box;
-}
-
-Q3DSSelectionWidget::BoundingBox Q3DSSelectionWidget::calculateBoundingBox(
- Q3DSGraphObject *graphObject)
-{
- 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);
- }
-
- for (Q3DSGraphObject *child = graphObject->firstChild(); child != nullptr;
- child = child->nextSibling()) {
- if (!child->isNode())
- continue;
-
- Q3DSNode *childNode = static_cast<Q3DSNode *>(child);
- BoundingBox childBB = calculateBoundingBox(child);
- if ((childBB.max - childBB.min).length() > 0) {
- const QVector3D scale = childNode->scale();
- childBB.min *= scale;
- childBB.max *= scale;
-
- rotateBoundingBox(childBB, calculateRotationQuaternion(childNode->rotation(),
- childNode->orientation()));
-
- const QVector3D position = childNode->position();
- 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());
- }
- }
-
- return boundingBox;
-}
-
-void Q3DSSelectionWidget::rotateBoundingBox(BoundingBox &box, const QQuaternion &rotation)
-{
- 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::select(Q3DSUipPresentation *presentation, Q3DSNode *node)
{
m_presentation = presentation;
@@ -232,26 +91,25 @@ void Q3DSSelectionWidget::update()
if (selection.visible) {
const auto boundingBox = selection.boundingBox;
- 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) {
- QMatrix4x4 rotMat = generateRotationMatrix(node->rotation(),
- node->rotationOrder());
- if (node->orientation() == Q3DSNode::RightHanded)
- adjustRotationLeftToRight(&rotMat);
- QVector3D offset = rotMat * (boundingBox.min + bbSize * 0.5f) * node->scale();
-
- model->notifyPropertyChanges({
- model->setPosition(node->position() + offset),
- model->setRotation(node->rotation()),
- model->setScale(node->scale() * bbSize * 0.5f),
- model->setRotationOrder(node->rotationOrder()),
- model->setOrientation(node->orientation()),
- model->setEyeballEnabled(true)
- });
- }
+ QVector3D bbSize;
+ QVector3D bbOffset;
+ calculateBoundingBoxOffsetAndSize(node, boundingBox, bbOffset, bbSize);
+
+ QVector3D scale = node->scale() * bbSize;
+ if (qFuzzyIsNull(scale.x()))
+ scale.setX(0.00000001f);
+ if (qFuzzyIsNull(scale.y()))
+ scale.setY(0.00000001f);
+ if (qFuzzyIsNull(scale.z()))
+ scale.setZ(0.00000001f);
+ model->notifyPropertyChanges({
+ model->setPosition(node->position() + bbOffset),
+ model->setRotation(node->rotation()),
+ model->setScale(node->scale() * bbSize),
+ model->setRotationOrder(node->rotationOrder()),
+ model->setOrientation(node->orientation()),
+ model->setEyeballEnabled(true)
+ });
} else if (model->eyeballEnabled()) {
model->notifyPropertyChanges({ model->setEyeballEnabled(false) });
}
diff --git a/src/Authoring/Studio/Render/Q3DSSelectionWidget.h b/src/Authoring/Studio/Render/Q3DSSelectionWidget.h
index efbc32e3..036bc550 100644
--- a/src/Authoring/Studio/Render/Q3DSSelectionWidget.h
+++ b/src/Authoring/Studio/Render/Q3DSSelectionWidget.h
@@ -30,6 +30,7 @@
#define Q3DSSELECTIONWIDGET_H
#include "q3dsruntime2api_p.h"
+#include "Q3DSWidgetUtils.h"
namespace Q3DStudio {
@@ -43,16 +44,6 @@ public:
private:
Q3DSUipPresentation *m_presentation = nullptr;
- 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());
- };
-
struct Selection
{
Q3DSNode *node = nullptr;
@@ -61,12 +52,8 @@ private:
bool visible = false;
};
- QHash<QString, BoundingBox> m_boundingBoxCache;
QHash<Q3DSNode *, Selection> m_selections;
- BoundingBox calculateLocalBoundingBox(Q3DSModelNode *model);
- BoundingBox calculateBoundingBox(Q3DSGraphObject *graphObject);
- void rotateBoundingBox(BoundingBox &box, const QQuaternion &rotation);
void selectRecursive(Q3DSUipPresentation *presentation, Q3DSNode *node, int &index, int depth);
};
diff --git a/src/Authoring/Studio/Render/Q3DSTranslation.cpp b/src/Authoring/Studio/Render/Q3DSTranslation.cpp
index b7beed59..2d2acff2 100644
--- a/src/Authoring/Studio/Render/Q3DSTranslation.cpp
+++ b/src/Authoring/Studio/Render/Q3DSTranslation.cpp
@@ -33,7 +33,6 @@
#include "Q3DSEditCamera.h"
#include "Q3DSInputStreamFactory.h"
#include "Q3DSTranslators.h"
-#include "Q3DSWidgetUtils.h"
#include "StudioApp.h"
#include "Core.h"
@@ -2167,4 +2166,67 @@ void Q3DSTranslation::rotateAlongWidget(const QPoint &inOriginalCoords,
inEditor.FireImmediateRefresh(m_doc.GetSelectedInstance());
}
+void Q3DSTranslation::editCameraZoomToFit()
+{
+ qt3dsdm::Qt3DSDMInstanceHandle instance = m_doc.GetSelectedInstance();
+
+ // If we aren't pointed at a node then bounce up the asset graph until we are
+ auto translator = getOrCreateTranslator(instance);
+ while (instance.Valid() && translator && !translator->graphObject().isNode()) {
+ instance = m_assetGraph.GetParent(instance);
+ translator = getOrCreateTranslator(instance);
+ }
+ // If we still aren't pointed at a node then use the active layer
+ if (!instance.Valid() || !translator || !translator->graphObject().isNode()) {
+ instance = m_doc.GetActiveLayer();
+ translator = getOrCreateTranslator(instance);
+ }
+ // If we *still* aren't pointed at a node then bail
+ if (!translator || !translator->graphObject().isNode())
+ return;
+
+ Q3DSNode &node = static_cast<Q3DSNode &>(translator->graphObject());
+ Q3DSNode *parent = static_cast<Q3DSNode *>(node.parent());
+ Q3DSNodeAttached *parentAttached = parent->attached<Q3DSNodeAttached>();
+
+ QVector3D nodePos;
+ QVector3D nodeScale;
+ if (node.type() != Q3DSGraphObject::Layer) {
+ nodePos = node.position();
+ nodeScale = node.scale();
+ } else {
+ // Layers do not have meaningful transforms
+ nodeScale = QVector3D(1.f, 1.f, 1.f);
+ }
+
+ BoundingBox box = calculateBoundingBox(&node);
+ QVector3D bbOffset;
+ QVector3D bbSize;
+ calculateBoundingBoxOffsetAndSize(&node, box, bbOffset, bbSize);
+ float bbExtent = (bbSize * nodeScale).length();
+ if (bbExtent <= 0) {
+ // Fake extent, about suitable for default box
+ bbExtent = 150.f;
+ }
+
+ // This provides good fit with our zoom handling
+ if (m_editCameraInfo.m_cameraType != EditCameraTypes::Perspective) {
+ float viewportDim = float(qMax(m_size.width(), m_size.height())
+ / qMin(m_size.width(), m_size.height()));
+ m_editCameraInfo.m_viewRadius = bbExtent * 2.f / viewportDim;
+ } else {
+ m_editCameraInfo.m_viewRadius = bbExtent / 2.f;
+ if (m_editCameraInfo.m_viewRadius > 200.f)
+ m_editCameraInfo.m_viewRadius = 200.f + 2.0f * (m_editCameraInfo.m_viewRadius - 200.f);
+ }
+
+ QVector3D center = nodePos + bbOffset;
+ flipZTranslation(center);
+ center = parentAttached->globalTransform * center;
+ flipZTranslation(center);
+
+ // Center the edit camera so that it points directly at the bounds center point
+ m_editCameraInfo.m_position = center - m_editCameraInfo.front() * 600.f;
+}
+
}
diff --git a/src/Authoring/Studio/Render/Q3DSTranslation.h b/src/Authoring/Studio/Render/Q3DSTranslation.h
index 61dc1ab9..671deb7e 100644
--- a/src/Authoring/Studio/Render/Q3DSTranslation.h
+++ b/src/Authoring/Studio/Render/Q3DSTranslation.h
@@ -55,6 +55,7 @@
#include "Q3DSManipulationWidget.h"
#include "Q3DSVisualAidWidget.h"
#include "StudioEnums.h"
+#include "Q3DSWidgetUtils.h"
namespace Q3DStudio
{
@@ -311,6 +312,7 @@ public:
CUpdateableDocumentEditor &inEditor, bool inLockToAxis);
void rotateAlongWidget(const QPoint &inOriginalCoords, const QPoint &inMouseCoords,
CUpdateableDocumentEditor &inEditor);
+ void editCameraZoomToFit();
};
}
diff --git a/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp b/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp
index 027c354e..8f57e3d2 100644
--- a/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp
+++ b/src/Authoring/Studio/Render/Q3DSWidgetUtils.cpp
@@ -27,9 +27,14 @@
****************************************************************************/
#include "q3dsruntime2api_p.h"
+#include "Q3DSWidgetUtils.h"
+
#include "qmath.h"
#include "Qt3DCore/qtransform.h"
#include <Qt3DRender/qcamera.h>
+#include <Qt3DRender/qattribute.h>
+#include <Qt3DRender/qbuffer.h>
+#include <Qt3DCore/qtransform.h>
namespace Q3DStudio {
@@ -399,4 +404,167 @@ Q3DSDefaultMaterial *createWidgetDefaultMaterial(Q3DSUipPresentation *presentati
return defMat;
}
+void rotateBoundingBox(Q3DStudio::BoundingBox &box, const QQuaternion &rotation)
+{
+ 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());
+ }}
+
+BoundingBox calculateLocalBoundingBox(Q3DSModelNode *model)
+{
+ static QHash<QString, BoundingBox> boundingBoxCache;
+
+ // TODO: Pre-calculate bounding boxes to prevent lag upon first selection
+ const QString srcPath = model->sourcePath();
+ if (boundingBoxCache.contains(srcPath))
+ return boundingBoxCache[srcPath];
+
+ BoundingBox box;
+
+ const MeshList meshList = model->mesh();
+ if (meshList.empty()) {
+ box.setEmpty();
+ 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);
+ box.setEmpty();
+ return box;
+ }
+
+ 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);
+ }
+
+ boundingBoxCache[srcPath] = box;
+ return box;
+}
+
+BoundingBox calculateBoundingBox(Q3DSGraphObject *graphObject)
+{
+ BoundingBox boundingBox;
+ if (graphObject->type() == Q3DSNode::Type::Model) {
+ boundingBox = calculateLocalBoundingBox(static_cast<Q3DSModelNode *>(graphObject));
+ } else if (graphObject->type() == Q3DSGraphObject::Type::Camera
+ || graphObject->type() == Q3DSGraphObject::Type::Light) {
+ float dim = 50.f;
+ boundingBox.min = QVector3D(-dim, -dim, -dim);
+ boundingBox.max = QVector3D(dim, dim, dim);
+ } else if (graphObject->childCount() == 0
+ || (graphObject->type() < Q3DSGraphObject::FirstNodeType)) {
+ boundingBox.setEmpty();
+ return boundingBox;
+ }
+
+ for (Q3DSGraphObject *child = graphObject->firstChild(); child != nullptr;
+ child = child->nextSibling()) {
+ if (!child->isNode() || child->type() == Q3DSGraphObject::Type::Camera
+ || child->type() == Q3DSGraphObject::Type::Light
+ || child->name().isEmpty()) {
+ continue;
+ }
+
+ Q3DSNode *childNode = static_cast<Q3DSNode *>(child);
+ BoundingBox childBB = calculateBoundingBox(child);
+ if (!childBB.isEmpty()) {
+ const QVector3D scale = childNode->scale();
+ childBB.min *= scale;
+ childBB.max *= scale;
+
+ rotateBoundingBox(childBB, calculateRotationQuaternion(childNode->rotation(),
+ childNode->orientation()));
+
+ const QVector3D position = childNode->position();
+ 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());
+ }
+ }
+
+ return boundingBox;
+}
+
+void calculateBoundingBoxOffsetAndSize(const Q3DSNode *node, const BoundingBox &boundingBox,
+ QVector3D &outOffset, QVector3D &outSize)
+{
+ outSize = QVector3D(qAbs(boundingBox.max.x() - boundingBox.min.x()),
+ qAbs(boundingBox.max.y() - boundingBox.min.y()),
+ qAbs(boundingBox.max.z() - boundingBox.min.z())) * 0.5f;
+
+ if (node->type() != Q3DSGraphObject::Layer) {
+ QMatrix4x4 rotMat = generateRotationMatrix(node->rotation(),
+ node->rotationOrder());
+ if (node->orientation() == Q3DSNode::RightHanded)
+ adjustRotationLeftToRight(&rotMat);
+ outOffset = rotMat * ((boundingBox.min + outSize) * node->scale());
+ }
+}
+
}
diff --git a/src/Authoring/Studio/Render/Q3DSWidgetUtils.h b/src/Authoring/Studio/Render/Q3DSWidgetUtils.h
index 15e45963..f67440da 100644
--- a/src/Authoring/Studio/Render/Q3DSWidgetUtils.h
+++ b/src/Authoring/Studio/Render/Q3DSWidgetUtils.h
@@ -33,6 +33,23 @@
namespace Q3DStudio {
+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());
+ bool isEmpty() { return min == max; }
+ void setEmpty() {
+ min = QVector3D(0, 0, 0);
+ max = QVector3D(0, 0, 0);
+ }
+ QVector3D center() { return min + (max - min) / 2.f; }
+ QVector3D extents() { return max - min; }
+};
+
void adjustRotationLeftToRight(QMatrix4x4 *m);
QQuaternion calculateRotationQuaternion(const QVector3D &rotation,
Q3DSNode::Orientation orientation);
@@ -65,6 +82,11 @@ Q3DSDefaultMaterial *createWidgetDefaultMaterial(Q3DSUipPresentation *presentati
const QString &name,
const QColor &color = Qt::white,
float opacity = 1.0f);
+BoundingBox calculateLocalBoundingBox(Q3DSModelNode *model);
+BoundingBox calculateBoundingBox(Q3DSGraphObject *graphObject);
+void rotateBoundingBox(BoundingBox &box, const QQuaternion &rotation);
+void calculateBoundingBoxOffsetAndSize(const Q3DSNode *node, const BoundingBox &boundingBox,
+ QVector3D &outOffset, QVector3D &outSize);
}
#endif // Q3DSWIDGETUTILS_H
diff --git a/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp b/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
index 78535a03..a67e4246 100644
--- a/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
+++ b/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
@@ -77,8 +77,8 @@ static SEditCameraDefinition g_editCameraDefinitions[] = {
{ EditCameraTypes::Orthographic, QVector3D(1, -1, -1), QObject::tr("Orthographic View") },
{ EditCameraTypes::Directional, QVector3D(0, -1, 0), QObject::tr("Top View") },
{ EditCameraTypes::Directional, QVector3D(0, 1, 0), QObject::tr("Bottom View") },
- { EditCameraTypes::Directional, QVector3D(1, 0, 0), QObject::tr("Left View") },
- { EditCameraTypes::Directional, QVector3D(-1, 0, 0), QObject::tr("Right View") },
+ { EditCameraTypes::Directional, QVector3D(-1, 0, 0), QObject::tr("Left View") },
+ { EditCameraTypes::Directional, QVector3D(1, 0, 0), QObject::tr("Right View") },
{ EditCameraTypes::Directional, QVector3D(0, 0, 1), QObject::tr("Front View") },
{ EditCameraTypes::Directional, QVector3D(0, 0, -1), QObject::tr("Back View") },
};
@@ -326,7 +326,12 @@ QT3DSI32 Q3DStudioRenderer::GetEditCamera() const
void Q3DStudioRenderer::EditCameraZoomToFit()
{
+ if (!m_translation || !editCameraEnabled())
+ return;
+
+ m_translation->editCameraZoomToFit();
+ RequestRender();
}
bool Q3DStudioRenderer::isMouseDown() const
@@ -478,7 +483,7 @@ void Q3DStudioRenderer::checkGuideInPresentationRect(qt3dsdm::Qt3DSDMGuideHandle
void Q3DStudioRenderer::drawRulersAndGuides(QPainter *painter)
{
- if (!m_guidesEnabled || editCameraEnabled())
+ if (!m_guidesEnabled || editCameraEnabled() || g_StudioApp.IsAuthorZoom())
return;
const int pixelRatio = int(m_parentPixelRatio);
diff --git a/src/Authoring/Studio/UI/Q3DSPlayerWnd.cpp b/src/Authoring/Studio/UI/Q3DSPlayerWnd.cpp
index 8aace2a7..24e5269c 100644
--- a/src/Authoring/Studio/UI/Q3DSPlayerWnd.cpp
+++ b/src/Authoring/Studio/UI/Q3DSPlayerWnd.cpp
@@ -69,10 +69,11 @@ T even(const T val)
Q3DSPlayerWnd::Q3DSPlayerWnd(QWidget *parent)
: QScrollArea(parent)
, m_mouseDown(false)
- , m_glWidget(new Q3DSPlayerWidget())
+ , m_clientWidget(new QWidget())
+ , m_glWidget(new Q3DSPlayerWidget(m_clientWidget))
, m_ViewMode(VIEW_SCENE)
{
- setWidget(m_glWidget);
+ setWidget(m_clientWidget);
setAcceptDrops(true);
RegisterForDnd(this);
@@ -128,8 +129,8 @@ void Q3DSPlayerWnd::mouseMoveEvent(QMouseEvent *event)
theModifierKeys = CHotKeys::MOUSE_MBUTTON | CHotKeys::GetCurrentKeyModifiers();
}
g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDrag(
- SceneDragSenderType::Matte, event->pos(), g_StudioApp.GetToolMode(),
- theModifierKeys);
+ SceneDragSenderType::Matte, mousePosToScenePos(event->pos()),
+ g_StudioApp.GetToolMode(), theModifierKeys);
}
}
@@ -173,8 +174,8 @@ void Q3DSPlayerWnd::mousePressEvent(QMouseEvent *event)
m_mouseDown = true;
g_StudioApp.SetToolMode(toolMode);
Q_EMIT Q3DSPlayerWnd::toolChanged();
- g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDown(SceneDragSenderType::Matte,
- event->pos(), toolMode);
+ g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDown(
+ SceneDragSenderType::Matte, mousePosToScenePos(event->pos()), toolMode);
}
} else {
if (btn == Qt::LeftButton || btn == Qt::RightButton) {
@@ -188,7 +189,8 @@ void Q3DSPlayerWnd::mousePressEvent(QMouseEvent *event)
toolMode = g_StudioApp.GetToolMode();
g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDown(
- SceneDragSenderType::SceneWindow, event->pos(), toolMode);
+ SceneDragSenderType::SceneWindow, mousePosToScenePos(event->pos()),
+ toolMode);
m_mouseDown = true;
}
}
@@ -239,7 +241,7 @@ void Q3DSPlayerWnd::mouseDoubleClickEvent(QMouseEvent *event)
}
g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDblClick(
- SceneDragSenderType::SceneWindow, event->pos());
+ SceneDragSenderType::SceneWindow, mousePosToScenePos(event->pos()));
}
bool Q3DSPlayerWnd::OnDragWithin(CDropSource &inSource)
@@ -368,24 +370,9 @@ void Q3DSPlayerWnd::onDragEnter()
m_objectRequestData.clear();
}
-//==============================================================================
-/**
- * SetPlayerWndPosition: Sets the position of the child player window
- *
- * Called when the view is scrolled to position the child player window
- *
- */
-//==============================================================================
-void Q3DSPlayerWnd::setWindowPosition()
-{
- recenterClient();
-}
-
-//==============================================================================
/**
* SetScrollRanges: Sets the scroll ranges when the view is being resized
*/
-//==============================================================================
void Q3DSPlayerWnd::setScrollRanges()
{
long theScrollWidth = 0;
@@ -411,44 +398,40 @@ void Q3DSPlayerWnd::setScrollRanges()
verticalScrollBar()->setVisible(true);
}
- // Setting scroll ranges will do some async geometry adjustments, so do the
- // recentering asynchronously as well
- QTimer::singleShot(0, [this]() {
- recenterClient();
- });
+ recenterClient();
}
-
-//==============================================================================
/**
* RecenterClient: Recenters the Client rect in the View's client area.
*/
-//==============================================================================
void Q3DSPlayerWnd::recenterClient()
{
QRect theViewRect = rect();
QSize theClientSize;
- QSize viewSize;
+ const QSize viewSize = theViewRect.size();
m_ClientRect = theViewRect;
- viewSize = theViewRect.size();
int rulerOffset = 0;
- if (!shouldHideScrollBars()) {
+ if (m_ViewMode != VIEW_EDIT) {
theClientSize = effectivePresentationSize();
- if (g_StudioApp.getRenderer().AreGuidesEnabled())
+ if (shouldDrawGuides())
rulerOffset = CStudioPreferences::rulerSize() / 2;
- if (theClientSize.width() < theViewRect.width()) {
+ if (g_StudioApp.IsAuthorZoom() && (theClientSize.height() > viewSize.height()
+ || theClientSize.width() > viewSize.width())) {
+ theClientSize.scale(viewSize, Qt::KeepAspectRatio);
+ }
+ if (theClientSize.width() < viewSize.width()) {
m_ClientRect.setLeft(
- even((theViewRect.width() / 2) - (theClientSize.width() / 2)));
+ even((viewSize.width() / 2) - (theClientSize.width() / 2)));
} else {
m_ClientRect.setLeft(-horizontalScrollBar()->value());
}
m_ClientRect.setWidth(theClientSize.width());
- if (theClientSize.height() < theViewRect.height()) {
+ if (theClientSize.height() < viewSize.height()) {
m_ClientRect.setTop(
- even((theViewRect.height() / 2) - (theClientSize.height() / 2)));
+ even((viewSize.height() / 2) - (theClientSize.height() / 2)));
} else {
m_ClientRect.setTop(-verticalScrollBar()->value());
}
@@ -467,6 +450,7 @@ void Q3DSPlayerWnd::recenterClient()
// Need explicit invalidate as changing editor to different ratio screen doesn't trigger
// resizeGL call.
m_glWidget->maybeInvalidateFbo(glRect.size());
+ m_clientWidget->resize(m_ClientRect.size() + QSize(m_ClientRect.x(), m_ClientRect.y()));
m_glWidget->setGeometry(m_ClientRect);
}
@@ -478,7 +462,8 @@ void Q3DSPlayerWnd::recenterClient()
//==============================================================================
void Q3DSPlayerWnd::onRulerGuideToggled()
{
- int scrollAmount = g_StudioApp.getRenderer().AreGuidesEnabled() ? 16 : -16;
+ int scrollAmount = (shouldDrawGuides() ? CStudioPreferences::rulerSize()
+ : -CStudioPreferences::rulerSize()) / 2;
bool hasHorz = horizontalScrollBar()->isVisible();
bool hasVert = verticalScrollBar()->isVisible();
int hscrollPos = 0, vscrollPos = 0;
@@ -522,7 +507,7 @@ QSize Q3DSPlayerWnd::effectivePresentationSize() const
// presentation
// This is a very dirty hack because we are of course hardcoding the size of the guides.
// If the size of the guides never changes, the bet paid off.
- if (g_StudioApp.getRenderer().AreGuidesEnabled())
+ if (shouldDrawGuides())
theSize += QSize(CStudioPreferences::rulerSize(), CStudioPreferences::rulerSize());
return theSize;
}
@@ -543,12 +528,25 @@ void Q3DSPlayerWnd::wheelEvent(QWheelEvent* event)
void Q3DSPlayerWnd::scrollContentsBy(int, int)
{
- setWindowPosition();
+ recenterClient();
}
-bool Q3DSPlayerWnd::shouldHideScrollBars()
+bool Q3DSPlayerWnd::shouldHideScrollBars() const
{
return m_ViewMode == VIEW_EDIT || g_StudioApp.IsAuthorZoom();
}
+bool Q3DSPlayerWnd::shouldDrawGuides() const
+{
+ return m_ViewMode != VIEW_EDIT && g_StudioApp.getRenderer().AreGuidesEnabled()
+ && !g_StudioApp.IsAuthorZoom();
+}
+
+QPoint Q3DSPlayerWnd::mousePosToScenePos(const QPoint &mousePos) const
+{
+ QPoint scenePos = mousePos
+ + QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value());
+ return scenePos;
+}
+
}
diff --git a/src/Authoring/Studio/UI/Q3DSPlayerWnd.h b/src/Authoring/Studio/UI/Q3DSPlayerWnd.h
index 77b7980f..bf80d09a 100644
--- a/src/Authoring/Studio/UI/Q3DSPlayerWnd.h
+++ b/src/Authoring/Studio/UI/Q3DSPlayerWnd.h
@@ -75,7 +75,6 @@ public:
void OnReflectMouse(CPt &, Qt::KeyboardModifiers) override {}
void setToolMode(long toolMode);
- void setWindowPosition();
void setScrollRanges();
void recenterClient();
@@ -108,7 +107,9 @@ protected:
void wheelEvent(QWheelEvent *) override;
void scrollContentsBy(int, int) override;
- bool shouldHideScrollBars();
+ bool shouldHideScrollBars() const;
+ bool shouldDrawGuides() const;
+ QPoint mousePosToScenePos(const QPoint &mousePos) const;
class ObjectRequestData {
public:
@@ -123,6 +124,7 @@ protected:
}
};
+ QWidget *m_clientWidget = nullptr;
Q3DSPlayerWidget *m_glWidget = nullptr;
bool m_mouseDown;
bool m_resumePlayOnMouseRelease = false;
diff --git a/src/Authoring/Studio/UI/SceneView.cpp b/src/Authoring/Studio/UI/SceneView.cpp
index 3fcd5649..d74eeff9 100644
--- a/src/Authoring/Studio/UI/SceneView.cpp
+++ b/src/Authoring/Studio/UI/SceneView.cpp
@@ -225,60 +225,27 @@ void CSceneView::setViewCursor()
}
}
-//==============================================================================
-/**
- * RecalcMatte: Recalculates the matte around the Client based on the settings.
- *
- * This will recalculate the matting around the Client based on the Client's
- * current size. If the Client is a "Fit To Window" mode, then the matte region
- * is cleared.
- */
-//==============================================================================
-void CSceneView::recalcMatte()
-{
- long theXOffset = 0;
- long theYOffset = 0;
- QRect theClientRect = rect();
-
- // Adjust the client area based if rulers are visible
- if (m_playerWnd) {
- m_playerWnd->setGeometry(theXOffset, theYOffset,
- theClientRect.width() - theXOffset,
- theClientRect.height() - theYOffset);
-
- // Recenter the Client rect
- m_playerWnd->recenterClient();
- }
-}
-
void CSceneView::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);
if (m_playerWnd) {
- recalcMatte();
setPlayerWndPosition();
g_StudioApp.GetCore()->GetDoc( )->GetSceneGraph()->RequestRender();
}
}
-//==============================================================================
/**
- * SetPlayerWndPosition: Sets the position of the child player window
- *
- * Called when the view is scrolled to position the child player window
- *
+ * Sets the position of the child player window
*/
-//==============================================================================
void CSceneView::setPlayerWndPosition()
{
// Move the child player window to coincide with the scrollbars
if (m_playerWnd) {
- m_playerWnd->setWindowPosition();
+ m_playerWnd->setGeometry(0, 0, width(), height());
m_playerWnd->update();
}
}
-//==============================================================================
/**
* Resets its scroll ranges and recenters client in the window. This is called when
* an outside source needs to tell the scene view that size ranges have changed such
@@ -337,7 +304,6 @@ void CSceneView::onEditCameraChanged()
// Reset any scrolling and recalculate the window position.
if (m_playerWnd) {
m_playerWnd->setScrollRanges();
- recalcMatte();
setPlayerWndPosition();
}
diff --git a/src/Authoring/Studio/UI/SceneView.h b/src/Authoring/Studio/UI/SceneView.h
index a3f8e530..96a03562 100644
--- a/src/Authoring/Studio/UI/SceneView.h
+++ b/src/Authoring/Studio/UI/SceneView.h
@@ -96,7 +96,6 @@ protected:
void resizeEvent(QResizeEvent *event) override;
private:
- void recalcMatte();
void onDropReceived();
};