1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQuick 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 | |
40 | #include "qquicksprite_p.h" |
41 | #include "qquickimagebase_p.h" |
42 | #include <qqml.h> |
43 | #include <QDebug> |
44 | #include <QRandomGenerator> |
45 | |
46 | QT_BEGIN_NAMESPACE |
47 | |
48 | /*! |
49 | \qmltype Sprite |
50 | \instantiates QQuickSprite |
51 | \inqmlmodule QtQuick |
52 | \ingroup qtquick-visual-utility |
53 | \brief Specifies sprite animations. |
54 | |
55 | Sprite defines a series of one or more frames to be animated and rendered by SpriteSequence. |
56 | The sprites can be in the middle of an image file, or split along multiple rows, as long as they form |
57 | a contiguous line wrapping to the next row of the file from the left edge of the file. |
58 | |
59 | For full details, see the \l{Sprite Animations} overview. |
60 | */ |
61 | /*! |
62 | \qmlproperty int QtQuick::Sprite::duration |
63 | |
64 | Duration of the animation. Values below 0 are invalid. |
65 | |
66 | If frameRate is valid then it will be used to calculate the duration of the frames. |
67 | If not, and frameDuration is valid, then frameDuration will be used. Otherwise duration is used. |
68 | */ |
69 | /*! |
70 | \qmlproperty int QtQuick::Sprite::durationVariation |
71 | |
72 | The duration of the animation can vary by up to this amount. Variation will never decrease the |
73 | length of the animation to less than 0. |
74 | |
75 | durationVariation will only take effect if duration is |
76 | used to calculate the duration of frames. |
77 | |
78 | Default is 0. |
79 | */ |
80 | |
81 | /*! |
82 | \qmlproperty qreal QtQuick::Sprite::frameRate |
83 | |
84 | Frames per second to show in the animation. Values below 0 are invalid. |
85 | |
86 | If frameRate is valid then it will be used to calculate the duration of the frames. |
87 | If not, and frameDuration is valid , then frameDuration will be used. Otherwise duration is used. |
88 | */ |
89 | /*! |
90 | \qmlproperty qreal QtQuick::Sprite::frameRateVariation |
91 | |
92 | The frame rate between animations can vary by up to this amount. Variation will never decrease the |
93 | length of the animation to less than 0. |
94 | |
95 | frameRateVariation will only take effect if frameRate is |
96 | used to calculate the duration of frames. |
97 | |
98 | Default is 0. |
99 | */ |
100 | |
101 | /*! |
102 | \qmlproperty int QtQuick::Sprite::frameDuration |
103 | |
104 | Duration of each frame of the animation in milliseconds. Values below 0 are invalid. |
105 | |
106 | If frameRate is valid then it will be used to calculate the duration of the frames. |
107 | If not, and frameDuration is valid, then frameDuration will be used. Otherwise duration is used. |
108 | */ |
109 | /*! |
110 | \qmlproperty int QtQuick::Sprite::frameDurationVariation |
111 | |
112 | The duration of a frame in the animation can vary by up to this amount. Variation will never decrease the |
113 | length of the animation to less than 0. |
114 | |
115 | frameDurationVariation will only take effect if frameDuration is |
116 | used to calculate the duration of frames. |
117 | |
118 | Default is 0. |
119 | */ |
120 | |
121 | /*! |
122 | \qmlproperty string QtQuick::Sprite::name |
123 | |
124 | The name of this sprite, for use in the to property of other sprites. |
125 | */ |
126 | /*! |
127 | \qmlproperty QVariantMap QtQuick::Sprite::to |
128 | |
129 | A list of other sprites and weighted transitions to them, |
130 | for example {"a":1, "b":2, "c":0} would specify that one-third should |
131 | transition to sprite "a" when this sprite is done, and two-thirds should |
132 | transition to sprite "b" when this sprite is done. As the transitions are |
133 | chosen randomly, these proportions will not be exact. With "c":0 in the list, |
134 | no sprites will randomly transition to "c", but it wll be a valid path if a sprite |
135 | goal is set. |
136 | |
137 | If no list is specified, or the sum of weights in the list is zero, then the sprite |
138 | will repeat itself after completing. |
139 | */ |
140 | /*! |
141 | \qmlproperty int QtQuick::Sprite::frameCount |
142 | |
143 | Number of frames in this sprite. |
144 | */ |
145 | /*! |
146 | \qmlproperty int QtQuick::Sprite::frameHeight |
147 | |
148 | Height of a single frame in this sprite. |
149 | */ |
150 | /*! |
151 | \qmlproperty int QtQuick::Sprite::frameWidth |
152 | |
153 | Width of a single frame in this sprite. |
154 | */ |
155 | /*! |
156 | \qmlproperty int QtQuick::Sprite::frameX |
157 | |
158 | The X coordinate in the image file of the first frame of the sprite. |
159 | */ |
160 | /*! |
161 | \qmlproperty int QtQuick::Sprite::frameY |
162 | |
163 | The Y coordinate in the image file of the first frame of the sprite. |
164 | */ |
165 | /*! |
166 | \qmlproperty url QtQuick::Sprite::source |
167 | |
168 | The image source for the animation. |
169 | |
170 | If frameHeight and frameWidth are not specified, it is assumed to be a single long row of square frames. |
171 | Otherwise, it can be multiple contiguous rows or rectangluar frames, when one row runs out the next will be used. |
172 | |
173 | If frameX and frameY are specified, the row of frames will be taken with that x/y coordinate as the upper left corner. |
174 | */ |
175 | |
176 | /*! |
177 | \qmlproperty bool QtQuick::Sprite::reverse |
178 | |
179 | If true, then the animation will be played in reverse. |
180 | |
181 | Default is false. |
182 | */ |
183 | |
184 | /*! |
185 | \qmlproperty bool QtQuick::Sprite::randomStart |
186 | |
187 | If true, then the animation will start its first animation with a random amount of its duration skipped. |
188 | This allows them to not look like they all just started when the animation begins. |
189 | |
190 | This only affects the very first animation played. Transitioning to another animation, or the same |
191 | animation again, will not trigger this. |
192 | |
193 | Default is false. |
194 | */ |
195 | |
196 | /*! |
197 | \qmlproperty bool QtQuick::Sprite::frameSync |
198 | |
199 | If true, then the animation will have no duration. Instead, the animation will advance |
200 | one frame each time a frame is rendered to the screen. This synchronizes it with the painting |
201 | rate as opposed to elapsed time. |
202 | |
203 | If frameSync is set to true, it overrides all of duration, frameRate and frameDuration. |
204 | |
205 | Default is false. |
206 | */ |
207 | |
208 | static const int unsetDuration = -2;//-1 means perframe for duration |
209 | QQuickSprite::QQuickSprite(QObject *parent) |
210 | : QQuickStochasticState(parent) |
211 | , m_generatedCount(0) |
212 | , m_framesPerRow(0) |
213 | , m_rowY(0) |
214 | , m_rowStartX(0) |
215 | , m_reverse(false) |
216 | , m_frameHeight(0) |
217 | , m_frameWidth(0) |
218 | , m_frames(1) |
219 | , m_frameX(0) |
220 | , m_frameY(0) |
221 | , m_frameRate(unsetDuration) |
222 | , m_frameRateVariation(0) |
223 | , m_frameDuration(unsetDuration) |
224 | , m_frameDurationVariation(0) |
225 | , m_frameSync(false) |
226 | , m_devicePixelRatio(1.0) |
227 | { |
228 | } |
229 | |
230 | /*! \internal */ |
231 | QQuickSprite::~QQuickSprite() |
232 | { |
233 | } |
234 | |
235 | int QQuickSprite::variedDuration() const //Deals with precedence when multiple durations are set |
236 | { |
237 | if (m_frameSync) |
238 | return 0; |
239 | |
240 | if (m_frameRate != unsetDuration) { |
241 | qreal fpms = (m_frameRate |
242 | + (m_frameRateVariation * QRandomGenerator::global()->generateDouble() * 2) |
243 | - m_frameRateVariation) / 1000.0; |
244 | return qMax(a: qreal(0.0) , b: m_frames / fpms); |
245 | } else if (m_frameDuration != unsetDuration) { |
246 | int mspf = m_frameDuration |
247 | + (m_frameDurationVariation * QRandomGenerator::global()->generateDouble() * 2) |
248 | - m_frameDurationVariation; |
249 | return qMax(a: 0, b: m_frames * mspf); |
250 | } else if (duration() >= 0) { |
251 | qWarning() << "Sprite::duration is changing meaning to the full animation duration." ; |
252 | qWarning() << "Use Sprite::frameDuration for the old meaning, of per frame duration." ; |
253 | qWarning() << "As an interim measure, duration/durationVariation means the same as frameDuration/frameDurationVariation, and you'll get this warning spewed out everywhere to motivate you." ; |
254 | //Note that the spammyness is due to this being the best location to detect, but also called once each animation loop |
255 | return QQuickStochasticState::variedDuration() * m_frames; |
256 | } |
257 | return 1000; //When nothing set |
258 | } |
259 | |
260 | void QQuickSprite::startImageLoading() |
261 | { |
262 | m_pix.clear(this); |
263 | if (!m_source.isEmpty()) { |
264 | QQmlEngine *e = qmlEngine(this); |
265 | if (!e) { //If not created in QML, you must set the QObject parent to the QML element so this can work |
266 | e = qmlEngine(parent()); |
267 | if (!e) |
268 | qWarning() << "QQuickSprite: Cannot find QQmlEngine - this class is only for use in QML and may not work" ; |
269 | } |
270 | QUrl loadUrl = m_source; |
271 | QQuickImageBase::resolve2xLocalFile(url: m_source, targetDevicePixelRatio: m_devicePixelRatio, sourceUrl: &loadUrl, sourceDevicePixelRatio: &m_devicePixelRatio); |
272 | |
273 | m_pix.load(e, loadUrl); |
274 | } |
275 | } |
276 | |
277 | QT_END_NAMESPACE |
278 | |
279 | #include "moc_qquicksprite_p.cpp" |
280 | |