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