summaryrefslogtreecommitdiffstats
path: root/src/animation
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-06-15 15:17:04 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2017-06-23 10:05:22 +0000
commit6f40494310dab964600375f04391f21b4eccdb44 (patch)
treea2dc6542a70672c3bf901a36723cff35089b6b11 /src/animation
parent11f092ce7c555814baeffc204f7fadc0f36fdcbb (diff)
Add support for animation callbacks
Let QChannelMapping optionally specify a callback, which then gets invoked either directly on a worker thread or the gui thread. Change-Id: I871776f47cc921ceb254f9dc1a7b89ae5c5618d8 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src/animation')
-rw-r--r--src/animation/backend/animationutils.cpp166
-rw-r--r--src/animation/backend/animationutils_p.h17
-rw-r--r--src/animation/backend/blendedclipanimator.cpp16
-rw-r--r--src/animation/backend/blendedclipanimator_p.h1
-rw-r--r--src/animation/backend/channelmapping.cpp10
-rw-r--r--src/animation/backend/channelmapping_p.h10
-rw-r--r--src/animation/backend/clipanimator.cpp16
-rw-r--r--src/animation/backend/clipanimator_p.h1
-rw-r--r--src/animation/backend/evaluateblendclipanimatorjob.cpp4
-rw-r--r--src/animation/backend/evaluateclipanimatorjob.cpp3
-rw-r--r--src/animation/frontend/frontend.pri7
-rw-r--r--src/animation/frontend/qanimationcallback.h66
-rw-r--r--src/animation/frontend/qanimationcallbacktrigger.cpp54
-rw-r--r--src/animation/frontend/qanimationcallbacktrigger_p.h85
-rw-r--r--src/animation/frontend/qchannelmapping.cpp60
-rw-r--r--src/animation/frontend/qchannelmapping.h4
-rw-r--r--src/animation/frontend/qchannelmapping_p.h5
-rw-r--r--src/animation/frontend/qclipanimator.cpp11
-rw-r--r--src/animation/frontend/qclipanimator.h1
19 files changed, 468 insertions, 69 deletions
diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp
index 2bfca2a33..e33a31b7b 100644
--- a/src/animation/backend/animationutils.cpp
+++ b/src/animation/backend/animationutils.cpp
@@ -225,81 +225,90 @@ ClipResults evaluateClipAtPhase(AnimationClip *clip, float phase)
return evaluateClipAtLocalTime(clip, localTime);
}
-QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId,
- const QVector<MappingData> &mappingDataVec,
- const QVector<float> &channelResults,
- bool finalFrame)
+QVariant buildPropertyValue(const MappingData &mappingData, const QVector<float> &channelResults)
{
- QVector<Qt3DCore::QSceneChangePtr> changes;
- // Iterate over the mappings
- for (const MappingData &mappingData : mappingDataVec) {
- // Construct a property update change, set target, property and delivery options
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(mappingData.targetId);
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName(mappingData.propertyName);
+ QVariant v;
- // Handle intermediate updates vs final flag properly
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isIntermediate = !finalFrame;
+ switch (mappingData.type) {
+ case QMetaType::Float:
+ case QVariant::Double: {
+ v = QVariant::fromValue(channelResults[mappingData.channelIndices[0]]);
+ break;
+ }
- // Build the new value from the channel/fcurve evaluation results
- QVariant v;
- switch (mappingData.type) {
- case QMetaType::Float:
- case QVariant::Double: {
- v = QVariant::fromValue(channelResults[mappingData.channelIndices[0]]);
- break;
- }
+ case QVariant::Vector2D: {
+ const QVector2D vector(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]]);
+ v = QVariant::fromValue(vector);
+ break;
+ }
- case QVariant::Vector2D: {
- const QVector2D vector(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]]);
- v = QVariant::fromValue(vector);
- break;
- }
+ case QVariant::Vector3D: {
+ const QVector3D vector(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]]);
+ v = QVariant::fromValue(vector);
+ break;
+ }
- case QVariant::Vector3D: {
- const QVector3D vector(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]]);
- v = QVariant::fromValue(vector);
- break;
- }
+ case QVariant::Vector4D: {
+ const QVector4D vector(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]],
+ channelResults[mappingData.channelIndices[3]]);
+ v = QVariant::fromValue(vector);
+ break;
+ }
- case QVariant::Vector4D: {
- const QVector4D vector(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]],
- channelResults[mappingData.channelIndices[3]]);
- v = QVariant::fromValue(vector);
- break;
- }
+ case QVariant::Quaternion: {
+ QQuaternion q(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]],
+ channelResults[mappingData.channelIndices[3]]);
+ q.normalize();
+ v = QVariant::fromValue(q);
+ break;
+ }
- case QVariant::Quaternion: {
- QQuaternion q(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]],
- channelResults[mappingData.channelIndices[3]]);
- q.normalize();
- v = QVariant::fromValue(q);
- break;
- }
+ case QVariant::Color: {
+ const QColor color = QColor::fromRgbF(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]]);
+ v = QVariant::fromValue(color);
+ break;
+ }
- case QVariant::Color: {
- const QColor color = QColor::fromRgbF(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]]);
- v = QVariant::fromValue(color);
- break;
- }
+ default:
+ qWarning() << "Unhandled animation type" << mappingData.type;
+ break;
+ }
+
+ return v;
+}
- default:
- qWarning() << "Unhandled animation type";
+QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId,
+ const QVector<MappingData> &mappingDataVec,
+ const QVector<float> &channelResults,
+ bool finalFrame)
+{
+ QVector<Qt3DCore::QSceneChangePtr> changes;
+ // Iterate over the mappings
+ for (const MappingData &mappingData : mappingDataVec) {
+ if (!mappingData.propertyName)
continue;
+ // Build the new value from the channel/fcurve evaluation results
+ const QVariant v = buildPropertyValue(mappingData, channelResults);
+ if (v.isValid()) {
+ // Construct a property update change, set target, property and delivery options
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(mappingData.targetId);
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName(mappingData.propertyName);
+ // Handle intermediate updates vs final flag properly
+ Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isIntermediate = !finalFrame;
+ // Assign new value and send
+ e->setValue(v);
+ changes.push_back(e);
}
-
- // Assign new value and send
- e->setValue(v);
- changes.push_back(e);
}
@@ -314,6 +323,25 @@ QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId anim
return changes;
}
+QVector<AnimationCallbackAndValue> prepareCallbacks(const QVector<MappingData> &mappingDataVec,
+ const QVector<float> &channelResults)
+{
+ QVector<AnimationCallbackAndValue> callbacks;
+ for (const MappingData &mappingData : mappingDataVec) {
+ if (!mappingData.callback)
+ continue;
+ const QVariant v = buildPropertyValue(mappingData, channelResults);
+ if (v.isValid()) {
+ AnimationCallbackAndValue callback;
+ callback.callback = mappingData.callback;
+ callback.flags = mappingData.callbackFlags;
+ callback.value = v;
+ callbacks.append(callback);
+ }
+ }
+ return callbacks;
+}
+
//TODO: Remove this and use new implementation below for both the unblended
// and blended animation cases.
QVector<MappingData> buildPropertyMappings(Handler *handler,
@@ -336,10 +364,13 @@ QVector<MappingData> buildPropertyMappings(Handler *handler,
mappingData.targetId = mapping->targetId();
mappingData.propertyName = mapping->propertyName();
mappingData.type = mapping->type();
+ mappingData.callback = mapping->callback();
+ mappingData.callbackFlags = mapping->callbackFlags();
if (mappingData.type == static_cast<int>(QVariant::Invalid)) {
qWarning() << "Unknown type for node id =" << mappingData.targetId
- << "and property =" << mapping->property();
+ << "and property =" << mapping->property()
+ << "and callback =" << mapping->callback();
continue;
}
@@ -384,10 +415,13 @@ QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping*> &chann
mappingData.targetId = mapping->targetId();
mappingData.propertyName = mapping->propertyName();
mappingData.type = mapping->type();
+ mappingData.callback = mapping->callback();
+ mappingData.callbackFlags = mapping->callbackFlags();
if (mappingData.type == static_cast<int>(QVariant::Invalid)) {
qWarning() << "Unknown type for node id =" << mappingData.targetId
- << "and property =" << mapping->property();
+ << "and property =" << mapping->property()
+ << "and callback =" << mapping->callback();
continue;
}
diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h
index f8fcbafa7..6f00fc632 100644
--- a/src/animation/backend/animationutils_p.h
+++ b/src/animation/backend/animationutils_p.h
@@ -49,12 +49,14 @@
//
#include <Qt3DAnimation/private/qt3danimation_global_p.h>
+#include <Qt3DAnimation/qanimationcallback.h>
#include <Qt3DCore/qnodeid.h>
#include <Qt3DCore/qscenechange.h>
QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
+class QAnimationCallback;
namespace Animation {
struct Channel;
@@ -70,6 +72,8 @@ struct MappingData
{
Qt3DCore::QNodeId targetId;
const char *propertyName;
+ QAnimationCallback *callback;
+ QAnimationCallback::Flags callbackFlags;
int type;
ComponentIndices channelIndices;
};
@@ -102,6 +106,13 @@ struct ChannelNameAndType
}
};
+struct AnimationCallbackAndValue
+{
+ QAnimationCallback *callback;
+ QAnimationCallback::Flags flags;
+ QVariant value;
+};
+
template<typename Animator>
AnimatorEvaluationData evaluationDataForAnimator(Animator animator, qint64 globalTime)
{
@@ -152,11 +163,15 @@ ClipResults evaluateClipAtPhase(AnimationClip *clip,
Q_AUTOTEST_EXPORT
QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId,
- const QVector<MappingData> &mappingData,
+ const QVector<MappingData> &mappingDataVec,
const QVector<float> &channelResults,
bool finalFrame);
Q_AUTOTEST_EXPORT
+QVector<AnimationCallbackAndValue> prepareCallbacks(const QVector<MappingData> &mappingDataVec,
+ const QVector<float> &channelResults);
+
+Q_AUTOTEST_EXPORT
QVector<MappingData> buildPropertyMappings(Handler *handler,
const AnimationClip *clip,
const ChannelMapper *mapper);
diff --git a/src/animation/backend/blendedclipanimator.cpp b/src/animation/backend/blendedclipanimator.cpp
index 08789a5f9..46b3b87fa 100644
--- a/src/animation/backend/blendedclipanimator.cpp
+++ b/src/animation/backend/blendedclipanimator.cpp
@@ -37,6 +37,7 @@
#include "blendedclipanimator_p.h"
#include <Qt3DAnimation/qblendedclipanimator.h>
#include <Qt3DAnimation/private/qblendedclipanimator_p.h>
+#include <Qt3DAnimation/private/qanimationcallbacktrigger_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -100,6 +101,21 @@ void BlendedClipAnimator::sendPropertyChanges(const QVector<Qt3DCore::QSceneChan
notifyObservers(change);
}
+void BlendedClipAnimator::sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks)
+{
+ for (const AnimationCallbackAndValue &callback : callbacks) {
+ if (callback.flags.testFlag(QAnimationCallback::OnThreadPool)) {
+ callback.callback->valueChanged(callback.value);
+ } else {
+ auto e = QAnimationCallbackTriggerPtr::create(peerId());
+ e->setCallback(callback.callback);
+ e->setValue(callback.value);
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ notifyObservers(e);
+ }
+ }
+}
+
Qt3DCore::QNodeId BlendedClipAnimator::blendTreeRootId() const
{
return m_blendTreeRootId;
diff --git a/src/animation/backend/blendedclipanimator_p.h b/src/animation/backend/blendedclipanimator_p.h
index 4421cb43a..e6311bc59 100644
--- a/src/animation/backend/blendedclipanimator_p.h
+++ b/src/animation/backend/blendedclipanimator_p.h
@@ -90,6 +90,7 @@ public:
QVector<MappingData> mappingData() const { return m_mappingData; }
void sendPropertyChanges(const QVector<Qt3DCore::QSceneChangePtr> &changes);
+ void sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks);
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
diff --git a/src/animation/backend/channelmapping.cpp b/src/animation/backend/channelmapping.cpp
index 0fd0f2714..82e6a95a8 100644
--- a/src/animation/backend/channelmapping.cpp
+++ b/src/animation/backend/channelmapping.cpp
@@ -52,6 +52,8 @@ ChannelMapping::ChannelMapping()
, m_property()
, m_type(static_cast<int>(QVariant::Invalid))
, m_propertyName(nullptr)
+ , m_callback(nullptr)
+ , m_callbackFlags(0)
{
}
@@ -64,6 +66,8 @@ void ChannelMapping::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt
m_property = data.property;
m_type = data.type;
m_propertyName = data.propertyName;
+ m_callback = data.callback;
+ m_callbackFlags = data.callbackFlags;
}
void ChannelMapping::cleanup()
@@ -74,6 +78,8 @@ void ChannelMapping::cleanup()
m_property.clear();
m_type = static_cast<int>(QVariant::Invalid);
m_propertyName = nullptr;
+ m_callback = nullptr;
+ m_callbackFlags = 0;
}
void ChannelMapping::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -91,6 +97,10 @@ void ChannelMapping::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_type = change->value().toInt();
else if (change->propertyName() == QByteArrayLiteral("propertyName"))
m_propertyName = static_cast<const char *>(const_cast<const void *>(change->value().value<void *>()));
+ else if (change->propertyName() == QByteArrayLiteral("callback"))
+ m_callback = static_cast<QAnimationCallback *>(change->value().value<void *>());
+ else if (change->propertyName() == QByteArrayLiteral("callbackFlags"))
+ m_callbackFlags = QAnimationCallback::Flags(change->value().toInt());
break;
}
diff --git a/src/animation/backend/channelmapping_p.h b/src/animation/backend/channelmapping_p.h
index 93cf5efed..f2dde0c74 100644
--- a/src/animation/backend/channelmapping_p.h
+++ b/src/animation/backend/channelmapping_p.h
@@ -50,6 +50,7 @@
#include <Qt3DAnimation/private/backendnode_p.h>
#include <Qt3DAnimation/private/fcurve_p.h>
+#include <Qt3DAnimation/qanimationcallback.h>
#include <Qt3DCore/qnodeid.h>
#include <QtCore/QMetaProperty>
@@ -57,6 +58,7 @@
QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
+
namespace Animation {
class Handler;
@@ -85,6 +87,12 @@ public:
void setPropertyName(const char *propertyName) { m_propertyName = propertyName; }
const char *propertyName() const { return m_propertyName; }
+ void setCallback(QAnimationCallback *callback) { m_callback = callback; }
+ QAnimationCallback *callback() const { return m_callback; }
+
+ void setCallbackFlags(QAnimationCallback::Flags flags) { m_callbackFlags = flags; }
+ QAnimationCallback::Flags callbackFlags() const { return m_callbackFlags; }
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -93,6 +101,8 @@ private:
QString m_property;
int m_type;
const char *m_propertyName;
+ QAnimationCallback *m_callback;
+ QAnimationCallback::Flags m_callbackFlags;
};
} // namespace Animation
diff --git a/src/animation/backend/clipanimator.cpp b/src/animation/backend/clipanimator.cpp
index 65fd0f57f..ea31698d0 100644
--- a/src/animation/backend/clipanimator.cpp
+++ b/src/animation/backend/clipanimator.cpp
@@ -40,6 +40,7 @@
#include <Qt3DAnimation/private/animationclip_p.h>
#include <Qt3DAnimation/private/managers_p.h>
#include <Qt3DAnimation/private/animationlogging_p.h>
+#include <Qt3DAnimation/private/qanimationcallbacktrigger_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
@@ -129,6 +130,21 @@ void ClipAnimator::sendPropertyChanges(const QVector<Qt3DCore::QSceneChangePtr>
notifyObservers(change);
}
+void ClipAnimator::sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks)
+{
+ for (const AnimationCallbackAndValue &callback : callbacks) {
+ if (callback.flags.testFlag(QAnimationCallback::OnThreadPool)) {
+ callback.callback->valueChanged(callback.value);
+ } else {
+ auto e = QAnimationCallbackTriggerPtr::create(peerId());
+ e->setCallback(callback.callback);
+ e->setValue(callback.value);
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ notifyObservers(e);
+ }
+ }
+}
+
} // namespace Animation
} // namespace Qt3DAnimation
diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h
index da9109cfb..f0f631a5c 100644
--- a/src/animation/backend/clipanimator_p.h
+++ b/src/animation/backend/clipanimator_p.h
@@ -91,6 +91,7 @@ public:
void setCurrentLoop(int currentLoop) { m_currentLoop = currentLoop; }
void sendPropertyChanges(const QVector<Qt3DCore::QSceneChangePtr> &changes);
+ void sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks);
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp
index 76d24a4d3..e0f52765f 100644
--- a/src/animation/backend/evaluateblendclipanimatorjob.cpp
+++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp
@@ -115,6 +115,10 @@ void EvaluateBlendClipAnimatorJob::run()
finalFrame);
// Send the property changes
blendedClipAnimator->sendPropertyChanges(changes);
+
+ // Trigger callbacks either on this thread or by notifying the gui thread.
+ const QVector<AnimationCallbackAndValue> callbacks = prepareCallbacks(mappingData, blendedResults);
+ blendedClipAnimator->sendCallbacks(callbacks);
}
} // Animation
diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp
index e89405d63..e9f3d1da8 100644
--- a/src/animation/backend/evaluateclipanimatorjob.cpp
+++ b/src/animation/backend/evaluateclipanimatorjob.cpp
@@ -84,6 +84,9 @@ void EvaluateClipAnimatorJob::run()
// Send the property changes
clipAnimator->sendPropertyChanges(changes);
+ // Trigger callbacks either on this thread or by notifying the gui thread.
+ const QVector<AnimationCallbackAndValue> callbacks = prepareCallbacks(clipAnimator->mappingData(), channelResults);
+ clipAnimator->sendCallbacks(callbacks);
}
} // namespace Animation
diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri
index 9ea438395..7f397462b 100644
--- a/src/animation/frontend/frontend.pri
+++ b/src/animation/frontend/frontend.pri
@@ -44,7 +44,9 @@ HEADERS += \
$$PWD/qchannelcomponent.h \
$$PWD/qkeyframe.h \
$$PWD/qanimationclip.h \
- $$PWD/qanimationclip_p.h
+ $$PWD/qanimationclip_p.h \
+ $$PWD/qanimationcallback.h \
+ $$PWD/qanimationcallbacktrigger_p.h
SOURCES += \
$$PWD/qanimationaspect.cpp \
@@ -71,6 +73,7 @@ SOURCES += \
$$PWD/qchannel.cpp \
$$PWD/qchannelcomponent.cpp \
$$PWD/qkeyframe.cpp \
- $$PWD/qanimationclip.cpp
+ $$PWD/qanimationclip.cpp \
+ $$PWD/qanimationcallbacktrigger.cpp
INCLUDEPATH += $$PWD
diff --git a/src/animation/frontend/qanimationcallback.h b/src/animation/frontend/qanimationcallback.h
new file mode 100644
index 000000000..63e094918
--- /dev/null
+++ b/src/animation/frontend/qanimationcallback.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QANIMATIONCALLBACK_H
+#define QT3DANIMATION_QANIMATIONCALLBACK_H
+
+#include <Qt3DAnimation/qt3danimation_global.h>
+#include <Qt3DCore/qnode.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QT3DANIMATIONSHARED_EXPORT QAnimationCallback
+{
+public:
+ enum Flag {
+ OnThreadPool = 0x01
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ virtual ~QAnimationCallback() { }
+
+ virtual void valueChanged(const QVariant &value) = 0;
+};
+
+} // namespace Qt3DAnimation
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Qt3DAnimation::QAnimationCallback::Flags)
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QANIMATIONCALLBACK_H
diff --git a/src/animation/frontend/qanimationcallbacktrigger.cpp b/src/animation/frontend/qanimationcallbacktrigger.cpp
new file mode 100644
index 000000000..83fccb5a4
--- /dev/null
+++ b/src/animation/frontend/qanimationcallbacktrigger.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qanimationcallbacktrigger_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+QAnimationCallbackTrigger::QAnimationCallbackTrigger(Qt3DCore::QNodeId subjectId)
+ : Qt3DCore::QSceneChange(Qt3DCore::CallbackTriggered, subjectId),
+ m_callback(nullptr)
+{
+}
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/frontend/qanimationcallbacktrigger_p.h b/src/animation/frontend/qanimationcallbacktrigger_p.h
new file mode 100644
index 000000000..9a05d421f
--- /dev/null
+++ b/src/animation/frontend/qanimationcallbacktrigger_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QANIMATIONCALLBACKTRIGGER_P_H
+#define QT3DANIMATION_QANIMATIONCALLBACKTRIGGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DAnimation/qt3danimation_global.h>
+#include <Qt3DAnimation/qanimationcallback.h>
+#include <Qt3DCore/qscenechange.h>
+#include <QtCore/qsharedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class Q_AUTOTEST_EXPORT QAnimationCallbackTrigger : public Qt3DCore::QSceneChange
+{
+public:
+ QAnimationCallbackTrigger(Qt3DCore::QNodeId subjectId);
+
+ void setCallback(QAnimationCallback *callback) { m_callback = callback; }
+ QAnimationCallback *callback() const { return m_callback; }
+
+ void setValue(const QVariant &value) { m_value = value; }
+ QVariant value() const { return m_value; }
+
+private:
+ QAnimationCallback *m_callback;
+ QVariant m_value;
+};
+
+typedef QSharedPointer<QAnimationCallbackTrigger> QAnimationCallbackTriggerPtr;
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QANIMATIONCALLBACKTRIGGER_P_H
diff --git a/src/animation/frontend/qchannelmapping.cpp b/src/animation/frontend/qchannelmapping.cpp
index faa77f5db..ec18332c7 100644
--- a/src/animation/frontend/qchannelmapping.cpp
+++ b/src/animation/frontend/qchannelmapping.cpp
@@ -53,6 +53,8 @@ QChannelMappingPrivate::QChannelMappingPrivate()
, m_property()
, m_propertyName(nullptr)
, m_type(static_cast<int>(QVariant::Invalid))
+ , m_callback(nullptr)
+ , m_callbackFlags(0)
{
}
@@ -148,6 +150,12 @@ QString QChannelMapping::property() const
return d->m_property;
}
+QAnimationCallback *QChannelMapping::callback() const
+{
+ Q_D(const QChannelMapping);
+ return d->m_callback;
+}
+
void QChannelMapping::setChannelName(const QString &channelName)
{
Q_D(QChannelMapping);
@@ -190,6 +198,56 @@ void QChannelMapping::setProperty(const QString &property)
d->updatePropertyNameAndType();
}
+/*!
+ Associates a \a callback object with this channel mapping.
+
+ Such mappings do not have to have a target object and property name. When
+ the \a callback object is set, every change in the animated value will lead
+ to invoking the callback's
+ \l{QAnimationCallback::onValueChanged()}{onValueChanged()} function either
+ on the gui/main thread, or directly on one of the thread pool's worker
+ thread. This is controlled by \a flags.
+
+ \a type specifies the type (for example, QVariant::Vector3D,
+ QVariant::Color, or QMetaType::Float) of the animated value. When animating
+ node properties this does not need to be provided separately, however it
+ becomes important to supply this when there is only a callback.
+
+ \note A mapping can be associated both with a node property and a
+ callback. It is important however that \a type matches the type of the
+ property in this case. Note also that for properties of type QVariant (for
+ example, QParameter::value), the \a type is the type of the value stored in
+ the QVariant.
+
+ \note The \a callback pointer is expected to stay valid while any
+ associated animators are running.
+ */
+void QChannelMapping::setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags)
+{
+ Q_D(QChannelMapping);
+ if (d->m_type != type) {
+ d->m_type = type;
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id());
+ e->setPropertyName("type");
+ e->setValue(QVariant(d->m_type));
+ notifyObservers(e);
+ }
+ if (d->m_callback != callback) {
+ d->m_callback = callback;
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id());
+ e->setPropertyName("callback");
+ e->setValue(QVariant::fromValue(static_cast<void *>(d->m_callback)));
+ notifyObservers(e);
+ }
+ if (d->m_callbackFlags != flags) {
+ d->m_callbackFlags = flags;
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id());
+ e->setPropertyName("callbackFlags");
+ e->setValue(QVariant::fromValue(int(d->m_callbackFlags)));
+ notifyObservers(e);
+ }
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QChannelMappingData>::create(this);
@@ -200,6 +258,8 @@ Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange()
data.property = d->m_property;
data.type = d->m_type;
data.propertyName = d->m_propertyName;
+ data.callback = d->m_callback;
+ data.callbackFlags = d->m_callbackFlags;
return creationChange;
}
diff --git a/src/animation/frontend/qchannelmapping.h b/src/animation/frontend/qchannelmapping.h
index d768298fe..d14015b9f 100644
--- a/src/animation/frontend/qchannelmapping.h
+++ b/src/animation/frontend/qchannelmapping.h
@@ -38,6 +38,7 @@
#define QT3DANIMATION_QCHANNELMAPPING_H
#include <Qt3DAnimation/qt3danimation_global.h>
+#include <Qt3DAnimation/qanimationcallback.h>
#include <Qt3DCore/qnode.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,9 @@ public:
QString channelName() const;
Qt3DCore::QNode *target() const;
QString property() const;
+ QAnimationCallback *callback() const;
+
+ void setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags);
public Q_SLOTS:
void setChannelName(const QString &channelName);
diff --git a/src/animation/frontend/qchannelmapping_p.h b/src/animation/frontend/qchannelmapping_p.h
index 2c48b0485..95b300888 100644
--- a/src/animation/frontend/qchannelmapping_p.h
+++ b/src/animation/frontend/qchannelmapping_p.h
@@ -49,6 +49,7 @@
//
#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DAnimation/qanimationcallback.h>
QT_BEGIN_NAMESPACE
@@ -68,6 +69,8 @@ public:
QString m_property;
const char *m_propertyName;
int m_type;
+ QAnimationCallback *m_callback;
+ QAnimationCallback::Flags m_callbackFlags;
};
struct QChannelMappingData
@@ -77,6 +80,8 @@ struct QChannelMappingData
QString property;
int type;
const char *propertyName;
+ QAnimationCallback *callback;
+ QAnimationCallback::Flags callbackFlags;
};
} // namespace Qt3DAnimation
diff --git a/src/animation/frontend/qclipanimator.cpp b/src/animation/frontend/qclipanimator.cpp
index eb6c80aee..da6534d16 100644
--- a/src/animation/frontend/qclipanimator.cpp
+++ b/src/animation/frontend/qclipanimator.cpp
@@ -41,6 +41,7 @@
#include "qclipanimator_p.h"
#include <Qt3DAnimation/qabstractanimationclip.h>
#include <Qt3DAnimation/qchannelmapper.h>
+#include <Qt3DAnimation/private/qanimationcallbacktrigger_p.h>
QT_BEGIN_NAMESPACE
@@ -165,6 +166,16 @@ Qt3DCore::QNodeCreatedChangeBasePtr QClipAnimator::createNodeCreationChange() co
return creationChange;
}
+/*! \internal */
+void QClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ if (change->type() == Qt3DCore::CallbackTriggered) {
+ QAnimationCallbackTriggerPtr callbackTrigger = qSharedPointerCast<Qt3DAnimation::QAnimationCallbackTrigger>(change);
+ if (callbackTrigger->callback())
+ callbackTrigger->callback()->valueChanged(callbackTrigger->value());
+ }
+}
+
} // namespace Qt3DAnimation
QT_END_NAMESPACE
diff --git a/src/animation/frontend/qclipanimator.h b/src/animation/frontend/qclipanimator.h
index 311ac4ab0..7b06f9878 100644
--- a/src/animation/frontend/qclipanimator.h
+++ b/src/animation/frontend/qclipanimator.h
@@ -70,6 +70,7 @@ Q_SIGNALS:
protected:
QClipAnimator(QClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QClipAnimator)