// Copyright (C) 2017 Paul Lemire // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include #include #include #include #include #include #include "qbackendnodetester.h" #include #include using namespace Qt3DAnimation::Animation; namespace { class TestClipBlendNode : public ClipBlendNode { public: TestClipBlendNode(const ClipResults &clipResults = ClipResults()) : ClipBlendNode(ClipBlendNode::LerpBlendType) , m_clipResults(clipResults) {} inline QList allDependencyIds() const override { return currentDependencyIds(); } QList currentDependencyIds() const final { return {}; } using ClipBlendNode::setClipResults; double duration() const final { return 0.0f; } protected: ClipResults doBlend(const QList &) const final { return m_clipResults; } private: ClipResults m_clipResults; }; } // anonymous Q_DECLARE_METATYPE(TestClipBlendNode *) class tst_ClipBlendNode : public Qt3DCore::QBackendNodeTester { Q_OBJECT public: TestClipBlendNode *createTestClipBlendNode(Handler *handler, const ClipResults &clipResults) { auto id = Qt3DCore::QNodeId::createId(); TestClipBlendNode *node = new TestClipBlendNode(clipResults); setPeerId(node, id); handler->clipBlendNodeManager()->appendNode(id, node); return node; } BlendedClipAnimator *createBlendedClipAnimator(Handler *handler, qint64 globalStartTimeNS, int loops) { auto animatorId = Qt3DCore::QNodeId::createId(); BlendedClipAnimator *animator = handler->blendedClipAnimatorManager()->getOrCreateResource(animatorId); setPeerId(animator, animatorId); animator->setStartTime(globalStartTimeNS); animator->setLoops(loops); return animator; } private Q_SLOTS: void checkInitialState() { // GIVEN TestClipBlendNode backendClipBlendNode; // THEN QCOMPARE(backendClipBlendNode.isEnabled(), false); QVERIFY(backendClipBlendNode.peerId().isNull()); QVERIFY(backendClipBlendNode.clipBlendNodeManager() == nullptr); QCOMPARE(backendClipBlendNode.blendType(), ClipBlendNode::LerpBlendType); QCOMPARE(backendClipBlendNode.clipResults(Qt3DCore::QNodeId()), ClipResults()); } void checkInitializeFromPeer() { // GIVEN Qt3DAnimation::QLerpClipBlend clipBlendNode; Qt3DAnimation::QAnimationClipLoader clip; QCoreApplication::processEvents(); { // WHEN ClipBlendNodeManager manager; TestClipBlendNode backendClipBlendNode; backendClipBlendNode.setClipBlendNodeManager(&manager); simulateInitializationSync(&clipBlendNode, &backendClipBlendNode); // THEN QCOMPARE(backendClipBlendNode.isEnabled(), true); QCOMPARE(backendClipBlendNode.peerId(), clipBlendNode.id()); QCOMPARE(backendClipBlendNode.clipBlendNodeManager(), &manager); QCOMPARE(backendClipBlendNode.blendType(), ClipBlendNode::LerpBlendType); QCOMPARE(backendClipBlendNode.clipResults(Qt3DCore::QNodeId()), ClipResults()); } { // WHEN ClipBlendNodeManager manager; TestClipBlendNode backendClipBlendNode; clipBlendNode.setEnabled(false); backendClipBlendNode.setClipBlendNodeManager(&manager); simulateInitializationSync(&clipBlendNode, &backendClipBlendNode); // THEN QCOMPARE(backendClipBlendNode.peerId(), clipBlendNode.id()); QCOMPARE(backendClipBlendNode.isEnabled(), false); } } void checkClipResults_data() { QTest::addColumn("blendNode"); QTest::addColumn>("indexes"); QTest::addColumn>("animatorIds"); QTest::addColumn>("expectedClipResults"); // Single entry { auto blendNode = new TestClipBlendNode; QList animatorIds; QList expectedClipResults; const auto animatorId = Qt3DCore::QNodeId::createId(); animatorIds.push_back(animatorId); ClipResults clipResults = { 0.0f, 1.0f, 2.0f }; for (int i = 0; i < 3; ++i) clipResults.push_back(float(i)); expectedClipResults.push_back(clipResults); // Set data and indexes blendNode->setClipResults(animatorId, clipResults); const QList indexes = { 0 }; QTest::newRow("single entry") << blendNode << indexes << animatorIds << expectedClipResults; } // No data { auto blendNode = new TestClipBlendNode; QList animatorIds; QList expectedClipResults; auto animatorId = Qt3DCore::QNodeId::createId(); animatorIds.push_back(animatorId); ClipResults clipResults; expectedClipResults.push_back(clipResults); // Don't set any data const QList indexes = { 0 }; QTest::newRow("no entries") << blendNode << indexes << animatorIds << expectedClipResults; } // Multiple entries, ordered { auto blendNode = new TestClipBlendNode; QList animatorIds; QList expectedClipResults; const int animatorCount = 10; for (int j = 0; j < animatorCount; ++j) { auto animatorId = Qt3DCore::QNodeId::createId(); animatorIds.push_back(animatorId); ClipResults clipResults; for (int i = 0; i < j + 5; ++i) clipResults.push_back(float(i + j)); expectedClipResults.push_back(clipResults); blendNode->setClipResults(animatorId, clipResults); } QVector indexes(animatorCount); std::iota(indexes.begin(), indexes.end(), 0); QTest::newRow("multiple entries, ordered") << blendNode << indexes << animatorIds << expectedClipResults; } // Multiple entries, unordered { auto blendNode = new TestClipBlendNode; QList animatorIds; QList expectedClipResults; const int animatorCount = 10; for (int j = 0; j < animatorCount; ++j) { auto animatorId = Qt3DCore::QNodeId::createId(); animatorIds.push_back(animatorId); ClipResults clipResults; for (int i = 0; i < j + 5; ++i) clipResults.push_back(float(i + j)); expectedClipResults.push_back(clipResults); blendNode->setClipResults(animatorId, clipResults); } // Shuffle the animatorIds to randomise the lookups QVector indexes(animatorCount); std::iota(indexes.begin(), indexes.end(), 0); std::random_device rd; std::mt19937 generator(rd()); std::shuffle(indexes.begin(), indexes.end(), generator); QTest::newRow("multiple entries, unordered") << blendNode << indexes << animatorIds << expectedClipResults; } } void checkClipResults() { // GIVEN QFETCH(TestClipBlendNode *, blendNode); QFETCH(QVector, indexes); QFETCH(QList, animatorIds); QFETCH(QList, expectedClipResults); for (int i = 0; i < indexes.size(); ++i) { // WHEN const int index = indexes[i]; const ClipResults actualClipResults = blendNode->clipResults(animatorIds[index]); // THEN QCOMPARE(actualClipResults.size(), expectedClipResults[index].size()); for (int j = 0; j < actualClipResults.size(); ++j) QCOMPARE(actualClipResults[j], expectedClipResults[index][j]); } delete blendNode; } void checkPerformBlend() { // GIVEN auto handler = new Handler(); ClipResults expectedResults = { 1.0f, 2.0f, 3.0f }; auto blendNode = createTestClipBlendNode(handler, expectedResults); const qint64 globalStartTimeNS = 0; const int loopCount = 1; auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); // WHEN blendNode->blend(animator->peerId()); // THEN const ClipResults actualResults = blendNode->clipResults(animator->peerId()); QCOMPARE(actualResults.size(), expectedResults.size()); for (int i = 0; i < actualResults.size(); ++i) QCOMPARE(actualResults[i], expectedResults[i]); } }; QTEST_MAIN(tst_ClipBlendNode) #include "tst_clipblendnode.moc"