Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgrendernode.cpp
Go to the documentation of this file.
1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6
7
9
10#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
11
12#include <QtQuick3DUtils/private/qssgutils_p.h>
13
16
17#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
18
19#include <QtQuick3DUtils/private/qssgplane_p.h>
20
22
23QSSGRenderNode::QSSGRenderNode()
24 : QSSGRenderNode(Type::Node)
25{
26}
27
28QSSGRenderNode::QSSGRenderNode(Type type, QSSGRenderGraphObject::FlagT flags)
29 : QSSGRenderGraphObject(type, flags)
30{
31 localTransform = calculateTransformMatrix({}, initScale, {}, {});
32}
33
34QSSGRenderNode::~QSSGRenderNode()
35 = default;
36
37void QSSGRenderNode::markDirty(DirtyFlag dirtyFlag)
38{
39 if ((flags & FlagT(dirtyFlag)) == 0) { // If not already marked
40 flags |= FlagT(dirtyFlag);
41 const bool markSubtreeDirty = ((FlagT(dirtyFlag) & FlagT(DirtyFlag::SubtreeUpdateMask)) != 0);
42 if (markSubtreeDirty) {
43 for (auto &child : children)
44 child.markDirty(dirtyFlag);
45 }
46 }
47}
48
49void QSSGRenderNode::clearDirty(DirtyFlag dirtyFlag)
50{
51 flags &= ~FlagT(dirtyFlag);
52}
53
54void QSSGRenderNode::setState(LocalState state, bool on)
55{
56 const bool changed = (getLocalState(state) != on);
57 if (changed) { // Mark state dirty
58 flags = on ? (flags | FlagT(state)) : (flags & ~FlagT(state));
59
60 // Mark state dirty
61 switch (state) {
62 case QSSGRenderNode::LocalState::Active:
63 markDirty(DirtyFlag::ActiveDirty);
64 break;
65 case QSSGRenderNode::LocalState::Pickable:
66 markDirty(DirtyFlag::PickableDirty);
67 break;
68 case QSSGRenderNode::LocalState::Imported:
69 markDirty(DirtyFlag::ImportDirty);
70 break;
71 }
72 }
73
74}
75
76QMatrix4x4 QSSGRenderNode::calculateTransformMatrix(QVector3D position, QVector3D scale, QVector3D pivot, QQuaternion rotation)
77{
78 QMatrix4x4 transform;
79
80 // Offset the origin (this is our pivot point)
81 auto offset = (-pivot * scale);
82
83 // Scale
84 transform(0, 0) = scale[0];
85 transform(1, 1) = scale[1];
86 transform(2, 2) = scale[2];
87
88 // Offset (before rotation)
89 transform(0, 3) = offset[0];
90 transform(1, 3) = offset[1];
91 transform(2, 3) = offset[2];
92
93 // rotate
94 transform = QMatrix4x4{rotation.toRotationMatrix()} * transform;
95
96 // translate
97 transform(0, 3) += position[0];
98 transform(1, 3) += position[1];
99 transform(2, 3) += position[2];
100
101 return transform;
102}
103
104void QSSGRenderNode::addChild(QSSGRenderNode &inChild)
105{
106 QSSG_ASSERT_X(inChild.parent != this, "Already a child of this node!", return);
107
108 // NOTE: A layer does not set a parent reference on its direct children.
109 // Those children (the View3D scene root, the ImportScene dummy, explicit cameras)
110 // are owned and kept alive by other subsystems, e.g. the scene root by the scene manager,
111 // so leaving their parent unset keeps the layer's lifetime decoupled from theirs (They can outlive the layer).
112 // Sharing of imported scenes is handled by the ImportScene dummy injected in
113 // QSSGRenderLayer::setImportScene().
114 if (type != QSSGRenderNode::Type::Layer) {
115 if (inChild.parent && inChild.parent != this)
116 inChild.parent->removeChild(inChild);
117 inChild.parent = this;
118 }
119
120 QSSG_ASSERT_X(type != QSSGRenderNode::Type::Root || inChild.type == QSSGRenderNode::Type::Layer,
121 "Only layers can be added to the root!", return);
122
123 if (inChild.type != QSSGRenderNode::Type::Root)
124 inChild.rootNodeRef = rootNodeRef;
125
126 // NOTE: We push importScene nodes to the front because this way we'll always index
127 // the imported scene first. This keeps their global index low and stable across
128 // views, so a shared imported scene can be placed at the start of a shared data store.
129 if (inChild.type != QSSGRenderNode::Type::ImportScene)
130 children.push_back(inChild);
131 else
132 children.push_front(inChild);
133
134 // Don't mark dirty if this is a layer, because layers won't have any global values
135 // calculated and therefore will not have the dirty flag cleared!
136 if (inChild.type != QSSGRenderNode::Type::Layer)
137 inChild.markDirty(DirtyFlag::GlobalValuesDirty);
138 if (QSSGRenderRoot *rootNode = QSSGRenderRoot::get(rootNodeRef))
139 rootNode->markDirty(QSSGRenderRoot::DirtyFlag::TreeDirty);
140}
141
142static inline bool isChildOfLayer(const QSSGRenderLayer &layer, const QSSGRenderNode &node)
143{
144 // A layer does not set parent on its direct children (see addChild()), so the nodes parent
145 // cannot be used to validate relationship between the layer and the node.
146 // Instead we scan the children list to check if node is actually a child of this layer.
147 // We CANNOT dereference node at all! The renderer caches a raw pointer to the
148 // scene-manager-owned scene root and can call this during teardown after that node has been freed.
149 for (const auto &child : layer.children) {
150 if (&child == &node)
151 return true;
152 }
153 return false;
154}
155
156void QSSGRenderNode::removeChild(QSSGRenderNode &inChild)
157{
158 if (type == QSSGRenderNode::Type::Layer) {
159 if (!isChildOfLayer(static_cast<const QSSGRenderLayer &>(*this), inChild))
160 return;
161 } else if (Q_UNLIKELY(inChild.parent != this)) {
162 Q_ASSERT(inChild.parent == this);
163 return;
164 }
165
166 inChild.parent = nullptr;
167 if (inChild.type != QSSGRenderNode::Type::Root)
168 inChild.rootNodeRef = nullptr;
169 inChild.h = {};
170 children.remove(inChild);
171 if (QSSGRenderRoot *rootNode = QSSGRenderRoot::get(rootNodeRef))
172 rootNode->markDirty(QSSGRenderRoot::DirtyFlag::TreeDirty);
173 inChild.markDirty(DirtyFlag::GlobalValuesDirty);
174}
175
176void QSSGRenderNode::removeFromGraph()
177{
178 if (parent)
179 parent->removeChild(*this);
180
181 // Orphan all of my children.
182 for (auto it = children.begin(), end = children.end(); it != end;) {
183 auto &removedChild = *it++;
184 children.remove(removedChild);
185 removedChild.parent = nullptr;
186 removedChild.rootNodeRef = nullptr;
187 }
188}
189
190QSSGBounds3 QSSGRenderNode::getBounds(QSSGBufferManager &inManager,
191 bool inIncludeChildren) const
192{
193 QSSGBounds3 retval;
194 if (inIncludeChildren)
195 retval = getChildBounds(inManager);
196
197 if (type == QSSGRenderGraphObject::Type::Model) {
198 auto model = static_cast<const QSSGRenderModel *>(this);
199 retval.include(inManager.getModelBounds(model));
200 }
201 return retval;
202}
203
204QSSGBounds3 QSSGRenderNode::getChildBounds(QSSGBufferManager &inManager) const
205{
206 QSSGBounds3 retval;
207 QSSGBounds3 childBounds;
208 for (auto &child : children) {
209 childBounds = child.getBounds(inManager);
210 if (!childBounds.isEmpty()) {
211 // Transform the bounds into our local space.
212 childBounds.transform(child.localTransform);
213 retval.include(childBounds);
214 }
215 }
216 return retval;
217}
218
219QVector3D QSSGRenderNode::getDirection(const QMatrix4x4 &globalTransform)
220{
221 const float *dataPtr(globalTransform.data());
222 QVector3D retval(dataPtr[8], dataPtr[9], dataPtr[10]);
223 retval.normalize();
224 return retval;
225}
226
227QVector3D QSSGRenderNode::getScalingCorrectDirection(const QMatrix4x4 &globalTransform)
228{
229 QMatrix3x3 theDirMatrix = globalTransform.normalMatrix();
230 QVector3D theOriginalDir(0, 0, -1);
231 QVector3D retval = QSSGUtils::mat33::transform(theDirMatrix, theOriginalDir);
232 // Should already be normalized, but whatever
233 retval.normalize();
234 return retval;
235}
236
237void QSSGRenderNode::calculateMVP(const QMatrix4x4 &globalTransform, const QMatrix4x4 &inViewProjection, QMatrix4x4 &outMVP)
238{
239 outMVP = inViewProjection * globalTransform;
240}
241
242void QSSGRenderNode::calculateNormalMatrix(const QMatrix4x4 &globalTransform, QMatrix3x3 &outNormalMatrix)
243{
244 outNormalMatrix = globalTransform.normalMatrix();
245}
246
247void QSSGRenderNode::calculateMVPAndNormalMatrix(const QMatrix4x4 &globalTransform,
248 const QMatrix4x4 &inViewProjection,
249 QMatrix4x4 &outMVP,
250 QMatrix3x3 &outNormalMatrix)
251{
252 calculateMVP(globalTransform, inViewProjection, outMVP);
253 calculateNormalMatrix(globalTransform, outNormalMatrix);
254}
255
256QT_END_NAMESPACE
Combined button and popup list for selecting options.
static bool isChildOfLayer(const QSSGRenderLayer &layer, const QSSGRenderNode &node)