c5fa656c71c02aa01e6e23023436b7fb4ead0648
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / coreapi / qsgnodeupdater.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 "qsgnodeupdater_p.h"
43
44 QT_BEGIN_NAMESPACE
45
46 // #define QSG_UPDATER_DEBUG
47
48 QSGNodeUpdater::QSGNodeUpdater()
49     : m_combined_matrix_stack(64)
50     , m_opacity_stack(64)
51     , m_current_clip(0)
52     , m_force_update(0)
53 {
54     m_opacity_stack.add(1);
55 }
56
57 void QSGNodeUpdater::updateStates(QSGNode *n)
58 {
59     m_current_clip = 0;
60     m_force_update = 0;
61
62     Q_ASSERT(m_opacity_stack.size() == 1); // The one we added in the constructr...
63     Q_ASSERT(m_combined_matrix_stack.isEmpty());
64
65     visitNode(n);
66 }
67
68 /*!
69     \fn void QSGNodeUpdater::setToplevelOpacity(qreal opacity)
70
71     Sets the toplevel opacity that will be multiplied with the
72
73     The default opacity is 1. Any other value will cause artifacts, and is
74     primarily useful for debug purposes.
75
76     The changing the value during an update pass will have undefined results
77  */
78
79 /*!
80     \fn qreal QSGNodeUpdater::toplevelOpacity() const
81
82     Returns the toplevel opacity for the node updater. The default
83     value is 1.
84  */
85
86
87 /*!
88     Returns true if \a node is has something that blocks it in the chain from
89     \a node to \a root doing a full state update pass.
90
91     This function does not process dirty states, simply does a simple traversion
92     up to the top.
93
94     The function assumes that \a root exists in the parent chain of \a node.
95  */
96
97 bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
98 {
99     qreal opacity = 1;
100     while (node != root) {
101         if (node->type() == QSGNode::OpacityNodeType) {
102             opacity *= static_cast<QSGOpacityNode *>(node)->opacity();
103             if (opacity < 0.001)
104                 return true;
105         }
106         node = node->parent();
107
108         Q_ASSERT_X(node, "QSGNodeUpdater::isNodeBlocked", "node is not in the subtree of root");
109     }
110
111     return false;
112 }
113
114
115 void QSGNodeUpdater::enterTransformNode(QSGTransformNode *t)
116 {
117     if (t->dirtyState() & QSGNode::DirtyMatrix)
118         ++m_force_update;
119
120 #ifdef QSG_UPDATER_DEBUG
121     qDebug() << "enter transform:" << t << "force=" << m_force_update;
122 #endif
123
124     if (!t->matrix().isIdentity()) {
125         if (!m_combined_matrix_stack.isEmpty()) {
126             t->setCombinedMatrix(*m_combined_matrix_stack.last() * t->matrix());
127         } else {
128             t->setCombinedMatrix(t->matrix());
129         }
130         m_combined_matrix_stack.add(&t->combinedMatrix());
131     } else {
132         if (!m_combined_matrix_stack.isEmpty()) {
133             t->setCombinedMatrix(*m_combined_matrix_stack.last());
134         } else {
135             t->setCombinedMatrix(QMatrix4x4());
136         }
137     }
138 }
139
140
141 void QSGNodeUpdater::leaveTransformNode(QSGTransformNode *t)
142 {
143 #ifdef QSG_UPDATER_DEBUG
144     qDebug() << "leave transform:" << t;
145 #endif
146
147     if (t->dirtyState() & QSGNode::DirtyMatrix)
148         --m_force_update;
149
150     if (!t->matrix().isIdentity()) {
151         m_combined_matrix_stack.pop_back();
152     }
153
154 }
155
156
157 void QSGNodeUpdater::enterClipNode(QSGClipNode *c)
158 {
159 #ifdef QSG_UPDATER_DEBUG
160     qDebug() << "enter clip:" << c;
161 #endif
162
163     if (c->dirtyState() & QSGNode::DirtyClipList)
164         ++m_force_update;
165
166     c->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
167     c->m_clip_list = m_current_clip;
168     m_current_clip = c;
169 }
170
171
172 void QSGNodeUpdater::leaveClipNode(QSGClipNode *c)
173 {
174 #ifdef QSG_UPDATER_DEBUG
175     qDebug() << "leave clip:" << c;
176 #endif
177
178     if (c->dirtyState() & QSGNode::DirtyClipList)
179         --m_force_update;
180
181     m_current_clip = c->m_clip_list;
182 }
183
184
185 void QSGNodeUpdater::enterGeometryNode(QSGGeometryNode *g)
186 {
187 #ifdef QSG_UPDATER_DEBUG
188     qDebug() << "enter geometry:" << g;
189 #endif
190
191     g->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
192     g->m_clip_list = m_current_clip;
193     g->setInheritedOpacity(m_opacity_stack.last());
194 }
195
196 void QSGNodeUpdater::leaveGeometryNode(QSGGeometryNode *g)
197 {
198 #ifdef QSG_UPDATER_DEBUG
199     qDebug() << "leave geometry" << g;
200 #else
201     Q_UNUSED(g)
202 #endif
203 }
204
205 void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
206 {
207     if (o->dirtyState() & QSGNode::DirtyOpacity)
208         ++m_force_update;
209
210     qreal opacity = m_opacity_stack.last() * o->opacity();
211     o->setCombinedOpacity(opacity);
212     m_opacity_stack.add(opacity);
213
214 #ifdef QSG_UPDATER_DEBUG
215     qDebug() << "enter opacity" << o;
216 #endif
217 }
218
219 void QSGNodeUpdater::leaveOpacityNode(QSGOpacityNode *o)
220 {
221 #ifdef QSG_UPDATER_DEBUG
222     qDebug() << "leave opacity" << o;
223 #endif
224     if (o->flags() & QSGNode::DirtyOpacity)
225         --m_force_update;
226
227     m_opacity_stack.pop_back();
228 }
229
230 void QSGNodeUpdater::visitChildren(QSGNode *n)
231 {
232     for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
233         visitNode(c);
234 }
235
236 void QSGNodeUpdater::visitNode(QSGNode *n)
237 {
238 #ifdef QSG_UPDATER_DEBUG
239     qDebug() << "enter:" << n;
240 #endif
241
242     if (!n->dirtyState() && !m_force_update)
243         return;
244     if (n->isSubtreeBlocked())
245         return;
246
247     bool forceUpdate = n->dirtyState() & (QSGNode::DirtyNodeAdded | QSGNode::DirtyForceUpdate);
248     if (forceUpdate)
249         ++m_force_update;
250
251     switch (n->type()) {
252     case QSGNode::TransformNodeType: {
253         QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
254         enterTransformNode(t);
255         visitChildren(t);
256         leaveTransformNode(t);
257         break; }
258     case QSGNode::GeometryNodeType: {
259         QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
260         enterGeometryNode(g);
261         visitChildren(g);
262         leaveGeometryNode(g);
263         break; }
264     case QSGNode::ClipNodeType: {
265         QSGClipNode *c = static_cast<QSGClipNode *>(n);
266         enterClipNode(c);
267         visitChildren(c);
268         leaveClipNode(c);
269         break; }
270     case QSGNode::OpacityNodeType: {
271         QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
272         enterOpacityNode(o);
273         visitChildren(o);
274         leaveOpacityNode(o);
275         break; }
276     default:
277         visitChildren(n);
278         break;
279     }
280
281     if (forceUpdate)
282         --m_force_update;
283
284     n->clearDirty();
285 }
286
287 QT_END_NAMESPACE