rename QSGGeometry::stride() to sizeOfVertex for symetry with index
[profile/ivi/qtdeclarative.git] / src / declarative / scenegraph / coreapi / qsgnode.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsgnode.h"
43 #include "qsgrenderer_p.h"
44 #include "qsgnodeupdater_p.h"
45 #include "qsgmaterial.h"
46
47 #include "limits.h"
48
49 QT_BEGIN_NAMESPACE
50
51 #ifndef QT_NO_DEBUG
52 static int qt_node_count = 0;
53
54 static 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     \class QSGNode
63     \brief The QSGNode class is the base class for all nodes in the scene graph.
64
65     The QSGNode class can be used as a child container. Children are added with
66     the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
67     insertChildNodeAfter(). Ordering of nodes is important as geometry nodes
68     will be rendered in the order they are added to the scene graph.
69     Actually, the scene may reorder nodes freely, but the resulting visual
70     order is still guaranteed.
71
72     If nodes change every frame, the preprocess() function can be used to
73     apply changes to a node for every frame its rendered. The use of preprocess()
74     must be explicitly enabled by setting the QSGNode::UsePreprocess flag
75     on the node.
76
77     The virtual isSubtreeBlocked() function can be used to disable a subtree all
78     together. Nodes in a blocked subtree will not be preprocessed() and not
79     rendered.
80
81     Anything related to QSGNode should happen on the scene graph rendering thread.
82  */
83
84 QSGNode::QSGNode()
85     : m_parent(0)
86     , m_type(BasicNodeType)
87     , m_firstChild(0)
88     , m_lastChild(0)
89     , m_nextSibling(0)
90     , m_previousSibling(0)
91     , m_subtreeGeometryCount(0)
92     , m_nodeFlags(OwnedByParent)
93     , m_flags(0)
94 {
95     init();
96 }
97
98 QSGNode::QSGNode(NodeType type)
99     : m_parent(0)
100     , m_type(type)
101     , m_firstChild(0)
102     , m_lastChild(0)
103     , m_nextSibling(0)
104     , m_previousSibling(0)
105     , m_subtreeGeometryCount(type == GeometryNodeType ? 1 : 0)
106     , m_nodeFlags(OwnedByParent)
107     , m_flags(0)
108 {
109     init();
110 }
111
112 void QSGNode::init()
113 {
114 #ifndef QT_NO_DEBUG
115     ++qt_node_count;
116     static bool atexit_registered = false;
117     if (!atexit_registered) {
118         atexit(qt_print_node_count);
119         atexit_registered = true;
120     }
121 #endif
122 }
123
124 QSGNode::~QSGNode()
125 {
126 #ifndef QT_NO_DEBUG
127     --qt_node_count;
128     if (qt_node_count < 0)
129         qDebug("Node destroyed after qt_print_node_count() was called.");
130 #endif
131     destroy();
132 }
133
134
135 /*!
136     \fn void QSGNode::preprocess()
137
138     Override this function to do processing on the node before it is rendered.
139
140     Preprocessing needs to be explicitly enabled by setting the flag
141     QSGNode::UsePreprocess. The flag needs to be set before the node is added
142     to the scene graph and will cause the preprocess() function to be called
143     for every frame the node is rendered.
144
145     The preprocess function is called before the update pass that propegates
146     opacity and transformations through the scene graph. That means that
147     functions like QSGOpacityNode::combinedOpacity() and
148     QSGTransformNode::combinedMatrix() will not contain up-to-date values.
149     If such values are changed during the preprocess, these changes will be
150     propegated through the scene graph before it is rendered.
151
152     \warning Beware of deleting nodes while they are being preprocessed. It is
153     possible, with a small performance hit, to delete a single node during its
154     own preprocess call. Deleting a subtree which has nodes that also use
155     preprocessing may result in a segmentation fault. This is done for
156     performance reasons.
157  */
158
159
160
161
162 /*!
163     Returns whether this node and its subtree is available for use.
164
165     Blocked subtrees will not get their dirty states updated and they
166     will not be rendered.
167
168     The QSGOpacityNode will return a blocked subtree when accumulated opacity
169     is 0, for instance.
170  */
171
172 bool QSGNode::isSubtreeBlocked() const
173 {
174     return m_subtreeGeometryCount == 0;
175 }
176
177 /*!
178     \internal
179     Detaches the node from the scene graph and deletes any children it owns.
180
181     This function is called from QSGNode's and QSGRootNode's destructor. It
182     should not be called explicitly in user code. QSGRootNode needs to call
183     destroy() because destroy() calls removeChildNode() which in turn calls
184     markDirty() which type-casts the node to QSGRootNode. This type-cast is not
185     valid at the time QSGNode's destructor is called because the node will
186     already be partially destroyed at that point.
187 */
188
189 void QSGNode::destroy()
190 {
191     if (m_parent) {
192         m_parent->removeChildNode(this);
193         Q_ASSERT(m_parent == 0);
194     }
195     while (m_firstChild) {
196         QSGNode *child = m_firstChild;
197         removeChildNode(child);
198         Q_ASSERT(child->m_parent == 0);
199         if (child->flags() & OwnedByParent)
200             delete child;
201     }
202
203     Q_ASSERT(m_firstChild == 0 && m_lastChild == 0);
204 }
205
206
207 /*!
208     Prepends \a node to this node's the list of children.
209
210     Ordering of nodes is important as geometry nodes will be rendered in the
211     order they are added to the scene graph.
212  */
213
214 void QSGNode::prependChildNode(QSGNode *node)
215 {
216     //Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
217     Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
218
219 #ifndef QT_NO_DEBUG
220     if (node->type() == QSGNode::GeometryNodeType) {
221         QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
222         Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
223         Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
224     }
225 #endif
226
227     if (m_firstChild)
228         m_firstChild->m_previousSibling = node;
229     else
230         m_lastChild = node;
231     node->m_nextSibling = m_firstChild;
232     m_firstChild = node;
233     node->m_parent = this;
234
235     node->markDirty(DirtyNodeAdded);
236 }
237
238 /*!
239     Appends \a node to this node's list of children.
240
241     Ordering of nodes is important as geometry nodes will be rendered in the
242     order they are added to the scene graph.
243  */
244
245 void QSGNode::appendChildNode(QSGNode *node)
246 {
247     //Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
248     Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
249
250 #ifndef QT_NO_DEBUG
251     if (node->type() == QSGNode::GeometryNodeType) {
252         QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
253         Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
254         Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
255     }
256 #endif
257
258     if (m_lastChild)
259         m_lastChild->m_nextSibling = node;
260     else
261         m_firstChild = node;
262     node->m_previousSibling = m_lastChild;
263     m_lastChild = node;
264     node->m_parent = this;
265
266     node->markDirty(DirtyNodeAdded);
267 }
268
269
270
271 /*!
272     Inserts \a node to this node's list of children before the node specified with \a before.
273
274     Ordering of nodes is important as geometry nodes will be rendered in the
275     order they are added to the scene graph.
276  */
277
278 void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
279 {
280     //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
281     Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
282     Q_ASSERT_X(before && before->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
283
284 #ifndef QT_NO_DEBUG
285     if (node->type() == QSGNode::GeometryNodeType) {
286         QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
287         Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
288         Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
289     }
290 #endif
291
292     QSGNode *previous = before->m_previousSibling;
293     if (previous)
294         previous->m_nextSibling = node;
295     else
296         m_firstChild = node;
297     node->m_previousSibling = previous;
298     node->m_nextSibling = before;
299     before->m_previousSibling = node;
300     node->m_parent = this;
301
302     node->markDirty(DirtyNodeAdded);
303 }
304
305
306
307 /*!
308     Inserts \a node to this node's list of children after the node specified with \a after.
309
310     Ordering of nodes is important as geometry nodes will be rendered in the
311     order they are added to the scene graph.
312  */
313
314 void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
315 {
316     //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
317     Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
318     Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
319
320 #ifndef QT_NO_DEBUG
321     if (node->type() == QSGNode::GeometryNodeType) {
322         QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
323         Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
324         Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
325     }
326 #endif
327
328     QSGNode *next = after->m_nextSibling;
329     if (next)
330         next->m_previousSibling = node;
331     else
332         m_lastChild = node;
333     node->m_nextSibling = next;
334     node->m_previousSibling = after;
335     after->m_nextSibling = node;
336     node->m_parent = this;
337
338     node->markDirty(DirtyNodeAdded);
339 }
340
341
342
343 /*!
344     Removes \a node from this node's list of children.
345  */
346
347 void QSGNode::removeChildNode(QSGNode *node)
348 {
349     //Q_ASSERT(m_children.contains(node));
350     Q_ASSERT(node->parent() == this);
351
352     QSGNode *previous = node->m_previousSibling;
353     QSGNode *next = node->m_nextSibling;
354     if (previous)
355         previous->m_nextSibling = next;
356     else
357         m_firstChild = next;
358     if (next)
359         next->m_previousSibling = previous;
360     else
361         m_lastChild = previous;
362     node->m_previousSibling = 0;
363     node->m_nextSibling = 0;
364
365     node->markDirty(DirtyNodeRemoved);
366     node->m_parent = 0;
367 }
368
369
370 /*!
371     Removes all child nodes from this node's list of children.
372  */
373
374 void QSGNode::removeAllChildNodes()
375 {
376     while (m_firstChild) {
377         QSGNode *node = m_firstChild;
378         m_firstChild = node->m_nextSibling;
379         node->m_nextSibling = 0;
380         if (m_firstChild)
381             m_firstChild->m_previousSibling = 0;
382         else
383             m_lastChild = 0;
384         node->markDirty(DirtyNodeRemoved);
385         node->m_parent = 0;
386     }
387 }
388
389
390 int QSGNode::childCount() const
391 {
392     int count = 0;
393     QSGNode *n = m_firstChild;
394     while (n) {
395         ++count;
396         n = n->m_nextSibling;
397     }
398     return count;
399 }
400
401
402 QSGNode *QSGNode::childAtIndex(int i) const
403 {
404     QSGNode *n = m_firstChild;
405     while (i && n) {
406         --i;
407         n = n->m_nextSibling;
408     }
409     return n;
410 }
411
412
413 /*!
414     Sets the flag \a f on this node if \a enabled is true;
415     otherwise clears the flag.
416
417     \sa flags()
418 */
419
420 void QSGNode::setFlag(Flag f, bool enabled)
421 {
422     if (enabled)
423         m_nodeFlags |= f;
424     else
425         m_nodeFlags &= ~f;
426 }
427
428
429 /*!
430     Sets the flags \a f on this node if \a enabled is true;
431     otherwise clears the flags.
432
433     \sa flags()
434 */
435
436 void QSGNode::setFlags(Flags f, bool enabled)
437 {
438     if (enabled)
439         m_nodeFlags |= f;
440     else
441         m_nodeFlags &= ~f;
442 }
443
444
445
446 /*!
447     Marks this node with the states in \a flags as dirty.
448
449     When a node is marked dirty, it recursively mark the parent chain
450     as dirty and notify all connected renderers that the has dirty states.
451  */
452
453 void QSGNode::markDirty(DirtyFlags flags)
454 {
455     m_flags |= (flags & DirtyPropagationMask);
456
457     DirtyFlags subtreeFlags = DirtyFlags((flags & DirtyPropagationMask) << 16);
458
459     int geometryCountDiff = 0;
460     if (flags & DirtyNodeAdded)
461         geometryCountDiff += m_subtreeGeometryCount;
462     if (flags & DirtyNodeRemoved)
463         geometryCountDiff -= m_subtreeGeometryCount;
464
465     QSGNode *p = m_parent;
466     while (p) {
467         p->m_flags |= subtreeFlags;
468         p->m_subtreeGeometryCount += geometryCountDiff;
469         if (p->type() == RootNodeType)
470             static_cast<QSGRootNode *>(p)->notifyNodeChange(this, flags);
471         p = p->m_parent;
472     }
473 }
474
475
476
477 /*!
478     \class QSGBasicGeometryNode
479     \brief The QSGBasicGeometryNode serves as a baseclass for geometry based nodes
480
481     The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
482     shared functionality between the QSGGeometryNode and QSGClipNode classes.
483   */
484
485
486 /*!
487     Creates a new basic geometry node.
488  */
489 QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
490     : QSGNode(type)
491     , m_geometry(0)
492     , m_matrix(0)
493     , m_clip_list(0)
494 {
495 }
496
497
498 /*!
499     Deletes this QSGBasicGeometryNode.
500
501     If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
502     geometry object it is pointing to. This flag is not set by default.
503   */
504
505 QSGBasicGeometryNode::~QSGBasicGeometryNode()
506 {
507     if (flags() & OwnsGeometry)
508         delete m_geometry;
509 }
510
511
512 /*!
513     \fn QSGGeometry *QSGBasicGeometryNode::geometry() const
514
515     Returns this node's geometry.
516
517     The geometry is null by default.
518  */
519
520
521 /*!
522     Sets the geometry of this node to \a geometry.
523
524     If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
525     geometry object it is pointing to. This flag is not set by default.
526  */
527
528 void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
529 {
530     if (flags() & OwnsGeometry)
531         delete m_geometry;
532     m_geometry = geometry;
533     markDirty(DirtyGeometry);
534 }
535
536
537
538 /*!
539     \class QSGGeometryNode
540     \brief The QSGGeometryNode class is used for all rendered content in the scene graph.
541
542     The QSGGeometryNode consists of geometry and material. The geometry defines the mesh,
543     the vertices and their structure, to be drawn. The Material defines how the shape is
544     filled.
545
546     A geometry node must have both geometry and a normal material before it is added to
547     the scene graph.
548
549     The geometry node supports two types of materials, the opaqueMaterial and the normal
550     material. The opaqueMaterial is used when the accumulated scene graph opacity at the
551     time of rendering is 1. The primary usecase is to special case opaque rendering
552     to avoid an extra operation in the fragment shader can have significant performance
553     impact on embedded graphics chips. The opaque material is optional.
554
555  */
556
557
558 /*!
559     Creates a new geometry node without geometry and material.
560  */
561
562 QSGGeometryNode::QSGGeometryNode()
563     : QSGBasicGeometryNode(GeometryNodeType)
564     , m_render_order(0)
565     , m_material(0)
566     , m_opaque_material(0)
567     , m_opacity(1)
568 {
569 }
570
571
572 /*!
573     Deletes this geometry node.
574
575     The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
576     QSGNode::OwnsGeometry decides weither the geometry node should also
577     delete the materials and geometry. By default, these flags are disabled.
578  */
579
580 QSGGeometryNode::~QSGGeometryNode()
581 {
582     if (flags() & OwnsMaterial)
583         delete m_material;
584     if (flags() & OwnsOpaqueMaterial)
585         delete m_opaque_material;
586 }
587
588
589
590 /*!
591     \fn int QSGGeometryNode::renderOrder() const
592
593     Returns the render order of this geometry node.
594
595     \internal
596  */
597
598
599 /*!
600     Sets the render order of this node to be \a order.
601
602     GeometryNodes are rendered in an order that visually looks like
603     low order nodes are rendered prior to high order nodes. For opaque
604     geometry there is little difference as z-testing will handle
605     the discard, but for translucent objects, the rendering should
606     normally be specified in the order of back-to-front.
607
608     The default render order is 0.
609
610     \internal
611   */
612 void QSGGeometryNode::setRenderOrder(int order)
613 {
614     m_render_order = order;
615 }
616
617
618
619 /*!
620     Sets the material of this geometry node to \a material.
621
622     Geometry nodes must have a material before they can be added to the
623     scene graph.
624  */
625 void QSGGeometryNode::setMaterial(QSGMaterial *material)
626 {
627     if (flags() & OwnsMaterial)
628         delete m_material;
629     m_material = material;
630 #ifndef QT_NO_DEBUG
631     if (m_material != 0 && m_opaque_material == m_material)
632         qWarning("QSGGeometryNode: using same material for both opaque and translucent");
633 #endif
634     markDirty(DirtyMaterial);
635 }
636
637
638
639 /*!
640     Sets the opaque material of this geometry to \a material.
641
642     The opaque material will be preferred by the renderer over the
643     default material, as returned by the material() function, if
644     it is not null and the geometry item has an inherited opacity of
645     1.
646
647     The opaqueness refers to scene graph opacity, the material is still
648     allowed to set QSGMaterial::Blending to true and draw transparent
649     pixels.
650  */
651 void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
652 {
653     if (flags() & OwnsOpaqueMaterial)
654         delete m_opaque_material;
655     m_opaque_material = material;
656 #ifndef QT_NO_DEBUG
657     if (m_opaque_material != 0 && m_opaque_material == m_material)
658         qWarning("QSGGeometryNode: using same material for both opaque and translucent");
659 #endif
660
661     markDirty(DirtyMaterial);
662 }
663
664
665
666 /*!
667     Returns the material which should currently be used for geometry node.
668
669     If the inherited opacity of the node is 1 and there is an opaque material
670     set on this node, it will be returned; otherwise, the default material
671     will be returned.
672
673     \warning This function requires the scene graph above this item to be
674     completely free of dirty states, so it can only be called during rendering
675
676     \internal
677
678     \sa setMaterial, setOpaqueMaterial
679  */
680 QSGMaterial *QSGGeometryNode::activeMaterial() const
681 {
682     Q_ASSERT_X(dirtyFlags() == 0, "QSGGeometryNode::activeMaterial()", "function assumes that all dirty states are cleaned up");
683     if (m_opaque_material && m_opacity > 0.999)
684         return m_opaque_material;
685     return m_material;
686 }
687
688
689 /*!
690     Sets the inherited opacity of this geometry to \a opacity.
691
692     This function is meant to be called by the node preprocessing
693     prior to rendering the tree, so it will not mark the tree as
694     dirty.
695
696     \internal
697   */
698 void QSGGeometryNode::setInheritedOpacity(qreal opacity)
699 {
700     Q_ASSERT(opacity >= 0 && opacity <= 1);
701     m_opacity = opacity;
702 }
703
704
705 /*!
706     \class QSGClipNode
707     \brief The QSGClipNode implements the clipping functionality in the scene graph.
708
709     Clipping applies to the node's subtree and can be nested. Multiple clip nodes will be
710     accumulated by intersecting all their geometries. The accumulation happens
711     as part of the rendering.
712
713     Clip nodes must have a geometry before they can be added to the scene graph.
714
715     Clipping is usually implemented by using the stencil buffer.
716  */
717
718
719
720 /*!
721     Creates a new QSGClipNode without a geometry.
722
723     The clip node must have a geometry before it can be added to the
724     scene graph.
725  */
726
727 QSGClipNode::QSGClipNode()
728     : QSGBasicGeometryNode(ClipNodeType)
729 {
730 }
731
732
733
734 /*!
735     Deletes this QSGClipNode.
736
737     If the flag QSGNode::OwnsGeometry is set, the geometry will also be
738     deleted.
739  */
740
741 QSGClipNode::~QSGClipNode()
742 {
743 }
744
745
746
747 /*!
748     \fn bool QSGClipNode::isRectangular() const
749
750     Returns if this clip node has a rectangular clip.
751  */
752
753
754
755 /*!
756     Sets whether this clip node has a rectangular clip to \a rectHint.
757
758     This is an optimization hint which means that the renderer can
759     use scissoring instead of stencil, which is significnatly faster.
760
761     When this hint is and it is applicable, the clip region will be
762     generated from clipRect() rather than geometry().
763  */
764
765 void QSGClipNode::setIsRectangular(bool rectHint)
766 {
767     m_is_rectangular = rectHint;
768 }
769
770
771
772 /*!
773     \fn void QSGClipNode::clipRect() const
774
775     Returns the clip rect of this node.
776  */
777
778
779 /*!
780     Sets the clip rect of this clip node to \a rect.
781
782     When a rectangular clip is set in combination with setIsRectangular
783     the renderer may in some cases use a more optimal clip method.
784  */
785 void QSGClipNode::setClipRect(const QRectF &rect)
786 {
787     m_clip_rect = rect;
788 }
789
790
791 /*!
792     \class QSGTransformNode
793     \brief The QSGTransformNode implements transformations in the scene graph
794
795     Transformations apply the node's subtree and can be nested. Multiple transform nodes
796     will be accumulated by intersecting all their matrices. The accumulation happens
797     as part of the rendering.
798
799     The transform nodes implement a 4x4 matrix which in theory supports full 3D
800     transformations. However, because the renderer optimizes for 2D use-cases rather
801     than 3D use-cases, rendering a scene with full 3D transformations needs to
802     be done with some care.
803  */
804
805 QSGTransformNode::QSGTransformNode()
806     : QSGNode(TransformNodeType)
807 {
808 }
809
810
811
812 /*!
813     Deletes this transform node.
814  */
815
816 QSGTransformNode::~QSGTransformNode()
817 {
818 }
819
820
821
822 /*!
823     \fn QMatrix4x4 QSGTransformNode::matrix() const
824
825     Returns this transform node's matrix.
826  */
827
828
829
830 /*!
831     Sets this transform node's matrix to \a matrix.
832  */
833
834 void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
835 {
836     m_matrix = matrix;
837     markDirty(DirtyMatrix);
838 }
839
840
841 /*!
842     Sets the combined matrix of this matrix to \a transform.
843
844     This function is meant to be called by the node preprocessing
845     prior to rendering the tree, so it will not mark the tree as
846     dirty.
847
848     \internal
849   */
850 void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
851 {
852     m_combined_matrix = matrix;
853 }
854
855
856
857 /*!
858     \class QSGRootNode
859     \brief The QSGRootNode is the toplevel root of any scene graph.
860
861     The root node is used to attach a scene graph to a renderer.
862
863     \internal
864  */
865
866
867
868 /*!
869     \fn QSGRootNode::QSGRootNode()
870
871     Creates a new root node.
872  */
873
874 QSGRootNode::QSGRootNode()
875     : QSGNode(RootNodeType)
876 {
877 }
878
879
880 /*!
881     Deletes the root node.
882
883     When a root node is deleted it removes itself from all of renderers
884     that are referencing it.
885  */
886
887 QSGRootNode::~QSGRootNode()
888 {
889     while (!m_renderers.isEmpty())
890         m_renderers.last()->setRootNode(0);
891     destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode.
892 }
893
894
895
896 /*!
897     Called to notify all renderers that \a node has been marked as dirty
898     with \a flags.
899  */
900
901 void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyFlags flags)
902 {
903     for (int i=0; i<m_renderers.size(); ++i) {
904         m_renderers.at(i)->nodeChanged(node, flags);
905     }
906 }
907
908
909
910 /*!
911     \class QSGOpacityNode
912     \brief The QSGOpacityNode is used
913
914     Opacity apply to its subtree and can be nested. Multiple opacity nodes
915     will be accumulated by multiplying their opacity. The accumulation happens
916     as part of the rendering.
917
918     When nested opacity gets below a certain threshold, the subtree might
919     be marked as blocked, causing isSubtreeBlocked() to return true. This
920     is done for performance reasons.
921
922  */
923
924
925
926 /*!
927     Constructs an opacity node with a default opacity of 1.
928
929     Opacity accumulate downwards in the scene graph so a node with two
930     QSGOpacityNode instances above it, both with opacity of 0.5, will have
931     effective opacity of 0.25.
932
933     The default opacity of nodes is 1.
934   */
935 QSGOpacityNode::QSGOpacityNode()
936     : QSGNode(OpacityNodeType)
937     , m_opacity(1)
938     , m_combined_opacity(1)
939 {
940 }
941
942
943
944 /*!
945     Deletes the opacity node.
946  */
947
948 QSGOpacityNode::~QSGOpacityNode()
949 {
950 }
951
952
953
954 /*!
955     \fn qreal QSGOpacityNode::opacity() const
956
957     Returns this opacity node's opacity.
958  */
959
960
961
962 /*!
963     Sets the opacity of this node to \a opacity.
964
965     Before rendering the graph, the renderer will do an update pass
966     over the subtree to propegate the opacity to its children.
967
968     The value will be bounded to the range 0 to 1.
969  */
970
971 void QSGOpacityNode::setOpacity(qreal opacity)
972 {
973     opacity = qBound<qreal>(0, opacity, 1);
974     if (m_opacity == opacity)
975         return;
976     m_opacity = opacity;
977     markDirty(DirtyOpacity);
978 }
979
980
981
982 /*!
983     \fn qreal QSGOpacityNode::combinedOpacity() const
984
985     Returns this node's accumulated opacity.
986
987     This vaule is calculated during rendering and only stored
988     in the opacity node temporarily.
989
990     \internal
991  */
992
993
994
995 /*!
996     Sets the combined opacity of this node to \a opacity.
997
998     This function is meant to be called by the node preprocessing
999     prior to rendering the tree, so it will not mark the tree as
1000     dirty.
1001
1002     \internal
1003  */
1004
1005 void QSGOpacityNode::setCombinedOpacity(qreal opacity)
1006 {
1007     m_combined_opacity = opacity;
1008 }
1009
1010
1011
1012 /*!
1013     For performance reasons, we block the subtree when the opacity
1014     is below a certain threshold.
1015
1016     \internal
1017  */
1018
1019 bool QSGOpacityNode::isSubtreeBlocked() const
1020 {
1021     return QSGNode::isSubtreeBlocked() || m_opacity < 0.001;
1022 }
1023
1024
1025 /*!
1026     \class QSGNodeVisitor
1027     \brief The QSGNodeVisitor class is a helper class for traversing the scene graph.
1028
1029     \internal
1030  */
1031
1032 QSGNodeVisitor::~QSGNodeVisitor()
1033 {
1034
1035 }
1036
1037
1038 void QSGNodeVisitor::visitNode(QSGNode *n)
1039 {
1040     switch (n->type()) {
1041     case QSGNode::TransformNodeType: {
1042         QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
1043         enterTransformNode(t);
1044         visitChildren(t);
1045         leaveTransformNode(t);
1046         break; }
1047     case QSGNode::GeometryNodeType: {
1048         QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
1049         enterGeometryNode(g);
1050         visitChildren(g);
1051         leaveGeometryNode(g);
1052         break; }
1053     case QSGNode::ClipNodeType: {
1054         QSGClipNode *c = static_cast<QSGClipNode *>(n);
1055         enterClipNode(c);
1056         visitChildren(c);
1057         leaveClipNode(c);
1058         break; }
1059     case QSGNode::OpacityNodeType: {
1060         QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
1061         enterOpacityNode(o);
1062         visitChildren(o);
1063         leaveOpacityNode(o);
1064         break; }
1065     default:
1066         visitChildren(n);
1067         break;
1068     }
1069 }
1070
1071 void QSGNodeVisitor::visitChildren(QSGNode *n)
1072 {
1073     for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
1074         visitNode(c);
1075 }
1076
1077
1078
1079 #ifndef QT_NO_DEBUG_STREAM
1080 QDebug operator<<(QDebug d, const QSGGeometryNode *n)
1081 {
1082     if (!n) {
1083         d << "QSGGeometryNode(null)";
1084         return d;
1085     }
1086     d << "QSGGeometryNode(" << hex << (void *) n << dec;
1087
1088     const QSGGeometry *g = n->geometry();
1089
1090     if (!g) {
1091         d << "no geometry";
1092     } else {
1093
1094         switch (g->drawingMode()) {
1095         case GL_TRIANGLE_STRIP: d << "strip"; break;
1096         case GL_TRIANGLE_FAN: d << "fan"; break;
1097         case GL_TRIANGLES: d << "triangles"; break;
1098         default: break;
1099         }
1100
1101          d << g->vertexCount();
1102
1103          if (g->attributeCount() > 0 && g->attributes()->type == GL_FLOAT) {
1104              float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
1105              int stride = g->sizeOfVertex();
1106              for (int i = 0; i < g->vertexCount(); ++i) {
1107                  float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
1108                  float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
1109
1110                  x1 = qMin(x1, x);
1111                  x2 = qMax(x2, x);
1112                  y1 = qMin(y1, y);
1113                  y2 = qMax(y2, y);
1114              }
1115
1116              d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
1117          }
1118     }
1119
1120     d << "order=" << n->renderOrder();
1121     if (n->material())
1122         d << "effect=" << n->material() << "type=" << n->material()->type();
1123
1124
1125     d << ")";
1126 #ifdef QML_RUNTIME_TESTING
1127     d << n->description;
1128 #endif
1129     d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
1130     return d;
1131 }
1132
1133 QDebug operator<<(QDebug d, const QSGClipNode *n)
1134 {
1135     if (!n) {
1136         d << "QSGClipNode(null)";
1137         return d;
1138     }
1139     d << "QSGClipNode(" << hex << (void *) n << dec;
1140
1141     if (n->childCount())
1142         d << "children=" << n->childCount();
1143
1144     d << "is rect?" << (n->isRectangular() ? "yes" : "no");
1145
1146     d << ")";
1147 #ifdef QML_RUNTIME_TESTING
1148     d << n->description;
1149 #endif
1150     d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1151     return d;
1152 }
1153
1154 QDebug operator<<(QDebug d, const QSGTransformNode *n)
1155 {
1156     if (!n) {
1157         d << "QSGTransformNode(null)";
1158         return d;
1159     }
1160     const QMatrix4x4 m = n->matrix();
1161     d << "QSGTransformNode(";
1162     d << hex << (void *) n << dec;
1163     if (m.isIdentity())
1164         d << "identity";
1165     else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
1166         d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
1167     else
1168         d << "det=" << n->matrix().determinant();
1169 #ifdef QML_RUNTIME_TESTING
1170     d << n->description;
1171 #endif
1172     d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1173     d << ")";
1174     return d;
1175 }
1176
1177 QDebug operator<<(QDebug d, const QSGOpacityNode *n)
1178 {
1179     if (!n) {
1180         d << "QSGOpacityNode(null)";
1181         return d;
1182     }
1183     d << "QSGOpacityNode(";
1184     d << hex << (void *) n << dec;
1185     d << "opacity=" << n->opacity()
1186       << "combined=" << n->combinedOpacity()
1187       << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1188 #ifdef QML_RUNTIME_TESTING
1189     d << n->description;
1190 #endif
1191     d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
1192     d << ")";
1193     return d;
1194 }
1195
1196
1197 QDebug operator<<(QDebug d, const QSGRootNode *n)
1198 {
1199     if (!n) {
1200         d << "QSGRootNode(null)";
1201         return d;
1202     }
1203     d << "QSGRootNode" << hex << (void *) n << "dirty=" << (int) n->dirtyFlags() << dec
1204       << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1205 #ifdef QML_RUNTIME_TESTING
1206     d << n->description;
1207 #endif
1208     d << ")";
1209     return d;
1210 }
1211
1212
1213
1214 QDebug operator<<(QDebug d, const QSGNode *n)
1215 {
1216     if (!n) {
1217         d << "QSGNode(null)";
1218         return d;
1219     }
1220     switch (n->type()) {
1221     case QSGNode::GeometryNodeType:
1222         d << static_cast<const QSGGeometryNode *>(n);
1223         break;
1224     case QSGNode::TransformNodeType:
1225         d << static_cast<const QSGTransformNode *>(n);
1226         break;
1227     case QSGNode::ClipNodeType:
1228         d << static_cast<const QSGClipNode *>(n);
1229         break;
1230     case QSGNode::RootNodeType:
1231         d << static_cast<const QSGRootNode *>(n);
1232         break;
1233     case QSGNode::OpacityNodeType:
1234         d << static_cast<const QSGOpacityNode *>(n);
1235         break;
1236     default:
1237         d << "QSGNode(" << hex << (void *) n << dec
1238           << "dirty=" << hex << (int) n->dirtyFlags()
1239           << "flags=" << (int) n->flags() << dec
1240           << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
1241 #ifdef QML_RUNTIME_TESTING
1242         d << n->description;
1243 #endif
1244         d << ")";
1245         break;
1246     }
1247     return d;
1248 }
1249
1250 #endif
1251
1252 QT_END_NAMESPACE