diff options
Diffstat (limited to 'src/declarative/particles/qsgparticlesystem.cpp')
-rw-r--r-- | src/declarative/particles/qsgparticlesystem.cpp | 363 |
1 files changed, 204 insertions, 159 deletions
diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index 4a8f75bb04..2dc21299cf 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -52,18 +52,35 @@ QT_BEGIN_NAMESPACE QSGParticleData::QSGParticleData() : group(0) , e(0) - , particleIndex(0) - , systemIndex(0) + , index(0) { - pv.x = 0; - pv.y = 0; - pv.t = -1; - pv.size = 0; - pv.endSize = 0; - pv.sx = 0; - pv.sy = 0; - pv.ax = 0; - pv.ay = 0; + x = 0; + y = 0; + t = -1; + size = 0; + endSize = 0; + sx = 0; + sy = 0; + ax = 0; + ay = 0; + xx = 1; + xy = 0; + yx = 0; + yy = 1; + rotation = 0; + rotationSpeed = 0; + autoRotate = 0; + animIdx = -1; + frameDuration = 1; + frameCount = 0; + animT = -1; + color.r = 255; + color.g = 255; + color.b = 255; + color.a = 255; + r = 0; + delegate = 0; + modelIndex = -1; } QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : @@ -71,174 +88,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; } @@ -248,14 +293,14 @@ void QSGParticleSystem::emitParticle(QSGParticleData* pd) //Account for relative emitter position QPointF offset = this->mapFromItem(pd->e, QPointF(0, 0)); if(!offset.isNull()){ - pd->pv.x += offset.x(); - pd->pv.y += offset.y(); + pd->x += offset.x(); + pd->y += offset.y(); } 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 +330,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); } @@ -296,107 +341,107 @@ qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p) //sets the x accleration without affecting the instantaneous x velocity or position void QSGParticleData::setInstantaneousAX(qreal ax) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - qreal sx = (pv.sx + t*pv.ax) - t*ax; - qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + qreal sx = (this->sx + t*this->ax) - t*ax; + qreal ex = this->x + this->sx * t + 0.5 * this->ax * t * t; qreal x = ex - t*sx - 0.5 * t*t*ax; - pv.ax = ax; - pv.sx = sx; - pv.x = x; + this->ax = ax; + this->sx = sx; + this->x = x; } //sets the x velocity without affecting the instantaneous x postion void QSGParticleData::setInstantaneousSX(qreal vx) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - qreal sx = vx - t*pv.ax; - qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t; - qreal x = ex - t*sx - 0.5 * t*t*pv.ax; + qreal t = (system->m_timeInt / 1000.0) - this->t; + qreal sx = vx - t*this->ax; + qreal ex = this->x + this->sx * t + 0.5 * this->ax * t * t; + qreal x = ex - t*sx - 0.5 * t*t*this->ax; - pv.sx = sx; - pv.x = x; + this->sx = sx; + this->x = x; } //sets the instantaneous x postion void QSGParticleData::setInstantaneousX(qreal x) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - pv.x = x - t*pv.sx - 0.5 * t*t*pv.ax; + qreal t = (system->m_timeInt / 1000.0) - this->t; + this->x = x - t*this->sx - 0.5 * t*t*this->ax; } //sets the y accleration without affecting the instantaneous y velocity or position void QSGParticleData::setInstantaneousAY(qreal ay) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - qreal sy = (pv.sy + t*pv.ay) - t*ay; - qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + qreal sy = (this->sy + t*this->ay) - t*ay; + qreal ey = this->y + this->sy * t + 0.5 * this->ay * t * t; qreal y = ey - t*sy - 0.5 * t*t*ay; - pv.ay = ay; - pv.sy = sy; - pv.y = y; + this->ay = ay; + this->sy = sy; + this->y = y; } //sets the y velocity without affecting the instantaneous y position void QSGParticleData::setInstantaneousSY(qreal vy) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - //qDebug() << t << (system->m_timeInt/1000.0) << pv.x << pv.sx << pv.ax << pv.x + pv.sx * t + 0.5 * pv.ax * t * t; - qreal sy = vy - t*pv.ay; - qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t; - qreal y = ey - t*sy - 0.5 * t*t*pv.ay; - - pv.sy = sy; - pv.y = y; + qreal t = (system->m_timeInt / 1000.0) - this->t; + //qDebug() << t << (system->m_timeInt/1000.0) << this->x << this->sx << this->ax << this->x + this->sx * t + 0.5 * this->ax * t * t; + qreal sy = vy - t*this->ay; + qreal ey = this->y + this->sy * t + 0.5 * this->ay * t * t; + qreal y = ey - t*sy - 0.5 * t*t*this->ay; + + this->sy = sy; + this->y = y; } //sets the instantaneous Y position void QSGParticleData::setInstantaneousY(qreal y) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - pv.y = y - t*pv.sy - 0.5 * t*t*pv.ay; + qreal t = (system->m_timeInt / 1000.0) - this->t; + this->y = y - t*this->sy - 0.5 * t*t*this->ay; } qreal QSGParticleData::curX() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.x + pv.sx * t + 0.5 * pv.ax * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return this->x + this->sx * t + 0.5 * this->ax * t * t; } qreal QSGParticleData::curSX() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.sx + t*pv.ax; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return this->sx + t*this->ax; } qreal QSGParticleData::curY() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.y + pv.sy * t + 0.5 * pv.ay * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return y + sy * t + 0.5 * ay * t * t; } qreal QSGParticleData::curSY() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.sy + t*pv.ay; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return sy + t*ay; } void QSGParticleData::debugDump() { qDebug() << "Particle" << group - << "Pos: " << pv.x << "," << pv.y - << "Vel: " << pv.sx << "," << pv.sy - << "Acc: " << pv.ax << "," << pv.ay - << "Size: " << pv.size << "," << pv.endSize - << "Time: " << pv.t << "," <<pv.lifeSpan; + << "Pos: " << x << "," << y + << "Vel: " << sx << "," << sy + << "Acc: " << ax << "," << ay + << "Size: " << size << "," << endSize + << "Time: " << t << "," <<lifeSpan; } bool QSGParticleData::stillAlive() { if(!system) return false; - return (pv.t + pv.lifeSpan) > (system->m_timeInt/1000.0); + return (t + lifeSpan) > (system->m_timeInt/1000.0); } QT_END_NAMESPACE |