1/****************************************************************************
2**
3** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39#include "qblendedclipanimator.h"
40#include "qblendedclipanimator_p.h"
41#include <Qt3DAnimation/qabstractclipblendnode.h>
42#include <Qt3DAnimation/qchannelmapper.h>
43#include <Qt3DAnimation/qclock.h>
44
45QT_BEGIN_NAMESPACE
46
47namespace Qt3DAnimation {
48
49QBlendedClipAnimatorPrivate::QBlendedClipAnimatorPrivate()
50 : Qt3DAnimation::QAbstractClipAnimatorPrivate()
51 , m_blendTreeRoot(nullptr)
52{
53}
54
55/*!
56 \qmltype BlendedClipAnimator
57 \instantiates Qt3DAnimation::QBlendedClipAnimator
58 \inqmlmodule Qt3D.Animation
59 \since 5.9
60
61 \brief BlendedClipAnimator is a component providing animation playback capabilities of a tree
62 of blend nodes.
63
64 An instance of BlendedClipAnimator can be aggregated by an Entity to add the ability to play
65 back animation clips and to apply the calculated animation values to properties of QObjects.
66
67 Whereas a ClipAnimator gets its animation data from a single animation clip,
68 BlendedClipAnimator can blend together multiple clips. The animation data is obtained by
69 evaluating a so called \e {blend tree}. A blend tree is a hierarchical tree structure where the
70 leaf nodes are value nodes that encapsulate an animation clip (AbstractAnimationClip); and the
71 internal nodes represent blending operations that operate on the nodes pointed to by their
72 operand properties.
73
74 To associate a blend tree with a BlendedClipAnimator, set the animator's blendTree property to
75 point at the root node of your blend tree:
76
77 \badcode
78 BlendedClipAnimator {
79 blendTree: AdditiveClipBlend {
80 ....
81 }
82 }
83 \endcode
84
85 A blend tree can be constructed from the following node types:
86
87 \note The blend node tree should only be edited when the animator is not running.
88
89 \list
90 \li Qt3D.Animation.ClipBlendValue
91 \li Qt3D.Animation.LerpClipBlend
92 \li Qt3D.Animation.AdditiveClipBlend
93 \endlist
94
95 Additional node types will be added over time.
96
97 As an example consider the following blend tree:
98
99 \badcode
100 Clip0----
101 |
102 Lerp Node----
103 | |
104 Clip1---- Additive Node
105 |
106 Clip2----
107 \endcode
108
109 This can be created and used as follows:
110
111 \badcode
112 BlendedClipAnimator {
113 blendTree: AdditiveClipBlend {
114 baseClip: LerpClipBlend {
115 startClip: ClipBlendValue {
116 clip: AnimationClipLoader { source: "walk.json" }
117 }
118
119 endClip: ClipBlendValue {
120 clip: AnimationClipLoader { source: "run.json" }
121 }
122 }
123
124 additiveClip: ClipBlendValue {
125 clip: AnimationClipLoader { source: "wave-arm.json" }
126 }
127 }
128
129 channelMapper: ChannelMapper {...}
130 running: true
131 }
132 \endcode
133
134 By authoring a set of animation clips and blending between them dynamically at runtime with a
135 blend tree, we open up a huge set of possible resulting animations. As some simple examples of
136 the above blend tree, where alpha is the additive factor and beta is the lerp blend factor we
137 can get a 2D continuum of possible animations:
138
139 \badcode
140 (alpha = 0, beta = 1) Running, No arm waving --- (alpha = 1, beta = 1) Running, Arm waving
141 | |
142 | |
143 | |
144 (alpha = 0, beta = 0) Walking, No arm waving --- (alpha = 0, beta = 1) Running, No arm waving
145 \endcode
146
147 More complex blend trees offer even more flexibility for combining your animation clips. Note
148 that the values used to control the blend tree (alpha and beta above) are simple properties on
149 the blend nodes. This means, that these properties themselves can also be controlled by
150 the animation framework.
151*/
152
153/*!
154 \class Qt3DAnimation::QBlendedClipAnimator
155 \inherits Qt3DAnimation::QAbstractClipAnimator
156
157 \inmodule Qt3DAnimation
158 \since 5.9
159
160 \brief QBlendedClipAnimator is a component providing animation playback capabilities of a tree
161 of blend nodes.
162
163 An instance of QBlendedClipAnimator can be aggregated by a QEntity to add the ability to play
164 back animation clips and to apply the calculated animation values to properties of QObjects.
165
166 Whereas a QClipAnimator gets its animation data from a single animation clip,
167 QBlendedClipAnimator can blend together multiple clips. The animation data is obtained by
168 evaluating a so called \e {blend tree}. A blend tree is a hierarchical tree structure where the
169 leaf nodes are value nodes that encapsulate an animation clip (QAbstractAnimationClip); and the
170 internal nodes represent blending operations that operate on the nodes pointed to by their
171 operand properties.
172
173 To associate a blend tree with a QBlendedClipAnimator, set the animator's blendTree property to
174 point at the root node of your blend tree:
175
176 \badcode
177 auto blendTreeRoot = new QAdditiveClipBlend();
178 ...
179 auto animator = new QBlendedClipAnimator();
180 animator->setBlendTree(blendTreeRoot);
181 \endcode
182
183 A blend tree can be constructed from the following node types:
184
185 \note The blend node tree should only be edited when the animator is not running.
186
187 \list
188 \li Qt3DAnimation::QClipBlendValue
189 \li Qt3DAnimation::QLerpClipBlend
190 \li Qt3DAnimation::QAdditiveClipBlend
191 \endlist
192
193 Additional node types will be added over time.
194
195 As an example consider the following blend tree:
196
197 \badcode
198 Clip0----
199 |
200 Lerp Node----
201 | |
202 Clip1---- Additive Node
203 |
204 Clip2----
205 \endcode
206
207 This can be created and used as follows:
208
209 \code
210 // Create leaf nodes of blend tree
211 auto clip0 = new QClipBlendValue(
212 new QAnimationClipLoader(QUrl::fromLocalFile("walk.json")));
213 auto clip1 = new QClipBlendValue(
214 new QAnimationClipLoader(QUrl::fromLocalFile("run.json")));
215 auto clip2 = new QClipBlendValue(
216 new QAnimationClipLoader(QUrl::fromLocalFile("wave-arm.json")));
217
218 // Create blend tree inner nodes
219 auto lerpNode = new QLerpClipBlend();
220 lerpNode->setStartClip(clip0);
221 lerpNode->setEndClip(clip1);
222 lerpNode->setBlendFactor(0.5f); // Half-walk, half-run
223
224 auto additiveNode = new QAdditiveClipBlend();
225 additiveNode->setBaseClip(lerpNode); // Comes from lerp sub-tree
226 additiveNode->setAdditiveClip(clip2);
227 additiveNode->setAdditiveFactor(1.0f); // Wave arm fully
228
229 // Run the animator
230 auto animator = new QBlendedClipAnimator();
231 animator->setBlendTree(additiveNode);
232 animator->setChannelMapper(...);
233 animator->setRunning(true);
234 \endcode
235
236 By authoring a set of animation clips and blending between them dynamically at runtime with a
237 blend tree, we open up a huge set of possible resulting animations. As some simple examples of
238 the above blend tree, where alpha is the additive factor and beta is the lerp blend factor we
239 can get a 2D continuum of possible animations:
240
241 \badcode
242 (alpha = 0, beta = 1) Running, No arm waving --- (alpha = 1, beta = 1) Running, Arm waving
243 | |
244 | |
245 | |
246 (alpha = 0, beta = 0) Walking, No arm waving --- (alpha = 0, beta = 1) Running, No arm waving
247 \endcode
248
249 More complex blend trees offer even more flexibility for combining your animation clips. Note
250 that the values used to control the blend tree (alpha and beta above) are simple properties on
251 the blend nodes. This means, that these properties themselves can also be controlled by
252 the animation framework.
253
254*/
255QBlendedClipAnimator::QBlendedClipAnimator(Qt3DCore::QNode *parent)
256 : Qt3DAnimation::QAbstractClipAnimator(*new QBlendedClipAnimatorPrivate, parent)
257{
258}
259
260/*! \internal */
261QBlendedClipAnimator::QBlendedClipAnimator(QBlendedClipAnimatorPrivate &dd, Qt3DCore::QNode *parent)
262 : Qt3DAnimation::QAbstractClipAnimator(dd, parent)
263{
264}
265
266QBlendedClipAnimator::~QBlendedClipAnimator()
267{
268}
269
270/*!
271 \qmlproperty AbstractClipBlendNode Qt3D.Animation::BlendedClipAnimator::blendTree
272
273 This property holds the root of the animation blend tree that will
274 be evaluated before being interpolated by the animator.
275*/
276/*!
277 \property QBlendedClipAnimator::blendTree
278
279 This property holds the root of the animation blend tree that will be evaluated before being
280 interpolated by the animator.
281*/
282QAbstractClipBlendNode *QBlendedClipAnimator::blendTree() const
283{
284 Q_D(const QBlendedClipAnimator);
285 return d->m_blendTreeRoot;
286}
287
288void QBlendedClipAnimator::setBlendTree(QAbstractClipBlendNode *blendTree)
289{
290 Q_D(QBlendedClipAnimator);
291 if (d->m_blendTreeRoot == blendTree)
292 return;
293
294 if (d->m_blendTreeRoot)
295 d->unregisterDestructionHelper(d->m_blendTreeRoot);
296
297 if (blendTree != nullptr && blendTree->parent() == nullptr)
298 blendTree->setParent(this);
299
300 d->m_blendTreeRoot = blendTree;
301
302 if (d->m_blendTreeRoot)
303 d->registerDestructionHelper(d->m_blendTreeRoot, &QBlendedClipAnimator::setBlendTree, d->m_blendTreeRoot);
304
305 emit blendTreeChanged(blendTree);
306}
307
308/*! \internal */
309Qt3DCore::QNodeCreatedChangeBasePtr QBlendedClipAnimator::createNodeCreationChange() const
310{
311 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QBlendedClipAnimatorData>::create(this);
312 QBlendedClipAnimatorData &data = creationChange->data;
313 Q_D(const QBlendedClipAnimator);
314 data.blendTreeRootId = Qt3DCore::qIdForNode(d->m_blendTreeRoot);
315 data.mapperId = Qt3DCore::qIdForNode(d->m_mapper);
316 data.clockId = Qt3DCore::qIdForNode(d->m_clock);
317 data.running = d->m_running;
318 data.loops = d->m_loops;
319 data.normalizedTime = d->m_normalizedTime;
320 return creationChange;
321}
322
323} // namespace Qt3DAnimation
324
325QT_END_NAMESPACE
326