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

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