1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQuick module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #ifndef PARTICLESYSTEM_H
43 #define PARTICLESYSTEM_H
45 #include <QtQuick/QQuickItem>
46 #include <QElapsedTimer>
50 #include <QSignalMapper>
51 #include <private/qquicksprite_p.h>
52 #include <QAbstractAnimation>
53 #include <QtQml/qqml.h>
54 #include <private/qv8engine_p.h> //For QQmlV8Handle
60 class QQuickParticleSystem;
61 class QQuickParticleAffector;
62 class QQuickParticleEmitter;
63 class QQuickParticlePainter;
64 class QQuickParticleData;
65 class QQuickParticleSystemAnimation;
66 class QQuickStochasticEngine;
68 class QQuickV8ParticleData;
69 class QQuickParticleGroup;
70 class QQuickImageParticle;
72 struct QQuickParticleDataHeapNode{
74 QSet<QQuickParticleData*> data;//Set ptrs instead?
77 class QQuickParticleDataHeap {
78 //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
79 //add it to the data* list. Pops return the whole list at once.
81 QQuickParticleDataHeap();
82 void insert(QQuickParticleData* data);
83 void insertTimed(QQuickParticleData* data, int time);
87 QSet<QQuickParticleData*> pop();
91 bool contains(QQuickParticleData*);//O(n), for debugging purposes only
99 QQuickParticleDataHeapNode m_tmp;
100 QVector<QQuickParticleDataHeapNode> m_data;
101 QHash<int,int> m_lookups;
104 class Q_AUTOTEST_EXPORT QQuickParticleGroupData {
106 QQuickParticleGroupData(int id, QQuickParticleSystem* sys);
107 ~QQuickParticleGroupData();
112 void setSize(int newSize);
115 QSet<QQuickParticlePainter*> painters;//TODO: What if they are dynamically removed?
117 //TODO: Refactor particle data list out into a separate class
118 QVector<QQuickParticleData*> data;
119 QQuickParticleDataHeap dataHeap;
120 QSet<int> reusableIndexes;
121 bool recycle(); //Force recycling round, returns true if all indexes are now reusable
124 void kill(QQuickParticleData* d);
126 //After calling this, initialize, then call prepareRecycler(d)
127 QQuickParticleData* newDatum(bool respectsLimits);
129 //TODO: Find and clean up those that don't get added to the recycler (currently they get lost)
130 void prepareRecycler(QQuickParticleData* d);
134 QQuickParticleSystem* m_system;
144 class Q_AUTOTEST_EXPORT QQuickParticleData {
146 //TODO: QObject like memory management (without the cost, just attached to system)
147 QQuickParticleData(QQuickParticleSystem* sys);
148 ~QQuickParticleData();
150 //Convenience functions for working backwards, because parameters are from the start of particle life
151 //If setting multiple parameters at once, doing the conversion yourself will be faster.
153 //sets the x accleration without affecting the instantaneous x velocity or position
154 void setInstantaneousAX(qreal ax);
155 //sets the x velocity without affecting the instantaneous x postion
156 void setInstantaneousVX(qreal vx);
157 //sets the instantaneous x postion
158 void setInstantaneousX(qreal x);
159 //sets the y accleration without affecting the instantaneous y velocity or position
160 void setInstantaneousAY(qreal ay);
161 //sets the y velocity without affecting the instantaneous y postion
162 void setInstantaneousVY(qreal vy);
163 //sets the instantaneous Y postion
164 void setInstantaneousY(qreal y);
166 //TODO: Slight caching?
169 qreal curAX() const { return ax; }
172 qreal curAY() const { return ay; }
175 QQuickParticleEmitter* e;//### Needed?
176 QQuickParticleSystem* system;
180 //General Position Stuff
192 //Painter-specific stuff, now universally shared
193 //Used by ImageParticle color mode
195 //Used by ImageParticle deform mode
202 float autoRotate;//Assume that GPUs prefer floats to bools
203 //Used by ImageParticle Sprite mode
206 float frameAt;//Used for duration -1
213 //Used by ImageParticle data shadowing
214 QQuickImageParticle* colorOwner;
215 QQuickImageParticle* rotationOwner;
216 QQuickImageParticle* deformationOwner;
217 QQuickImageParticle* animationOwner;
218 //Used by CustomParticle
220 //Used by ItemParticle
221 QQuickItem* delegate;
223 //Used by custom affectors
228 bool stillAlive();//Only checks end, because usually that's all you need and it's a little faster.
232 void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index
233 QQmlV8Handle v8Value();
234 void extendLife(float time);
236 QQuickV8ParticleData* v8Datum;
239 class Q_AUTOTEST_EXPORT QQuickParticleSystem : public QQuickItem
242 Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
243 Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
244 Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged)
247 explicit QQuickParticleSystem(QQuickItem *parent = 0);
248 ~QQuickParticleSystem();
250 bool isRunning() const
255 int count(){ return particleCount; }
257 static const int maxLife = 600000;
261 void systemInitialized();
262 void runningChanged(bool arg);
263 void pausedChanged(bool arg);
264 void emptyChanged(bool arg);
267 void start(){setRunning(true);}
268 void stop(){setRunning(false);}
269 void restart(){setRunning(false);setRunning(true);}
270 void pause(){setPaused(true);}
271 void resume(){setPaused(false);}
274 void setRunning(bool arg);
275 void setPaused(bool arg);
277 virtual int duration() const { return -1; }
281 //This one only once per frame (effectively)
282 void componentComplete();
285 void emittersChanged();
286 void loadPainter(QObject* p);
287 void createEngine(); //Not invoked by sprite engine, unlike Sprite uses
288 void particleStateChange(int idx);
291 //These can be called multiple times per frame, performance critical
292 void emitParticle(QQuickParticleData* p);
293 QQuickParticleData* newDatum(int groupId, bool respectLimits = true, int sysIdx = -1);
294 void finishNewDatum(QQuickParticleData*);
295 void moveGroups(QQuickParticleData *d, int newGIdx);
296 int nextSystemIndex();
298 //This one only once per painter per frame
299 int systemSync(QQuickParticlePainter* p);
301 //Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize
302 QSet<QQuickParticleData*> needsReset;
303 QVector<QQuickParticleData*> bySysIdx; //Another reference to the data (data owned by group), but by sysIdx
304 QHash<QString, int> groupIds;
305 QHash<int, QQuickParticleGroupData*> groupData;
306 QQuickStochasticEngine* stateEngine;
308 //Also only here for auto-test usage
309 void updateCurrentTime( int currentTime );
310 QQuickParticleSystemAnimation* m_animation;
318 void registerParticlePainter(QQuickParticlePainter* p);
319 void registerParticleEmitter(QQuickParticleEmitter* e);
320 void registerParticleAffector(QQuickParticleAffector* a);
321 void registerParticleGroup(QQuickParticleGroup* g);
323 static void statePropertyRedirect(QQmlListProperty<QObject> *prop, QObject *value);
324 static void stateRedirect(QQuickParticleGroup* group, QQuickParticleSystem* sys, QObject *value);
325 bool isPaused() const
336 void initializeSystem();
338 QList<QPointer<QQuickParticleEmitter> > m_emitters;
339 QList<QPointer<QQuickParticleAffector> > m_affectors;
340 QList<QPointer<QQuickParticlePainter> > m_painters;
341 QList<QPointer<QQuickParticlePainter> > m_syncList;
342 QList<QQuickParticleGroup*> m_groups;
345 QSet<int> m_reusableIndexes;
346 bool m_componentComplete;
348 QSignalMapper m_painterMapper;
349 QSignalMapper m_emitterMapper;
355 // Internally, this animation drives all the timing. Painters sync up in their updatePaintNode
356 class QQuickParticleSystemAnimation : public QAbstractAnimation
360 QQuickParticleSystemAnimation(QQuickParticleSystem* system)
361 : QAbstractAnimation(static_cast<QObject*>(system)), m_system(system)
364 virtual void updateCurrentTime( int t )
366 m_system->updateCurrentTime(t);
369 virtual int duration() const
375 QQuickParticleSystem* m_system;
383 #endif // PARTICLESYSTEM_H