diff options
Diffstat (limited to 'src/quick/particles/qquickparticlesystem_p.h')
-rw-r--r-- | src/quick/particles/qquickparticlesystem_p.h | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/src/quick/particles/qquickparticlesystem_p.h b/src/quick/particles/qquickparticlesystem_p.h new file mode 100644 index 0000000000..6a3403aa93 --- /dev/null +++ b/src/quick/particles/qquickparticlesystem_p.h @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation ([email protected]) +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PARTICLESYSTEM_H +#define PARTICLESYSTEM_H + +#include <QtQuick/QQuickItem> +#include <QElapsedTimer> +#include <QVector> +#include <QHash> +#include <QPointer> +#include <QSignalMapper> +#include <private/qquicksprite_p.h> +#include <QAbstractAnimation> +#include <QtDeclarative/qdeclarative.h> +#include <private/qv8engine_p.h> //For QDeclarativeV8Handle + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QQuickParticleSystem; +class QQuickParticleAffector; +class QQuickParticleEmitter; +class QQuickParticlePainter; +class QQuickParticleData; +class QQuickParticleSystemAnimation; +class QQuickStochasticEngine; +class QQuickSprite; +class QQuickV8ParticleData; +class QQuickParticleGroup; +class QQuickImageParticle; + +struct QQuickParticleDataHeapNode{ + int time;//in ms + QSet<QQuickParticleData*> data;//Set ptrs instead? +}; + +class QQuickParticleDataHeap { + //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 + //add it to the data* list. Pops return the whole list at once. +public: + QQuickParticleDataHeap(); + void insert(QQuickParticleData* data); + void insertTimed(QQuickParticleData* data, int time); + + int top(); + + QSet<QQuickParticleData*> pop(); + + void clear(); + + bool contains(QQuickParticleData*);//O(n), for debugging purposes only +private: + void grow(); + void swap(int, int); + void bubbleUp(int); + void bubbleDown(int); + int m_size; + int m_end; + QQuickParticleDataHeapNode m_tmp; + QVector<QQuickParticleDataHeapNode> m_data; + QHash<int,int> m_lookups; +}; + +class Q_AUTOTEST_EXPORT QQuickParticleGroupData { +public: + QQuickParticleGroupData(int id, QQuickParticleSystem* sys); + ~QQuickParticleGroupData(); + + int size(); + QString name(); + + void setSize(int newSize); + + int index; + QSet<QQuickParticlePainter*> painters;//TODO: What if they are dynamically removed? + + //TODO: Refactor particle data list out into a separate class + QVector<QQuickParticleData*> data; + QQuickParticleDataHeap dataHeap; + QSet<int> reusableIndexes; + bool recycle(); //Force recycling round, returns true if all indexes are now reusable + + void initList(); + void kill(QQuickParticleData* d); + + //After calling this, initialize, then call prepareRecycler(d) + QQuickParticleData* newDatum(bool respectsLimits); + + //TODO: Find and clean up those that don't get added to the recycler (currently they get lost) + void prepareRecycler(QQuickParticleData* d); + +private: + int m_size; + QQuickParticleSystem* m_system; +}; + +struct Color4ub { + uchar r; + uchar g; + uchar b; + uchar a; +}; + +class Q_AUTOTEST_EXPORT QQuickParticleData { +public: + //TODO: QObject like memory management (without the cost, just attached to system) + QQuickParticleData(QQuickParticleSystem* sys); + ~QQuickParticleData(); + + //Convenience functions for working backwards, because parameters are from the start of particle life + //If setting multiple parameters at once, doing the conversion yourself will be faster. + + //sets the x accleration without affecting the instantaneous x velocity or position + void setInstantaneousAX(qreal ax); + //sets the x velocity without affecting the instantaneous x postion + void setInstantaneousVX(qreal vx); + //sets the instantaneous x postion + void setInstantaneousX(qreal x); + //sets the y accleration without affecting the instantaneous y velocity or position + void setInstantaneousAY(qreal ay); + //sets the y velocity without affecting the instantaneous y postion + void setInstantaneousVY(qreal vy); + //sets the instantaneous Y postion + void setInstantaneousY(qreal y); + + //TODO: Slight caching? + qreal curX() const; + qreal curVX() const; + qreal curAX() const { return ax; } + qreal curY() const; + qreal curVY() const; + qreal curAY() const { return ay; } + + int group; + QQuickParticleEmitter* e;//### Needed? + QQuickParticleSystem* system; + int index; + int systemIndex; + + //General Position Stuff + float x; + float y; + float t; + float lifeSpan; + float size; + float endSize; + float vx; + float vy; + float ax; + float ay; + + //Other stuff, now universally shared + Color4ub color; + float xx; + float xy; + float yx; + float yy; + float rotation; + float rotationSpeed; + float autoRotate;//Assume that GPUs prefer floats to bools + float animIdx; + float frameDuration; + float frameCount; + float animT; + float animX; + float animY; + float animWidth; + float animHeight; + float r; + QQuickItem* delegate; + int modelIndex; + float update;//Used by custom affectors + + //Used by image particle + QQuickImageParticle* colorOwner; + QQuickImageParticle* rotationOwner; + QQuickImageParticle* deformationOwner; + QQuickImageParticle* animationOwner; + + void debugDump(); + bool stillAlive();//Only checks end, because usually that's all you need and it's a little faster. + bool alive(); + float lifeLeft(); + float curSize(); + void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index + QDeclarativeV8Handle v8Value(); + void extendLife(float time); +private: + QQuickV8ParticleData* v8Datum; +}; + +class Q_AUTOTEST_EXPORT QQuickParticleSystem : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) + Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) + Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged) + +public: + explicit QQuickParticleSystem(QQuickItem *parent = 0); + ~QQuickParticleSystem(); + + bool isRunning() const + { + return m_running; + } + + int count(){ return particleCount; } + + static const int maxLife = 600000; + +signals: + + void systemInitialized(); + void runningChanged(bool arg); + void pausedChanged(bool arg); + void emptyChanged(bool arg); + +public slots: + void start(){setRunning(true);} + void stop(){setRunning(false);} + void restart(){setRunning(false);setRunning(true);} + void pause(){setPaused(true);} + void resume(){setPaused(false);} + + void reset(); + void setRunning(bool arg); + void setPaused(bool arg); + + virtual int duration() const { return -1; } + + +protected: + //This one only once per frame (effectively) + void componentComplete(); + +private slots: + void emittersChanged(); + void loadPainter(QObject* p); + void createEngine(); //Not invoked by sprite engine, unlike Sprite uses + void particleStateChange(int idx); + +public: + //These can be called multiple times per frame, performance critical + void emitParticle(QQuickParticleData* p); + QQuickParticleData* newDatum(int groupId, bool respectLimits = true, int sysIdx = -1); + void finishNewDatum(QQuickParticleData*); + void moveGroups(QQuickParticleData *d, int newGIdx); + int nextSystemIndex(); + + //This one only once per painter per frame + int systemSync(QQuickParticlePainter* p); + + //Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize + QSet<QQuickParticleData*> needsReset; + QVector<QQuickParticleData*> bySysIdx; //Another reference to the data (data owned by group), but by sysIdx + QHash<QString, int> groupIds; + QHash<int, QQuickParticleGroupData*> groupData; + QQuickStochasticEngine* stateEngine; + + //Also only here for auto-test usage + void updateCurrentTime( int currentTime ); + QQuickParticleSystemAnimation* m_animation; + bool m_running; + + int timeInt; + bool initialized; + int particleCount; + + void registerParticlePainter(QQuickParticlePainter* p); + void registerParticleEmitter(QQuickParticleEmitter* e); + void registerParticleAffector(QQuickParticleAffector* a); + void registerParticleGroup(QQuickParticleGroup* g); + + static void statePropertyRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value); + static void stateRedirect(QQuickParticleGroup* group, QQuickParticleSystem* sys, QObject *value); + bool isPaused() const + { + return m_paused; + } + + bool isEmpty() const + { + return m_empty; + } + +private: + void initializeSystem(); + void initGroups(); + QList<QPointer<QQuickParticleEmitter> > m_emitters; + QList<QPointer<QQuickParticleAffector> > m_affectors; + QList<QPointer<QQuickParticlePainter> > m_painters; + QList<QPointer<QQuickParticlePainter> > m_syncList; + QList<QQuickParticleGroup*> m_groups; + int m_nextGroupId; + int m_nextIndex; + QSet<int> m_reusableIndexes; + bool m_componentComplete; + + QSignalMapper m_painterMapper; + QSignalMapper m_emitterMapper; + bool m_paused; + bool m_debugMode; + bool m_allDead; + bool m_empty; +}; + +// Internally, this animation drives all the timing. Painters sync up in their updatePaintNode +class QQuickParticleSystemAnimation : public QAbstractAnimation +{ + Q_OBJECT +public: + QQuickParticleSystemAnimation(QQuickParticleSystem* system) + : QAbstractAnimation(static_cast<QObject*>(system)), m_system(system) + { } +protected: + virtual void updateCurrentTime( int t ) + { + m_system->updateCurrentTime(t); + } + + virtual int duration() const + { + return -1; + } + +private: + QQuickParticleSystem* m_system; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // PARTICLESYSTEM_H + + |