1c50a4aa301f2b8b1859a92b907b4fea9cca942a
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / coreapi / qsgnodeupdater.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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 && node != 0) {
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
109     return false;
110 }
111
112
113 void QSGNodeUpdater::enterTransformNode(QSGTransformNode *t)
114 {
115     if (t->dirtyState() & QSGNode::DirtyMatrix)
116         ++m_force_update;
117
118 #ifdef QSG_UPDATER_DEBUG
119     qDebug() << "enter transform:" << t << "force=" << m_force_update;
120 #endif
121
122     if (!t->matrix().isIdentity()) {
123         if (!m_combined_matrix_stack.isEmpty()) {
124             t->setCombinedMatrix(*m_combined_matrix_stack.last() * t->matrix());
125         } else {
126             t->setCombinedMatrix(t->matrix());
127         }
128         m_combined_matrix_stack.add(&t->combinedMatrix());
129     } else {
130         if (!m_combined_matrix_stack.isEmpty()) {
131             t->setCombinedMatrix(*m_combined_matrix_stack.last());
132         } else {
133             t->setCombinedMatrix(QMatrix4x4());
134         }
135     }
136 }
137
138
139 void QSGNodeUpdater::leaveTransformNode(QSGTransformNode *t)
140 {
141 #ifdef QSG_UPDATER_DEBUG
142     qDebug() << "leave transform:" << t;
143 #endif
144
145     if (t->dirtyState() & QSGNode::DirtyMatrix)
146         --m_force_update;
147
148     if (!t->matrix().isIdentity()) {
149         m_combined_matrix_stack.pop_back();
150     }
151
152 }
153
154
155 void QSGNodeUpdater::enterClipNode(QSGClipNode *c)
156 {
157 #ifdef QSG_UPDATER_DEBUG
158     qDebug() << "enter clip:" << c;
159 #endif
160
161     if (c->dirtyState() & QSGNode::DirtyClipList)
162         ++m_force_update;
163
164     c->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
165     c->m_clip_list = m_current_clip;
166     m_current_clip = c;
167 }
168
169
170 void QSGNodeUpdater::leaveClipNode(QSGClipNode *c)
171 {
172 #ifdef QSG_UPDATER_DEBUG
173     qDebug() << "leave clip:" << c;
174 #endif
175
176     if (c->dirtyState() & QSGNode::DirtyClipList)
177         --m_force_update;
178
179     m_current_clip = c->m_clip_list;
180 }
181
182
183 void QSGNodeUpdater::enterGeometryNode(QSGGeometryNode *g)
184 {
185 #ifdef QSG_UPDATER_DEBUG
186     qDebug() << "enter geometry:" << g;
187 #endif
188
189     g->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.last();
190     g->m_clip_list = m_current_clip;
191     g->setInheritedOpacity(m_opacity_stack.last());
192 }
193
194 void QSGNodeUpdater::leaveGeometryNode(QSGGeometryNode *g)
195 {
196 #ifdef QSG_UPDATER_DEBUG
197     qDebug() << "leave geometry" << g;
198 #else
199     Q_UNUSED(g)
200 #endif
201 }
202
203 void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
204 {
205     if (o->dirtyState() & QSGNode::DirtyOpacity)
206         ++m_force_update;
207
208     qreal opacity = m_opacity_stack.last() * o->opacity();
209     o->setCombinedOpacity(opacity);
210     m_opacity_stack.add(opacity);
211
212 #ifdef QSG_UPDATER_DEBUG
213     qDebug() << "enter opacity" << o;
214 #endif
215 }
216
217 void QSGNodeUpdater::leaveOpacityNode(QSGOpacityNode *o)
218 {
219 #ifdef QSG_UPDATER_DEBUG
220     qDebug() << "leave opacity" << o;
221 #endif
222     if (o->flags() & QSGNode::DirtyOpacity)
223         --m_force_update;
224
225     m_opacity_stack.pop_back();
226 }
227
228 void QSGNodeUpdater::visitChildren(QSGNode *n)
229 {
230     for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
231         visitNode(c);
232 }
233
234 void QSGNodeUpdater::visitNode(QSGNode *n)
235 {
236 #ifdef QSG_UPDATER_DEBUG
237     qDebug() << "enter:" << n;
238 #endif
239
240     if (!n->dirtyState() && !m_force_update)
241         return;
242     if (n->isSubtreeBlocked())
243         return;
244
245     bool forceUpdate = n->dirtyState() & (QSGNode::DirtyNodeAdded | QSGNode::DirtyForceUpdate);
246     if (forceUpdate)
247         ++m_force_update;
248
249     switch (n->type()) {
250     case QSGNode::TransformNodeType: {
251         QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
252         enterTransformNode(t);
253         visitChildren(t);
254         leaveTransformNode(t);
255         break; }
256     case QSGNode::GeometryNodeType: {
257         QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
258         enterGeometryNode(g);
259         visitChildren(g);
260         leaveGeometryNode(g);
261         break; }
262     case QSGNode::ClipNodeType: {
263         QSGClipNode *c = static_cast<QSGClipNode *>(n);
264         enterClipNode(c);
265         visitChildren(c);
266         leaveClipNode(c);
267         break; }
268     case QSGNode::OpacityNodeType: {
269         QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
270         enterOpacityNode(o);
271         visitChildren(o);
272         leaveOpacityNode(o);
273         break; }
274     default:
275         visitChildren(n);
276         break;
277     }
278
279     if (forceUpdate)
280         --m_force_update;
281
282     n->clearDirty();
283 }
284
285 QT_END_NAMESPACE