1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsgnode.h"
41#include "qsgnode_p.h"
42#include "qsgrenderer_p.h"
43#include "qsgnodeupdater_p.h"
44#include "qsgmaterial.h"
45
46#include "limits.h"
47
48QT_BEGIN_NAMESPACE
49
50#ifndef QT_NO_DEBUG
51static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty(varName: "QML_LEAK_CHECK");
52static int qt_node_count = 0;
53
54static void qt_print_node_count()
55{
56 qDebug(msg: "Number of leaked nodes: %i", qt_node_count);
57 qt_node_count = -1;
58}
59#endif
60
61/*!
62 \group qtquick-scenegraph-nodes
63 \title Qt Quick Scene Graph Node classes
64 \brief Nodes that can be used as part of the scene graph.
65
66 This page lists the nodes in \l {Qt Quick}'s \l {scene graph}{Qt Quick Scene Graph}.
67 */
68
69/*!
70 \class QSGNode
71 \brief The QSGNode class is the base class for all nodes in the scene graph.
72
73 \inmodule QtQuick
74 \ingroup qtquick-scenegraph-nodes
75
76 The QSGNode class can be used as a child container. Children are added with
77 the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
78 insertChildNodeAfter(). The order of nodes is important as geometry nodes
79 are rendered according to their ordering in the scene graph.
80
81 The scene graph nodes contains a mechanism to describe which
82 parts of the scene has changed. This includes the combined matrices,
83 accumulated opacity, changes to the node hierarchy, and so on. This
84 information can be used for optimizations inside the scene graph renderer.
85 For the renderer to properly render the nodes, it is important that users
86 call QSGNode::markDirty() with the correct flags when nodes are changed.
87 Most of the functions on the node classes will implicitly call markDirty().
88 For example, QSGNode::appendChildNode() will call markDirty() passing in
89 QSGNode::DirtyNodeAdded.
90
91 If nodes change every frame, the preprocess() function can be used to
92 apply changes to a node for every frame it is rendered. The use of
93 preprocess() must be explicitly enabled by setting the
94 QSGNode::UsePreprocess flag on the node.
95
96 The virtual isSubtreeBlocked() function can be used to disable a subtree all
97 together. Nodes in a blocked subtree will not be preprocessed() and not
98 rendered.
99
100 \note All classes with QSG prefix should be used solely on the scene graph's
101 rendering thread. See \l {Scene Graph and Rendering} for more information.
102 */
103
104/*!
105 \enum QSGNode::DirtyStateBit
106
107 Used in QSGNode::markDirty() to indicate how the scene graph has changed.
108
109 \value DirtyMatrix The matrix in a QSGTransformNode has changed.
110 \value DirtyNodeAdded A node was added.
111 \value DirtyNodeRemoved A node was removed.
112 \value DirtyGeometry The geometry of a QSGGeometryNode has changed.
113 \value DirtyMaterial The material of a QSGGeometryNode has changed.
114 \value DirtyOpacity The opacity of a QSGOpacityNode has changed.
115 \value DirtySubtreeBlocked The subtree has been blocked.
116
117 \omitvalue DirtyForceUpdate
118 \omitvalue DirtyUsePreprocess
119 \omitvalue DirtyPropagationMask
120
121 \sa QSGNode::markDirty()
122 */
123
124/*!
125 \enum QSGNode::Flag
126
127 The QSGNode::Flag enum describes flags on the QSGNode
128
129 \value OwnedByParent The node is owned by its parent and will be deleted
130 when the parent is deleted.
131 \value UsePreprocess The node's virtual preprocess() function will be called
132 before rendering starts.
133 \value OwnsGeometry Only valid for QSGGeometryNode and QSGClipNode.
134 The node has ownership over the QSGGeometry instance and will
135 delete it when the node is destroyed or a geometry is assigned.
136 \value OwnsMaterial Only valid for QSGGeometryNode. The node has ownership
137 over the material and will delete it when the node is destroyed or a material is assigned.
138 \value OwnsOpaqueMaterial Only valid for QSGGeometryNode. The node has
139 ownership over the opaque material and will delete it when the node is
140 destroyed or a material is assigned.
141 \value InternalReserved Reserved for internal use.
142
143 \omitvalue IsVisitableNode
144 */
145
146/*!
147 \enum QSGNode::NodeType
148
149 Can be used to figure out the type of node.
150
151 \value BasicNodeType The type of QSGNode
152 \value GeometryNodeType The type of QSGGeometryNode
153 \value TransformNodeType The type of QSGTransformNode
154 \value ClipNodeType The type of QSGClipNode
155 \value OpacityNodeType The type of QSGOpacityNode
156 \value RenderNodeType The type of QSGRenderNode
157
158 \omitvalue RootNodeType
159
160 \sa type()
161 */
162
163/*!
164 \fn QSGNode *QSGNode::childAtIndex(int i) const
165
166 Returns the child at index \a i.
167
168 Children are stored internally as a linked list, so iterating
169 over the children via the index is suboptimal.
170 */
171
172/*!
173 \fn int QSGNode::childCount() const
174
175 Returns the number of child nodes.
176 */
177
178/*!
179 \fn void QSGNode::clearDirty()
180
181 \internal
182 */
183
184/*!
185 \fn QSGNode *QSGNode::firstChild() const
186
187 Returns the first child of this node.
188
189 The children are stored in a linked list.
190 */
191
192/*!
193 \fn QSGNode *QSGNode::lastChild() const
194
195 Returns the last child of this node.
196
197 The children are stored as a linked list.
198 */
199
200/*!
201 \fn QSGNode::Flags QSGNode::flags() const
202
203 Returns the set of flags for this node.
204 */
205
206/*!
207 \fn QSGNode *QSGNode::nextSibling() const
208
209 Returns the node after this in the parent's list of children.
210
211 The children are stored as a linked list.
212 */
213
214/*!
215 \fn QSGNode *QSGNode::previousSibling() const
216
217 Returns the node before this in the parent's list of children.
218
219 The children are stored as a linked list.
220 */
221
222/*!
223 \fn QSGNode::Type QSGNode::type() const
224
225 Returns the type of this node. The node type must be one of the
226 predefined types defined in QSGNode::NodeType and can safely be
227 used to cast to the corresponding class.
228 */
229
230/*!
231 \fn QSGNode::DirtyState QSGNode::dirtyState() const
232
233 \internal
234 */
235
236/*!
237 \fn QSGNode *QSGNode::parent() const
238
239 Returns the parent node of this node.
240 */
241
242
243/*!
244 * Constructs a new node
245 */
246QSGNode::QSGNode()
247 : m_nodeFlags(OwnedByParent)
248{
249 init();
250}
251
252/*!
253 * Constructs a new node with the given node type.
254 *
255 * \internal
256 */
257QSGNode::QSGNode(NodeType type)
258 : m_parent(nullptr)
259 , m_type(type)
260 , m_firstChild(nullptr)
261 , m_lastChild(nullptr)
262 , m_nextSibling(nullptr)
263 , m_previousSibling(nullptr)
264 , m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0)
265 , m_nodeFlags(OwnedByParent)
266{
267 init();
268}
269
270/*!
271 * Constructs a new node with the given node type.
272 *
273 * \internal
274 */
275QSGNode::QSGNode(QSGNodePrivate &dd, NodeType type)
276 : m_parent(nullptr)
277 , m_type(type)
278 , m_firstChild(nullptr)
279 , m_lastChild(nullptr)
280 , m_nextSibling(nullptr)
281 , m_previousSibling(nullptr)
282 , m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0)
283 , m_nodeFlags(OwnedByParent)
284 , d_ptr(&dd)
285{
286 init();
287}
288
289/*!
290 * \internal
291 */
292void QSGNode::init()
293{
294#ifndef QT_NO_DEBUG
295 if (qsg_leak_check) {
296 ++qt_node_count;
297 static bool atexit_registered = false;
298 if (!atexit_registered) {
299 atexit(func: qt_print_node_count);
300 atexit_registered = true;
301 }
302 }
303#endif
304
305#ifdef QSG_RUNTIME_DESCRIPTION
306 if (d_ptr.isNull())
307 d_ptr.reset(other: new QSGNodePrivate());
308#endif
309}
310
311/*!
312 * Destroys the node.
313 *
314 * Every child of this node that has the flag QSGNode::OwnedByParent set,
315 * will also be deleted.
316 */
317QSGNode::~QSGNode()
318{
319#ifndef QT_NO_DEBUG
320 if (qsg_leak_check) {
321 --qt_node_count;
322 if (qt_node_count < 0)
323 qDebug(msg: "Node destroyed after qt_print_node_count() was called.");
324 }
325#endif
326 destroy();
327}
328
329
330/*!
331 \fn void QSGNode::preprocess()
332
333 Override this function to do processing on the node before it is rendered.
334
335 Preprocessing needs to be explicitly enabled by setting the flag
336 QSGNode::UsePreprocess. The flag needs to be set before the node is added
337 to the scene graph and will cause the preprocess() function to be called
338 for every frame the node is rendered.
339
340 \warning Beware of deleting nodes while they are being preprocessed. It is
341 possible, with a small performance hit, to delete a single node during its
342 own preprocess call. Deleting a subtree which has nodes that also use
343 preprocessing may result in a segmentation fault. This is done for
344 performance reasons.
345 */
346
347
348
349
350/*!
351 Returns whether this node and its subtree is available for use.
352
353 Blocked subtrees will not get their dirty states updated and they
354 will not be rendered.
355
356 The QSGOpacityNode will return a blocked subtree when accumulated opacity
357 is 0, for instance.
358 */
359
360bool QSGNode::isSubtreeBlocked() const
361{
362 return false;
363}
364
365/*!
366 \internal
367 Detaches the node from the scene graph and deletes any children it owns.
368
369 This function is called from QSGNode's and QSGRootNode's destructor. It
370 should not be called explicitly in user code. QSGRootNode needs to call
371 destroy() because destroy() calls removeChildNode() which in turn calls
372 markDirty() which type-casts the node to QSGRootNode. This type-cast is not
373 valid at the time QSGNode's destructor is called because the node will
374 already be partially destroyed at that point.
375*/
376
377void QSGNode::destroy()
378{
379 if (m_parent) {
380 m_parent->removeChildNode(node: this);
381 Q_ASSERT(m_parent == nullptr);
382 }
383 while (m_firstChild) {
384 QSGNode *child = m_firstChild;
385 removeChildNode(node: child);
386 Q_ASSERT(child->m_parent == nullptr);
387 if (child->flags() & OwnedByParent)
388 delete child;
389 }
390
391 Q_ASSERT(m_firstChild == nullptr && m_lastChild == nullptr);
392}
393
394
395/*!
396 Prepends \a node to this node's the list of children.
397
398 Ordering of nodes is important as geometry nodes will be rendered in the
399 order they are added to the scene graph.
400 */
401
402void QSGNode::prependChildNode(QSGNode *node)
403{
404 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
405 Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
406
407#ifndef QT_NO_DEBUG
408 if (node->type() == QSGNode::GeometryNodeType) {
409 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
410 Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
411 Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
412 }
413#endif
414
415 if (m_firstChild)
416 m_firstChild->m_previousSibling = node;
417 else
418 m_lastChild = node;
419 node->m_nextSibling = m_firstChild;
420 m_firstChild = node;
421 node->m_parent = this;
422
423 node->markDirty(bits: DirtyNodeAdded);
424}
425
426/*!
427 Appends \a node to this node's list of children.
428
429 Ordering of nodes is important as geometry nodes will be rendered in the
430 order they are added to the scene graph.
431 */
432
433void QSGNode::appendChildNode(QSGNode *node)
434{
435 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
436 Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
437
438#ifndef QT_NO_DEBUG
439 if (node->type() == QSGNode::GeometryNodeType) {
440 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
441 Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
442 Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
443 }
444#endif
445
446 if (m_lastChild)
447 m_lastChild->m_nextSibling = node;
448 else
449 m_firstChild = node;
450 node->m_previousSibling = m_lastChild;
451 m_lastChild = node;
452 node->m_parent = this;
453
454 node->markDirty(bits: DirtyNodeAdded);
455}
456
457
458
459/*!
460 Inserts \a node to this node's list of children before the node specified with \a before.
461
462 Ordering of nodes is important as geometry nodes will be rendered in the
463 order they are added to the scene graph.
464 */
465
466void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
467{
468 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
469 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
470 Q_ASSERT_X(before && before->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
471
472#ifndef QT_NO_DEBUG
473 if (node->type() == QSGNode::GeometryNodeType) {
474 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
475 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
476 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
477 }
478#endif
479
480 QSGNode *previous = before->m_previousSibling;
481 if (previous)
482 previous->m_nextSibling = node;
483 else
484 m_firstChild = node;
485 node->m_previousSibling = previous;
486 node->m_nextSibling = before;
487 before->m_previousSibling = node;
488 node->m_parent = this;
489
490 node->markDirty(bits: DirtyNodeAdded);
491}
492
493
494
495/*!
496 Inserts \a node to this node's list of children after the node specified with \a after.
497
498 Ordering of nodes is important as geometry nodes will be rendered in the
499 order they are added to the scene graph.
500 */
501
502void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
503{
504 //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
505 Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
506 Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeAfter", "The parent of \'after\' is wrong");
507
508#ifndef QT_NO_DEBUG
509 if (node->type() == QSGNode::GeometryNodeType) {
510 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
511 Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
512 Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
513 }
514#endif
515
516 QSGNode *next = after->m_nextSibling;
517 if (next)
518 next->m_previousSibling = node;
519 else
520 m_lastChild = node;
521 node->m_nextSibling = next;
522 node->m_previousSibling = after;
523 after->m_nextSibling = node;
524 node->m_parent = this;
525
526 node->markDirty(bits: DirtyNodeAdded);
527}
528
529
530
531/*!
532 Removes \a node from this node's list of children.
533 */
534
535void QSGNode::removeChildNode(QSGNode *node)
536{
537 //Q_ASSERT(m_children.contains(node));
538 Q_ASSERT(node->parent() == this);
539
540 QSGNode *previous = node->m_previousSibling;
541 QSGNode *next = node->m_nextSibling;
542 if (previous)
543 previous->m_nextSibling = next;
544 else
545 m_firstChild = next;
546 if (next)
547 next->m_previousSibling = previous;
548 else
549 m_lastChild = previous;
550 node->m_previousSibling = nullptr;
551 node->m_nextSibling = nullptr;
552
553 node->markDirty(bits: DirtyNodeRemoved);
554 node->m_parent = nullptr;
555}
556
557
558/*!
559 Removes all child nodes from this node's list of children.
560 */
561
562void QSGNode::removeAllChildNodes()
563{
564 while (m_firstChild) {
565 QSGNode *node = m_firstChild;
566 m_firstChild = node->m_nextSibling;
567 node->m_nextSibling = nullptr;
568 if (m_firstChild)
569 m_firstChild->m_previousSibling = nullptr;
570 else
571 m_lastChild = nullptr;
572 node->markDirty(bits: DirtyNodeRemoved);
573 node->m_parent = nullptr;
574 }
575}
576
577/*!
578 * \internal
579 *
580 * Reparents all nodes of this node to \a newParent.
581 */
582void QSGNode::reparentChildNodesTo(QSGNode *newParent)
583{
584 for (QSGNode *c = firstChild(); c; c = firstChild()) {
585 removeChildNode(node: c);
586 newParent->appendChildNode(node: c);
587 }
588}
589
590
591int QSGNode::childCount() const
592{
593 int count = 0;
594 QSGNode *n = m_firstChild;
595 while (n) {
596 ++count;
597 n = n->m_nextSibling;
598 }
599 return count;
600}
601
602
603QSGNode *QSGNode::childAtIndex(int i) const
604{
605 QSGNode *n = m_firstChild;
606 while (i && n) {
607 --i;
608 n = n->m_nextSibling;
609 }
610 return n;
611}
612
613
614/*!
615 Sets the flag \a f on this node if \a enabled is true;
616 otherwise clears the flag.
617
618 \sa flags()
619*/
620
621void QSGNode::setFlag(Flag f, bool enabled)
622{
623 if (bool(m_nodeFlags & f) == enabled)
624 return;
625 m_nodeFlags ^= f;
626 Q_ASSERT(int(UsePreprocess) == int(DirtyUsePreprocess));
627 int changedFlag = f & UsePreprocess;
628 if (changedFlag)
629 markDirty(bits: DirtyState(changedFlag));
630}
631
632
633/*!
634 Sets the flags \a f on this node if \a enabled is true;
635 otherwise clears the flags.
636
637 \sa flags()
638*/
639
640void QSGNode::setFlags(Flags f, bool enabled)
641{
642 Flags oldFlags = m_nodeFlags;
643 if (enabled)
644 m_nodeFlags |= f;
645 else
646 m_nodeFlags &= ~f;
647 Q_ASSERT(int(UsePreprocess) == int(DirtyUsePreprocess));
648 int changedFlags = (oldFlags ^ m_nodeFlags) & UsePreprocess;
649 if (changedFlags)
650 markDirty(bits: DirtyState(changedFlags));
651}
652
653
654
655/*!
656 Notifies all connected renderers that the node has dirty \a bits.
657 */
658
659void QSGNode::markDirty(DirtyState bits)
660{
661 int renderableCountDiff = 0;
662 if (bits & DirtyNodeAdded)
663 renderableCountDiff += m_subtreeRenderableCount;
664 if (bits & DirtyNodeRemoved)
665 renderableCountDiff -= m_subtreeRenderableCount;
666
667 QSGNode *p = m_parent;
668 while (p) {
669 p->m_subtreeRenderableCount += renderableCountDiff;
670 if (p->type() == RootNodeType)
671 static_cast<QSGRootNode *>(p)->notifyNodeChange(node: this, state: bits);
672 p = p->m_parent;
673 }
674}
675
676void qsgnode_set_description(QSGNode *node, const QString &description)
677{
678#ifdef QSG_RUNTIME_DESCRIPTION
679 QSGNodePrivate::setDescription(node, description);
680#else
681 Q_UNUSED(node);
682 Q_UNUSED(description);
683#endif
684}
685
686/*!
687 \class QSGBasicGeometryNode
688 \brief The QSGBasicGeometryNode class serves as a baseclass for geometry based nodes.
689
690 \inmodule QtQuick
691
692 The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
693 shared functionality between the QSGGeometryNode and QSGClipNode classes.
694
695 \note All classes with QSG prefix should be used solely on the scene graph's
696 rendering thread. See \l {Scene Graph and Rendering} for more information.
697 */
698
699
700/*!
701 Creates a new basic geometry node of type \a type
702
703 \internal
704 */
705QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
706 : QSGNode(type)
707 , m_geometry(nullptr)
708 , m_matrix(nullptr)
709 , m_clip_list(nullptr)
710{
711}
712
713
714/*!
715 \internal
716 */
717QSGBasicGeometryNode::QSGBasicGeometryNode(QSGBasicGeometryNodePrivate &dd, NodeType type)
718 : QSGNode(dd, type)
719 , m_geometry(nullptr)
720 , m_matrix(nullptr)
721 , m_clip_list(nullptr)
722{
723}
724
725
726/*!
727 Deletes this QSGBasicGeometryNode.
728
729 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
730 geometry object it is pointing to. This flag is not set by default.
731 */
732
733QSGBasicGeometryNode::~QSGBasicGeometryNode()
734{
735 if (flags() & OwnsGeometry)
736 delete m_geometry;
737}
738
739
740/*!
741 \fn QSGGeometry *QSGBasicGeometryNode::geometry()
742
743 Returns this node's geometry.
744
745 The geometry is null by default.
746 */
747
748/*!
749 \fn const QSGGeometry *QSGBasicGeometryNode::geometry() const
750
751 Returns this node's geometry.
752
753 The geometry is null by default.
754 */
755
756/*!
757 \fn QMatrix4x4 *QSGBasicGeometryNode::matrix() const
758
759 Will be set during rendering to contain transformation of the geometry
760 for that rendering pass.
761
762 \internal
763 */
764
765/*!
766 \fn QSGClipNode *QSGBasicGeometryNode::clipList() const
767
768 Will be set during rendering to contain the clip of the geometry
769 for that rendering pass.
770
771 \internal
772 */
773
774/*!
775 \fn void QSGBasicGeometryNode::setRendererMatrix(const QMatrix4x4 *m)
776
777 \internal
778 */
779
780/*!
781 \fn void QSGBasicGeometryNode::setRendererClipList(const QSGClipNode *c)
782
783 \internal
784 */
785
786
787/*!
788 Sets the geometry of this node to \a geometry.
789
790 If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
791 geometry object it is pointing to. This flag is not set by default.
792
793 If the geometry is changed without calling setGeometry() again, the user
794 must also mark the geometry as dirty using QSGNode::markDirty().
795
796 \sa markDirty()
797 */
798
799void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
800{
801 if ((flags() & OwnsGeometry) != 0 && m_geometry != geometry)
802 delete m_geometry;
803 m_geometry = geometry;
804 markDirty(bits: DirtyGeometry);
805}
806
807
808
809/*!
810 \class QSGGeometryNode
811 \brief The QSGGeometryNode class is used for all rendered content in the scene graph.
812
813 \inmodule QtQuick
814 \ingroup qtquick-scenegraph-nodes
815
816 The QSGGeometryNode consists of geometry and material. The geometry defines the mesh,
817 the vertices and their structure, to be drawn. The Material defines how the shape is
818 filled.
819
820 The following is a code snippet illustrating how to create a red
821 line using a QSGGeometryNode:
822 \code
823 QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2);
824 geometry->setDrawingMode(GL_LINES);
825 geometry->setLineWidth(3);
826 geometry->vertexDataAsPoint2D()[0].set(0, 0);
827 geometry->vertexDataAsPoint2D()[1].set(width(), height());
828
829 QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
830 material->setColor(QColor(255, 0, 0));
831
832 QSGGeometryNode *node = new QSGGeometryNode;
833 node->setGeometry(geometry);
834 node->setFlag(QSGNode::OwnsGeometry);
835 node->setMaterial(material);
836 node->setFlag(QSGNode::OwnsMaterial);
837 \endcode
838
839 A geometry node must have both geometry and a normal material before it is added to
840 the scene graph. When the geometry and materials are changed after the node has
841 been added to the scene graph, the user should also mark them as dirty using
842 QSGNode::markDirty().
843
844 The geometry node supports two types of materials, the opaqueMaterial and the normal
845 material. The opaqueMaterial is used when the accumulated scene graph opacity at the
846 time of rendering is 1. The primary use case is to special case opaque rendering
847 to avoid an extra operation in the fragment shader can have significant performance
848 impact on embedded graphics chips. The opaque material is optional.
849
850 \note All classes with QSG prefix should be used solely on the scene graph's
851 rendering thread. See \l {Scene Graph and Rendering} for more information.
852
853 \sa QSGGeometry, QSGMaterial, QSGSimpleMaterial
854 */
855
856
857/*!
858 Creates a new geometry node without geometry and material.
859 */
860
861QSGGeometryNode::QSGGeometryNode()
862 : QSGBasicGeometryNode(GeometryNodeType)
863{
864}
865
866
867/*!
868 \internal
869 */
870QSGGeometryNode::QSGGeometryNode(QSGGeometryNodePrivate &dd)
871 : QSGBasicGeometryNode(dd, GeometryNodeType)
872 , m_render_order(0)
873 , m_material(nullptr)
874 , m_opaque_material(nullptr)
875 , m_opacity(1)
876{
877}
878
879
880/*!
881 Deletes this geometry node.
882
883 The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
884 QSGNode::OwnsGeometry decides whether the geometry node should also
885 delete the materials and geometry. By default, these flags are disabled.
886 */
887
888QSGGeometryNode::~QSGGeometryNode()
889{
890 if (flags() & OwnsMaterial)
891 delete m_material;
892 if (flags() & OwnsOpaqueMaterial)
893 delete m_opaque_material;
894}
895
896
897
898/*!
899 \fn int QSGGeometryNode::renderOrder() const
900
901 Returns the render order of this geometry node.
902
903 \internal
904 */
905
906/*!
907 \fn QSGMaterial *QSGGeometryNode::material() const
908
909 Returns the material of the QSGGeometryNode.
910
911 \sa setMaterial()
912 */
913
914/*!
915 \fn QSGMaterial *QSGGeometryNode::opaqueMaterial() const
916
917 Returns the opaque material of the QSGGeometryNode.
918
919 \sa setOpaqueMaterial()
920 */
921
922/*!
923 \fn qreal QSGGeometryNode::inheritedOpacity() const
924
925 Set during rendering to specify the inherited opacity for that
926 rendering pass.
927
928 \internal
929 */
930
931
932/*!
933 Sets the render order of this node to be \a order.
934
935 Geometry nodes are rendered in an order that visually looks like
936 low order nodes are rendered prior to high order nodes. For opaque
937 geometry there is little difference as z-testing will handle
938 the discard, but for translucent objects, the rendering should
939 normally be specified in the order of back-to-front.
940
941 The default render order is \c 0.
942
943 \internal
944 */
945void QSGGeometryNode::setRenderOrder(int order)
946{
947 m_render_order = order;
948}
949
950
951
952/*!
953 Sets the material of this geometry node to \a material.
954
955 Geometry nodes must have a material before they can be added to the
956 scene graph.
957
958 If the material is changed without calling setMaterial() again, the user
959 must also mark the material as dirty using QSGNode::markDirty().
960
961 */
962void QSGGeometryNode::setMaterial(QSGMaterial *material)
963{
964 if ((flags() & OwnsMaterial) != 0 && m_material != material)
965 delete m_material;
966 m_material = material;
967#ifndef QT_NO_DEBUG
968 if (m_material != nullptr && m_opaque_material == m_material)
969 qWarning(msg: "QSGGeometryNode: using same material for both opaque and translucent");
970#endif
971 markDirty(bits: DirtyMaterial);
972}
973
974
975
976/*!
977 Sets the opaque material of this geometry to \a material.
978
979 The opaque material will be preferred by the renderer over the
980 default material, as returned by the material() function, if
981 it is not null and the geometry item has an inherited opacity of
982 1.
983
984 The opaqueness refers to scene graph opacity, the material is still
985 allowed to set QSGMaterial::Blending to true and draw transparent
986 pixels.
987
988 If the material is changed without calling setOpaqueMaterial()
989 again, the user must also mark the opaque material as dirty using
990 QSGNode::markDirty().
991
992 */
993void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
994{
995 if ((flags() & OwnsOpaqueMaterial) != 0 && m_opaque_material != m_material)
996 delete m_opaque_material;
997 m_opaque_material = material;
998#ifndef QT_NO_DEBUG
999 if (m_opaque_material != nullptr && m_opaque_material == m_material)
1000 qWarning(msg: "QSGGeometryNode: using same material for both opaque and translucent");
1001#endif
1002
1003 markDirty(bits: DirtyMaterial);
1004}
1005
1006
1007
1008/*!
1009 Returns the material which should currently be used for geometry node.
1010
1011 If the inherited opacity of the node is 1 and there is an opaque material
1012 set on this node, it will be returned; otherwise, the default material
1013 will be returned.
1014
1015 \warning This function requires the scene graph above this item to be
1016 completely free of dirty states, so it can only be called during rendering
1017
1018 \internal
1019
1020 \sa setMaterial, setOpaqueMaterial
1021 */
1022QSGMaterial *QSGGeometryNode::activeMaterial() const
1023{
1024 if (m_opaque_material && m_opacity > 0.999)
1025 return m_opaque_material;
1026 return m_material;
1027}
1028
1029
1030/*!
1031 Sets the inherited opacity of this geometry to \a opacity.
1032
1033 This function is meant to be called by the node preprocessing
1034 prior to rendering the tree, so it will not mark the tree as
1035 dirty.
1036
1037 \internal
1038 */
1039void QSGGeometryNode::setInheritedOpacity(qreal opacity)
1040{
1041 Q_ASSERT(opacity >= 0 && opacity <= 1);
1042 m_opacity = opacity;
1043}
1044
1045
1046/*!
1047 \class QSGClipNode
1048 \brief The QSGClipNode class implements the clipping functionality in the scene graph.
1049
1050 \inmodule QtQuick
1051 \ingroup qtquick-scenegraph-nodes
1052
1053 Clipping applies to the node's subtree and can be nested. Multiple clip nodes will be
1054 accumulated by intersecting all their geometries. The accumulation happens
1055 as part of the rendering.
1056
1057 Clip nodes must have a geometry before they can be added to the scene graph.
1058
1059 Clipping is usually implemented by using the stencil buffer.
1060
1061 \note All classes with QSG prefix should be used solely on the scene graph's
1062 rendering thread. See \l {Scene Graph and Rendering} for more information.
1063 */
1064
1065
1066
1067/*!
1068 Creates a new QSGClipNode without a geometry.
1069
1070 The clip node must have a geometry before it can be added to the
1071 scene graph.
1072 */
1073
1074QSGClipNode::QSGClipNode()
1075 : QSGBasicGeometryNode(ClipNodeType)
1076 , m_is_rectangular(false)
1077{
1078 Q_UNUSED(m_reserved);
1079}
1080
1081
1082
1083/*!
1084 Deletes this QSGClipNode.
1085
1086 If the flag QSGNode::OwnsGeometry is set, the geometry will also be
1087 deleted.
1088 */
1089
1090QSGClipNode::~QSGClipNode()
1091{
1092}
1093
1094
1095
1096/*!
1097 \fn bool QSGClipNode::isRectangular() const
1098
1099 Returns if this clip node has a rectangular clip.
1100 */
1101
1102
1103
1104/*!
1105 Sets whether this clip node has a rectangular clip to \a rectHint.
1106
1107 This is an optimization hint which means that the renderer can
1108 use scissoring instead of stencil, which is significantly faster.
1109
1110 When this hint is set and it is applicable, the clip region will be
1111 generated from clipRect() rather than geometry().
1112
1113 By default this property is \c false.
1114 */
1115
1116void QSGClipNode::setIsRectangular(bool rectHint)
1117{
1118 m_is_rectangular = rectHint;
1119}
1120
1121
1122
1123/*!
1124 \fn QRectF QSGClipNode::clipRect() const
1125
1126 Returns the clip rect of this node.
1127 */
1128
1129
1130/*!
1131 Sets the clip rect of this clip node to \a rect.
1132
1133 When a rectangular clip is set in combination with setIsRectangular
1134 the renderer may in some cases use a more optimal clip method.
1135 */
1136void QSGClipNode::setClipRect(const QRectF &rect)
1137{
1138 m_clip_rect = rect;
1139}
1140
1141
1142/*!
1143 \class QSGTransformNode
1144 \brief The QSGTransformNode class implements transformations in the scene graph.
1145
1146 \inmodule QtQuick
1147 \ingroup qtquick-scenegraph-nodes
1148
1149 Transformations apply the node's subtree and can be nested. Multiple transform nodes
1150 will be accumulated by intersecting all their matrices. The accumulation happens
1151 as part of the rendering.
1152
1153 The transform nodes implement a 4x4 matrix which in theory supports full 3D
1154 transformations. However, because the renderer optimizes for 2D use-cases rather
1155 than 3D use-cases, rendering a scene with full 3D transformations needs to
1156 be done with some care.
1157
1158 \note All classes with QSG prefix should be used solely on the scene graph's
1159 rendering thread. See \l {Scene Graph and Rendering} for more information.
1160
1161 */
1162
1163
1164/*!
1165 Create a new QSGTransformNode with its matrix set to the identity matrix.
1166 */
1167
1168QSGTransformNode::QSGTransformNode()
1169 : QSGNode(TransformNodeType)
1170{
1171}
1172
1173
1174
1175/*!
1176 Deletes this transform node.
1177 */
1178
1179QSGTransformNode::~QSGTransformNode()
1180{
1181}
1182
1183
1184
1185/*!
1186 \fn QMatrix4x4 QSGTransformNode::matrix() const
1187
1188 Returns this transform node's matrix.
1189 */
1190
1191
1192
1193/*!
1194 Sets this transform node's matrix to \a matrix.
1195 */
1196
1197void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
1198{
1199 m_matrix = matrix;
1200 markDirty(bits: DirtyMatrix);
1201}
1202
1203/*!
1204 \fn const QMatrix4x4 &QSGTransformNode::combinedMatrix() const
1205
1206 Set during rendering to the combination of all parent matrices for
1207 that rendering pass.
1208
1209 \internal
1210 */
1211
1212
1213
1214/*!
1215 Sets the combined matrix of this matrix to \a transform.
1216
1217 This function is meant to be called by the node preprocessing
1218 prior to rendering the tree, so it will not mark the tree as
1219 dirty.
1220
1221 \internal
1222 */
1223void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
1224{
1225 m_combined_matrix = matrix;
1226}
1227
1228
1229
1230/*!
1231 \class QSGRootNode
1232 \brief The QSGRootNode is the toplevel root of any scene graph.
1233
1234 The root node is used to attach a scene graph to a renderer.
1235
1236 \internal
1237 */
1238
1239
1240
1241/*!
1242 \fn QSGRootNode::QSGRootNode()
1243
1244 Creates a new root node.
1245 */
1246
1247QSGRootNode::QSGRootNode()
1248 : QSGNode(RootNodeType)
1249{
1250}
1251
1252
1253/*!
1254 Deletes the root node.
1255
1256 When a root node is deleted it removes itself from all of renderers
1257 that are referencing it.
1258 */
1259
1260QSGRootNode::~QSGRootNode()
1261{
1262 while (!m_renderers.isEmpty())
1263 m_renderers.constLast()->setRootNode(nullptr);
1264 destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode.
1265}
1266
1267
1268
1269/*!
1270 Called to notify all renderers that \a node has been marked as dirty
1271 with \a flags.
1272 */
1273
1274void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyState state)
1275{
1276 for (int i=0; i<m_renderers.size(); ++i) {
1277 m_renderers.at(i)->nodeChanged(node, state);
1278 }
1279}
1280
1281
1282
1283/*!
1284 \class QSGOpacityNode
1285 \brief The QSGOpacityNode class is used to change opacity of nodes.
1286
1287 \inmodule QtQuick
1288 \ingroup qtquick-scenegraph-nodes
1289
1290 Opacity applies to its subtree and can be nested. Multiple opacity nodes
1291 will be accumulated by multiplying their opacity. The accumulation happens
1292 as part of the rendering.
1293
1294 When nested opacity gets below a certain threshold, the subtree might
1295 be marked as blocked, causing isSubtreeBlocked() to return true. This
1296 is done for performance reasons.
1297
1298 \note All classes with QSG prefix should be used solely on the scene graph's
1299 rendering thread. See \l {Scene Graph and Rendering} for more information.
1300 */
1301
1302
1303
1304/*!
1305 Constructs an opacity node with a default opacity of 1.
1306
1307 Opacity accumulates downwards in the scene graph so a node with two
1308 QSGOpacityNode instances above it, both with opacity of 0.5, will have
1309 effective opacity of 0.25.
1310
1311 The default opacity of nodes is 1.
1312 */
1313QSGOpacityNode::QSGOpacityNode()
1314 : QSGNode(OpacityNodeType)
1315{
1316}
1317
1318
1319
1320/*!
1321 Deletes the opacity node.
1322 */
1323
1324QSGOpacityNode::~QSGOpacityNode()
1325{
1326}
1327
1328
1329
1330/*!
1331 \fn qreal QSGOpacityNode::opacity() const
1332
1333 Returns this opacity node's opacity.
1334 */
1335
1336const qreal OPACITY_THRESHOLD = 0.001;
1337
1338/*!
1339 Sets the opacity of this node to \a opacity.
1340
1341 Before rendering the graph, the renderer will do an update pass
1342 over the subtree to propagate the opacity to its children.
1343
1344 The value will be bounded to the range 0 to 1.
1345 */
1346
1347void QSGOpacityNode::setOpacity(qreal opacity)
1348{
1349 opacity = qBound<qreal>(min: 0, val: opacity, max: 1);
1350 if (m_opacity == opacity)
1351 return;
1352 DirtyState dirtyState = DirtyOpacity;
1353
1354 if ((m_opacity < OPACITY_THRESHOLD && opacity >= OPACITY_THRESHOLD) // blocked to unblocked
1355 || (m_opacity >= OPACITY_THRESHOLD && opacity < OPACITY_THRESHOLD)) // unblocked to blocked
1356 dirtyState |= DirtySubtreeBlocked;
1357
1358 m_opacity = opacity;
1359 markDirty(bits: dirtyState);
1360}
1361
1362
1363
1364/*!
1365 \fn qreal QSGOpacityNode::combinedOpacity() const
1366
1367 Returns this node's accumulated opacity.
1368
1369 This value is calculated during rendering and only stored
1370 in the opacity node temporarily.
1371
1372 \internal
1373 */
1374
1375
1376
1377/*!
1378 Sets the combined opacity of this node to \a opacity.
1379
1380 This function is meant to be called by the node preprocessing
1381 prior to rendering the tree, so it will not mark the tree as
1382 dirty.
1383
1384 \internal
1385 */
1386
1387void QSGOpacityNode::setCombinedOpacity(qreal opacity)
1388{
1389 m_combined_opacity = opacity;
1390}
1391
1392
1393
1394/*!
1395 For performance reasons, we block the subtree when the opacity
1396 is below a certain threshold.
1397
1398 \internal
1399 */
1400
1401bool QSGOpacityNode::isSubtreeBlocked() const
1402{
1403 return m_opacity < OPACITY_THRESHOLD;
1404}
1405
1406
1407/*!
1408 \class QSGNodeVisitor
1409 \brief The QSGNodeVisitor class is a helper class for traversing the scene graph.
1410
1411 \internal
1412 */
1413
1414QSGNodeVisitor::~QSGNodeVisitor()
1415{
1416
1417}
1418
1419
1420void QSGNodeVisitor::visitNode(QSGNode *n)
1421{
1422 switch (n->type()) {
1423 case QSGNode::TransformNodeType: {
1424 QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
1425 enterTransformNode(t);
1426 visitChildren(n: t);
1427 leaveTransformNode(t);
1428 break; }
1429 case QSGNode::GeometryNodeType: {
1430 QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
1431 enterGeometryNode(g);
1432 visitChildren(n: g);
1433 leaveGeometryNode(g);
1434 break; }
1435 case QSGNode::ClipNodeType: {
1436 QSGClipNode *c = static_cast<QSGClipNode *>(n);
1437 enterClipNode(c);
1438 visitChildren(n: c);
1439 leaveClipNode(c);
1440 break; }
1441 case QSGNode::OpacityNodeType: {
1442 QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
1443 enterOpacityNode(o);
1444 visitChildren(n: o);
1445 leaveOpacityNode(o);
1446 break; }
1447 default:
1448 visitChildren(n);
1449 break;
1450 }
1451}
1452
1453void QSGNodeVisitor::visitChildren(QSGNode *n)
1454{
1455 for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
1456 visitNode(n: c);
1457}
1458
1459#ifndef QT_NO_DEBUG_STREAM
1460QDebug operator<<(QDebug d, const QSGGeometryNode *n)
1461{
1462 if (!n) {
1463 d << "Geometry(null)";
1464 return d;
1465 }
1466 d << "GeometryNode(" << Qt::hex << (const void *) n << Qt::dec;
1467
1468 const QSGGeometry *g = n->geometry();
1469
1470 if (!g) {
1471 d << "no geometry";
1472 } else {
1473
1474 switch (g->drawingMode()) {
1475 case QSGGeometry::DrawTriangleStrip: d << "strip"; break;
1476 case QSGGeometry::DrawTriangleFan: d << "fan"; break;
1477 case QSGGeometry::DrawTriangles: d << "triangles"; break;
1478 default: break;
1479 }
1480
1481 d << "#V:" << g->vertexCount() << "#I:" << g->indexCount();
1482
1483 if (g->attributeCount() > 0 && g->attributes()->type == QSGGeometry::FloatType) {
1484 float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
1485 int stride = g->sizeOfVertex();
1486 for (int i = 0; i < g->vertexCount(); ++i) {
1487 float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
1488 float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
1489
1490 x1 = qMin(a: x1, b: x);
1491 x2 = qMax(a: x2, b: x);
1492 y1 = qMin(a: y1, b: y);
1493 y2 = qMax(a: y2, b: y);
1494 }
1495
1496 d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
1497 }
1498 }
1499
1500 if (n->material())
1501 d << "materialtype=" << n->material()->type();
1502
1503
1504 d << ')';
1505#ifdef QSG_RUNTIME_DESCRIPTION
1506 d << QSGNodePrivate::description(node: n);
1507#endif
1508 return d;
1509}
1510
1511QDebug operator<<(QDebug d, const QSGClipNode *n)
1512{
1513 if (!n) {
1514 d << "ClipNode(null)";
1515 return d;
1516 }
1517 d << "ClipNode(" << Qt::hex << (const void *) n << Qt::dec;
1518
1519 if (n->childCount())
1520 d << "children=" << n->childCount();
1521
1522 d << "is rect?" << (n->isRectangular() ? "yes" : "no");
1523
1524 d << ')';
1525#ifdef QSG_RUNTIME_DESCRIPTION
1526 d << QSGNodePrivate::description(node: n);
1527#endif
1528 d << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1529 return d;
1530}
1531
1532QDebug operator<<(QDebug d, const QSGTransformNode *n)
1533{
1534 if (!n) {
1535 d << "TransformNode(null)";
1536 return d;
1537 }
1538 const QMatrix4x4 m = n->matrix();
1539 d << "TransformNode(";
1540 d << Qt::hex << (const void *) n << Qt::dec;
1541 if (m.isIdentity())
1542 d << "identity";
1543 else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
1544 d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
1545 else
1546 d << "det=" << n->matrix().determinant();
1547#ifdef QSG_RUNTIME_DESCRIPTION
1548 d << QSGNodePrivate::description(node: n);
1549#endif
1550 d << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1551 d << ')';
1552 return d;
1553}
1554
1555QDebug operator<<(QDebug d, const QSGOpacityNode *n)
1556{
1557 if (!n) {
1558 d << "OpacityNode(null)";
1559 return d;
1560 }
1561 d << "OpacityNode(";
1562 d << Qt::hex << (const void *) n << Qt::dec;
1563 d << "opacity=" << n->opacity()
1564 << "combined=" << n->combinedOpacity()
1565 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1566#ifdef QSG_RUNTIME_DESCRIPTION
1567 d << QSGNodePrivate::description(node: n);
1568#endif
1569 d << ')';
1570 return d;
1571}
1572
1573
1574QDebug operator<<(QDebug d, const QSGRootNode *n)
1575{
1576 if (!n) {
1577 d << "RootNode(null)";
1578 return d;
1579 }
1580 QDebugStateSaver saver(d);
1581 d << "RootNode" << Qt::hex << (const void *) n << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1582#ifdef QSG_RUNTIME_DESCRIPTION
1583 d << QSGNodePrivate::description(node: n);
1584#endif
1585 d << ')';
1586 return d;
1587}
1588
1589
1590
1591QDebug operator<<(QDebug d, const QSGNode *n)
1592{
1593 if (!n) {
1594 d << "Node(null)";
1595 return d;
1596 }
1597 switch (n->type()) {
1598 case QSGNode::GeometryNodeType:
1599 d << static_cast<const QSGGeometryNode *>(n);
1600 break;
1601 case QSGNode::TransformNodeType:
1602 d << static_cast<const QSGTransformNode *>(n);
1603 break;
1604 case QSGNode::ClipNodeType:
1605 d << static_cast<const QSGClipNode *>(n);
1606 break;
1607 case QSGNode::RootNodeType:
1608 d << static_cast<const QSGRootNode *>(n);
1609 break;
1610 case QSGNode::OpacityNodeType:
1611 d << static_cast<const QSGOpacityNode *>(n);
1612 break;
1613 case QSGNode::RenderNodeType:
1614 d << "RenderNode(" << Qt::hex << (const void *) n << Qt::dec
1615 << "flags=" << (int) n->flags() << Qt::dec
1616 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1617#ifdef QSG_RUNTIME_DESCRIPTION
1618 d << QSGNodePrivate::description(node: n);
1619#endif
1620 d << ')';
1621 break;
1622 default:
1623 d << "Node(" << Qt::hex << (const void *) n << Qt::dec
1624 << "flags=" << (int) n->flags() << Qt::dec
1625 << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1626#ifdef QSG_RUNTIME_DESCRIPTION
1627 d << QSGNodePrivate::description(node: n);
1628#endif
1629 d << ')';
1630 break;
1631 }
1632 return d;
1633}
1634
1635#endif
1636
1637QT_END_NAMESPACE
1638

source code of qtdeclarative/src/quick/scenegraph/coreapi/qsgnode.cpp