1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the Qt scene graph research project.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtCore/QString>
43 #include <QtTest/QtTest>
45 #include <QtQuick/qsgnode.h>
46 #include <QtQuick/private/qsgrenderer_p.h>
47 #include <QtQuick/private/qsgnodeupdater_p.h>
49 #include <QtQuick/qsgsimplerectnode.h>
50 #include <QtOpenGL/QGLWidget>
51 class NodesTest : public QObject
60 void cleanupTestCase() {
66 void propegateWithMultipleRoots();
67 void simulatedEffect_data();
68 void simulatedEffect();
71 void basicOpacityNode();
72 void opacityPropegation();
75 void isBlockedCheck();
80 QSGNodeUpdater updater;
83 void NodesTest::initTestCase()
85 widget = new QGLWidget();
86 widget->resize(100, 30);
90 class DummyRenderer : public QSGRenderer
93 DummyRenderer(QSGRootNode *root)
94 : QSGRenderer(QSGContext::createDefaultContext())
104 renderingOrder = ++globalRendereringOrder;
107 void nodeChanged(QSGNode *node, QSGNode::DirtyState state) {
109 changedState = state;
110 QSGRenderer::nodeChanged(node, state);
113 QSGNode *changedNode;
114 QSGNode::DirtyState changedState;
118 static int globalRendereringOrder;
121 int DummyRenderer::globalRendereringOrder;
123 NodesTest::NodesTest()
128 void NodesTest::propegate()
131 QSGNode child; child.setFlag(QSGNode::OwnedByParent, false);
132 root.appendChildNode(&child);
134 DummyRenderer renderer(&root);
136 child.markDirty(QSGNode::DirtyGeometry);
138 QCOMPARE(&child, renderer.changedNode);
139 QCOMPARE((int) renderer.changedState, (int) QSGNode::DirtyGeometry);
143 void NodesTest::propegateWithMultipleRoots()
146 QSGNode child2; child2.setFlag(QSGNode::OwnedByParent, false);
147 QSGRootNode root3; root3.setFlag(QSGNode::OwnedByParent, false);
148 QSGNode child4; child4.setFlag(QSGNode::OwnedByParent, false);
150 root1.appendChildNode(&child2);
151 child2.appendChildNode(&root3);
152 root3.appendChildNode(&child4);
154 DummyRenderer ren1(&root1);
155 DummyRenderer ren2(&root3);
157 child4.markDirty(QSGNode::DirtyGeometry);
159 QCOMPARE(ren1.changedNode, &child4);
160 QCOMPARE(ren2.changedNode, &child4);
162 QCOMPARE((int) ren1.changedState, (int) QSGNode::DirtyGeometry);
163 QCOMPARE((int) ren2.changedState, (int) QSGNode::DirtyGeometry);
168 class SimulatedEffectRenderer : public DummyRenderer
171 SimulatedEffectRenderer(QSGRootNode *root, QSGBasicGeometryNode *c)
172 : DummyRenderer(root)
178 matrix = child->matrix() ? *child->matrix() : QMatrix4x4();
179 DummyRenderer::render();
182 QSGBasicGeometryNode *child;
187 class PseudoEffectNode : public QSGNode {
189 PseudoEffectNode(QSGRenderer *r)
192 setFlag(UsePreprocess);
197 if (renderer->rootNode()->parent()) {
198 // Mark the root dirty to build a clean state from the root and down
199 renderer->rootNode()->markDirty(QSGNode::DirtyForceUpdate);
202 renderer->renderScene();
204 if (renderer->rootNode()->parent()) {
205 // Mark the parent of the root dirty to force the root and down to be updated.
206 renderer->rootNode()->parent()->markDirty(QSGNode::DirtyForceUpdate);
210 QSGRenderer *renderer;
213 void NodesTest::simulatedEffect_data()
215 QTest::addColumn<bool>("connected");
217 QTest::newRow("connected") << true;
218 QTest::newRow("disconnected") << false;
221 void NodesTest::simulatedEffect()
223 QFETCH(bool, connected);
227 QSGTransformNode xform;
228 QSGSimpleRectNode geometry;
229 geometry.setRect(QRectF(0, 0, 1, 1));
230 geometry.setColor(Qt::red);
232 root.setFlag(QSGNode::OwnedByParent, false);
233 source.setFlag(QSGNode::OwnedByParent, false);
234 xform.setFlag(QSGNode::OwnedByParent, false);
235 geometry.setFlag(QSGNode::OwnedByParent, false);
237 SimulatedEffectRenderer rootRenderer(&root, &geometry);
238 SimulatedEffectRenderer sourceRenderer(&source, &geometry);
240 PseudoEffectNode effect(&sourceRenderer);
243 root Source is redirected into effect using the SimulatedEffectRenderer
252 root.appendChildNode(&xform);
253 root.appendChildNode(&effect);
255 xform.appendChildNode(&source);
256 source.appendChildNode(&geometry);
257 QMatrix4x4 m; m.translate(1, 2, 3);
260 // Clear all dirty states...
261 updater.updateStates(&root);
263 rootRenderer.renderScene();
265 // compare that we got one render call to each
266 QCOMPARE(rootRenderer.renderCount, 1);
267 QCOMPARE(sourceRenderer.renderCount, 1);
268 QVERIFY(sourceRenderer.renderingOrder < rootRenderer.renderingOrder);
269 if (connected) // geometry is not rendered in this case, so skip it...
270 QCOMPARE(rootRenderer.matrix, xform.matrix());
271 QCOMPARE(sourceRenderer.matrix, QMatrix4x4());
274 void NodesTest::basicOpacityNode()
277 QCOMPARE(n.opacity(), 1.);
280 QCOMPARE(n.opacity(), 0.5);
283 QCOMPARE(n.opacity(), 0.);
286 QCOMPARE(n.opacity(), 1.);
289 void NodesTest::opacityPropegation()
292 QSGOpacityNode *a = new QSGOpacityNode;
293 QSGOpacityNode *b = new QSGOpacityNode;
294 QSGOpacityNode *c = new QSGOpacityNode;
296 QSGSimpleRectNode *geometry = new QSGSimpleRectNode;
297 geometry->setRect(0, 0, 100, 100);
299 root.appendChildNode(a);
300 a->appendChildNode(b);
301 b->appendChildNode(c);
302 c->appendChildNode(geometry);
308 updater.updateStates(&root);
310 QCOMPARE(a->combinedOpacity(), 0.9);
311 QCOMPARE(b->combinedOpacity(), 0.9 * 0.8);
312 QCOMPARE(c->combinedOpacity(), 0.9 * 0.8 * 0.7);
313 QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.8 * 0.7);
316 updater.updateStates(&root);
318 QCOMPARE(a->combinedOpacity(), 0.9);
319 QCOMPARE(b->combinedOpacity(), 0.9 * 0.1);
320 QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
321 QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);
324 updater.updateStates(&root);
326 QVERIFY(b->isSubtreeBlocked());
328 // Verify that geometry did not get updated as it is in a blocked
330 QCOMPARE(c->combinedOpacity(), 0.9 * 0.1 * 0.7);
331 QCOMPARE(geometry->inheritedOpacity(), 0.9 * 0.1 * 0.7);
334 void NodesTest::isBlockedCheck()
337 QSGOpacityNode *opacity = new QSGOpacityNode();
338 QSGNode *node = new QSGNode();
340 root.appendChildNode(opacity);
341 opacity->appendChildNode(node);
343 QSGNodeUpdater updater;
345 opacity->setOpacity(0);
346 QVERIFY(updater.isNodeBlocked(node, &root));
348 opacity->setOpacity(1);
349 QVERIFY(!updater.isNodeBlocked(node, &root));
352 QTEST_MAIN(NodesTest);
354 #include "tst_nodestest.moc"