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

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