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#ifndef QQUICKSPRITEENGINE_P_H
41#define QQUICKSPRITEENGINE_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <private/qtquickglobal_p.h>
55
56QT_REQUIRE_CONFIG(quick_sprite);
57
58#include <QObject>
59#include <QVector>
60#include <QTimer>
61#include <QElapsedTimer>
62#include <QList>
63#include <QQmlListProperty>
64#include <QImage>
65#include <QPair>
66#include <QRandomGenerator>
67#include <private/qquickpixmapcache_p.h>
68#include <private/qtquickglobal_p.h>
69
70QT_BEGIN_NAMESPACE
71
72class QQuickSprite;
73class Q_QUICK_PRIVATE_EXPORT QQuickStochasticState : public QObject //Currently for internal use only - Sprite and ParticleGroup
74{
75 Q_OBJECT
76 Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
77 Q_PROPERTY(int durationVariation READ durationVariation WRITE setDurationVariation NOTIFY durationVariationChanged)
78 //Note that manually advanced sprites need to query this variable and implement own behaviour for it
79 Q_PROPERTY(bool randomStart READ randomStart WRITE setRandomStart NOTIFY randomStartChanged)
80 Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged)
81 Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
82
83public:
84 QQuickStochasticState(QObject* parent = nullptr)
85 : QObject(parent)
86 {
87 }
88
89 int duration() const
90 {
91 return m_duration;
92 }
93
94 QString name() const
95 {
96 return m_name;
97 }
98
99 QVariantMap to() const
100 {
101 return m_to;
102 }
103
104 int durationVariation() const
105 {
106 return m_durationVariation;
107 }
108
109
110 virtual int variedDuration() const
111 {
112 return qMax(a: 0.0 , b: m_duration
113 + (m_durationVariation * QRandomGenerator::global()->bounded(highest: 2.0))
114 - m_durationVariation);
115 }
116
117 bool randomStart() const
118 {
119 return m_randomStart;
120 }
121
122Q_SIGNALS:
123 void durationChanged(int arg);
124
125 void nameChanged(const QString &arg);
126
127 void toChanged(const QVariantMap &arg);
128
129 void durationVariationChanged(int arg);
130
131 void entered();//### Just playing around - don't expect full state API
132
133 void randomStartChanged(bool arg);
134
135public Q_SLOTS:
136 void setDuration(int arg)
137 {
138 if (m_duration != arg) {
139 m_duration = arg;
140 Q_EMIT durationChanged(arg);
141 }
142 }
143
144 void setName(const QString &arg)
145 {
146 if (m_name != arg) {
147 m_name = arg;
148 Q_EMIT nameChanged(arg);
149 }
150 }
151
152 void setTo(const QVariantMap &arg)
153 {
154 if (m_to != arg) {
155 m_to = arg;
156 Q_EMIT toChanged(arg);
157 }
158 }
159
160 void setDurationVariation(int arg)
161 {
162 if (m_durationVariation != arg) {
163 m_durationVariation = arg;
164 Q_EMIT durationVariationChanged(arg);
165 }
166 }
167
168 void setRandomStart(bool arg)
169 {
170 if (m_randomStart != arg) {
171 m_randomStart = arg;
172 Q_EMIT randomStartChanged(arg);
173 }
174 }
175
176private:
177 QString m_name;
178 QVariantMap m_to;
179 int m_duration = -1;
180 int m_durationVariation = 0;
181
182 friend class QQuickStochasticEngine;
183 bool m_randomStart = false;
184};
185
186class Q_QUICK_PRIVATE_EXPORT QQuickStochasticEngine : public QObject
187{
188 Q_OBJECT
189 //TODO: Optimize single state case?
190 Q_PROPERTY(QString globalGoal READ globalGoal WRITE setGlobalGoal NOTIFY globalGoalChanged)
191 Q_PROPERTY(QQmlListProperty<QQuickStochasticState> states READ states)
192public:
193 explicit QQuickStochasticEngine(QObject *parent = nullptr);
194 QQuickStochasticEngine(const QList<QQuickStochasticState*> &states, QObject *parent = nullptr);
195 ~QQuickStochasticEngine() override;
196
197 QQmlListProperty<QQuickStochasticState> states()
198 {
199 return QQmlListProperty<QQuickStochasticState>(this, &m_states);
200 }
201
202 QString globalGoal() const
203 {
204 return m_globalGoal;
205 }
206
207 int count() const {return m_things.count();}
208 void setCount(int c);
209
210 void setGoal(int state, int sprite=0, bool jump=false);
211 void start(int index=0, int state=0);
212 virtual void restart(int index=0);
213 virtual void advance(int index=0);//Sends state to the next chosen state, unlike goal.
214 void stop(int index=0);
215 int curState(int index=0) const {return m_things[index];}
216
217 QQuickStochasticState* state(int idx) const {return m_states[idx];}
218 int stateIndex(QQuickStochasticState* s) const {return m_states.indexOf(t: s);}
219 int stateIndex(const QString& s) const {
220 for (int i=0; i<m_states.count(); i++)
221 if (m_states[i]->name() == s)
222 return i;
223 return -1;
224 }
225
226 int stateCount() {return m_states.count();}
227private:
228Q_SIGNALS:
229
230 void globalGoalChanged(const QString &arg);
231 void stateChanged(int idx);
232
233public Q_SLOTS:
234 void setGlobalGoal(const QString &arg)
235 {
236 if (m_globalGoal != arg) {
237 m_globalGoal = arg;
238 Q_EMIT globalGoalChanged(arg);
239 }
240 }
241
242 uint updateSprites(uint time);
243
244protected:
245 friend class QQuickParticleSystem;
246 void addToUpdateList(uint t, int idx);
247 int nextState(int curState, int idx=0);
248 int goalSeek(int curState, int idx, int dist=-1);
249 QList<QQuickStochasticState*> m_states;
250 //### Consider struct or class for the four data variables?
251 QVector<int> m_things;//int is the index in m_states of the current state
252 QVector<int> m_goals;
253 QVector<int> m_duration;
254 QVector<int> m_startTimes;
255 QVector<QPair<uint, QVector<int> > > m_stateUpdates;//### This could be done faster - priority queue?
256
257 QElapsedTimer m_advanceTimer;
258 uint m_timeOffset;
259 QString m_globalGoal;
260 int m_maxFrames;
261 int m_imageStateCount;
262 bool m_addAdvance;
263};
264
265class Q_QUICK_PRIVATE_EXPORT QQuickSpriteEngine : public QQuickStochasticEngine
266{
267 Q_OBJECT
268 Q_PROPERTY(QQmlListProperty<QQuickSprite> sprites READ sprites)
269public:
270 explicit QQuickSpriteEngine(QObject *parent = nullptr);
271 QQuickSpriteEngine(const QList<QQuickSprite*> &sprites, QObject *parent = nullptr);
272 ~QQuickSpriteEngine() override;
273 QQmlListProperty<QQuickSprite> sprites()
274 {
275 return QQmlListProperty<QQuickSprite>(this, &m_sprites);
276 }
277
278 QQuickSprite* sprite(int sprite = 0) const;
279 int spriteState(int sprite = 0) const;
280 int spriteStart(int sprite = 0) const;
281 int spriteFrames(int sprite = 0) const;
282 int spriteDuration(int sprite = 0) const;
283 int spriteX(int sprite = 0) const;
284 int spriteY(int sprite = 0) const;
285 int spriteWidth(int sprite = 0) const;
286 int spriteHeight(int sprite = 0) const;
287 int spriteCount() const;//Like state count
288 int maxFrames() const;
289
290 void restart(int index=0) override;
291 void advance(int index=0) override;
292
293 //Similar API to QQuickPixmap for async loading convenience
294 bool isNull() const { return status() == QQuickPixmap::Null; }
295 bool isReady() const { return status() == QQuickPixmap::Ready; }
296 bool isLoading() const { return status() == QQuickPixmap::Loading; }
297 bool isError() const { return status() == QQuickPixmap::Error; }
298 QQuickPixmap::Status status() const; //Composed status of all Sprites
299 void startAssemblingImage();
300 QImage assembledImage(int maxSize = 2048);
301
302private:
303 int pseudospriteProgress(int, int, int *rd = nullptr) const;
304 QList<QQuickSprite*> m_sprites;
305 bool m_startedImageAssembly;
306 bool m_loaded;
307 bool m_errorsPrinted;
308};
309
310//Common use is to have your own list property which is transparently an engine
311inline void spriteAppend(QQmlListProperty<QQuickSprite> *p, QQuickSprite* s)
312{
313 reinterpret_cast<QList<QQuickSprite *> *>(p->data)->append(t: s);
314 p->object->metaObject()->invokeMethod(obj: p->object, member: "createEngine");
315}
316
317inline QQuickSprite* spriteAt(QQmlListProperty<QQuickSprite> *p, int idx)
318{
319 return reinterpret_cast<QList<QQuickSprite *> *>(p->data)->at(i: idx);
320}
321
322inline void spriteClear(QQmlListProperty<QQuickSprite> *p)
323{
324 reinterpret_cast<QList<QQuickSprite *> *>(p->data)->clear();
325 p->object->metaObject()->invokeMethod(obj: p->object, member: "createEngine");
326}
327
328inline int spriteCount(QQmlListProperty<QQuickSprite> *p)
329{
330 return reinterpret_cast<QList<QQuickSprite *> *>(p->data)->count();
331}
332
333inline void spriteReplace(QQmlListProperty<QQuickSprite> *p, int idx, QQuickSprite *s)
334{
335 reinterpret_cast<QList<QQuickSprite *> *>(p->data)->replace(i: idx, t: s);
336 p->object->metaObject()->invokeMethod(obj: p->object, member: "createEngine");
337}
338
339inline void spriteRemoveLast(QQmlListProperty<QQuickSprite> *p)
340{
341 reinterpret_cast<QList<QQuickSprite *> *>(p->data)->removeLast();
342 p->object->metaObject()->invokeMethod(obj: p->object, member: "createEngine");
343}
344
345QT_END_NAMESPACE
346
347#endif // QQUICKSPRITEENGINE_P_H
348

source code of qtdeclarative/src/quick/items/qquickspriteengine_p.h