diff options
Diffstat (limited to 'src/declarative/particles/qsgparticlesystem.cpp')
-rw-r--r-- | src/declarative/particles/qsgparticlesystem.cpp | 788 |
1 files changed, 587 insertions, 201 deletions
diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index 2dc21299cf..d648d46330 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -44,19 +44,232 @@ #include "qsgparticleemitter_p.h" #include "qsgparticleaffector_p.h" #include "qsgparticlepainter_p.h" +#include "qsgspriteengine_p.h" +#include "qsgsprite_p.h" + +#include "qsgfollowemitter_p.h"//###For auto-follow on states, perhaps should be in emitter? #include <cmath> #include <QDebug> QT_BEGIN_NAMESPACE -QSGParticleData::QSGParticleData() +const qreal EPSILON = 0.001; +//Utility functions for when within 1ms is close enough +bool timeEqualOrGreater(qreal a, qreal b){ + return (a+EPSILON >= b); +} + +bool timeLess(qreal a, qreal b){ + return (a-EPSILON < b); +} + +bool timeEqual(qreal a, qreal b){ + return (a+EPSILON > b) && (a-EPSILON < b); +} + +int roundedTime(qreal a){// in ms + return (int)qRound(a*1000.0); +} + +QSGParticleDataHeap::QSGParticleDataHeap() + : m_data(0) +{ + m_data.reserve(1000); + clear(); +} + +void QSGParticleDataHeap::grow() //###Consider automatic growth vs resize() calls from GroupData +{ + m_data.resize(1 << ++m_size); +} + +void QSGParticleDataHeap::insert(QSGParticleData* data) +{ + int time = roundedTime(data->t + data->lifeSpan); + if (m_lookups.contains(time)){ + m_data[m_lookups[time]].data << data; + return; + } + if (m_end == (1 << m_size)) + grow(); + m_data[m_end].time = time; + m_data[m_end].data.clear(); + m_data[m_end].data.insert(data); + m_lookups.insert(time, m_end); + bubbleUp(m_end++); +} + +int QSGParticleDataHeap::top() +{ + if (m_end == 0) + return 1e24; + return m_data[0].time; +} + +QSet<QSGParticleData*> QSGParticleDataHeap::pop() +{ + if (!m_end) + return QSet<QSGParticleData*> (); + QSet<QSGParticleData*> ret = m_data[0].data; + m_lookups.remove(m_data[0].time); + if (m_end == 1){ + --m_end; + }else{ + m_data[0] = m_data[--m_end]; + bubbleDown(0); + } + return ret; +} + +void QSGParticleDataHeap::clear() +{ + m_size = 0; + m_end = 0; + //m_size is in powers of two. So to start at 0 we have one allocated + m_data.resize(1); + m_lookups.clear(); +} + +bool QSGParticleDataHeap::contains(QSGParticleData* d) +{ + for (int i=0; i<m_end; i++) + if (m_data[i].data.contains(d)) + return true; + return false; +} + +void QSGParticleDataHeap::swap(int a, int b) +{ + m_tmp = m_data[a]; + m_data[a] = m_data[b]; + m_data[b] = m_tmp; + m_lookups[m_data[a].time] = a; + m_lookups[m_data[b].time] = b; +} + +void QSGParticleDataHeap::bubbleUp(int idx)//tends to be called once +{ + if (!idx) + return; + int parent = (idx-1)/2; + if (m_data[idx].time < m_data[parent].time){ + swap(idx, parent); + bubbleUp(parent); + } +} + +void QSGParticleDataHeap::bubbleDown(int idx)//tends to be called log n times +{ + int left = idx*2 + 1; + if (left >= m_end) + return; + int lesser = left; + int right = idx*2 + 2; + if (right < m_end){ + if (m_data[left].time > m_data[right].time) + lesser = right; + } + if (m_data[idx].time > m_data[lesser].time){ + swap(idx, lesser); + bubbleDown(lesser); + } +} + +QSGParticleGroupData::QSGParticleGroupData(int id, QSGParticleSystem* sys):index(id),m_size(0),m_system(sys) +{ + initList(); +} + +QSGParticleGroupData::~QSGParticleGroupData() +{ + foreach (QSGParticleData* d, data) + delete d; +} + +int QSGParticleGroupData::size() +{ + return m_size; +} + +QString QSGParticleGroupData::name()//### Worth caching as well? +{ + return m_system->m_groupIds.key(index); +} + +void QSGParticleGroupData::setSize(int newSize){ + if (newSize == m_size) + return; + Q_ASSERT(newSize > m_size);//XXX allow shrinking + data.resize(newSize); + for (int i=m_size; i<newSize; i++){ + data[i] = new QSGParticleData(m_system); + data[i]->group = index; + data[i]->index = i; + reusableIndexes << i; + } + int delta = newSize - m_size; + m_size = newSize; + foreach (QSGParticlePainter* p, painters) + p->setCount(p->count() + delta); +} + +void QSGParticleGroupData::initList() +{ + dataHeap.clear(); +} + +void QSGParticleGroupData::kill(QSGParticleData* d){ + Q_ASSERT(d->group == index); + d->lifeSpan = 0;//Kill off + foreach (QSGParticlePainter* p, painters) + p->reload(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 + } + } + } + + while (!reusableIndexes.empty()){ + int idx = *(reusableIndexes.begin()); + reusableIndexes.remove(idx); + if (data[idx]->stillAlive()){// ### This means resurrection of dead particles. Is that allowed? + prepareRecycler(data[idx]); + continue; + } + return data[idx]; + } + if (respectsLimits) + return 0; + + int oldSize = m_size; + setSize(oldSize + 10);//###+1,10%,+10? Choose something non-arbitrarily + reusableIndexes.remove(oldSize); + return data[oldSize]; +} + +void QSGParticleGroupData::prepareRecycler(QSGParticleData* d){ + dataHeap.insert(d); +} + +QSGParticleData::QSGParticleData(QSGParticleSystem* sys) : group(0) , e(0) + , system(sys) , index(0) + , systemIndex(-1) { x = 0; y = 0; t = -1; + lifeSpan = 0; size = 0; endSize = 0; sx = 0; @@ -70,9 +283,9 @@ QSGParticleData::QSGParticleData() rotation = 0; rotationSpeed = 0; autoRotate = 0; - animIdx = -1; + animIdx = 0; frameDuration = 1; - frameCount = 0; + frameCount = 1; animT = -1; color.r = 255; color.g = 255; @@ -83,12 +296,163 @@ QSGParticleData::QSGParticleData() modelIndex = -1; } +void QSGParticleData::clone(const QSGParticleData& other) +{ + x = other.x; + y = other.y; + t = other.t; + lifeSpan = other.lifeSpan; + size = other.size; + endSize = other.endSize; + sx = other.sx; + sy = other.sy; + ax = other.ax; + ay = other.ay; + xx = other.xx; + xy = other.xy; + yx = other.yx; + yy = other.yy; + rotation = other.rotation; + rotationSpeed = other.rotationSpeed; + autoRotate = other.autoRotate; + animIdx = other.animIdx; + frameDuration = other.frameDuration; + frameCount = other.frameCount; + animT = other.animT; + color.r = other.color.r; + color.g = other.color.g; + color.b = other.color.b; + color.a = other.color.a; + r = other.r; + delegate = other.delegate; + modelIndex = other.modelIndex; +} + +//sets the x accleration without affecting the instantaneous x velocity or position +void QSGParticleData::setInstantaneousAX(qreal ax) +{ + 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; + + 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) - 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; + + this->sx = sx; + this->x = x; +} + +//sets the instantaneous x postion +void QSGParticleData::setInstantaneousX(qreal x) +{ + 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) - 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; + + 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) - this->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) - 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) - 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) - this->t; + return this->sx + t*this->ax; +} + +qreal QSGParticleData::curY() const +{ + 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) - this->t; + return sy + t*ay; +} + +void QSGParticleData::debugDump() +{ + qDebug() << "Particle" << systemIndex << group << "/" << index << stillAlive() + << "Pos: " << x << "," << y + //<< "Vel: " << sx << "," << sy + //<< "Acc: " << ax << "," << ay + << "Size: " << size << "," << endSize + << "Time: " << t << "," <<lifeSpan << ";" << (system->m_timeInt / 1000.0) ; +} + +bool QSGParticleData::stillAlive() +{ + if (!system) + return false; + //fprintf(stderr, "%.9lf %.9lf\n",((qreal)system->m_timeInt/1000.0), (t+lifeSpan)); + return (t + lifeSpan - EPSILON) > ((qreal)system->m_timeInt/1000.0); +} + +float QSGParticleData::curSize() +{ + if (!system || !lifeSpan) + return 0.0f; + return size + (endSize - size) * (lifeLeft() / lifeSpan); +} + +float QSGParticleData::lifeLeft() +{ + if (!system) + return 0.0f; + return (t + lifeSpan) - (system->m_timeInt/1000.0); +} + QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : QSGItem(parent), m_particle_count(0), m_running(true) - , m_startTime(0), m_overwrite(false) - , m_componentComplete(false) + , m_startTime(0), m_nextIndex(0), m_componentComplete(false), m_spriteEngine(0) { - QSGParticleGroupData* gd = new QSGParticleGroupData;//Default group + QSGParticleGroupData* gd = new QSGParticleGroupData(0, this);//Default group m_groupData.insert(0,gd); m_groupIds.insert("",0); m_nextGroupId = 1; @@ -97,6 +461,17 @@ QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : this, SLOT(loadPainter(QObject*))); } +QSGParticleSystem::~QSGParticleSystem() +{ + foreach (QSGParticleGroupData* gd, m_groupData) + delete gd; +} + +QDeclarativeListProperty<QSGSprite> QSGParticleSystem::particleStates() +{ + return QDeclarativeListProperty<QSGSprite>(this, &m_states, spriteAppend, spriteCount, spriteAt, spriteClear); +} + void QSGParticleSystem::registerParticlePainter(QSGParticlePainter* p) { //TODO: a way to Unregister emitters, painters and affectors @@ -125,20 +500,29 @@ void QSGParticleSystem::registerParticleAffector(QSGParticleAffector* a) void QSGParticleSystem::loadPainter(QObject *p) { - if(!m_componentComplete) + if (!m_componentComplete) return; QSGParticlePainter* painter = qobject_cast<QSGParticlePainter*>(p); Q_ASSERT(painter);//XXX - foreach(QSGParticleGroupData* sg, m_groupData) + foreach (QSGParticleGroupData* sg, m_groupData) sg->painters.remove(painter); int particleCount = 0; - if(painter->particles().isEmpty()){//Uses default particle - particleCount += m_groupData[0]->size; + if (painter->particles().isEmpty()){//Uses default particle + QStringList def; + def << ""; + painter->setParticles(def); + particleCount += m_groupData[0]->size(); m_groupData[0]->painters << painter; }else{ - foreach(const QString &group, painter->particles()){ - particleCount += m_groupData[m_groupIds[group]]->size; + foreach (const QString &group, painter->particles()){ + if (group != QLatin1String("") && !m_groupIds[group]){//new group + int id = m_nextGroupId++; + QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); + m_groupIds.insert(group, id); + m_groupData.insert(id, gd); + } + particleCount += m_groupData[m_groupIds[group]]->size(); m_groupData[m_groupIds[group]]->painters << painter; } } @@ -149,64 +533,50 @@ void QSGParticleSystem::loadPainter(QObject *p) void QSGParticleSystem::emittersChanged() { - if(!m_componentComplete) + if (!m_componentComplete) return; m_emitters.removeAll(0); - //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; - 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; + QList<int> previousSizes; + QList<int> newSizes; + for (int i=0; i<m_nextGroupId; i++){ + previousSizes << m_groupData[i]->size(); + newSizes << 0; + } - foreach(QSGParticleEmitter* e, m_emitters){//Populate groups and set sizes. - if(!m_groupIds.contains(e->particle()) + 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 - QSGParticleGroupData* gd = new QSGParticleGroupData; int id = m_nextGroupId++; + QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); m_groupIds.insert(e->particle(), id); m_groupData.insert(id, gd); + previousSizes << 0; + newSizes << 0; } - m_groupData[m_groupIds[e->particle()]]->size += e->particleCount(); - m_particle_count += e->particleCount(); + newSizes[m_groupIds[e->particle()]] += e->particleCount(); //###: Cull emptied groups? } - 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); - } - */ - } + //TODO: Garbage collection? + m_particle_count = 0; + for (int i=0; i<m_nextGroupId; i++){ + m_groupData[i]->setSize(qMax(newSizes[i], previousSizes[i])); + m_particle_count += m_groupData[i]->size(); } - foreach(QSGParticlePainter *p, m_particlePainters) + + Q_ASSERT(m_particle_count >= m_bySysIdx.size());//XXX when GC done right + m_bySysIdx.resize(m_particle_count); + + foreach (QSGParticlePainter *p, m_particlePainters) loadPainter(p); - if(m_particle_count > 16000)//###Investigate if these limits are worth warning about? + if (!m_states.isEmpty()) + createEngine(); + + 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"; } @@ -219,17 +589,51 @@ void QSGParticleSystem::setRunning(bool arg) } } +void QSGParticleSystem::stateRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value) +{ + //Hooks up automatic state-associated stuff + QSGParticleSystem* sys = qobject_cast<QSGParticleSystem*>(prop->object->parent()); + QSGSprite* sprite = qobject_cast<QSGSprite*>(prop->object); + if (!sprite || !sys) + return; + QStringList list; + list << sprite->name(); + QSGParticleAffector* a = qobject_cast<QSGParticleAffector*>(value); + if (a){ + a->setParentItem(sys); + a->setParticles(list); + a->setSystem(sys); + return; + } + QSGFollowEmitter* e = qobject_cast<QSGFollowEmitter*>(value); + if (e){ + e->setParentItem(sys); + e->setFollow(sprite->name()); + e->setSystem(sys); + return; + } + QSGParticlePainter* p = qobject_cast<QSGParticlePainter*>(value); + if (p){ + p->setParentItem(sys); + p->setParticles(list); + p->setSystem(sys); + return; + } + qWarning() << value << " was placed inside a particle system state but cannot be taken into the particle system. It will be lost."; +} + void QSGParticleSystem::componentComplete() + { QSGItem::componentComplete(); m_componentComplete = true; - //if(!m_emitters.isEmpty() && !m_particlePainters.isEmpty()) + //if (!m_emitters.isEmpty() && !m_particlePainters.isEmpty()) reset(); } -void QSGParticleSystem::reset()//TODO: Needed? +void QSGParticleSystem::reset()//TODO: Needed? Or just in component complete? { - if(!m_componentComplete) + if (!m_componentComplete) return; //Clear guarded pointers which have been deleted @@ -237,54 +641,134 @@ void QSGParticleSystem::reset()//TODO: Needed? cleared += m_emitters.removeAll(0); cleared += m_particlePainters.removeAll(0); cleared += m_affectors.removeAll(0); - //qDebug() << "Reset" << m_emitters.count() << m_particles.count() << "Cleared" << cleared; emittersChanged(); //TODO: Reset data -// foreach(QSGParticlePainter* p, m_particlePainters) +// foreach (QSGParticlePainter* p, m_particlePainters) // p->reset(); -// foreach(QSGParticleEmitter* e, m_emitters) +// foreach (QSGParticleEmitter* e, m_emitters) // e->reset(); //### Do affectors need reset too? - if(!m_running) + if (!m_running) return; - foreach(QSGParticlePainter *p, m_particlePainters){ + foreach (QSGParticlePainter *p, m_particlePainters){ loadPainter(p); p->reset(); } - m_timestamp.start();//TODO: Better placement + m_timeInt = 0; + m_timestamp.restart();//TODO: Better placement m_initialized = true; } -QSGParticleData* QSGParticleSystem::newDatum(int groupId) +void QSGParticleSystem::createEngine() { + if (!m_componentComplete) + return; + //### Solve the losses if size/states go down + foreach (QSGSprite* sprite, m_states){ + bool exists = false; + foreach (const QString &name, m_groupIds.keys()) + if (sprite->name() == name) + exists = true; + if (!exists){ + int id = m_nextGroupId++; + QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); + m_groupIds.insert(sprite->name(), id); + m_groupData.insert(id, gd); + } + } + if (m_states.count()){ + //Reorder Sprite List so as to have the same order as groups + QList<QSGSprite*> newList; + for (int i=0; i<m_nextGroupId; i++){ + bool exists = false; + QString name = m_groupData[i]->name(); + foreach (QSGSprite* existing, m_states){ + if (existing->name() == name){ + newList << existing; + exists = true; + } + } + if (!exists){ + newList << new QSGSprite(this); + newList.back()->setName(name); + } + } + m_states = newList; + + if (!m_spriteEngine) + m_spriteEngine = new QSGSpriteEngine(this); + m_spriteEngine->setCount(m_particle_count); + m_spriteEngine->m_states = m_states; + + connect(m_spriteEngine, SIGNAL(stateChanged(int)), + this, SLOT(particleStateChange(int))); + + }else{ + if (m_spriteEngine) + delete m_spriteEngine; + m_spriteEngine = 0; + } + +} + +void QSGParticleSystem::particleStateChange(int idx) +{ + moveGroups(m_bySysIdx[idx], m_spriteEngine->spriteState(idx)); +} + +void QSGParticleSystem::moveGroups(QSGParticleData *d, int newGIdx) +{ + QSGParticleData* pd = newDatum(newGIdx, false, d->systemIndex); + pd->clone(*d); + finishNewDatum(pd); + + d->systemIndex = -1; + m_groupData[d->group]->kill(d); +} + +int QSGParticleSystem::nextSystemIndex() +{ + if (!m_reusableIndexes.isEmpty()){ + int ret = *(m_reusableIndexes.begin()); + m_reusableIndexes.remove(ret); + return ret; + } + if (m_nextIndex >= m_bySysIdx.size()) + m_bySysIdx.resize(m_bySysIdx.size() < 10 ? 10 : m_bySysIdx.size()*1.1);//###+1,10%,+10? Choose something non-arbitrarily + return m_nextIndex++; +} + +QSGParticleData* QSGParticleSystem::newDatum(int groupId, bool respectLimits, int sysIndex) +{ Q_ASSERT(groupId < m_groupData.count());//XXX shouldn't really be an assert - Q_ASSERT(m_groupData[groupId]->size); - - if( m_groupData[groupId]->nextIdx >= m_groupData[groupId]->size) - m_groupData[groupId]->nextIdx = 0; - int nextIdx = m_groupData[groupId]->nextIdx++; - - Q_ASSERT(nextIdx < m_groupData[groupId]->size); - QSGParticleData* ret; - 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? + + QSGParticleData* ret = m_groupData[groupId]->newDatum(respectLimits); + if (!ret){ + return 0; + } + if (sysIndex == -1){ + if (ret->systemIndex == -1) + ret->systemIndex = nextSystemIndex(); }else{ - ret = new QSGParticleData; - m_groupData[groupId]->data[nextIdx] = ret; + if (ret->systemIndex != -1){ + if (m_spriteEngine) + m_spriteEngine->stopSprite(ret->systemIndex); + m_reusableIndexes << ret->systemIndex; + m_bySysIdx[ret->systemIndex] = 0; + } + ret->systemIndex = sysIndex; } + m_bySysIdx[ret->systemIndex] = ret; + + if (m_spriteEngine) + m_spriteEngine->startSprite(ret->systemIndex, ret->group); - ret->system = this; - ret->index = nextIdx; - ret->group = groupId; return ret; } @@ -292,20 +776,24 @@ void QSGParticleSystem::emitParticle(QSGParticleData* pd) {// called from prepareNextFrame()->emitWindow - enforce? //Account for relative emitter position QPointF offset = this->mapFromItem(pd->e, QPointF(0, 0)); - if(!offset.isNull()){ + if (!offset.isNull()){ pd->x += offset.x(); pd->y += offset.y(); } - foreach(QSGParticleAffector *a, m_affectors) - if(a && a->m_needsReset) - a->reset(pd); - foreach(QSGParticlePainter* p, m_groupData[pd->group]->painters) - if(p) - p->load(pd); + finishNewDatum(pd); } +void QSGParticleSystem::finishNewDatum(QSGParticleData *pd){ + m_groupData[pd->group]->prepareRecycler(pd); + foreach (QSGParticleAffector *a, m_affectors) + if (a && a->m_needsReset) + a->reset(pd); + foreach (QSGParticlePainter* p, m_groupData[pd->group]->painters) + if (p) + p->load(pd); +} qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p) { @@ -314,7 +802,7 @@ qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p) if (!m_initialized) return 0;//error in initialization - if(m_syncList.isEmpty() || m_syncList.contains(p)){//Need to advance the simulation + if (m_syncList.isEmpty() || m_syncList.contains(p)){//Need to advance the simulation m_syncList.clear(); //### Elapsed time never shrinks - may cause problems if left emitting for weeks at a time. @@ -323,125 +811,23 @@ qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p) qreal time = m_timeInt / 1000.; dt = time - dt; m_needsReset.clear(); - foreach(QSGParticleEmitter* emitter, m_emitters) - if(emitter) + if (m_spriteEngine) + m_spriteEngine->updateSprites(m_timeInt); + + foreach (QSGParticleEmitter* emitter, m_emitters) + if (emitter) emitter->emitWindow(m_timeInt); - foreach(QSGParticleAffector* a, m_affectors) - if(a) + foreach (QSGParticleAffector* a, m_affectors) + if (a) a->affectSystem(dt); - foreach(QSGParticleData* d, m_needsReset) - foreach(QSGParticlePainter* p, m_groupData[d->group]->painters) - if(p && d) + foreach (QSGParticleData* d, m_needsReset) + foreach (QSGParticlePainter* p, m_groupData[d->group]->painters) + if (p && d) p->reload(d); } m_syncList << p; return m_timeInt; } -//sets the x accleration without affecting the instantaneous x velocity or position -void QSGParticleData::setInstantaneousAX(qreal ax) -{ - 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; - - 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) - 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; - - this->sx = sx; - this->x = x; -} - -//sets the instantaneous x postion -void QSGParticleData::setInstantaneousX(qreal x) -{ - 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) - 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; - - 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) - 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) - 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) - 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) - this->t; - return this->sx + t*this->ax; -} - -qreal QSGParticleData::curY() const -{ - 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) - this->t; - return sy + t*ay; -} - -void QSGParticleData::debugDump() -{ - qDebug() << "Particle" << group - << "Pos: " << x << "," << y - << "Vel: " << sx << "," << sy - << "Acc: " << ax << "," << ay - << "Size: " << size << "," << endSize - << "Time: " << t << "," <<lifeSpan; -} - -bool QSGParticleData::stillAlive() -{ - if(!system) - return false; - return (t + lifeSpan) > (system->m_timeInt/1000.0); -} QT_END_NAMESPACE |