summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Strømme <christian.stromme@qt.io>2017-11-21 12:23:55 +0100
committerSean Harmer <sean.harmer@kdab.com>2018-01-23 18:23:31 +0000
commitf6a9174e5efeda68151f2d992fcd916fb2dd2c99 (patch)
treecee5aa42d7164d5e3f8b18c6c1a0217965d0784e
parentf6699afc911da958347c6916c1eff3558ee8d431 (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.h2
-rw-r--r--src/animation/backend/blendedclipanimator.cpp17
-rw-r--r--src/animation/backend/blendedclipanimator_p.h15
-rw-r--r--src/animation/backend/buildblendtreesjob.cpp13
-rw-r--r--src/animation/backend/evaluateblendclipanimatorjob.cpp18
-rw-r--r--src/animation/backend/fcurve_p.h1
-rw-r--r--src/animation/frontend/qabstractclipanimator.cpp14
-rw-r--r--src/animation/frontend/qblendedclipanimator.cpp1
-rw-r--r--tests/auto/animation/qblendedclipanimator/tst_qblendedclipanimator.cpp75
-rw-r--r--tests/manual/animation-keyframe-blendtree/main.qml16
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
- }
}