diff options
Diffstat (limited to 'tests/auto/animation')
51 files changed, 7235 insertions, 902 deletions
diff --git a/tests/auto/animation/qconductedclipanimator/qconductedclipanimator.pro b/tests/auto/animation/additiveclipblend/additiveclipblend.pro index ef04bb54c..09b2e1156 100644 --- a/tests/auto/animation/qconductedclipanimator/qconductedclipanimator.pro +++ b/tests/auto/animation/additiveclipblend/additiveclipblend.pro @@ -1,12 +1,12 @@ TEMPLATE = app -TARGET = tst_qconductedclipanimator +TARGET = tst_additiveclipblend QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib CONFIG += testcase SOURCES += \ - tst_qconductedclipanimator.cpp + tst_additiveclipblend.cpp include(../../core/common/common.pri) diff --git a/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp new file mode 100644 index 000000000..28ab8917a --- /dev/null +++ b/tests/auto/animation/additiveclipblend/tst_additiveclipblend.cpp @@ -0,0 +1,433 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QTest> +#include <Qt3DAnimation/qadditiveclipblend.h> +#include <Qt3DAnimation/qanimationcliploader.h> +#include <Qt3DAnimation/private/qadditiveclipblend_p.h> +#include <Qt3DAnimation/private/additiveclipblend_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include "qbackendnodetester.h" + +using namespace Qt3DAnimation::Animation; + +Q_DECLARE_METATYPE(Handler *) +Q_DECLARE_METATYPE(AdditiveClipBlend *) + +namespace { + +class TestClipBlendNode : public ClipBlendNode +{ +public: + TestClipBlendNode(double duration) + : ClipBlendNode(ClipBlendNode::LerpBlendType) + , m_duration(duration) + {} + + inline QVector<Qt3DCore::QNodeId> allDependencyIds() const Q_DECL_OVERRIDE + { + return currentDependencyIds(); + } + + QVector<Qt3DCore::QNodeId> currentDependencyIds() const Q_DECL_FINAL + { + return QVector<Qt3DCore::QNodeId>(); + } + + using ClipBlendNode::setClipResults; + + double duration() const Q_DECL_FINAL { return m_duration; } + +protected: + ClipResults doBlend(const QVector<ClipResults> &) const Q_DECL_FINAL { return ClipResults(); } + +private: + double m_duration; +}; + +} // anonymous + +class tst_AdditiveClipBlend : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT +public: + TestClipBlendNode *createTestBlendNode(Handler *handler, + double duration) + { + auto id = Qt3DCore::QNodeId::createId(); + TestClipBlendNode *node = new TestClipBlendNode(duration); + setPeerId(node, id); + node->setHandler(handler); + node->setClipBlendNodeManager(handler->clipBlendNodeManager()); + handler->clipBlendNodeManager()->appendNode(id, node); + return node; + } + + AdditiveClipBlend *createAdditiveClipBlendNode(Handler *handler, const float &blendFactor) + { + auto id = Qt3DCore::QNodeId::createId(); + AdditiveClipBlend *node = new AdditiveClipBlend(); + node->setAdditiveFactor(blendFactor); + setPeerId(node, id); + node->setHandler(handler); + node->setClipBlendNodeManager(handler->clipBlendNodeManager()); + 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 + AdditiveClipBlend backendAdditiveBlend; + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), false); + QVERIFY(backendAdditiveBlend.peerId().isNull()); + QCOMPARE(backendAdditiveBlend.baseClipId(), Qt3DCore::QNodeId()); + QCOMPARE(backendAdditiveBlend.additiveClipId(), Qt3DCore::QNodeId()); + QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.0f); + QCOMPARE(backendAdditiveBlend.blendType(), ClipBlendNode::AdditiveBlendType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend additiveBlend; + Qt3DAnimation::QAdditiveClipBlend baseClip; + Qt3DAnimation::QAdditiveClipBlend additiveClip; + Qt3DAnimation::QAnimationClipLoader clip; + additiveBlend.setBaseClip(&baseClip); + additiveBlend.setAdditiveClip(&additiveClip); + additiveBlend.setAdditiveFactor(0.8f); + + { + // WHEN + AdditiveClipBlend backendAdditiveBlend; + simulateInitialization(&additiveBlend, &backendAdditiveBlend); + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), true); + QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); + QCOMPARE(backendAdditiveBlend.baseClipId(), baseClip.id()); + QCOMPARE(backendAdditiveBlend.additiveClipId(), additiveClip.id()); + QCOMPARE(backendAdditiveBlend.additiveFactor(), 0.8f); + } + { + // WHEN + AdditiveClipBlend backendAdditiveBlend; + additiveBlend.setEnabled(false); + simulateInitialization(&additiveBlend, &backendAdditiveBlend); + + // THEN + QCOMPARE(backendAdditiveBlend.peerId(), additiveBlend.id()); + QCOMPARE(backendAdditiveBlend.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + AdditiveClipBlend backendAdditiveBlend; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.isEnabled(), newValue); + } + { + // WHEN + const float newValue = 0.883f; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("additiveFactor"); + change->setValue(QVariant::fromValue(newValue)); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.additiveFactor(), newValue); + } + { + // WHEN + const Qt3DAnimation::QAdditiveClipBlend newValue; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("baseClip"); + change->setValue(QVariant::fromValue(newValue.id())); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.baseClipId(), newValue.id()); + } + { + // WHEN + const Qt3DAnimation::QAdditiveClipBlend newValue; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("additiveClip"); + change->setValue(QVariant::fromValue(newValue.id())); + backendAdditiveBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendAdditiveBlend.additiveClipId(), newValue.id()); + } + } + + void checkDependencyIds() + { + // GIVEN + AdditiveClipBlend addBlend; + auto baseClipId = Qt3DCore::QNodeId::createId(); + auto additiveClipId = Qt3DCore::QNodeId::createId(); + + // WHEN + addBlend.setBaseClipId(baseClipId); + addBlend.setAdditiveClipId(additiveClipId); + QVector<Qt3DCore::QNodeId> actualIds = addBlend.currentDependencyIds(); + + // THEN + QCOMPARE(actualIds.size(), 2); + QCOMPARE(actualIds[0], baseClipId); + QCOMPARE(actualIds[1], additiveClipId); + + // WHEN + auto anotherAdditiveClipId = Qt3DCore::QNodeId::createId(); + addBlend.setAdditiveClipId(anotherAdditiveClipId); + actualIds = addBlend.currentDependencyIds(); + + // THEN + QCOMPARE(actualIds.size(), 2); + QCOMPARE(actualIds[0], baseClipId); + QCOMPARE(actualIds[1], anotherAdditiveClipId); + } + + void checkDuration() + { + // GIVEN + auto handler = new Handler(); + const double expectedDuration = 123.5; + const double baseNodeDuration = expectedDuration; + const double additiveNodeDuration = 5.0; + + auto baseNode = createTestBlendNode(handler, baseNodeDuration); + auto additiveNode = createTestBlendNode(handler, additiveNodeDuration); + + AdditiveClipBlend blendNode; + blendNode.setHandler(handler); + blendNode.setClipBlendNodeManager(handler->clipBlendNodeManager()); + blendNode.setBaseClipId(baseNode->peerId()); + blendNode.setAdditiveClipId(additiveNode->peerId()); + + // WHEN + double actualDuration = blendNode.duration(); + + // THEN + QCOMPARE(actualDuration, expectedDuration); + } + + void checkDoBlend_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<AdditiveClipBlend *>("blendNode"); + QTest::addColumn<Qt3DCore::QNodeId>("animatorId"); + QTest::addColumn<ClipResults>("expectedResults"); + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto baseNode = createTestBlendNode(handler, duration); + baseNode->setClipResults(animator->peerId(), { 0.0f, 0.0f, 0.0f }); + auto additiveNode = createTestBlendNode(handler, duration); + additiveNode->setClipResults(animator->peerId(), { 1.0f, 1.0f, 1.0f }); + + const float additiveFactor = 0.0f; + auto blendNode = createAdditiveClipBlendNode(handler, additiveFactor); + blendNode->setBaseClipId(baseNode->peerId()); + blendNode->setAdditiveClipId(additiveNode->peerId()); + blendNode->setAdditiveFactor(additiveFactor); + + ClipResults expectedResults = { 0.0f, 0.0f, 0.0f }; + + QTest::addRow("unit additive, beta = 0.0") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto baseNode = createTestBlendNode(handler, duration); + baseNode->setClipResults(animator->peerId(), { 0.0f, 0.0f, 0.0f }); + auto additiveNode = createTestBlendNode(handler, duration); + additiveNode->setClipResults(animator->peerId(), { 1.0f, 1.0f, 1.0f }); + + const float additiveFactor = 0.5f; + auto blendNode = createAdditiveClipBlendNode(handler, additiveFactor); + blendNode->setBaseClipId(baseNode->peerId()); + blendNode->setAdditiveClipId(additiveNode->peerId()); + blendNode->setAdditiveFactor(additiveFactor); + + ClipResults expectedResults = { 0.5f, 0.5f, 0.5f }; + + QTest::addRow("unit additive, beta = 0.5") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto baseNode = createTestBlendNode(handler, duration); + baseNode->setClipResults(animator->peerId(), { 0.0f, 0.0f, 0.0f }); + auto additiveNode = createTestBlendNode(handler, duration); + additiveNode->setClipResults(animator->peerId(), { 1.0f, 1.0f, 1.0f }); + + const float additiveFactor = 1.0f; + auto blendNode = createAdditiveClipBlendNode(handler, additiveFactor); + blendNode->setBaseClipId(baseNode->peerId()); + blendNode->setAdditiveClipId(additiveNode->peerId()); + blendNode->setAdditiveFactor(additiveFactor); + + ClipResults expectedResults = { 1.0f, 1.0f, 1.0f }; + + QTest::addRow("unit additive, beta = 1.0") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto baseNode = createTestBlendNode(handler, duration); + baseNode->setClipResults(animator->peerId(), { 0.0f, 1.0f, 2.0f }); + auto additiveNode = createTestBlendNode(handler, duration); + additiveNode->setClipResults(animator->peerId(), { 1.0f, 2.0f, 3.0f }); + + const float blendFactor = 0.5f; + auto blendNode = createAdditiveClipBlendNode(handler, blendFactor); + blendNode->setBaseClipId(baseNode->peerId()); + blendNode->setAdditiveClipId(additiveNode->peerId()); + blendNode->setAdditiveFactor(blendFactor); + + ClipResults expectedResults = { 0.5f, 2.0f, 3.5f }; + + QTest::addRow("lerp varying data, beta = 0.5") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + const int dataCount = 1000; + ClipResults baseData(dataCount); + ClipResults additiveData(dataCount); + ClipResults expectedResults(dataCount); + for (int i = 0; i < dataCount; ++i) { + baseData[i] = float(i); + additiveData[i] = 2.0f * float(i); + expectedResults[i] = 2.0f * float(i); + } + auto baseNode = createTestBlendNode(handler, duration); + baseNode->setClipResults(animator->peerId(), baseData); + auto additiveNode = createTestBlendNode(handler, duration); + additiveNode->setClipResults(animator->peerId(), additiveData); + + const float blendFactor = 0.5f; + auto blendNode = createAdditiveClipBlendNode(handler, blendFactor); + blendNode->setBaseClipId(baseNode->peerId()); + blendNode->setAdditiveClipId(additiveNode->peerId()); + blendNode->setAdditiveFactor(blendFactor); + + QTest::addRow("lerp lots of data, beta = 0.5") + << handler << blendNode << animator->peerId() << expectedResults; + } + } + + void checkDoBlend() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(AdditiveClipBlend *, blendNode); + QFETCH(Qt3DCore::QNodeId, animatorId); + QFETCH(ClipResults, expectedResults); + + // WHEN + blendNode->blend(animatorId); + + // THEN + const ClipResults actualResults = blendNode->clipResults(animatorId); + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) + QCOMPARE(actualResults[i], expectedResults[i]); + + // Cleanup + delete handler; + } +}; + +QTEST_MAIN(tst_AdditiveClipBlend) + +#include "tst_additiveclipblend.moc" diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index 43844ed88..b48fd347b 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -2,28 +2,37 @@ TEMPLATE = subdirs SUBDIRS += \ qanimationaspect \ - qanimationclip \ + qanimationcliploader \ qclipanimator \ qblendedclipanimator \ - qconductedclipanimator \ qchannelmapping \ - qchannelmapper + qchannelmapper \ + qclipblendvalue \ + qanimationcontroller \ + qanimationgroup \ + qkeyframeanimation \ + qmorphinganimation \ + qmorphtarget \ + qvertexblendanimation qtConfig(private_tests) { SUBDIRS += \ animationclip \ - qabstractclipblendnode \ fcurve \ functionrangefinder \ bezierevaluator \ clipanimator \ blendedclipanimator \ - conductedclipanimator \ channelmapper \ channelmapping \ - qlerpblend \ + qlerpclipblend \ clipblendnodemanager \ clipblendnode \ - lerpblend \ - clipblendnodevisitor + lerpclipblend \ + clipblendnodevisitor \ + qadditiveclipblend \ + additiveclipblend \ + clipblendvalue \ + animationutils \ + qabstractanimation } diff --git a/tests/auto/animation/animationclip/tst_animationclip.cpp b/tests/auto/animation/animationclip/tst_animationclip.cpp index f0b45bfeb..61c55d36e 100644 --- a/tests/auto/animation/animationclip/tst_animationclip.cpp +++ b/tests/auto/animation/animationclip/tst_animationclip.cpp @@ -28,7 +28,7 @@ #include <QtTest/QTest> #include <Qt3DAnimation/private/animationclip_p.h> -#include <Qt3DAnimation/qanimationclip.h> +#include <Qt3DAnimation/qanimationcliploader.h> #include <Qt3DCore/private/qnode_p.h> #include <Qt3DCore/private/qscene_p.h> #include <Qt3DCore/qpropertyupdatedchange.h> @@ -37,7 +37,9 @@ #include <qbackendnodetester.h> #include <testpostmanarbiter.h> -class tst_AnimationClip: public Qt3DCore::QBackendNodeTester +using namespace Qt3DAnimation::Animation; + +class tst_AnimationClip : public Qt3DCore::QBackendNodeTester { Q_OBJECT @@ -45,10 +47,10 @@ private Q_SLOTS: void checkPeerPropertyMirroring() { // GIVEN - Qt3DAnimation::Animation::AnimationClip backendClip; - Qt3DAnimation::Animation::Handler handler; + AnimationClip backendClip; + Handler handler; backendClip.setHandler(&handler); - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; clip.setSource(QUrl::fromLocalFile("walk.qlip")); @@ -64,8 +66,8 @@ private Q_SLOTS: void checkInitialAndCleanedUpState() { // GIVEN - Qt3DAnimation::Animation::AnimationClip backendClip; - Qt3DAnimation::Animation::Handler handler; + AnimationClip backendClip; + Handler handler; backendClip.setHandler(&handler); // THEN @@ -73,9 +75,10 @@ private Q_SLOTS: QCOMPARE(backendClip.isEnabled(), false); QCOMPARE(backendClip.source(), QUrl()); QCOMPARE(backendClip.duration(), 0.0f); + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::NotReady); // GIVEN - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; clip.setSource(QUrl::fromLocalFile("walk.qlip")); // WHEN @@ -87,14 +90,16 @@ private Q_SLOTS: QCOMPARE(backendClip.source(), QUrl()); QCOMPARE(backendClip.isEnabled(), false); QCOMPARE(backendClip.duration(), 0.0f); + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::NotReady); } void checkPropertyChanges() { // GIVEN - Qt3DAnimation::Animation::AnimationClip backendClip; - Qt3DAnimation::Animation::Handler handler; + AnimationClip backendClip; + Handler handler; backendClip.setHandler(&handler); + backendClip.setDataType(Qt3DAnimation::Animation::AnimationClip::File); Qt3DCore::QPropertyUpdatedChangePtr updateChange; // WHEN @@ -121,7 +126,7 @@ private Q_SLOTS: { // GIVEN TestArbiter arbiter; - Qt3DAnimation::Animation::AnimationClip backendClip; + AnimationClip backendClip; backendClip.setEnabled(true); Qt3DCore::QBackendNodePrivate::get(&backendClip)->setArbiter(&arbiter); @@ -134,7 +139,8 @@ private Q_SLOTS: Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); QCOMPARE(change->propertyName(), "duration"); QCOMPARE(change->value().toFloat(), backendClip.duration()); - QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isFinal, true); + QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isIntermediate, + false); arbiter.events.clear(); @@ -147,6 +153,38 @@ private Q_SLOTS: arbiter.events.clear(); } + + void checkStatusPropertyBackendNotification() + { + // GIVEN + TestArbiter arbiter; + AnimationClip backendClip; + backendClip.setEnabled(true); + Qt3DCore::QBackendNodePrivate::get(&backendClip)->setArbiter(&arbiter); + + // WHEN + backendClip.setStatus(Qt3DAnimation::QAnimationClipLoader::Error); + + // THEN + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::Error); + QCOMPARE(arbiter.events.count(), 1); + Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "status"); + QCOMPARE(change->value().value<Qt3DAnimation::QAnimationClipLoader::Status>(), backendClip.status()); + QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isIntermediate, + false); + + arbiter.events.clear(); + + // WHEN + backendClip.setStatus(Qt3DAnimation::QAnimationClipLoader::Error); + + // THEN + QCOMPARE(backendClip.status(), Qt3DAnimation::QAnimationClipLoader::Error); + QCOMPARE(arbiter.events.count(), 0); + + arbiter.events.clear(); + } }; QTEST_APPLESS_MAIN(tst_AnimationClip) diff --git a/tests/auto/animation/qabstractclipblendnode/qabstractclipblendnode.pro b/tests/auto/animation/animationutils/animationutils.pro index 9dff8e7bd..5c7e3c510 100644 --- a/tests/auto/animation/qabstractclipblendnode/qabstractclipblendnode.pro +++ b/tests/auto/animation/animationutils/animationutils.pro @@ -1,11 +1,15 @@ TEMPLATE = app -TARGET = tst_qabstractclipblendnode +TARGET = tst_animationutils QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib CONFIG += testcase -SOURCES += tst_qabstractclipblendnode.cpp +SOURCES += \ + tst_animationutils.cpp include(../../core/common/common.pri) + +RESOURCES += \ + animationutils.qrc diff --git a/tests/auto/animation/animationutils/animationutils.qrc b/tests/auto/animation/animationutils/animationutils.qrc new file mode 100644 index 000000000..bbcd96524 --- /dev/null +++ b/tests/auto/animation/animationutils/animationutils.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/"> + <file>clip1.json</file> + <file>clip2.json</file> + <file>clip3.json</file> + </qresource> +</RCC> diff --git a/tests/auto/animation/animationutils/clip1.json b/tests/auto/animation/animationutils/clip1.json new file mode 100644 index 000000000..8fa382589 --- /dev/null +++ b/tests/auto/animation/animationutils/clip1.json @@ -0,0 +1,113 @@ +{ + "animations": [ + { + "animationName": "CubeAction", + "channels": [ + { + "channelComponents": [ + { + "channelComponentName": "Location X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + }, + { + "channelComponentName": "Location Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Location Z", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Location" + } + ] + } + ] +}
\ No newline at end of file diff --git a/tests/auto/animation/animationutils/clip2.json b/tests/auto/animation/animationutils/clip2.json new file mode 100644 index 000000000..3faff409c --- /dev/null +++ b/tests/auto/animation/animationutils/clip2.json @@ -0,0 +1,250 @@ +{ + "animations": [ + { + "animationName": "CubeAction", + "channels": [ + { + "channelComponents": [ + { + "channelComponentName": "Location X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + }, + { + "channelComponentName": "Location Z", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Location Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Location" + }, + { + "channelComponents": [ + { + "channelComponentName": "Rotation W", + "keyFrames": [ + { + "coords": [ + 0.0, + 1.0 + ], + "leftHandle": [ + -0.9597616195678711, + 1.0 + ], + "rightHandle": [ + 0.9597616195678711, + 1.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -4.371138828673793e-08 + ], + "leftHandle": [ + 1.4985717137654622, + -4.371138828673793e-08 + ], + "rightHandle": [ + 3.4180949529012046, + -4.371138828673793e-08 + ] + } + ] + }, + { + "channelComponentName": "Rotation X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Z", + "keyFrames": [ + { + "coords": [ + 0.0, + -0.0 + ], + "leftHandle": [ + -0.9597616195678711, + -0.0 + ], + "rightHandle": [ + 0.9597616195678711, + -0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -1.0 + ], + "leftHandle": [ + 1.4985717137654622, + -1.0 + ], + "rightHandle": [ + 3.4180949529012046, + -1.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Rotation" + } + ] + } + ] +}
\ No newline at end of file diff --git a/tests/auto/animation/animationutils/clip3.json b/tests/auto/animation/animationutils/clip3.json new file mode 100644 index 000000000..ae390590e --- /dev/null +++ b/tests/auto/animation/animationutils/clip3.json @@ -0,0 +1,430 @@ +{ + "animations": [ + { + "animationName": "CubeAction", + "channels": [ + { + "channelComponents": [ + { + "channelComponentName": "Rotation W", + "keyFrames": [ + { + "coords": [ + 0.0, + 1.0 + ], + "leftHandle": [ + -0.9597616195678711, + 1.0 + ], + "rightHandle": [ + 0.9597616195678711, + 1.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -4.371138828673793e-08 + ], + "leftHandle": [ + 1.4985717137654622, + -4.371138828673793e-08 + ], + "rightHandle": [ + 3.4180949529012046, + -4.371138828673793e-08 + ] + } + ] + }, + { + "channelComponentName": "Rotation X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Z", + "keyFrames": [ + { + "coords": [ + 0.0, + -0.0 + ], + "leftHandle": [ + -0.9597616195678711, + -0.0 + ], + "rightHandle": [ + 0.9597616195678711, + -0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + -1.0 + ], + "leftHandle": [ + 1.4985717137654622, + -1.0 + ], + "rightHandle": [ + 3.4180949529012046, + -1.0 + ] + } + ] + }, + { + "channelComponentName": "Rotation Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Rotation" + }, + { + "channelComponents": [ + { + "channelComponentName": "Location X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + }, + { + "channelComponentName": "Location Z", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Location Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Location" + }, + { + "channelComponents": [ + { + "channelComponentName": "Base Color X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + }, + { + "channelComponentName": "Base Color Y", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + }, + { + "channelComponentName": "Base Color Z", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 0.0 + ], + "leftHandle": [ + 1.4985717137654622, + 0.0 + ], + "rightHandle": [ + 3.4180949529012046, + 0.0 + ] + } + ] + } + ], + "channelName": "Base Color" + }, + { + "channelComponents": [ + { + "channelComponentName": "Metalness X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + } + ], + "channelName": "Metalness" + }, + { + "channelComponents": [ + { + "channelComponentName": "Roughness X", + "keyFrames": [ + { + "coords": [ + 0.0, + 0.0 + ], + "leftHandle": [ + -0.9597616195678711, + 0.0 + ], + "rightHandle": [ + 0.9597616195678711, + 0.0 + ] + }, + { + "coords": [ + 2.4583333333333335, + 5.0 + ], + "leftHandle": [ + 1.4985717137654622, + 5.0 + ], + "rightHandle": [ + 3.4180949529012046, + 5.0 + ] + } + ] + } + ], + "channelName": "Roughness" + } + ] + } + ] +} diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp new file mode 100644 index 000000000..ac4fb6fa0 --- /dev/null +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -0,0 +1,2501 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QTest> +#include <Qt3DAnimation/private/animationclip_p.h> +#include <Qt3DAnimation/private/animationutils_p.h> +#include <Qt3DAnimation/private/blendedclipanimator_p.h> +#include <Qt3DAnimation/private/channelmapper_p.h> +#include <Qt3DAnimation/private/channelmapping_p.h> +#include <Qt3DAnimation/private/clipblendvalue_p.h> +#include <Qt3DAnimation/private/handler_p.h> +#include <Qt3DAnimation/private/additiveclipblend_p.h> +#include <Qt3DAnimation/private/lerpclipblend_p.h> +#include <Qt3DAnimation/private/managers_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> +#include <QtGui/qquaternion.h> + +#include <qbackendnodetester.h> +#include <testpostmanarbiter.h> + +using namespace Qt3DAnimation::Animation; + +Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*) +Q_DECLARE_METATYPE(QVector<ChannelMapping *>) +Q_DECLARE_METATYPE(ChannelMapper *) +Q_DECLARE_METATYPE(AnimationClip *) +Q_DECLARE_METATYPE(QVector<MappingData>) +Q_DECLARE_METATYPE(QVector<Qt3DCore::QPropertyUpdatedChangePtr>) +Q_DECLARE_METATYPE(Channel) +Q_DECLARE_METATYPE(AnimatorEvaluationData) +Q_DECLARE_METATYPE(ClipEvaluationData) +Q_DECLARE_METATYPE(ClipAnimator *) +Q_DECLARE_METATYPE(BlendedClipAnimator *) +Q_DECLARE_METATYPE(QVector<ChannelNameAndType>) + +namespace { + +class MeanBlendNode : public ClipBlendNode +{ +public: + MeanBlendNode() + : ClipBlendNode(ClipBlendNode::LerpBlendType) + {} + + void setValueNodeIds(Qt3DCore::QNodeId value1Id, + Qt3DCore::QNodeId value2Id) + { + m_value1Id = value1Id; + m_value2Id = value2Id; + } + + inline QVector<Qt3DCore::QNodeId> allDependencyIds() const Q_DECL_OVERRIDE + { + return currentDependencyIds(); + } + + QVector<Qt3DCore::QNodeId> currentDependencyIds() const Q_DECL_FINAL + { + return QVector<Qt3DCore::QNodeId>() << m_value1Id << m_value2Id; + } + + using ClipBlendNode::setClipResults; + + double duration() const Q_DECL_FINAL { return 0.0f; } + +protected: + ClipResults doBlend(const QVector<ClipResults> &blendData) const Q_DECL_FINAL + { + Q_ASSERT(blendData.size() == 2); + const int elementCount = blendData.first().size(); + ClipResults blendResults(elementCount); + + for (int i = 0; i < elementCount; ++i) + blendResults[i] = 0.5f * (blendData[0][i] + blendData[1][i]); + + return blendResults; + } + +private: + Qt3DCore::QNodeId m_value1Id; + Qt3DCore::QNodeId m_value2Id; +}; + +bool fuzzyCompare(float x1, float x2) +{ + if (qFuzzyIsNull(x1) && qFuzzyIsNull(x2)) { + return true; + } else if ((qFuzzyIsNull(x1) && !qFuzzyIsNull(x2)) || + (!qFuzzyIsNull(x1) && qFuzzyIsNull(x2))) { + return false; + } else { + return qFuzzyCompare(x1, x2); + } +} + +} // anonymous + + +class tst_AnimationUtils : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +public: + ChannelMapping *createChannelMapping(Handler *handler, + const QString &channelName, + const Qt3DCore::QNodeId targetId, + const QString &property, + const char *propertyName, + int type) + { + auto channelMappingId = Qt3DCore::QNodeId::createId(); + ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(channelMappingId); + setPeerId(channelMapping, channelMappingId); + channelMapping->setTargetId(targetId); + channelMapping->setProperty(property); + channelMapping->setPropertyName(propertyName); + channelMapping->setChannelName(channelName); + channelMapping->setType(type); + return channelMapping; + } + + ChannelMapper *createChannelMapper(Handler *handler, + const QVector<Qt3DCore::QNodeId> &mappingIds) + { + auto channelMapperId = Qt3DCore::QNodeId::createId(); + ChannelMapper *channelMapper = handler->channelMapperManager()->getOrCreateResource(channelMapperId); + setPeerId(channelMapper, channelMapperId); + channelMapper->setMappingIds(mappingIds); + return channelMapper; + } + + AnimationClip *createAnimationClipLoader(Handler *handler, + const QUrl &source) + { + auto clipId = Qt3DCore::QNodeId::createId(); + AnimationClip *clip = handler->animationClipLoaderManager()->getOrCreateResource(clipId); + setPeerId(clip, clipId); + clip->setDataType(AnimationClip::File); + clip->setSource(source); + clip->loadAnimation(); + return clip; + } + + ClipAnimator *createClipAnimator(Handler *handler, + qint64 globalStartTimeNS, + int loops) + { + auto animatorId = Qt3DCore::QNodeId::createId(); + ClipAnimator *animator = handler->clipAnimatorManager()->getOrCreateResource(animatorId); + setPeerId(animator, animatorId); + animator->setStartTime(globalStartTimeNS); + animator->setLoops(loops); + return animator; + } + + 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; + } + + LerpClipBlend *createLerpClipBlend(Handler *handler) + { + auto lerpId = Qt3DCore::QNodeId::createId(); + LerpClipBlend *lerp = new LerpClipBlend(); + setPeerId(lerp, lerpId); + lerp->setClipBlendNodeManager(handler->clipBlendNodeManager()); + lerp->setHandler(handler); + handler->clipBlendNodeManager()->appendNode(lerpId, lerp); + return lerp; + } + + AdditiveClipBlend *createAdditiveClipBlend(Handler *handler) + { + auto additiveId = Qt3DCore::QNodeId::createId(); + AdditiveClipBlend *additive = new AdditiveClipBlend(); + setPeerId(additive, additiveId); + additive->setClipBlendNodeManager(handler->clipBlendNodeManager()); + additive->setHandler(handler); + handler->clipBlendNodeManager()->appendNode(additiveId, additive); + return additive; + } + + ClipBlendValue *createClipBlendValue(Handler *handler) + { + auto valueId = Qt3DCore::QNodeId::createId(); + ClipBlendValue *value = new ClipBlendValue(); + setPeerId(value, valueId); + value->setClipBlendNodeManager(handler->clipBlendNodeManager()); + value->setHandler(handler); + handler->clipBlendNodeManager()->appendNode(valueId, value); + return value; + } + + MeanBlendNode *createMeanBlendNode(Handler *handler) + { + auto id = Qt3DCore::QNodeId::createId(); + MeanBlendNode *node = new MeanBlendNode(); + setPeerId(node, id); + node->setClipBlendNodeManager(handler->clipBlendNodeManager()); + node->setHandler(handler); + handler->clipBlendNodeManager()->appendNode(id, node); + return node; + } + +private Q_SLOTS: + void checkBuildPropertyMappings_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<QVector<ChannelMapping *>>("channelMappings"); + QTest::addColumn<ChannelMapper *>("channelMapper"); + QTest::addColumn<AnimationClip *>("clip"); + QTest::addColumn<QVector<MappingData>>("expectedMappingData"); + + auto handler = new Handler; + auto channelMapping = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + QLatin1String("translation"), + "translation", + static_cast<int>(QVariant::Vector3D)); + QVector<ChannelMapping *> channelMappings; + channelMappings.push_back(channelMapping); + + // ... a channel mapper... + auto channelMapper = createChannelMapper(handler, QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); + + // ...and an animation clip + auto clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + + QVector<MappingData> mappingData; + MappingData mapping; + mapping.targetId = channelMapping->targetId(); + mapping.propertyName = channelMapping->propertyName(); // Location + mapping.type = channelMapping->type(); + mapping.channelIndices = QVector<int>() << 0 << 1 << 2; // Location X, Y, Z + mappingData.push_back(mapping); + + QTest::newRow("clip1.json") << handler + << channelMappings + << channelMapper + << clip + << mappingData; + } + + void checkBuildPropertyMappings() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(QVector<ChannelMapping *>, channelMappings); + QFETCH(ChannelMapper *, channelMapper); + QFETCH(AnimationClip *, clip); + QFETCH(QVector<MappingData>, expectedMappingData); + + // WHEN + // Build the mapping data for the above configuration + QVector<MappingData> mappingData = buildPropertyMappings(handler, clip, channelMapper); + + // THEN + QCOMPARE(mappingData.size(), expectedMappingData.size()); + for (int i = 0; i < mappingData.size(); ++i) { + const auto mapping = mappingData[i]; + const auto expectedMapping = expectedMappingData[i]; + + QCOMPARE(mapping.targetId, expectedMapping.targetId); + QCOMPARE(mapping.propertyName, expectedMapping.propertyName); + QCOMPARE(mapping.type, expectedMapping.type); + QCOMPARE(mapping.channelIndices.size(), expectedMapping.channelIndices.size()); + for (int j = 0; j < mapping.channelIndices.size(); ++j) { + QCOMPARE(mapping.channelIndices[j], expectedMapping.channelIndices[j]); + } + } + + // Cleanup + delete handler; + } + + void checkBuildPropertyMappings2_data() + { + QTest::addColumn<QVector<ChannelMapping *>>("channelMappings"); + QTest::addColumn<QVector<ChannelNameAndType>>("channelNamesAndTypes"); + QTest::addColumn<QVector<ComponentIndices>>("channelComponentIndices"); + QTest::addColumn<QVector<MappingData>>("expectedResults"); + + // Single ChannelMapping + { + auto channelMapping = new ChannelMapping(); + channelMapping->setChannelName("Location"); + channelMapping->setTargetId(Qt3DCore::QNodeId::createId()); + channelMapping->setProperty(QLatin1String("translation")); + channelMapping->setPropertyName("translation"); + channelMapping->setType(static_cast<int>(QVariant::Vector3D)); + + QVector<ChannelMapping *> channelMappings = { channelMapping }; + + // Create a few channels in the format description + ChannelNameAndType rotation = { QLatin1String("Rotation"), + static_cast<int>(QVariant::Quaternion) }; + ChannelNameAndType location = { QLatin1String("Location"), + static_cast<int>(QVariant::Vector3D) }; + ChannelNameAndType baseColor = { QLatin1String("BaseColor"), + static_cast<int>(QVariant::Vector3D) }; + ChannelNameAndType metalness = { QLatin1String("Metalness"), + static_cast<int>(QVariant::Double) }; + ChannelNameAndType roughness = { QLatin1String("Roughness"), + static_cast<int>(QVariant::Double) }; + QVector<ChannelNameAndType> channelNamesAndTypes + = { rotation, location, baseColor, metalness, roughness }; + + // And the matching indices + ComponentIndices rotationIndices = { 0, 1, 2, 3 }; + ComponentIndices locationIndices = { 4, 5, 6 }; + ComponentIndices baseColorIndices = { 7, 8, 9 }; + ComponentIndices metalnessIndices = { 10 }; + ComponentIndices roughnessIndices = { 11 }; + QVector<ComponentIndices> channelComponentIndices + = { rotationIndices, locationIndices, baseColorIndices, + metalnessIndices, roughnessIndices }; + + MappingData expectedMapping; + expectedMapping.targetId = channelMapping->targetId(); + expectedMapping.propertyName = channelMapping->propertyName(); + expectedMapping.type = channelMapping->type(); + expectedMapping.channelIndices = locationIndices; + QVector<MappingData> expectedResults = { expectedMapping }; + + QTest::newRow("single mapping") + << channelMappings + << channelNamesAndTypes + << channelComponentIndices + << expectedResults; + } + + // Multiple ChannelMappings + { + auto locationMapping = new ChannelMapping(); + locationMapping->setChannelName("Location"); + locationMapping->setTargetId(Qt3DCore::QNodeId::createId()); + locationMapping->setProperty(QLatin1String("translation")); + locationMapping->setPropertyName("translation"); + locationMapping->setType(static_cast<int>(QVariant::Vector3D)); + + auto metalnessMapping = new ChannelMapping(); + metalnessMapping->setChannelName("Metalness"); + metalnessMapping->setTargetId(Qt3DCore::QNodeId::createId()); + metalnessMapping->setProperty(QLatin1String("metalness")); + metalnessMapping->setPropertyName("metalness"); + metalnessMapping->setType(static_cast<int>(QVariant::Double)); + + auto baseColorMapping = new ChannelMapping(); + baseColorMapping->setChannelName("BaseColor"); + baseColorMapping->setTargetId(Qt3DCore::QNodeId::createId()); + baseColorMapping->setProperty(QLatin1String("baseColor")); + baseColorMapping->setPropertyName("baseColor"); + baseColorMapping->setType(static_cast<int>(QVariant::Vector3D)); + + auto roughnessMapping = new ChannelMapping(); + roughnessMapping->setChannelName("Roughness"); + roughnessMapping->setTargetId(Qt3DCore::QNodeId::createId()); + roughnessMapping->setProperty(QLatin1String("roughness")); + roughnessMapping->setPropertyName("roughness"); + roughnessMapping->setType(static_cast<int>(QVariant::Double)); + + auto rotationMapping = new ChannelMapping(); + rotationMapping->setChannelName("Rotation"); + rotationMapping->setTargetId(Qt3DCore::QNodeId::createId()); + rotationMapping->setProperty(QLatin1String("rotation")); + rotationMapping->setPropertyName("rotation"); + rotationMapping->setType(static_cast<int>(QVariant::Quaternion)); + + QVector<ChannelMapping *> channelMappings + = { locationMapping, metalnessMapping, + baseColorMapping, roughnessMapping, + rotationMapping }; + + // Create a few channels in the format description + ChannelNameAndType rotation = { QLatin1String("Rotation"), + static_cast<int>(QVariant::Quaternion) }; + ChannelNameAndType location = { QLatin1String("Location"), + static_cast<int>(QVariant::Vector3D) }; + ChannelNameAndType baseColor = { QLatin1String("BaseColor"), + static_cast<int>(QVariant::Vector3D) }; + ChannelNameAndType metalness = { QLatin1String("Metalness"), + static_cast<int>(QVariant::Double) }; + ChannelNameAndType roughness = { QLatin1String("Roughness"), + static_cast<int>(QVariant::Double) }; + QVector<ChannelNameAndType> channelNamesAndTypes + = { rotation, location, baseColor, metalness, roughness }; + + // And the matching indices + ComponentIndices rotationIndices = { 0, 1, 2, 3 }; + ComponentIndices locationIndices = { 4, 5, 6 }; + ComponentIndices baseColorIndices = { 7, 8, 9 }; + ComponentIndices metalnessIndices = { 10 }; + ComponentIndices roughnessIndices = { 11 }; + QVector<ComponentIndices> channelComponentIndices + = { rotationIndices, locationIndices, baseColorIndices, + metalnessIndices, roughnessIndices }; + + MappingData expectedLocationMapping; + expectedLocationMapping.targetId = locationMapping->targetId(); + expectedLocationMapping.propertyName = locationMapping->propertyName(); + expectedLocationMapping.type = locationMapping->type(); + expectedLocationMapping.channelIndices = locationIndices; + + MappingData expectedMetalnessMapping; + expectedMetalnessMapping.targetId = metalnessMapping->targetId(); + expectedMetalnessMapping.propertyName = metalnessMapping->propertyName(); + expectedMetalnessMapping.type = metalnessMapping->type(); + expectedMetalnessMapping.channelIndices = metalnessIndices; + + MappingData expectedBaseColorMapping; + expectedBaseColorMapping.targetId = baseColorMapping->targetId(); + expectedBaseColorMapping.propertyName = baseColorMapping->propertyName(); + expectedBaseColorMapping.type = baseColorMapping->type(); + expectedBaseColorMapping.channelIndices = baseColorIndices; + + MappingData expectedRoughnessMapping; + expectedRoughnessMapping.targetId = roughnessMapping->targetId(); + expectedRoughnessMapping.propertyName = roughnessMapping->propertyName(); + expectedRoughnessMapping.type = roughnessMapping->type(); + expectedRoughnessMapping.channelIndices = roughnessIndices; + + MappingData expectedRotationMapping; + expectedRotationMapping.targetId = rotationMapping->targetId(); + expectedRotationMapping.propertyName = rotationMapping->propertyName(); + expectedRotationMapping.type = rotationMapping->type(); + expectedRotationMapping.channelIndices = rotationIndices; + + QVector<MappingData> expectedResults + = { expectedLocationMapping, + expectedMetalnessMapping, + expectedBaseColorMapping, + expectedRoughnessMapping, + expectedRotationMapping }; + + QTest::newRow("multiple mappings") + << channelMappings + << channelNamesAndTypes + << channelComponentIndices + << expectedResults; + } + } + + void checkBuildPropertyMappings2() + { + // GIVEN + QFETCH(QVector<ChannelMapping *>, channelMappings); + QFETCH(QVector<ChannelNameAndType>, channelNamesAndTypes); + QFETCH(QVector<ComponentIndices>, channelComponentIndices); + QFETCH(QVector<MappingData>, expectedResults); + + // WHEN + const QVector<MappingData> actualResults = buildPropertyMappings(channelMappings, + channelNamesAndTypes, + channelComponentIndices); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + const auto actualMapping = actualResults[i]; + const auto expectedMapping = expectedResults[i]; + + QCOMPARE(actualMapping.targetId, expectedMapping.targetId); + QCOMPARE(actualMapping.propertyName, expectedMapping.propertyName); + QCOMPARE(actualMapping.type, expectedMapping.type); + QCOMPARE(actualMapping.channelIndices.size(), expectedMapping.channelIndices.size()); + for (int j = 0; j < actualMapping.channelIndices.size(); ++j) { + QCOMPARE(actualMapping.channelIndices[j], expectedMapping.channelIndices[j]); + } + } + } + + void checkLocalTimeFromGlobalTime_data() + { + QTest::addColumn<double>("globalTime"); + QTest::addColumn<double>("globalStartTime"); + QTest::addColumn<double>("playbackRate"); + QTest::addColumn<double>("duration"); + QTest::addColumn<int>("loopCount"); + QTest::addColumn<double>("expectedLocalTime"); + QTest::addColumn<int>("expectedCurrentLoop"); + + double globalTime; + double globalStartTime; + double playbackRate; + double duration; + int loopCount; + double expectedLocalTime; + int expectedCurrentLoop; + + globalTime = 0.0; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 0.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 0") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 0.5; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.0; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 1.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 1.0") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = -0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 0.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = -0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedLocalTime = 1.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 2; + expectedLocalTime = 0.5; + expectedCurrentLoop = 0; + QTest::newRow("simple, loopCount = 2, t_global = 0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 2; + expectedLocalTime = 0.5; + expectedCurrentLoop = 1; + QTest::newRow("simple, loopCount = 2, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 3.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 2.0; + loopCount = 2; + expectedLocalTime = 1.5; + expectedCurrentLoop = 1; + QTest::newRow("duration = 2, loopCount = 2, t_global = 3.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 4.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 2.0; + loopCount = 2; + expectedLocalTime = 2.0; + expectedCurrentLoop = 1; + QTest::newRow("duration = 2, loopCount = 2, t_global = 4.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 0; + expectedLocalTime = 0.5; + expectedCurrentLoop = 1; + QTest::newRow("simple, loopCount = inf, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + + globalTime = 10.2; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 0; + expectedLocalTime = 0.2; + expectedCurrentLoop = 10; + QTest::newRow("simple, loopCount = inf, t_global = 10.2") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedLocalTime << expectedCurrentLoop; + } + + void checkLocalTimeFromGlobalTime() + { + // GIVEN + QFETCH(double, globalTime); + QFETCH(double, globalStartTime); + QFETCH(double, playbackRate); + QFETCH(double, duration); + QFETCH(int, loopCount); + QFETCH(double, expectedLocalTime); + QFETCH(int, expectedCurrentLoop); + + // WHEN + int actualCurrentLoop = 0; + double actualLocalTime = localTimeFromGlobalTime(globalTime, + globalStartTime, + playbackRate, + duration, + loopCount, + actualCurrentLoop); + + // THEN + QCOMPARE(actualCurrentLoop, expectedCurrentLoop); + QCOMPARE(actualLocalTime, expectedLocalTime); + } + + void checkPhaseFromGlobalTime_data() + { + QTest::addColumn<double>("globalTime"); + QTest::addColumn<double>("globalStartTime"); + QTest::addColumn<double>("playbackRate"); + QTest::addColumn<double>("duration"); + QTest::addColumn<int>("loopCount"); + QTest::addColumn<double>("expectedPhase"); + QTest::addColumn<int>("expectedCurrentLoop"); + + double globalTime; + double globalStartTime; + double playbackRate; + double duration; + int loopCount; + double expectedPhase; + int expectedCurrentLoop; + + globalTime = 0.0; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedPhase = 0.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 0") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedPhase = 0.5; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 1.0; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedPhase = 1.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 1.0") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = -0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedPhase = 0.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = -0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 1; + expectedPhase = 1.0; + expectedCurrentLoop = 0; + QTest::newRow("simple, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 0.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 2; + expectedPhase = 0.5; + expectedCurrentLoop = 0; + QTest::newRow("simple, loopCount = 2, t_global = 0.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 2; + expectedPhase = 0.5; + expectedCurrentLoop = 1; + QTest::newRow("simple, loopCount = 2, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 3.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 2.0; + loopCount = 2; + expectedPhase = 0.75; + expectedCurrentLoop = 1; + QTest::newRow("duration = 2, loopCount = 2, t_global = 3.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 4.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 2.0; + loopCount = 2; + expectedPhase = 1.0; + expectedCurrentLoop = 1; + QTest::newRow("duration = 2, loopCount = 2, t_global = 4.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 1.5; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 0; + expectedPhase = 0.5; + expectedCurrentLoop = 1; + QTest::newRow("simple, loopCount = inf, t_global = 1.5") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + + globalTime = 10.2; + globalStartTime = 0.0; + playbackRate = 1.0; + duration = 1.0; + loopCount = 0; + expectedPhase = 0.2; + expectedCurrentLoop = 10; + QTest::newRow("simple, loopCount = inf, t_global = 10.2") + << globalTime << globalStartTime << playbackRate << duration << loopCount + << expectedPhase << expectedCurrentLoop; + } + + void checkPhaseFromGlobalTime() + { + // GIVEN + QFETCH(double, globalTime); + QFETCH(double, globalStartTime); + QFETCH(double, playbackRate); + QFETCH(double, duration); + QFETCH(int, loopCount); + QFETCH(double, expectedPhase); + QFETCH(int, expectedCurrentLoop); + + // WHEN + int actualCurrentLoop = 0; + double actualPhase = phaseFromGlobalTime(globalTime, + globalStartTime, + playbackRate, + duration, + loopCount, + actualCurrentLoop); + + // THEN + QCOMPARE(actualCurrentLoop, expectedCurrentLoop); + QCOMPARE(actualPhase, expectedPhase); + } + + void checkPreparePropertyChanges_data() + { + QTest::addColumn<Qt3DCore::QNodeId>("animatorId"); + QTest::addColumn<QVector<MappingData>>("mappingData"); + QTest::addColumn<QVector<float>>("channelResults"); + QTest::addColumn<bool>("finalFrame"); + QTest::addColumn<QVector<Qt3DCore::QPropertyUpdatedChangePtr>>("expectedChanges"); + + Qt3DCore::QNodeId animatorId; + QVector<MappingData> mappingData; + QVector<float> channelResults; + bool finalFrame; + QVector<Qt3DCore::QPropertyUpdatedChangePtr> expectedChanges; + + // Single property, vec3 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "translation"; + mapping.type = static_cast<int>(QVariant::Vector3D); + mapping.channelIndices = QVector<int>() << 0 << 1 << 2; + mappingData.push_back(mapping); + channelResults = QVector<float>() << 1.0f << 2.0f << 3.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QVector3D(1.0f, 2.0f, 3.0f))); + expectedChanges.push_back(change); + + QTest::newRow("vec3 translation, final = false") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + finalFrame = true; + auto animatorChange = Qt3DCore::QPropertyUpdatedChangePtr::create(animatorId); + animatorChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + animatorChange->setPropertyName("running"); + animatorChange->setValue(false); + expectedChanges.push_back(animatorChange); + + QTest::newRow("vec3 translation, final = true") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Multiple properties, all vec3 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData translationMapping; + translationMapping.targetId = Qt3DCore::QNodeId::createId(); + translationMapping.propertyName = "translation"; + translationMapping.type = static_cast<int>(QVariant::Vector3D); + translationMapping.channelIndices = QVector<int>() << 0 << 1 << 2; + mappingData.push_back(translationMapping); + + MappingData scaleMapping; + scaleMapping.targetId = Qt3DCore::QNodeId::createId(); + scaleMapping.propertyName = "scale"; + scaleMapping.type = static_cast<int>(QVariant::Vector3D); + scaleMapping.channelIndices = QVector<int>() << 3 << 4 << 5; + mappingData.push_back(scaleMapping); + + channelResults = QVector<float>() << 1.0f << 2.0f << 3.0f + << 4.0f << 5.0f << 6.0f; + finalFrame = false; + + auto translationChange = Qt3DCore::QPropertyUpdatedChangePtr::create(translationMapping.targetId); + translationChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + translationChange->setPropertyName(translationMapping.propertyName); + translationChange->setValue(QVariant::fromValue(QVector3D(1.0f, 2.0f, 3.0f))); + expectedChanges.push_back(translationChange); + + auto scaleChange = Qt3DCore::QPropertyUpdatedChangePtr::create(scaleMapping.targetId); + scaleChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + scaleChange->setPropertyName(scaleMapping.propertyName); + scaleChange->setValue(QVariant::fromValue(QVector3D(4.0f, 5.0f, 6.0f))); + expectedChanges.push_back(scaleChange); + + QTest::newRow("vec3 translation, vec3 scale, final = false") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + finalFrame = true; + auto animatorChange = Qt3DCore::QPropertyUpdatedChangePtr::create(animatorId); + animatorChange->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + animatorChange->setPropertyName("running"); + animatorChange->setValue(false); + expectedChanges.push_back(animatorChange); + + QTest::newRow("vec3 translation, vec3 scale, final = true") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, double + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "mass"; + mapping.type = static_cast<int>(QVariant::Double); + mapping.channelIndices = QVector<int>() << 0; + mappingData.push_back(mapping); + channelResults = QVector<float>() << 3.5f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(3.5f)); + expectedChanges.push_back(change); + + QTest::newRow("double mass") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, vec2 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "pos"; + mapping.type = static_cast<int>(QVariant::Vector2D); + mapping.channelIndices = QVector<int>() << 0 << 1; + mappingData.push_back(mapping); + channelResults = QVector<float>() << 2.0f << 1.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QVector2D(2.0f, 1.0f))); + expectedChanges.push_back(change); + + QTest::newRow("vec2 pos") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, vec4 + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "foo"; + mapping.type = static_cast<int>(QVariant::Vector2D); + mapping.channelIndices = QVector<int>() << 0 << 1 << 2 << 3; + mappingData.push_back(mapping); + channelResults = QVector<float>() << 4.0f << 3.0f << 2.0f << 1.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QVector4D(4.0f, 3.0f, 2.0f, 1.0f))); + expectedChanges.push_back(change); + + QTest::newRow("vec4 foo") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + + // Single property, quaternion + { + animatorId = Qt3DCore::QNodeId::createId(); + MappingData mapping; + mapping.targetId = Qt3DCore::QNodeId::createId(); + mapping.propertyName = "rotation"; + mapping.type = static_cast<int>(QVariant::Quaternion); + mapping.channelIndices = QVector<int>() << 0 << 1 << 2 << 3; + mappingData.push_back(mapping); + channelResults = QVector<float>() << 1.0f << 0.0f << 0.0f << 1.0f; + finalFrame = false; + + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(mapping.targetId); + change->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + change->setPropertyName(mapping.propertyName); + change->setValue(QVariant::fromValue(QQuaternion(1.0f, 0.0f, 0.0f, 1.0f))); + expectedChanges.push_back(change); + + QTest::newRow("quaternion rotation") + << animatorId << mappingData << channelResults << finalFrame + << expectedChanges; + + mappingData.clear(); + channelResults.clear(); + expectedChanges.clear(); + } + } + + void checkPreparePropertyChanges() + { + // GIVEN + QFETCH(Qt3DCore::QNodeId, animatorId); + QFETCH(QVector<MappingData>, mappingData); + QFETCH(QVector<float>, channelResults); + QFETCH(bool, finalFrame); + QFETCH(QVector<Qt3DCore::QPropertyUpdatedChangePtr>, expectedChanges); + + // WHEN + QVector<Qt3DCore::QSceneChangePtr> actualChanges + = preparePropertyChanges(animatorId, mappingData, channelResults, finalFrame); + + // THEN + QCOMPARE(actualChanges.size(), expectedChanges.size()); + for (int i = 0; i < actualChanges.size(); ++i) { + auto expectedChange = expectedChanges[i]; + auto actualChange + = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(expectedChanges[i]); + + QCOMPARE(actualChange->subjectId(), expectedChange->subjectId()); + QCOMPARE(actualChange->deliveryFlags(), expectedChange->deliveryFlags()); + QCOMPARE(actualChange->propertyName(), expectedChange->propertyName()); + QCOMPARE(actualChange->value(), expectedChange->value()); + } + } + + void checkEvaluateClipAtLocalTime_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<AnimationClip *>("clip"); + QTest::addColumn<float>("localTime"); + QTest::addColumn<ClipResults>("expectedResults"); + + Handler *handler; + AnimationClip *clip; + float localTime; + ClipResults expectedResults; + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + localTime = 0.0f; + expectedResults = QVector<float>() << 0.0f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, t = 0.0") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + localTime = clip->duration(); + expectedResults = QVector<float>() << 5.0f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, t = duration") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + localTime = clip->duration() / 2.0f; + expectedResults = QVector<float>() << 2.5f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, t = duration/2") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + localTime = 0.0f; + expectedResults = QVector<float>() + << 0.0f << 0.0f << 0.0f // Translation + << 1.0f << 0.0f << 0.0f << 0.0f; // Rotation + + QTest::newRow("clip2.json, t = 0.0") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + localTime = clip->duration(); + expectedResults = QVector<float>() + << 5.0f << 0.0f << 0.0f // Translation + << 0.0f << 0.0f << -1.0f << 0.0f; // Rotation + + QTest::newRow("clip2.json, t = duration") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + localTime = clip->duration() / 2.0f; + expectedResults = QVector<float>() + << 2.5f << 0.0f << 0.0f // Translation + << 0.5f << 0.0f << -0.5f << 0.0f; // Rotation + + QTest::newRow("clip2.json, t = duration/2") + << handler << clip << localTime << expectedResults; + expectedResults.clear(); + } + } + + void checkEvaluateClipAtLocalTime() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(AnimationClip *, clip); + QFETCH(float, localTime); + QFETCH(ClipResults, expectedResults); + + // WHEN + ClipResults actualResults = evaluateClipAtLocalTime(clip, localTime); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + auto actual = actualResults[i]; + auto expected = expectedResults[i]; + + QVERIFY(fuzzyCompare(actual, expected) == true); + } + + // Cleanup + delete handler; + } + + void checkEvaluateClipAtPhase_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<AnimationClip *>("clip"); + QTest::addColumn<float>("phase"); + QTest::addColumn<ClipResults>("expectedResults"); + + Handler *handler; + AnimationClip *clip; + float phase; + ClipResults expectedResults; + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + phase = 0.0f; + expectedResults = QVector<float>() << 0.0f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, phi = 0.0") + << handler << clip << phase << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + phase = 1.0f; + expectedResults = QVector<float>() << 5.0f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, phi = 1.0") + << handler << clip << phase << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + phase = 0.5f; + expectedResults = QVector<float>() << 2.5f << 0.0f << 0.0f; + + QTest::newRow("clip1.json, phi = 0.5") + << handler << clip << phase << expectedResults; + expectedResults.clear(); + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + phase = 0.0f; + expectedResults = QVector<float>() + << 0.0f << 0.0f << 0.0f // Translation + << 1.0f << 0.0f << 0.0f << 0.0f; // Rotation + + QTest::newRow("clip2.json, phi = 0.0") + << handler << clip << phase << expectedResults; + expectedResults.clear(); + } + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + phase = 1.0f; + expectedResults = QVector<float>() + << 5.0f << 0.0f << 0.0f // Translation + << 0.0f << 0.0f << -1.0f << 0.0f; // Rotation + + QTest::newRow("clip2.json, t = 1.0") + << handler << clip << phase << expectedResults; + expectedResults.clear(); + } + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip2.json")); + phase = 0.5f; + expectedResults = QVector<float>() + << 2.5f << 0.0f << 0.0f // Translation + << 0.5f << 0.0f << -0.5f << 0.0f; // Rotation + + QTest::newRow("clip2.json, phi = 0.5") + << handler << clip << phase << expectedResults; + expectedResults.clear(); + } + } + + void checkEvaluateClipAtPhase() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(AnimationClip *, clip); + QFETCH(float, phase); + QFETCH(ClipResults, expectedResults); + + // WHEN + ClipResults actualResults = evaluateClipAtPhase(clip, phase); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + auto actual = actualResults[i]; + auto expected = expectedResults[i]; + + QVERIFY(fuzzyCompare(actual, expected) == true); + } + + // Cleanup + delete handler; + } + + void checkChannelComponentsToIndicesHelper_data() + { + QTest::addColumn<Channel>("channel"); + QTest::addColumn<int>("dataType"); + QTest::addColumn<int>("offset"); + QTest::addColumn<QVector<char>>("suffixes"); + QTest::addColumn<QVector<int>>("expectedResults"); + + Channel channel; + int dataType; + int offset; + QVector<char> suffixes; + QVector<int> expectedResults; + + // vec3 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("Location"); + channel.channelComponents.resize(3); + channel.channelComponents[0].name = QLatin1String("Location X"); + channel.channelComponents[1].name = QLatin1String("Location Y"); + channel.channelComponents[2].name = QLatin1String("Location Z"); + + dataType = static_cast<int>(QVariant::Vector3D); + offset = 0; + suffixes = (QVector<char>() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector<int>() << 0 << 1 << 2); + + QTest::newRow("vec3 location, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 4; + expectedResults = (QVector<int>() << 4 << 5 << 6); + QTest::newRow("vec3 location, offset = 4") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // vec2 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("pos"); + channel.channelComponents.resize(2); + channel.channelComponents[0].name = QLatin1String("pos X"); + channel.channelComponents[1].name = QLatin1String("pos Y"); + + dataType = static_cast<int>(QVariant::Vector2D); + offset = 0; + suffixes = (QVector<char>() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector<int>() << 0 << 1); + + QTest::newRow("vec2 pos, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 2; + expectedResults = (QVector<int>() << 2 << 3); + QTest::newRow("vec2 pos, offset = 2") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // vec4 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("foo"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("foo X"); + channel.channelComponents[1].name = QLatin1String("foo Y"); + channel.channelComponents[2].name = QLatin1String("foo Z"); + channel.channelComponents[3].name = QLatin1String("foo W"); + + dataType = static_cast<int>(QVariant::Vector4D); + offset = 0; + suffixes = (QVector<char>() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector<int>() << 0 << 1 << 2 << 3); + + QTest::newRow("vec4 foo, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector<int>() << 10 << 11 << 12 << 13); + QTest::newRow("vec4 foo, offset = 10") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // double with and without offset + { + channel = Channel(); + channel.name = QLatin1String("foo"); + channel.channelComponents.resize(1); + channel.channelComponents[0].name = QLatin1String("Mass X"); + + dataType = static_cast<int>(QVariant::Double); + offset = 0; + suffixes = (QVector<char>() << 'X' << 'Y' << 'Z' << 'W'); + expectedResults = (QVector<int>() << 0); + + QTest::newRow("double Mass, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 5; + expectedResults = (QVector<int>() << 5); + QTest::newRow("double Mass, offset = 5") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // quaternion with and without offset + { + channel = Channel(); + channel.name = QLatin1String("Rotation"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("Rotation W"); + channel.channelComponents[1].name = QLatin1String("Rotation X"); + channel.channelComponents[2].name = QLatin1String("Rotation Y"); + channel.channelComponents[3].name = QLatin1String("Rotation Z"); + + dataType = static_cast<int>(QVariant::Quaternion); + offset = 0; + suffixes = (QVector<char>() << 'W' << 'X' << 'Y' << 'Z'); + expectedResults = (QVector<int>() << 0 << 1 << 2 << 3); + + QTest::newRow("quaternion Rotation, offset = 0") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector<int>() << 10 << 11 << 12 << 13); + QTest::newRow("quaternion Rotation, offset = 10") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + + // quaternion with and without offset, randomized + { + channel = Channel(); + channel.name = QLatin1String("Rotation"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("Rotation X"); + channel.channelComponents[1].name = QLatin1String("Rotation W"); + channel.channelComponents[2].name = QLatin1String("Rotation Z"); + channel.channelComponents[3].name = QLatin1String("Rotation Y"); + + dataType = static_cast<int>(QVariant::Quaternion); + offset = 0; + suffixes = (QVector<char>() << 'W' << 'X' << 'Y' << 'Z'); + expectedResults = (QVector<int>() << 1 << 0 << 3 << 2); + + QTest::newRow("quaternion Rotation, offset = 0, randomized") + << channel << dataType << offset << suffixes << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector<int>() << 11 << 10 << 13 << 12); + QTest::newRow("quaternion Rotation, offset = 10, randomized") + << channel << dataType << offset << suffixes << expectedResults; + + suffixes.clear(); + expectedResults.clear(); + } + } + + void checkChannelComponentsToIndicesHelper() + { + // GIVEN + QFETCH(Channel, channel); + QFETCH(int, dataType); + QFETCH(int, offset); + QFETCH(QVector<char>, suffixes); + QFETCH(QVector<int>, expectedResults); + + // WHEN + QVector<int> actualResults + = channelComponentsToIndicesHelper(channel, dataType, offset, suffixes); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + QCOMPARE(actualResults[i], expectedResults[i]); + } + } + + void checkChannelComponentsToIndices_data() + { + QTest::addColumn<Channel>("channel"); + QTest::addColumn<int>("dataType"); + QTest::addColumn<int>("offset"); + QTest::addColumn<QVector<int>>("expectedResults"); + + Channel channel; + int dataType; + int offset; + QVector<int> expectedResults; + + // Quaternion + { + channel = Channel(); + channel.name = QLatin1String("Rotation"); + channel.channelComponents.resize(4); + channel.channelComponents[0].name = QLatin1String("Rotation W"); + channel.channelComponents[1].name = QLatin1String("Rotation X"); + channel.channelComponents[2].name = QLatin1String("Rotation Y"); + channel.channelComponents[3].name = QLatin1String("Rotation Z"); + + dataType = static_cast<int>(QVariant::Quaternion); + offset = 0; + expectedResults = (QVector<int>() << 0 << 1 << 2 << 3); + + QTest::newRow("quaternion Rotation, offset = 0") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + + offset = 10; + expectedResults = (QVector<int>() << 10 << 11 << 12 << 13); + QTest::newRow("quaternion Rotation, offset = 10") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + } + + // vec3 with and without offset + { + channel = Channel(); + channel.name = QLatin1String("Location"); + channel.channelComponents.resize(3); + channel.channelComponents[0].name = QLatin1String("Location X"); + channel.channelComponents[1].name = QLatin1String("Location Y"); + channel.channelComponents[2].name = QLatin1String("Location Z"); + + dataType = static_cast<int>(QVariant::Vector3D); + offset = 0; + expectedResults = (QVector<int>() << 0 << 1 << 2); + + QTest::newRow("vec3 location, offset = 0") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + + offset = 4; + expectedResults = (QVector<int>() << 4 << 5 << 6); + QTest::newRow("vec3 location, offset = 4") + << channel << dataType << offset << expectedResults; + + expectedResults.clear(); + } + } + + void checkChannelComponentsToIndices() + { + QFETCH(Channel, channel); + QFETCH(int, dataType); + QFETCH(int, offset); + QFETCH(QVector<int>, expectedResults); + + // WHEN + QVector<int> actualResults + = channelComponentsToIndices(channel, dataType, offset); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + QCOMPARE(actualResults[i], expectedResults[i]); + } + } + + void checkEvaluationDataForClip_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<AnimationClip *>("clip"); + QTest::addColumn<AnimatorEvaluationData>("animatorData"); + QTest::addColumn<ClipEvaluationData>("expectedClipData"); + + Handler *handler; + AnimationClip *clip; + AnimatorEvaluationData animatorData; + ClipEvaluationData clipData; + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = 0; + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = false; + + QTest::newRow("clip1.json, globalTime = 0") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = (clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = true; + + QTest::newRow("clip1.json, globalTime = duration") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 0; // Infinite loops + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = 2.0 * clip->duration() * 1.0e9; + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = false; + + QTest::newRow("clip1.json, globalTime = 2 * duration, loops = infinite") + << handler << clip << animatorData << clipData; + } + + { + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + const qint64 globalStartTimeNS = 0; + const int loops = 2; + auto animator = createClipAnimator(handler, globalStartTimeNS, loops); + const qint64 globalTimeNS = (2.0 * clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip + animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere + + clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime, + animatorData.startTime, + animatorData.playbackRate, + clip->duration(), + animatorData.loopCount, + clipData.currentLoop); // Tested elsewhere + clipData.isFinalFrame = true; + + QTest::newRow("clip1.json, globalTime = 2 * duration + 1, loops = 2") + << handler << clip << animatorData << clipData; + } + } + + void checkEvaluationDataForClip() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(AnimationClip *, clip); + QFETCH(AnimatorEvaluationData, animatorData); + QFETCH(ClipEvaluationData, expectedClipData); + + // WHEN + ClipEvaluationData actualClipData = evaluationDataForClip(clip, animatorData); + + // THEN + QCOMPARE(actualClipData.currentLoop, expectedClipData.currentLoop); + QVERIFY(fuzzyCompare(actualClipData.localTime, expectedClipData.localTime) == true); + QCOMPARE(actualClipData.isFinalFrame, expectedClipData.isFinalFrame); + + // Cleanup + delete handler; + } + + void checkEvaluationDataForAnimator_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<ClipAnimator *>("animator"); + QTest::addColumn<qint64>("globalTimeNS"); + QTest::addColumn<AnimatorEvaluationData>("expectedAnimatorData"); + + Handler *handler; + ClipAnimator *animator; + qint64 globalTimeNS; + AnimatorEvaluationData expectedAnimatorData; + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 0; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 0.0; + expectedAnimatorData.globalTime = 0.0; + + QTest::newRow("globalStartTime = 0, globalTime = 0, loops = 1") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loops = 5; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 0; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 0.0; + expectedAnimatorData.globalTime = 0.0; + + QTest::newRow("globalStartTime = 0, globalTime = 0, loops = 5") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 5000000000; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 0.0; + expectedAnimatorData.globalTime = 5.0; + + QTest::newRow("globalStartTime = 0, globalTime = 5, loops = 1") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + + { + handler = new Handler(); + const qint64 globalStartTimeNS = 3000000000; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + globalTimeNS = 5000000000; + + expectedAnimatorData.loopCount = loops; + expectedAnimatorData.playbackRate = 1.0; // hard-wired for now + expectedAnimatorData.startTime = 3.0; + expectedAnimatorData.globalTime = 5.0; + + QTest::newRow("globalStartTime = 3, globalTime = 5, loops = 1") + << handler << animator << globalTimeNS << expectedAnimatorData; + } + } + + void checkEvaluationDataForAnimator() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(ClipAnimator *, animator); + QFETCH(qint64, globalTimeNS); + QFETCH(AnimatorEvaluationData, expectedAnimatorData); + + // WHEN + AnimatorEvaluationData actualAnimatorData = evaluationDataForAnimator(animator, globalTimeNS); + + // THEN + QCOMPARE(actualAnimatorData.loopCount, expectedAnimatorData.loopCount); + QVERIFY(fuzzyCompare(actualAnimatorData.playbackRate, expectedAnimatorData.playbackRate) == true); + QVERIFY(fuzzyCompare(actualAnimatorData.startTime, expectedAnimatorData.startTime) == true); + QVERIFY(fuzzyCompare(actualAnimatorData.globalTime, expectedAnimatorData.globalTime) == true); + + // Cleanup + delete handler; + } + + void checkGatherValueNodesToEvaluate_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<Qt3DCore::QNodeId>("blendTreeRootId"); + QTest::addColumn<QVector<Qt3DCore::QNodeId>>("expectedIds"); + + { + Handler *handler = new Handler; + + const auto lerp = createLerpClipBlend(handler); + const auto value1 = createClipBlendValue(handler); + const auto clip1Id = Qt3DCore::QNodeId::createId(); + value1->setClipId(clip1Id); + lerp->setStartClipId(value1->peerId()); + + const auto value2 = createClipBlendValue(handler); + const auto clip2Id = Qt3DCore::QNodeId::createId(); + value2->setClipId(clip2Id); + lerp->setEndClipId(value2->peerId()); + + QVector<Qt3DCore::QNodeId> expectedIds = { value1->peerId(), value2->peerId() }; + + QTest::newRow("simple lerp") << handler << lerp->peerId() << expectedIds; + } + } + + void checkGatherValueNodesToEvaluate() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(Qt3DCore::QNodeId, blendTreeRootId); + QFETCH(QVector<Qt3DCore::QNodeId>, expectedIds); + + // WHEN + QVector<Qt3DCore::QNodeId> actualIds = gatherValueNodesToEvaluate(handler, blendTreeRootId); + + // THEN + QCOMPARE(actualIds.size(), expectedIds.size()); + for (int i = 0; i < actualIds.size(); ++i) + QCOMPARE(actualIds[i], expectedIds[i]); + + // Cleanup + delete handler; + } + + void checkEvaluateBlendTree_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<BlendedClipAnimator *>("animator"); + QTest::addColumn<Qt3DCore::QNodeId>("blendNodeId"); + QTest::addColumn<ClipResults>("expectedResults"); + + { + /* + ValueNode1---- + | + MeanBlendNode + | + ValueNode2---- + */ + + auto handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + // Set up the blend node and dependencies (evaluated clip results of the + // dependent nodes in the animator indexed by their ids). + MeanBlendNode *blendNode = createMeanBlendNode(handler); + + // First clip to use in the mean + auto valueNode1 = createClipBlendValue(handler); + ClipResults valueNode1Results = { 0.0f, 0.0f, 0.0f }; + valueNode1->setClipResults(animator->peerId(), valueNode1Results); + + // Second clip to use in the mean + auto valueNode2 = createClipBlendValue(handler); + ClipResults valueNode2Results = { 1.0f, 1.0f, 1.0f }; + valueNode2->setClipResults(animator->peerId(), valueNode2Results); + + blendNode->setValueNodeIds(valueNode1->peerId(), valueNode2->peerId()); + + ClipResults expectedResults = { 0.5f, 0.5f, 0.5f }; + + QTest::newRow("mean node, 1 channel") + << handler << animator << blendNode->peerId() << expectedResults; + } + + { + /* + ValueNode1---- + | + MeanBlendNode + | + ValueNode2---- + */ + + auto handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + // Set up the blend node and dependencies (evaluated clip results of the + // dependent nodes in the animator indexed by their ids). + MeanBlendNode *blendNode = createMeanBlendNode(handler); + + // First clip to use in the mean + auto valueNode1 = createClipBlendValue(handler); + ClipResults valueNode1Results = { 0.0f, 0.0f, 0.0f, 1.0f, 2.0f, 3.0f }; + valueNode1->setClipResults(animator->peerId(), valueNode1Results); + + // Second clip to use in the mean + auto valueNode2 = createClipBlendValue(handler); + ClipResults valueNode2Results = { 1.0f, 1.0f, 1.0f, 2.0f, 4.0f, 6.0f }; + valueNode2->setClipResults(animator->peerId(), valueNode2Results); + + blendNode->setValueNodeIds(valueNode1->peerId(), valueNode2->peerId()); + + ClipResults expectedResults = { 0.5f, 0.5f, 0.5f, 1.5f, 3.0f, 4.5f }; + + QTest::newRow("mean node, 2 channels") + << handler << animator << blendNode->peerId() << expectedResults; + } + + { + /* + ValueNode1---- + | + MeanBlendNode1------ + | | + ValueNode2---- | + MeanBlendNode3 + ValueNode3---- | + | | + MeanBlendNode2------ + | + ValueNode4---- + */ + + auto handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + // Set up the blend node and dependencies (evaluated clip results of the + // dependent nodes in the animator indexed by their ids). + + // MeanBlendNode1 + MeanBlendNode *meanNode1 = createMeanBlendNode(handler); + + // First clip to use in mean1 + auto valueNode1 = createClipBlendValue(handler); + ClipResults valueNode1Results = { 0.0f, 0.0f, 0.0f }; + valueNode1->setClipResults(animator->peerId(), valueNode1Results); + + // Second clip to use in mean1 + auto valueNode2 = createClipBlendValue(handler); + ClipResults valueNode2Results = { 2.0f, 2.0f, 2.0f }; + valueNode2->setClipResults(animator->peerId(), valueNode2Results); + + meanNode1->setValueNodeIds(valueNode1->peerId(), valueNode2->peerId()); + + + // MeanBlendNode2 + MeanBlendNode *meanNode2 = createMeanBlendNode(handler); + + // First clip to use in mean1 + auto valueNode3 = createClipBlendValue(handler); + ClipResults valueNode3Results = { 10.0f, 10.0f, 10.0f }; + valueNode3->setClipResults(animator->peerId(), valueNode3Results); + + // Second clip to use in mean1 + auto valueNode4 = createClipBlendValue(handler); + ClipResults valueNode4Results = { 20.0f, 20.0f, 20.0f }; + valueNode4->setClipResults(animator->peerId(), valueNode4Results); + + meanNode2->setValueNodeIds(valueNode3->peerId(), valueNode4->peerId()); + + + // MeanBlendNode3 + MeanBlendNode *meanNode3 = createMeanBlendNode(handler); + meanNode3->setValueNodeIds(meanNode1->peerId(), meanNode2->peerId()); + + // Mean1 = 1 + // Mean2 = 15 + // Mean3 = (1 + 15 ) / 2 = 8 + ClipResults expectedResults = { 8.0f, 8.0f, 8.0f }; + + QTest::newRow("3 mean nodes, 1 channel") + << handler << animator << meanNode3->peerId() << expectedResults; + } + + { + /* + ValueNode1---- + | + MeanBlendNode1------ + | | + ValueNode2---- | + MeanBlendNode3--- + ValueNode3---- | | + | | | + MeanBlendNode2------ AdditiveBlendNode1 + | | + ValueNode4---- | + ValueNode5------- + */ + + auto handler = new Handler(); + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + // Set up the blend node and dependencies (evaluated clip results of the + // dependent nodes in the animator indexed by their ids). + + // MeanBlendNode1 + MeanBlendNode *meanNode1 = createMeanBlendNode(handler); + + // First clip to use in mean1 + auto valueNode1 = createClipBlendValue(handler); + ClipResults valueNode1Results = { 0.0f, 0.0f, 0.0f }; + valueNode1->setClipResults(animator->peerId(), valueNode1Results); + + // Second clip to use in mean1 + auto valueNode2 = createClipBlendValue(handler); + ClipResults valueNode2Results = { 2.0f, 2.0f, 2.0f }; + valueNode2->setClipResults(animator->peerId(), valueNode2Results); + + meanNode1->setValueNodeIds(valueNode1->peerId(), valueNode2->peerId()); + + + // MeanBlendNode2 + MeanBlendNode *meanNode2 = createMeanBlendNode(handler); + + // First clip to use in mean2 + auto valueNode3 = createClipBlendValue(handler); + ClipResults valueNode3Results = { 10.0f, 10.0f, 10.0f }; + valueNode3->setClipResults(animator->peerId(), valueNode3Results); + + // Second clip to use in mean2 + auto valueNode4 = createClipBlendValue(handler); + ClipResults valueNode4Results = { 20.0f, 20.0f, 20.0f }; + valueNode4->setClipResults(animator->peerId(), valueNode4Results); + + meanNode2->setValueNodeIds(valueNode3->peerId(), valueNode4->peerId()); + + + // MeanBlendNode3 + MeanBlendNode *meanNode3 = createMeanBlendNode(handler); + meanNode3->setValueNodeIds(meanNode1->peerId(), meanNode2->peerId()); + + + // AdditiveBlendNode1 + AdditiveClipBlend *additiveBlendNode1 = createAdditiveClipBlend(handler); + auto valueNode5 = createClipBlendValue(handler); + ClipResults valueNode5Results = { 1.0f, 2.0f, 3.0f }; + valueNode5->setClipResults(animator->peerId(), valueNode5Results); + + additiveBlendNode1->setBaseClipId(meanNode3->peerId()); + additiveBlendNode1->setAdditiveClipId(valueNode5->peerId()); + additiveBlendNode1->setAdditiveFactor(0.5); + + // Mean1 = 1 + // Mean2 = 15 + // Mean3 = (1 + 15 ) / 2 = 8 + // Additive1 = 8 + 0.5 * (1, 2, 3) = (8.5, 9, 9.5) + ClipResults expectedResults = { 8.5f, 9.0f, 9.5f }; + + QTest::newRow("3 mean nodes + additive, 1 channel") + << handler << animator << additiveBlendNode1->peerId() << expectedResults; + } + } + + void checkEvaluateBlendTree() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(BlendedClipAnimator *, animator); + QFETCH(Qt3DCore::QNodeId, blendNodeId); + QFETCH(ClipResults, expectedResults); + + // WHEN + const ClipResults actualResults = evaluateBlendTree(handler, animator, blendNodeId); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) + QCOMPARE(actualResults[i], expectedResults[i]); + + // Cleanup + delete handler; + } + + void checkFormatClipResults_data() + { + QTest::addColumn<ClipResults>("rawClipResults"); + QTest::addColumn<ComponentIndices>("format"); + QTest::addColumn<ClipResults>("expectedResults"); + + { + ClipResults rawClipResults = { 1.0f, 2.0f, 3.0f }; + ComponentIndices format = { 0, 1, 2 }; + ClipResults expectedResults = { 1.0f, 2.0f, 3.0f }; + + QTest::newRow("identity") + << rawClipResults << format << expectedResults; + } + + { + ClipResults rawClipResults = { 1.0f, 2.0f }; + ComponentIndices format = { 1, 0 }; + ClipResults expectedResults = { 2.0f, 1.0f }; + + QTest::newRow("swap") + << rawClipResults << format << expectedResults; + } + + { + ClipResults rawClipResults = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + ComponentIndices format = { 0, 2, 1, 3, 4 }; + ClipResults expectedResults = { 1.0f, 3.0f, 2.0f, 4.0f, 5.0f }; + + QTest::newRow("swap subset") + << rawClipResults << format << expectedResults; + } + + { + ClipResults rawClipResults = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + ComponentIndices format = { 4, 3, 2, 1, 0 }; + ClipResults expectedResults = { 5.0f, 4.0f, 3.0f, 2.0f, 1.0f }; + + QTest::newRow("reverse") + << rawClipResults << format << expectedResults; + } + + { + ClipResults rawClipResults = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; + ComponentIndices format = { 0, 1, -1, 3, 4 }; + ClipResults expectedResults = { 1.0f, 2.0f, 0.0f, 4.0f, 5.0f }; + + QTest::newRow("include missing") + << rawClipResults << format << expectedResults; + } + } + + void checkFormatClipResults() + { + // GIVEN + QFETCH(ClipResults, rawClipResults); + QFETCH(ComponentIndices, format); + QFETCH(ClipResults, expectedResults); + + // WHEN + const ClipResults actualResults = formatClipResults(rawClipResults, format); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) + QCOMPARE(actualResults[i], expectedResults[i]); + } + + void checkBuildRequiredChannelsAndTypes_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<ChannelMapper *>("mapper"); + QTest::addColumn<QVector<ChannelNameAndType>>("expectedResults"); + + { + auto handler = new Handler(); + auto channelMapping = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + QLatin1String("translation"), + "translation", + static_cast<int>(QVariant::Vector3D)); + QVector<ChannelMapping *> channelMappings; + channelMappings.push_back(channelMapping); + + auto channelMapper = createChannelMapper(handler, + QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); + + QVector<ChannelNameAndType> expectedResults; + expectedResults.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + + QTest::addRow("Location, vec3") << handler << channelMapper << expectedResults; + } + + { + auto handler = new Handler(); + auto channelMapping1 = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + QLatin1String("translation"), + "translation", + static_cast<int>(QVariant::Vector3D)); + auto channelMapping2 = createChannelMapping(handler, + QLatin1String("Rotation"), + Qt3DCore::QNodeId::createId(), + QLatin1String("rotatrion"), + "rotation", + static_cast<int>(QVariant::Quaternion)); + QVector<ChannelMapping *> channelMappings; + channelMappings.push_back(channelMapping1); + channelMappings.push_back(channelMapping2); + + QVector<Qt3DCore::QNodeId> channelMappingIds + = (QVector<Qt3DCore::QNodeId>() + << channelMapping1->peerId() + << channelMapping2->peerId()); + auto channelMapper = createChannelMapper(handler, channelMappingIds); + + QVector<ChannelNameAndType> expectedResults; + expectedResults.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + expectedResults.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + + QTest::addRow("Multiple unique channels") << handler << channelMapper << expectedResults; + } + + { + auto handler = new Handler(); + auto channelMapping1 = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + QLatin1String("translation"), + "translation", + static_cast<int>(QVariant::Vector3D)); + auto channelMapping2 = createChannelMapping(handler, + QLatin1String("Rotation"), + Qt3DCore::QNodeId::createId(), + QLatin1String("rotation"), + "rotation", + static_cast<int>(QVariant::Quaternion)); + auto channelMapping3 = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + QLatin1String("translation"), + "translation", + static_cast<int>(QVariant::Vector3D)); + auto channelMapping4 = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + QLatin1String("translation"), + "translation", + static_cast<int>(QVariant::Vector3D)); + + QVector<ChannelMapping *> channelMappings; + channelMappings.push_back(channelMapping1); + channelMappings.push_back(channelMapping2); + channelMappings.push_back(channelMapping3); + channelMappings.push_back(channelMapping4); + + QVector<Qt3DCore::QNodeId> channelMappingIds + = (QVector<Qt3DCore::QNodeId>() + << channelMapping1->peerId() + << channelMapping2->peerId() + << channelMapping3->peerId() + << channelMapping4->peerId()); + auto channelMapper = createChannelMapper(handler, channelMappingIds); + + QVector<ChannelNameAndType> expectedResults; + expectedResults.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + expectedResults.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + + QTest::addRow("Multiple channels with repeats") << handler << channelMapper << expectedResults; + } + } + + void checkBuildRequiredChannelsAndTypes() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(ChannelMapper *, mapper); + QFETCH(QVector<ChannelNameAndType>, expectedResults); + + // WHEN + const QVector<ChannelNameAndType> actualResults = buildRequiredChannelsAndTypes(handler, mapper); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) + QCOMPARE(actualResults[i], expectedResults[i]); + + // Cleanup + delete handler; + } + + void checkAssignChannelComponentIndices_data() + { + QTest::addColumn<QVector<ChannelNameAndType>>("allChannels"); + QTest::addColumn<QVector<ComponentIndices>>("expectedResults"); + + { + QVector<ChannelNameAndType> allChannels; + allChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + + QVector<ComponentIndices> expectedResults; + expectedResults.push_back({ 0, 1, 2 }); + + QTest::newRow("vec3 location") << allChannels << expectedResults; + } + + { + QVector<ChannelNameAndType> allChannels; + allChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + allChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + + QVector<ComponentIndices> expectedResults; + expectedResults.push_back({ 0, 1, 2 }); + expectedResults.push_back({ 3, 4, 5, 6 }); + + QTest::newRow("vec3 location, quaterion rotation") << allChannels << expectedResults; + } + + { + QVector<ChannelNameAndType> allChannels; + allChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + allChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + allChannels.push_back({ QLatin1String("BaseColor"), static_cast<int>(QVariant::Vector3D) }); + allChannels.push_back({ QLatin1String("Metalness"), static_cast<int>(QVariant::Double) }); + allChannels.push_back({ QLatin1String("Roughness"), static_cast<int>(QVariant::Double) }); + + QVector<ComponentIndices> expectedResults; + expectedResults.push_back({ 0, 1, 2 }); + expectedResults.push_back({ 3, 4, 5, 6 }); + expectedResults.push_back({ 7, 8, 9 }); + expectedResults.push_back({ 10 }); + expectedResults.push_back({ 11 }); + + QTest::newRow("vec3 location, quaterion rotation, pbr metal-rough") << allChannels << expectedResults; + } + } + + void checkAssignChannelComponentIndices() + { + // GIVEN + QFETCH(QVector<ChannelNameAndType>, allChannels); + QFETCH(QVector<ComponentIndices>, expectedResults); + + // WHEN + const QVector<ComponentIndices> actualResults = assignChannelComponentIndices(allChannels); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) { + const ComponentIndices &actualResult = actualResults[i]; + const ComponentIndices &expectedResult = expectedResults[i]; + + for (int j = 0; j < actualResult.size(); ++j) + QCOMPARE(actualResult[j], expectedResult[j]); + } + } + + void checkGenerateClipFormatIndices_data() + { + QTest::addColumn<QVector<ChannelNameAndType>>("targetChannels"); + QTest::addColumn<QVector<ComponentIndices>>("targetIndices"); + QTest::addColumn<AnimationClip *>("clip"); + QTest::addColumn<ComponentIndices>("expectedResults"); + + { + QVector<ChannelNameAndType> targetChannels; + targetChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + targetChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Base Color"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Metalness"), static_cast<int>(QVariant::Double) }); + targetChannels.push_back({ QLatin1String("Roughness"), static_cast<int>(QVariant::Double) }); + + QVector<ComponentIndices> targetIndices; + targetIndices.push_back({ 0, 1, 2, 3 }); + targetIndices.push_back({ 4, 5, 6 }); + targetIndices.push_back({ 7, 8, 9 }); + targetIndices.push_back({ 10 }); + targetIndices.push_back({ 11 }); + + auto *clip = new AnimationClip(); + clip->setDataType(AnimationClip::File); + clip->setSource(QUrl("qrc:/clip3.json")); + clip->loadAnimation(); + + ComponentIndices expectedResults = { 0, 1, 2, 3, // Rotation + 4, 5, 6, // Location + 7, 8, 9, // Base Color + 10, // Metalness + 11 }; // Roughness + + QTest::newRow("rotation, location, pbr metal-rough") + << targetChannels << targetIndices << clip << expectedResults; + } + + { + QVector<ChannelNameAndType> targetChannels; + targetChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + targetChannels.push_back({ QLatin1String("Base Color"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Metalness"), static_cast<int>(QVariant::Double) }); + targetChannels.push_back({ QLatin1String("Roughness"), static_cast<int>(QVariant::Double) }); + + QVector<ComponentIndices> targetIndices; + targetIndices.push_back({ 0, 1, 2 }); + targetIndices.push_back({ 3, 4, 5, 6 }); + targetIndices.push_back({ 7, 8, 9 }); + targetIndices.push_back({ 10 }); + targetIndices.push_back({ 11 }); + + auto *clip = new AnimationClip(); + clip->setDataType(AnimationClip::File); + clip->setSource(QUrl("qrc:/clip3.json")); + clip->loadAnimation(); + + ComponentIndices expectedResults = { 4, 5, 6, // Location + 0, 1, 2, 3, // Rotation + 7, 8, 9, // Base Color + 10, // Metalness + 11 }; // Roughness + + QTest::newRow("location, rotation, pbr metal-rough") + << targetChannels << targetIndices << clip << expectedResults; + } + + { + QVector<ChannelNameAndType> targetChannels; + targetChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + targetChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Albedo"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Metalness"), static_cast<int>(QVariant::Double) }); + targetChannels.push_back({ QLatin1String("Roughness"), static_cast<int>(QVariant::Double) }); + + QVector<ComponentIndices> targetIndices; + targetIndices.push_back({ 0, 1, 2, 3 }); + targetIndices.push_back({ 4, 5, 6 }); + targetIndices.push_back({ 7, 8, 9 }); + targetIndices.push_back({ 10 }); + targetIndices.push_back({ 11 }); + + auto *clip = new AnimationClip(); + clip->setDataType(AnimationClip::File); + clip->setSource(QUrl("qrc:/clip3.json")); + clip->loadAnimation(); + + ComponentIndices expectedResults = { 0, 1, 2, 3, // Rotation + 4, 5, 6, // Location + -1, -1, -1, // Albedo (missing from clip) + 10, // Metalness + 11 }; // Roughness + + QTest::newRow("rotation, location, albedo (missing), metal-rough") + << targetChannels << targetIndices << clip << expectedResults; + } + + { + QVector<ChannelNameAndType> targetChannels; + targetChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) }); + targetChannels.push_back({ QLatin1String("Albedo"), static_cast<int>(QVariant::Vector3D) }); + targetChannels.push_back({ QLatin1String("Metalness"), static_cast<int>(QVariant::Double) }); + targetChannels.push_back({ QLatin1String("Roughness"), static_cast<int>(QVariant::Double) }); + + QVector<ComponentIndices> targetIndices; + targetIndices.push_back({ 0, 1, 2 }); + targetIndices.push_back({ 3, 4, 5, 6 }); + targetIndices.push_back({ 7, 8, 9 }); + targetIndices.push_back({ 10 }); + targetIndices.push_back({ 11 }); + + auto *clip = new AnimationClip(); + clip->setDataType(AnimationClip::File); + clip->setSource(QUrl("qrc:/clip3.json")); + clip->loadAnimation(); + + ComponentIndices expectedResults = { 4, 5, 6, // Location + 0, 1, 2, 3, // Rotation + -1, -1, -1, // Albedo (missing from clip) + 10, // Metalness + 11 }; // Roughness + + QTest::newRow("location, rotation, albedo (missing), metal-rough") + << targetChannels << targetIndices << clip << expectedResults; + } + } + + void checkGenerateClipFormatIndices() + { + // GIVEN + QFETCH(QVector<ChannelNameAndType>, targetChannels); + QFETCH(QVector<ComponentIndices>, targetIndices); + QFETCH(AnimationClip *, clip); + QFETCH(ComponentIndices, expectedResults); + + // WHEN + const ComponentIndices actualResults = generateClipFormatIndices(targetChannels, + targetIndices, + clip); + + // THEN + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) + QCOMPARE(actualResults[i], expectedResults[i]); + + // Cleanup + delete clip; + } +}; + +QTEST_MAIN(tst_AnimationUtils) + +#include "tst_animationutils.moc" diff --git a/tests/auto/animation/bezierevaluator/tst_bezierevaluator.cpp b/tests/auto/animation/bezierevaluator/tst_bezierevaluator.cpp index 746af8d55..5dc971ab7 100644 --- a/tests/auto/animation/bezierevaluator/tst_bezierevaluator.cpp +++ b/tests/auto/animation/bezierevaluator/tst_bezierevaluator.cpp @@ -35,6 +35,7 @@ Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Keyframe) +using namespace Qt3DAnimation; using namespace Qt3DAnimation::Animation; class tst_BezierEvaluator : public QObject @@ -131,9 +132,9 @@ private Q_SLOTS: QTest::addColumn<QVector<float>>("bezierParamters"); float t0 = 0.0f; - Keyframe kf0{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, Keyframe::Bezier}; + Keyframe kf0{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, QKeyFrame::BezierInterpolation}; float t1 = 50.0f; - Keyframe kf1{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, Keyframe::Bezier}; + Keyframe kf1{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, QKeyFrame::BezierInterpolation}; const int count = 21; QVector<float> times = (QVector<float>() << 0.0f @@ -199,9 +200,9 @@ private Q_SLOTS: QTest::addColumn<QVector<float>>("values"); float t0 = 0.0f; - Keyframe kf0{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, Keyframe::Bezier}; + Keyframe kf0{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, QKeyFrame::BezierInterpolation}; float t1 = 50.0f; - Keyframe kf1{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, Keyframe::Bezier}; + Keyframe kf1{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, QKeyFrame::BezierInterpolation}; QVector<float> times = (QVector<float>() << 0.0f << 1.00375f diff --git a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp index c53f6ec62..3265de167 100644 --- a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp +++ b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp @@ -28,7 +28,7 @@ #include <QtTest/QTest> #include <Qt3DAnimation/private/blendedclipanimator_p.h> -#include <Qt3DAnimation/qanimationclip.h> +#include <Qt3DAnimation/qanimationcliploader.h> #include <Qt3DAnimation/qblendedclipanimator.h> #include <Qt3DCore/private/qnode_p.h> #include <Qt3DCore/private/qscene_p.h> @@ -39,7 +39,7 @@ #include <QtTest/QTest> #include <Qt3DAnimation/qblendedclipanimator.h> -#include <Qt3DAnimation/qlerpblend.h> +#include <Qt3DAnimation/qlerpclipblend.h> #include <Qt3DAnimation/qchannelmapper.h> #include <Qt3DAnimation/private/qblendedclipanimator_p.h> #include <Qt3DAnimation/private/blendedclipanimator_p.h> @@ -65,7 +65,6 @@ private Q_SLOTS: QCOMPARE(backendBlendedClipAnimator.isRunning(), false); QCOMPARE(backendBlendedClipAnimator.startTime(), 0); QCOMPARE(backendBlendedClipAnimator.currentLoop(), 0); - QCOMPARE(backendBlendedClipAnimator.mappingData().size(), 0); QCOMPARE(backendBlendedClipAnimator.loops(), 1); } @@ -83,9 +82,6 @@ private Q_SLOTS: backendBlendedClipAnimator.setMapperId(Qt3DCore::QNodeId::createId()); backendBlendedClipAnimator.setRunning(true); backendBlendedClipAnimator.setStartTime(28); - QVector<Qt3DAnimation::Animation::AnimationUtils::BlendingMappingData> mappingData; - mappingData.resize(5); - backendBlendedClipAnimator.setMappingData(mappingData); backendBlendedClipAnimator.cleanup(); // THEN @@ -95,7 +91,6 @@ private Q_SLOTS: QCOMPARE(backendBlendedClipAnimator.isRunning(), false); QCOMPARE(backendBlendedClipAnimator.startTime(), 0); QCOMPARE(backendBlendedClipAnimator.currentLoop(), 0); - QCOMPARE(backendBlendedClipAnimator.mappingData().size(), 0); QCOMPARE(backendBlendedClipAnimator.loops(), 1); } @@ -104,11 +99,11 @@ private Q_SLOTS: // GIVEN Qt3DAnimation::QBlendedClipAnimator blendedClipAnimator; Qt3DAnimation::QChannelMapper mapper; - Qt3DAnimation::QLerpBlend blendTree; + Qt3DAnimation::QLerpClipBlend blendTree; blendedClipAnimator.setRunning(true); blendedClipAnimator.setBlendTree(&blendTree); blendedClipAnimator.setChannelMapper(&mapper); - blendedClipAnimator.setLoops(10); + blendedClipAnimator.setLoopCount(10); { // WHEN diff --git a/tests/auto/animation/clipanimator/tst_clipanimator.cpp b/tests/auto/animation/clipanimator/tst_clipanimator.cpp index 77f067973..615547405 100644 --- a/tests/auto/animation/clipanimator/tst_clipanimator.cpp +++ b/tests/auto/animation/clipanimator/tst_clipanimator.cpp @@ -28,7 +28,7 @@ #include <QtTest/QTest> #include <Qt3DAnimation/private/clipanimator_p.h> -#include <Qt3DAnimation/qanimationclip.h> +#include <Qt3DAnimation/qanimationcliploader.h> #include <Qt3DAnimation/qclipanimator.h> #include <Qt3DCore/private/qnode_p.h> #include <Qt3DCore/private/qscene_p.h> @@ -49,10 +49,10 @@ private Q_SLOTS: Qt3DAnimation::Animation::ClipAnimator backendAnimator; backendAnimator.setHandler(&handler); Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(clip); - animator.setLoops(10); + animator.setLoopCount(10); // WHEN simulateInitialization(&animator, &backendAnimator); @@ -62,7 +62,7 @@ private Q_SLOTS: QCOMPARE(backendAnimator.isEnabled(), animator.isEnabled()); QCOMPARE(backendAnimator.clipId(), clip->id()); QCOMPARE(backendAnimator.isRunning(), animator.isRunning()); - QCOMPARE(backendAnimator.loops(), animator.loops()); + QCOMPARE(backendAnimator.loops(), animator.loopCount()); } void checkInitialAndCleanedUpState() @@ -81,10 +81,10 @@ private Q_SLOTS: // GIVEN Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(clip); animator.setRunning(true); - animator.setLoops(25); + animator.setLoopCount(25); // WHEN simulateInitialization(&animator, &backendAnimator); @@ -116,7 +116,7 @@ private Q_SLOTS: QCOMPARE(backendAnimator.isEnabled(), true); // WHEN - auto newClip = new Qt3DAnimation::QAnimationClip(); + auto newClip = new Qt3DAnimation::QAnimationClipLoader(); updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); updateChange->setPropertyName("clip"); updateChange->setValue(QVariant::fromValue(newClip->id())); diff --git a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp index c045c2112..b64e263bf 100644 --- a/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp +++ b/tests/auto/animation/clipblendnode/tst_clipblendnode.cpp @@ -28,8 +28,8 @@ #include <QtTest/QTest> -#include <Qt3DAnimation/qlerpblend.h> -#include <Qt3DAnimation/qanimationclip.h> +#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> @@ -39,21 +39,73 @@ #include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> #include "qbackendnodetester.h" +#include <random> +#include <algorithm> + +using namespace Qt3DAnimation::Animation; + namespace { -class TestClipBlendNode : public Qt3DAnimation::Animation::ClipBlendNode +class TestClipBlendNode : public ClipBlendNode { public: - TestClipBlendNode() - : Qt3DAnimation::Animation::ClipBlendNode(Qt3DAnimation::Animation::ClipBlendNode::LerpBlendType) + TestClipBlendNode(const ClipResults &clipResults = ClipResults()) + : ClipBlendNode(ClipBlendNode::LerpBlendType) + , m_clipResults(clipResults) {} + + inline QVector<Qt3DCore::QNodeId> allDependencyIds() const Q_DECL_OVERRIDE + { + return currentDependencyIds(); + } + + QVector<Qt3DCore::QNodeId> currentDependencyIds() const Q_DECL_FINAL + { + return QVector<Qt3DCore::QNodeId>(); + } + + using ClipBlendNode::setClipResults; + + double duration() const Q_DECL_FINAL { return 0.0f; } + +protected: + ClipResults doBlend(const QVector<ClipResults> &) const Q_DECL_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: @@ -65,25 +117,22 @@ private Q_SLOTS: // THEN QCOMPARE(backendClipBlendNode.isEnabled(), false); QVERIFY(backendClipBlendNode.peerId().isNull()); - QCOMPARE(backendClipBlendNode.clipIds(), Qt3DCore::QNodeIdVector()); - QCOMPARE(backendClipBlendNode.parentId(), Qt3DCore::QNodeId()); - QCOMPARE(backendClipBlendNode.childrenIds(), Qt3DCore::QNodeIdVector()); QVERIFY(backendClipBlendNode.clipBlendNodeManager() == nullptr); - QCOMPARE(backendClipBlendNode.blendType(), Qt3DAnimation::Animation::ClipBlendNode::LerpBlendType); + QCOMPARE(backendClipBlendNode.blendType(), ClipBlendNode::LerpBlendType); + QCOMPARE(backendClipBlendNode.clipResults(Qt3DCore::QNodeId()), ClipResults()); } void checkInitializeFromPeer() { // GIVEN - Qt3DAnimation::QLerpBlend clipBlendNode; - Qt3DAnimation::QAnimationClip clip; - clipBlendNode.addClip(&clip); + Qt3DAnimation::QLerpClipBlend clipBlendNode; + Qt3DAnimation::QAnimationClipLoader clip; QCoreApplication::processEvents(); { // WHEN - Qt3DAnimation::Animation::ClipBlendNodeManager manager; + ClipBlendNodeManager manager; TestClipBlendNode backendClipBlendNode; backendClipBlendNode.setClipBlendNodeManager(&manager); simulateInitialization(&clipBlendNode, &backendClipBlendNode); @@ -91,16 +140,13 @@ private Q_SLOTS: // THEN QCOMPARE(backendClipBlendNode.isEnabled(), true); QCOMPARE(backendClipBlendNode.peerId(), clipBlendNode.id()); - QCOMPARE(backendClipBlendNode.clipIds().size(), 1); - QCOMPARE(backendClipBlendNode.clipIds().first(), clip.id()); - QCOMPARE(backendClipBlendNode.parentId(), Qt3DCore::QNodeId()); - QCOMPARE(backendClipBlendNode.childrenIds().size(), 0); QCOMPARE(backendClipBlendNode.clipBlendNodeManager(), &manager); - QCOMPARE(backendClipBlendNode.blendType(), Qt3DAnimation::Animation::ClipBlendNode::LerpBlendType); + QCOMPARE(backendClipBlendNode.blendType(), ClipBlendNode::LerpBlendType); + QCOMPARE(backendClipBlendNode.clipResults(Qt3DCore::QNodeId()), ClipResults()); } { // WHEN - Qt3DAnimation::Animation::ClipBlendNodeManager manager; + ClipBlendNodeManager manager; TestClipBlendNode backendClipBlendNode; clipBlendNode.setEnabled(false); backendClipBlendNode.setClipBlendNodeManager(&manager); @@ -112,112 +158,152 @@ private Q_SLOTS: } } - void checkSceneChangeEvents() + void checkClipResults_data() { - // GIVEN - TestClipBlendNode backendClipBlendNode; - Qt3DAnimation::Animation::ClipBlendNodeManager manager; - backendClipBlendNode.setClipBlendNodeManager(&manager); + QTest::addColumn<TestClipBlendNode *>("blendNode"); + QTest::addColumn<QVector<int>>("indexes"); + QTest::addColumn<QVector<Qt3DCore::QNodeId>>("animatorIds"); + QTest::addColumn<QVector<ClipResults>>("expectedClipResults"); + + // Single entry { - // WHEN - const bool newValue = false; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("enabled"); - change->setValue(newValue); - backendClipBlendNode.sceneChangeEvent(change); + auto blendNode = new TestClipBlendNode; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<ClipResults> expectedClipResults; - // THEN - QCOMPARE(backendClipBlendNode.isEnabled(), newValue); + 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); + QVector<int> indexes = QVector<int>() << 0; + + QTest::newRow("single entry") + << blendNode << indexes << animatorIds << expectedClipResults; } + + // No data { - // WHEN - Qt3DAnimation::QAnimationClip clip; - // To geneate the type_info in the QNodePrivate of clip - Qt3DCore::QNodeCreatedChangeGenerator generator(&clip); + auto blendNode = new TestClipBlendNode; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<ClipResults> expectedClipResults; - const auto addedChange = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &clip); - backendClipBlendNode.sceneChangeEvent(addedChange); + auto animatorId = Qt3DCore::QNodeId::createId(); + animatorIds.push_back(animatorId); - // THEN - QCOMPARE(backendClipBlendNode.clipIds().size(), 1); - QCOMPARE(backendClipBlendNode.clipIds().first(), clip.id()); + ClipResults clipResults; + expectedClipResults.push_back(clipResults); - // WHEN - const auto removedChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &clip); - backendClipBlendNode.sceneChangeEvent(removedChange); + // Don't set any data + QVector<int> indexes = QVector<int>() << 0; - // THEN - QCOMPARE(backendClipBlendNode.clipIds().size(), 0); + QTest::newRow("no entries") + << blendNode << indexes << animatorIds << expectedClipResults; } + + // Multiple entries, ordered { - // WHEN - Qt3DAnimation::QLerpBlend clipBlendChild; - // Will be destroyed when manager is destroyed - TestClipBlendNode *backenChildClipBlendNode = new TestClipBlendNode(); - backendClipBlendNode.setClipBlendNodeManager(&manager); - manager.appendNode(clipBlendChild.id(), backenChildClipBlendNode); + auto blendNode = new TestClipBlendNode; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<ClipResults> expectedClipResults; - // To geneate the type_info in the QNodePrivate of clipBlendChild - Qt3DCore::QNodeCreatedChangeGenerator generator(&clipBlendChild); - const auto addChange = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &clipBlendChild); - backendClipBlendNode.sceneChangeEvent(addChange); + const int animatorCount = 10; + for (int j = 0; j < animatorCount; ++j) { + auto animatorId = Qt3DCore::QNodeId::createId(); + animatorIds.push_back(animatorId); - // THEN - QCOMPARE(backendClipBlendNode.childrenIds().size(), 1); - QCOMPARE(backendClipBlendNode.childrenIds().first(), clipBlendChild.id()); + ClipResults clipResults; + for (int i = 0; i < j + 5; ++i) + clipResults.push_back(float(i + j)); + expectedClipResults.push_back(clipResults); - // WHEN - const auto removedChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &clipBlendChild); - backendClipBlendNode.sceneChangeEvent(removedChange); + blendNode->setClipResults(animatorId, clipResults); + } - // THEN - QCOMPARE(backendClipBlendNode.childrenIds().size(), 0); + 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; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<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 checkParentInitialization() + void checkClipResults() { // GIVEN - TestClipBlendNode *backendClipBlendNode = new TestClipBlendNode(); - TestClipBlendNode *backendChildClipBlendNode = new TestClipBlendNode(); - Qt3DAnimation::QLerpBlend clipBlendParent; - Qt3DAnimation::QLerpBlend childClipBlend(&clipBlendParent); - Qt3DAnimation::Animation::ClipBlendNodeManager manager; - backendClipBlendNode->setClipBlendNodeManager(&manager); - backendChildClipBlendNode->setClipBlendNodeManager(&manager); + QFETCH(TestClipBlendNode *, blendNode); + QFETCH(QVector<int>, indexes); + QFETCH(QVector<Qt3DCore::QNodeId>, animatorIds); + QFETCH(QVector<ClipResults>, expectedClipResults); - // THEN - QCOMPARE(backendClipBlendNode->parentId(), Qt3DCore::QNodeId()); - QCOMPARE(backendClipBlendNode->childrenIds().size(), 0); - QCOMPARE(backendChildClipBlendNode->parentId(), Qt3DCore::QNodeId()); - QCOMPARE(backendChildClipBlendNode->childrenIds().size(), 0); + for (int i = 0; i < indexes.size(); ++i) { + // WHEN + const int index = indexes[i]; + const ClipResults actualClipResults = blendNode->clipResults(animatorIds[index]); - // WHEN - manager.appendNode(clipBlendParent.id(), backendClipBlendNode); - manager.appendNode(childClipBlend.id(), backendChildClipBlendNode); - simulateInitialization(&clipBlendParent, backendClipBlendNode); - simulateInitialization(&childClipBlend, backendChildClipBlendNode); + // THEN + QCOMPARE(actualClipResults.size(), expectedClipResults[index].size()); + for (int j = 0; j < actualClipResults.size(); ++j) + QCOMPARE(actualClipResults[j], expectedClipResults[index][j]); + } - // THEN - QCOMPARE(backendClipBlendNode->parentId(), Qt3DCore::QNodeId()); - QCOMPARE(backendClipBlendNode->childrenIds().size(), 1); - QCOMPARE(backendClipBlendNode->childrenIds().first(), childClipBlend.id()); - QCOMPARE(backendChildClipBlendNode->parentId(), clipBlendParent.id()); - QCOMPARE(backendChildClipBlendNode->childrenIds().size(), 0); + 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 - // To geneate the type_info in the QNodePrivate of clipBlendChild - Qt3DCore::QNodeCreatedChangeGenerator generator(&childClipBlend); - const auto removedChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &childClipBlend); - backendClipBlendNode->sceneChangeEvent(removedChange); + blendNode->blend(animator->peerId()); // THEN - QCOMPARE(backendClipBlendNode->parentId(), Qt3DCore::QNodeId()); - QCOMPARE(backendClipBlendNode->childrenIds().size(), 0); - QCOMPARE(backendChildClipBlendNode->parentId(), Qt3DCore::QNodeId()); - QCOMPARE(backendChildClipBlendNode->childrenIds().size(), 0); + 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) diff --git a/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp b/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp index 2cf549f7e..7bcef28ae 100644 --- a/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp +++ b/tests/auto/animation/clipblendnodemanager/tst_clipblendnodemanager.cpp @@ -48,6 +48,24 @@ public: { deadCount += 1; } + + inline QVector<Qt3DCore::QNodeId> allDependencyIds() const Q_DECL_OVERRIDE + { + return currentDependencyIds(); + } + + QVector<Qt3DCore::QNodeId> currentDependencyIds() const Q_DECL_FINAL + { + return QVector<Qt3DCore::QNodeId>(); + } + + double duration() const Q_DECL_FINAL { return 0.0f; } + +protected: + Qt3DAnimation::Animation::ClipResults doBlend(const QVector<Qt3DAnimation::Animation::ClipResults> &) const Q_DECL_FINAL + { + return Qt3DAnimation::Animation::ClipResults(); + } }; } // anonymous diff --git a/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp b/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp index 6c6723920..3f705e713 100644 --- a/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp +++ b/tests/auto/animation/clipblendnodevisitor/tst_clipblendnodevisitor.cpp @@ -31,8 +31,8 @@ #include <QSignalSpy> #include <Qt3DAnimation/private/managers_p.h> #include <Qt3DAnimation/private/clipblendnodevisitor_p.h> -#include <Qt3DAnimation/private/lerpblend_p.h> -#include <Qt3DAnimation/qlerpblend.h> +#include <Qt3DAnimation/private/lerpclipblend_p.h> +#include <Qt3DAnimation/qlerpclipblend.h> #include "qbackendnodetester.h" class tst_ClipBlendNodeVisitor : public Qt3DCore::QBackendNodeTester @@ -43,17 +43,21 @@ private Q_SLOTS: void checkVisitAllNodes() { // GIVEN - Qt3DAnimation::QLerpBlend rootBlendNode; - Qt3DAnimation::QLerpBlend childBlendNode1(&rootBlendNode); - Qt3DAnimation::QLerpBlend childBlendNode2(&rootBlendNode); - Qt3DAnimation::QLerpBlend childBlendNode11(&childBlendNode1); - Qt3DAnimation::QLerpBlend childBlendNode12(&childBlendNode1); - - Qt3DAnimation::Animation::LerpBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode11 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode12 = new Qt3DAnimation::Animation::LerpBlend(); + Qt3DAnimation::QLerpClipBlend rootBlendNode; + Qt3DAnimation::QLerpClipBlend childBlendNode1(&rootBlendNode); + Qt3DAnimation::QLerpClipBlend childBlendNode2(&rootBlendNode); + rootBlendNode.setStartClip(&childBlendNode1); + rootBlendNode.setEndClip(&childBlendNode2); + Qt3DAnimation::QLerpClipBlend childBlendNode11(&childBlendNode1); + Qt3DAnimation::QLerpClipBlend childBlendNode12(&childBlendNode1); + childBlendNode1.setStartClip(&childBlendNode11); + childBlendNode1.setEndClip(&childBlendNode12); + + Qt3DAnimation::Animation::LerpClipBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode11 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode12 = new Qt3DAnimation::Animation::LerpClipBlend(); Qt3DAnimation::Animation::ClipBlendNodeManager manager; backendRootBlendNode->setClipBlendNodeManager(&manager); @@ -76,30 +80,26 @@ private Q_SLOTS: simulateInitialization(&childBlendNode12, backendChildBlendNode12); // THEN - QVERIFY(backendRootBlendNode->parentId().isNull()); - QCOMPARE(backendRootBlendNode->childrenIds().size(), 2); - QCOMPARE(backendChildBlendNode1->parentId(), rootBlendNode.id()); - QCOMPARE(backendChildBlendNode1->childrenIds().size(), 2); - QCOMPARE(backendChildBlendNode2->parentId(), rootBlendNode.id()); - QCOMPARE(backendChildBlendNode2->childrenIds().size(), 0); - QCOMPARE(backendChildBlendNode11->parentId(), childBlendNode1.id()); - QCOMPARE(backendChildBlendNode11->childrenIds().size(), 0); - QCOMPARE(backendChildBlendNode12->parentId(), childBlendNode1.id()); - QCOMPARE(backendChildBlendNode12->childrenIds().size(), 0); + QCOMPARE(backendRootBlendNode->allDependencyIds().size(), 2); + QCOMPARE(backendChildBlendNode1->allDependencyIds().size(), 2); + QCOMPARE(backendChildBlendNode2->allDependencyIds().size(), 2); + QCOMPARE(backendChildBlendNode11->allDependencyIds().size(), 2); + QCOMPARE(backendChildBlendNode12->allDependencyIds().size(), 2); // WHEN int i = 0; + // Note: post-order traversal auto childCounter = [&] (Qt3DAnimation::Animation::ClipBlendNode *node) { if (i == 0) - QCOMPARE(node, backendRootBlendNode); + QCOMPARE(node, backendChildBlendNode11); else if (i == 1) - QCOMPARE(node, backendChildBlendNode1); + QCOMPARE(node, backendChildBlendNode12); else if (i == 2) - QCOMPARE(node, backendChildBlendNode11); + QCOMPARE(node, backendChildBlendNode1); else if (i == 3) - QCOMPARE(node, backendChildBlendNode12); - else if (i == 4) QCOMPARE(node, backendChildBlendNode2); + else if (i == 4) + QCOMPARE(node, backendRootBlendNode); ++i; }; @@ -111,9 +111,9 @@ private Q_SLOTS: void checkDoesntCrashIfRootNodeIsNotFound() { // GIVEN - Qt3DAnimation::QLerpBlend rootBlendNode; + Qt3DAnimation::QLerpClipBlend rootBlendNode; - Qt3DAnimation::Animation::LerpBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpClipBlend(); Qt3DAnimation::Animation::ClipBlendNodeManager manager; backendRootBlendNode->setClipBlendNodeManager(&manager); @@ -124,8 +124,7 @@ private Q_SLOTS: simulateInitialization(&rootBlendNode, backendRootBlendNode); // THEN - QVERIFY(backendRootBlendNode->parentId().isNull()); - QCOMPARE(backendRootBlendNode->childrenIds().size(), 0); + QCOMPARE(backendRootBlendNode->allDependencyIds().size(), 2); // WHEN auto childCounter = [] (Qt3DAnimation::Animation::ClipBlendNode *) {}; @@ -138,13 +137,15 @@ private Q_SLOTS: void checkDoesntCrashIfChildNodeIsNotFound() { // GIVEN - Qt3DAnimation::QLerpBlend rootBlendNode; - Qt3DAnimation::QLerpBlend childBlendNode1(&rootBlendNode); - Qt3DAnimation::QLerpBlend childBlendNode2(&rootBlendNode); + Qt3DAnimation::QLerpClipBlend rootBlendNode; + Qt3DAnimation::QLerpClipBlend childBlendNode1(&rootBlendNode); + Qt3DAnimation::QLerpClipBlend childBlendNode2(&rootBlendNode); + rootBlendNode.setStartClip(&childBlendNode1); + rootBlendNode.setEndClip(&childBlendNode2); - Qt3DAnimation::Animation::LerpBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpBlend(); - Qt3DAnimation::Animation::LerpBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendRootBlendNode = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode1 = new Qt3DAnimation::Animation::LerpClipBlend(); + Qt3DAnimation::Animation::LerpClipBlend *backendChildBlendNode2 = new Qt3DAnimation::Animation::LerpClipBlend(); Qt3DAnimation::Animation::ClipBlendNodeManager manager; backendRootBlendNode->setClipBlendNodeManager(&manager); @@ -163,12 +164,9 @@ private Q_SLOTS: simulateInitialization(&childBlendNode2, backendChildBlendNode2); // THEN - QVERIFY(backendRootBlendNode->parentId().isNull()); - QCOMPARE(backendRootBlendNode->childrenIds().size(), 2); - QCOMPARE(backendChildBlendNode1->parentId(), rootBlendNode.id()); - QCOMPARE(backendChildBlendNode1->childrenIds().size(), 0); - QCOMPARE(backendChildBlendNode2->parentId(), rootBlendNode.id()); - QCOMPARE(backendChildBlendNode2->childrenIds().size(), 0); + QCOMPARE(backendRootBlendNode->allDependencyIds().size(), 2); + QCOMPARE(backendChildBlendNode1->allDependencyIds().size(), 2); + QCOMPARE(backendChildBlendNode2->allDependencyIds().size(), 2); // WHEN int i = 0; diff --git a/tests/auto/animation/lerpblend/lerpblend.pro b/tests/auto/animation/clipblendvalue/clipblendvalue.pro index bc2cc383b..ff50f0bbd 100644 --- a/tests/auto/animation/lerpblend/lerpblend.pro +++ b/tests/auto/animation/clipblendvalue/clipblendvalue.pro @@ -1,11 +1,12 @@ TEMPLATE = app -TARGET = tst_lerpblend +TARGET = tst_clipblendvalue QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib CONFIG += testcase -SOURCES += tst_lerpblend.cpp +SOURCES += \ + tst_clipblendvalue.cpp include(../../core/common/common.pri) diff --git a/tests/auto/animation/clipblendvalue/tst_clipblendvalue.cpp b/tests/auto/animation/clipblendvalue/tst_clipblendvalue.cpp new file mode 100644 index 000000000..6fe2846b8 --- /dev/null +++ b/tests/auto/animation/clipblendvalue/tst_clipblendvalue.cpp @@ -0,0 +1,299 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QTest> +#include <Qt3DAnimation/qclipblendvalue.h> +#include <Qt3DAnimation/qanimationcliploader.h> +#include <Qt3DAnimation/private/qclipblendvalue_p.h> +#include <Qt3DAnimation/private/clipblendvalue_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include "qbackendnodetester.h" + +#include <random> +#include <algorithm> + +using namespace Qt3DAnimation::Animation; + +Q_DECLARE_METATYPE(ClipBlendValue *) + +class tst_ClipBlendValue : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT +public: + AnimationClip *createAnimationClipLoader(Handler *handler, + double duration) + { + auto clipId = Qt3DCore::QNodeId::createId(); + AnimationClip *clip = handler->animationClipLoaderManager()->getOrCreateResource(clipId); + setPeerId(clip, clipId); + clip->setDuration(duration); + return clip; + } + +private Q_SLOTS: + void checkInitialState() + { + // GIVEN + ClipBlendValue backendClipBlendValue; + + // THEN + QCOMPARE(backendClipBlendValue.isEnabled(), false); + QVERIFY(backendClipBlendValue.peerId().isNull()); + QCOMPARE(backendClipBlendValue.clipId(), Qt3DCore::QNodeId()); + QCOMPARE(backendClipBlendValue.blendType(), ClipBlendNode::ValueType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendValue; + Qt3DAnimation::QAnimationClipLoader clip; + clipBlendValue.setClip(&clip); + + { + // WHEN + ClipBlendValue backendClipBlendValue; + simulateInitialization(&clipBlendValue, &backendClipBlendValue); + + // THEN + QCOMPARE(backendClipBlendValue.isEnabled(), true); + QCOMPARE(backendClipBlendValue.peerId(), clipBlendValue.id()); + QCOMPARE(backendClipBlendValue.clipId(), clip.id()); + } + { + // WHEN + ClipBlendValue backendClipBlendValue; + clipBlendValue.setEnabled(false); + simulateInitialization(&clipBlendValue, &backendClipBlendValue); + + // THEN + QCOMPARE(backendClipBlendValue.peerId(), clipBlendValue.id()); + QCOMPARE(backendClipBlendValue.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + ClipBlendValue backendClipBlendValue; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendClipBlendValue.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendClipBlendValue.isEnabled(), newValue); + } + { + // WHEN + const Qt3DAnimation::QAnimationClipLoader newValue; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("clip"); + change->setValue(QVariant::fromValue(newValue.id())); + backendClipBlendValue.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendClipBlendValue.clipId(), newValue.id()); + } + } + + void checkDependencyIds() + { + // GIVEN + ClipBlendValue clipNode; + auto clipId = Qt3DCore::QNodeId::createId(); + + // WHEN + clipNode.setClipId(clipId); + QVector<Qt3DCore::QNodeId> actualIds = clipNode.currentDependencyIds(); + + // THEN + QCOMPARE(actualIds.size(), 1); + QCOMPARE(actualIds[0], clipId); + + // WHEN + auto anotherClipId = Qt3DCore::QNodeId::createId(); + clipNode.setClipId(anotherClipId); + actualIds = clipNode.currentDependencyIds(); + + // THEN + QCOMPARE(actualIds.size(), 1); + QCOMPARE(actualIds[0], anotherClipId); + } + + void checkDuration() + { + // GIVEN + auto handler = new Handler(); + const double expectedDuration = 123.5; + auto clip = createAnimationClipLoader(handler, expectedDuration); + ClipBlendValue clipNode; + clipNode.setHandler(handler); + clipNode.setClipBlendNodeManager(handler->clipBlendNodeManager()); + clipNode.setClipId(clip->peerId()); + + // WHEN + double actualDuration = clipNode.duration(); + + // THEN + QCOMPARE(actualDuration, expectedDuration); + } + + void checkFormatIndices_data() + { + QTest::addColumn<ClipBlendValue *>("blendNode"); + QTest::addColumn<QVector<int>>("indexes"); + QTest::addColumn<QVector<Qt3DCore::QNodeId>>("animatorIds"); + QTest::addColumn<QVector<ComponentIndices>>("expectedFormatIndices"); + + // Single entry + { + auto blendNode = new ClipBlendValue; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<ComponentIndices> expectedFormatIndices; + + const auto animatorId = Qt3DCore::QNodeId::createId(); + animatorIds.push_back(animatorId); + + ComponentIndices formatIndices = { 0, 1, 2 }; + expectedFormatIndices.push_back(formatIndices); + + // Set data and indexes + blendNode->setFormatIndices(animatorId, formatIndices); + QVector<int> indexes = QVector<int>() << 0; + + QTest::newRow("single entry") + << blendNode << indexes << animatorIds << expectedFormatIndices; + } + + // No data + { + auto blendNode = new ClipBlendValue; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<ComponentIndices> expectedFormatIndices; + + auto animatorId = Qt3DCore::QNodeId::createId(); + animatorIds.push_back(animatorId); + + ComponentIndices formatIndices; + expectedFormatIndices.push_back(formatIndices); + + // Don't set any data + QVector<int> indexes = QVector<int>() << 0; + + QTest::newRow("no entries") + << blendNode << indexes << animatorIds << expectedFormatIndices; + } + + // Multiple entries, ordered + { + auto blendNode = new ClipBlendValue; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<ComponentIndices> expectedFormatIndices; + + const int animatorCount = 10; + for (int j = 0; j < animatorCount; ++j) { + auto animatorId = Qt3DCore::QNodeId::createId(); + animatorIds.push_back(animatorId); + + ComponentIndices formatIndices; + for (int i = 0; i < j + 5; ++i) + formatIndices.push_back(i + j); + expectedFormatIndices.push_back(formatIndices); + + blendNode->setFormatIndices(animatorId, formatIndices); + } + + QVector<int> indexes(animatorCount); + std::iota(indexes.begin(), indexes.end(), 0); + + QTest::newRow("multiple entries, ordered") + << blendNode << indexes << animatorIds << expectedFormatIndices; + } + + // Multiple entries, unordered + { + auto blendNode = new ClipBlendValue; + QVector<Qt3DCore::QNodeId> animatorIds; + QVector<ComponentIndices> expectedFormatIndices; + + const int animatorCount = 10; + for (int j = 0; j < animatorCount; ++j) { + auto animatorId = Qt3DCore::QNodeId::createId(); + animatorIds.push_back(animatorId); + + ComponentIndices formatIndices; + for (int i = 0; i < j + 5; ++i) + formatIndices.push_back(i + j); + expectedFormatIndices.push_back(formatIndices); + + blendNode->setFormatIndices(animatorId, formatIndices); + } + + // 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 << expectedFormatIndices; + } + } + + void checkFormatIndices() + { + // GIVEN + QFETCH(ClipBlendValue *, blendNode); + QFETCH(QVector<int>, indexes); + QFETCH(QVector<Qt3DCore::QNodeId>, animatorIds); + QFETCH(QVector<ComponentIndices>, expectedFormatIndices); + + for (int i = 0; i < indexes.size(); ++i) { + // WHEN + const int index = indexes[i]; + const ComponentIndices actualFormatIndices = blendNode->formatIndices(animatorIds[index]); + + // THEN + QCOMPARE(actualFormatIndices.size(), expectedFormatIndices[index].size()); + for (int j = 0; j < actualFormatIndices.size(); ++j) + QCOMPARE(actualFormatIndices[j], expectedFormatIndices[index][j]); + } + + delete blendNode; + } +}; + +QTEST_MAIN(tst_ClipBlendValue) + +#include "tst_clipblendvalue.moc" diff --git a/tests/auto/animation/conductedclipanimator/conductedclipanimator.pro b/tests/auto/animation/conductedclipanimator/conductedclipanimator.pro deleted file mode 100644 index 61a1106d9..000000000 --- a/tests/auto/animation/conductedclipanimator/conductedclipanimator.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = app - -TARGET = tst_conductedclipanimator - -QT += core-private 3dcore 3dcore-private 3danimation 3danimation-private testlib - -CONFIG += testcase - -SOURCES += \ - tst_conductedclipanimator.cpp - -include(../../core/common/common.pri) diff --git a/tests/auto/animation/conductedclipanimator/tst_conductedclipanimator.cpp b/tests/auto/animation/conductedclipanimator/tst_conductedclipanimator.cpp deleted file mode 100644 index 8536ab7e7..000000000 --- a/tests/auto/animation/conductedclipanimator/tst_conductedclipanimator.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtTest/QTest> -#include <Qt3DAnimation/private/conductedclipanimator_p.h> -#include <Qt3DAnimation/qanimationclip.h> -#include <Qt3DAnimation/qconductedclipanimator.h> -#include <Qt3DCore/private/qnode_p.h> -#include <Qt3DCore/private/qscene_p.h> -#include <Qt3DCore/qpropertyupdatedchange.h> -#include <Qt3DCore/private/qbackendnode_p.h> -#include <qbackendnodetester.h> -#include <testpostmanarbiter.h> - -class tst_ConductedClipAnimator: public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - void checkPeerPropertyMirroring() - { - // GIVEN - Qt3DAnimation::Animation::ConductedClipAnimator backendAnimator; - Qt3DAnimation::QConductedClipAnimator animator; - - // WHEN - simulateInitialization(&animator, &backendAnimator); - - // THEN - QCOMPARE(backendAnimator.peerId(), animator.id()); - QCOMPARE(backendAnimator.isEnabled(), animator.isEnabled()); - } - - void checkInitialAndCleanedUpState() - { - // GIVEN - Qt3DAnimation::Animation::ConductedClipAnimator backendAnimator; - - // THEN - QVERIFY(backendAnimator.peerId().isNull()); - QCOMPARE(backendAnimator.isEnabled(), false); - - // GIVEN - Qt3DAnimation::QConductedClipAnimator animator; - - // WHEN - simulateInitialization(&animator, &backendAnimator); - backendAnimator.cleanup(); - - // THEN - QCOMPARE(backendAnimator.isEnabled(), false); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::Animation::ConductedClipAnimator backendAnimator; - Qt3DCore::QPropertyUpdatedChangePtr updateChange; - - // WHEN - updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); - updateChange->setPropertyName("enabled"); - updateChange->setValue(true); - backendAnimator.sceneChangeEvent(updateChange); - - // THEN - QCOMPARE(backendAnimator.isEnabled(), true); - } -}; - -QTEST_APPLESS_MAIN(tst_ConductedClipAnimator) - -#include "tst_conductedclipanimator.moc" diff --git a/tests/auto/animation/fcurve/tst_fcurve.cpp b/tests/auto/animation/fcurve/tst_fcurve.cpp index 8cd8b9537..e3e8db50d 100644 --- a/tests/auto/animation/fcurve/tst_fcurve.cpp +++ b/tests/auto/animation/fcurve/tst_fcurve.cpp @@ -29,6 +29,7 @@ #include <QtTest/QTest> #include <private/fcurve_p.h> +using namespace Qt3DAnimation; using namespace Qt3DAnimation::Animation; class tst_FCurve : public QObject @@ -53,7 +54,7 @@ private Q_SLOTS: FCurve fcurve; // WHEN - const Keyframe kf0{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, Keyframe::Bezier}; + const Keyframe kf0{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, QKeyFrame::BezierInterpolation}; fcurve.appendKeyframe(0.0f, kf0); // THEN @@ -62,7 +63,7 @@ private Q_SLOTS: QCOMPARE(fcurve.endTime(), 0.0f); // WHEN - const Keyframe kf1{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, Keyframe::Bezier}; + const Keyframe kf1{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, QKeyFrame::BezierInterpolation}; fcurve.appendKeyframe(50.0f, kf1); // THEN @@ -77,8 +78,8 @@ private Q_SLOTS: { // GIVEN FCurve fcurve; - fcurve.appendKeyframe(0.0f, Keyframe{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, Keyframe::Bezier}); - fcurve.appendKeyframe(50.0f, Keyframe{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, Keyframe::Bezier}); + fcurve.appendKeyframe(0.0f, Keyframe{0.0f, {-5.0f, 0.0f}, {5.0f, 0.0f}, QKeyFrame::BezierInterpolation}); + fcurve.appendKeyframe(50.0f, Keyframe{5.0f, {45.0f, 5.0f}, {55.0f, 5.0f}, QKeyFrame::BezierInterpolation}); // WHEN fcurve.clearKeyframes(); diff --git a/tests/auto/animation/lerpblend/tst_lerpblend.cpp b/tests/auto/animation/lerpblend/tst_lerpblend.cpp deleted file mode 100644 index 9d758e7c4..000000000 --- a/tests/auto/animation/lerpblend/tst_lerpblend.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <QtTest/QTest> -#include <Qt3DAnimation/qlerpblend.h> -#include <Qt3DAnimation/qanimationclip.h> -#include <Qt3DAnimation/private/qlerpblend_p.h> -#include <Qt3DAnimation/private/lerpblend_p.h> -#include <Qt3DCore/qpropertyupdatedchange.h> -#include "qbackendnodetester.h" - -class tst_LerpBlend : public Qt3DCore::QBackendNodeTester -{ - Q_OBJECT - -private Q_SLOTS: - - void checkInitialState() - { - // GIVEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - - // THEN - QCOMPARE(backendLerpBlend.isEnabled(), false); - QVERIFY(backendLerpBlend.peerId().isNull()); - QCOMPARE(backendLerpBlend.blendFactor(), 0.0f); - } - - void checkInitializeFromPeer() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - Qt3DAnimation::QAnimationClip clip; - lerpBlend.setBlendFactor(0.8f); - lerpBlend.addClip(&clip); - - { - // WHEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - simulateInitialization(&lerpBlend, &backendLerpBlend); - - // THEN - QCOMPARE(backendLerpBlend.isEnabled(), true); - QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); - QCOMPARE(backendLerpBlend.blendFactor(), 0.8f); - QCOMPARE(backendLerpBlend.clipIds().size(), 1); - QCOMPARE(backendLerpBlend.clipIds().first(), clip.id()); - } - { - // WHEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - lerpBlend.setEnabled(false); - simulateInitialization(&lerpBlend, &backendLerpBlend); - - // THEN - QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); - QCOMPARE(backendLerpBlend.isEnabled(), false); - } - } - - void checkSceneChangeEvents() - { - // GIVEN - Qt3DAnimation::Animation::LerpBlend backendLerpBlend; - { - // WHEN - const bool newValue = false; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("enabled"); - change->setValue(newValue); - backendLerpBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendLerpBlend.isEnabled(), newValue); - } - { - // WHEN - const float newValue = 0.883f; - const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); - change->setPropertyName("blendFactor"); - change->setValue(QVariant::fromValue(newValue)); - backendLerpBlend.sceneChangeEvent(change); - - // THEN - QCOMPARE(backendLerpBlend.blendFactor(), newValue); - } - } - -}; - -QTEST_MAIN(tst_LerpBlend) - -#include "tst_lerpblend.moc" diff --git a/tests/auto/animation/qlerpblend/qlerpblend.pro b/tests/auto/animation/lerpclipblend/lerpclipblend.pro index f5bdc848f..e5447cccf 100644 --- a/tests/auto/animation/qlerpblend/qlerpblend.pro +++ b/tests/auto/animation/lerpclipblend/lerpclipblend.pro @@ -1,11 +1,11 @@ TEMPLATE = app -TARGET = tst_qlerpblend +TARGET = tst_lerpclipblend QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib CONFIG += testcase -SOURCES += tst_qlerpblend.cpp +SOURCES += tst_lerpclipblend.cpp include(../../core/common/common.pri) diff --git a/tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp b/tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp new file mode 100644 index 000000000..003b1ef53 --- /dev/null +++ b/tests/auto/animation/lerpclipblend/tst_lerpclipblend.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QTest> +#include <Qt3DAnimation/qlerpclipblend.h> +#include <Qt3DAnimation/qanimationcliploader.h> +#include <Qt3DAnimation/private/qlerpclipblend_p.h> +#include <Qt3DAnimation/private/lerpclipblend_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include "qbackendnodetester.h" + +using namespace Qt3DAnimation::Animation; + +Q_DECLARE_METATYPE(Handler *) +Q_DECLARE_METATYPE(LerpClipBlend *) + +namespace { + +class TestClipBlendNode : public ClipBlendNode +{ +public: + TestClipBlendNode(double duration) + : ClipBlendNode(ClipBlendNode::LerpBlendType) + , m_duration(duration) + {} + + inline QVector<Qt3DCore::QNodeId> allDependencyIds() const Q_DECL_OVERRIDE + { + return currentDependencyIds(); + } + + QVector<Qt3DCore::QNodeId> currentDependencyIds() const Q_DECL_FINAL + { + return QVector<Qt3DCore::QNodeId>(); + } + + using ClipBlendNode::setClipResults; + + double duration() const Q_DECL_FINAL { return m_duration; } + +protected: + ClipResults doBlend(const QVector<ClipResults> &) const Q_DECL_FINAL { return ClipResults(); } + +private: + double m_duration; +}; + +} // anonymous + +class tst_LerpClipBlend : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT +public: + TestClipBlendNode *createTestBlendNode(Handler *handler, + double duration) + { + auto id = Qt3DCore::QNodeId::createId(); + TestClipBlendNode *node = new TestClipBlendNode(duration); + setPeerId(node, id); + node->setHandler(handler); + node->setClipBlendNodeManager(handler->clipBlendNodeManager()); + handler->clipBlendNodeManager()->appendNode(id, node); + return node; + } + + LerpClipBlend *createLerpClipBlendNode(Handler *handler, const float &blendFactor) + { + auto id = Qt3DCore::QNodeId::createId(); + LerpClipBlend *node = new LerpClipBlend(); + node->setBlendFactor(blendFactor); + setPeerId(node, id); + node->setHandler(handler); + node->setClipBlendNodeManager(handler->clipBlendNodeManager()); + 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 + LerpClipBlend backendLerpBlend; + + // THEN + QCOMPARE(backendLerpBlend.isEnabled(), false); + QVERIFY(backendLerpBlend.peerId().isNull()); + QCOMPARE(backendLerpBlend.blendFactor(), 0.0f); + QCOMPARE(backendLerpBlend.blendType(), ClipBlendNode::LerpBlendType); + } + + void checkInitializeFromPeer() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + Qt3DAnimation::QAnimationClipLoader clip; + lerpBlend.setBlendFactor(0.8f); + + { + // WHEN + LerpClipBlend backendLerpBlend; + simulateInitialization(&lerpBlend, &backendLerpBlend); + + // THEN + QCOMPARE(backendLerpBlend.isEnabled(), true); + QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); + QCOMPARE(backendLerpBlend.blendFactor(), 0.8f); + } + { + // WHEN + LerpClipBlend backendLerpBlend; + lerpBlend.setEnabled(false); + simulateInitialization(&lerpBlend, &backendLerpBlend); + + // THEN + QCOMPARE(backendLerpBlend.peerId(), lerpBlend.id()); + QCOMPARE(backendLerpBlend.isEnabled(), false); + } + } + + void checkSceneChangeEvents() + { + // GIVEN + LerpClipBlend backendLerpBlend; + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendLerpBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendLerpBlend.isEnabled(), newValue); + } + { + // WHEN + const float newValue = 0.883f; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("blendFactor"); + change->setValue(QVariant::fromValue(newValue)); + backendLerpBlend.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendLerpBlend.blendFactor(), newValue); + } + } + + void checkDependencyIds() + { + // GIVEN + LerpClipBlend lerpBlend; + auto startClipId = Qt3DCore::QNodeId::createId(); + auto endClipId = Qt3DCore::QNodeId::createId(); + + // WHEN + lerpBlend.setStartClipId(startClipId); + lerpBlend.setEndClipId(endClipId); + QVector<Qt3DCore::QNodeId> actualIds = lerpBlend.currentDependencyIds(); + + // THEN + QCOMPARE(actualIds.size(), 2); + QCOMPARE(actualIds[0], startClipId); + QCOMPARE(actualIds[1], endClipId); + + // WHEN + auto anotherEndClipId = Qt3DCore::QNodeId::createId(); + lerpBlend.setEndClipId(anotherEndClipId); + actualIds = lerpBlend.currentDependencyIds(); + + // THEN + QCOMPARE(actualIds.size(), 2); + QCOMPARE(actualIds[0], startClipId); + QCOMPARE(actualIds[1], anotherEndClipId); + } + + void checkDuration() + { + // GIVEN + auto handler = new Handler(); + const double startNodeDuration = 10.0; + const double endNodeDuration = 20.0; + const float blendFactor = 0.25f; + const double expectedDuration = 12.5; + + auto startNode = createTestBlendNode(handler, startNodeDuration); + auto endNode = createTestBlendNode(handler, endNodeDuration); + + LerpClipBlend blendNode; + blendNode.setHandler(handler); + blendNode.setClipBlendNodeManager(handler->clipBlendNodeManager()); + blendNode.setStartClipId(startNode->peerId()); + blendNode.setEndClipId(endNode->peerId()); + blendNode.setBlendFactor(blendFactor); + + // WHEN + double actualDuration = blendNode.duration(); + + // THEN + QCOMPARE(actualDuration, expectedDuration); + } + + void checkDoBlend_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<LerpClipBlend *>("blendNode"); + QTest::addColumn<Qt3DCore::QNodeId>("animatorId"); + QTest::addColumn<ClipResults>("expectedResults"); + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto startNode = createTestBlendNode(handler, duration); + startNode->setClipResults(animator->peerId(), { 0.0f, 0.0f, 0.0f }); + auto endNode = createTestBlendNode(handler, duration); + endNode->setClipResults(animator->peerId(), { 1.0f, 1.0f, 1.0f }); + + const float blendFactor = 0.0f; + auto blendNode = createLerpClipBlendNode(handler, blendFactor); + blendNode->setStartClipId(startNode->peerId()); + blendNode->setEndClipId(endNode->peerId()); + blendNode->setBlendFactor(blendFactor); + + ClipResults expectedResults = { 0.0f, 0.0f, 0.0f }; + + QTest::addRow("unit lerp, beta = 0.0") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto startNode = createTestBlendNode(handler, duration); + startNode->setClipResults(animator->peerId(), { 0.0f, 0.0f, 0.0f }); + auto endNode = createTestBlendNode(handler, duration); + endNode->setClipResults(animator->peerId(), { 1.0f, 1.0f, 1.0f }); + + const float blendFactor = 0.5f; + auto blendNode = createLerpClipBlendNode(handler, blendFactor); + blendNode->setStartClipId(startNode->peerId()); + blendNode->setEndClipId(endNode->peerId()); + blendNode->setBlendFactor(blendFactor); + + ClipResults expectedResults = { 0.5f, 0.5f, 0.5f }; + + QTest::addRow("unit lerp, beta = 0.5") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto startNode = createTestBlendNode(handler, duration); + startNode->setClipResults(animator->peerId(), { 0.0f, 0.0f, 0.0f }); + auto endNode = createTestBlendNode(handler, duration); + endNode->setClipResults(animator->peerId(), { 1.0f, 1.0f, 1.0f }); + + const float blendFactor = 1.0f; + auto blendNode = createLerpClipBlendNode(handler, blendFactor); + blendNode->setStartClipId(startNode->peerId()); + blendNode->setEndClipId(endNode->peerId()); + blendNode->setBlendFactor(blendFactor); + + ClipResults expectedResults = { 1.0f, 1.0f, 1.0f }; + + QTest::addRow("unit lerp, beta = 1.0") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + auto startNode = createTestBlendNode(handler, duration); + startNode->setClipResults(animator->peerId(), { 0.0f, 1.0f, 2.0f }); + auto endNode = createTestBlendNode(handler, duration); + endNode->setClipResults(animator->peerId(), { 1.0f, 2.0f, 3.0f }); + + const float blendFactor = 0.5f; + auto blendNode = createLerpClipBlendNode(handler, blendFactor); + blendNode->setStartClipId(startNode->peerId()); + blendNode->setEndClipId(endNode->peerId()); + blendNode->setBlendFactor(blendFactor); + + ClipResults expectedResults = { 0.5f, 1.5f, 2.5f }; + + QTest::addRow("lerp varying data, beta = 0.5") + << handler << blendNode << animator->peerId() << expectedResults; + } + + { + auto handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loopCount = 1; + auto animator = createBlendedClipAnimator(handler, globalStartTimeNS, loopCount); + + const double duration = 1.0; + const int dataCount = 1000; + ClipResults startData(dataCount); + ClipResults endData(dataCount); + ClipResults expectedResults(dataCount); + for (int i = 0; i < dataCount; ++i) { + startData[i] = float(i); + endData[i] = 2.0f * float(i); + expectedResults[i] = 1.5f * float(i); + } + auto startNode = createTestBlendNode(handler, duration); + startNode->setClipResults(animator->peerId(), startData); + auto endNode = createTestBlendNode(handler, duration); + endNode->setClipResults(animator->peerId(), endData); + + const float blendFactor = 0.5f; + auto blendNode = createLerpClipBlendNode(handler, blendFactor); + blendNode->setStartClipId(startNode->peerId()); + blendNode->setEndClipId(endNode->peerId()); + blendNode->setBlendFactor(blendFactor); + + QTest::addRow("lerp lots of data, beta = 0.5") + << handler << blendNode << animator->peerId() << expectedResults; + } + } + + void checkDoBlend() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(LerpClipBlend *, blendNode); + QFETCH(Qt3DCore::QNodeId, animatorId); + QFETCH(ClipResults, expectedResults); + + // WHEN + blendNode->blend(animatorId); + + // THEN + const ClipResults actualResults = blendNode->clipResults(animatorId); + QCOMPARE(actualResults.size(), expectedResults.size()); + for (int i = 0; i < actualResults.size(); ++i) + QCOMPARE(actualResults[i], expectedResults[i]); + + // Cleanup + delete handler; + } +}; + +QTEST_MAIN(tst_LerpClipBlend) + +#include "tst_lerpclipblend.moc" diff --git a/tests/auto/animation/qabstractanimation/qabstractanimation.pro b/tests/auto/animation/qabstractanimation/qabstractanimation.pro new file mode 100644 index 000000000..be37677b6 --- /dev/null +++ b/tests/auto/animation/qabstractanimation/qabstractanimation.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +TARGET = tst_qabstractanimation + +QT += 3dcore 3dcore-private 3drender 3drender-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += tst_qabstractanimation.cpp + diff --git a/tests/auto/animation/qabstractanimation/tst_qabstractanimation.cpp b/tests/auto/animation/qabstractanimation/tst_qabstractanimation.cpp new file mode 100644 index 000000000..90349fb28 --- /dev/null +++ b/tests/auto/animation/qabstractanimation/tst_qabstractanimation.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <Qt3DAnimation/qabstractanimation.h> +#include <Qt3DCore/qnode.h> +#include <qobject.h> +#include <qsignalspy.h> + +#include <private/qabstractanimation_p.h> + +class TestAnimation : public Qt3DAnimation::QAbstractAnimation +{ +public: + explicit TestAnimation(Qt3DCore::QNode *parent = nullptr) + : Qt3DAnimation::QAbstractAnimation( + *new Qt3DAnimation::QAbstractAnimationPrivate( + Qt3DAnimation::QAbstractAnimation::KeyframeAnimation), parent) + { + + } +}; + +class tst_QAbstractAnimation : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + TestAnimation abstractAnimation; + + // THEN + QCOMPARE(abstractAnimation.animationName(), QString()); + QCOMPARE(abstractAnimation.animationType(), + Qt3DAnimation::QAbstractAnimation::KeyframeAnimation); + QCOMPARE(abstractAnimation.position(), 0.0f); + QCOMPARE(abstractAnimation.duration(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + TestAnimation abstractAnimation; + + { + // WHEN + QSignalSpy spy(&abstractAnimation, SIGNAL(animationNameChanged(QString))); + const QString newValue = QString("test"); + abstractAnimation.setAnimationName(newValue); + + // THEN + QCOMPARE(abstractAnimation.animationName(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + abstractAnimation.setAnimationName(newValue); + + // THEN + QCOMPARE(abstractAnimation.animationName(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&abstractAnimation, SIGNAL(positionChanged(float))); + const float newValue = 1.0f; + abstractAnimation.setPosition(newValue); + + // THEN + QCOMPARE(abstractAnimation.position(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + abstractAnimation.setPosition(newValue); + + // THEN + QCOMPARE(abstractAnimation.position(), newValue); + QCOMPARE(spy.count(), 0); + + } + } + +}; + +QTEST_APPLESS_MAIN(tst_QAbstractAnimation) + +#include "tst_qabstractanimation.moc" diff --git a/tests/auto/animation/qabstractclipblendnode/tst_qabstractclipblendnode.cpp b/tests/auto/animation/qabstractclipblendnode/tst_qabstractclipblendnode.cpp deleted file mode 100644 index e2d963310..000000000 --- a/tests/auto/animation/qabstractclipblendnode/tst_qabstractclipblendnode.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <QtTest/QTest> -#include <Qt3DAnimation/qabstractclipblendnode.h> -#include <Qt3DAnimation/qanimationclip.h> -#include <QObject> -#include <QSignalSpy> -#include <Qt3DCore/qpropertyupdatedchange.h> -#include <Qt3DCore/qpropertynodeaddedchange.h> -#include <Qt3DCore/qpropertynoderemovedchange.h> -#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> -#include <Qt3DCore/qnodecreatedchange.h> -#include "testpostmanarbiter.h" - -namespace { - -class TestClipBlendNode : public Qt3DAnimation::QAbstractClipBlendNode -{ -public: - TestClipBlendNode(Qt3DCore::QNode *parent = nullptr) - : Qt3DAnimation::QAbstractClipBlendNode(parent) - {} - - using Qt3DAnimation::QAbstractClipBlendNode::addClip; - using Qt3DAnimation::QAbstractClipBlendNode::removeClip; -}; - -} - -class tst_QAbstractClipBlendNode : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - - void checkDefaultConstruction() - { - // GIVEN - TestClipBlendNode abstractClipBlendNode; - - // THEN - QCOMPARE(abstractClipBlendNode.clips().size(), 0); - } - - void checkPropertyChanges() - { - // GIVEN - TestClipBlendNode abstractClipBlendNode; - - { - // WHEN - Qt3DAnimation::QAnimationClip newValue; - abstractClipBlendNode.addClip(&newValue); - - // THEN - QCOMPARE(abstractClipBlendNode.clips().size(), 1); - - // WHEN - abstractClipBlendNode.addClip(&newValue); - - // THEN - QCOMPARE(abstractClipBlendNode.clips().size(), 1); - - // WHEN - abstractClipBlendNode.removeClip(&newValue); - - // THEN - QCOMPARE(abstractClipBlendNode.clips().size(), 0); - } - } - - void checkClipBookkeeping() - { - // GIVEN - TestClipBlendNode abstractClipBlendNode; - - { - // WHEN - Qt3DAnimation::QAnimationClip clip; - abstractClipBlendNode.addClip(&clip); - - QCOMPARE(abstractClipBlendNode.clips().size(), 1); - } - - // THEN -> should not crash - QCOMPARE(abstractClipBlendNode.clips().size(), 0); - } - - void checkClipUpdate() - { - // GIVEN - TestArbiter arbiter; - TestClipBlendNode abstractClipBlendNode; - Qt3DAnimation::QAnimationClip clip; - arbiter.setArbiterOnNode(&abstractClipBlendNode); - - { - // WHEN - abstractClipBlendNode.addClip(&clip); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>(); - QCOMPARE(change->propertyName(), "clip"); - QCOMPARE(change->addedNodeId(), clip.id()); - QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded); - - arbiter.events.clear(); - } - - { - // WHEN - abstractClipBlendNode.removeClip(&clip); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>(); - QCOMPARE(change->propertyName(), "clip"); - QCOMPARE(change->removedNodeId(), clip.id()); - QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved); - - arbiter.events.clear(); - } - - } - - void checkParentClipBlendNode() - { - // GIVEN - TestClipBlendNode clipNodeLevel0; - TestClipBlendNode clipNodeLevel1_1(&clipNodeLevel0); - TestClipBlendNode clipNodeLevel1_2(&clipNodeLevel0); - TestClipBlendNode clipNodeLevel2_1(&clipNodeLevel1_1); - Qt3DCore::QNode fakeNodeLevel2_2(&clipNodeLevel1_2); - TestClipBlendNode clipNodeLeve3_1(&fakeNodeLevel2_2); - - // THEN - QVERIFY(clipNodeLevel0.parent() == nullptr); - QCOMPARE(clipNodeLevel1_1.parent(), &clipNodeLevel0); - QCOMPARE(clipNodeLevel1_2.parent(), &clipNodeLevel0); - QCOMPARE(clipNodeLevel2_1.parent(), &clipNodeLevel1_1); - QCOMPARE(fakeNodeLevel2_2.parent(), &clipNodeLevel1_2); - QCOMPARE(clipNodeLeve3_1.parent(), &fakeNodeLevel2_2); - - QVERIFY(clipNodeLevel0.parentClipBlendNode() == nullptr); - QCOMPARE(clipNodeLevel1_1.parentClipBlendNode(), &clipNodeLevel0); - QCOMPARE(clipNodeLevel1_2.parentClipBlendNode(), &clipNodeLevel0); - QCOMPARE(clipNodeLevel2_1.parentClipBlendNode(), &clipNodeLevel1_1); - QCOMPARE(clipNodeLeve3_1.parentClipBlendNode(), &clipNodeLevel1_2); - } -}; - -QTEST_MAIN(tst_QAbstractClipBlendNode) - -#include "tst_qabstractclipblendnode.moc" diff --git a/tests/auto/animation/qadditiveclipblend/qadditiveclipblend.pro b/tests/auto/animation/qadditiveclipblend/qadditiveclipblend.pro new file mode 100644 index 000000000..e5c6797ee --- /dev/null +++ b/tests/auto/animation/qadditiveclipblend/qadditiveclipblend.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qadditiveclipblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qadditiveclipblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp new file mode 100644 index 000000000..c1f01394f --- /dev/null +++ b/tests/auto/animation/qadditiveclipblend/tst_qadditiveclipblend.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QTest> +#include <Qt3DAnimation/qadditiveclipblend.h> +#include <Qt3DAnimation/qanimationcliploader.h> +#include <Qt3DAnimation/private/qadditiveclipblend_p.h> +#include <QObject> +#include <QSignalSpy> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> +#include <Qt3DAnimation/qclipblendnodecreatedchange.h> +#include <Qt3DCore/qnodecreatedchange.h> +#include "testpostmanarbiter.h" + +class tst_QAdditiveClipBlend : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType<Qt3DAnimation::QAbstractClipBlendNode*>(); + } + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend addBlend; + + // THEN + QCOMPARE(addBlend.additiveFactor(), 0.0f); + QCOMPARE(addBlend.baseClip(), static_cast<Qt3DAnimation::QAbstractClipBlendNode *>(nullptr)); + QCOMPARE(addBlend.additiveClip(), static_cast<Qt3DAnimation::QAbstractClipBlendNode *>(nullptr)); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend addBlend; + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(additiveFactorChanged(float))); + const float newValue = 0.5f; + addBlend.setAdditiveFactor(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.additiveFactor(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setAdditiveFactor(newValue); + + // THEN + QCOMPARE(addBlend.additiveFactor(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(baseClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QAdditiveClipBlend(); + addBlend.setBaseClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.baseClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setBaseClip(newValue); + + // THEN + QCOMPARE(addBlend.baseClip(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + QSignalSpy spy(&addBlend, SIGNAL(additiveClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QAdditiveClipBlend(); + addBlend.setAdditiveClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(addBlend.additiveClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + addBlend.setAdditiveClip(newValue); + + // THEN + QCOMPARE(addBlend.additiveClip(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QAdditiveClipBlend addBlend; + Qt3DAnimation::QAdditiveClipBlend baseClip; + Qt3DAnimation::QAdditiveClipBlend additiveClip; + + addBlend.setBaseClip(&baseClip); + addBlend.setAdditiveClip(&additiveClip); + addBlend.setAdditiveFactor(0.8f); + + + // WHEN + QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QAdditiveClipBlendData>>(creationChanges.first()); + const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.additiveFactor(), cloneData.additiveFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), true); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.baseClipId, baseClip.id()); + QCOMPARE(cloneData.additiveClipId, additiveClip.id()); + } + + // WHEN + addBlend.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&addBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QAdditiveClipBlendData>>(creationChanges.first()); + const Qt3DAnimation::QAdditiveClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(addBlend.additiveFactor(), cloneData.additiveFactor); + QCOMPARE(addBlend.id(), creationChangeData->subjectId()); + QCOMPARE(addBlend.isEnabled(), false); + QCOMPARE(addBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(addBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.baseClipId, baseClip.id()); + QCOMPARE(cloneData.additiveClipId, additiveClip.id()); + } + } + + void checkAdditiveFactorUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAdditiveClipBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + + { + // WHEN + addBlend.setAdditiveFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "additiveFactor"); + QCOMPARE(change->value().value<float>(), addBlend.additiveFactor()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setAdditiveFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkBaseClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAdditiveClipBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + auto baseClip = new Qt3DAnimation::QAdditiveClipBlend(); + + { + // WHEN + addBlend.setBaseClip(baseClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "baseClip"); + QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), addBlend.baseClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setBaseClip(baseClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkAdditiveClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QAdditiveClipBlend addBlend; + arbiter.setArbiterOnNode(&addBlend); + auto additiveClip = new Qt3DAnimation::QAdditiveClipBlend(); + + { + // WHEN + addBlend.setAdditiveClip(additiveClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "additiveClip"); + QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), addBlend.additiveClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + addBlend.setAdditiveClip(additiveClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkBaseClipBookkeeping() + { + // GIVEN + QScopedPointer<Qt3DAnimation::QAdditiveClipBlend> additiveBlend(new Qt3DAnimation::QAdditiveClipBlend); + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend clip; + additiveBlend->setBaseClip(&clip); + + // THEN + QCOMPARE(clip.parent(), additiveBlend.data()); + QCOMPARE(additiveBlend->baseClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(additiveBlend->baseClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend someOtherAdditiveBlend; + QScopedPointer<Qt3DAnimation::QAdditiveClipBlend> clip(new Qt3DAnimation::QAdditiveClipBlend(&someOtherAdditiveBlend)); + additiveBlend->setBaseClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherAdditiveBlend); + QCOMPARE(additiveBlend->baseClip(), clip.data()); + + // WHEN + additiveBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } + + void checkAdditiveClipBookkeeping() + { + // GIVEN + QScopedPointer<Qt3DAnimation::QAdditiveClipBlend> additiveBlend(new Qt3DAnimation::QAdditiveClipBlend); + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend clip; + additiveBlend->setAdditiveClip(&clip); + + // THEN + QCOMPARE(clip.parent(), additiveBlend.data()); + QCOMPARE(additiveBlend->additiveClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(additiveBlend->additiveClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QAdditiveClipBlend someOtherAdditiveBlend; + QScopedPointer<Qt3DAnimation::QAdditiveClipBlend> clip(new Qt3DAnimation::QAdditiveClipBlend(&someOtherAdditiveBlend)); + additiveBlend->setAdditiveClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherAdditiveBlend); + QCOMPARE(additiveBlend->additiveClip(), clip.data()); + + // WHEN + additiveBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } +}; + +QTEST_MAIN(tst_QAdditiveClipBlend) + +#include "tst_qadditiveclipblend.moc" diff --git a/tests/auto/animation/qanimationclip/qanimationclip.pro b/tests/auto/animation/qanimationcliploader/qanimationcliploader.pro index 5a9678496..d6ef54df6 100644 --- a/tests/auto/animation/qanimationclip/qanimationclip.pro +++ b/tests/auto/animation/qanimationcliploader/qanimationcliploader.pro @@ -7,6 +7,6 @@ QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib CONFIG += testcase SOURCES += \ - tst_qanimationclip.cpp + tst_qanimationcliploader.cpp include(../../core/common/common.pri) diff --git a/tests/auto/animation/qanimationclip/tst_qanimationclip.cpp b/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp index 8c83f6530..968ad8764 100644 --- a/tests/auto/animation/qanimationclip/tst_qanimationclip.cpp +++ b/tests/auto/animation/qanimationcliploader/tst_qanimationcliploader.cpp @@ -28,8 +28,8 @@ #include <QtTest/QTest> -#include <Qt3DAnimation/qanimationclip.h> -#include <Qt3DAnimation/private/qanimationclip_p.h> +#include <Qt3DAnimation/qanimationcliploader.h> +#include <Qt3DAnimation/private/qanimationcliploader_p.h> #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/qnodecreatedchange.h> #include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> @@ -37,7 +37,7 @@ #include <QSignalSpy> #include <testpostmanarbiter.h> -class tst_QAnimationClip : public QObject +class tst_QAnimationClipLoader : public Qt3DAnimation::QAnimationClipLoader { Q_OBJECT @@ -45,17 +45,18 @@ private Q_SLOTS: void checkDefaultConstruction() { // GIVEN - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; // THEN QCOMPARE(clip.source(), QUrl()); QCOMPARE(clip.duration(), 0.0f); + QCOMPARE(clip.status(), Qt3DAnimation::QAnimationClipLoader::NotReady); } void checkPropertyChanges() { // GIVEN - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; { // WHEN @@ -81,7 +82,7 @@ private Q_SLOTS: void checkCreationData() { // GIVEN - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; clip.setSource(QUrl(QStringLiteral("http://someRemoteURL.com"))); @@ -97,8 +98,8 @@ private Q_SLOTS: { QCOMPARE(creationChanges.size(), 1); - const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QAnimationClipData>>(creationChanges.first()); - const Qt3DAnimation::QAnimationClipData data = creationChangeData->data; + const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QAnimationClipLoaderData>>(creationChanges.first()); + const Qt3DAnimation::QAnimationClipLoaderData data = creationChangeData->data; QCOMPARE(clip.id(), creationChangeData->subjectId()); QCOMPARE(clip.isEnabled(), true); @@ -119,7 +120,7 @@ private Q_SLOTS: { QCOMPARE(creationChanges.size(), 1); - const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QAnimationClipData>>(creationChanges.first()); + const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QAnimationClipLoaderData>>(creationChanges.first()); QCOMPARE(clip.id(), creationChangeData->subjectId()); QCOMPARE(clip.isEnabled(), false); @@ -132,7 +133,7 @@ private Q_SLOTS: { // GIVEN TestArbiter arbiter; - Qt3DAnimation::QAnimationClip clip; + Qt3DAnimation::QAnimationClipLoader clip; arbiter.setArbiterOnNode(&clip); { @@ -159,8 +160,41 @@ private Q_SLOTS: } } + + void checkStatusPropertyUpdate() + { + // GIVEN + qRegisterMetaType<Qt3DAnimation::QAnimationClipLoader::Status>("Status"); + TestArbiter arbiter; + arbiter.setArbiterOnNode(this); + QSignalSpy spy(this, SIGNAL(statusChanged(Status))); + const Qt3DAnimation::QAnimationClipLoader::Status newStatus = Qt3DAnimation::QAnimationClipLoader::Error; + + // THEN + QVERIFY(spy.isValid()); + + // WHEN + Qt3DCore::QPropertyUpdatedChangePtr valueChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + valueChange->setPropertyName("status"); + valueChange->setValue(QVariant::fromValue(newStatus)); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 1); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(status(), newStatus); + + // WHEN + spy.clear(); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(spy.count(), 0); + QCOMPARE(arbiter.events.size(), 0); + QCOMPARE(status(), newStatus); + } }; -QTEST_MAIN(tst_QAnimationClip) +QTEST_MAIN(tst_QAnimationClipLoader) -#include "tst_qanimationclip.moc" +#include "tst_qanimationcliploader.moc" diff --git a/tests/auto/animation/qanimationcontroller/qanimationcontroller.pro b/tests/auto/animation/qanimationcontroller/qanimationcontroller.pro new file mode 100644 index 000000000..ff5348d47 --- /dev/null +++ b/tests/auto/animation/qanimationcontroller/qanimationcontroller.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +TARGET = tst_qanimationcontroller + +QT += 3dcore 3dcore-private 3drender 3drender-private 3danimation testlib + +CONFIG += testcase + +SOURCES += tst_qanimationcontroller.cpp + diff --git a/tests/auto/animation/qanimationcontroller/tst_qanimationcontroller.cpp b/tests/auto/animation/qanimationcontroller/tst_qanimationcontroller.cpp new file mode 100644 index 000000000..4774dc8ba --- /dev/null +++ b/tests/auto/animation/qanimationcontroller/tst_qanimationcontroller.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <Qt3DAnimation/qanimationcontroller.h> +#include <Qt3DAnimation/qkeyframeanimation.h> +#include <Qt3DAnimation/qmorphinganimation.h> +#include <qobject.h> +#include <qsignalspy.h> + +class tst_QAnimationController : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QAnimationController animationController; + + // THEN + QCOMPARE(animationController.activeAnimationGroup(), 0); + QCOMPARE(animationController.position(), 0.0f); + QCOMPARE(animationController.positionScale(), 1.0f); + QCOMPARE(animationController.positionOffset(), 0.0f); + QCOMPARE(animationController.entity(), nullptr); + QCOMPARE(animationController.recursive(), true); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QAnimationController animationController; + + { + // WHEN + QSignalSpy spy(&animationController, SIGNAL(activeAnimationGroupChanged(int))); + const int newValue = 1; + animationController.setActiveAnimationGroup(newValue); + + // THEN + QCOMPARE(animationController.activeAnimationGroup(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationController.setActiveAnimationGroup(newValue); + + // THEN + QCOMPARE(animationController.activeAnimationGroup(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&animationController, SIGNAL(positionChanged(float))); + const float newValue = 2.0f; + animationController.setPosition(newValue); + + // THEN + QCOMPARE(animationController.position(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationController.setPosition(newValue); + + // THEN + QCOMPARE(animationController.position(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&animationController, SIGNAL(positionScaleChanged(float))); + const float newValue = 3.0f; + animationController.setPositionScale(newValue); + + // THEN + QCOMPARE(animationController.positionScale(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationController.setPositionScale(newValue); + + // THEN + QCOMPARE(animationController.positionScale(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&animationController, SIGNAL(positionOffsetChanged(float))); + const float newValue = -1.0f; + animationController.setPositionOffset(newValue); + + // THEN + QCOMPARE(animationController.positionOffset(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationController.setPositionOffset(newValue); + + // THEN + QCOMPARE(animationController.positionOffset(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity); + QSignalSpy spy(&animationController, SIGNAL(entityChanged(Qt3DCore::QEntity *))); + Qt3DCore::QEntity * newValue = entity.data(); + animationController.setEntity(newValue); + + // THEN + QCOMPARE(animationController.entity(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationController.setEntity(newValue); + + // THEN + QCOMPARE(animationController.entity(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&animationController, SIGNAL(recursiveChanged(bool))); + const bool newValue = false; + animationController.setRecursive(newValue); + + // THEN + QCOMPARE(animationController.recursive(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationController.setRecursive(newValue); + + // THEN + QCOMPARE(animationController.recursive(), newValue); + QCOMPARE(spy.count(), 0); + + } + } + + void testSetEntity() + { + // GIVEN + Qt3DAnimation::QAnimationController animationController; + Qt3DAnimation::QKeyframeAnimation *keyframeAnimation; + Qt3DAnimation::QKeyframeAnimation *keyframeAnimation2; + Qt3DAnimation::QMorphingAnimation *morphingAnimation; + + QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity); + keyframeAnimation = new Qt3DAnimation::QKeyframeAnimation(entity.data()); + keyframeAnimation2 = new Qt3DAnimation::QKeyframeAnimation(entity.data()); + morphingAnimation = new Qt3DAnimation::QMorphingAnimation(entity.data()); + + const QString animName1 = QString("animation1"); + const QString animName2 = QString("animation2"); + morphingAnimation->setAnimationName(animName1); + keyframeAnimation->setAnimationName(animName1); + keyframeAnimation2->setAnimationName(animName2); + + { + // WHEN + animationController.setEntity(entity.data()); + + // THEN + QVector<Qt3DAnimation::QAnimationGroup *> list = animationController.animationGroupList(); + QCOMPARE(list.size(), 2); + + QCOMPARE(list.at(0)->name(), animName1); + QCOMPARE(list.at(1)->name(), animName2); + + QCOMPARE(list.at(0)->animationList().size(), 2); + QCOMPARE(list.at(1)->animationList().size(), 1); + } + } + + void testSetEntityRecursive() + { + // GIVEN + Qt3DAnimation::QAnimationController animationController; + Qt3DAnimation::QKeyframeAnimation *keyframeAnimation; + Qt3DAnimation::QMorphingAnimation *morphingAnimation; + + QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity); + keyframeAnimation = new Qt3DAnimation::QKeyframeAnimation(entity.data()); + Qt3DCore::QEntity *childEntity = new Qt3DCore::QEntity(entity.data()); + morphingAnimation = new Qt3DAnimation::QMorphingAnimation(childEntity); + + const QString animName1 = QString("animation1"); + const QString animName2 = QString("animation2"); + + keyframeAnimation->setAnimationName(animName1); + morphingAnimation->setAnimationName(animName2); + + { + // WHEN + animationController.setEntity(entity.data()); + + // THEN + QVector<Qt3DAnimation::QAnimationGroup *> list = animationController.animationGroupList(); + QCOMPARE(list.size(), 2); + + QCOMPARE(list.at(0)->name(), animName1); + QCOMPARE(list.at(1)->name(), animName2); + + QCOMPARE(list.at(0)->animationList().size(), 1); + QCOMPARE(list.at(1)->animationList().size(), 1); + + animationController.setEntity(nullptr); + } + + { + // WHEN + animationController.setRecursive(false); + animationController.setEntity(entity.data()); + + // THEN + QVector<Qt3DAnimation::QAnimationGroup *> list = animationController.animationGroupList(); + QCOMPARE(list.size(), 1); + + QCOMPARE(list.at(0)->name(), animName1); + + QCOMPARE(list.at(0)->animationList().size(), 1); + } + } + + + void testPropagatePosition() + { + // GIVEN + Qt3DAnimation::QAnimationController animationController; + Qt3DAnimation::QKeyframeAnimation *keyframeAnimation; + + QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity); + keyframeAnimation = new Qt3DAnimation::QKeyframeAnimation(entity.data()); + + const QString animName1 = QString("animation1"); + keyframeAnimation->setAnimationName(animName1); + + { + // WHEN + animationController.setEntity(entity.data()); + animationController.setPosition(2.0f); + + // THEN + QCOMPARE(animationController.animationGroupList().at(0)->position(), 2.0f); + QCOMPARE(keyframeAnimation->position(), 2.0f); + } + + { + // WHEN + animationController.setPositionOffset(1.0); + animationController.setPositionScale(2.0f); + animationController.setPosition(2.0f); + + // THEN + QCOMPARE(animationController.animationGroupList().at(0)->position(), 5.0f); + QCOMPARE(keyframeAnimation->position(), 5.0f); + } + } + +}; + +QTEST_APPLESS_MAIN(tst_QAnimationController) + +#include "tst_qanimationcontroller.moc" diff --git a/tests/auto/animation/qanimationgroup/qanimationgroup.pro b/tests/auto/animation/qanimationgroup/qanimationgroup.pro new file mode 100644 index 000000000..5c39fa539 --- /dev/null +++ b/tests/auto/animation/qanimationgroup/qanimationgroup.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +TARGET = tst_qanimationgroup + +QT += 3dcore 3dcore-private 3drender 3drender-private 3danimation testlib + +CONFIG += testcase + +SOURCES += tst_qanimationgroup.cpp + diff --git a/tests/auto/animation/qanimationgroup/tst_qanimationgroup.cpp b/tests/auto/animation/qanimationgroup/tst_qanimationgroup.cpp new file mode 100644 index 000000000..0c7a66222 --- /dev/null +++ b/tests/auto/animation/qanimationgroup/tst_qanimationgroup.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QTest> +#include <Qt3DAnimation/qanimationgroup.h> +#include <qobject.h> +#include <qsignalspy.h> + +class tst_QAnimationGroup : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QAnimationGroup animationGroup; + + // THEN + QCOMPARE(animationGroup.name(), QString()); + QCOMPARE(animationGroup.position(), 0.0f); + QCOMPARE(animationGroup.duration(), 0.0f); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QAnimationGroup animationGroup; + + { + // WHEN + QSignalSpy spy(&animationGroup, SIGNAL(nameChanged(QString))); + const QString newValue = QString("group"); + animationGroup.setName(newValue); + + // THEN + QCOMPARE(animationGroup.name(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationGroup.setName(newValue); + + // THEN + QCOMPARE(animationGroup.name(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&animationGroup, SIGNAL(positionChanged(float))); + const float newValue = 2.0f; + animationGroup.setPosition(newValue); + + // THEN + QCOMPARE(animationGroup.position(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + animationGroup.setPosition(newValue); + + // THEN + QCOMPARE(animationGroup.position(), newValue); + QCOMPARE(spy.count(), 0); + + } + } + +}; + +QTEST_APPLESS_MAIN(tst_QAnimationGroup) + +#include "tst_qanimationgroup.moc" diff --git a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp index 42997d8aa..d25041886 100644 --- a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp +++ b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp @@ -28,11 +28,9 @@ #include <QtTest/QTest> -#include <Qt3DAnimation/qanimationclip.h> #include <Qt3DAnimation/qblendedclipanimator.h> -#include <Qt3DAnimation/private/qanimationclip_p.h> #include <Qt3DAnimation/private/qblendedclipanimator_p.h> -#include <Qt3DAnimation/qlerpblend.h> +#include <Qt3DAnimation/qlerpclipblend.h> #include <Qt3DAnimation/qchannelmapper.h> #include <Qt3DCore/qpropertyupdatedchange.h> #include <Qt3DCore/qnodecreatedchange.h> @@ -62,7 +60,7 @@ private Q_SLOTS: QVERIFY(blendedClipAnimator.blendTree() == nullptr); QVERIFY(blendedClipAnimator.channelMapper() == nullptr); QCOMPARE(blendedClipAnimator.isRunning(), false); - QCOMPARE(blendedClipAnimator.loops(), 1); + QCOMPARE(blendedClipAnimator.loopCount(), 1); } void checkPropertyChanges() @@ -73,7 +71,7 @@ private Q_SLOTS: { // WHEN QSignalSpy spy(&blendedClipAnimator, SIGNAL(blendTreeChanged(QAbstractClipBlendNode *))); - Qt3DAnimation::QLerpBlend newValue; + Qt3DAnimation::QLerpClipBlend newValue; blendedClipAnimator.setBlendTree(&newValue); // THEN @@ -130,21 +128,21 @@ private Q_SLOTS: { // WHEN - QSignalSpy spy(&blendedClipAnimator, SIGNAL(loopsChanged(int))); + QSignalSpy spy(&blendedClipAnimator, SIGNAL(loopCountChanged(int))); const int newValue = 5; - blendedClipAnimator.setLoops(newValue); + blendedClipAnimator.setLoopCount(newValue); // THEN QVERIFY(spy.isValid()); - QCOMPARE(blendedClipAnimator.loops(), newValue); + QCOMPARE(blendedClipAnimator.loopCount(), newValue); QCOMPARE(spy.count(), 1); // WHEN spy.clear(); - blendedClipAnimator.setLoops(newValue); + blendedClipAnimator.setLoopCount(newValue); // THEN - QCOMPARE(blendedClipAnimator.loops(), newValue); + QCOMPARE(blendedClipAnimator.loopCount(), newValue); QCOMPARE(spy.count(), 0); } } @@ -154,7 +152,7 @@ private Q_SLOTS: // GIVEN Qt3DAnimation::QBlendedClipAnimator blendedClipAnimator; Qt3DAnimation::QChannelMapper channelMapper; - Qt3DAnimation::QLerpBlend blendRoot; + Qt3DAnimation::QLerpClipBlend blendRoot; blendedClipAnimator.setBlendTree(&blendRoot); blendedClipAnimator.setChannelMapper(&channelMapper); @@ -182,7 +180,7 @@ private Q_SLOTS: QCOMPARE(blendedClipAnimator.isEnabled(), true); QCOMPARE(blendedClipAnimator.isEnabled(), creationChangeData->isNodeEnabled()); QCOMPARE(blendedClipAnimator.metaObject(), creationChangeData->metaObject()); - QCOMPARE(blendedClipAnimator.loops(), cloneData.loops); + QCOMPARE(blendedClipAnimator.loopCount(), cloneData.loops); } // WHEN @@ -216,7 +214,7 @@ private Q_SLOTS: TestArbiter arbiter; Qt3DAnimation::QBlendedClipAnimator blendedClipAnimator; arbiter.setArbiterOnNode(&blendedClipAnimator); - Qt3DAnimation::QLerpBlend blendRoot; + Qt3DAnimation::QLerpClipBlend blendRoot; { // WHEN @@ -251,7 +249,7 @@ private Q_SLOTS: { // WHEN - Qt3DAnimation::QLerpBlend blendRoot; + Qt3DAnimation::QLerpClipBlend blendRoot; blendedClipAnimator.setBlendTree(&blendRoot); QCOMPARE(blendedClipAnimator.blendTree(), &blendRoot); @@ -354,14 +352,14 @@ private Q_SLOTS: { // WHEN - blendedClipAnimator.setLoops(1584); + blendedClipAnimator.setLoopCount(1584); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.events.size(), 1); auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); QCOMPARE(change->propertyName(), "loops"); - QCOMPARE(change->value().value<int>(), blendedClipAnimator.loops()); + QCOMPARE(change->value().value<int>(), blendedClipAnimator.loopCount()); QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); arbiter.events.clear(); @@ -369,7 +367,7 @@ private Q_SLOTS: { // WHEN - blendedClipAnimator.setLoops(1584); + blendedClipAnimator.setLoopCount(1584); QCoreApplication::processEvents(); // THEN diff --git a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp index d210d4365..1ed4b8f13 100644 --- a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp +++ b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp @@ -28,7 +28,7 @@ #include <QtTest/QTest> -#include <Qt3DAnimation/qanimationclip.h> +#include <Qt3DAnimation/qanimationcliploader.h> #include <Qt3DAnimation/qchannelmapper.h> #include <Qt3DAnimation/qclipanimator.h> #include <Qt3DAnimation/private/qanimationclip_p.h> @@ -47,7 +47,7 @@ class tst_QClipAnimator : public QObject private Q_SLOTS: void initTestCase() { - qRegisterMetaType<Qt3DAnimation::QAnimationClip*>(); + qRegisterMetaType<Qt3DAnimation::QAbstractAnimationClip*>(); qRegisterMetaType<Qt3DAnimation::QChannelMapper*>(); } @@ -57,9 +57,9 @@ private Q_SLOTS: Qt3DAnimation::QClipAnimator animator; // THEN - QCOMPARE(animator.clip(), static_cast<Qt3DAnimation::QAnimationClip *>(nullptr)); + QCOMPARE(animator.clip(), static_cast<Qt3DAnimation::QAbstractAnimationClip *>(nullptr)); QCOMPARE(animator.channelMapper(), static_cast<Qt3DAnimation::QChannelMapper *>(nullptr)); - QCOMPARE(animator.loops(), 1); + QCOMPARE(animator.loopCount(), 1); } void checkPropertyChanges() @@ -69,8 +69,8 @@ private Q_SLOTS: { // WHEN - QSignalSpy spy(&animator, SIGNAL(clipChanged(Qt3DAnimation::QAnimationClip *))); - auto newValue = new Qt3DAnimation::QAnimationClip(); + QSignalSpy spy(&animator, SIGNAL(clipChanged(Qt3DAnimation::QAbstractAnimationClip *))); + auto newValue = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(newValue); // THEN @@ -111,21 +111,21 @@ private Q_SLOTS: { // WHEN - QSignalSpy spy(&animator, SIGNAL(loopsChanged(int))); + QSignalSpy spy(&animator, SIGNAL(loopCountChanged(int))); const int newValue = 5; - animator.setLoops(newValue); + animator.setLoopCount(newValue); // THEN QVERIFY(spy.isValid()); - QCOMPARE(animator.loops(), newValue); + QCOMPARE(animator.loopCount(), newValue); QCOMPARE(spy.count(), 1); // WHEN spy.clear(); - animator.setLoops(newValue); + animator.setLoopCount(newValue); // THEN - QCOMPARE(animator.loops(), newValue); + QCOMPARE(animator.loopCount(), newValue); QCOMPARE(spy.count(), 0); } } @@ -134,7 +134,7 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); animator.setClip(clip); auto mapper = new Qt3DAnimation::QChannelMapper(); animator.setChannelMapper(mapper); @@ -159,7 +159,7 @@ private Q_SLOTS: QCOMPARE(animator.metaObject(), creationChangeData->metaObject()); QCOMPARE(animator.clip()->id(), data.clipId); QCOMPARE(animator.channelMapper()->id(), data.mapperId); - QCOMPARE(animator.loops(), data.loops); + QCOMPARE(animator.loopCount(), data.loops); } // WHEN @@ -187,7 +187,7 @@ private Q_SLOTS: // GIVEN TestArbiter arbiter; Qt3DAnimation::QClipAnimator animator; - auto clip = new Qt3DAnimation::QAnimationClip(); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); arbiter.setArbiterOnNode(&animator); { @@ -242,7 +242,7 @@ private Q_SLOTS: { // WHEN - animator.setLoops(10); + animator.setLoopCount(10); QCoreApplication::processEvents(); // THEN @@ -250,14 +250,14 @@ private Q_SLOTS: auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); QCOMPARE(change->propertyName(), "loops"); QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - QCOMPARE(change->value().toInt(), animator.loops()); + QCOMPARE(change->value().toInt(), animator.loopCount()); arbiter.events.clear(); } { // WHEN - animator.setLoops(10); + animator.setLoopCount(10); QCoreApplication::processEvents(); // THEN diff --git a/tests/auto/animation/qclipblendvalue/qclipblendvalue.pro b/tests/auto/animation/qclipblendvalue/qclipblendvalue.pro new file mode 100644 index 000000000..b44b387db --- /dev/null +++ b/tests/auto/animation/qclipblendvalue/qclipblendvalue.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qclipblendvalue + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qclipblendvalue.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qclipblendvalue/tst_qclipblendvalue.cpp b/tests/auto/animation/qclipblendvalue/tst_qclipblendvalue.cpp new file mode 100644 index 000000000..bdbee9380 --- /dev/null +++ b/tests/auto/animation/qclipblendvalue/tst_qclipblendvalue.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QTest> +#include <Qt3DAnimation/qclipblendvalue.h> +#include <Qt3DAnimation/qanimationcliploader.h> +#include <Qt3DAnimation/private/qclipblendvalue_p.h> +#include <QObject> +#include <QSignalSpy> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> +#include <Qt3DAnimation/qclipblendnodecreatedchange.h> +#include <Qt3DCore/qnodecreatedchange.h> +#include "testpostmanarbiter.h" + +class tst_QClipBlendValue : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType<Qt3DAnimation::QAbstractAnimationClip*>(); + } + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendNode; + + // THEN; + QCOMPARE(clipBlendNode.clip(), static_cast<Qt3DAnimation::QAbstractAnimationClip *>(nullptr)); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendNode; + + { + // WHEN + QSignalSpy spy(&clipBlendNode, SIGNAL(clipChanged(Qt3DAnimation::QAbstractAnimationClip*))); + auto newValue = new Qt3DAnimation::QAnimationClipLoader(); + clipBlendNode.setClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(clipBlendNode.clip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + clipBlendNode.setClip(newValue); + + // THEN + QCOMPARE(clipBlendNode.clip(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QClipBlendValue clipBlendNode; + Qt3DAnimation::QAnimationClipLoader clip; + + clipBlendNode.setClip(&clip); + + // WHEN + QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clipBlendNode); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 2); // 1 + 1 clip + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QClipBlendValueData>>(creationChanges.first()); + const Qt3DAnimation::QClipBlendValueData cloneData = creationChangeData->data; + + QCOMPARE(clipBlendNode.id(), creationChangeData->subjectId()); + QCOMPARE(clipBlendNode.isEnabled(), true); + QCOMPARE(clipBlendNode.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(clipBlendNode.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.clipId, clip.id()); + } + + // WHEN + clipBlendNode.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clipBlendNode); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 2); // 1 + 1 clip + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QClipBlendValueData>>(creationChanges.first()); + const Qt3DAnimation::QClipBlendValueData cloneData = creationChangeData->data; + + QCOMPARE(clipBlendNode.id(), creationChangeData->subjectId()); + QCOMPARE(clipBlendNode.isEnabled(), false); + QCOMPARE(clipBlendNode.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(clipBlendNode.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.clipId, clip.id()); + } + } + + void checkClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QClipBlendValue clipBlendNode; + arbiter.setArbiterOnNode(&clipBlendNode); + auto clip = new Qt3DAnimation::QAnimationClipLoader(); + + { + // WHEN + clipBlendNode.setClip(clip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "clip"); + QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), clipBlendNode.clip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + clipBlendNode.setClip(clip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkStartClipBookkeeping() + { + // GIVEN + QScopedPointer<Qt3DAnimation::QClipBlendValue> clipBlendNode(new Qt3DAnimation::QClipBlendValue); + { + // WHEN + Qt3DAnimation::QAnimationClipLoader clip; + clipBlendNode->setClip(&clip); + + // THEN + QCOMPARE(clip.parent(), clipBlendNode.data()); + QCOMPARE(clipBlendNode->clip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(clipBlendNode->clip() == nullptr); + + { + // WHEN + Qt3DAnimation::QClipBlendValue someOtherNode; + QScopedPointer<Qt3DAnimation::QAnimationClipLoader> clip(new Qt3DAnimation::QAnimationClipLoader(&someOtherNode)); + clipBlendNode->setClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherNode); + QCOMPARE(clipBlendNode->clip(), clip.data()); + + // WHEN + clipBlendNode.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } +}; + +QTEST_MAIN(tst_QClipBlendValue) + +#include "tst_qclipblendvalue.moc" diff --git a/tests/auto/animation/qconductedclipanimator/tst_qconductedclipanimator.cpp b/tests/auto/animation/qconductedclipanimator/tst_qconductedclipanimator.cpp deleted file mode 100644 index 7e40e5033..000000000 --- a/tests/auto/animation/qconductedclipanimator/tst_qconductedclipanimator.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <QtTest/QTest> -#include <Qt3DAnimation/qanimationclip.h> -#include <Qt3DAnimation/qconductedclipanimator.h> -#include <Qt3DAnimation/private/qanimationclip_p.h> -#include <Qt3DAnimation/private/qconductedclipanimator_p.h> -#include <Qt3DCore/qpropertyupdatedchange.h> -#include <Qt3DCore/qnodecreatedchange.h> -#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> -#include <QObject> -#include <QSignalSpy> -#include <testpostmanarbiter.h> - -class tst_QConductedClipAnimator : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - void initTestCase() - { - qRegisterMetaType<Qt3DAnimation::QAnimationClip*>(); - } - - void checkDefaultConstruction() - { - // GIVEN - Qt3DAnimation::QConductedClipAnimator animator; - - // THEN - // TODO: Check default property state - } -}; - -QTEST_MAIN(tst_QConductedClipAnimator) - -#include "tst_qconductedclipanimator.moc" diff --git a/tests/auto/animation/qkeyframeanimation/qkeyframeanimation.pro b/tests/auto/animation/qkeyframeanimation/qkeyframeanimation.pro new file mode 100644 index 000000000..994d8d0d9 --- /dev/null +++ b/tests/auto/animation/qkeyframeanimation/qkeyframeanimation.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +TARGET = tst_qkeyframeanimation + +QT += 3dcore 3dcore-private 3drender 3drender-private 3danimation testlib + +CONFIG += testcase + +SOURCES += tst_qkeyframeanimation.cpp + diff --git a/tests/auto/animation/qkeyframeanimation/tst_qkeyframeanimation.cpp b/tests/auto/animation/qkeyframeanimation/tst_qkeyframeanimation.cpp new file mode 100644 index 000000000..33bbebc52 --- /dev/null +++ b/tests/auto/animation/qkeyframeanimation/tst_qkeyframeanimation.cpp @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <Qt3DAnimation/qkeyframeanimation.h> +#include <qobject.h> +#include <qsignalspy.h> + +class tst_QKeyframeAnimation : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void initTestCase() + { + qRegisterMetaType<Qt3DAnimation::QKeyframeAnimation::RepeatMode>( + "QKeyframeAnimation::RepeatMode"); + } + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QKeyframeAnimation keyframeAnimation; + + // THEN + QCOMPARE(keyframeAnimation.target(), nullptr); + QCOMPARE(keyframeAnimation.easing(), QEasingCurve()); + QCOMPARE(keyframeAnimation.targetName(), QString()); + QCOMPARE(keyframeAnimation.startMode(), Qt3DAnimation::QKeyframeAnimation::Constant); + QCOMPARE(keyframeAnimation.endMode(), Qt3DAnimation::QKeyframeAnimation::Constant); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QKeyframeAnimation keyframeAnimation; + + { + // WHEN + QScopedPointer<Qt3DCore::QTransform> transform(new Qt3DCore::QTransform); + QSignalSpy spy(&keyframeAnimation, SIGNAL(targetChanged(Qt3DCore::QTransform *))); + Qt3DCore::QTransform * newValue = transform.data(); + keyframeAnimation.setTarget(newValue); + + // THEN + QCOMPARE(keyframeAnimation.target(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + keyframeAnimation.setTarget(newValue); + + // THEN + QCOMPARE(keyframeAnimation.target(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&keyframeAnimation, SIGNAL(easingChanged(const QEasingCurve &))); + const QEasingCurve newValue = QEasingCurve(QEasingCurve::CosineCurve); + keyframeAnimation.setEasing(newValue); + + // THEN + QCOMPARE(keyframeAnimation.easing(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + keyframeAnimation.setEasing(newValue); + + // THEN + QCOMPARE(keyframeAnimation.easing(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&keyframeAnimation, SIGNAL(targetNameChanged(QString))); + const QString newValue = QString("target"); + keyframeAnimation.setTargetName(newValue); + + // THEN + QCOMPARE(keyframeAnimation.targetName(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + keyframeAnimation.setTargetName(newValue); + + // THEN + QCOMPARE(keyframeAnimation.targetName(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&keyframeAnimation, + SIGNAL(startModeChanged(QKeyframeAnimation::RepeatMode))); + const Qt3DAnimation::QKeyframeAnimation::RepeatMode newValue + = Qt3DAnimation::QKeyframeAnimation::Repeat; + keyframeAnimation.setStartMode(newValue); + + // THEN + QCOMPARE(keyframeAnimation.startMode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + keyframeAnimation.setStartMode(newValue); + + // THEN + QCOMPARE(keyframeAnimation.startMode(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&keyframeAnimation, + SIGNAL(endModeChanged(QKeyframeAnimation::RepeatMode))); + const Qt3DAnimation::QKeyframeAnimation::RepeatMode newValue + = Qt3DAnimation::QKeyframeAnimation::Repeat; + keyframeAnimation.setEndMode(newValue); + + // THEN + QCOMPARE(keyframeAnimation.endMode(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + keyframeAnimation.setEndMode(newValue); + + // THEN + QCOMPARE(keyframeAnimation.endMode(), newValue); + QCOMPARE(spy.count(), 0); + + } + } + + void testAnimating() + { + // GIVEN + Qt3DAnimation::QKeyframeAnimation keyframeAnimation; + Qt3DCore::QTransform targetTransform; + keyframeAnimation.setTarget(&targetTransform); + + const float positions[3] = {0.0f, 1.0f, 2.0f}; + + Qt3DCore::QTransform keyframes[3]; + keyframes[0].setScale(1.0f); + keyframes[1].setScale(2.0f); + keyframes[2].setScale(3.0f); + + keyframes[0].setTranslation(QVector3D(0.0f, 0.0f, 0.0f)); + keyframes[1].setTranslation(QVector3D(1.0f, 1.0f, 0.0f)); + keyframes[2].setTranslation(QVector3D(2.0f, 0.0f, 2.0f)); + + keyframes[0].setRotationX(0.0f); + keyframes[1].setRotationY(45.0f); + keyframes[2].setRotationZ(90.0f); + + QVector<float> framePositions; + framePositions.push_back(positions[0]); + framePositions.push_back(positions[1]); + framePositions.push_back(positions[2]); + + QVector<Qt3DCore::QTransform*> frames; + frames.push_back(&keyframes[0]); + frames.push_back(&keyframes[1]); + frames.push_back(&keyframes[2]); + + keyframeAnimation.setFramePositions(framePositions); + keyframeAnimation.setKeyframes(frames); + + { + // WHEN + keyframeAnimation.setPosition(0.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(1.0f, 1.0f, 1.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(0.0f, 0.0f, 0.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 0.0f, 0.0f)))); + + // WHEN + keyframeAnimation.setPosition(1.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(2.0f, 2.0f, 2.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(1.0f, 1.0f, 0.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 45.0f, 0.0f)))); + + // WHEN + keyframeAnimation.setPosition(2.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(3.0f, 3.0f, 3.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(2.0f, 0.0f, 2.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 0.0f, 90.0f)))); + + // WHEN + keyframeAnimation.setPosition(3.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(3.0f, 3.0f, 3.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(2.0f, 0.0f, 2.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 0.0f, 90.0f)))); + + // WHEN + keyframeAnimation.setStartMode(Qt3DAnimation::QKeyframeAnimation::None); + keyframeAnimation.setEndMode(Qt3DAnimation::QKeyframeAnimation::None); + keyframeAnimation.setPosition(-1.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(3.0f, 3.0f, 3.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(2.0f, 0.0f, 2.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 0.0f, 90.0f)))); + + // WHEN + keyframeAnimation.setPosition(5.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(3.0f, 3.0f, 3.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(2.0f, 0.0f, 2.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 0.0f, 90.0f)))); + + // WHEN + keyframeAnimation.setStartMode(Qt3DAnimation::QKeyframeAnimation::Repeat); + keyframeAnimation.setEndMode(Qt3DAnimation::QKeyframeAnimation::Repeat); + keyframeAnimation.setPosition(-1.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(2.0f, 2.0f, 2.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(1.0f, 1.0f, 0.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 45.0f, 0.0f)))); + + // WHEN + keyframeAnimation.setStartMode(Qt3DAnimation::QKeyframeAnimation::Repeat); + keyframeAnimation.setEndMode(Qt3DAnimation::QKeyframeAnimation::Repeat); + keyframeAnimation.setPosition(4.0f); + + // THEN + QVERIFY(qFuzzyCompare(targetTransform.scale3D(), QVector3D(1.0f, 1.0f, 1.0f))); + QVERIFY(qFuzzyCompare(targetTransform.translation(), QVector3D(0.0f, 0.0f, 0.0f))); + QVERIFY(qFuzzyCompare(targetTransform.rotation(), + QQuaternion::fromEulerAngles(QVector3D(0.0f, 0.0f, 0.0f)))); + } + } +}; + +QTEST_APPLESS_MAIN(tst_QKeyframeAnimation) + +#include "tst_qkeyframeanimation.moc" diff --git a/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp b/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp deleted file mode 100644 index 6bd6bb324..000000000 --- a/tests/auto/animation/qlerpblend/tst_qlerpblend.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <QtTest/QTest> -#include <Qt3DAnimation/qlerpblend.h> -#include <Qt3DAnimation/qanimationclip.h> -#include <Qt3DAnimation/private/qlerpblend_p.h> -#include <QObject> -#include <QSignalSpy> -#include <Qt3DCore/qpropertyupdatedchange.h> -#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> -#include <Qt3DAnimation/qclipblendnodecreatedchange.h> -#include <Qt3DCore/qnodecreatedchange.h> -#include "testpostmanarbiter.h" - -class tst_QLerpBlend : public QObject -{ - Q_OBJECT - -private Q_SLOTS: - - void checkDefaultConstruction() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - - // THEN - QCOMPARE(lerpBlend.blendFactor(), 0.0f); - } - - void checkPropertyChanges() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - - { - // WHEN - QSignalSpy spy(&lerpBlend, SIGNAL(blendFactorChanged(float))); - const float newValue = 0.5f; - lerpBlend.setBlendFactor(newValue); - - // THEN - QVERIFY(spy.isValid()); - QCOMPARE(lerpBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 1); - - // WHEN - spy.clear(); - lerpBlend.setBlendFactor(newValue); - - // THEN - QCOMPARE(lerpBlend.blendFactor(), newValue); - QCOMPARE(spy.count(), 0); - } - } - - void checkCreationData() - { - // GIVEN - Qt3DAnimation::QLerpBlend lerpBlend; - Qt3DAnimation::QAnimationClip clip1; - Qt3DAnimation::QAnimationClip clip2; - - lerpBlend.addClip(&clip1); - lerpBlend.addClip(&clip2); - lerpBlend.setBlendFactor(0.8f); - - - // WHEN - QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges; - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QLerpBlendData>>(creationChanges.first()); - const Qt3DAnimation::QLerpBlendData cloneData = creationChangeData->data; - - QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); - QCOMPARE(lerpBlend.isEnabled(), true); - QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - - // WHEN - lerpBlend.setEnabled(false); - - { - Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); - creationChanges = creationChangeGenerator.creationChanges(); - } - - // THEN - { - QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips - - const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QLerpBlendData>>(creationChanges.first()); - const Qt3DAnimation::QLerpBlendData cloneData = creationChangeData->data; - - QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); - QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); - QCOMPARE(lerpBlend.isEnabled(), false); - QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); - QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); - QCOMPARE(creationChangeData->clips().size(), 2); - QCOMPARE(creationChangeData->clips().first(), clip1.id()); - QCOMPARE(creationChangeData->clips().last(), clip2.id()); - QCOMPARE(creationChangeData->parentClipBlendNodeId(), Qt3DCore::QNodeId()); - } - } - - void checkBlendFactorUpdate() - { - // GIVEN - TestArbiter arbiter; - Qt3DAnimation::QLerpBlend lerpBlend; - arbiter.setArbiterOnNode(&lerpBlend); - - { - // WHEN - lerpBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 1); - auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); - QCOMPARE(change->propertyName(), "blendFactor"); - QCOMPARE(change->value().value<float>(), lerpBlend.blendFactor()); - QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); - - arbiter.events.clear(); - } - - { - // WHEN - lerpBlend.setBlendFactor(0.4f); - QCoreApplication::processEvents(); - - // THEN - QCOMPARE(arbiter.events.size(), 0); - } - - } - -}; - -QTEST_MAIN(tst_QLerpBlend) - -#include "tst_qlerpblend.moc" diff --git a/tests/auto/animation/qlerpclipblend/qlerpclipblend.pro b/tests/auto/animation/qlerpclipblend/qlerpclipblend.pro new file mode 100644 index 000000000..3c26dbb19 --- /dev/null +++ b/tests/auto/animation/qlerpclipblend/qlerpclipblend.pro @@ -0,0 +1,12 @@ +TEMPLATE = app + +TARGET = tst_qlerpclipblend + +QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_qlerpclipblend.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp b/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp new file mode 100644 index 000000000..057f37786 --- /dev/null +++ b/tests/auto/animation/qlerpclipblend/tst_qlerpclipblend.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Paul Lemire <paul.lemire350@gmail.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QTest> +#include <Qt3DAnimation/qlerpclipblend.h> +#include <Qt3DAnimation/qanimationcliploader.h> +#include <Qt3DAnimation/private/qlerpclipblend_p.h> +#include <QObject> +#include <QSignalSpy> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> +#include <Qt3DAnimation/qclipblendnodecreatedchange.h> +#include <Qt3DCore/qnodecreatedchange.h> +#include "testpostmanarbiter.h" + +class tst_QLerpClipBlend : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase() + { + qRegisterMetaType<Qt3DAnimation::QAbstractClipBlendNode*>(); + } + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + + // THEN + QCOMPARE(lerpBlend.blendFactor(), 0.0f); + QCOMPARE(lerpBlend.startClip(), static_cast<Qt3DAnimation::QAbstractClipBlendNode *>(nullptr)); + QCOMPARE(lerpBlend.endClip(), static_cast<Qt3DAnimation::QAbstractClipBlendNode *>(nullptr)); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + + { + // WHEN + QSignalSpy spy(&lerpBlend, SIGNAL(blendFactorChanged(float))); + const float newValue = 0.5f; + lerpBlend.setBlendFactor(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(lerpBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + lerpBlend.setBlendFactor(newValue); + + // THEN + QCOMPARE(lerpBlend.blendFactor(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + QSignalSpy spy(&lerpBlend, SIGNAL(startClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QLerpClipBlend(); + lerpBlend.setStartClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(lerpBlend.startClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + lerpBlend.setStartClip(newValue); + + // THEN + QCOMPARE(lerpBlend.startClip(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + QSignalSpy spy(&lerpBlend, SIGNAL(endClipChanged(Qt3DAnimation::QAbstractClipBlendNode*))); + auto newValue = new Qt3DAnimation::QLerpClipBlend(); + lerpBlend.setEndClip(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(lerpBlend.endClip(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + lerpBlend.setEndClip(newValue); + + // THEN + QCOMPARE(lerpBlend.endClip(), newValue); + QCOMPARE(spy.count(), 0); + } + } + + void checkCreationData() + { + // GIVEN + Qt3DAnimation::QLerpClipBlend lerpBlend; + Qt3DAnimation::QLerpClipBlend startClip; + Qt3DAnimation::QLerpClipBlend endClip; + + lerpBlend.setStartClip(&startClip); + lerpBlend.setEndClip(&endClip); + lerpBlend.setBlendFactor(0.8f); + + + // WHEN + QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges; + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QLerpClipBlendData>>(creationChanges.first()); + const Qt3DAnimation::QLerpClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); + QCOMPARE(lerpBlend.isEnabled(), true); + QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.startClipId, startClip.id()); + QCOMPARE(cloneData.endClipId, endClip.id()); + } + + // WHEN + lerpBlend.setEnabled(false); + + { + Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&lerpBlend); + creationChanges = creationChangeGenerator.creationChanges(); + } + + // THEN + { + QCOMPARE(creationChanges.size(), 3); // 1 + 2 clips + + const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QClipBlendNodeCreatedChange<Qt3DAnimation::QLerpClipBlendData>>(creationChanges.first()); + const Qt3DAnimation::QLerpClipBlendData cloneData = creationChangeData->data; + + QCOMPARE(lerpBlend.blendFactor(), cloneData.blendFactor); + QCOMPARE(lerpBlend.id(), creationChangeData->subjectId()); + QCOMPARE(lerpBlend.isEnabled(), false); + QCOMPARE(lerpBlend.isEnabled(), creationChangeData->isNodeEnabled()); + QCOMPARE(lerpBlend.metaObject(), creationChangeData->metaObject()); + QCOMPARE(cloneData.startClipId, startClip.id()); + QCOMPARE(cloneData.endClipId, endClip.id()); + } + } + + void checkBlendFactorUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QLerpClipBlend lerpBlend; + arbiter.setArbiterOnNode(&lerpBlend); + + { + // WHEN + lerpBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "blendFactor"); + QCOMPARE(change->value().value<float>(), lerpBlend.blendFactor()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + lerpBlend.setBlendFactor(0.4f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } + + void checkStartClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QLerpClipBlend lerpBlend; + arbiter.setArbiterOnNode(&lerpBlend); + auto startClip = new Qt3DAnimation::QLerpClipBlend(); + + { + // WHEN + lerpBlend.setStartClip(startClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "startClip"); + QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), lerpBlend.startClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + lerpBlend.setStartClip(startClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkEndClipUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QLerpClipBlend lerpBlend; + arbiter.setArbiterOnNode(&lerpBlend); + auto endClip = new Qt3DAnimation::QLerpClipBlend(); + + { + // WHEN + lerpBlend.setEndClip(endClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "endClip"); + QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), lerpBlend.endClip()->id()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + lerpBlend.setEndClip(endClip); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + } + + void checkStartClipBookkeeping() + { + // GIVEN + QScopedPointer<Qt3DAnimation::QLerpClipBlend> lerpBlend(new Qt3DAnimation::QLerpClipBlend); + { + // WHEN + Qt3DAnimation::QLerpClipBlend clip; + lerpBlend->setStartClip(&clip); + + // THEN + QCOMPARE(clip.parent(), lerpBlend.data()); + QCOMPARE(lerpBlend->startClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(lerpBlend->startClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QLerpClipBlend someOtherLerpBlend; + QScopedPointer<Qt3DAnimation::QLerpClipBlend> clip(new Qt3DAnimation::QLerpClipBlend(&someOtherLerpBlend)); + lerpBlend->setStartClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherLerpBlend); + QCOMPARE(lerpBlend->startClip(), clip.data()); + + // WHEN + lerpBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } + + void checkEndClipBookkeeping() + { + // GIVEN + QScopedPointer<Qt3DAnimation::QLerpClipBlend> lerpBlend(new Qt3DAnimation::QLerpClipBlend); + { + // WHEN + Qt3DAnimation::QLerpClipBlend clip; + lerpBlend->setEndClip(&clip); + + // THEN + QCOMPARE(clip.parent(), lerpBlend.data()); + QCOMPARE(lerpBlend->endClip(), &clip); + } + // THEN (Should not crash and clip be unset) + QVERIFY(lerpBlend->endClip() == nullptr); + + { + // WHEN + Qt3DAnimation::QLerpClipBlend someOtherLerpBlend; + QScopedPointer<Qt3DAnimation::QLerpClipBlend> clip(new Qt3DAnimation::QLerpClipBlend(&someOtherLerpBlend)); + lerpBlend->setEndClip(clip.data()); + + // THEN + QCOMPARE(clip->parent(), &someOtherLerpBlend); + QCOMPARE(lerpBlend->endClip(), clip.data()); + + // WHEN + lerpBlend.reset(); + clip.reset(); + + // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) + } + } +}; + +QTEST_MAIN(tst_QLerpClipBlend) + +#include "tst_qlerpclipblend.moc" diff --git a/tests/auto/animation/qmorphinganimation/qmorphinganimation.pro b/tests/auto/animation/qmorphinganimation/qmorphinganimation.pro new file mode 100644 index 000000000..aaad3b763 --- /dev/null +++ b/tests/auto/animation/qmorphinganimation/qmorphinganimation.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +TARGET = tst_qmorphinganimation + +QT += 3dcore 3dcore-private 3drender 3drender-private 3danimation testlib + +CONFIG += testcase + +SOURCES += tst_qmorphinganimation.cpp + diff --git a/tests/auto/animation/qmorphinganimation/tst_qmorphinganimation.cpp b/tests/auto/animation/qmorphinganimation/tst_qmorphinganimation.cpp new file mode 100644 index 000000000..77ff01851 --- /dev/null +++ b/tests/auto/animation/qmorphinganimation/tst_qmorphinganimation.cpp @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <Qt3DAnimation/qmorphinganimation.h> +#include <qobject.h> +#include <qsignalspy.h> + +class tst_QMorphingAnimation : public QObject +{ + Q_OBJECT + + bool verifyAttribute(Qt3DRender::QGeometry *geometry, QString name, + Qt3DRender::QAttribute *attribute) + { + const QVector<Qt3DRender::QAttribute *> attributes = geometry->attributes(); + for (const Qt3DRender::QAttribute *attr : attributes) { + if (attr->name() == name) { + if (attr == attribute) + return true; + return false; + } + } + return false; + } + +private Q_SLOTS: + + void initTestCase() + { + qRegisterMetaType<Qt3DAnimation::QMorphingAnimation::Method>("QMorphingAnimation::Method"); + } + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QMorphingAnimation morphingAnimation; + + // THEN + QCOMPARE(morphingAnimation.interpolator(), 0.0f); + QCOMPARE(morphingAnimation.target(), nullptr); + QCOMPARE(morphingAnimation.targetName(), QString()); + QCOMPARE(morphingAnimation.method(), Qt3DAnimation::QMorphingAnimation::Relative); + QCOMPARE(morphingAnimation.easing(), QEasingCurve()); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QMorphingAnimation morphingAnimation; + + { + // WHEN + QScopedPointer<Qt3DRender::QGeometryRenderer> gr(new Qt3DRender::QGeometryRenderer); + QSignalSpy spy(&morphingAnimation, + SIGNAL(targetChanged(Qt3DRender::QGeometryRenderer *))); + Qt3DRender::QGeometryRenderer *newValue = gr.data(); + morphingAnimation.setTarget(newValue); + + // THEN + QCOMPARE(morphingAnimation.target(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + morphingAnimation.setTarget(newValue); + + // THEN + QCOMPARE(morphingAnimation.target(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&morphingAnimation, SIGNAL(targetNameChanged(QString))); + const QString newValue = QString("target"); + morphingAnimation.setTargetName(newValue); + + // THEN + QCOMPARE(morphingAnimation.targetName(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + morphingAnimation.setTargetName(newValue); + + // THEN + QCOMPARE(morphingAnimation.targetName(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&morphingAnimation, SIGNAL(methodChanged(QMorphingAnimation::Method))); + const Qt3DAnimation::QMorphingAnimation::Method newValue + = Qt3DAnimation::QMorphingAnimation::Normalized; + morphingAnimation.setMethod(newValue); + + // THEN + QCOMPARE(morphingAnimation.method(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + morphingAnimation.setMethod(newValue); + + // THEN + QCOMPARE(morphingAnimation.method(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&morphingAnimation, SIGNAL(easingChanged(QEasingCurve))); + const QEasingCurve newValue = QEasingCurve(QEasingCurve::InBounce); + morphingAnimation.setEasing(newValue); + + // THEN + QCOMPARE(morphingAnimation.easing(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + morphingAnimation.setEasing(newValue); + + // THEN + QCOMPARE(morphingAnimation.easing(), newValue); + QCOMPARE(spy.count(), 0); + + } + } + + void testAnimation() + { + // GIVEN + const QString baseName("position"); + const QString targetName("positionTarget"); + Qt3DAnimation::QMorphingAnimation morphingAnimation; + Qt3DRender::QAttribute *base = new Qt3DRender::QAttribute; + + Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry; + Qt3DAnimation::QMorphTarget *mt1 = new Qt3DAnimation::QMorphTarget(&morphingAnimation); + Qt3DAnimation::QMorphTarget *mt2 = new Qt3DAnimation::QMorphTarget(&morphingAnimation); + Qt3DAnimation::QMorphTarget *mt3 = new Qt3DAnimation::QMorphTarget(&morphingAnimation); + Qt3DRender::QAttribute *a1 = new Qt3DRender::QAttribute(geometry); + Qt3DRender::QAttribute *a2 = new Qt3DRender::QAttribute(geometry); + Qt3DRender::QAttribute *a3 = new Qt3DRender::QAttribute(geometry); + Qt3DRender::QGeometryRenderer gr; + + base->setName(baseName); + geometry->addAttribute(base); + gr.setGeometry(geometry); + morphingAnimation.setTarget(&gr); + a1->setName(baseName); + a2->setName(baseName); + a3->setName(baseName); + mt1->addAttribute(a1); + mt2->addAttribute(a2); + mt3->addAttribute(a3); + morphingAnimation.addMorphTarget(mt1); + morphingAnimation.addMorphTarget(mt2); + morphingAnimation.addMorphTarget(mt3); + + QVector<float> positions; + QVector<float> weights; + positions.push_back(0.0f); + positions.push_back(1.0f); + positions.push_back(2.0f); + positions.push_back(3.0f); + positions.push_back(4.0f); + morphingAnimation.setTargetPositions(positions); + + weights.resize(3); + + weights[0] = 1.0f; + weights[1] = 0.0f; + weights[2] = 0.0f; + morphingAnimation.setWeights(0, weights); + weights[0] = 0.0f; + weights[1] = 0.0f; + weights[2] = 0.0f; + morphingAnimation.setWeights(1, weights); + weights[0] = 0.0f; + weights[1] = 1.0f; + weights[2] = 0.0f; + morphingAnimation.setWeights(2, weights); + weights[0] = 0.0f; + weights[1] = 0.0f; + weights[2] = 0.0f; + morphingAnimation.setWeights(3, weights); + weights[0] = 0.0f; + weights[1] = 0.0f; + weights[2] = 1.0f; + morphingAnimation.setWeights(4, weights); + + morphingAnimation.setMethod(Qt3DAnimation::QMorphingAnimation::Relative); + { + // WHEN + morphingAnimation.setPosition(0.0f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), -1.0f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a1)); + + // WHEN + morphingAnimation.setPosition(0.5f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), -0.5f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a1)); + + // WHEN + morphingAnimation.setPosition(1.0f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), -0.0f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + + // WHEN + morphingAnimation.setPosition(1.5f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), -0.5f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a2)); + + // WHEN + morphingAnimation.setPosition(4.0f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), -1.0f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a3)); + } + + morphingAnimation.setMethod(Qt3DAnimation::QMorphingAnimation::Normalized); + { + // WHEN + morphingAnimation.setPosition(0.0f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), 1.0f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a1)); + + // WHEN + morphingAnimation.setPosition(0.5f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), 0.5f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a1)); + + // WHEN + morphingAnimation.setPosition(1.0f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), 0.0f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + + // WHEN + morphingAnimation.setPosition(1.5f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), 0.5f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a2)); + + // WHEN + morphingAnimation.setPosition(4.0f); + + // THEN + QVERIFY(qFuzzyCompare(morphingAnimation.interpolator(), 1.0f)); + QVERIFY(verifyAttribute(geometry, baseName, base)); + QVERIFY(verifyAttribute(geometry, targetName, a3)); + } + } +}; + +QTEST_APPLESS_MAIN(tst_QMorphingAnimation) + +#include "tst_qmorphinganimation.moc" diff --git a/tests/auto/animation/qmorphtarget/qmorphtarget.pro b/tests/auto/animation/qmorphtarget/qmorphtarget.pro new file mode 100644 index 000000000..bb38aad19 --- /dev/null +++ b/tests/auto/animation/qmorphtarget/qmorphtarget.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +TARGET = tst_qmorphtarget + +QT += 3dcore 3dcore-private 3drender 3drender-private 3danimation testlib + +CONFIG += testcase + +SOURCES += tst_qmorphtarget.cpp + diff --git a/tests/auto/animation/qmorphtarget/tst_qmorphtarget.cpp b/tests/auto/animation/qmorphtarget/tst_qmorphtarget.cpp new file mode 100644 index 000000000..2cba9ba2a --- /dev/null +++ b/tests/auto/animation/qmorphtarget/tst_qmorphtarget.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <Qt3DAnimation/qmorphtarget.h> +#include <qobject.h> +#include <qsignalspy.h> + +class tst_QMorphTarget : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QMorphTarget morphTarget; + + // THEN + QCOMPARE(morphTarget.attributeNames(), QStringList()); + } + + void testSetAttributes() + { + // GIVEN + Qt3DAnimation::QMorphTarget morphTarget; + Qt3DRender::QAttribute attribute1; + Qt3DRender::QAttribute attribute2; + + attribute1.setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + attribute2.setName(Qt3DRender::QAttribute::defaultNormalAttributeName()); + + { + // WHEN + morphTarget.addAttribute(&attribute1); + + // THEN + QStringList names = morphTarget.attributeNames(); + QCOMPARE(names.size(), 1); + QCOMPARE(names.at(0), Qt3DRender::QAttribute::defaultPositionAttributeName()); + } + + { + // WHEN + morphTarget.addAttribute(&attribute2); + + // THEN + QStringList names = morphTarget.attributeNames(); + QCOMPARE(names.size(), 2); + QCOMPARE(names.at(1), Qt3DRender::QAttribute::defaultNormalAttributeName()); + } + } + + void testFromGeometry() + { + // GIVEN + Qt3DRender::QGeometry geometry; + Qt3DRender::QAttribute *attribute1 = new Qt3DRender::QAttribute; + Qt3DRender::QAttribute *attribute2 = new Qt3DRender::QAttribute; + attribute1->setName(Qt3DRender::QAttribute::defaultPositionAttributeName()); + attribute2->setName(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName()); + geometry.addAttribute(attribute1); + geometry.addAttribute(attribute2); + + QStringList attributes; + attributes.push_back(Qt3DRender::QAttribute::defaultPositionAttributeName()); + + { + // WHEN + QScopedPointer<Qt3DAnimation::QMorphTarget> morphTarget( + Qt3DAnimation::QMorphTarget::fromGeometry(&geometry, attributes)); + + // THEN + QStringList names = morphTarget->attributeNames(); + QCOMPARE(names.size(), 1); + QCOMPARE(names.at(0), Qt3DRender::QAttribute::defaultPositionAttributeName()); + } + + { + // WHEN + attributes.push_back(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName()); + QScopedPointer<Qt3DAnimation::QMorphTarget> morphTarget( + Qt3DAnimation::QMorphTarget::fromGeometry(&geometry, attributes)); + + // THEN + QStringList names = morphTarget->attributeNames(); + QCOMPARE(names.size(), 2); + QCOMPARE(names.at(0), Qt3DRender::QAttribute::defaultPositionAttributeName()); + QCOMPARE(names.at(1), Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName()); + } + } + +}; + +QTEST_APPLESS_MAIN(tst_QMorphTarget) + +#include "tst_qmorphtarget.moc" diff --git a/tests/auto/animation/qvertexblendanimation/qvertexblendanimation.pro b/tests/auto/animation/qvertexblendanimation/qvertexblendanimation.pro new file mode 100644 index 000000000..8079ebf15 --- /dev/null +++ b/tests/auto/animation/qvertexblendanimation/qvertexblendanimation.pro @@ -0,0 +1,10 @@ +TEMPLATE = app + +TARGET = tst_qvertexblendanimation + +QT += 3dcore 3dcore-private 3drender 3drender-private 3danimation testlib + +CONFIG += testcase + +SOURCES += tst_qvertexblendanimation.cpp + diff --git a/tests/auto/animation/qvertexblendanimation/tst_qvertexblendanimation.cpp b/tests/auto/animation/qvertexblendanimation/tst_qvertexblendanimation.cpp new file mode 100644 index 000000000..dc27e4a7e --- /dev/null +++ b/tests/auto/animation/qvertexblendanimation/tst_qvertexblendanimation.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <Qt3DAnimation/qvertexblendanimation.h> +#include <qobject.h> +#include <qsignalspy.h> + +class tst_QVertexBlendAnimation : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void checkDefaultConstruction() + { + // GIVEN + Qt3DAnimation::QVertexBlendAnimation vertexBlendAnimation; + + // THEN + QCOMPARE(vertexBlendAnimation.interpolator(), 0.0f); + QCOMPARE(vertexBlendAnimation.target(), nullptr); + QCOMPARE(vertexBlendAnimation.targetName(), QString()); + } + + void checkPropertyChanges() + { + // GIVEN + Qt3DAnimation::QVertexBlendAnimation vertexBlendAnimation; + + { + // WHEN + QScopedPointer<Qt3DRender::QGeometryRenderer> gm(new Qt3DRender::QGeometryRenderer); + QSignalSpy spy(&vertexBlendAnimation, + SIGNAL(targetChanged(Qt3DRender::QGeometryRenderer *))); + Qt3DRender::QGeometryRenderer *newValue = gm.data(); + vertexBlendAnimation.setTarget(newValue); + + // THEN + QCOMPARE(vertexBlendAnimation.target(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + vertexBlendAnimation.setTarget(newValue); + + // THEN + QCOMPARE(vertexBlendAnimation.target(), newValue); + QCOMPARE(spy.count(), 0); + + } + { + // WHEN + QSignalSpy spy(&vertexBlendAnimation, SIGNAL(targetNameChanged(QString))); + const QString newValue = QString("target"); + vertexBlendAnimation.setTargetName(newValue); + + // THEN + QCOMPARE(vertexBlendAnimation.targetName(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + vertexBlendAnimation.setTargetName(newValue); + + // THEN + QCOMPARE(vertexBlendAnimation.targetName(), newValue); + QCOMPARE(spy.count(), 0); + + } + } + +}; + +QTEST_APPLESS_MAIN(tst_QVertexBlendAnimation) + +#include "tst_qvertexblendanimation.moc" |