From ef98f5a80369e3f014585edc3dd63a2ec331d1ea Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 20 Sep 2011 15:28:14 +1000 Subject: [PATCH] CustomEmitter/Affector now affect whole lists at once Better performance potential (fewer drops to JS, possibility of more optimzed JS). Change-Id: If386f06ac8714162a5bfc6b5eef7f2e67f9dae95 Reviewed-on: http://codereview.qt-project.org/5189 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- .../particles/affectors/customaffector.qml | 48 +++++++++++--------- .../particles/emitters/customemitter.qml | 21 +++++---- src/declarative/particles/qsgcustomaffector.cpp | 43 +++++++++++++---- src/declarative/particles/qsgcustomaffector_p.h | 4 +- src/declarative/particles/qsgparticleaffector_p.h | 4 +- src/declarative/particles/qsgparticleemitter.cpp | 31 +++++++++--- src/declarative/particles/qsgparticleemitter_p.h | 2 +- src/declarative/particles/qsgtrailemitter.cpp | 35 ++++++++++---- src/declarative/particles/qsgtrailemitter_p.h | 2 +- 9 files changed, 126 insertions(+), 64 deletions(-) diff --git a/examples/declarative/particles/affectors/customaffector.qml b/examples/declarative/particles/affectors/customaffector.qml index 35708b7..e9aea62 100644 --- a/examples/declarative/particles/affectors/customaffector.qml +++ b/examples/declarative/particles/affectors/customaffector.qml @@ -71,7 +71,7 @@ Item { property real speed: 1.5 width: parent.width height: parent.height - 100 - onAffectParticle:{ + onAffectParticles:{ /* //Linear movement if (particle.r == 0){ particle.r = Math.random() > 0.5 ? -1 : 1; @@ -86,14 +86,17 @@ Item { } */ //Wobbly movement - if (particle.r == 0.0){ - particle.r = Math.random() + 0.01; + for (var i=0; i +#include +#include #include QT_BEGIN_NAMESPACE //TODO: Move docs (and inherit) to real base when docs can propagate -//TODO: Document particle 'type' /*! - \qmlsignal QtQuick.Particles2::Affector::affectParticle(particle, dt) + \qmlsignal QtQuick.Particles2::Affector::affectParticles(Array particles, real dt) - This handler is called when particles are selected to be affected. + This handler is called when particles are selected to be affected. particles contains + an array of particle objects which can be directly manipulated. dt is the time since the last time it was affected. Use dt to normalize trajectory manipulations to real time. @@ -63,18 +66,38 @@ QSGCustomAffector::QSGCustomAffector(QSGItem *parent) : bool QSGCustomAffector::isAffectConnected() { - static int idx = QObjectPrivate::get(this)->signalIndex("affectParticle(QDeclarativeV8Handle,qreal)"); + static int idx = QObjectPrivate::get(this)->signalIndex("affectParticles(QDeclarativeV8Handle,qreal)"); return QObjectPrivate::get(this)->isSignalConnected(idx); } -bool QSGCustomAffector::affectParticle(QSGParticleData *d, qreal dt) +void QSGCustomAffector::affectSystem(qreal dt) { - if (isAffectConnected()){ - d->update = 0.0; - emit affectParticle(d->v8Value(), dt); - return d->update == 1.0; + if (!isAffectConnected()) { + QSGParticleAffector::affectSystem(dt); + return; } - return true; + if (!m_enabled) + return; + updateOffsets(); + + QList toAffect; + foreach (QSGParticleGroupData* gd, m_system->m_groupData) + if (activeGroup(m_system->m_groupData.key(gd))) + foreach (QSGParticleData* d, gd->data) + if (shouldAffect(d)) + toAffect << d; + + v8::HandleScope handle_scope; + v8::Context::Scope scope(QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this))->context()); + v8::Handle array = v8::Array::New(toAffect.size()); + for (int i=0; iSet(i, toAffect[i]->v8Value().toHandle()); + + emit affectParticles(QDeclarativeV8Handle::fromHandle(array), dt); + + foreach (QSGParticleData* d, toAffect) + if (d->update == 1.0) + postAffect(d); } QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgcustomaffector_p.h b/src/declarative/particles/qsgcustomaffector_p.h index 7f39200..fc0735e 100644 --- a/src/declarative/particles/qsgcustomaffector_p.h +++ b/src/declarative/particles/qsgcustomaffector_p.h @@ -59,13 +59,13 @@ class QSGCustomAffector : public QSGParticleAffector public: explicit QSGCustomAffector(QSGItem *parent = 0); + virtual void affectSystem(qreal dt); signals: - void affectParticle(QDeclarativeV8Handle particle, qreal dt); + void affectParticles(QDeclarativeV8Handle particles, qreal dt); public slots: protected: bool isAffectConnected(); - virtual bool affectParticle(QSGParticleData *d, qreal dt); private: }; diff --git a/src/declarative/particles/qsgparticleaffector_p.h b/src/declarative/particles/qsgparticleaffector_p.h index c67912f..c46164d 100644 --- a/src/declarative/particles/qsgparticleaffector_p.h +++ b/src/declarative/particles/qsgparticleaffector_p.h @@ -163,6 +163,8 @@ void setWhenCollidingWith(QStringList arg) emit whenCollidingWithChanged(arg); } } +public slots: + void updateOffsets(); protected: friend class QSGParticleSystem; @@ -189,8 +191,6 @@ private: QStringList m_whenCollidingWith; bool isColliding(QSGParticleData* d); -private slots: - void updateOffsets(); }; QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgparticleemitter.cpp b/src/declarative/particles/qsgparticleemitter.cpp index f10bf1e..e1a7ef2 100644 --- a/src/declarative/particles/qsgparticleemitter.cpp +++ b/src/declarative/particles/qsgparticleemitter.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qsgparticleemitter_p.h" +#include QT_BEGIN_NAMESPACE @@ -183,12 +184,12 @@ QT_BEGIN_NAMESPACE Default value is 0. */ -//TODO: Document particle 'type' + /*! - \qmlsignal QtQuick.Particles2::Emitter::onEmitParticle(Particle particle) + \qmlsignal QtQuick.Particles2::Emitter::onEmitParticles(Array particles) - This handler is called when a particle is emitted. You can modify particle - attributes from within the handler. + This handler is called when particles are emitted. particles is a javascript + array of Particle objects. You can modify particle attributes directly within the handler. Note that JS is slower to execute, so it is not recommended to use this in high-volume particle systems. @@ -252,7 +253,7 @@ QSGParticleEmitter::~QSGParticleEmitter() bool QSGParticleEmitter::isEmitConnected() { - static int idx = QObjectPrivate::get(this)->signalIndex("emitParticle(QDeclarativeV8Handle)"); + static int idx = QObjectPrivate::get(this)->signalIndex("emitParticles(QDeclarativeV8Handle)"); return QObjectPrivate::get(this)->isSignalConnected(idx); } @@ -396,6 +397,9 @@ void QSGParticleEmitter::emitWindow(int timeStamp) qreal emitter_y_offset = m_last_emitter.y() - y(); if (!m_burstQueue.isEmpty() && !m_burstLeft && !m_enabled)//'outside time' emissions only pt = time; + + QList toEmit; + 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_group], !m_overwrite); @@ -459,9 +463,7 @@ void QSGParticleEmitter::emitWindow(int timeStamp) datum->size = size;// * float(m_emitting); datum->endSize = endSize;// * float(m_emitting); - if (isEmitConnected()) - emitParticle(datum->v8Value());//A chance for arbitrary JS changes - m_system->emitParticle(datum); + toEmit << datum; } if (m_burstQueue.isEmpty()){ pt += particleRatio; @@ -471,6 +473,19 @@ void QSGParticleEmitter::emitWindow(int timeStamp) m_burstQueue.pop_front(); } } + + if (isEmitConnected()) { + v8::HandleScope handle_scope; + v8::Context::Scope scope(QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this))->context()); + v8::Handle array = v8::Array::New(toEmit.size()); + for (int i=0; iSet(i, toEmit[i]->v8Value().toHandle()); + + emitParticles(QDeclarativeV8Handle::fromHandle(array));//A chance for arbitrary JS changes + } + foreach (QSGParticleData* d, toEmit) + m_system->emitParticle(d); + m_last_emission = pt; m_last_last_last_emitter = m_last_last_emitter; diff --git a/src/declarative/particles/qsgparticleemitter_p.h b/src/declarative/particles/qsgparticleemitter_p.h index 8bd205b..11c79ec 100644 --- a/src/declarative/particles/qsgparticleemitter_p.h +++ b/src/declarative/particles/qsgparticleemitter_p.h @@ -123,7 +123,7 @@ public: void setSpeedFromMovement(qreal s); virtual void componentComplete(); signals: - void emitParticle(QDeclarativeV8Handle particle); + void emitParticles(QDeclarativeV8Handle particles); void particlesPerSecondChanged(qreal); void particleDurationChanged(int); void enabledChanged(bool); diff --git a/src/declarative/particles/qsgtrailemitter.cpp b/src/declarative/particles/qsgtrailemitter.cpp index 5a19ac5..e819663 100644 --- a/src/declarative/particles/qsgtrailemitter.cpp +++ b/src/declarative/particles/qsgtrailemitter.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qsgtrailemitter_p.h" +#include #include QT_BEGIN_NAMESPACE @@ -102,18 +103,17 @@ QSGTrailEmitter::QSGTrailEmitter(QSGItem *parent) : \qmlproperty real QtQuick.Particles2::TrailEmitter::emitRatePerParticle */ /*! - \qmlsignal QtQuick.Particles2::TrailEmitter::emitFollowParticle(particle, followed) + \qmlsignal QtQuick.Particles2::TrailEmitter::emitFollowParticles(Array particles, real followed) - This handler is called when a particle is emitted. You can modify particle - attributes from within the handler. followed is the particle that this is being - emitted off of. + This handler is called when particles are emitted from the \a followed particle. \a particles contains an array of particle objects which can be directly manipulated. + + If you use this signal handler, emitParticles will not be emitted. - If you use this signal handler, emitParticle will not be emitted. */ bool QSGTrailEmitter::isEmitFollowConnected() { - static int idx = QObjectPrivate::get(this)->signalIndex("emitFollowParticle(QDeclarativeV8Handle,QDeclarativeV8Handle)"); + static int idx = QObjectPrivate::get(this)->signalIndex("emitFollowParticles(QDeclarativeV8Handle,QDeclarativeV8Handle)"); return QObjectPrivate::get(this)->isSignalConnected(idx); } @@ -180,6 +180,9 @@ void QSGTrailEmitter::emitWindow(int timeStamp) m_lastEmission[d->index] = time;//jump over this time period without emitting, because it's outside continue; } + + QList toEmit; + while (pt < time || !m_burstQueue.isEmpty()){ QSGParticleData* datum = m_system->newDatum(gId2, !m_overwrite); if (datum){//else, skip this emission @@ -235,10 +238,7 @@ void QSGTrailEmitter::emitWindow(int timeStamp) datum->size = size * float(m_enabled); datum->endSize = endSize * float(m_enabled); - if (isEmitFollowConnected()) - emitFollowParticle(datum->v8Value(), d->v8Value());//A chance for many arbitrary JS changes - else if (isEmitConnected()) - emitParticle(datum->v8Value());//A chance for arbitrary JS changes + toEmit << datum; m_system->emitParticle(datum); } @@ -250,6 +250,21 @@ void QSGTrailEmitter::emitWindow(int timeStamp) pt += particleRatio; } } + + if (isEmitConnected() || isEmitFollowConnected()) { + v8::HandleScope handle_scope; + v8::Context::Scope scope(QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this))->context()); + v8::Handle array = v8::Array::New(toEmit.size()); + for (int i=0; iSet(i, toEmit[i]->v8Value().toHandle()); + + if (isEmitFollowConnected()) + emitFollowParticles(QDeclarativeV8Handle::fromHandle(array), d->v8Value());//A chance for many arbitrary JS changes + else if (isEmitConnected()) + emitParticles(QDeclarativeV8Handle::fromHandle(array));//A chance for arbitrary JS changes + } + foreach (QSGParticleData* d, toEmit) + m_system->emitParticle(d); m_lastEmission[d->index] = pt; } diff --git a/src/declarative/particles/qsgtrailemitter_p.h b/src/declarative/particles/qsgtrailemitter_p.h index 009ccd5..e0103af 100644 --- a/src/declarative/particles/qsgtrailemitter_p.h +++ b/src/declarative/particles/qsgtrailemitter_p.h @@ -94,7 +94,7 @@ public: } signals: - void emitFollowParticle(QDeclarativeV8Handle group, QDeclarativeV8Handle followed); + void emitFollowParticles(QDeclarativeV8Handle particles, QDeclarativeV8Handle followed); void particlesPerParticlePerSecondChanged(int arg); -- 1.7.2.5