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 | |
42 | QT_BEGIN_NAMESPACE |
43 | |
44 | namespace 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 | |
157 | QAnimationControllerPrivate::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 | |
170 | void 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 | |
178 | float QAnimationControllerPrivate::scaledPosition(float position) const |
179 | { |
180 | return m_positionScale * position + m_positionOffset; |
181 | } |
182 | |
183 | QAnimationGroup *QAnimationControllerPrivate::findGroup(const QString &name) |
184 | { |
185 | for (QAnimationGroup *g : qAsConst(t&: m_animationGroups)) { |
186 | if (g->name() == name) |
187 | return g; |
188 | } |
189 | return nullptr; |
190 | } |
191 | |
192 | void QAnimationControllerPrivate::() |
193 | { |
194 | Q_Q(QAnimationController); |
195 | if (!m_entity) |
196 | return; |
197 | QList<Qt3DAnimation::QAbstractAnimation *> animations |
198 | = m_entity->findChildren<Qt3DAnimation::QAbstractAnimation *>(aName: QString(), |
199 | options: m_recursive ? Qt::FindChildrenRecursively : Qt::FindDirectChildrenOnly); |
200 | if (animations.size() > 0) { |
201 | for (Qt3DAnimation::QAbstractAnimation *a : animations) { |
202 | QAnimationGroup *group = findGroup(name: a->animationName()); |
203 | if (!group) { |
204 | group = new QAnimationGroup(q); |
205 | group->setName(a->animationName()); |
206 | m_animationGroups.push_back(t: group); |
207 | } |
208 | group->addAnimation(animation: a); |
209 | } |
210 | } |
211 | } |
212 | void QAnimationControllerPrivate::clearAnimations() |
213 | { |
214 | for (Qt3DAnimation::QAnimationGroup *a : qAsConst(t&: 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 | */ |
223 | QAnimationController::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 | */ |
232 | QVector<QAnimationGroup *> QAnimationController::animationGroupList() |
233 | { |
234 | Q_D(QAnimationController); |
235 | return d->m_animationGroups; |
236 | } |
237 | |
238 | int QAnimationController::activeAnimationGroup() const |
239 | { |
240 | Q_D(const QAnimationController); |
241 | return d->m_activeAnimationGroup; |
242 | } |
243 | |
244 | float QAnimationController::position() const |
245 | { |
246 | Q_D(const QAnimationController); |
247 | return d->m_position; |
248 | } |
249 | |
250 | float QAnimationController::positionScale() const |
251 | { |
252 | Q_D(const QAnimationController); |
253 | return d->m_positionScale; |
254 | } |
255 | |
256 | float QAnimationController::positionOffset() const |
257 | { |
258 | Q_D(const QAnimationController); |
259 | return d->m_positionOffset; |
260 | } |
261 | |
262 | Qt3DCore::QEntity *QAnimationController::entity() const |
263 | { |
264 | Q_D(const QAnimationController); |
265 | return d->m_entity; |
266 | } |
267 | |
268 | bool 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 | */ |
277 | void 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(position: d->m_position); |
284 | } |
285 | |
286 | /*! |
287 | Adds the given \a animationGroup to the controller. |
288 | */ |
289 | void QAnimationController::addAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) |
290 | { |
291 | Q_D(QAnimationController); |
292 | if (!d->m_animationGroups.contains(t: animationGroup)) |
293 | d->m_animationGroups.push_back(t: animationGroup); |
294 | } |
295 | |
296 | /*! |
297 | Removes the given \a animationGroup from the controller. |
298 | */ |
299 | void QAnimationController::removeAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) |
300 | { |
301 | Q_D(QAnimationController); |
302 | if (d->m_animationGroups.contains(t: animationGroup)) |
303 | d->m_animationGroups.removeAll(t: animationGroup); |
304 | if (d->m_activeAnimationGroup >= d->m_animationGroups.size()) |
305 | d->m_activeAnimationGroup = 0; |
306 | } |
307 | |
308 | void QAnimationController::setActiveAnimationGroup(int index) |
309 | { |
310 | Q_D(QAnimationController); |
311 | if (d->m_activeAnimationGroup != index) { |
312 | d->m_activeAnimationGroup = index; |
313 | d->updatePosition(position: d->m_position); |
314 | emit activeAnimationGroupChanged(index); |
315 | } |
316 | } |
317 | void QAnimationController::setPosition(float position) |
318 | { |
319 | Q_D(QAnimationController); |
320 | if (!qFuzzyCompare(p1: d->m_scaledPosition, p2: d->scaledPosition(position))) { |
321 | d->updatePosition(position); |
322 | emit positionChanged(position); |
323 | } |
324 | } |
325 | |
326 | void QAnimationController::setPositionScale(float scale) |
327 | { |
328 | Q_D(QAnimationController); |
329 | if (!qFuzzyCompare(p1: d->m_positionScale, p2: scale)) { |
330 | d->m_positionScale = scale; |
331 | emit positionScaleChanged(scale); |
332 | } |
333 | } |
334 | |
335 | void QAnimationController::setPositionOffset(float offset) |
336 | { |
337 | Q_D(QAnimationController); |
338 | if (!qFuzzyCompare(p1: d->m_positionOffset, p2: offset)) { |
339 | d->m_positionOffset = offset; |
340 | emit positionOffsetChanged(offset); |
341 | } |
342 | } |
343 | |
344 | void 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(position: d->m_position); |
352 | emit entityChanged(entity); |
353 | } |
354 | } |
355 | |
356 | void 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 | */ |
369 | int 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 | */ |
382 | QAnimationGroup *QAnimationController::getGroup(int index) const |
383 | { |
384 | Q_D(const QAnimationController); |
385 | return d->m_animationGroups.at(i: index); |
386 | } |
387 | |
388 | } // Qt3DAnimation |
389 | |
390 | QT_END_NAMESPACE |
391 | |