1// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "updateworldtransformjob_p.h"
5
6#include <Qt3DCore/qtransform.h>
7#include <Qt3DCore/private/qtransform_p.h>
8#include <Qt3DCore/private/qaspectmanager_p.h>
9#include <Qt3DRender/private/entity_p.h>
10#include <Qt3DRender/private/transform_p.h>
11#include <Qt3DRender/private/renderlogging_p.h>
12#include <Qt3DRender/private/job_common_p.h>
13#include <Qt3DRender/private/managers_p.h>
14#include <Qt3DRender/private/nodemanagers_p.h>
15
16#include <QThread>
17
18QT_BEGIN_NAMESPACE
19
20namespace Qt3DRender {
21namespace Render {
22
23namespace {
24
25struct TransformUpdate
26{
27 Qt3DCore::QNodeId peerId;
28 QMatrix4x4 worldTransformMatrix;
29};
30
31void updateWorldTransformAndBounds(NodeManagers *manager, Entity *node, const Matrix4x4 &parentTransform, bool hasParentTransform, QList<TransformUpdate> &updatedTransforms)
32{
33 if (!node->isEnabled())
34 return;
35
36 Matrix4x4 worldTransform(parentTransform);
37 Transform *nodeTransform = node->renderComponent<Transform>();
38
39 const bool hasTransformComponent = nodeTransform != nullptr && nodeTransform->isEnabled();
40 if (hasTransformComponent)
41 worldTransform = worldTransform * nodeTransform->transformMatrix();
42
43 if (*(node->worldTransform()) != worldTransform) {
44 *(node->worldTransform()) = worldTransform;
45 if (hasTransformComponent)
46 updatedTransforms.push_back(t: {.peerId: nodeTransform->peerId(), .worldTransformMatrix: convertToQMatrix4x4(v: worldTransform)});
47 }
48 node->setParentLessTransform(!hasParentTransform);
49
50 const auto &childrenHandles = node->childrenHandles();
51 for (const HEntity &handle : childrenHandles) {
52 Entity *child = manager->renderNodesManager()->data(handle);
53 if (child)
54 updateWorldTransformAndBounds(manager, node: child, parentTransform: worldTransform, hasParentTransform: hasParentTransform || hasTransformComponent, updatedTransforms);
55 }
56}
57
58}
59
60class Q_3DRENDERSHARED_PRIVATE_EXPORT UpdateWorldTransformJobPrivate : public Qt3DCore::QAspectJobPrivate
61{
62public:
63 UpdateWorldTransformJobPrivate() {}
64 ~UpdateWorldTransformJobPrivate() override {}
65
66 void postFrame(Qt3DCore::QAspectManager *manager) override;
67
68 QList<TransformUpdate> m_updatedTransforms;
69};
70
71UpdateWorldTransformJob::UpdateWorldTransformJob()
72 : Qt3DCore::QAspectJob(*new UpdateWorldTransformJobPrivate())
73 , m_node(nullptr)
74 , m_manager(nullptr)
75{
76 SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTransform, 0)
77}
78
79void UpdateWorldTransformJob::setRoot(Entity *root)
80{
81 m_node = root;
82}
83
84void UpdateWorldTransformJob::setManagers(NodeManagers *manager)
85{
86 m_manager = manager;
87}
88
89void UpdateWorldTransformJob::run()
90{
91 // Iterate over each level of hierarchy in our scene
92 // and update each node's world transform from its
93 // local transform and its parent's world transform
94
95 // TODO: Parallelise this on each level using a parallel_for
96 // implementation.
97
98 Q_D(UpdateWorldTransformJob);
99 qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread();
100
101 Matrix4x4 parentTransform;
102 Entity *parent = m_node->parent();
103 if (parent != nullptr)
104 parentTransform = *(parent->worldTransform());
105 updateWorldTransformAndBounds(manager: m_manager, node: m_node, parentTransform, hasParentTransform: false, updatedTransforms&: d->m_updatedTransforms);
106
107 qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread();
108}
109
110void UpdateWorldTransformJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
111{
112 const QList<TransformUpdate> updatedTransforms = Qt3DCore::moveAndClear(data&: m_updatedTransforms);
113 for (const TransformUpdate &t : updatedTransforms) {
114 Qt3DCore::QTransform *node =
115 qobject_cast<Qt3DCore::QTransform *>(object: manager->lookupNode(id: t.peerId));
116 if (!node)
117 continue;
118 Qt3DCore::QTransformPrivate *dNode =
119 static_cast<Qt3DCore::QTransformPrivate *>(Qt3DCore::QNodePrivate::get(q: node));
120 dNode->setWorldMatrix(t.worldTransformMatrix);
121 }
122}
123
124} // namespace Render
125} // namespace Qt3DRender
126
127QT_END_NAMESPACE
128

source code of qt3d/src/render/jobs/updateworldtransformjob.cpp