diff options
Diffstat (limited to 'src/declarative/particles/qsgparticlesystem.cpp')
-rw-r--r-- | src/declarative/particles/qsgparticlesystem.cpp | 235 |
1 files changed, 131 insertions, 104 deletions
diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index 4a8f75bb04..a93f2a5eba 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -52,8 +52,7 @@ QT_BEGIN_NAMESPACE QSGParticleData::QSGParticleData() : group(0) , e(0) - , particleIndex(0) - , systemIndex(0) + , index(0) { pv.x = 0; pv.y = 0; @@ -71,174 +70,202 @@ QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : , m_startTime(0), m_overwrite(false) , m_componentComplete(false) { - m_groupIds = QHash<QString, int>(); + QSGParticleGroupData* gd = new QSGParticleGroupData;//Default group + m_groupData.insert(0,gd); + m_groupIds.insert("",0); + m_nextGroupId = 1; + + connect(&m_painterMapper, SIGNAL(mapped(QObject*)), + this, SLOT(loadPainter(QObject*))); } -void QSGParticleSystem::registerParticleType(QSGParticlePainter* p) +void QSGParticleSystem::registerParticlePainter(QSGParticlePainter* p) { - m_particles << QPointer<QSGParticlePainter>(p);//###Set or uniqueness checking? - reset(); + //TODO: a way to Unregister emitters, painters and affectors + m_particlePainters << 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) { m_emitters << QPointer<QSGParticleEmitter>(e);//###How to get them out? connect(e, SIGNAL(particleCountChanged()), - this, SLOT(countChanged())); + this, SLOT(emittersChanged())); connect(e, SIGNAL(particleChanged(QString)), - this, SLOT(countChanged())); - reset(); + this, SLOT(emittersChanged())); + emittersChanged(); + e->reset();//Start, so that starttime factors appropriately } void QSGParticleSystem::registerParticleAffector(QSGParticleAffector* a) { m_affectors << QPointer<QSGParticleAffector>(a); - //reset();//TODO: Slim down the huge batch of resets at the start } -void QSGParticleSystem::countChanged() +void QSGParticleSystem::loadPainter(QObject *p) { - reset();//Need to give Particles new Count -} + if(!m_componentComplete) + return; -void QSGParticleSystem::setRunning(bool arg) -{ - if (m_running != arg) { - m_running = arg; - emit runningChanged(arg); - reset(); + QSGParticlePainter* painter = qobject_cast<QSGParticlePainter*>(p); + Q_ASSERT(painter);//XXX + foreach(QSGParticleGroupData* sg, m_groupData) + sg->painters.remove(painter); + int particleCount = 0; + if(painter->particles().isEmpty()){//Uses default particle + particleCount += m_groupData[0]->size; + m_groupData[0]->painters << painter; + }else{ + foreach(const QString &group, painter->particles()){ + particleCount += m_groupData[m_groupIds[group]]->size; + m_groupData[m_groupIds[group]]->painters << painter; + } } + painter->setCount(particleCount); + painter->update();//###Initial update here? + return; } -void QSGParticleSystem::componentComplete() -{ - QSGItem::componentComplete(); - m_componentComplete = true; - if(!m_emitters.isEmpty() && !m_particles.isEmpty()) - reset(); -} - -void QSGParticleSystem::initializeSystem() +void QSGParticleSystem::emittersChanged() { - int oldCount = m_particle_count; - m_particle_count = 0;//TODO: Only when changed? - - //### Reset the data too? - for(int i=0; i<oldCount; i++){ - if(m_data[i]){ - delete m_data[i]; - m_data[i] = 0; - } - } + if(!m_componentComplete) + return; - for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++) - delete (*iter); - m_groupData.clear(); - m_groupIds.clear(); + m_emitters.removeAll(0); - GroupData* gd = new GroupData;//Default group - gd->size = 0; - gd->start = -1; - gd->nextIdx = 0; - m_groupData.insert(0,gd); - m_groupIds.insert("",0); - m_nextGroupId = 1; + //Recalculate all counts, as emitter 'particle' may have changed as well + //### Worth tracking previous 'particle' per emitter to do partial recalculations? + m_particle_count = 0; - if(!m_emitters.count() || !m_particles.count()) - return; + int previousGroups = m_nextGroupId; + QVector<int> previousSizes; + previousSizes.resize(previousGroups); + for(int i=0; i<previousGroups; i++) + previousSizes[i] = m_groupData[i]->size; + for(int i=0; i<previousGroups; i++) + m_groupData[i]->size = 0; - foreach(QSGParticleEmitter* e, m_emitters){ + foreach(QSGParticleEmitter* e, m_emitters){//Populate groups and set sizes. if(!m_groupIds.contains(e->particle()) || (!e->particle().isEmpty() && !m_groupIds[e->particle()])){//or it was accidentally inserted by a failed lookup earlier - GroupData* gd = new GroupData; - gd->size = 0; - gd->start = -1; - gd->nextIdx = 0; + QSGParticleGroupData* gd = new QSGParticleGroupData; int id = m_nextGroupId++; m_groupIds.insert(e->particle(), id); m_groupData.insert(id, gd); } m_groupData[m_groupIds[e->particle()]]->size += e->particleCount(); + m_particle_count += e->particleCount(); + //###: Cull emptied groups? } - for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++){ - (*iter)->start = m_particle_count; - m_particle_count += (*iter)->size; - } - m_data.resize(m_particle_count); - for(int i=oldCount; i<m_particle_count; i++) - m_data[i] = 0;//setup new ones - - if(m_particle_count > 16000) - qWarning() << "Particle system contains a vast number of particles (>16000). Expect poor performance"; - - foreach(QSGParticlePainter* particle, m_particles){ - int particleCount = 0; - if(particle->particles().isEmpty()){//Uses default particle - particleCount += m_groupData[0]->size; - m_groupData[0]->types << particle; - }else{ - foreach(const QString &group, particle->particles()){ - particleCount += m_groupData[m_groupIds[group]]->size; - m_groupData[m_groupIds[group]]->types << particle; + foreach(QSGParticleGroupData* gd, m_groupData){//resize groups and update painters + int id = m_groupData.key(gd); + + //TODO: Shrink back down! (but it has the problem of trying to remove the dead particles while maintaining integrity) + gd->size = qMax(gd->size, id < previousGroups?previousSizes[id]:0); + + gd->data.resize(gd->size); + if(id < previousGroups){ + for(int i=previousSizes[id]; i<gd->size; i++) + gd->data[i] = 0; + /*TODO:Consider salvaging partial updates, but have to batch changes to a single painter + int delta = 0; + delta = gd->size - previousSizes[id]; + foreach(QSGParticlePainter* painter, gd->painters){ + if(!painter->count() && delta){ + painter->reset(); + painter->update(); + } + qDebug() << "Phi" << painter << painter->count() << delta; + painter->setCount(painter->count() + delta); } + */ } - particle->setCount(particleCount); - particle->m_pleaseReset = true; } + foreach(QSGParticlePainter *p, m_particlePainters) + loadPainter(p); - m_timestamp.start(); - m_initialized = true; - emit systemInitialized(); - qDebug() << "System Initialized. Size:" << m_particle_count; + 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::reset() +void QSGParticleSystem::componentComplete() +{ + QSGItem::componentComplete(); + m_componentComplete = true; + //if(!m_emitters.isEmpty() && !m_particlePainters.isEmpty()) + reset(); +} + +void QSGParticleSystem::reset()//TODO: Needed? { if(!m_componentComplete) - return;//Batch starting reset()s a little + return; + //Clear guarded pointers which have been deleted int cleared = 0; cleared += m_emitters.removeAll(0); - cleared += m_particles.removeAll(0); + cleared += m_particlePainters.removeAll(0); cleared += m_affectors.removeAll(0); //qDebug() << "Reset" << m_emitters.count() << m_particles.count() << "Cleared" << cleared; - foreach(QSGParticlePainter* p, m_particles) - p->reset(); - foreach(QSGParticleEmitter* e, m_emitters) - e->reset(); + + 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; - initializeSystem(); - foreach(QSGParticlePainter* p, m_particles) - p->update(); - foreach(QSGParticleEmitter* e, m_emitters) - e->emitWindow(0);//Start, so that starttime factors appropriately + + foreach(QSGParticlePainter *p, m_particlePainters){ + loadPainter(p); + p->reset(); + } + + m_timestamp.start();//TODO: Better placement + m_initialized = true; } QSGParticleData* QSGParticleSystem::newDatum(int groupId) { + Q_ASSERT(groupId < m_groupData.count());//XXX shouldn't really be an assert Q_ASSERT(m_groupData[groupId]->size); - int nextIdx = m_groupData[groupId]->start + m_groupData[groupId]->nextIdx++; + if( m_groupData[groupId]->nextIdx >= m_groupData[groupId]->size) m_groupData[groupId]->nextIdx = 0; + int nextIdx = m_groupData[groupId]->nextIdx++; - Q_ASSERT(nextIdx < m_data.size()); + Q_ASSERT(nextIdx < m_groupData[groupId]->size); QSGParticleData* ret; - if(m_data[nextIdx]){//Recycle, it's faster. - ret = m_data[nextIdx]; + if(m_groupData[groupId]->data[nextIdx]){//Recycle, it's faster. + ret = m_groupData[groupId]->data[nextIdx]; if(!m_overwrite && ret->stillAlive()){ return 0;//Artificial longevity (or too fast emission) means this guy hasn't died. To maintain count, don't emit a new one }//###Reset? }else{ ret = new QSGParticleData; - m_data[nextIdx] = ret; + m_groupData[groupId]->data[nextIdx] = ret; } ret->system = this; - ret->systemIndex = nextIdx; - ret->particleIndex = nextIdx - m_groupData[groupId]->start; + ret->index = nextIdx; ret->group = groupId; return ret; } @@ -254,8 +281,8 @@ void QSGParticleSystem::emitParticle(QSGParticleData* pd) foreach(QSGParticleAffector *a, m_affectors) if(a && a->m_needsReset) - a->reset(pd->systemIndex); - foreach(QSGParticlePainter* p, m_groupData[pd->group]->types) + a->reset(pd); + foreach(QSGParticlePainter* p, m_groupData[pd->group]->painters) if(p) p->load(pd); } @@ -285,7 +312,7 @@ qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p) if(a) a->affectSystem(dt); foreach(QSGParticleData* d, m_needsReset) - foreach(QSGParticlePainter* p, m_groupData[d->group]->types) + foreach(QSGParticlePainter* p, m_groupData[d->group]->painters) if(p && d) p->reload(d); } |