Revision control
Copy as Markdown
// Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QTest>
#include <Qt3DAnimation/qlerpclipblend.h>
#include <Qt3DAnimation/qanimationcliploader.h>
#include <Qt3DAnimation/private/qabstractclipblendnode_p.h>
#include <Qt3DAnimation/private/clipblendnode_p.h>
#include <Qt3DAnimation/private/managers_p.h>
#include "qbackendnodetester.h"
#include <random>
#include <algorithm>
using namespace Qt3DAnimation::Animation;
namespace {
class TestClipBlendNode : public ClipBlendNode
{
public:
TestClipBlendNode(const ClipResults &clipResults = ClipResults())
: ClipBlendNode(ClipBlendNode::LerpBlendType)
, m_clipResults(clipResults)
{}
inline QList<Qt3DCore::QNodeId> allDependencyIds() const override
{
return currentDependencyIds();
}
QList<Qt3DCore::QNodeId> currentDependencyIds() const final
{
return {};
}
using ClipBlendNode::setClipResults;
double duration() const final { return 0.0f; }
protected:
ClipResults doBlend(const QList<ClipResults> &) 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<TestClipBlendNode *>("blendNode");
QTest::addColumn<QList<int>>("indexes");
QTest::addColumn<QList<Qt3DCore::QNodeId>>("animatorIds");
QTest::addColumn<QList<ClipResults>>("expectedClipResults");
// Single entry
{
auto blendNode = new TestClipBlendNode;
QList<Qt3DCore::QNodeId> animatorIds;
QList<ClipResults> 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<int> indexes = { 0 };
QTest::newRow("single entry")
<< blendNode << indexes << animatorIds << expectedClipResults;
}
// No data
{
auto blendNode = new TestClipBlendNode;
QList<Qt3DCore::QNodeId> animatorIds;
QList<ClipResults> expectedClipResults;
auto animatorId = Qt3DCore::QNodeId::createId();
animatorIds.push_back(animatorId);
ClipResults clipResults;
expectedClipResults.push_back(clipResults);
// Don't set any data
const QList<int> indexes = { 0 };
QTest::newRow("no entries")
<< blendNode << indexes << animatorIds << expectedClipResults;
}
// Multiple entries, ordered
{
auto blendNode = new TestClipBlendNode;
QList<Qt3DCore::QNodeId> animatorIds;
QList<ClipResults> 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<int> 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<Qt3DCore::QNodeId> animatorIds;
QList<ClipResults> 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<int> 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<int>, indexes);
QFETCH(QList<Qt3DCore::QNodeId>, animatorIds);
QFETCH(QList<ClipResults>, 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"