From 4a94e68d5975b53f11ab2ab7755f6b944fc8b614 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sat, 21 Jan 2017 15:53:09 +0000 Subject: Add a job to load animation clips Defers the actual work to AnimationClip. Also made all backend nodes have a common base class to make it easy to track the Handler. Added a manual test to exercise this and which we can build up over time as we add API. Change-Id: I7cdd8da948498544059ba51efe38642dd54ea410 Reviewed-by: Paul Lemire --- src/animation/backend/animationclip.cpp | 74 +++++++++++++++++- src/animation/backend/animationclip_p.h | 36 ++++++++- src/animation/backend/backend.pri | 8 +- src/animation/backend/backendnode.cpp | 71 ++++++++++++++++++ src/animation/backend/backendnode_p.h | 81 ++++++++++++++++++++ src/animation/backend/blendedclipanimator.cpp | 3 +- src/animation/backend/blendedclipanimator_p.h | 8 +- src/animation/backend/clipanimator.cpp | 3 +- src/animation/backend/clipanimator_p.h | 5 +- src/animation/backend/conductedclipanimator.cpp | 3 +- src/animation/backend/conductedclipanimator_p.h | 8 +- src/animation/backend/fcurve.cpp | 58 +++++++++++++++ src/animation/backend/fcurve_p.h | 63 ++++++++++++++++ src/animation/backend/handler.cpp | 26 ++++++- src/animation/backend/handler_p.h | 12 +++ src/animation/backend/loadanimationclipjob.cpp | 82 ++++++++++++++++++++ src/animation/backend/loadanimationclipjob_p.h | 87 ++++++++++++++++++++++ .../animation/animationclip/tst_animationclip.cpp | 6 ++ .../DefaultSceneEntity.qml | 35 +++++++++ .../animation-keyframe-simple.pro | 5 ++ .../animation-keyframe-simple/cubeanimation.json | 35 +++++++++ tests/manual/animation-keyframe-simple/main.cpp | 25 +++++++ tests/manual/animation-keyframe-simple/main.qml | 53 +++++++++++++ tests/manual/animation-keyframe-simple/main.qrc | 7 ++ tests/manual/manual.pro | 3 +- 25 files changed, 765 insertions(+), 32 deletions(-) create mode 100644 src/animation/backend/backendnode.cpp create mode 100644 src/animation/backend/backendnode_p.h create mode 100644 src/animation/backend/loadanimationclipjob.cpp create mode 100644 src/animation/backend/loadanimationclipjob_p.h create mode 100644 tests/manual/animation-keyframe-simple/DefaultSceneEntity.qml create mode 100644 tests/manual/animation-keyframe-simple/animation-keyframe-simple.pro create mode 100644 tests/manual/animation-keyframe-simple/cubeanimation.json create mode 100644 tests/manual/animation-keyframe-simple/main.cpp create mode 100644 tests/manual/animation-keyframe-simple/main.qml create mode 100644 tests/manual/animation-keyframe-simple/main.qrc diff --git a/src/animation/backend/animationclip.cpp b/src/animation/backend/animationclip.cpp index d5244e8c5..c7d262507 100644 --- a/src/animation/backend/animationclip.cpp +++ b/src/animation/backend/animationclip.cpp @@ -37,17 +37,27 @@ #include "animationclip_p.h" #include #include +#include +#include #include +#include +#include +#include +#include +#include + QT_BEGIN_NAMESPACE namespace Qt3DAnimation { namespace Animation { AnimationClip::AnimationClip() - : Qt3DCore::QBackendNode(ReadOnly) - , m_handler(nullptr) + : BackendNode(ReadOnly) , m_source() + , m_name() + , m_objectName() + , m_channelGroups() { } @@ -56,6 +66,8 @@ void AnimationClip::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr const auto typedChange = qSharedPointerCast>(change); const auto &data = typedChange->data; m_source = data.source; + if (!m_source.isEmpty()) + setDirty(Handler::AnimationClipDirty); } void AnimationClip::cleanup() @@ -63,6 +75,8 @@ void AnimationClip::cleanup() setEnabled(false); m_handler = nullptr; m_source.clear(); + + clearData(); } void AnimationClip::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -70,8 +84,10 @@ void AnimationClip::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) switch (e->type()) { case Qt3DCore::PropertyUpdated: { const auto change = qSharedPointerCast(e); - if (change->propertyName() == QByteArrayLiteral("source")) + if (change->propertyName() == QByteArrayLiteral("source")) { m_source = change->value().toUrl(); + setDirty(Handler::AnimationClipDirty); + } break; } @@ -81,6 +97,58 @@ void AnimationClip::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) QBackendNode::sceneChangeEvent(e); } +/*! + \internal + Called by LoadAnimationClipJob on the threadpool + */ +void AnimationClip::loadAnimation() +{ + qCDebug(Jobs) << Q_FUNC_INFO << m_source; + clearData(); + + // TODO: Handle remote files + QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_source); + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "Could not find animation clip:" << filePath; + return; + } + + QByteArray animationData = file.readAll(); + QJsonDocument document = QJsonDocument::fromJson(animationData); + QJsonObject rootObject = document.object(); + + // TODO: Allow loading of a named animation from a file containing many + QJsonArray animationsArray = rootObject[QLatin1String("animations")].toArray(); + qCDebug(Jobs) << "Found" << animationsArray.size() << "animations:"; + for (int i = 0; i < animationsArray.size(); ++i) { + QJsonObject animation = animationsArray.at(i).toObject(); + qCDebug(Jobs) << "\tName:" << animation[QLatin1String("action")].toString() + << "Object:" << animation[QLatin1String("object")].toString(); + } + + // For now just load the first animation + QJsonObject animation = animationsArray.at(0).toObject(); + m_name = animation[QLatin1String("action")].toString(); + m_objectName = animation[QLatin1String("object")].toString(); + QJsonArray groupsArray = animation[QLatin1String("groups")].toArray(); + const int groupCount = groupsArray.size(); + m_channelGroups.resize(groupCount); + for (int i = 0; i < groupCount; ++i) { + const QJsonObject group = groupsArray.at(i).toObject(); + m_channelGroups[i].read(group); + } + + qCDebug(Jobs) << "Loaded animation data:" << *this; +} + +void AnimationClip::clearData() +{ + m_name.clear(); + m_objectName.clear(); + m_channelGroups.clear(); +} + } // namespace Animation } // namespace Qt3DAnimation diff --git a/src/animation/backend/animationclip_p.h b/src/animation/backend/animationclip_p.h index 9a2da5ed0..6170c3423 100644 --- a/src/animation/backend/animationclip_p.h +++ b/src/animation/backend/animationclip_p.h @@ -48,7 +48,8 @@ // We mean it. // -#include +#include +#include #include QT_BEGIN_NAMESPACE @@ -58,7 +59,7 @@ namespace Animation { class Handler; -class Q_AUTOTEST_EXPORT AnimationClip : public Qt3DCore::QBackendNode +class Q_AUTOTEST_EXPORT AnimationClip : public BackendNode { public: AnimationClip(); @@ -68,15 +69,42 @@ public: QUrl source() const { return m_source; } void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - void setHandler(Handler *handler) { m_handler = handler; } + QString name() const { return m_name; } + QString objectName() const { return m_objectName; } + QVector channelGroups() const { return m_channelGroups; } + + // Called from jobs + void loadAnimation(); private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; + void clearData(); - Handler *m_handler; QUrl m_source; + + QString m_name; + QString m_objectName; + QVector m_channelGroups; }; +#ifndef QT_NO_DEBUG_STREAM +inline QDebug operator<<(QDebug dbg, const AnimationClip &animationClip) +{ + QDebugStateSaver saver(dbg); + dbg << "QNodeId =" << animationClip.peerId() << endl + << "Name =" << animationClip.name() << endl + << "Object Name =" << animationClip.objectName() << endl + << "Channel Groups:" << endl; + + const QVector channelGroups = animationClip.channelGroups(); + for (const auto channelGroup : channelGroups) { + dbg << channelGroup; + } + + return dbg; +} +#endif + } // namespace Animation } // namespace Qt3DAnimation diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri index 1e8b27fa2..86b2b9e15 100644 --- a/src/animation/backend/backend.pri +++ b/src/animation/backend/backend.pri @@ -13,7 +13,9 @@ HEADERS += \ $$PWD/functionrangefinder_p.h \ $$PWD/clipanimator_p.h \ $$PWD/blendedclipanimator_p.h \ - $$PWD/conductedclipanimator_p.h + $$PWD/conductedclipanimator_p.h \ + $$PWD/backendnode_p.h \ + $$PWD/loadanimationclipjob_p.h SOURCES += \ $$PWD/animationclip.cpp \ @@ -23,4 +25,6 @@ SOURCES += \ $$PWD/functionrangefinder.cpp \ $$PWD/clipanimator.cpp \ $$PWD/blendedclipanimator.cpp \ - $$PWD/conductedclipanimator.cpp + $$PWD/conductedclipanimator.cpp \ + $$PWD/backendnode.cpp \ + $$PWD/loadanimationclipjob.cpp diff --git a/src/animation/backend/backendnode.cpp b/src/animation/backend/backendnode.cpp new file mode 100644 index 000000000..6ea7f89c7 --- /dev/null +++ b/src/animation/backend/backendnode.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 "backendnode_p.h" + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +BackendNode::BackendNode(Mode mode) + : Qt3DCore::QBackendNode(mode) + , m_handler(nullptr) +{ +} + +BackendNode::~BackendNode() +{ +} + +void BackendNode::setHandler(Handler *handler) +{ + m_handler = handler; +} + +void BackendNode::setDirty(Handler::DirtyFlag flag) +{ + Q_ASSERT(m_handler); + m_handler->setDirty(flag, peerId()); +} + +} // namespace Animation +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/backendnode_p.h b/src/animation/backend/backendnode_p.h new file mode 100644 index 000000000..d7842517a --- /dev/null +++ b/src/animation/backend/backendnode_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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_ANIMATION_BACKENDNODE_H +#define QT3DANIMATION_ANIMATION_BACKENDNODE_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 +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +class Q_AUTOTEST_EXPORT BackendNode : public Qt3DCore::QBackendNode +{ +public: + BackendNode(Qt3DCore::QBackendNode::Mode mode = ReadOnly); + ~BackendNode(); + + void setHandler(Handler *handler); + +protected: + void setDirty(Handler::DirtyFlag flag); + Handler *m_handler; +}; + +} // namespace Animation +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_BACKENDNODE_H diff --git a/src/animation/backend/blendedclipanimator.cpp b/src/animation/backend/blendedclipanimator.cpp index 1fbd2cd0e..63278dbb6 100644 --- a/src/animation/backend/blendedclipanimator.cpp +++ b/src/animation/backend/blendedclipanimator.cpp @@ -45,8 +45,7 @@ namespace Qt3DAnimation { namespace Animation { BlendedClipAnimator::BlendedClipAnimator() - : Qt3DCore::QBackendNode(ReadOnly) - , m_handler(nullptr) + : BackendNode(ReadOnly) { } diff --git a/src/animation/backend/blendedclipanimator_p.h b/src/animation/backend/blendedclipanimator_p.h index 47c0c7310..022399b25 100644 --- a/src/animation/backend/blendedclipanimator_p.h +++ b/src/animation/backend/blendedclipanimator_p.h @@ -48,7 +48,7 @@ // We mean it. // -#include +#include QT_BEGIN_NAMESPACE @@ -57,7 +57,7 @@ namespace Animation { class Handler; -class Q_AUTOTEST_EXPORT BlendedClipAnimator : public Qt3DCore::QBackendNode +class Q_AUTOTEST_EXPORT BlendedClipAnimator : public BackendNode { public: BlendedClipAnimator(); @@ -66,12 +66,8 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - void setHandler(Handler *handler) { m_handler = handler; } - private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - - Handler *m_handler; }; } // namespace Animation diff --git a/src/animation/backend/clipanimator.cpp b/src/animation/backend/clipanimator.cpp index 1f9af398b..a0e62c636 100644 --- a/src/animation/backend/clipanimator.cpp +++ b/src/animation/backend/clipanimator.cpp @@ -45,8 +45,7 @@ namespace Qt3DAnimation { namespace Animation { ClipAnimator::ClipAnimator() - : Qt3DCore::QBackendNode(ReadOnly) - , m_handler(nullptr) + : BackendNode(ReadOnly) , m_clipId() { } diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h index 6b5b13bb2..87039cec7 100644 --- a/src/animation/backend/clipanimator_p.h +++ b/src/animation/backend/clipanimator_p.h @@ -48,7 +48,7 @@ // We mean it. // -#include +#include #include QT_BEGIN_NAMESPACE @@ -58,7 +58,7 @@ namespace Animation { class Handler; -class Q_AUTOTEST_EXPORT ClipAnimator : public Qt3DCore::QBackendNode +class Q_AUTOTEST_EXPORT ClipAnimator : public BackendNode { public: ClipAnimator(); @@ -73,7 +73,6 @@ public: private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - Handler *m_handler; Qt3DCore::QNodeId m_clipId; }; diff --git a/src/animation/backend/conductedclipanimator.cpp b/src/animation/backend/conductedclipanimator.cpp index 2342e06fc..32db1b7ea 100644 --- a/src/animation/backend/conductedclipanimator.cpp +++ b/src/animation/backend/conductedclipanimator.cpp @@ -45,8 +45,7 @@ namespace Qt3DAnimation { namespace Animation { ConductedClipAnimator::ConductedClipAnimator() - : Qt3DCore::QBackendNode(ReadOnly) - , m_handler(nullptr) + : BackendNode(ReadOnly) { } diff --git a/src/animation/backend/conductedclipanimator_p.h b/src/animation/backend/conductedclipanimator_p.h index 2a96e99ef..d4534447e 100644 --- a/src/animation/backend/conductedclipanimator_p.h +++ b/src/animation/backend/conductedclipanimator_p.h @@ -48,7 +48,7 @@ // We mean it. // -#include +#include QT_BEGIN_NAMESPACE @@ -57,7 +57,7 @@ namespace Animation { class Handler; -class Q_AUTOTEST_EXPORT ConductedClipAnimator : public Qt3DCore::QBackendNode +class Q_AUTOTEST_EXPORT ConductedClipAnimator : public BackendNode { public: ConductedClipAnimator(); @@ -66,12 +66,8 @@ public: void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; - void setHandler(Handler *handler) { m_handler = handler; } - private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; - - Handler *m_handler; }; } // namespace Animation diff --git a/src/animation/backend/fcurve.cpp b/src/animation/backend/fcurve.cpp index 95e3d1568..88874cab5 100644 --- a/src/animation/backend/fcurve.cpp +++ b/src/animation/backend/fcurve.cpp @@ -37,6 +37,10 @@ #include "fcurve_p.h" #include +#include +#include +#include + QT_BEGIN_NAMESPACE namespace Qt3DAnimation { @@ -77,6 +81,60 @@ void FCurve::appendKeyframe(float localTime, const Keyframe &keyframe) m_keyframes.append(keyframe); } +void FCurve::read(const QJsonObject &json) +{ + clearKeyframes(); + + const QJsonArray keyframeArray = json[QLatin1String("keyframes")].toArray(); + const int keyframeCount = keyframeArray.size(); + + for (int i = 0; i < keyframeCount; ++i) { + const QJsonObject keyframeData = keyframeArray.at(i).toObject(); + + // Extract the keyframe local time and value + const QJsonArray keyframeCoords = keyframeData[QLatin1String("co")].toArray(); + float localTime = keyframeCoords.at(0).toDouble(); + + Keyframe keyframe; + keyframe.interpolation = Keyframe::Bezier; + keyframe.value = keyframeCoords.at(1).toDouble(); + + const QJsonArray leftHandle = keyframeData[QLatin1String("handle_left")].toArray(); + keyframe.leftControlPoint[0] = leftHandle.at(0).toDouble(); + keyframe.leftControlPoint[1] = leftHandle.at(1).toDouble(); + + const QJsonArray rightHandle = keyframeData[QLatin1String("handle_right")].toArray(); + keyframe.rightControlPoint[0] = rightHandle.at(0).toDouble(); + keyframe.rightControlPoint[1] = rightHandle.at(1).toDouble(); + + appendKeyframe(localTime, keyframe); + } + + // TODO: Ensure beziers have no loops or cusps by scaling the control points + // back so they do not interset. +} + +void Channel::read(const QJsonObject &json) +{ + fcurve.read(json); +} + +void ChannelGroup::read(const QJsonObject &json) +{ + name = json[QLatin1String("group")].toString(); + const QJsonArray channelsArray = json[QLatin1String("channels")].toArray(); + const int channelCount = channelsArray.size(); + channels.resize(channelCount); + + // TODO: Add channel names to export format + const QStringList channelNameSuffixes = {QLatin1String("X"), QLatin1String("Y"), QLatin1String("Z")}; + for (int i = 0; i < channelCount; ++i) { + const QJsonObject channel = channelsArray.at(i).toObject(); + channels[i].read(channel); + channels[i].name = name + QLatin1String(".") + channelNameSuffixes.at(i); + } +} + } // namespace Animation } // namespace Qt3DAnimation diff --git a/src/animation/backend/fcurve_p.h b/src/animation/backend/fcurve_p.h index 88990fb81..def33941e 100644 --- a/src/animation/backend/fcurve_p.h +++ b/src/animation/backend/fcurve_p.h @@ -52,6 +52,10 @@ #include "functionrangefinder_p.h" #include +#ifndef QT_NO_DEBUG_STREAM +#include +#endif + QT_BEGIN_NAMESPACE namespace Qt3DAnimation { @@ -76,6 +80,8 @@ public: float evaluateAtTime(float localTime) const; + void read(const QJsonObject &json); + private: QVector m_localTimes; QVector m_keyframes; @@ -83,6 +89,63 @@ private: FunctionRangeFinder m_rangeFinder; }; +#ifndef QT_NO_DEBUG_STREAM +inline QDebug operator<<(QDebug dbg, const FCurve &fcurve) +{ + QDebugStateSaver saver(dbg); + dbg << "Keyframe Count =" << fcurve.keyframeCount() << endl; + for (int i = 0; i < fcurve.keyframeCount(); ++i) { + const Keyframe &kf = fcurve.keyframe(i); + dbg << "t =" << fcurve.localTime(i) + << "value =" << kf.value + << "leftHandle =" << kf.leftControlPoint + << "rightHandle =" << kf.rightControlPoint + << endl; + } + return dbg; +} +#endif + +struct Channel +{ + QString name; + FCurve fcurve; + + void read(const QJsonObject &json); +}; + +#ifndef QT_NO_DEBUG_STREAM +inline QDebug operator<<(QDebug dbg, const Channel &channel) +{ + QDebugStateSaver saver(dbg); + dbg << "Channel Name: " << channel.name << endl + << "Fcurve:" << channel.fcurve << endl; + return dbg; +} +#endif + +struct ChannelGroup +{ + QString name; + QVector channels; + + void read(const QJsonObject &json); +}; + +#ifndef QT_NO_DEBUG_STREAM +inline QDebug operator<<(QDebug dbg, const ChannelGroup &channelGroup) +{ + QDebugStateSaver saver(dbg); + dbg << "Name: " << channelGroup.name << endl + << "Channels:" << channelGroup.channels.size() << endl; + + for (const auto channel : qAsConst(channelGroup.channels)) { + dbg << channel; + } + return dbg; +} +#endif + } // namespace Animation } // namespace Qt3DAnimation diff --git a/src/animation/backend/handler.cpp b/src/animation/backend/handler.cpp index bfcb22090..0da9ba4dd 100644 --- a/src/animation/backend/handler.cpp +++ b/src/animation/backend/handler.cpp @@ -36,7 +36,8 @@ #include "handler_p.h" #include - +#include +#include QT_BEGIN_NAMESPACE @@ -48,17 +49,40 @@ Handler::Handler() , m_clipAnimatorManager(new ClipAnimatorManager) , m_blendedClipAnimatorManager(new BlendedClipAnimatorManager) , m_conductedClipAnimatorManager(new ConductedClipAnimatorManager) + , m_loadAnimationClipJob(new LoadAnimationClipJob) { + m_loadAnimationClipJob->setHandler(this); } Handler::~Handler() { } +void Handler::setDirty(DirtyFlag flag, Qt3DCore::QNodeId nodeId) +{ + switch (flag) { + case AnimationClipDirty: { + const auto handle = m_animationClipManager->lookupHandle(nodeId); + m_dirtyAnimationClips.push_back(handle); + break; + } + } +} + QVector Handler::jobsToExecute(qint64 time) { Q_UNUSED(time); QVector jobs; + + // If there are any dirty animation clips that need loading, + // queue up a job for them + if (!m_dirtyAnimationClips.isEmpty()) { + qCDebug(HandlerLogic) << "Added LoadAnimationClipJob"; + m_loadAnimationClipJob->addDirtyAnimationClips(m_dirtyAnimationClips); + jobs.push_back(m_loadAnimationClipJob); + m_dirtyAnimationClips.clear(); + } + return jobs; } diff --git a/src/animation/backend/handler_p.h b/src/animation/backend/handler_p.h index 248184a04..8a5f1bfd4 100644 --- a/src/animation/backend/handler_p.h +++ b/src/animation/backend/handler_p.h @@ -72,12 +72,20 @@ class BlendedClipAnimatorManager; class ConductedClipAnimator; class ConductedClipAnimatorManager; +class LoadAnimationClipJob; + class Q_AUTOTEST_EXPORT Handler { public: Handler(); ~Handler(); + enum DirtyFlag { + AnimationClipDirty + }; + + void setDirty(DirtyFlag flag, Qt3DCore::QNodeId nodeId); + AnimationClipManager *animationClipManager() const Q_DECL_NOTHROW { return m_animationClipManager.data(); } ClipAnimatorManager *clipAnimatorManager() const Q_DECL_NOTHROW { return m_clipAnimatorManager.data(); } BlendedClipAnimatorManager *blendedClipAnimatorManager() const Q_DECL_NOTHROW { return m_blendedClipAnimatorManager.data(); } @@ -91,6 +99,10 @@ private: QScopedPointer m_blendedClipAnimatorManager; QScopedPointer m_conductedClipAnimatorManager; + QVector m_dirtyAnimationClips; + + QSharedPointer m_loadAnimationClipJob; + #if defined(QT_BUILD_INTERNAL) friend class QT_PREPEND_NAMESPACE(tst_Handler); #endif diff --git a/src/animation/backend/loadanimationclipjob.cpp b/src/animation/backend/loadanimationclipjob.cpp new file mode 100644 index 000000000..c94435398 --- /dev/null +++ b/src/animation/backend/loadanimationclipjob.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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$ +** +****************************************************************************/ + +#include "loadanimationclipjob_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +LoadAnimationClipJob::LoadAnimationClipJob() + : Qt3DCore::QAspectJob() + , m_animationClipHandles() +{ +} + +void LoadAnimationClipJob::addDirtyAnimationClips(const QVector &animationClipHandles) +{ + for (const auto handle : animationClipHandles) { + if (!m_animationClipHandles.contains(handle)) + m_animationClipHandles.push_back(handle); + } +} + +void LoadAnimationClipJob::clearDirtyAnimationClips() +{ + m_animationClipHandles.clear(); +} + +void LoadAnimationClipJob::run() +{ + Q_ASSERT(m_handler); + AnimationClipManager *animationClipManager = m_handler->animationClipManager(); + for (const auto animationClipHandle : qAsConst(m_animationClipHandles)) { + AnimationClip *animationClip = animationClipManager->data(animationClipHandle); + animationClip->loadAnimation(); + } + + clearDirtyAnimationClips(); +} + +} // namespace Animation +} // namespace Qt3DAnimation + +QT_END_NAMESPACE diff --git a/src/animation/backend/loadanimationclipjob_p.h b/src/animation/backend/loadanimationclipjob_p.h new file mode 100644 index 000000000..f5d0a3b82 --- /dev/null +++ b/src/animation/backend/loadanimationclipjob_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** 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_ANIMATION_LOADANIMATIONCLIPJOB_H +#define QT3DANIMATION_ANIMATION_LOADANIMATIONCLIPJOB_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 +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Qt3DAnimation { +namespace Animation { + +class Handler; +class FindGraphJob; + +class LoadAnimationClipJob : public Qt3DCore::QAspectJob +{ +public: + LoadAnimationClipJob(); + + void setHandler(Handler *handler) { m_handler = handler; } + Handler *handler() const { return m_handler; } + + void addDirtyAnimationClips(const QVector &animationClipHandles); + void clearDirtyAnimationClips(); + +protected: + void run() Q_DECL_OVERRIDE; + +private: + QVector m_animationClipHandles; + Handler *m_handler; +}; + +} // namespace Animation +} // namespace Qt3DAnimation + +QT_END_NAMESPACE + +#endif // QT3DANIMATION_ANIMATION_LOADANIMATIONCLIPJOB_H diff --git a/tests/auto/animation/animationclip/tst_animationclip.cpp b/tests/auto/animation/animationclip/tst_animationclip.cpp index 735646db6..cd1d2ccf0 100644 --- a/tests/auto/animation/animationclip/tst_animationclip.cpp +++ b/tests/auto/animation/animationclip/tst_animationclip.cpp @@ -45,6 +45,8 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::Animation::AnimationClip backendClip; + Qt3DAnimation::Animation::Handler handler; + backendClip.setHandler(&handler); Qt3DAnimation::QAnimationClip clip; clip.setSource(QUrl::fromLocalFile("walk.qlip")); @@ -62,6 +64,8 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::Animation::AnimationClip backendClip; + Qt3DAnimation::Animation::Handler handler; + backendClip.setHandler(&handler); // THEN QVERIFY(backendClip.peerId().isNull()); @@ -86,6 +90,8 @@ private Q_SLOTS: { // GIVEN Qt3DAnimation::Animation::AnimationClip backendClip; + Qt3DAnimation::Animation::Handler handler; + backendClip.setHandler(&handler); Qt3DCore::QPropertyUpdatedChangePtr updateChange; // WHEN diff --git a/tests/manual/animation-keyframe-simple/DefaultSceneEntity.qml b/tests/manual/animation-keyframe-simple/DefaultSceneEntity.qml new file mode 100644 index 000000000..efffd44c9 --- /dev/null +++ b/tests/manual/animation-keyframe-simple/DefaultSceneEntity.qml @@ -0,0 +1,35 @@ +/************************************************************************* + * + * Copyright (c) 2016, Klaralvdalens Datakonsult AB (KDAB) + * All rights reserved. + * + * See the LICENSE.txt file shipped along with this file for the license. + * + *************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qt3D.Extras 2.0 + +Entity { + id: root + property Camera camera + + components: [ + RenderSettings { + activeFrameGraph: ForwardRenderer { + camera: root.camera + } + }, + // Event Source will be set by the Qt3DQuickWindow + InputSettings { } + ] + + Entity { + components: [ + PointLight { intensity: 0.5 }, + Transform { translation: camera.position } + ] + } +} diff --git a/tests/manual/animation-keyframe-simple/animation-keyframe-simple.pro b/tests/manual/animation-keyframe-simple/animation-keyframe-simple.pro new file mode 100644 index 000000000..04db4207e --- /dev/null +++ b/tests/manual/animation-keyframe-simple/animation-keyframe-simple.pro @@ -0,0 +1,5 @@ +TEMPLATE = app +QT += 3dquickextras 3dquickanimation +SOURCES += main.cpp +RESOURCES += main.qrc +OTHER_FILES += main.qml DefaultSceneEntity.qml diff --git a/tests/manual/animation-keyframe-simple/cubeanimation.json b/tests/manual/animation-keyframe-simple/cubeanimation.json new file mode 100644 index 000000000..e9c55177f --- /dev/null +++ b/tests/manual/animation-keyframe-simple/cubeanimation.json @@ -0,0 +1,35 @@ +{ + "animations": [ + { "object": "Cube", + "action": "CubeAction", + "groups": [ + { "group": "Location", + "channels": [ + { "keyframes": [ + { "co": [1.0, 0.0], + "handle_left": [-22.034278869628906, 0.0], + "handle_right": [24.034278869628906, 0.0]} + ,{ "co": [60.0, 5.0], + "handle_left": [36.965721130371094, 5.0], + "handle_right": [83.0342788696289, 5.0]} + ]} + ,{ "keyframes": [ + { "co": [1.0, 0.0], + "handle_left": [-22.034278869628906, 0.0], + "handle_right": [24.034278869628906, 0.0]} + ,{ "co": [60.0, 0.0], + "handle_left": [36.965721130371094, 0.0], + "handle_right": [83.0342788696289, 0.0]} + ]} + ,{ "keyframes": [ + { "co": [1.0, 0.0], + "handle_left": [-22.034278869628906, 0.0], + "handle_right": [24.034278869628906, 0.0]} + ,{ "co": [60.0, 0.0], + "handle_left": [36.965721130371094, 0.0], + "handle_right": [83.0342788696289, 0.0]} + ]} + ]} + ]} + ] +} diff --git a/tests/manual/animation-keyframe-simple/main.cpp b/tests/manual/animation-keyframe-simple/main.cpp new file mode 100644 index 000000000..fc48fc702 --- /dev/null +++ b/tests/manual/animation-keyframe-simple/main.cpp @@ -0,0 +1,25 @@ +/************************************************************************* + * + * Copyright (c) 2016, Klaralvdalens Datakonsult AB (KDAB) + * All rights reserved. + * + * See the LICENSE.txt file shipped along with this file for the license. + * + *************************************************************************/ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + Qt3DExtras::Quick::Qt3DQuickWindow view; + view.registerAspect(new Qt3DAnimation::QAnimationAspect()); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + return app.exec(); +} diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml new file mode 100644 index 000000000..37f5eba2f --- /dev/null +++ b/tests/manual/animation-keyframe-simple/main.qml @@ -0,0 +1,53 @@ +/************************************************************************* + * + * Copyright (c) 2016, Klaralvdalens Datakonsult AB (KDAB) + * All rights reserved. + * + * See the LICENSE.txt file shipped along with this file for the license. + * + *************************************************************************/ + +import Qt3D.Core 2.0 +import Qt3D.Render 2.0 +import Qt3D.Input 2.0 +import Qt3D.Animation 2.2 +import Qt3D.Extras 2.0 + +DefaultSceneEntity { + id: scene + + Entity { + id: cube + + components: [ + CuboidMesh { + }, + PhongMaterial { + ambient: Qt.rgba(0.02, 0.02, 0.02, 1.0) + diffuse: "blue" + shininess: 50 + }, + Transform { + id: cubeTransform + }, + ClipAnimator { + running: true + clip: AnimationClip { + source: "cubeanimation.json" + } + } + + ] + } + + camera: Camera { + position: Qt.vector3d(10, 10, 10) + viewCenter: Qt.vector3d(0, 0, 0) + } + + OrbitCameraController { + camera: scene.camera + linearSpeed: 8 + lookSpeed: 180 + } +} diff --git a/tests/manual/animation-keyframe-simple/main.qrc b/tests/manual/animation-keyframe-simple/main.qrc new file mode 100644 index 000000000..ca5342f26 --- /dev/null +++ b/tests/manual/animation-keyframe-simple/main.qrc @@ -0,0 +1,7 @@ + + + main.qml + DefaultSceneEntity.qml + cubeanimation.json + + diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 90e9c250e..a2ca61758 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -37,7 +37,8 @@ SUBDIRS += \ transparency-qml-scene3d \ rendercapture-qml \ additional-attributes-qml \ - dynamic-model-loader-qml + dynamic-model-loader-qml \ + animation-keyframe-simple qtHaveModule(widgets): { SUBDIRS += \ -- cgit v1.2.3