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
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)
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;
}
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);
}
if (m_spriteEngine)
m_spriteEngine->startSprite(ret->systemIndex, ret->group);
+ m_clear = false;
return ret;
}
void QSGParticleSystem::updateCurrentTime( int currentTime )
{
- if (!m_running)
- return;
if (!m_initialized)
return;//error in initialization
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);
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)
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);
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)
void pausedChanged(bool arg);
+ void clearChanged(bool arg);
+
public slots:
void start(){setRunning(true);}
void stop(){setRunning(false);}
return m_paused;
}
+ bool isClear() const
+ {
+ return m_clear;
+ }
+
private:
void initializeSystem();
void initGroups();
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