From d00a2ef6ab2081d73475460d12b5a35d32923a9a Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 1 Sep 2011 17:59:11 +1000 Subject: [PATCH] Add clear property to QSGParticleSystem Makes it possible to pause the system when all particles are expired. Change-Id: Iebeb987c2e2af261bdffa4584d75f3b108dcf050 Reviewed-on: http://codereview.qt-project.org/4046 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- .../declarative/particles/trails/overburst.qml | 6 ++- src/declarative/particles/qsgparticlesystem.cpp | 61 +++++++++++++++----- src/declarative/particles/qsgparticlesystem_p.h | 11 ++++ 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/examples/declarative/particles/trails/overburst.qml b/examples/declarative/particles/trails/overburst.qml index ca6bc6d..620ae46 100644 --- a/examples/declarative/particles/trails/overburst.qml +++ b/examples/declarative/particles/trails/overburst.qml @@ -45,7 +45,10 @@ Rectangle{ color: "black" width: 360 height: 540 - ParticleSystem{ id: sys } + ParticleSystem{ + id: sys + onClearChanged: if (clear) sys.pause(); + } ImageParticle{ system: sys id: cp @@ -69,6 +72,7 @@ Rectangle{ } MouseArea{ anchors.fill: parent + onPressed: sys.resume() id: ma } MouseArea{ diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index 8bd3998..0888e7b 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -80,10 +80,25 @@ DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG) paused is set to false again, the simulation will resume from the same point it was paused. + The simulation will automatically pause if it detects that there are no live particles + left, and unpause when new live particles are added. + It can also be controlled with the pause() and resume() methods. */ /*! + \qmlproperty bool QtQuick.Particles2::ParticleSystem::clear + + clear is set to true when there are no live particles left in the system. + + You can use this to pause the system, keeping it from spending any time updating, + but you will need to resume it in order for additional particles to be generated + by the system. + + To kill all the particles in the system, use a Kill affector. +*/ + +/*! \qmlproperty int QtQuick.Particles2::ParticleSystem::startTime If start time is specified, then the system will simulate up to this time @@ -267,7 +282,8 @@ void QSGParticleGroupData::initList() dataHeap.clear(); } -void QSGParticleGroupData::kill(QSGParticleData* d){ +void QSGParticleGroupData::kill(QSGParticleData* d) +{ Q_ASSERT(d->group == index); d->lifeSpan = 0;//Kill off foreach (QSGParticlePainter* p, painters) @@ -275,21 +291,14 @@ void QSGParticleGroupData::kill(QSGParticleData* d){ reusableIndexes << d->index; } -QSGParticleData* QSGParticleGroupData::newDatum(bool respectsLimits){ - while (dataHeap.top() <= m_system->m_timeInt){ - foreach (QSGParticleData* datum, dataHeap.pop()){ - if (!datum->stillAlive()){ - reusableIndexes << datum->index; - }else{ - prepareRecycler(datum); //ttl has been altered mid-way, put it back - } - } - } +QSGParticleData* QSGParticleGroupData::newDatum(bool respectsLimits) +{ + //recycle();//Extra recycler round to be sure? while (!reusableIndexes.empty()){ int idx = *(reusableIndexes.begin()); reusableIndexes.remove(idx); - if (data[idx]->stillAlive()){// ### This means resurrection of dead particles. Is that allowed? + if (data[idx]->stillAlive()){// ### This means resurrection of 'dead' particles. Is that allowed? prepareRecycler(data[idx]); continue; } @@ -304,6 +313,22 @@ QSGParticleData* QSGParticleGroupData::newDatum(bool respectsLimits){ return data[oldSize]; } +bool QSGParticleGroupData::recycle() +{ + while (dataHeap.top() <= m_system->m_timeInt){ + foreach (QSGParticleData* datum, dataHeap.pop()){ + if (!datum->stillAlive()){ + reusableIndexes << datum->index; + }else{ + prepareRecycler(datum); //ttl has been altered mid-way, put it back + } + } + } + + //TODO: If the data is clear, gc (consider shrinking stack size)? + return reusableIndexes.count() == m_size; +} + void QSGParticleGroupData::prepareRecycler(QSGParticleData* d){ dataHeap.insert(d); } @@ -870,6 +895,7 @@ QSGParticleData* QSGParticleSystem::newDatum(int groupId, bool respectLimits, in if (m_spriteEngine) m_spriteEngine->startSprite(ret->systemIndex, ret->group); + m_clear = false; return ret; } @@ -899,8 +925,6 @@ void QSGParticleSystem::finishNewDatum(QSGParticleData *pd){ void QSGParticleSystem::updateCurrentTime( int currentTime ) { - if (!m_running) - return; if (!m_initialized) return;//error in initialization @@ -910,6 +934,12 @@ void QSGParticleSystem::updateCurrentTime( int currentTime ) qreal time = m_timeInt / 1000.; dt = time - dt; m_needsReset.clear(); + + bool oldClear = m_clear; + m_clear = true; + foreach (QSGParticleGroupData* gd, m_groupData)//Recycle all groups and see if they're out of live particles + m_clear = m_clear && gd->recycle(); + if (m_spriteEngine) m_spriteEngine->updateSprites(m_timeInt); @@ -923,6 +953,9 @@ void QSGParticleSystem::updateCurrentTime( int currentTime ) foreach (QSGParticlePainter* p, m_groupData[d->group]->painters) if (p && d) p->reload(d); + + if (oldClear != m_clear) + clearChanged(m_clear); } int QSGParticleSystem::systemSync(QSGParticlePainter* p) diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h index f578c43..5df6afb 100644 --- a/src/declarative/particles/qsgparticlesystem_p.h +++ b/src/declarative/particles/qsgparticlesystem_p.h @@ -117,6 +117,7 @@ public: QVector data; QSGParticleDataHeap dataHeap; QSet reusableIndexes; + bool recycle(); //Force recycling round, reutrns true if all indexes are now reusable void initList(); void kill(QSGParticleData* d); @@ -219,6 +220,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(bool clear READ isClear NOTIFY clearChanged) Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged) Q_PROPERTY(QDeclarativeListProperty particleStates READ particleStates) @@ -250,6 +252,8 @@ signals: void pausedChanged(bool arg); + void clearChanged(bool arg); + public slots: void start(){setRunning(true);} void stop(){setRunning(false);} @@ -315,6 +319,11 @@ public://###but only really for related class usage. Perhaps we should all be fr return m_paused; } + bool isClear() const + { + return m_clear; + } + private: void initializeSystem(); void initGroups(); @@ -337,6 +346,8 @@ private: QSGParticleSystemAnimation* m_animation; bool m_paused; bool m_debugMode; + bool m_allDead; + bool m_clear; }; // Internally, this animation drives all the timing. Painters sync up in their updatePaintNode -- 1.7.2.5