aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2011-09-01 15:27:05 +1000
committerQt by Nokia <qt-info@nokia.com>2011-09-07 09:26:15 +0200
commitca6d931bb7714de7293dab5d14a19f74dc98d103 (patch)
tree46b860a2dc0a352877420e7d58ab4324b2511242 /src/declarative
parentb04f4207d9070b29221eec8fb3206ba8510b2004 (diff)
Animation-like API for ParticleSystem
Includes skipping rendering when paused. Change-Id: I353ac415fb877917d46ba1832ad9cb5a84640b57 Reviewed-on: http://codereview.qt.nokia.com/4041 Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/declarative')
-rw-r--r--src/declarative/particles/qsgcustomparticle.cpp13
-rw-r--r--src/declarative/particles/qsgimageparticle.cpp14
-rw-r--r--src/declarative/particles/qsgparticleemitter.cpp6
-rw-r--r--src/declarative/particles/qsgparticleemitter_p.h14
-rw-r--r--src/declarative/particles/qsgparticlesystem.cpp255
-rw-r--r--src/declarative/particles/qsgparticlesystem_p.h22
6 files changed, 201 insertions, 123 deletions
diff --git a/src/declarative/particles/qsgcustomparticle.cpp b/src/declarative/particles/qsgcustomparticle.cpp
index 11bc7e35fb..00e3ec185b 100644
--- a/src/declarative/particles/qsgcustomparticle.cpp
+++ b/src/declarative/particles/qsgcustomparticle.cpp
@@ -413,13 +413,14 @@ QSGNode *QSGCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
m_dirtyData = false;
}
- if (m_system && m_system->isRunning())
+ if (m_system && m_system->isRunning() && !m_system->isPaused()){
prepareNextFrame();
- if (m_rootNode){
- update();
- //### Should I be using dirty geometry too/instead?
- foreach (QSGShaderEffectNode* node, m_nodes)
- node->markDirty(QSGNode::DirtyMaterial); //done in buildData?
+ if (m_rootNode) {
+ update();
+ //### Should I be using dirty geometry too/instead?
+ foreach (QSGGeometryNode* node, m_nodes)
+ node->markDirty(QSGNode::DirtyMaterial);//done in buildData?
+ }
}
return m_rootNode;
diff --git a/src/declarative/particles/qsgimageparticle.cpp b/src/declarative/particles/qsgimageparticle.cpp
index ec6c7375dc..5e0e97797f 100644
--- a/src/declarative/particles/qsgimageparticle.cpp
+++ b/src/declarative/particles/qsgimageparticle.cpp
@@ -53,7 +53,6 @@
#include <qsgengine.h>
QT_BEGIN_NAMESPACE
-
//###Switch to define later, for now user-friendly (no compilation) debugging is worth it
DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG)
@@ -1024,13 +1023,14 @@ QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
m_pleaseReset = false;
}
- if (m_system && m_system->isRunning())
+ if (m_system && m_system->isRunning() && !m_system->isPaused()){
prepareNextFrame();
- if (m_rootNode){
- update();
- //### Should I be using dirty geometry too/instead?
- foreach (QSGGeometryNode* node, m_nodes)
- node->markDirty(QSGNode::DirtyMaterial);
+ if (m_rootNode) {
+ update();
+ //### Should I be using dirty geometry too/instead?
+ foreach (QSGGeometryNode* node, m_nodes)
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
}
return m_rootNode;
diff --git a/src/declarative/particles/qsgparticleemitter.cpp b/src/declarative/particles/qsgparticleemitter.cpp
index bf4f5701e5..2a76f77cf1 100644
--- a/src/declarative/particles/qsgparticleemitter.cpp
+++ b/src/declarative/particles/qsgparticleemitter.cpp
@@ -317,6 +317,11 @@ void QSGParticleEmitter::setSpeedFromMovement(qreal t)
emit speedFromMovementChanged();
}
+void QSGParticleEmitter::reset()
+{
+ m_reset_last = true;
+}
+
void QSGParticleEmitter::emitWindow(int timeStamp)
{
if (m_system == 0)
@@ -346,7 +351,6 @@ void QSGParticleEmitter::emitWindow(int timeStamp)
}
qreal time = timeStamp / 1000.;
-
qreal particleRatio = 1. / m_particlesPerSecond;
qreal pt = m_last_emission;
diff --git a/src/declarative/particles/qsgparticleemitter_p.h b/src/declarative/particles/qsgparticleemitter_p.h
index 2c75fbfe22..cd14fa55e9 100644
--- a/src/declarative/particles/qsgparticleemitter_p.h
+++ b/src/declarative/particles/qsgparticleemitter_p.h
@@ -257,17 +257,17 @@ public slots:
}
void setOverWrite(bool arg)
-{
- if (m_overwrite != arg) {
- m_overwrite = arg;
-emit overwriteChanged(arg);
-}
-}
+ {
+ if (m_overwrite != arg) {
+ m_overwrite = arg;
+ emit overwriteChanged(arg);
+ }
+ }
public:
int particleCount() const;
- virtual void reset(){;}
+ virtual void reset();
QSGParticleExtruder* extruder() const
{
return m_extruder;
diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp
index efd6c22bd9..8bd39984ee 100644
--- a/src/declarative/particles/qsgparticlesystem.cpp
+++ b/src/declarative/particles/qsgparticlesystem.cpp
@@ -54,6 +54,8 @@
#include <QDebug>
QT_BEGIN_NAMESPACE
+//###Switch to define later, for now user-friendly (no compilation) debugging is worth it
+DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG)
/*!
\qmlclass ParticleSystem QSGParticleSystem
\inqmlmodule QtQuick.Particles 2
@@ -64,8 +66,23 @@ QT_BEGIN_NAMESPACE
/*!
\qmlproperty bool QtQuick.Particles2::ParticleSystem::running
- If running is set to false, the particle system will not advance the simulation.
+ If running is set to false, the particle system will stop the simulation. All particles
+ will be destroyed when the system is set to running again.
+
+ It can also be controlled with the start() and stop() methods.
+*/
+
+
+/*!
+ \qmlproperty bool QtQuick.Particles2::ParticleSystem::paused
+
+ If paused is set to true, the particle system will not advance the simulation. When
+ paused is set to false again, the simulation will resume from the same point it was
+ paused.
+
+ It can also be controlled with the pause() and resume() methods.
*/
+
/*!
\qmlproperty int QtQuick.Particles2::ParticleSystem::startTime
@@ -491,13 +508,10 @@ QSGParticleSystem::QSGParticleSystem(QSGItem *parent) :
QSGItem(parent), m_particle_count(0), m_running(true)
, m_startTime(0), m_nextIndex(0), m_componentComplete(false), m_spriteEngine(0)
{
- QSGParticleGroupData* gd = new QSGParticleGroupData(0, this);//Default group
- m_groupData.insert(0,gd);
- m_groupIds.insert("",0);
- m_nextGroupId = 1;
-
connect(&m_painterMapper, SIGNAL(mapped(QObject*)),
this, SLOT(loadPainter(QObject*)));
+
+ m_debugMode = qmlParticlesDebug();
}
QSGParticleSystem::~QSGParticleSystem()
@@ -506,7 +520,22 @@ QSGParticleSystem::~QSGParticleSystem()
delete gd;
}
-QDeclarativeListProperty<QSGSprite> QSGParticleSystem::particleStates()
+void QSGParticleSystem::initGroups()
+{
+ m_reusableIndexes.clear();
+ m_nextIndex = 0;
+
+ qDeleteAll(m_groupData);
+ m_groupData.clear();
+ m_groupIds.clear();
+
+ QSGParticleGroupData* gd = new QSGParticleGroupData(0, this);//Default group
+ m_groupData.insert(0,gd);
+ m_groupIds.insert("",0);
+ m_nextGroupId = 1;
+}
+
+ QDeclarativeListProperty<QSGSprite> QSGParticleSystem::particleStates()
{
return QDeclarativeListProperty<QSGSprite>(this, &m_states, spriteAppend, spriteCount, spriteAt, spriteClear);
}
@@ -514,11 +543,10 @@ QDeclarativeListProperty<QSGSprite> QSGParticleSystem::particleStates()
void QSGParticleSystem::registerParticlePainter(QSGParticlePainter* p)
{
//TODO: a way to Unregister emitters, painters and affectors
- m_particlePainters << QPointer<QSGParticlePainter>(p);//###Set or uniqueness checking?
+ m_painters << QPointer<QSGParticlePainter>(p);//###Set or uniqueness checking?
connect(p, SIGNAL(particlesChanged(QStringList)),
&m_painterMapper, SLOT(map()));
loadPainter(p);
- p->update();//###Initial update here?
}
void QSGParticleSystem::registerParticleEmitter(QSGParticleEmitter* e)
@@ -537,6 +565,120 @@ void QSGParticleSystem::registerParticleAffector(QSGParticleAffector* a)
m_affectors << QPointer<QSGParticleAffector>(a);
}
+void QSGParticleSystem::setRunning(bool arg)
+{
+ if (m_running != arg) {
+ m_running = arg;
+ emit runningChanged(arg);
+ setPaused(false);
+ if (m_animation)//Not created until componentCompleted
+ m_running ? m_animation->start() : m_animation->stop();
+ reset();
+ }
+}
+
+void QSGParticleSystem::setPaused(bool arg){
+ if (m_paused != arg) {
+ m_paused = arg;
+ if (m_animation && m_animation->state() != QAbstractAnimation::Stopped)
+ m_paused ? m_animation->pause() : m_animation->resume();
+ if (!m_paused){
+ foreach (QSGParticlePainter *p, m_painters)
+ p->update();
+ }
+ emit pausedChanged(arg);
+ }
+}
+
+void QSGParticleSystem::stateRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value)
+{
+ //Hooks up automatic state-associated stuff
+ QSGParticleSystem* sys = qobject_cast<QSGParticleSystem*>(prop->object->parent());
+ QSGSprite* sprite = qobject_cast<QSGSprite*>(prop->object);
+ if (!sprite || !sys)
+ return;
+ QStringList list;
+ list << sprite->name();
+ QSGParticleAffector* a = qobject_cast<QSGParticleAffector*>(value);
+ if (a){
+ a->setParentItem(sys);
+ a->setParticles(list);
+ a->setSystem(sys);
+ return;
+ }
+ QSGFollowEmitter* fe = qobject_cast<QSGFollowEmitter*>(value);
+ if (fe){
+ fe->setParentItem(sys);
+ fe->setFollow(sprite->name());
+ fe->setSystem(sys);
+ return;
+ }
+ QSGParticleEmitter* e = qobject_cast<QSGParticleEmitter*>(value);
+ if (e){
+ e->setParentItem(sys);
+ e->setParticle(sprite->name());
+ e->setSystem(sys);
+ return;
+ }
+ QSGParticlePainter* p = qobject_cast<QSGParticlePainter*>(value);
+ if (p){
+ p->setParentItem(sys);
+ p->setParticles(list);
+ p->setSystem(sys);
+ return;
+ }
+ qWarning() << value << " was placed inside a particle system state but cannot be taken into the particle system. It will be lost.";
+}
+
+void QSGParticleSystem::componentComplete()
+
+{
+ QSGItem::componentComplete();
+ m_componentComplete = true;
+ m_animation = new QSGParticleSystemAnimation(this);
+ reset();//restarts animation as well
+}
+
+void QSGParticleSystem::reset()
+{
+ if (!m_componentComplete)
+ return;
+
+ m_timeInt = 0;
+ //Clear guarded pointers which have been deleted
+ int cleared = 0;
+ cleared += m_emitters.removeAll(0);
+ cleared += m_painters.removeAll(0);
+ cleared += m_affectors.removeAll(0);
+
+ m_bySysIdx.resize(0);
+ initGroups();//Also clears all logical particles
+
+ if (!m_running)
+ return;
+
+ foreach (QSGParticleEmitter* e, m_emitters)
+ e->reset();
+
+ emittersChanged();
+
+ foreach (QSGParticlePainter *p, m_painters){
+ loadPainter(p);
+ p->reset();
+ }
+
+ //### Do affectors need reset too?
+
+ if (m_animation){//reset restarts animation (if running)
+ m_animation->stop();
+ m_animation->start();
+ if (m_paused)
+ m_animation->pause();
+ }
+ m_initialized = true;
+}
+
+
void QSGParticleSystem::loadPainter(QObject *p)
{
if (!m_componentComplete)
@@ -566,7 +708,7 @@ void QSGParticleSystem::loadPainter(QObject *p)
}
}
painter->setCount(particleCount);
- painter->update();//###Initial update here?
+ painter->update();//Initial update here
return;
}
@@ -609,101 +751,14 @@ void QSGParticleSystem::emittersChanged()
Q_ASSERT(m_particle_count >= m_bySysIdx.size());//XXX when GC done right
m_bySysIdx.resize(m_particle_count);
- foreach (QSGParticlePainter *p, m_particlePainters)
+ foreach (QSGParticlePainter *p, m_painters)
loadPainter(p);
if (!m_states.isEmpty())
createEngine();
- if (m_particle_count > 16000)//###Investigate if these limits are worth warning about?
- qWarning() << "Particle system arbitarily believes it has a vast number of particles (>16000). Expect poor performance";
-}
-
-void QSGParticleSystem::setRunning(bool arg)
-{
- if (m_running != arg) {
- m_running = arg;
- emit runningChanged(arg);
- reset();
- }
-}
-
-void QSGParticleSystem::stateRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value)
-{
- //Hooks up automatic state-associated stuff
- QSGParticleSystem* sys = qobject_cast<QSGParticleSystem*>(prop->object->parent());
- QSGSprite* sprite = qobject_cast<QSGSprite*>(prop->object);
- if (!sprite || !sys)
- return;
- QStringList list;
- list << sprite->name();
- QSGParticleAffector* a = qobject_cast<QSGParticleAffector*>(value);
- if (a){
- a->setParentItem(sys);
- a->setParticles(list);
- a->setSystem(sys);
- return;
- }
- QSGFollowEmitter* e = qobject_cast<QSGFollowEmitter*>(value);
- if (e){
- e->setParentItem(sys);
- e->setFollow(sprite->name());
- e->setSystem(sys);
- return;
- }
- QSGParticlePainter* p = qobject_cast<QSGParticlePainter*>(value);
- if (p){
- p->setParentItem(sys);
- p->setParticles(list);
- p->setSystem(sys);
- return;
- }
- qWarning() << value << " was placed inside a particle system state but cannot be taken into the particle system. It will be lost.";
-}
-
-void QSGParticleSystem::componentComplete()
-
-{
- QSGItem::componentComplete();
- m_componentComplete = true;
- m_animation = new QSGParticleSystemAnimation(this);
- reset();//restarts animation as well
-}
-
-void QSGParticleSystem::reset()//TODO: Needed? Or just in component complete?
-{
- if (!m_componentComplete)
- return;
-
- m_timeInt = 0;
- //Clear guarded pointers which have been deleted
- int cleared = 0;
- cleared += m_emitters.removeAll(0);
- cleared += m_particlePainters.removeAll(0);
- cleared += m_affectors.removeAll(0);
-
- emittersChanged();
-
- //TODO: Reset data
-// foreach (QSGParticlePainter* p, m_particlePainters)
-// p->reset();
-// foreach (QSGParticleEmitter* e, m_emitters)
-// e->reset();
- //### Do affectors need reset too?
-
- if (!m_running)
- return;
-
- foreach (QSGParticlePainter *p, m_particlePainters){
- loadPainter(p);
- p->reset();
- }
-
- if (m_animation){
- m_animation->stop();
- m_animation->start();
- }
- m_initialized = true;
+ if (m_debugMode)
+ qDebug() << "Particle system emitters changed. New particle count: " << m_particle_count;
}
void QSGParticleSystem::createEngine()
diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h
index abb7f52c31..f578c43378 100644
--- a/src/declarative/particles/qsgparticlesystem_p.h
+++ b/src/declarative/particles/qsgparticlesystem_p.h
@@ -218,6 +218,7 @@ class QSGParticleSystem : public QSGItem
{
Q_OBJECT
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged)
Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
Q_PROPERTY(QDeclarativeListProperty<QSGSprite> particleStates READ particleStates)
@@ -247,10 +248,18 @@ signals:
void startTimeChanged(int arg);
+ void pausedChanged(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);
void setStartTime(int arg)
{
@@ -264,6 +273,7 @@ public slots:
virtual int duration() const { return -1; }
+
protected:
//This one only once per frame (effectively)
void componentComplete();
@@ -300,12 +310,18 @@ public://###but only really for related class usage. Perhaps we should all be fr
int m_particle_count;
static void stateRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value);//From QSGSprite
+ bool isPaused() const
+ {
+ return m_paused;
+ }
+
private:
void initializeSystem();
+ void initGroups();
bool m_running;
QList<QPointer<QSGParticleEmitter> > m_emitters;
QList<QPointer<QSGParticleAffector> > m_affectors;
- QList<QPointer<QSGParticlePainter> > m_particlePainters;
+ QList<QPointer<QSGParticlePainter> > m_painters;
QList<QPointer<QSGParticlePainter> > m_syncList;
qint64 m_startTime;
int m_nextGroupId;
@@ -319,6 +335,8 @@ private:
friend class QSGParticleSystemAnimation;
void updateCurrentTime( int currentTime );
QSGParticleSystemAnimation* m_animation;
+ bool m_paused;
+ bool m_debugMode;
};
// Internally, this animation drives all the timing. Painters sync up in their updatePaintNode