diff options
author | Juan Jose Casafranca <juan.casafranca@kdab.com> | 2019-08-04 18:57:07 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2019-09-23 10:20:50 +0200 |
commit | 968be8e9ee0851d401d302621eccc1de415ec243 (patch) | |
tree | 2cf6fbe54943831511bec9e266540036af622166 /tests | |
parent | 18d84627842e0ccece92d5e8ed91db537aeeabdb (diff) |
Add a property map job in animation aspect
ClipAnimator is always dirty because at each frame the normalizedTime is
changed. This has a big performance penalisation as we are launching
job which updates the property map at each frame.
This patch adds a new dirty flag which is use to decide if the animator
need to update the mapping of the fcurve to actual node properties.
Using that flag, a new UpdatePropertyMapJob is launched for dirty
clipAnimators.
Some scenes boost from 30fps to 60fps (vsync) during animation.
Change-Id: Ic8a8db01535c55995bc569ea5a69660a40014401
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'tests')
8 files changed, 547 insertions, 89 deletions
diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro index c600da690..2b8d9d385 100644 --- a/tests/auto/animation/animation.pro +++ b/tests/auto/animation/animation.pro @@ -40,5 +40,6 @@ qtConfig(private_tests) { clock \ skeleton \ findrunningclipanimatorsjob \ + updatepropertymapjob \ qchannelmapping } diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp index 36f1cbe2f..d2825c2b7 100644 --- a/tests/auto/animation/animationutils/tst_animationutils.cpp +++ b/tests/auto/animation/animationutils/tst_animationutils.cpp @@ -203,6 +203,7 @@ public: auto animatorId = Qt3DCore::QNodeId::createId(); ClipAnimator *animator = handler->clipAnimatorManager()->getOrCreateResource(animatorId); setPeerId(animator, animatorId); + animator->setHandler(handler); animator->setStartTime(globalStartTimeNS); animator->setLoops(loops); return animator; diff --git a/tests/auto/animation/clipanimator/tst_clipanimator.cpp b/tests/auto/animation/clipanimator/tst_clipanimator.cpp index 0272bcfaa..fbe865220 100644 --- a/tests/auto/animation/clipanimator/tst_clipanimator.cpp +++ b/tests/auto/animation/clipanimator/tst_clipanimator.cpp @@ -28,9 +28,12 @@ #include <QtTest/QTest> #include <Qt3DAnimation/private/clipanimator_p.h> +#include <Qt3DAnimation/private/managers_p.h> +#include <Qt3DAnimation/private/handle_types_p.h> #include <Qt3DAnimation/qanimationcliploader.h> #include <Qt3DAnimation/qclipanimator.h> #include <Qt3DAnimation/qclock.h> +#include <Qt3DAnimation/qchannelmapper.h> #include <Qt3DCore/private/qnode_p.h> #include <Qt3DCore/private/qscene_p.h> #include <Qt3DCore/qpropertyupdatedchange.h> @@ -69,6 +72,9 @@ private Q_SLOTS: QCOMPARE(backendAnimator.isRunning(), animator.isRunning()); QCOMPARE(backendAnimator.loops(), animator.loopCount()); QCOMPARE(backendAnimator.normalizedLocalTime(), animator.normalizedTime()); + + QCOMPARE(handler.m_dirtyClipAnimators.size(), 1); + QCOMPARE(handler.m_dirtyClipAnimatorMaps.size(), 1); } void checkInitialAndCleanedUpState() @@ -120,6 +126,8 @@ private Q_SLOTS: backendAnimator.setHandler(&handler); Qt3DCore::QPropertyUpdatedChangePtr updateChange; + handler.clipAnimatorManager()->getOrAcquireHandle(backendAnimator.peerId()); + // WHEN updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId()); updateChange->setPropertyName("enabled"); @@ -135,9 +143,13 @@ private Q_SLOTS: updateChange->setPropertyName("clip"); updateChange->setValue(QVariant::fromValue(newClip->id())); backendAnimator.sceneChangeEvent(updateChange); - // THEN QCOMPARE(backendAnimator.clipId(), newClip->id()); + QCOMPARE(handler.m_dirtyClipAnimators.size(), 1); + QCOMPARE(handler.m_dirtyClipAnimatorMaps.size(), 1); + + handler.m_dirtyClipAnimators.clear(); + handler.m_dirtyClipAnimatorMaps.clear(); // WHEN auto clock = new Qt3DAnimation::QClock(); @@ -148,6 +160,24 @@ private Q_SLOTS: // THEN QCOMPARE(backendAnimator.clockId(), clock->id()); + QCOMPARE(handler.m_dirtyClipAnimators.size(), 1); + QCOMPARE(handler.m_dirtyClipAnimatorMaps.size(), 0); + + handler.m_dirtyClipAnimators.clear(); + + // WHEN + auto mapper = new Qt3DAnimation::QChannelMapper(); + updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId()); + updateChange->setPropertyName("channelMapper"); + updateChange->setValue(QVariant::fromValue(mapper->id())); + backendAnimator.sceneChangeEvent(updateChange); + + // THEN + QCOMPARE(backendAnimator.mapperId(), mapper->id()); + QCOMPARE(handler.m_dirtyClipAnimators.size(), 0); + QCOMPARE(handler.m_dirtyClipAnimatorMaps.size(), 1); + + handler.m_dirtyClipAnimatorMaps.clear(); // WHEN updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId()); @@ -157,6 +187,11 @@ private Q_SLOTS: // THEN QCOMPARE(backendAnimator.isRunning(), true); + QCOMPARE(handler.m_dirtyClipAnimators.size(), 1); + QCOMPARE(handler.m_dirtyClipAnimatorMaps.size(), 1); + + handler.m_dirtyClipAnimators.clear(); + handler.m_dirtyClipAnimatorMaps.clear(); // WHEN updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId()); @@ -166,6 +201,10 @@ private Q_SLOTS: // THEN QCOMPARE(backendAnimator.loops(), 64); + QCOMPARE(handler.m_dirtyClipAnimators.size(), 1); + QCOMPARE(handler.m_dirtyClipAnimatorMaps.size(), 0); + + handler.m_dirtyClipAnimators.clear(); // WHEN updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId()); @@ -175,6 +214,10 @@ private Q_SLOTS: // THEN QVERIFY(qFuzzyCompare(backendAnimator.normalizedLocalTime(), 0.5f)); + QCOMPARE(handler.m_dirtyClipAnimators.size(), 1); + QCOMPARE(handler.m_dirtyClipAnimatorMaps.size(), 0); + + handler.m_dirtyClipAnimators.clear(); } }; diff --git a/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp b/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp index 5d71b7dc6..777d2a21a 100644 --- a/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp +++ b/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp @@ -49,54 +49,26 @@ using namespace Qt3DAnimation::Animation; Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*) Q_DECLARE_METATYPE(QVector<Qt3DAnimation::Animation::HClipAnimator>) -typedef QHash<ClipAnimator*, QVector<Qt3DAnimation::Animation::MappingData>> MappingDataResults; -Q_DECLARE_METATYPE(MappingDataResults) - class tst_FindRunningClipAnimatorsJob: public Qt3DCore::QBackendNodeTester { Q_OBJECT public: - ChannelMapping *createChannelMapping(Handler *handler, - const QString &channelName, - const Qt3DCore::QNodeId targetId, - const char *propertyName, - int type, - int componentCount) - { - auto channelMappingId = Qt3DCore::QNodeId::createId(); - ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(channelMappingId); - setPeerId(channelMapping, channelMappingId); - channelMapping->setHandler(handler); - channelMapping->setTargetId(targetId); - channelMapping->setPropertyName(propertyName); - channelMapping->setChannelName(channelName); - channelMapping->setType(type); - channelMapping->setComponentCount(componentCount); - channelMapping->setMappingType(ChannelMapping::ChannelMappingType); - return channelMapping; - } - - ChannelMapper *createChannelMapper(Handler *handler, - const QVector<Qt3DCore::QNodeId> &mappingIds) + ChannelMapper *createChannelMapper(Handler *handler) { auto channelMapperId = Qt3DCore::QNodeId::createId(); ChannelMapper *channelMapper = handler->channelMapperManager()->getOrCreateResource(channelMapperId); setPeerId(channelMapper, channelMapperId); channelMapper->setHandler(handler); - channelMapper->setMappingIds(mappingIds); return channelMapper; } - AnimationClip *createAnimationClipLoader(Handler *handler, - const QUrl &source) + AnimationClip *createAnimationClip(Handler *handler) { auto clipId = Qt3DCore::QNodeId::createId(); AnimationClip *clip = handler->animationClipLoaderManager()->getOrCreateResource(clipId); setPeerId(clip, clipId); clip->setHandler(handler); - clip->setDataType(AnimationClip::File); - clip->setSource(source); - clip->loadAnimation(); + clip->setDuration(100); return clip; } @@ -118,18 +90,36 @@ private Q_SLOTS: { QTest::addColumn<Handler *>("handler"); QTest::addColumn<QVector<HClipAnimator>>("dirtyClipAnimators"); - QTest::addColumn<MappingDataResults>("expectedResults"); + QTest::addColumn<bool>("isRunning"); + { + Handler *handler; + ClipAnimator *animator; + QVector<HClipAnimator> dirtyClipAnimators; + handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + dirtyClipAnimators = (QVector<HClipAnimator>() + << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); + + animator->setRunning(true); // Has to be marked as running for the job to process it + animator->setEnabled(true); // Has to be marked as enabled for the job to process it + + QTest::newRow("Missing clip and mapping") + << handler + << dirtyClipAnimators + << false; + } { Handler *handler; AnimationClip *clip; ClipAnimator *animator; QVector<HClipAnimator> dirtyClipAnimators; - ChannelMapper *channelMapper; - MappingDataResults expectedResults; handler = new Handler(); - clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + clip = createAnimationClip(handler); const qint64 globalStartTimeNS = 0; const int loops = 1; @@ -138,69 +128,121 @@ private Q_SLOTS: dirtyClipAnimators = (QVector<HClipAnimator>() << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); - auto channelMapping = createChannelMapping(handler, - QLatin1String("Location"), - Qt3DCore::QNodeId::createId(), - "translation", - static_cast<int>(QVariant::Vector3D), - 3); - QVector<ChannelMapping *> channelMappings; - channelMappings.push_back(channelMapping); - - channelMapper = createChannelMapper(handler, QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); - animator->setMapperId(channelMapper->peerId()); animator->setRunning(true); // Has to be marked as running for the job to process it animator->setEnabled(true); // Has to be marked as enabled for the job to process it - const ComponentIndices locationIndices = { 0, 1, 2 }; - MappingData expectedMapping; - expectedMapping.targetId = channelMapping->targetId(); - expectedMapping.propertyName = channelMapping->propertyName(); - expectedMapping.type = channelMapping->type(); - expectedMapping.channelIndices = locationIndices; - expectedResults.insert(animator, QVector<MappingData>() << expectedMapping); - - QTest::newRow("single mapping") + QTest::newRow("Missing mapper") << handler << dirtyClipAnimators - << expectedResults; + << false; } { Handler *handler; - AnimationClip *clip; ClipAnimator *animator; QVector<HClipAnimator> dirtyClipAnimators; ChannelMapper *channelMapper; - MappingDataResults expectedResults; handler = new Handler(); - clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); const qint64 globalStartTimeNS = 0; const int loops = 1; animator = createClipAnimator(handler, globalStartTimeNS, loops); - animator->setClipId(clip->peerId()); dirtyClipAnimators = (QVector<HClipAnimator>() << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); - auto channelMapping = createChannelMapping(handler, - QLatin1String("Location"), - Qt3DCore::QNodeId::createId(), - "translation", - static_cast<int>(QVariant::Vector3D), - 3); - QVector<ChannelMapping *> channelMappings; - channelMappings.push_back(channelMapping); + channelMapper = createChannelMapper(handler); + animator->setMapperId(channelMapper->peerId()); + animator->setRunning(true); // Has to be marked as running for the job to process it + animator->setEnabled(false); // Has to be marked as enabled for the job to process it - channelMapper = createChannelMapper(handler, QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); + QTest::newRow("Missing clip") + << handler + << dirtyClipAnimators + << false; + } + + { + Handler *handler; + AnimationClip *clip; + ClipAnimator *animator; + QVector<HClipAnimator> dirtyClipAnimators; + ChannelMapper *channelMapper; + handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + dirtyClipAnimators = (QVector<HClipAnimator>() + << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); + + clip = createAnimationClip(handler); + animator->setClipId(clip->peerId()); + + channelMapper = createChannelMapper(handler); animator->setMapperId(channelMapper->peerId()); animator->setRunning(true); // Has to be marked as running for the job to process it animator->setEnabled(false); // Has to be marked as enabled for the job to process it - QTest::newRow("disabled animator") + QTest::newRow("Aniamtor disabled") << handler << dirtyClipAnimators - << expectedResults; + << false; + } + + { + Handler *handler; + AnimationClip *clip; + ClipAnimator *animator; + QVector<HClipAnimator> dirtyClipAnimators; + ChannelMapper *channelMapper; + handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + dirtyClipAnimators = (QVector<HClipAnimator>() + << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); + + clip = createAnimationClip(handler); + animator->setClipId(clip->peerId()); + + channelMapper = createChannelMapper(handler); + animator->setMapperId(channelMapper->peerId()); + animator->setRunning(false); // Has to be marked as running for the job to process it + animator->setEnabled(true); // Has to be marked as enabled for the job to process it + + QTest::newRow("Animator not running") + << handler + << dirtyClipAnimators + << false; + } + + { + Handler *handler; + AnimationClip *clip; + ClipAnimator *animator; + QVector<HClipAnimator> dirtyClipAnimators; + ChannelMapper *channelMapper; + handler = new Handler(); + + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + dirtyClipAnimators = (QVector<HClipAnimator>() + << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); + + clip = createAnimationClip(handler); + animator->setClipId(clip->peerId()); + + channelMapper = createChannelMapper(handler); + animator->setMapperId(channelMapper->peerId()); + animator->setRunning(true); // Has to be marked as running for the job to process it + animator->setEnabled(true); // Has to be marked as enabled for the job to process it + + QTest::newRow("Animator running") + << handler + << dirtyClipAnimators + << true; } } @@ -209,7 +251,7 @@ private Q_SLOTS: // GIVEN QFETCH(Handler *, handler); QFETCH(QVector<HClipAnimator>, dirtyClipAnimators); - QFETCH(MappingDataResults, expectedResults); + QFETCH(bool, isRunning); FindRunningClipAnimatorsJob job; // WHEN @@ -218,22 +260,10 @@ private Q_SLOTS: job.run(); // THEN - check the resulting MappingData on the animator matches the expected results - for (const auto &dirtyClipAnimator : dirtyClipAnimators) { - const auto animator = handler->clipAnimatorManager()->data(dirtyClipAnimator); - const QVector<MappingData> actualMappingData = animator->mappingData(); - const QVector<MappingData> expectedMappingData = expectedResults[animator]; - - QCOMPARE(expectedMappingData.size(), actualMappingData.size()); - for (int i = 0; i < actualMappingData.size(); ++i) { - QCOMPARE(expectedMappingData[i].targetId, actualMappingData[i].targetId); - QCOMPARE(expectedMappingData[i].type, actualMappingData[i].type); - QVERIFY(qstrcmp(expectedMappingData[i].propertyName, actualMappingData[i].propertyName) == 0); - QCOMPARE(expectedMappingData[i].channelIndices.size(), actualMappingData[i].channelIndices.size()); - - for (int j = 0; j < actualMappingData[i].channelIndices.size(); ++j) { - QCOMPARE(expectedMappingData[i].channelIndices[j], actualMappingData[i].channelIndices[j]); - } - } + for (const auto &dirtyClipAnimatorHandle : dirtyClipAnimators) { + + auto runningClipHandle = std::find(std::begin(handler->runningClipAnimators()), std::end(handler->runningClipAnimators()), dirtyClipAnimatorHandle); + QCOMPARE(runningClipHandle != std::end(handler->runningClipAnimators()), isRunning); } } }; diff --git a/tests/auto/animation/updatepropertymapjob/clip1.json b/tests/auto/animation/updatepropertymapjob/clip1.json new file mode 100644 index 000000000..a2ad365a8 --- /dev/null +++ b/tests/auto/animation/updatepropertymapjob/clip1.json @@ -0,0 +1,114 @@ +{ + "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" + } + ] + } + ] +} + diff --git a/tests/auto/animation/updatepropertymapjob/tst_updatepropertymapjob.cpp b/tests/auto/animation/updatepropertymapjob/tst_updatepropertymapjob.cpp new file mode 100644 index 000000000..2a9cc39d2 --- /dev/null +++ b/tests/auto/animation/updatepropertymapjob/tst_updatepropertymapjob.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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/qanimationcliploader.h> +#include <Qt3DAnimation/qclipanimator.h> +#include <Qt3DAnimation/qchannelmapper.h> +#include <Qt3DAnimation/qchannelmapping.h> +#include <Qt3DAnimation/private/clipanimator_p.h> +#include <Qt3DAnimation/private/channelmapper_p.h> +#include <Qt3DAnimation/private/channelmapping_p.h> +#include <Qt3DAnimation/private/updatepropertymapjob_p.h> +#include <Qt3DAnimation/private/findrunningclipanimatorsjob_p.h> +#include <Qt3DAnimation/private/handler_p.h> +#include <Qt3DAnimation/private/managers_p.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> + +using namespace Qt3DAnimation::Animation; + +Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*) +Q_DECLARE_METATYPE(QVector<Qt3DAnimation::Animation::HClipAnimator>) + +typedef QHash<ClipAnimator*, QVector<Qt3DAnimation::Animation::MappingData>> MappingDataResults; +Q_DECLARE_METATYPE(MappingDataResults) + +class tst_UpdatePropertyMapJob: public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT +public: + ChannelMapping *createChannelMapping(Handler *handler, + const QString &channelName, + const Qt3DCore::QNodeId targetId, + const char *propertyName, + int type, + int componentCount) + { + auto channelMappingId = Qt3DCore::QNodeId::createId(); + ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(channelMappingId); + setPeerId(channelMapping, channelMappingId); + channelMapping->setHandler(handler); + channelMapping->setTargetId(targetId); + channelMapping->setPropertyName(propertyName); + channelMapping->setChannelName(channelName); + channelMapping->setType(type); + channelMapping->setComponentCount(componentCount); + channelMapping->setMappingType(ChannelMapping::ChannelMappingType); + 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->setHandler(handler); + 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->setHandler(handler); + 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->setHandler(handler); + animator->setStartTime(globalStartTimeNS); + animator->setLoops(loops); + return animator; + } + +private Q_SLOTS: + void checkJob_data() + { + QTest::addColumn<Handler *>("handler"); + QTest::addColumn<QVector<HClipAnimator>>("dirtyClipAnimators"); + QTest::addColumn<MappingDataResults>("expectedResults"); + + + { + Handler *handler; + AnimationClip *clip; + ClipAnimator *animator; + QVector<HClipAnimator> dirtyClipAnimators; + ChannelMapper *channelMapper; + MappingDataResults expectedResults; + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + animator->setClipId(clip->peerId()); + dirtyClipAnimators = (QVector<HClipAnimator>() + << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); + + auto channelMapping = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + "translation", + static_cast<int>(QVariant::Vector3D), + 3); + QVector<ChannelMapping *> channelMappings; + channelMappings.push_back(channelMapping); + + channelMapper = createChannelMapper(handler, QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); + animator->setMapperId(channelMapper->peerId()); + animator->setRunning(true); // Has to be marked as running for the job to process it + animator->setEnabled(true); // Has to be marked as enabled for the job to process it + + const ComponentIndices locationIndices = { 0, 1, 2 }; + MappingData expectedMapping; + expectedMapping.targetId = channelMapping->targetId(); + expectedMapping.propertyName = channelMapping->propertyName(); + expectedMapping.type = channelMapping->type(); + expectedMapping.channelIndices = locationIndices; + expectedResults.insert(animator, QVector<MappingData>() << expectedMapping); + + QTest::newRow("single mapping") + << handler + << dirtyClipAnimators + << expectedResults; + } + + { + Handler *handler; + AnimationClip *clip; + ClipAnimator *animator; + QVector<HClipAnimator> dirtyClipAnimators; + ChannelMapper *channelMapper; + MappingDataResults expectedResults; + handler = new Handler(); + clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json")); + + const qint64 globalStartTimeNS = 0; + const int loops = 1; + animator = createClipAnimator(handler, globalStartTimeNS, loops); + animator->setClipId(clip->peerId()); + dirtyClipAnimators = (QVector<HClipAnimator>() + << handler->clipAnimatorManager()->getOrAcquireHandle(animator->peerId())); + + auto channelMapping = createChannelMapping(handler, + QLatin1String("Location"), + Qt3DCore::QNodeId::createId(), + "translation", + static_cast<int>(QVariant::Vector3D), + 3); + QVector<ChannelMapping *> channelMappings; + channelMappings.push_back(channelMapping); + + channelMapper = createChannelMapper(handler, QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); + animator->setMapperId(channelMapper->peerId()); + animator->setRunning(true); // Has to be marked as running for the job to process it + animator->setEnabled(false); // Has to be marked as enabled for the job to process it + + QTest::newRow("disabled animator") + << handler + << dirtyClipAnimators + << expectedResults; + } + } + + void checkJob() + { + // GIVEN + QFETCH(Handler *, handler); + QFETCH(QVector<HClipAnimator>, dirtyClipAnimators); + QFETCH(MappingDataResults, expectedResults); + FindRunningClipAnimatorsJob runningClipsJob; + UpdatePropertyMapJob job; + + // WHEN + runningClipsJob.setHandler(handler); + runningClipsJob.setDirtyClipAnimators(dirtyClipAnimators); + runningClipsJob.run(); + + job.setHandler(handler); + job.setDirtyClipAnimators(dirtyClipAnimators); + job.run(); + + // THEN - check the resulting MappingData on the animator matches the expected results + for (const auto &dirtyClipAnimator : dirtyClipAnimators) { + const auto animator = handler->clipAnimatorManager()->data(dirtyClipAnimator); + const QVector<MappingData> actualMappingData = animator->mappingData(); + const QVector<MappingData> expectedMappingData = expectedResults[animator]; + + QCOMPARE(expectedMappingData.size(), actualMappingData.size()); + for (int i = 0; i < actualMappingData.size(); ++i) { + QCOMPARE(expectedMappingData[i].targetId, actualMappingData[i].targetId); + QCOMPARE(expectedMappingData[i].type, actualMappingData[i].type); + QVERIFY(qstrcmp(expectedMappingData[i].propertyName, actualMappingData[i].propertyName) == 0); + QCOMPARE(expectedMappingData[i].channelIndices.size(), actualMappingData[i].channelIndices.size()); + + for (int j = 0; j < actualMappingData[i].channelIndices.size(); ++j) { + QCOMPARE(expectedMappingData[i].channelIndices[j], actualMappingData[i].channelIndices[j]); + } + } + } + } +}; + +QTEST_APPLESS_MAIN(tst_UpdatePropertyMapJob) + +#include "tst_updatepropertymapjob.moc" diff --git a/tests/auto/animation/updatepropertymapjob/updatepropertymapjob.pro b/tests/auto/animation/updatepropertymapjob/updatepropertymapjob.pro new file mode 100644 index 000000000..217fc76ec --- /dev/null +++ b/tests/auto/animation/updatepropertymapjob/updatepropertymapjob.pro @@ -0,0 +1,15 @@ +TEMPLATE = app + +TARGET = tst_updatepropertymapjob + +QT += core-private 3dcore 3dcore-private 3danimation 3danimation-private testlib + +CONFIG += testcase + +SOURCES += \ + tst_updatepropertymapjob.cpp + +include(../../core/common/common.pri) + +RESOURCES += \ + updatepropertymapjob.qrc diff --git a/tests/auto/animation/updatepropertymapjob/updatepropertymapjob.qrc b/tests/auto/animation/updatepropertymapjob/updatepropertymapjob.qrc new file mode 100644 index 000000000..72234ec64 --- /dev/null +++ b/tests/auto/animation/updatepropertymapjob/updatepropertymapjob.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>clip1.json</file> + </qresource> +</RCC> |