| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** GNU General Public License Usage |
| 18 | ** Alternatively, this file may be used under the terms of the GNU |
| 19 | ** General Public License version 3 as published by the Free Software |
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| 21 | ** included in the packaging of this file. Please review the following |
| 22 | ** information to ensure the GNU General Public License requirements will |
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| 24 | ** |
| 25 | ** $QT_END_LICENSE$ |
| 26 | ** |
| 27 | ****************************************************************************/ |
| 28 | |
| 29 | #include <QtTest/QTest> |
| 30 | #include <Qt3DAnimation/qanimationcliploader.h> |
| 31 | #include <Qt3DAnimation/qclipanimator.h> |
| 32 | #include <Qt3DAnimation/qchannelmapper.h> |
| 33 | #include <Qt3DAnimation/qchannelmapping.h> |
| 34 | #include <Qt3DAnimation/private/clipanimator_p.h> |
| 35 | #include <Qt3DAnimation/private/channelmapper_p.h> |
| 36 | #include <Qt3DAnimation/private/channelmapping_p.h> |
| 37 | #include <Qt3DAnimation/private/findrunningclipanimatorsjob_p.h> |
| 38 | #include <Qt3DAnimation/private/handler_p.h> |
| 39 | #include <Qt3DAnimation/private/managers_p.h> |
| 40 | #include <Qt3DCore/private/qnode_p.h> |
| 41 | #include <Qt3DCore/private/qscene_p.h> |
| 42 | #include <Qt3DCore/private/qbackendnode_p.h> |
| 43 | #include <qbackendnodetester.h> |
| 44 | #include <testpostmanarbiter.h> |
| 45 | |
| 46 | using namespace Qt3DAnimation::Animation; |
| 47 | |
| 48 | Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*) |
| 49 | Q_DECLARE_METATYPE(QVector<Qt3DAnimation::Animation::HClipAnimator>) |
| 50 | |
| 51 | typedef QHash<ClipAnimator*, QVector<Qt3DAnimation::Animation::MappingData>> MappingDataResults; |
| 52 | Q_DECLARE_METATYPE(MappingDataResults) |
| 53 | |
| 54 | class tst_FindRunningClipAnimatorsJob: public Qt3DCore::QBackendNodeTester |
| 55 | { |
| 56 | Q_OBJECT |
| 57 | public: |
| 58 | ChannelMapping *createChannelMapping(Handler *handler, |
| 59 | const QString &channelName, |
| 60 | const Qt3DCore::QNodeId targetId, |
| 61 | const char *propertyName, |
| 62 | int type, |
| 63 | int componentCount) |
| 64 | { |
| 65 | auto channelMappingId = Qt3DCore::QNodeId::createId(); |
| 66 | ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(id: channelMappingId); |
| 67 | setPeerId(backend: channelMapping, id: channelMappingId); |
| 68 | channelMapping->setHandler(handler); |
| 69 | channelMapping->setTargetId(targetId); |
| 70 | channelMapping->setPropertyName(propertyName); |
| 71 | channelMapping->setChannelName(channelName); |
| 72 | channelMapping->setType(type); |
| 73 | channelMapping->setComponentCount(componentCount); |
| 74 | channelMapping->setMappingType(ChannelMapping::ChannelMappingType); |
| 75 | return channelMapping; |
| 76 | } |
| 77 | |
| 78 | ChannelMapper *createChannelMapper(Handler *handler, |
| 79 | const QVector<Qt3DCore::QNodeId> &mappingIds) |
| 80 | { |
| 81 | auto channelMapperId = Qt3DCore::QNodeId::createId(); |
| 82 | ChannelMapper *channelMapper = handler->channelMapperManager()->getOrCreateResource(id: channelMapperId); |
| 83 | setPeerId(backend: channelMapper, id: channelMapperId); |
| 84 | channelMapper->setHandler(handler); |
| 85 | channelMapper->setMappingIds(mappingIds); |
| 86 | return channelMapper; |
| 87 | } |
| 88 | |
| 89 | AnimationClip *createAnimationClipLoader(Handler *handler, |
| 90 | const QUrl &source) |
| 91 | { |
| 92 | auto clipId = Qt3DCore::QNodeId::createId(); |
| 93 | AnimationClip *clip = handler->animationClipLoaderManager()->getOrCreateResource(id: clipId); |
| 94 | setPeerId(backend: clip, id: clipId); |
| 95 | clip->setHandler(handler); |
| 96 | clip->setDataType(AnimationClip::File); |
| 97 | clip->setSource(source); |
| 98 | clip->loadAnimation(); |
| 99 | return clip; |
| 100 | } |
| 101 | |
| 102 | ClipAnimator *createClipAnimator(Handler *handler, |
| 103 | qint64 globalStartTimeNS, |
| 104 | int loops) |
| 105 | { |
| 106 | auto animatorId = Qt3DCore::QNodeId::createId(); |
| 107 | ClipAnimator *animator = handler->clipAnimatorManager()->getOrCreateResource(id: animatorId); |
| 108 | setPeerId(backend: animator, id: animatorId); |
| 109 | animator->setHandler(handler); |
| 110 | animator->setStartTime(globalStartTimeNS); |
| 111 | animator->setLoops(loops); |
| 112 | return animator; |
| 113 | } |
| 114 | |
| 115 | private Q_SLOTS: |
| 116 | void checkJob_data() |
| 117 | { |
| 118 | QTest::addColumn<Handler *>(name: "handler" ); |
| 119 | QTest::addColumn<QVector<HClipAnimator>>(name: "dirtyClipAnimators" ); |
| 120 | QTest::addColumn<MappingDataResults>(name: "expectedResults" ); |
| 121 | |
| 122 | |
| 123 | { |
| 124 | Handler *handler; |
| 125 | AnimationClip *clip; |
| 126 | ClipAnimator *animator; |
| 127 | QVector<HClipAnimator> dirtyClipAnimators; |
| 128 | ChannelMapper *channelMapper; |
| 129 | MappingDataResults expectedResults; |
| 130 | handler = new Handler(); |
| 131 | clip = createAnimationClipLoader(handler, source: QUrl("qrc:/clip1.json" )); |
| 132 | |
| 133 | const qint64 globalStartTimeNS = 0; |
| 134 | const int loops = 1; |
| 135 | animator = createClipAnimator(handler, globalStartTimeNS, loops); |
| 136 | animator->setClipId(clip->peerId()); |
| 137 | dirtyClipAnimators = (QVector<HClipAnimator>() |
| 138 | << handler->clipAnimatorManager()->getOrAcquireHandle(id: animator->peerId())); |
| 139 | |
| 140 | auto channelMapping = createChannelMapping(handler, |
| 141 | channelName: QLatin1String("Location" ), |
| 142 | targetId: Qt3DCore::QNodeId::createId(), |
| 143 | propertyName: "translation" , |
| 144 | type: static_cast<int>(QVariant::Vector3D), |
| 145 | componentCount: 3); |
| 146 | QVector<ChannelMapping *> channelMappings; |
| 147 | channelMappings.push_back(t: channelMapping); |
| 148 | |
| 149 | channelMapper = createChannelMapper(handler, mappingIds: QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); |
| 150 | animator->setMapperId(channelMapper->peerId()); |
| 151 | animator->setRunning(true); // Has to be marked as running for the job to process it |
| 152 | animator->setEnabled(true); // Has to be marked as enabled for the job to process it |
| 153 | |
| 154 | const ComponentIndices locationIndices = { 0, 1, 2 }; |
| 155 | MappingData expectedMapping; |
| 156 | expectedMapping.targetId = channelMapping->targetId(); |
| 157 | expectedMapping.propertyName = channelMapping->propertyName(); |
| 158 | expectedMapping.type = channelMapping->type(); |
| 159 | expectedMapping.channelIndices = locationIndices; |
| 160 | expectedResults.insert(akey: animator, avalue: QVector<MappingData>() << expectedMapping); |
| 161 | |
| 162 | QTest::newRow(dataTag: "single mapping" ) |
| 163 | << handler |
| 164 | << dirtyClipAnimators |
| 165 | << expectedResults; |
| 166 | } |
| 167 | |
| 168 | { |
| 169 | Handler *handler; |
| 170 | AnimationClip *clip; |
| 171 | ClipAnimator *animator; |
| 172 | QVector<HClipAnimator> dirtyClipAnimators; |
| 173 | ChannelMapper *channelMapper; |
| 174 | MappingDataResults expectedResults; |
| 175 | handler = new Handler(); |
| 176 | clip = createAnimationClipLoader(handler, source: QUrl("qrc:/clip1.json" )); |
| 177 | |
| 178 | const qint64 globalStartTimeNS = 0; |
| 179 | const int loops = 1; |
| 180 | animator = createClipAnimator(handler, globalStartTimeNS, loops); |
| 181 | animator->setClipId(clip->peerId()); |
| 182 | dirtyClipAnimators = (QVector<HClipAnimator>() |
| 183 | << handler->clipAnimatorManager()->getOrAcquireHandle(id: animator->peerId())); |
| 184 | |
| 185 | auto channelMapping = createChannelMapping(handler, |
| 186 | channelName: QLatin1String("Location" ), |
| 187 | targetId: Qt3DCore::QNodeId::createId(), |
| 188 | propertyName: "translation" , |
| 189 | type: static_cast<int>(QVariant::Vector3D), |
| 190 | componentCount: 3); |
| 191 | QVector<ChannelMapping *> channelMappings; |
| 192 | channelMappings.push_back(t: channelMapping); |
| 193 | |
| 194 | channelMapper = createChannelMapper(handler, mappingIds: QVector<Qt3DCore::QNodeId>() << channelMapping->peerId()); |
| 195 | animator->setMapperId(channelMapper->peerId()); |
| 196 | animator->setRunning(true); // Has to be marked as running for the job to process it |
| 197 | animator->setEnabled(false); // Has to be marked as enabled for the job to process it |
| 198 | |
| 199 | QTest::newRow(dataTag: "disabled animator" ) |
| 200 | << handler |
| 201 | << dirtyClipAnimators |
| 202 | << expectedResults; |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | void checkJob() |
| 207 | { |
| 208 | // GIVEN |
| 209 | QFETCH(Handler *, handler); |
| 210 | QFETCH(QVector<HClipAnimator>, dirtyClipAnimators); |
| 211 | QFETCH(MappingDataResults, expectedResults); |
| 212 | FindRunningClipAnimatorsJob job; |
| 213 | |
| 214 | // WHEN |
| 215 | job.setHandler(handler); |
| 216 | job.setDirtyClipAnimators(dirtyClipAnimators); |
| 217 | job.run(); |
| 218 | |
| 219 | // THEN - check the resulting MappingData on the animator matches the expected results |
| 220 | for (const auto &dirtyClipAnimator : dirtyClipAnimators) { |
| 221 | const auto animator = handler->clipAnimatorManager()->data(handle: dirtyClipAnimator); |
| 222 | const QVector<MappingData> actualMappingData = animator->mappingData(); |
| 223 | const QVector<MappingData> expectedMappingData = expectedResults[animator]; |
| 224 | |
| 225 | QCOMPARE(expectedMappingData.size(), actualMappingData.size()); |
| 226 | for (int i = 0; i < actualMappingData.size(); ++i) { |
| 227 | QCOMPARE(expectedMappingData[i].targetId, actualMappingData[i].targetId); |
| 228 | QCOMPARE(expectedMappingData[i].type, actualMappingData[i].type); |
| 229 | QVERIFY(qstrcmp(expectedMappingData[i].propertyName, actualMappingData[i].propertyName) == 0); |
| 230 | QCOMPARE(expectedMappingData[i].channelIndices.size(), actualMappingData[i].channelIndices.size()); |
| 231 | |
| 232 | for (int j = 0; j < actualMappingData[i].channelIndices.size(); ++j) { |
| 233 | QCOMPARE(expectedMappingData[i].channelIndices[j], actualMappingData[i].channelIndices[j]); |
| 234 | } |
| 235 | } |
| 236 | } |
| 237 | } |
| 238 | }; |
| 239 | |
| 240 | QTEST_APPLESS_MAIN(tst_FindRunningClipAnimatorsJob) |
| 241 | |
| 242 | #include "tst_findrunningclipanimatorsjob.moc" |
| 243 | |