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 <qt_sanity_bot@ovi.com>
Reviewed-by: Martin Jones <martin.jones@nokia.com>
This commit is contained in:
Alan Alpert 2011-09-01 17:59:11 +10:00 committed by Qt by Nokia
parent fee3fe7d76
commit d00a2ef6ab
3 changed files with 63 additions and 15 deletions

View File

@ -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{

View File

@ -80,9 +80,24 @@ 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
@ -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)

View File

@ -117,6 +117,7 @@ public:
QVector<QSGParticleData*> data;
QSGParticleDataHeap dataHeap;
QSet<int> 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<QSGSprite> 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