From e45295bef132ddf220cecfa3f4343d90908744c5 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 1 Sep 2011 20:11:42 +1000 Subject: [PATCH] Allow particles to have eternal life Change-Id: I3b776a6e79cb064e826cb7b7721a3a57744225c1 Reviewed-on: http://codereview.qt-project.org/4064 Reviewed-by: Alan Alpert Reviewed-by: Qt Sanity Bot --- src/declarative/particles/qsgparticleaffector.cpp | 2 +- src/declarative/particles/qsgparticleemitter.cpp | 17 ++++++++-- src/declarative/particles/qsgparticleemitter_p.h | 9 ++++-- src/declarative/particles/qsgparticlesystem.cpp | 38 +++++++++++++++++++++-- src/declarative/particles/qsgparticlesystem_p.h | 4 +++ 5 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/declarative/particles/qsgparticleaffector.cpp b/src/declarative/particles/qsgparticleaffector.cpp index a64b4ee..8391289 100644 --- a/src/declarative/particles/qsgparticleaffector.cpp +++ b/src/declarative/particles/qsgparticleaffector.cpp @@ -166,7 +166,7 @@ void QSGParticleAffector::affectSystem(qreal dt) m_system->m_needsReset << d; if (m_onceOff) m_onceOffed << qMakePair(d->group, d->index); - if (m_signal) + if (m_signal)//###Make signal based on if connected, and then m_signal just affects AffectParticle for base? emit affected(curPos.x(), curPos.y()); } } diff --git a/src/declarative/particles/qsgparticleemitter.cpp b/src/declarative/particles/qsgparticleemitter.cpp index 2a76f77..6519bf5 100644 --- a/src/declarative/particles/qsgparticleemitter.cpp +++ b/src/declarative/particles/qsgparticleemitter.cpp @@ -100,6 +100,12 @@ QT_BEGIN_NAMESPACE The time in milliseconds each emitted particle should last for. + If you do not want particles to automatically die after a time, for example if + you wish to dispose of them manually, set lifeSpan to Emitter.InfiniteLife. + + lifeSpans greater than or equal to 600000 (10 minutes) will be treated as infinite. + Particles with lifeSpans less than or equal to 0 will start out dead. + Default value is 1000 (one second). */ /*! @@ -205,7 +211,6 @@ QSGParticleEmitter::QSGParticleEmitter(QSGItem *parent) : , m_maxParticleCount(-1) , m_burstLeft(0) , m_speed_from_movement(0) - , m_particle_count(0) , m_reset_last(true) , m_last_timestamp(-1) , m_last_emission(0) @@ -339,6 +344,7 @@ void QSGParticleEmitter::emitWindow(int timeStamp) m_last_timestamp = timeStamp/1000.; m_last_emission = m_last_timestamp; m_reset_last = false; + m_emitCap = particleCount(); } if (m_burstLeft){ @@ -375,7 +381,7 @@ void QSGParticleEmitter::emitWindow(int timeStamp) qreal emitter_y_offset = m_last_emitter.y() - y(); if (!m_burstQueue.isEmpty() && !m_burstLeft && !m_emitting)//'outside time' emissions only pt = time; - while (pt < time || !m_burstQueue.isEmpty()) { + while ((pt < time && m_emitCap) || !m_burstQueue.isEmpty()) { //int pos = m_last_particle % m_particle_count; QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle], !m_overwrite); if (datum){//actually emit(otherwise we've been asked to skip this one) @@ -393,11 +399,16 @@ void QSGParticleEmitter::emitWindow(int timeStamp) // Particle timestamp datum->t = pt; - datum->lifeSpan = //TODO:Promote to base class? + datum->lifeSpan = (m_particleDuration + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) / 1000.0; + if (datum->lifeSpan >= m_system->maxLife){ + datum->lifeSpan = m_system->maxLife; + m_emitCap--;//emitCap keeps us from reemitting 'infinite' particles after their life. Unless you reset the emitter. + } + // Particle position QRectF boundsRect; if (!m_burstQueue.isEmpty()){ diff --git a/src/declarative/particles/qsgparticleemitter_p.h b/src/declarative/particles/qsgparticleemitter_p.h index cd14fa5..9e1fc7a 100644 --- a/src/declarative/particles/qsgparticleemitter_p.h +++ b/src/declarative/particles/qsgparticleemitter_p.h @@ -80,11 +80,16 @@ class QSGParticleEmitter : public QSGItem Q_PROPERTY(QSGStochasticDirection *acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged) Q_PROPERTY(qreal speedFromMovement READ speedFromMovement WRITE setSpeedFromMovement NOTIFY speedFromMovementChanged) + Q_ENUMS(Lifetime) public: explicit QSGParticleEmitter(QSGItem *parent = 0); virtual ~QSGParticleEmitter(); virtual void emitWindow(int timeStamp); + enum Lifetime { + InfiniteLife = QSGParticleSystem::maxLife + }; + bool emitting() const { return m_emitting; @@ -264,10 +269,10 @@ public slots: } } + virtual void reset(); public: int particleCount() const; - virtual void reset(); QSGParticleExtruder* extruder() const { return m_extruder; @@ -340,7 +345,7 @@ protected: //Used in default implementation, but might be useful qreal m_speed_from_movement; - int m_particle_count; + int m_emitCap; bool m_reset_last; qreal m_last_timestamp; qreal m_last_emission; diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index 0888e7b..534b1ca 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -147,9 +147,13 @@ void QSGParticleDataHeap::grow() //###Consider automatic growth vs resize() call m_data.resize(1 << ++m_size); } -void QSGParticleDataHeap::insert(QSGParticleData* data)//TODO: Optimize 0 lifespan (or already dead) case +void QSGParticleDataHeap::insert(QSGParticleData* data) { - int time = roundedTime(data->t + data->lifeSpan); + insertTimed(data, roundedTime(data->t + data->lifeSpan)); +} + +void QSGParticleDataHeap::insertTimed(QSGParticleData* data, int time){ + //TODO: Optimize 0 lifespan (or already dead) case if (m_lookups.contains(time)){ m_data[m_lookups[time]].data << data; return; @@ -330,7 +334,13 @@ bool QSGParticleGroupData::recycle() } void QSGParticleGroupData::prepareRecycler(QSGParticleData* d){ - dataHeap.insert(d); + if (d->lifeSpan*1000 < m_system->maxLife){ + dataHeap.insert(d); + } else { + while ((roundedTime(d->t) + 2*m_system->maxLife/3) <= m_system->m_timeInt) + d->extendLife(m_system->maxLife/3000.0); + dataHeap.insertTimed(d, roundedTime(d->t) + 2*m_system->maxLife/3); + } } QSGParticleData::QSGParticleData(QSGParticleSystem* sys) @@ -529,6 +539,28 @@ float QSGParticleData::lifeLeft() return (t + lifeSpan) - (system->m_timeInt/1000.0); } +void QSGParticleData::extendLife(float time) +{ + qreal newX = curX(); + qreal newY = curY(); + qreal newVX = curVX(); + qreal newVY = curVY(); + + t += time; + animT += time; + + qreal elapsed = (system->m_timeInt / 1000.0) - t; + qreal evy = newVY - elapsed*ay; + qreal ey = newY - elapsed*evy - 0.5 * elapsed*elapsed*ay; + qreal evx = newVX - elapsed*ax; + qreal ex = newX - elapsed*evx - 0.5 * elapsed*elapsed*ax; + + x = ex; + vx = evx; + y = ey; + vy = evy; +} + QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : QSGItem(parent), m_particle_count(0), m_running(true) , m_startTime(0), m_nextIndex(0), m_componentComplete(false), m_spriteEngine(0) diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h index 5df6afb..17b67d9 100644 --- a/src/declarative/particles/qsgparticlesystem_p.h +++ b/src/declarative/particles/qsgparticlesystem_p.h @@ -80,6 +80,7 @@ class QSGParticleDataHeap { public: QSGParticleDataHeap(); void insert(QSGParticleData* data); + void insertTimed(QSGParticleData* data, int time); int top(); @@ -211,6 +212,7 @@ public: float curSize(); void clone(const QSGParticleData& other);//Not =, leaves meta-data like index QDeclarativeV8Handle v8Value(); + void extendLife(float time); private: QSGV8ParticleData* v8Datum; }; @@ -242,6 +244,8 @@ public: int count(){ return m_particle_count; } + static const int maxLife = 600000; + signals: void systemInitialized(); -- 2.7.4