Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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>
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_PRIVATE_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
87
88 void clear();
89
90 bool contains(QQuickParticleData*);//O(n), for debugging purposes only
91private:
92 void grow();
93 void swap(int, int);
94 void bubbleUp(int);
95 void bubbleDown(int);
96 int m_size;
97 int m_end;
100 QHash<int,int> m_lookups;
101};
102
103class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleGroupData {
104 class FreeList
105 {
106 public:
107 FreeList() {}
108
109 void resize(int newSize)
110 {
111 Q_ASSERT(newSize >= 0);
112 int oldSize = isUnused.size();
113 isUnused.resize(newSize, true);
114 if (newSize > oldSize) {
115 if (firstUnused == UINT_MAX) {
116 firstUnused = oldSize;
117 } else {
118 firstUnused = std::min(firstUnused, unsigned(oldSize));
119 }
120 } else if (firstUnused >= unsigned(newSize)) {
121 firstUnused = UINT_MAX;
122 }
123 }
124
125 void free(int index)
126 {
127 isUnused.setBit(index);
128 firstUnused = std::min(firstUnused, unsigned(index));
129 --allocated;
130 }
131
132 int count() const
133 { return allocated; }
134
135 bool hasUnusedEntries() const
136 { return firstUnused != UINT_MAX; }
137
138 int alloc()
139 {
140 if (hasUnusedEntries()) {
141 int nextFree = firstUnused;
142 isUnused.clearBit(firstUnused);
143 firstUnused = isUnused.findNext(firstUnused, true, false);
144 if (firstUnused >= unsigned(isUnused.size())) {
145 firstUnused = UINT_MAX;
146 }
147 ++allocated;
148 return nextFree;
149 } else {
150 return -1;
151 }
152 }
153
154 private:
155 QV4::BitVector isUnused;
156 unsigned firstUnused = UINT_MAX;
157 int allocated = 0;
158 };
159
160public: // types
161 typedef int ID;
162 enum { InvalidID = -1, DefaultGroupID = 0 };
163
164public:
167
168 int size() const
169 {
170 return m_size;
171 }
172
173 bool isActive() { return freeList.count() > 0; }
174
175 QString name() const;
176
177 void setSize(int newSize);
178
179 const ID index;
180 QQuickParticleVarLengthArray<QQuickParticlePainter*, 4> painters;//TODO: What if they are dynamically removed?
181
182 //TODO: Refactor particle data list out into a separate class
184 FreeList freeList;
186 bool recycle(); //Force recycling round, returns true if all indexes are now reusable
187
188 void initList();
189 void kill(QQuickParticleData* d);
190
191 //After calling this, initialize, then call prepareRecycler(d)
192 QQuickParticleData* newDatum(bool respectsLimits);
193
194 //TODO: Find and clean up those that don't get added to the recycler (currently they get lost)
195 void prepareRecycler(QQuickParticleData* d);
196
197private:
198 int m_size;
199 QQuickParticleSystem* m_system;
200 // Only used in recycle() for tracking of alive particles after latest recycling round
201 QVector<QQuickParticleData*> m_latestAliveParticles;
202};
203
204struct Color4ub {
209};
210
211class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleData {
212public:
213 //TODO: QObject like memory management (without the cost, just attached to system)
216
219
220 //Convenience functions for working backwards, because parameters are from the start of particle life
221 //If setting multiple parameters at once, doing the conversion yourself will be faster.
222
223 //sets the x accleration without affecting the instantaneous x velocity or position
224 void setInstantaneousAX(float ax, QQuickParticleSystem *particleSystem);
225 //sets the x velocity without affecting the instantaneous x postion
226 void setInstantaneousVX(float vx, QQuickParticleSystem *particleSystem);
227 //sets the instantaneous x postion
228 void setInstantaneousX(float x, QQuickParticleSystem *particleSystem);
229 //sets the y accleration without affecting the instantaneous y velocity or position
230 void setInstantaneousAY(float ay, QQuickParticleSystem *particleSystem);
231 //sets the y velocity without affecting the instantaneous y postion
232 void setInstantaneousVY(float vy, QQuickParticleSystem *particleSystem);
233 //sets the instantaneous Y postion
234 void setInstantaneousY(float y, QQuickParticleSystem *particleSystem);
235
236 //TODO: Slight caching?
237 float curX(QQuickParticleSystem *particleSystem) const;
238 float curVX(QQuickParticleSystem *particleSystem) const;
239 float curAX() const { return ax; }
240 float curAX(QQuickParticleSystem *) const { return ax; } // used by the macros in qquickv4particledata.cpp
241 float curY(QQuickParticleSystem *particleSystem) const;
242 float curVY(QQuickParticleSystem *particleSystem) const;
243 float curAY() const { return ay; }
244 float curAY(QQuickParticleSystem *) const { return ay; } // used by the macros in qquickv4particledata.cpp
245
246 int index;
248
249 //General Position Stuff
250 float x;
251 float y;
252 float t;
253 float lifeSpan;
254 float size;
255 float endSize;
256 float vx;
257 float vy;
258 float ax;
259 float ay;
260
261 //Painter-specific stuff, now universally shared
262 //Used by ImageParticle color mode
264 //Used by ImageParticle deform mode
265 float xx;
266 float xy;
267 float yx;
268 float yy;
269 float rotation;
271 uchar autoRotate; // Basically a bool
272 //Used by ImageParticle Sprite mode
273 float animIdx;
275 float frameAt;//Used for duration -1
277 float animT;
278 float animX;
279 float animY;
282
284
285 //Used by ImageParticle data shadowing
290
291 //Used by ItemParticle
293 //Used by custom affectors
294 float update;
295
296 void debugDump(QQuickParticleSystem *particleSystem) const;
297 bool stillAlive(QQuickParticleSystem *particleSystem) const; //Only checks end, because usually that's all you need and it's a little faster.
298 bool alive(QQuickParticleSystem *particleSystem) const;
299 float lifeLeft(QQuickParticleSystem *particleSystem) const;
300
301 float curSize(QQuickParticleSystem *particleSystem) const;
302 void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index
303 QV4::ReturnedValue v4Value(QQuickParticleSystem *particleSystem);
304 void extendLife(float time, QQuickParticleSystem *particleSystem);
305
306 static inline constexpr float EPSILON() noexcept { return 0.001f; }
307
308private:
310};
311
312class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleSystem : public QQuickItem
313{
315 Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged FINAL)
316 Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged FINAL)
317 Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged FINAL)
318 QML_NAMED_ELEMENT(ParticleSystem)
320
321public:
322 explicit QQuickParticleSystem(QQuickItem *parent = nullptr);
324
325 bool isRunning() const
326 {
327 return m_running;
328 }
329
330 int count() const
331 {
332 return particleCount;
333 }
334
335 static const int maxLife = 600000;
336
338
340 void runningChanged(bool arg);
341 void pausedChanged(bool arg);
342 void emptyChanged(bool arg);
343
344public Q_SLOTS:
345 void start(){setRunning(true);}
346 void stop(){setRunning(false);}
347 void restart(){setRunning(false);setRunning(true);}
348 void pause(){setPaused(true);}
349 void resume(){setPaused(false);}
350
351 void reset();
352 void setRunning(bool arg);
353 void setPaused(bool arg);
354
355 virtual int duration() const { return -1; }
356
357
358protected:
359 //This one only once per frame (effectively)
360 void componentComplete() override;
361
362private Q_SLOTS:
363 void emittersChanged();
364 void loadPainter(QQuickParticlePainter *p);
365 void createEngine(); //Not invoked by sprite engine, unlike Sprite uses
366 void particleStateChange(int idx);
367
368public:
369 //These can be called multiple times per frame, performance critical
370 void emitParticle(QQuickParticleData* p, QQuickParticleEmitter *particleEmitter);
371 QQuickParticleData* newDatum(int groupId, bool respectLimits = true, int sysIdx = -1);
372 void finishNewDatum(QQuickParticleData*);
373 void moveGroups(QQuickParticleData *d, int newGIdx);
374 int nextSystemIndex();
375
376 //This one only once per painter per frame
377 int systemSync(QQuickParticlePainter* p);
378
379 //Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize
381 QVector<QQuickParticleData*> bySysIdx; //Another reference to the data (data owned by group), but by sysIdx
383
387 int registerParticleGroupData(const QString &name, QQuickParticleGroupData *pgd);
388
389 //Also only here for auto-test usage
390 void updateCurrentTime( int currentTime );
394
398
399 void registerParticlePainter(QQuickParticlePainter* p);
400 void registerParticleEmitter(QQuickParticleEmitter* e);
401 void finishRegisteringParticleEmitter(QQuickParticleEmitter *e);
402 void registerParticleAffector(QQuickParticleAffector* a);
403 void registerParticleGroup(QQuickParticleGroup* g);
404
405 static void statePropertyRedirect(QQmlListProperty<QObject> *prop, QObject *value);
406 static void stateRedirect(QQuickParticleGroup* group, QQuickParticleSystem* sys, QObject *value);
407 bool isPaused() const
408 {
409 return m_paused;
410 }
411
412 bool isEmpty() const
413 {
414 return m_empty;
415 }
416
417private:
418 void searchNextFreeGroupId();
419
420private:
421 void initializeSystem();
422 void initGroups();
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 qhash.h:818
Definition qlist.h:74
\inmodule QtCore
Definition qobject.h:90
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
void setInstantaneousVY(float vy, QQuickParticleSystem *particleSystem)
QQuickImageParticle * deformationOwner
QQuickImageParticle * colorOwner
void setInstantaneousVX(float vx, QQuickParticleSystem *particleSystem)
QQuickParticleGroupData::ID groupId
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
QQuickImageParticle * animationOwner
bool stillAlive(QQuickParticleSystem *particleSystem) const
QQuickImageParticle * rotationOwner
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
Definition qset.h:18
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
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()
double e
cache insert(employee->id(), employee)
Combined button and popup list for selecting options.
quint64 ReturnedValue
static bool m_running
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
GLboolean GLuint group
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
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:358
#define Q_PROPERTY(...)
#define Q_OBJECT
#define Q_SLOTS
#define Q_SIGNALS
unsigned char uchar
Definition qtypes.h:27
static double currentTime()
QSharedPointer< T > other(t)
[5]
this swap(other)
QAction * at
QSet< QQuickParticleData * > data
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent