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 \inherits AbstractClipAnimator
60 \since 5.9
61
62 \brief BlendedClipAnimator is a component providing animation playback capabilities of a tree
63 of blend nodes.
64
65 An instance of BlendedClipAnimator can be aggregated by an Entity to add the ability to play
66 back animation clips and to apply the calculated animation values to properties of QObjects.
67
68 Whereas a ClipAnimator gets its animation data from a single animation clip,
69 BlendedClipAnimator can blend together multiple clips. The animation data is obtained by
70 evaluating a so called \e {blend tree}. A blend tree is a hierarchical tree structure where the
71 leaf nodes are value nodes that encapsulate an animation clip (AbstractAnimationClip); and the
72 internal nodes represent blending operations that operate on the nodes pointed to by their
73 operand properties.
74
75 To associate a blend tree with a BlendedClipAnimator, set the animator's blendTree property to
76 point at the root node of your blend tree:
77
78 \badcode
79 BlendedClipAnimator {
80 blendTree: AdditiveClipBlend {
81 ....
82 }
83 }
84 \endcode
85
86 A blend tree can be constructed from the following node types:
87
88 \note The blend node tree should only be edited when the animator is not running.
89
90 \list
91 \li Qt3D.Animation.ClipBlendValue
92 \li Qt3D.Animation.LerpClipBlend
93 \li Qt3D.Animation.AdditiveClipBlend
94 \endlist
95
96 Additional node types will be added over time.
97
98 As an example consider the following blend tree:
99
100 \badcode
101 Clip0----
102 |
103 Lerp Node----
104 | |
105 Clip1---- Additive Node
106 |
107 Clip2----
108 \endcode
109
110 This can be created and used as follows:
111
112 \badcode
113 BlendedClipAnimator {
114 blendTree: AdditiveClipBlend {
115 baseClip: LerpClipBlend {
116 startClip: ClipBlendValue {
117 clip: AnimationClipLoader { source: "walk.json" }
118 }
119
120 endClip: ClipBlendValue {
121 clip: AnimationClipLoader { source: "run.json" }
122 }
123 }
124
125 additiveClip: ClipBlendValue {
126 clip: AnimationClipLoader { source: "wave-arm.json" }
127 }
128 }
129
130 channelMapper: ChannelMapper {...}
131 running: true
132 }
133 \endcode
134
135 By authoring a set of animation clips and blending between them dynamically at runtime with a
136 blend tree, we open up a huge set of possible resulting animations. As some simple examples of
137 the above blend tree, where alpha is the additive factor and beta is the lerp blend factor we
138 can get a 2D continuum of possible animations:
139
140 \badcode
141 (alpha = 0, beta = 1) Running, No arm waving --- (alpha = 1, beta = 1) Running, Arm waving
142 | |
143 | |
144 | |
145 (alpha = 0, beta = 0) Walking, No arm waving --- (alpha = 0, beta = 1) Running, No arm waving
146 \endcode
147
148 More complex blend trees offer even more flexibility for combining your animation clips. Note
149 that the values used to control the blend tree (alpha and beta above) are simple properties on
150 the blend nodes. This means, that these properties themselves can also be controlled by
151 the animation framework.
152*/
153
154/*!
155 \class Qt3DAnimation::QBlendedClipAnimator
156 \inherits Qt3DAnimation::QAbstractClipAnimator
157
158 \inmodule Qt3DAnimation
159 \since 5.9
160
161 \brief QBlendedClipAnimator is a component providing animation playback capabilities of a tree
162 of blend nodes.
163
164 An instance of QBlendedClipAnimator can be aggregated by a QEntity to add the ability to play
165 back animation clips and to apply the calculated animation values to properties of QObjects.
166
167 Whereas a QClipAnimator gets its animation data from a single animation clip,
168 QBlendedClipAnimator can blend together multiple clips. The animation data is obtained by
169 evaluating a so called \e {blend tree}. A blend tree is a hierarchical tree structure where the
170 leaf nodes are value nodes that encapsulate an animation clip (QAbstractAnimationClip); and the
171 internal nodes represent blending operations that operate on the nodes pointed to by their
172 operand properties.
173
174 To associate a blend tree with a QBlendedClipAnimator, set the animator's blendTree property to
175 point at the root node of your blend tree:
176
177 \badcode
178 auto blendTreeRoot = new QAdditiveClipBlend();
179 ...
180 auto animator = new QBlendedClipAnimator();
181 animator->setBlendTree(blendTreeRoot);
182 \endcode
183
184 A blend tree can be constructed from the following node types:
185
186 \note The blend node tree should only be edited when the animator is not running.
187
188 \list
189 \li Qt3DAnimation::QClipBlendValue
190 \li Qt3DAnimation::QLerpClipBlend
191 \li Qt3DAnimation::QAdditiveClipBlend
192 \endlist
193
194 Additional node types will be added over time.
195
196 As an example consider the following blend tree:
197
198 \badcode
199 Clip0----
200 |
201 Lerp Node----
202 | |
203 Clip1---- Additive Node
204 |
205 Clip2----
206 \endcode
207
208 This can be created and used as follows:
209
210 \code
211 // Create leaf nodes of blend tree
212 auto clip0 = new QClipBlendValue(
213 new QAnimationClipLoader(QUrl::fromLocalFile("walk.json")));
214 auto clip1 = new QClipBlendValue(
215 new QAnimationClipLoader(QUrl::fromLocalFile("run.json")));
216 auto clip2 = new QClipBlendValue(
217 new QAnimationClipLoader(QUrl::fromLocalFile("wave-arm.json")));
218
219 // Create blend tree inner nodes
220 auto lerpNode = new QLerpClipBlend();
221 lerpNode->setStartClip(clip0);
222 lerpNode->setEndClip(clip1);
223 lerpNode->setBlendFactor(0.5f); // Half-walk, half-run
224
225 auto additiveNode = new QAdditiveClipBlend();
226 additiveNode->setBaseClip(lerpNode); // Comes from lerp sub-tree
227 additiveNode->setAdditiveClip(clip2);
228 additiveNode->setAdditiveFactor(1.0f); // Wave arm fully
229
230 // Run the animator
231 auto animator = new QBlendedClipAnimator();
232 animator->setBlendTree(additiveNode);
233 animator->setChannelMapper(...);
234 animator->setRunning(true);
235 \endcode
236
237 By authoring a set of animation clips and blending between them dynamically at runtime with a
238 blend tree, we open up a huge set of possible resulting animations. As some simple examples of
239 the above blend tree, where alpha is the additive factor and beta is the lerp blend factor we
240 can get a 2D continuum of possible animations:
241
242 \badcode
243 (alpha = 0, beta = 1) Running, No arm waving --- (alpha = 1, beta = 1) Running, Arm waving
244 | |
245 | |
246 | |
247 (alpha = 0, beta = 0) Walking, No arm waving --- (alpha = 0, beta = 1) Running, No arm waving
248 \endcode
249
250 More complex blend trees offer even more flexibility for combining your animation clips. Note
251 that the values used to control the blend tree (alpha and beta above) are simple properties on
252 the blend nodes. This means, that these properties themselves can also be controlled by
253 the animation framework.
254
255*/
256QBlendedClipAnimator::QBlendedClipAnimator(Qt3DCore::QNode *parent)
257 : Qt3DAnimation::QAbstractClipAnimator(*new QBlendedClipAnimatorPrivate, parent)
258{
259}
260
261/*! \internal */
262QBlendedClipAnimator::QBlendedClipAnimator(QBlendedClipAnimatorPrivate &dd, Qt3DCore::QNode *parent)
263 : Qt3DAnimation::QAbstractClipAnimator(dd, parent)
264{
265}
266
267QBlendedClipAnimator::~QBlendedClipAnimator()
268{
269}
270
271/*!
272 \qmlproperty AbstractClipBlendNode Qt3D.Animation::BlendedClipAnimator::blendTree
273
274 This property holds the root of the animation blend tree that will
275 be evaluated before being interpolated by the animator.
276*/
277/*!
278 \property QBlendedClipAnimator::blendTree
279
280 This property holds the root of the animation blend tree that will be evaluated before being
281 interpolated by the animator.
282*/
283QAbstractClipBlendNode *QBlendedClipAnimator::blendTree() const
284{
285 Q_D(const QBlendedClipAnimator);
286 return d->m_blendTreeRoot;
287}
288
289void QBlendedClipAnimator::setBlendTree(QAbstractClipBlendNode *blendTree)
290{
291 Q_D(QBlendedClipAnimator);
292 if (d->m_blendTreeRoot == blendTree)
293 return;
294
295 if (d->m_blendTreeRoot)
296 d->unregisterDestructionHelper(node: d->m_blendTreeRoot);
297
298 if (blendTree != nullptr && blendTree->parent() == nullptr)
299 blendTree->setParent(this);
300
301 d->m_blendTreeRoot = blendTree;
302
303 if (d->m_blendTreeRoot)
304 d->registerDestructionHelper(node: d->m_blendTreeRoot, func: &QBlendedClipAnimator::setBlendTree, d->m_blendTreeRoot);
305
306 emit blendTreeChanged(blendTree);
307}
308
309/*! \internal */
310Qt3DCore::QNodeCreatedChangeBasePtr QBlendedClipAnimator::createNodeCreationChange() const
311{
312 auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QBlendedClipAnimatorData>::create(arguments: this);
313 QBlendedClipAnimatorData &data = creationChange->data;
314 Q_D(const QBlendedClipAnimator);
315 data.blendTreeRootId = Qt3DCore::qIdForNode(node: d->m_blendTreeRoot);
316 data.mapperId = Qt3DCore::qIdForNode(node: d->m_mapper);
317 data.clockId = Qt3DCore::qIdForNode(node: d->m_clock);
318 data.running = d->m_running;
319 data.loops = d->m_loops;
320 data.normalizedTime = d->m_normalizedTime;
321 return creationChange;
322}
323
324} // namespace Qt3DAnimation
325
326QT_END_NAMESPACE
327

source code of qt3d/src/animation/frontend/qblendedclipanimator.cpp