diff options
author | Christian Strømme <christian.stromme@qt.io> | 2017-11-21 12:23:55 +0100 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2018-01-23 18:23:31 +0000 |
commit | f6a9174e5efeda68151f2d992fcd916fb2dd2c99 (patch) | |
tree | cee5aa42d7164d5e3f8b18c6c1a0217965d0784e | |
parent | f6699afc911da958347c6916c1eff3558ee8d431 (diff) |
Add normalizedTime function to blendedlclip animators
Change-Id: I19c1907371d9d131295558eb19c297d544ebef7d
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r-- | src/animation/backend/animationutils_p.h | 2 | ||||
-rw-r--r-- | src/animation/backend/blendedclipanimator.cpp | 17 | ||||
-rw-r--r-- | src/animation/backend/blendedclipanimator_p.h | 15 | ||||
-rw-r--r-- | src/animation/backend/buildblendtreesjob.cpp | 13 | ||||
-rw-r--r-- | src/animation/backend/evaluateblendclipanimatorjob.cpp | 18 | ||||
-rw-r--r-- | src/animation/backend/fcurve_p.h | 1 | ||||
-rw-r--r-- | src/animation/frontend/qabstractclipanimator.cpp | 14 | ||||
-rw-r--r-- | src/animation/frontend/qblendedclipanimator.cpp | 1 | ||||
-rw-r--r-- | tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp | 75 | ||||
-rw-r--r-- | tests/manual/animation-keyframe-blendtree/main.qml | 16 |
10 files changed, 149 insertions, 23 deletions
diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h index 66e417a2a..01816bda2 100644 --- a/src/animation/backend/animationutils_p.h +++ b/src/animation/backend/animationutils_p.h @@ -315,7 +315,7 @@ Q_AUTOTEST_EXPORT QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId, const QVector<MappingData> &mappingDataVec, const QVector<float> &channelResults, - bool finalFrame, float normalizedLocalTime = -1.0f); + bool finalFrame, float normalizedLocalTime); Q_AUTOTEST_EXPORT QVector<AnimationCallbackAndValue> prepareCallbacks(const QVector<MappingData> &mappingDataVec, diff --git a/src/animation/backend/blendedclipanimator.cpp b/src/animation/backend/blendedclipanimator.cpp index 1487d6c3e..fe8a5d815 100644 --- a/src/animation/backend/blendedclipanimator.cpp +++ b/src/animation/backend/blendedclipanimator.cpp @@ -52,6 +52,8 @@ BlendedClipAnimator::BlendedClipAnimator() , m_lastLocalTime(0.0) , m_currentLoop(0) , m_loops(1) + , m_normalizedLocalTime(-1.0f) + , m_lastNormalizedLocalTime(-1.0) { } @@ -64,6 +66,7 @@ void BlendedClipAnimator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeB m_clockId = data.clockId; m_running = data.running; m_loops = data.loops; + m_normalizedLocalTime = data.normalizedTime; setDirty(Handler::BlendedClipAnimatorDirty); } @@ -77,6 +80,11 @@ void BlendedClipAnimator::setLastLocalTime(double lastLocalTime) m_lastLocalTime = lastLocalTime; } +void BlendedClipAnimator::setLastNormalizedLocalTime(float normalizedTime) +{ + m_lastNormalizedLocalTime = normalizedTime; +} + void BlendedClipAnimator::setLastGlobalTimeNS(const qint64 &lastGlobalTimeNS) { m_lastGlobalTimeNS = lastGlobalTimeNS; @@ -152,6 +160,13 @@ Qt3DCore::QNodeId BlendedClipAnimator::blendTreeRootId() const return m_blendTreeRootId; } +void BlendedClipAnimator::setNormalizedLocalTime(float normalizedTime) +{ + m_normalizedLocalTime = normalizedTime; + if (isValidNormalizedTime(m_normalizedLocalTime)) + setDirty(Handler::BlendedClipAnimatorDirty); +} + void BlendedClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { switch (e->type()) { @@ -167,6 +182,8 @@ void BlendedClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) setRunning(change->value().toBool()); else if (change->propertyName() == QByteArrayLiteral("loops")) m_loops = change->value().toInt(); + else if (change->propertyName() == QByteArrayLiteral("normalizedTime")) + setNormalizedLocalTime(change->value().toFloat()); break; } diff --git a/src/animation/backend/blendedclipanimator_p.h b/src/animation/backend/blendedclipanimator_p.h index 79c6d8c43..09a071c06 100644 --- a/src/animation/backend/blendedclipanimator_p.h +++ b/src/animation/backend/blendedclipanimator_p.h @@ -70,9 +70,11 @@ public: Qt3DCore::QNodeId mapperId() const { return m_mapperId; } Qt3DCore::QNodeId clockId() const { return m_clockId; } bool isRunning() const { return m_running; } + void setNormalizedLocalTime(float normalizedTime); + float normalizedLocalTime() const { return m_normalizedLocalTime; } // Called by BuildBlendTreeJob - bool canRun() const { return !m_mapperId.isNull() && !m_blendTreeRootId.isNull() && m_running; } + bool canRun() const { return !m_mapperId.isNull() && !m_blendTreeRootId.isNull(); } void setBlendTreeRootId(Qt3DCore::QNodeId blendTreeRootId); void setMapperId(Qt3DCore::QNodeId mapperId); @@ -101,6 +103,14 @@ public: double lastLocalTime() const; void setLastLocalTime(double lastLocalTime); + float lastNormalizedLocalTime() { return m_lastNormalizedLocalTime; } + void setLastNormalizedLocalTime(float normalizedTime); + bool isSeeking() const + { + return isValidNormalizedTime(m_normalizedLocalTime) + && !qFuzzyCompare(m_lastNormalizedLocalTime, m_normalizedLocalTime); + } + private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final; Qt3DCore::QNodeId m_blendTreeRootId; @@ -114,6 +124,9 @@ private: int m_currentLoop; int m_loops; + float m_normalizedLocalTime; + float m_lastNormalizedLocalTime; + QVector<MappingData> m_mappingData; }; diff --git a/src/animation/backend/buildblendtreesjob.cpp b/src/animation/backend/buildblendtreesjob.cpp index 581b133b5..be96889fa 100644 --- a/src/animation/backend/buildblendtreesjob.cpp +++ b/src/animation/backend/buildblendtreesjob.cpp @@ -57,6 +57,12 @@ BuildBlendTreesJob::BuildBlendTreesJob() void BuildBlendTreesJob::setBlendedClipAnimators(const QVector<HBlendedClipAnimator> &blendedClipAnimatorHandles) { m_blendedClipAnimatorHandles = blendedClipAnimatorHandles; + BlendedClipAnimatorManager *blendedClipAnimatorManager = m_handler->blendedClipAnimatorManager(); + BlendedClipAnimator *blendedClipAnimator = nullptr; + for (const auto &blendedClipAnimatorHandle : qAsConst(m_blendedClipAnimatorHandles)) { + blendedClipAnimator = blendedClipAnimatorManager->data(blendedClipAnimatorHandle); + Q_ASSERT(blendedClipAnimator); + } } // Note this job is run once for all stopped blended animators that have been marked dirty @@ -68,10 +74,13 @@ void BuildBlendTreesJob::run() BlendedClipAnimator *blendClipAnimator = m_handler->blendedClipAnimatorManager()->data(blendedClipAnimatorHandle); Q_ASSERT(blendClipAnimator); + const bool canRun = blendClipAnimator->canRun(); - m_handler->setBlendedClipAnimatorRunning(blendedClipAnimatorHandle, canRun); + const bool running = blendClipAnimator->isRunning(); + const bool seeking = blendClipAnimator->isSeeking(); + m_handler->setBlendedClipAnimatorRunning(blendedClipAnimatorHandle, canRun && (seeking || running)); - if (!canRun) + if (!canRun && !(seeking || running)) continue; // Build the format for clip results that should be used by nodes in the blend diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp index d01cf3bdd..e0bb8b155 100644 --- a/src/animation/backend/evaluateblendclipanimatorjob.cpp +++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp @@ -65,11 +65,12 @@ void EvaluateBlendClipAnimatorJob::run() BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle); Q_ASSERT(blendedClipAnimator); - if (!blendedClipAnimator->isRunning()) + const bool running = blendedClipAnimator->isRunning(); + const bool seeking = blendedClipAnimator->isSeeking(); + if (!running && !seeking) { + m_handler->setBlendedClipAnimatorRunning(m_blendClipAnimatorHandle, false); return; - - qint64 globalTimeNS = m_handler->simulationTime(); - qint64 nsSincePreviousFrame = blendedClipAnimator->nsSincePreviousFrame(globalTimeNS); + } Qt3DCore::QNodeId blendTreeRootId = blendedClipAnimator->blendTreeRootId(); const QVector<Qt3DCore::QNodeId> valueNodeIdsToEvaluate = gatherValueNodesToEvaluate(m_handler, blendTreeRootId); @@ -82,6 +83,10 @@ void EvaluateBlendClipAnimatorJob::run() Clock *clock = m_handler->clockManager()->lookupResource(blendedClipAnimator->clockId()); + qint64 globalTimeNS = m_handler->simulationTime(); + qint64 nsSincePreviousFrame = seeking ? toNsecs(duration * blendedClipAnimator->normalizedLocalTime()) + : blendedClipAnimator->nsSincePreviousFrame(globalTimeNS); + // Calculate the phase given the blend tree duration and global time AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, clock, nsSincePreviousFrame); const double phase = phaseFromElapsedTime(animatorData.currentTime, animatorData.elapsedTime, @@ -115,6 +120,8 @@ void EvaluateBlendClipAnimatorJob::run() const double localTime = phase * duration; blendedClipAnimator->setLastGlobalTimeNS(globalTimeNS); blendedClipAnimator->setLastLocalTime(localTime); + blendedClipAnimator->setLastNormalizedLocalTime(phase); + blendedClipAnimator->setNormalizedLocalTime(-1.0f); // Re-set to something invalid. blendedClipAnimator->setCurrentLoop(animatorData.currentLoop); const bool finalFrame = isFinalFrame(localTime, duration, animatorData.currentLoop, animatorData.loopCount); @@ -123,7 +130,8 @@ void EvaluateBlendClipAnimatorJob::run() const QVector<Qt3DCore::QSceneChangePtr> changes = preparePropertyChanges(blendedClipAnimator->peerId(), mappingData, blendedResults, - finalFrame); + finalFrame, + phase); // Send the property changes blendedClipAnimator->sendPropertyChanges(changes); diff --git a/src/animation/backend/fcurve_p.h b/src/animation/backend/fcurve_p.h index 8c5cdd54d..f96c98c1c 100644 --- a/src/animation/backend/fcurve_p.h +++ b/src/animation/backend/fcurve_p.h @@ -110,7 +110,6 @@ inline QDebug operator<<(QDebug dbg, const FCurve &fcurve) << endl; break; } - case QKeyFrame::ConstantInterpolation: case QKeyFrame::LinearInterpolation: { dbg << "t = " << fcurve.localTime(i) diff --git a/src/animation/frontend/qabstractclipanimator.cpp b/src/animation/frontend/qabstractclipanimator.cpp index a56b349e7..404879d0a 100644 --- a/src/animation/frontend/qabstractclipanimator.cpp +++ b/src/animation/frontend/qabstractclipanimator.cpp @@ -267,15 +267,17 @@ void QAbstractClipAnimator::setClock(QClock *clock) void QAbstractClipAnimator::setNormalizedTime(float timeFraction) { Q_D(QAbstractClipAnimator); - const float adjustedFraction = qBound(0.0f, timeFraction, 1.0f); - if (!qFuzzyCompare(timeFraction, adjustedFraction)) - qWarning("time fraction value clipped to : %f", double(adjustedFraction)); + const bool validTime = !(timeFraction < 0.0f) && !(timeFraction > 1.0f); + if (!validTime) { + qWarning("Time value %f is not valid, needs to be in the range 0.0 to 1.0", timeFraction); + return; + } - if (qFuzzyCompare(d->m_normalizedTime, adjustedFraction)) + if (qFuzzyCompare(d->m_normalizedTime, timeFraction)) return; - d->m_normalizedTime = adjustedFraction; - emit normalizedTimeChanged(adjustedFraction); + d->m_normalizedTime = timeFraction; + emit normalizedTimeChanged(timeFraction); } /*! diff --git a/src/animation/frontend/qblendedclipanimator.cpp b/src/animation/frontend/qblendedclipanimator.cpp index 785c810d3..388144c81 100644 --- a/src/animation/frontend/qblendedclipanimator.cpp +++ b/src/animation/frontend/qblendedclipanimator.cpp @@ -316,6 +316,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QBlendedClipAnimator::createNodeCreationChan data.clockId = Qt3DCore::qIdForNode(d->m_clock); data.running = d->m_running; data.loops = d->m_loops; + data.normalizedTime = d->m_normalizedTime; return creationChange; } diff --git a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp index d25041886..56be94472 100644 --- a/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp +++ b/tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp @@ -145,6 +145,47 @@ private Q_SLOTS: QCOMPARE(blendedClipAnimator.loopCount(), newValue); QCOMPARE(spy.count(), 0); } + + { + // WHEN + QSignalSpy spy(&blendedClipAnimator, SIGNAL(normalizedTimeChanged(float))); + const float newValue = 0.5; + blendedClipAnimator.setNormalizedTime(newValue); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(blendedClipAnimator.normalizedTime(), newValue); + QCOMPARE(spy.count(), 1); + + // WHEN + spy.clear(); + blendedClipAnimator.setNormalizedTime(newValue); + + // THEN + QCOMPARE(blendedClipAnimator.normalizedTime(), newValue); + QCOMPARE(spy.count(), 0); + } + + { + // WHEN + QSignalSpy spy(&blendedClipAnimator, SIGNAL(normalizedTimeChanged(float))); + const float newValue = -0.01f; // Invalid + blendedClipAnimator.setNormalizedTime(newValue); + const float oldValue = blendedClipAnimator.normalizedTime(); + + // THEN + QVERIFY(spy.isValid()); + QCOMPARE(blendedClipAnimator.normalizedTime(), oldValue); + QCOMPARE(spy.count(), 0); + + // WHEN + spy.clear(); + blendedClipAnimator.setNormalizedTime(1.01f); // Invalid + + // THEN + QCOMPARE(blendedClipAnimator.normalizedTime(), oldValue); + QCOMPARE(spy.count(), 0); + } } void checkCreationData() @@ -181,6 +222,7 @@ private Q_SLOTS: QCOMPARE(blendedClipAnimator.isEnabled(), creationChangeData->isNodeEnabled()); QCOMPARE(blendedClipAnimator.metaObject(), creationChangeData->metaObject()); QCOMPARE(blendedClipAnimator.loopCount(), cloneData.loops); + QCOMPARE(blendedClipAnimator.normalizedTime(), cloneData.normalizedTime); } // WHEN @@ -375,6 +417,39 @@ private Q_SLOTS: } } + + void checkNormalizedTimeUpdate() + { + // GIVEN + TestArbiter arbiter; + Qt3DAnimation::QBlendedClipAnimator blendedClipAnimator; + arbiter.setArbiterOnNode(&blendedClipAnimator); + + { + // WHEN + blendedClipAnimator.setNormalizedTime(0.5f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 1); + auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(change->propertyName(), "normalizedTime"); + QCOMPARE(change->value().value<float>(), blendedClipAnimator.normalizedTime()); + QCOMPARE(change->type(), Qt3DCore::PropertyUpdated); + + arbiter.events.clear(); + } + + { + // WHEN + blendedClipAnimator.setNormalizedTime(0.5f); + QCoreApplication::processEvents(); + + // THEN + QCOMPARE(arbiter.events.size(), 0); + } + + } }; QTEST_MAIN(tst_QBlendedClipAnimator) diff --git a/tests/manual/animation-keyframe-blendtree/main.qml b/tests/manual/animation-keyframe-blendtree/main.qml index 3d7fa47e5..74413b4e2 100644 --- a/tests/manual/animation-keyframe-blendtree/main.qml +++ b/tests/manual/animation-keyframe-blendtree/main.qml @@ -57,6 +57,15 @@ import Qt3D.Extras 2.0 DefaultSceneEntity { id: scene + KeyboardDevice { id: kyb } + KeyboardHandler { + id: keyboardHandler + sourceDevice: kyb + focus: true + onLeftPressed:blendedAnimator.normalizedTime -= 0.02 + onRightPressed: blendedAnimator.normalizedTime += 0.02 + } + Entity { id: cube @@ -95,7 +104,6 @@ DefaultSceneEntity { BlendedClipAnimator { id: blendedAnimator loops: 3 - clock: Clock { id: animatorClock playbackRate: 0.5 @@ -127,10 +135,4 @@ DefaultSceneEntity { position: Qt.vector3d(10, 3, 15) viewCenter: Qt.vector3d(2.5, 1, 0) } - - OrbitCameraController { - camera: scene.camera - linearSpeed: 8 - lookSpeed: 180 - } } |