aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/particles/qsgparticlesystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/particles/qsgparticlesystem.cpp')
-rw-r--r--src/declarative/particles/qsgparticlesystem.cpp363
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