Revision control

Copy as Markdown

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QEasingCurve>
#include <QVector3D>
inline QUrl testFileUrl(const QString &fileName)
{
static const QString dir = QTest::qFindTestData("data");
QString result = dir;
result += QLatin1Char('/');
result += fileName;
return QUrl::fromLocalFile(result);
}
class Tst_BlendTrees : public QObject
{
Q_OBJECT
private Q_SLOTS:
void checkImport();
void testBlendAnimationNode();
};
void Tst_BlendTrees::checkImport()
{
QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import QtQuick; import QtQuick.Timeline; import QtQuick.Timeline.BlendTrees; Item { }", QUrl());
QScopedPointer<QObject> object(component.create());
QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
}
void Tst_BlendTrees::testBlendAnimationNode()
{
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(testFileUrl("BlendTreeTest.qml"));
QScopedPointer<QObject> object(component.create());
QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
// Get all of the necessary objects
auto *timeline = object->findChild<QObject * >("timeline");
auto *timelineAnimation1 = object->findChild<QObject *>("animation1");
QVERIFY2(timelineAnimation1, "Could not find animation1");
auto *timelineAnimation2 = object->findChild<QObject *>("animation2");
QVERIFY2(timelineAnimation2, "Could not find animation2");
auto *animation1Node = object->findChild<QObject *>("animation1Node");
QVERIFY2(animation1Node, "Could not find animation1Node");
auto *animation2Node = object->findChild<QObject *>("animation2Node");
QVERIFY2(animation2Node, "Could not find animation2Node");
auto *blendAnimation = object->findChild<QObject *>("blendAnimation");
QVERIFY2(blendAnimation, "Could not find blendAnimation");
auto *rectangle = object->findChild<QObject *>("rectangle");
QVERIFY2(rectangle, "Could not find rectangle");
auto *animation1Controller = object->findChild<QObject *>("animation1Controller");
QVERIFY2(animation1Controller, "Could not find animation1Controller");
auto *animation2Controller = object->findChild<QObject *>("animation2Controller");
QVERIFY2(animation2Controller, "Could not find animation2Controller");
// At this point nothing should be happening because the animations have controllers
// attached to this which forces them to always be paused. Starting states is:
// animation1Node.currentFrame == 0
// animation2Node.currentFrame == 100
// rectangle.x = 100
// rectangle.y = 100
// rectangle.color = #ff7f00
QCOMPARE(animation1Node->property("currentFrame").toInt(), 0);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 100);
QCOMPARE(rectangle->property("y").toInt(), 100);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff7f00"));
// Push animation1 to end
// Should be a blend of 50% blend of animation1 and and 50% blend of animation2
// animation 1 should be at frame 100 (100%)
// animation 2 should be at frame 100 (0%)
animation1Controller->setProperty("progress", 1.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 200);
QCOMPARE(rectangle->property("y").toInt(), 200);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ffff00"));
// Push animation2 to end
// Should be a blend of 50% blend of animation1 and and 50% blend of animation2
// animation 1 should be at frame 100 (100%)
// animation 2 should be at frame 200 (100%)
animation2Controller->setProperty("progress", 1.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 100);
QCOMPARE(rectangle->property("y").toInt(), 300);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff7f7f"));
// Change weight to 0.0
// Should be a blend of 100% blend of animation1 and and 0% blend of animation2
// animation 1 should be at frame 100 (100%)
// animation 2 should be at frame 200 (100%)
blendAnimation->setProperty("weight", 0.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 200);
QCOMPARE(rectangle->property("y").toInt(), 200);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ffff00"));
// Change weight to 1.0
// Should be a blend of 0% blend of animation1 and and 100% blend of animation2
// animation 1 should be at frame 100 (100%)
// animation 2 should be at frame 200 (100%)
blendAnimation->setProperty("weight", 1.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 400);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff00ff"));
// Change animation1 to start (should be the same as previous)
// Should be a blend of 0% blend of animation1 and and 100% blend of animation2
// animation 1 should be at frame 0 (0%)
// animation 2 should be at frame 200 (100%)
animation1Controller->setProperty("progress", 0.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 0);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 400);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff00ff"));
// Change weight to 0.0
// Should be a blend of 100% blend of animation1 and and 0% blend of animation2
// animation 1 should be at frame 0 (0%)
// animation 2 should be at frame 200 (100%)
blendAnimation->setProperty("weight", 0.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 0);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 0);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff0000"));
// Change animation2 to start (should be the same as previous)
// Should be a blend of 100% blend of animation1 and and 0% blend of animation2
// animation 1 should be at frame 0 (0%)
// animation 2 should be at frame 100 (0%)
animation2Controller->setProperty("progress", 0.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 0);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 0);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff0000"));
// Disable committing of changes by animationBlendNode
blendAnimation->setProperty("outputEnabled", false);
// Now changing either animation progress or weight should have no effect on the scene
animation1Controller->setProperty("progress", 1.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 0);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff0000"));
animation2Controller->setProperty("progress", 1.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 0);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff0000"));
blendAnimation->setProperty("weight", 0.5f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 0);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff0000"));
// re-enable committing of changes by animationBlendNode
// This should cause the animation to blend to the new state
blendAnimation->setProperty("outputEnabled", true);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 100);
QCOMPARE(rectangle->property("y").toInt(), 300);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff7f7f"));
// Test disconnecting animation1
blendAnimation->setProperty("source1", QVariant());
animation1Controller->setProperty("progress", 0.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 0);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 100);
QCOMPARE(rectangle->property("y").toInt(), 300);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff7f7f"));
// Test disconnecting animation2
blendAnimation->setProperty("source2", QVariant());
animation2Controller->setProperty("progress", 0.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 0);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 100);
QCOMPARE(rectangle->property("y").toInt(), 300);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff7f7f"));
// Disable committing of changes by animationBlendNode
blendAnimation->setProperty("outputEnabled", false);
// Try outputting dirrectly from animation1
animation1Node->setProperty("outputEnabled", true);
// Should have changed to be the value of animation1 at frame 0
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 0);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff0000"));
animation1Controller->setProperty("progress", 1.0f);
// Should have changed to be the value of animation1 at frame 100
QCOMPARE(rectangle->property("x").toInt(), 200);
QCOMPARE(rectangle->property("y").toInt(), 200);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ffff00"));
// Disable outputting dirrectly from animation1
animation1Node->setProperty("outputEnabled", false);
// Try outputting dirrectly from animation2
animation2Node->setProperty("outputEnabled", true);
// Nothing should have changed since both would be at frame 100 anyway
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 200);
QCOMPARE(rectangle->property("y").toInt(), 200);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ffff00"));
animation2Controller->setProperty("progress", 1.0f);
QCOMPARE(animation1Node->property("currentFrame").toInt(), 100);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 200);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 400);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff00ff"));
// Try breaking animation2Node's connection to timeline (the source of frame data)
// currentFrame should change but the output should not
animation2Node->setProperty("timeline", QVariant());
animation2Controller->setProperty("progress", 0.0f);
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 400);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff00ff"));
// reattach the timeline
animation2Node->setProperty("timeline", QVariant::fromValue(timeline));
// Should update the output now that we can fetch frameData for frame 100
QCOMPARE(animation2Node->property("currentFrame").toInt(), 100);
QCOMPARE(rectangle->property("x").toInt(), 200);
QCOMPARE(rectangle->property("y").toInt(), 200);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ffff00"));
// Try breaking animation2Node's connection to animation
animation2Node->setProperty("animation", QVariant());
animation2Controller->setProperty("progress", 1.0f);
QCOMPARE(rectangle->property("x").toInt(), 200);
QCOMPARE(rectangle->property("y").toInt(), 200);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ffff00"));
// reattach the animation
animation2Node->setProperty("animation", QVariant::fromValue(timelineAnimation2));
// Should update the output now that we can fetch frameData for frame 200
QCOMPARE(rectangle->property("x").toInt(), 0);
QCOMPARE(rectangle->property("y").toInt(), 400);
QCOMPARE(rectangle->property("color").value<QColor>(), QColor("#ff00ff"));
}
QTEST_MAIN(Tst_BlendTrees)
#include "tst_blendtrees.moc"