summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-08-09 10:22:25 +0200
committerPaul Lemire <paul.lemire@kdab.com>2019-08-13 14:32:29 +0200
commit3cdd4e12eb25757bb5711977ecf7ede419c44dd1 (patch)
treea41b7df4003f4ed79c2afb838d275a4703778e78
parentbb5caa526c242e68ae9ba5cd64933f7f3dea1aef (diff)
QTransform: add worldMatrix property
Will make it more convenient to retrieve the world transform of a given QEntity as well as monitor it for changes without having to traverse the parent hierarchy of QEntity/QTransform [ChangeLog] Add worldMatrix property on QTransform Change-Id: Ie9ffb70c03b365850ed08693df2746701ca9a1fb Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r--src/core/transforms/qtransform.cpp66
-rw-r--r--src/core/transforms/qtransform.h5
-rw-r--r--src/core/transforms/qtransform_p.h2
-rw-r--r--src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp1
-rw-r--r--src/render/backend/transform.cpp11
-rw-r--r--src/render/backend/transform_p.h4
-rw-r--r--src/render/jobs/updateworldtransformjob.cpp9
-rw-r--r--tests/auto/core/qtransform/tst_qtransform.cpp49
-rw-r--r--tests/auto/render/transform/tst_transform.cpp26
9 files changed, 167 insertions, 6 deletions
diff --git a/src/core/transforms/qtransform.cpp b/src/core/transforms/qtransform.cpp
index d0e2628f7..bedf108f2 100644
--- a/src/core/transforms/qtransform.cpp
+++ b/src/core/transforms/qtransform.cpp
@@ -135,6 +135,18 @@ QTransformPrivate::~QTransformPrivate()
*/
/*!
+ \qmlproperty matrix4x4 QTransform::worldMatrix
+
+ Holds the world transformation matrix for the transform. This assumes the
+ Transform component is being referenced by an Entity. This makes it more
+ convenient to identify when an Entity part of a subtree has been
+ transformed in the world even though its local transformation might not
+ have changed.
+
+ \since 5.14
+ */
+
+/*!
\qmlmethod quaternion Transform::fromAxisAndAngle(vector3d axis, real angle)
Creates a quaternion from \a axis and \a angle.
Returns the resulting quaternion.
@@ -222,6 +234,35 @@ QTransform::QTransform(QTransformPrivate &dd, QNode *parent)
{
}
+/*!
+ \internal
+ */
+void QTransform::sceneChangeEvent(const QSceneChangePtr &change)
+{
+ switch (change->type()) {
+ case PropertyUpdated: {
+ Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (propertyChange->propertyName() == QByteArrayLiteral("worldMatrix")) {
+ const bool blocked = blockNotifications(true);
+ setWorldMatrix(propertyChange->value().value<QMatrix4x4>());
+ blockNotifications(blocked);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void QTransform::setWorldMatrix(const QMatrix4x4 &worldMatrix)
+{
+ Q_D(QTransform);
+ if (d->m_worldMatrix == worldMatrix)
+ return;
+ d->m_worldMatrix = worldMatrix;
+ emit worldMatrixChanged(worldMatrix);
+}
+
void QTransform::setMatrix(const QMatrix4x4 &m)
{
Q_D(QTransform);
@@ -240,7 +281,6 @@ void QTransform::setMatrix(const QMatrix4x4 &m)
emit scale3DChanged(s);
emit rotationChanged(r);
emit translationChanged(t);
-
const bool wasBlocked = blockNotifications(true);
emit matrixChanged();
emit scaleChanged(d->m_scale.x());
@@ -330,6 +370,30 @@ QMatrix4x4 QTransform::matrix() const
}
/*!
+ \property QTransform::worldMatrix
+
+ Holds the world transformation matrix for the transform. This assumes the
+ QTransform component is being referenced by a QEntity. This makes it more
+ convenient to identify when a QEntity part of a subtree has been
+ transformed in the world even though its local transformation might not
+ have changed.
+
+ \since 5.14
+ */
+
+/*!
+ Returns the world transformation matrix associated to the QTransform when
+ referenced by a QEntity which may be part of a QEntity hierarchy.
+
+ \since 5.14
+ */
+QMatrix4x4 QTransform::worldMatrix() const
+{
+ Q_D(const QTransform);
+ return d->m_worldMatrix;
+}
+
+/*!
\property Qt3DCore::QTransform::rotationX
Holds the x rotation of the transform as Euler angle.
diff --git a/src/core/transforms/qtransform.h b/src/core/transforms/qtransform.h
index a80385a1b..527760df7 100644
--- a/src/core/transforms/qtransform.h
+++ b/src/core/transforms/qtransform.h
@@ -61,6 +61,7 @@ class Q_3DCORESHARED_EXPORT QTransform : public QComponent
Q_PROPERTY(float rotationX READ rotationX WRITE setRotationX NOTIFY rotationXChanged)
Q_PROPERTY(float rotationY READ rotationY WRITE setRotationY NOTIFY rotationYChanged)
Q_PROPERTY(float rotationZ READ rotationZ WRITE setRotationZ NOTIFY rotationZChanged)
+ Q_PROPERTY(QMatrix4x4 worldMatrix READ worldMatrix NOTIFY worldMatrixChanged REVISION 14)
public:
explicit QTransform(QNode *parent = nullptr);
@@ -88,6 +89,7 @@ public:
Q_INVOKABLE static QMatrix4x4 rotateFromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis);
QMatrix4x4 matrix() const;
+ QMatrix4x4 worldMatrix() const;
float rotationX() const;
float rotationY() const;
@@ -113,9 +115,12 @@ Q_SIGNALS:
void rotationXChanged(float rotationX);
void rotationYChanged(float rotationY);
void rotationZChanged(float rotationZ);
+ void worldMatrixChanged(const QMatrix4x4 &worldMatrix);
protected:
explicit QTransform(QTransformPrivate &dd, QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
+ void setWorldMatrix(const QMatrix4x4 &worldMatrix);
private:
Q_DECLARE_PRIVATE(QTransform)
diff --git a/src/core/transforms/qtransform_p.h b/src/core/transforms/qtransform_p.h
index 89bc55491..d44e5e157 100644
--- a/src/core/transforms/qtransform_p.h
+++ b/src/core/transforms/qtransform_p.h
@@ -75,6 +75,8 @@ public:
mutable QMatrix4x4 m_matrix;
mutable bool m_matrixDirty;
+
+ QMatrix4x4 m_worldMatrix;
};
struct QTransformData
diff --git a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
index 0f8f7d11e..59df221ab 100644
--- a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
+++ b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
@@ -69,6 +69,7 @@ void Qt3DQuick3DCorePlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DCore::Quick::Quick3DEntityLoader, 12>(uri, 2, 12, "EntityLoader");
qmlRegisterType<Qt3DCore::Quick::Quick3DNodeInstantiator>(uri, 2, 0, "NodeInstantiator");
qmlRegisterType<Qt3DCore::QTransform>(uri, 2, 0, "Transform");
+ qmlRegisterType<Qt3DCore::QTransform, 14>(uri, 2, 14, "Transform");
qmlRegisterType<Qt3DCore::QArmature>(uri, 2, 10, "Armature");
qmlRegisterUncreatableType<Qt3DCore::QAbstractSkeleton>(uri, 2, 10, "AbstractSkeleton", QStringLiteral("AbstractSkeleton is an abstract base class"));
qmlRegisterType<Qt3DCore::QSkeletonLoader>(uri, 2, 10, "SkeletonLoader");
diff --git a/src/render/backend/transform.cpp b/src/render/backend/transform.cpp
index 20574d6f7..6d011cf81 100644
--- a/src/render/backend/transform.cpp
+++ b/src/render/backend/transform.cpp
@@ -52,7 +52,7 @@ namespace Qt3DRender {
namespace Render {
Transform::Transform()
- : BackendNode()
+ : BackendNode(ReadWrite)
, m_rotation()
, m_scale(1.0f, 1.0f, 1.0f)
, m_translation()
@@ -119,6 +119,15 @@ void Transform::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
BackendNode::sceneChangeEvent(e);
}
+void Transform::notifyWorldTransformChanged(const Matrix4x4 &worldMatrix)
+{
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("worldMatrix");
+ change->setValue(convertToQMatrix4x4(worldMatrix));
+ notifyObservers(change);
+}
+
void Transform::updateMatrix()
{
QMatrix4x4 m;
diff --git a/src/render/backend/transform_p.h b/src/render/backend/transform_p.h
index 8e3e9d639..e3bcad317 100644
--- a/src/render/backend/transform_p.h
+++ b/src/render/backend/transform_p.h
@@ -77,10 +77,10 @@ public:
QVector3D translation() const;
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
-
- void updateMatrix();
+ void notifyWorldTransformChanged(const Matrix4x4 &worldMatrix);
private:
+ void updateMatrix();
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
Matrix4x4 m_transformMatrix;
diff --git a/src/render/jobs/updateworldtransformjob.cpp b/src/render/jobs/updateworldtransformjob.cpp
index 1a9697843..6b8bccec2 100644
--- a/src/render/jobs/updateworldtransformjob.cpp
+++ b/src/render/jobs/updateworldtransformjob.cpp
@@ -61,10 +61,15 @@ void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Ma
Matrix4x4 worldTransform(parentTransform);
Transform *nodeTransform = node->renderComponent<Transform>();
- if (nodeTransform != nullptr && nodeTransform->isEnabled())
+ const bool hasTransformComponent = nodeTransform != nullptr && nodeTransform->isEnabled();
+ if (hasTransformComponent)
worldTransform = worldTransform * nodeTransform->transformMatrix();
- *(node->worldTransform()) = worldTransform;
+ if (*(node->worldTransform()) != worldTransform) {
+ *(node->worldTransform()) = worldTransform;
+ if (hasTransformComponent)
+ nodeTransform->notifyWorldTransformChanged(worldTransform);
+ }
const auto childrenHandles = node->childrenHandles();
for (const HEntity &handle : childrenHandles) {
diff --git a/tests/auto/core/qtransform/tst_qtransform.cpp b/tests/auto/core/qtransform/tst_qtransform.cpp
index f5527ebf5..dbdda1ce1 100644
--- a/tests/auto/core/qtransform/tst_qtransform.cpp
+++ b/tests/auto/core/qtransform/tst_qtransform.cpp
@@ -36,6 +36,15 @@
using namespace Qt3DCore;
+class FakeTransform : public Qt3DCore::QTransform
+{
+public:
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override
+ {
+ Qt3DCore::QTransform::sceneChangeEvent(change);
+ }
+};
+
class tst_QTransform : public QObject
{
Q_OBJECT
@@ -49,6 +58,7 @@ private Q_SLOTS:
// THEN
QCOMPARE(transform.isShareable(), false);
QCOMPARE(transform.matrix(), QMatrix4x4());
+ QCOMPARE(transform.worldMatrix(), QMatrix4x4());
QCOMPARE(transform.scale(), 1.0f);
QCOMPARE(transform.scale3D(), QVector3D(1.0f, 1.0f, 1.0f));
QCOMPARE(transform.rotation(), QQuaternion());
@@ -112,6 +122,7 @@ private Q_SLOTS:
QCOMPARE(transform->translation(), cloneData.translation);
QCOMPARE(transform->scale3D(), cloneData.scale);
QCOMPARE(transform->rotation(), cloneData.rotation);
+ QCOMPARE(transform->worldMatrix(), QMatrix4x4());
}
void checkPropertyUpdates()
@@ -342,6 +353,44 @@ private Q_SLOTS:
// Note: t.matrix() != t2.matrix() since different matrices
// can result in the same scale, rotation, translation
}
+
+ void checkUpdateWorldTransform()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTransform t;
+ arbiter.setArbiterOnNode(&t);
+
+ // WHEN
+ QSignalSpy spy(&t, SIGNAL(worldMatrixChanged(QMatrix4x4)));
+
+ // THEN
+ QVERIFY(spy.isValid());
+
+ // WHEN
+ Qt3DCore::QPropertyUpdatedChangePtr valueChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ valueChange->setPropertyName("worldMatrix");
+ const QMatrix4x4 newValue(1.0f, 2.0f, 3.0f, 4.0f,
+ 5.0f, 6.0f, 7.0f, 8.0f,
+ 9.0f, 10.0f, 11.0f, 12.0f,
+ 13.0f, 14.0f, 15.0f, 16.0f);
+ valueChange->setValue(newValue);
+ t.sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(t.worldMatrix(), newValue);
+
+ // WHEN
+ spy.clear();
+ t.sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(spy.count(), 0);
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(t.worldMatrix(), newValue);
+ }
};
QTEST_MAIN(tst_QTransform)
diff --git a/tests/auto/render/transform/tst_transform.cpp b/tests/auto/render/transform/tst_transform.cpp
index 151baff76..5619f8ed3 100644
--- a/tests/auto/render/transform/tst_transform.cpp
+++ b/tests/auto/render/transform/tst_transform.cpp
@@ -32,8 +32,10 @@
#include <Qt3DCore/private/qtransform_p.h>
#include <Qt3DRender/private/transform_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <private/qbackendnode_p.h>
#include "qbackendnodetester.h"
#include "testrenderer.h"
+#include "testpostmanarbiter.h"
class tst_Transform : public Qt3DCore::QBackendNodeTester
{
@@ -171,6 +173,30 @@ private Q_SLOTS:
}
}
+ void checkWorldTransformUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::Render::Transform backend;
+
+ Qt3DCore::QBackendNodePrivate::get(&backend)->setArbiter(&arbiter);
+
+ // WHEN
+ const QMatrix4x4 expectedNewWorldMatrix(1.0f, 2.0f, 3.0f, 4.0f,
+ 5.0f, 6.0f, 7.0f, 8.0f,
+ 9.0f, 10.0f, 11.0f, 12.0f,
+ 13.0f, 14.0f, 15.0f, 16.0f);
+ Matrix4x4 newWorldMatrix(expectedNewWorldMatrix);
+ backend.notifyWorldTransformChanged(newWorldMatrix);
+
+ // THEN
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(arbiter.events.count(), 1);
+ QCOMPARE(change->propertyName(), "worldMatrix");
+ QCOMPARE(change->value().value<QMatrix4x4>(), expectedNewWorldMatrix);
+
+ arbiter.events.clear();
+ }
};
QTEST_MAIN(tst_Transform)