summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2017-01-28 15:22:19 +0000
committerPaul Lemire <paul.lemire@kdab.com>2017-01-29 13:59:24 +0000
commit9efbf9abd5452dd2c05250449efe1abf5887f481 (patch)
tree8ee8731491f9de28e451935cbc00034e372bf94c
parentddc85a1244c49fbe1873fa2c83e74dfb485d3598 (diff)
Add loops property to ClipAnimator and implement logic for it
Change-Id: Ied67635f202e01c626177b4869b77db5bd3e80d4 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r--src/animation/backend/clipanimator.cpp35
-rw-r--r--src/animation/backend/clipanimator_p.h6
-rw-r--r--src/animation/frontend/qclipanimator.cpp18
-rw-r--r--src/animation/frontend/qclipanimator.h4
-rw-r--r--src/animation/frontend/qclipanimator_p.h2
-rw-r--r--tests/auto/animation/clipanimator/tst_clipanimator.cpp14
-rw-r--r--tests/auto/animation/qclipanimator/tst_qclipanimator.cpp46
-rw-r--r--tests/manual/animation-keyframe-simple/main.qml2
8 files changed, 121 insertions, 6 deletions
diff --git a/src/animation/backend/clipanimator.cpp b/src/animation/backend/clipanimator.cpp
index 6b5dbbf33..ac6ca6710 100644
--- a/src/animation/backend/clipanimator.cpp
+++ b/src/animation/backend/clipanimator.cpp
@@ -39,6 +39,7 @@
#include <Qt3DAnimation/private/qclipanimator_p.h>
#include <Qt3DAnimation/private/animationclip_p.h>
#include <Qt3DAnimation/private/managers_p.h>
+#include <Qt3DAnimation/private/animationlogging_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
@@ -48,6 +49,7 @@
#include <QtGui/qquaternion.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE
@@ -59,6 +61,7 @@ ClipAnimator::ClipAnimator()
, m_clipId()
, m_mapperId()
, m_running(false)
+ , m_loops(1)
, m_startGlobalTime(0)
, m_channelResults()
, m_mappingData()
@@ -74,6 +77,7 @@ void ClipAnimator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr
m_clipId = data.clipId;
m_mapperId = data.mapperId;
m_running = data.running;
+ m_loops = data.loops;
setDirty(Handler::ClipAnimatorDirty);
}
@@ -106,6 +110,7 @@ void ClipAnimator::cleanup()
m_clipId = Qt3DCore::QNodeId();
m_mapperId = Qt3DCore::QNodeId();
m_running = false;
+ m_loops = 1;
}
void ClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -119,6 +124,8 @@ void ClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
setMapperId(change->value().value<Qt3DCore::QNodeId>());
else if (change->propertyName() == QByteArrayLiteral("running"))
setRunning(change->value().toBool());
+ else if (change->propertyName() == QByteArrayLiteral("loops"))
+ m_loops = change->value().toInt();
break;
}
@@ -192,11 +199,10 @@ void ClipAnimator::evaluateAtGlobalTime(qint64 globalTime)
const double t_start_global = double(m_startGlobalTime) / 1.0e9;
const double playbackRate = 1.0; // Assume standard playback rate for now
const double duration = clip->duration();
- const int loopCount = 1; // TODO: Make property on QClipAnimator
const double localTime = localTimeFromGlobalTime(t_global, t_start_global,
playbackRate, duration,
- loopCount);
+ m_loops, &m_currentLoop);
evaluateAtLocalTime(localTime);
}
@@ -206,8 +212,11 @@ void ClipAnimator::evaluateAtLocalTime(float localTime)
Q_ASSERT(clip);
// TODO: Uncomment when we add loopCount property
- if (localTime >= clip->duration() && /*loopCount != 0 &&*/ m_currentLoop == 0 /*loopCount - 1*/)
+ if (localTime >= clip->duration()
+ && m_loops != 0
+ && m_currentLoop == m_loops - 1) {
m_finalFrame = true;
+ }
// Ensure we have enough storage to hold the evaluations
m_channelResults.resize(clip->channelCount());
@@ -300,19 +309,37 @@ void ClipAnimator::sendPropertyChanges()
double ClipAnimator::localTimeFromGlobalTime(double t_global, double t_start_global,
double playbackRate, double duration,
- int loopCount)
+ int loopCount, int *currentLoop)
{
double t_local = playbackRate * (t_global - t_start_global);
+ double loopNumber = 0;
if (loopCount == 1) {
t_local = qBound(0.0, t_local, duration);
} else if (loopCount == 0) {
// Loops forever
+ (void) std::modf(t_local / duration, &loopNumber);
t_local = std::fmod(t_local, duration);
} else {
// N loops
t_local = qBound(0.0, t_local, double(loopCount) * duration);
+ (void) std::modf(t_local / duration, &loopNumber);
t_local = std::fmod(t_local, duration);
+
+ // Ensure we clamp to end of final loop
+ if (loopNumber == loopCount) {
+ loopNumber = loopCount - 1;
+ t_local = duration;
+ }
}
+
+ qCDebug(Jobs) << "t_global - t_start =" << t_global - t_start_global
+ << "current loop =" << loopNumber
+ << "t =" << t_local
+ << "duration =" << duration;
+
+ if (currentLoop != nullptr)
+ *currentLoop = loopNumber;
+
return t_local;
}
diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h
index 91403b918..f5c5ae03d 100644
--- a/src/animation/backend/clipanimator_p.h
+++ b/src/animation/backend/clipanimator_p.h
@@ -72,6 +72,7 @@ public:
void setRunning(bool running);
bool isRunning() const { return m_running; }
+ int loops() const { return m_loops; }
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
@@ -92,7 +93,7 @@ public:
static double localTimeFromGlobalTime(double t_global, double t_start_global,
double playbackRate, double duration,
- int loopCount);
+ int loopCount, int *currentLoop = nullptr);
static QVector<int> channelsToIndices(const ChannelGroup &channelGroup,
int dataType,
@@ -106,10 +107,13 @@ private:
int offset,
const QStringList &suffixes);
+ // Mirror of frontend properties
Qt3DCore::QNodeId m_clipId;
Qt3DCore::QNodeId m_mapperId;
bool m_running;
+ int m_loops;
+ // Working state
qint64 m_startGlobalTime;
QVector<float> m_channelResults;
diff --git a/src/animation/frontend/qclipanimator.cpp b/src/animation/frontend/qclipanimator.cpp
index 485f13091..e6c06c989 100644
--- a/src/animation/frontend/qclipanimator.cpp
+++ b/src/animation/frontend/qclipanimator.cpp
@@ -51,6 +51,7 @@ QClipAnimatorPrivate::QClipAnimatorPrivate()
, m_clip(nullptr)
, m_mapper(nullptr)
, m_running(false)
+ , m_loops(1)
{
}
@@ -86,6 +87,12 @@ QChannelMapper *QClipAnimator::channelMapper() const
return d->m_mapper;
}
+int QClipAnimator::loops() const
+{
+ Q_D(const QClipAnimator);
+ return d->m_loops;
+}
+
void QClipAnimator::setClip(QAnimationClip *clip)
{
Q_D(QClipAnimator);
@@ -134,6 +141,16 @@ void QClipAnimator::setChannelMapper(QChannelMapper *mapping)
emit channelMapperChanged(mapping);
}
+void QClipAnimator::setLoops(int loops)
+{
+ Q_D(QClipAnimator);
+ if (d->m_loops == loops)
+ return;
+
+ d->m_loops = loops;
+ emit loopsChanged(loops);
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QClipAnimator::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QClipAnimatorData>::create(this);
@@ -142,6 +159,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QClipAnimator::createNodeCreationChange() co
data.clipId = Qt3DCore::qIdForNode(d->m_clip);
data.mapperId = Qt3DCore::qIdForNode(d->m_mapper);
data.running = d->m_running;
+ data.loops = d->m_loops;
return creationChange;
}
diff --git a/src/animation/frontend/qclipanimator.h b/src/animation/frontend/qclipanimator.h
index ab5d5e541..176d6fc0c 100644
--- a/src/animation/frontend/qclipanimator.h
+++ b/src/animation/frontend/qclipanimator.h
@@ -56,6 +56,7 @@ class QT3DANIMATIONSHARED_EXPORT QClipAnimator : public Qt3DCore::QComponent
Q_OBJECT
Q_PROPERTY(Qt3DAnimation::QAnimationClip *clip READ clip WRITE setClip NOTIFY clipChanged)
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged)
Q_PROPERTY(Qt3DAnimation::QChannelMapper *channelMapper READ channelMapper WRITE setChannelMapper NOTIFY channelMapperChanged)
public:
@@ -65,16 +66,19 @@ public:
Qt3DAnimation::QAnimationClip *clip() const;
bool isRunning() const;
Qt3DAnimation::QChannelMapper *channelMapper() const;
+ int loops() const;
public Q_SLOTS:
void setClip(Qt3DAnimation::QAnimationClip *clip);
void setRunning(bool running);
void setChannelMapper(Qt3DAnimation::QChannelMapper *channelMapper);
+ void setLoops(int loops);
Q_SIGNALS:
void clipChanged(Qt3DAnimation::QAnimationClip *clip);
void runningChanged(bool running);
void channelMapperChanged(Qt3DAnimation::QChannelMapper *channelMapper);
+ void loopsChanged(int loops);
protected:
QClipAnimator(QClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr);
diff --git a/src/animation/frontend/qclipanimator_p.h b/src/animation/frontend/qclipanimator_p.h
index c158c12d8..7bb9c526f 100644
--- a/src/animation/frontend/qclipanimator_p.h
+++ b/src/animation/frontend/qclipanimator_p.h
@@ -70,6 +70,7 @@ public:
QAnimationClip *m_clip;
Qt3DAnimation::QChannelMapper *m_mapper;
bool m_running;
+ int m_loops;
};
struct QClipAnimatorData
@@ -77,6 +78,7 @@ struct QClipAnimatorData
Qt3DCore::QNodeId clipId;
Qt3DCore::QNodeId mapperId;
bool running;
+ int loops;
};
} // namespace Qt3DAnimation
diff --git a/tests/auto/animation/clipanimator/tst_clipanimator.cpp b/tests/auto/animation/clipanimator/tst_clipanimator.cpp
index b19f60da2..77f067973 100644
--- a/tests/auto/animation/clipanimator/tst_clipanimator.cpp
+++ b/tests/auto/animation/clipanimator/tst_clipanimator.cpp
@@ -52,6 +52,7 @@ private Q_SLOTS:
auto clip = new Qt3DAnimation::QAnimationClip();
animator.setClip(clip);
+ animator.setLoops(10);
// WHEN
simulateInitialization(&animator, &backendAnimator);
@@ -61,6 +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());
}
void checkInitialAndCleanedUpState()
@@ -75,12 +77,14 @@ private Q_SLOTS:
QCOMPARE(backendAnimator.isEnabled(), false);
QCOMPARE(backendAnimator.clipId(), Qt3DCore::QNodeId());
QCOMPARE(backendAnimator.isRunning(), false);
+ QCOMPARE(backendAnimator.loops(), 1);
// GIVEN
Qt3DAnimation::QClipAnimator animator;
auto clip = new Qt3DAnimation::QAnimationClip();
animator.setClip(clip);
animator.setRunning(true);
+ animator.setLoops(25);
// WHEN
simulateInitialization(&animator, &backendAnimator);
@@ -91,6 +95,7 @@ private Q_SLOTS:
QCOMPARE(backendAnimator.clipId(), Qt3DCore::QNodeId());
QCOMPARE(backendAnimator.isEnabled(), false);
QCOMPARE(backendAnimator.isRunning(), false);
+ QCOMPARE(backendAnimator.loops(), 1);
}
void checkPropertyChanges()
@@ -128,6 +133,15 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendAnimator.isRunning(), true);
+
+ // WHEN
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("loops");
+ updateChange->setValue(64);
+ backendAnimator.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendAnimator.loops(), 64);
}
};
diff --git a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp
index 59195606d..d210d4365 100644
--- a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp
+++ b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp
@@ -59,6 +59,7 @@ private Q_SLOTS:
// THEN
QCOMPARE(animator.clip(), static_cast<Qt3DAnimation::QAnimationClip *>(nullptr));
QCOMPARE(animator.channelMapper(), static_cast<Qt3DAnimation::QChannelMapper *>(nullptr));
+ QCOMPARE(animator.loops(), 1);
}
void checkPropertyChanges()
@@ -107,6 +108,26 @@ private Q_SLOTS:
QCOMPARE(animator.channelMapper(), newValue);
QCOMPARE(spy.count(), 0);
}
+
+ {
+ // WHEN
+ QSignalSpy spy(&animator, SIGNAL(loopsChanged(int)));
+ const int newValue = 5;
+ animator.setLoops(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(animator.loops(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ animator.setLoops(newValue);
+
+ // THEN
+ QCOMPARE(animator.loops(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
}
void checkCreationData()
@@ -138,6 +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);
}
// WHEN
@@ -218,6 +240,30 @@ private Q_SLOTS:
QCOMPARE(arbiter.events.size(), 0);
}
+ {
+ // WHEN
+ animator.setLoops(10);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "loops");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().toInt(), animator.loops());
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ animator.setLoops(10);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
}
};
diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml
index 38b898b93..ad9e59659 100644
--- a/tests/manual/animation-keyframe-simple/main.qml
+++ b/tests/manual/animation-keyframe-simple/main.qml
@@ -38,7 +38,7 @@ DefaultSceneEntity {
},
ClipAnimator {
id: animator
-
+ loops: 3
onRunningChanged: console.log("running = " + running)
clip: AnimationClip {