Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickparticlesystem_p.h
Go to the documentation of this file.
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 PARTICLESYSTEM_H
5#define PARTICLESYSTEM_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 <QtQuick/QQuickItem>
19#include <QElapsedTimer>
20#include <QVector>
21#include <QVarLengthArray>
22#include <QHash>
23#include <QSet>
24#include <QPointer>
25#include <private/qquicksprite_p.h>
26#include <QAbstractAnimation>
27#include <QtQml/qqml.h>
28#include <private/qv4util_p.h>
29#include <private/qv4global_p.h>
30#include <private/qv4staticvalue_p.h>
31#include <private/qtquickparticlesglobal_p.h>
32
34
35template<class T, int Prealloc>
37{
38public:
39 void insert(const T &element)
40 {
41 if (!this->contains(element)) {
42 this->append(element);
43 }
44 }
45
46 bool removeOne(const T &element)
47 {
48 for (int i = 0; i < this->size(); ++i) {
49 if (this->at(i) == element) {
50 this->remove(i);
51 return true;
52 }
53 }
54
55 return false;
56 }
57};
58
66class QQuickSprite;
70
72 int time;//in ms
73 QSet<QQuickParticleData*> data;//Set ptrs instead?
74};
75
76class Q_QUICKPARTICLES_EXPORT QQuickParticleDataHeap {
77 //Idea is to do a binary heap, but which also stores a set of int,Node* so that if the int already exists, you can
78 //add it to the data* list. Pops return the whole list at once.
79public:
82 void insertTimed(QQuickParticleData* data, int time);
83
84 int top();
85
86 bool isEmpty() const { return m_end == 0; }
87
88 QSet<QQuickParticleData*> pop();
89
90 void clear();
91
92 bool contains(QQuickParticleData*);//O(n), for debugging purposes only
93private:
94 void grow();
95 void swap(int, int);
96 void bubbleUp(int);
97 void bubbleDown(int);
98 int m_size;
99 int m_end;
101 QVector<QQuickParticleDataHeapNode> m_data;
102 QHash<int,int> m_lookups;
103};
104
105class Q_QUICKPARTICLES_EXPORT QQuickParticleGroupData {
106 class FreeList
107 {
108 public:
109 FreeList() {}
110
111 void resize(int newSize)
112 {
113 Q_ASSERT(newSize >= 0);
114 int oldSize = isUnused.size();
115 isUnused.resize(newSize, true);
116 if (newSize > oldSize) {
117 if (firstUnused == UINT_MAX) {
118 firstUnused = oldSize;
119 } else {
120 firstUnused = std::min(firstUnused, unsigned(oldSize));
121 }
122 } else if (firstUnused >= unsigned(newSize)) {
123 firstUnused = UINT_MAX;
124 }
125 }
126
127 void free(int index)
128 {
129 isUnused.setBit(index);
130 firstUnused = std::min(firstUnused, unsigned(index));
131 --allocated;
132 }
133
134 int count() const
135 { return allocated; }
136
137 bool hasUnusedEntries() const
138 { return firstUnused != UINT_MAX; }
139
140 int alloc()
141 {
142 if (hasUnusedEntries()) {
143 int nextFree = firstUnused;
144 isUnused.clearBit(firstUnused);
145 firstUnused = isUnused.findNext(firstUnused, true, false);
146 if (firstUnused >= unsigned(isUnused.size())) {
147 firstUnused = UINT_MAX;
148 }
149 ++allocated;
150 return nextFree;
151 } else {
152 return -1;
153 }
154 }
155
156 private:
157 QV4::BitVector isUnused;
158 unsigned firstUnused = UINT_MAX;
159 int allocated = 0;
160 };
161
162public: // types
163 typedef int ID;
164 enum { InvalidID = -1, DefaultGroupID = 0 };
165
166public:
169
170 int size() const
171 {
172 return m_size;
173 }
174
175 bool isActive() { return freeList.count() > 0; }
176
177 QString name() const;
178
179 void setSize(int newSize);
180
181 const ID index;
182 QQuickParticleVarLengthArray<QQuickParticlePainter*, 4> painters;//TODO: What if they are dynamically removed?
183
184 //TODO: Refactor particle data list out into a separate class
185 QVector<QQuickParticleData*> data;
186 FreeList freeList;
188 bool recycle(); //Force recycling round, returns true if all indexes are now reusable
189
190 void initList();
191 void kill(QQuickParticleData* d);
192
193 //After calling this, initialize, then call prepareRecycler(d)
194 QQuickParticleData* newDatum(bool respectsLimits);
195
196 //TODO: Find and clean up those that don't get added to the recycler (currently they get lost)
197 void prepareRecycler(QQuickParticleData* d);
198
199private:
200 int m_size;
201 QQuickParticleSystem* m_system;
202 // Only used in recycle() for tracking of alive particles after latest recycling round
203 QVector<QQuickParticleData*> m_latestAliveParticles;
204};
205
212
213class Q_QUICKPARTICLES_EXPORT QQuickParticleData
214{
215public:
216 //Convenience functions for working backwards, because parameters are from the start of particle life
217 //If setting multiple parameters at once, doing the conversion yourself will be faster.
218
219 //sets the x accleration without affecting the instantaneous x velocity or position
220 void setInstantaneousAX(float ax, QQuickParticleSystem *particleSystem);
221 //sets the x velocity without affecting the instantaneous x postion
222 void setInstantaneousVX(float vx, QQuickParticleSystem *particleSystem);
223 //sets the instantaneous x postion
224 void setInstantaneousX(float x, QQuickParticleSystem *particleSystem);
225 //sets the y accleration without affecting the instantaneous y velocity or position
226 void setInstantaneousAY(float ay, QQuickParticleSystem *particleSystem);
227 //sets the y velocity without affecting the instantaneous y postion
228 void setInstantaneousVY(float vy, QQuickParticleSystem *particleSystem);
229 //sets the instantaneous Y postion
230 void setInstantaneousY(float y, QQuickParticleSystem *particleSystem);
231
232 //TODO: Slight caching?
233 float curX(QQuickParticleSystem *particleSystem) const;
234 float curVX(QQuickParticleSystem *particleSystem) const;
235 float curAX() const { return ax; }
236 float curAX(QQuickParticleSystem *) const { return ax; } // used by the macros in qquickv4particledata.cpp
237 float curY(QQuickParticleSystem *particleSystem) const;
238 float curVY(QQuickParticleSystem *particleSystem) const;
239 float curAY() const { return ay; }
240 float curAY(QQuickParticleSystem *) const { return ay; } // used by the macros in qquickv4particledata.cpp
241
242 int index = 0;
243 int systemIndex = -1;
244
245 //General Position Stuff
246 float x = 0;
247 float y = 0;
248 float t = -1;
249 float lifeSpan = 0;
250 float size = 0;
251 float endSize = 0;
252 float vx = 0;
253 float vy = 0;
254 float ax = 0;
255 float ay = 0;
256
257 //Painter-specific stuff, now universally shared
258 //Used by ImageParticle color mode
259 Color4ub color = { 255, 255, 255, 255};
260 //Used by ImageParticle deform mode
261 float xx = 1;
262 float xy = 0;
263 float yx = 0;
264 float yy = 1;
265 float rotation = 0;
266 float rotationVelocity = 0;
267 uchar autoRotate = 0; // Basically a bool
268 //Used by ImageParticle Sprite mode
269 float animIdx = 0;
270 float frameDuration = 1;
271 float frameAt = -1;//Used for duration -1
272 float frameCount = 1;
273 float animT = -1;
274 float animX = 0;
275 float animY = 0;
276 float animWidth = 1;
277 float animHeight = 1;
278
280
281 //Used by ImageParticle data shadowing
282 QQuickImageParticle* colorOwner = nullptr;
283 QQuickImageParticle* rotationOwner = nullptr;
284 QQuickImageParticle* deformationOwner = nullptr;
285 QQuickImageParticle* animationOwner = nullptr;
286
287 //Used by ItemParticle
288 QQuickItem* delegate = nullptr;
289 //Used by custom affectors
290 float update = 0;
291
292 void debugDump(QQuickParticleSystem *particleSystem) const;
293 bool stillAlive(QQuickParticleSystem *particleSystem) const; //Only checks end, because usually that's all you need and it's a little faster.
294 bool alive(QQuickParticleSystem *particleSystem) const;
295 float lifeLeft(QQuickParticleSystem *particleSystem) const;
296
297 float curSize(QQuickParticleSystem *particleSystem) const;
298
299 QQuickV4ParticleData v4Value(QQuickParticleSystem *particleSystem);
300 void extendLife(float time, QQuickParticleSystem *particleSystem);
301
302 static inline constexpr float EPSILON() noexcept { return 0.001f; }
303};
304
305static_assert(std::is_trivially_copyable_v<QQuickParticleData>);
306static_assert(std::is_trivially_destructible_v<QQuickParticleData>);
307
308class Q_QUICKPARTICLES_EXPORT QQuickParticleSystem : public QQuickItem
309{
311 Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
312 Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
313 Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
314 QML_NAMED_ELEMENT(ParticleSystem)
316
317public:
318 explicit QQuickParticleSystem(QQuickItem *parent = nullptr);
320
321 bool isRunning() const
322 {
323 return m_running;
324 }
325
326 int count() const
327 {
328 return particleCount;
329 }
330
331 static const int maxLife = 600000;
332
334
336 void runningChanged(bool arg);
337 void pausedChanged(bool arg);
338 void emptyChanged(bool arg);
339
340public Q_SLOTS:
341 void start(){setRunning(true);}
342 void stop(){setRunning(false);}
343 void restart(){setRunning(false);setRunning(true);}
344 void pause(){setPaused(true);}
345 void resume(){setPaused(false);}
346
347 void reset();
348 void setRunning(bool arg);
349 void setPaused(bool arg);
350
351 virtual int duration() const { return -1; }
352
353
354protected:
355 //This one only once per frame (effectively)
356 void componentComplete() override;
357
358private Q_SLOTS:
359 void emittersChanged();
360 void loadPainter(QQuickParticlePainter *p);
361 void createEngine(); //Not invoked by sprite engine, unlike Sprite uses
362 void particleStateChange(int idx);
363
364public:
365 //These can be called multiple times per frame, performance critical
366 void emitParticle(QQuickParticleData* p, QQuickParticleEmitter *particleEmitter);
367 QQuickParticleData *newDatum(
368 int groupId, bool respectLimits = true, int sysIdx = -1,
369 const QQuickParticleData *cloneFrom = nullptr);
370 void finishNewDatum(QQuickParticleData*);
371 void moveGroups(QQuickParticleData *d, int newGIdx);
372 int nextSystemIndex();
373
374 //This one only once per painter per frame
375 int systemSync(QQuickParticlePainter* p);
376
377 //Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize
378 QSet<QQuickParticleData*> needsReset;
379 QVector<QQuickParticleData*> bySysIdx; //Another reference to the data (data owned by group), but by sysIdx
381
382 QHash<QString, int> groupIds;
383 QVarLengthArray<QQuickParticleGroupData*, 32> groupData;
385 int registerParticleGroupData(const QString &name, QQuickParticleGroupData *pgd);
386
387 //Also only here for auto-test usage
388 void updateCurrentTime( int currentTime );
392
396
397 void registerParticlePainter(QQuickParticlePainter* p);
398 void registerParticleEmitter(QQuickParticleEmitter* e);
399 void finishRegisteringParticleEmitter(QQuickParticleEmitter *e);
400 void registerParticleAffector(QQuickParticleAffector* a);
401 void registerParticleGroup(QQuickParticleGroup* g);
402
403 static void statePropertyRedirect(QQmlListProperty<QObject> *prop, QObject *value);
404 static void stateRedirect(QQuickParticleGroup* group, QQuickParticleSystem* sys, QObject *value);
405 bool isPaused() const
406 {
407 return m_paused;
408 }
409
410 bool isEmpty() const
411 {
412 return m_empty;
413 }
414
415private:
416 void searchNextFreeGroupId();
417
418private:
419 void emitterAdded(QQuickParticleEmitter *e);
420 void postProcessEmitters();
421 void initializeSystem();
422 void initGroups();
423 QList<QPointer<QQuickParticleEmitter> > m_emitters;
424 QList<QPointer<QQuickParticleAffector> > m_affectors;
425 QList<QPointer<QQuickParticlePainter> > m_painters;
426 QList<QPointer<QQuickParticlePainter> > m_syncList;
427 QList<QQuickParticleGroup*> m_groups;
428 int m_nextIndex;
429 QSet<int> m_reusableIndexes;
430 bool m_componentComplete;
431
432 bool m_paused;
433 bool m_allDead;
434 bool m_empty;
435};
436
437// Internally, this animation drives all the timing. Painters sync up in their updatePaintNode
439{
441public:
443 : QAbstractAnimation(static_cast<QObject*>(system)), m_system(system)
444 { }
445protected:
446 void updateCurrentTime(int t) override
447 {
448 m_system->updateCurrentTime(t);
449 }
450
451 int duration() const override
452 {
453 return -1;
454 }
455
456private:
457 QQuickParticleSystem* m_system;
458};
459
461{
462 float t = (particleSystem->timeInt / 1000.0f) - this->t;
463 float t_sq = t * t;
464 float vx = (this->vx + t * this->ax) - t * ax;
465 float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq;
466 float x = ex - t * vx - 0.5f * t_sq * ax;
467
468 this->ax = ax;
469 this->vx = vx;
470 this->x = x;
471}
472
474{
475 float t = (particleSystem->timeInt / 1000.0f) - this->t;
476 float t_sq = t * t;
477 float evx = vx - t * this->ax;
478 float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq;
479 float x = ex - t * evx - 0.5f * t_sq * this->ax;
480
481 this->vx = evx;
482 this->x = x;
483}
484
486{
487 float t = (particleSystem->timeInt / 1000.0f) - this->t;
488 float t_sq = t * t;
489 this->x = x - t * this->vx - 0.5f * t_sq * this->ax;
490}
491
493{
494 float t = (particleSystem->timeInt / 1000.0f) - this->t;
495 float t_sq = t * t;
496 float vy = (this->vy + t * this->ay) - t * ay;
497 float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq;
498 float y = ey - t * vy - 0.5f * t_sq * ay;
499
500 this->ay = ay;
501 this->vy = vy;
502 this->y = y;
503}
504
506{
507 float t = (particleSystem->timeInt / 1000.0f) - this->t;
508 float t_sq = t * t;
509 float evy = vy - t * this->ay;
510 float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq;
511 float y = ey - t*evy - 0.5f * t_sq * this->ay;
512
513 this->vy = evy;
514 this->y = y;
515}
516
518{
519 float t = (particleSystem->timeInt / 1000.0f) - this->t;
520 float t_sq = t * t;
521 this->y = y - t * this->vy - 0.5f * t_sq * this->ay;
522}
523
524inline float QQuickParticleData::curX(QQuickParticleSystem *particleSystem) const
525{
526 float t = (particleSystem->timeInt / 1000.0f) - this->t;
527 float t_sq = t * t;
528 return this->x + this->vx * t + 0.5f * this->ax * t_sq;
529}
530
531inline float QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) const
532{
533 float t = (particleSystem->timeInt / 1000.0f) - this->t;
534 return this->vx + t * this->ax;
535}
536
537inline float QQuickParticleData::curY(QQuickParticleSystem *particleSystem) const
538{
539 float t = (particleSystem->timeInt / 1000.0f) - this->t;
540 float t_sq = t * t;
541 return y + vy * t + 0.5f * ay * t_sq;
542}
543
544inline float QQuickParticleData::curVY(QQuickParticleSystem *particleSystem) const
545{
546 float t = (particleSystem->timeInt / 1000.0f) - this->t;
547 return vy + t*ay;
548}
549
551{
552 if (!system)
553 return false;
554 return (t + lifeSpan - EPSILON()) > (system->timeInt / 1000.0f);
555}
556
558{
559 if (!system)
560 return false;
561 float st = (system->timeInt / 1000.0f);
562 return (t + EPSILON()) < st && (t + lifeSpan - EPSILON()) > st;
563}
564
565inline float QQuickParticleData::lifeLeft(QQuickParticleSystem *particleSystem) const
566{
567 if (!particleSystem)
568 return 0.0f;
569 return (t + lifeSpan) - (particleSystem->timeInt / 1000.0f);
570}
571
572inline float QQuickParticleData::curSize(QQuickParticleSystem *particleSystem) const
573{
574 if (!particleSystem || lifeSpan == 0.0f)
575 return 0.0f;
576 return size + (endSize - size) * (1 - (lifeLeft(particleSystem) / lifeSpan));
577}
578
580
581#endif // PARTICLESYSTEM_H
582
583
NSData * m_data
\inmodule QtCore
Definition qobject.h:103
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void setInstantaneousVY(float vy, QQuickParticleSystem *particleSystem)
void setInstantaneousVX(float vx, QQuickParticleSystem *particleSystem)
float curY(QQuickParticleSystem *particleSystem) const
void setInstantaneousX(float x, QQuickParticleSystem *particleSystem)
void setInstantaneousAY(float ay, QQuickParticleSystem *particleSystem)
void setInstantaneousAX(float ax, QQuickParticleSystem *particleSystem)
float curVY(QQuickParticleSystem *particleSystem) const
void setInstantaneousY(float y, QQuickParticleSystem *particleSystem)
float curAX(QQuickParticleSystem *) const
bool stillAlive(QQuickParticleSystem *particleSystem) const
float curAY(QQuickParticleSystem *) const
float curVX(QQuickParticleSystem *particleSystem) const
static constexpr float EPSILON() noexcept
bool alive(QQuickParticleSystem *particleSystem) const
float curX(QQuickParticleSystem *particleSystem) const
float lifeLeft(QQuickParticleSystem *particleSystem) const
float curSize(QQuickParticleSystem *particleSystem) const
QVector< QQuickParticleData * > data
QQuickParticleVarLengthArray< QQuickParticlePainter *, 4 > painters
QQuickParticleDataHeap dataHeap
QQuickParticleSystemAnimation(QQuickParticleSystem *system)
void updateCurrentTime(int t) override
This pure virtual function is called every time the animation's currentTime changes.
int duration() const override
This pure virtual function returns the duration of the animation, and defines for how long QAbstractA...
QQuickStochasticEngine * stateEngine
void runningChanged(bool arg)
QVarLengthArray< QQuickParticleGroupData *, 32 > groupData
QQuickParticleSystemAnimation * m_animation
virtual int duration() const
QHash< QString, int > groupIds
void pausedChanged(bool arg)
QVector< QQuickParticleData * > bySysIdx
void updateCurrentTime(int currentTime)
void emptyChanged(bool arg)
QSet< QQuickParticleData * > needsReset
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
constexpr size_type size() const noexcept
void remove(qsizetype i, qsizetype n=1)
void append(const T &t)
bool contains(const AT &t) const
a resize(100000)
b clear()
cache insert(employee->id(), employee)
Combined button and popup list for selecting options.
static int grow(QLayoutStruct &ls, int delta)
static Q_CONSTINIT QBasicAtomicInt running
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
Engine * createEngine(QGeoServiceProviderPrivate *)
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLint GLint GLint GLint GLint x
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint color
[2]
GLboolean GLuint group
GLboolean GLboolean g
GLuint name
GLint y
GLboolean reset
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
#define QML_NAMED_ELEMENT(NAME)
#define QML_ADDED_IN_VERSION(MAJOR, MINOR)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
static bool isRunning()
Definition main.cpp:452
#define Q_PROPERTY(...)
#define Q_OBJECT
#define Q_SLOTS
#define Q_SIGNALS
unsigned char uchar
Definition qtypes.h:32
static double currentTime()
#define explicit
this swap(other)
QAction * at
QSet< QQuickParticleData * > data