1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
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 http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qanimationcontroller.h"
38#include "qanimationgroup.h"
39
40#include <private/qanimationcontroller_p.h>
41
42QT_BEGIN_NAMESPACE
43
44namespace Qt3DAnimation {
45
46/*!
47 \class Qt3DAnimation::QAnimationController
48 \brief A controller class for animations.
49 \inmodule Qt3DAnimation
50 \since 5.9
51 \inherits QObject
52
53 Qt3DAnimation::QAnimationController class controls the selection and playback of animations.
54 The class can be used to find all animations from Qt3DCore::QEntity tree and create
55 \l {Qt3DAnimation::QAnimationGroup} {QAnimationGroups} from the animations with the same name.
56 The user can select which animation group is currently controlled with the animation
57 controller by setting the active animation. The animation position is then propagated to
58 that group after scaling and offsetting the provided position value with the
59 positionScale and positionOffset values.
60
61 \note that the animation controller doesn't have internal timer, but instead the user
62 is responsible for updating the position property in timely manner.
63*/
64
65/*!
66 \qmltype AnimationController
67 \brief A controller type for animations.
68 \inqmlmodule Qt3D.Animation
69 \since 5.9
70 \instantiates Qt3DAnimation::QAnimationController
71
72 AnimationController type controls the selection and playback of animations.
73 The type can be used to find all animations from Entity tree and create
74 \l {AnimationGroup} {AnimationGroups} from the animations with the same name.
75 The user can select which animation group is currently controlled with the animation
76 controller by setting the active animation. The animation position is then propagated to
77 that group after scaling and offsetting the provided position value with the
78 positionScale and positionOffset values.
79
80 \note that the animation controller doesn't have internal timer, but instead the user
81 is responsible for updating the position property in timely manner.
82*/
83
84/*!
85 \property Qt3DAnimation::QAnimationController::activeAnimationGroup
86 Holds the currectly active animation group.
87*/
88/*!
89 \property Qt3DAnimation::QAnimationController::position
90 Holds the current position of the animation. When the position is set,
91 it is scaled and offset with positionScale/positionOffset and propagated
92 to the active animation group.
93*/
94/*!
95 \property Qt3DAnimation::QAnimationController::positionScale
96 Holds the position scale of the animation.
97*/
98/*!
99 \property Qt3DAnimation::QAnimationController::positionOffset
100 Holds the position offset of the animation.
101*/
102/*!
103 \property Qt3DAnimation::QAnimationController::entity
104 Holds the entity animations are gathered and grouped from. If the controller already
105 holds animations, they are cleared.
106*/
107/*!
108 \property Qt3DAnimation::QAnimationController::recursive
109 Holds whether the recursively search the entity tree when gathering animations from the entity.
110 If set to true, the animations are searched also from the child entities of the entity.
111 If set to false, only the entity passed to the controller is searched.
112*/
113
114/*!
115 \qmlproperty int AnimationController::activeAnimationGroup
116 Holds the currectly active animation group.
117*/
118/*!
119 \qmlproperty real AnimationController::position
120 Holds the current position of the animation. When the position is set,
121 it is scaled and offset with positionScale/positionOffset and propagated
122 to the active animation group.
123*/
124/*!
125 \qmlproperty real AnimationController::positionScale
126 Holds the position scale of the animation.
127*/
128/*!
129 \qmlproperty real AnimationController::positionOffset
130 Holds the position offset of the animation.
131*/
132/*!
133 \qmlproperty Entity AnimationController::entity
134 Holds the entity animations are gathered and grouped from. If the controller already
135 holds animations, they are cleared.
136*/
137/*!
138 \qmlproperty bool AnimationController::recursive
139 Holds whether the recursively search the entity tree when gathering animations from the entity.
140 If set to true, the animations are searched also from the child entities of the entity.
141 If set to false, only the entity passed to the controller is searched.
142*/
143/*!
144 \qmlproperty list<AnimationGroup> AnimationController::animationGroups
145 Holds the list of animation groups in the controller.
146*/
147/*!
148 \qmlmethod int Qt3D.Animation::AnimationController::getAnimationIndex(name)
149 Returns the index of the animation with \a name. Returns -1 if no AnimationGroup
150 with the given name is found.
151*/
152/*!
153 \qmlmethod AnimationGroup Qt3D.Animation::AnimationController::getGroup(index)
154 Returns the AnimationGroup with the given \a index.
155*/
156
157QAnimationControllerPrivate::QAnimationControllerPrivate()
158 : QObjectPrivate()
159 , m_activeAnimationGroup(0)
160 , m_position(0.0f)
161 , m_scaledPosition(0.0f)
162 , m_positionScale(1.0f)
163 , m_positionOffset(0.0f)
164 , m_entity(nullptr)
165 , m_recursive(true)
166{
167
168}
169
170void QAnimationControllerPrivate::updatePosition(float position)
171{
172 m_position = position;
173 m_scaledPosition = scaledPosition(position);
174 if (m_activeAnimationGroup >= 0 && m_activeAnimationGroup < m_animationGroups.size())
175 m_animationGroups[m_activeAnimationGroup]->setPosition(m_scaledPosition);
176}
177
178float QAnimationControllerPrivate::scaledPosition(float position) const
179{
180 return m_positionScale * position + m_positionOffset;
181}
182
183QAnimationGroup *QAnimationControllerPrivate::findGroup(const QString &name)
184{
185 for (QAnimationGroup *g : qAsConst(m_animationGroups)) {
186 if (g->name() == name)
187 return g;
188 }
189 return nullptr;
190}
191
192void QAnimationControllerPrivate::extractAnimations()
193{
194 Q_Q(QAnimationController);
195 if (!m_entity)
196 return;
197 QList<Qt3DAnimation::QAbstractAnimation *> animations
198 = m_entity->findChildren<Qt3DAnimation::QAbstractAnimation *>(QString(),
199 m_recursive ? Qt::FindChildrenRecursively : Qt::FindDirectChildrenOnly);
200 if (animations.size() > 0) {
201 for (Qt3DAnimation::QAbstractAnimation *a : animations) {
202 QAnimationGroup *group = findGroup(a->animationName());
203 if (!group) {
204 group = new QAnimationGroup(q);
205 group->setName(a->animationName());
206 m_animationGroups.push_back(group);
207 }
208 group->addAnimation(a);
209 }
210 }
211}
212void QAnimationControllerPrivate::clearAnimations()
213{
214 for (Qt3DAnimation::QAnimationGroup *a : qAsConst(m_animationGroups))
215 a->deleteLater();
216 m_animationGroups.clear();
217 m_activeAnimationGroup = 0;
218}
219
220/*!
221 Constructs a new QAnimationController with \a parent.
222 */
223QAnimationController::QAnimationController(QObject *parent)
224 : QObject(*new QAnimationControllerPrivate, parent)
225{
226
227}
228
229/*!
230 Returns the list of animation groups the conroller is currently holding.
231 */
232QVector<QAnimationGroup *> QAnimationController::animationGroupList()
233{
234 Q_D(QAnimationController);
235 return d->m_animationGroups;
236}
237
238int QAnimationController::activeAnimationGroup() const
239{
240 Q_D(const QAnimationController);
241 return d->m_activeAnimationGroup;
242}
243
244float QAnimationController::position() const
245{
246 Q_D(const QAnimationController);
247 return d->m_position;
248}
249
250float QAnimationController::positionScale() const
251{
252 Q_D(const QAnimationController);
253 return d->m_positionScale;
254}
255
256float QAnimationController::positionOffset() const
257{
258 Q_D(const QAnimationController);
259 return d->m_positionOffset;
260}
261
262Qt3DCore::QEntity *QAnimationController::entity() const
263{
264 Q_D(const QAnimationController);
265 return d->m_entity;
266}
267
268bool QAnimationController::recursive() const
269{
270 Q_D(const QAnimationController);
271 return d->m_recursive;
272}
273
274/*!
275 Sets the \a animationGroups for the controller. Old groups are cleared.
276 */
277void QAnimationController::setAnimationGroups(const QVector<Qt3DAnimation::QAnimationGroup *> &animationGroups)
278{
279 Q_D(QAnimationController);
280 d->m_animationGroups = animationGroups;
281 if (d->m_activeAnimationGroup >= d->m_animationGroups.size())
282 d->m_activeAnimationGroup = 0;
283 d->updatePosition(d->m_position);
284}
285
286/*!
287 Adds the given \a animationGroup to the controller.
288 */
289void QAnimationController::addAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup)
290{
291 Q_D(QAnimationController);
292 if (!d->m_animationGroups.contains(animationGroup))
293 d->m_animationGroups.push_back(animationGroup);
294}
295
296/*!
297 Removes the given \a animationGroup from the controller.
298 */
299void QAnimationController::removeAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup)
300{
301 Q_D(QAnimationController);
302 if (d->m_animationGroups.contains(animationGroup))
303 d->m_animationGroups.removeAll(animationGroup);
304 if (d->m_activeAnimationGroup >= d->m_animationGroups.size())
305 d->m_activeAnimationGroup = 0;
306}
307
308void QAnimationController::setActiveAnimationGroup(int index)
309{
310 Q_D(QAnimationController);
311 if (d->m_activeAnimationGroup != index) {
312 d->m_activeAnimationGroup = index;
313 d->updatePosition(d->m_position);
314 emit activeAnimationGroupChanged(index);
315 }
316}
317void QAnimationController::setPosition(float position)
318{
319 Q_D(QAnimationController);
320 if (!qFuzzyCompare(d->m_scaledPosition, d->scaledPosition(position))) {
321 d->updatePosition(position);
322 emit positionChanged(position);
323 }
324}
325
326void QAnimationController::setPositionScale(float scale)
327{
328 Q_D(QAnimationController);
329 if (!qFuzzyCompare(d->m_positionScale, scale)) {
330 d->m_positionScale = scale;
331 emit positionScaleChanged(scale);
332 }
333}
334
335void QAnimationController::setPositionOffset(float offset)
336{
337 Q_D(QAnimationController);
338 if (!qFuzzyCompare(d->m_positionOffset, offset)) {
339 d->m_positionOffset = offset;
340 emit positionOffsetChanged(offset);
341 }
342}
343
344void QAnimationController::setEntity(Qt3DCore::QEntity *entity)
345{
346 Q_D(QAnimationController);
347 if (d->m_entity != entity) {
348 d->clearAnimations();
349 d->m_entity = entity;
350 d->extractAnimations();
351 d->updatePosition(d->m_position);
352 emit entityChanged(entity);
353 }
354}
355
356void QAnimationController::setRecursive(bool recursive)
357{
358 Q_D(QAnimationController);
359 if (d->m_recursive != recursive) {
360 d->m_recursive = recursive;
361 emit recursiveChanged(recursive);
362 }
363}
364
365/*!
366 Returns the index of the animation with \a name. Returns -1 if no AnimationGroup
367 with the given name is found.
368*/
369int QAnimationController::getAnimationIndex(const QString &name) const
370{
371 Q_D(const QAnimationController);
372 for (int i = 0; i < d->m_animationGroups.size(); ++i) {
373 if (d->m_animationGroups[i]->name() == name)
374 return i;
375 }
376 return -1;
377}
378
379/*!
380 Returns the AnimationGroup with the given \a index.
381*/
382QAnimationGroup *QAnimationController::getGroup(int index) const
383{
384 Q_D(const QAnimationController);
385 return d->m_animationGroups.at(index);
386}
387
388} // Qt3DAnimation
389
390QT_END_NAMESPACE
391