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 <qt_sanity_bot@ovi.com>
Reviewed-by: Martin Jones <martin.jones@nokia.com>
This commit is contained in:
Alan Alpert 2011-09-20 15:28:14 +10:00 committed by Qt by Nokia
parent 4114b9dcff
commit ef98f5a803
9 changed files with 127 additions and 65 deletions

View File

@ -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<particles.length; i++) {
var particle = particles[i];
if (particle.r == 0.0) {
particle.r = Math.random() + 0.01;
}
particle.rotation += speed * particle.r * dt;
particle.r -= particle.rotation * coefficient;
if (particle.r == 0.0)
particle.r -= particle.rotation * 0.000001;
particle.update = 1;
}
particle.rotation += speed * particle.r * dt;
particle.r -= particle.rotation * coefficient;
if (particle.r == 0.0)
particle.r -= particle.rotation * 0.000001;
particle.update = 1;
}
}
@ -104,19 +107,22 @@ Item {
width: parent.width + 120
height: 100
anchors.bottom: parent.bottom
onAffectParticle:{
var pseudoRand = (Math.floor(particle.t*1327) % 10) + 1;
var yslow = pseudoRand * 0.01 + 1.01;
var xslow = pseudoRand * 0.005 + 1.0;
if (particle.vy < 1)
particle.vy = 0;
else
particle.vy = (particle.vy / yslow);
if (particle.vx < 1)
particle.vx = 0;
else
particle.vx = (particle.vx / xslow);
particle.update = 1;
onAffectParticles:{
for (var i=0; i<particles.length; i++) {
var particle = particles[i];
var pseudoRand = (Math.floor(particle.t*1327) % 10) + 1;
var yslow = dt * pseudoRand * 0.5 + 1;
var xslow = dt * pseudoRand * 0.05 + 1;
if (particle.vy < 1)
particle.vy = 0;
else
particle.vy = (particle.vy / yslow);
if (particle.vx < 1)
particle.vx = 0;
else
particle.vx = (particle.vx / xslow);
particle.update = 1;
}
}
}
ImageParticle{

View File

@ -66,15 +66,18 @@ ParticleSystem{
emitRate: 120
size: 12
anchors.centerIn: parent
onEmitParticle:{
particle.startSize = Math.max(02,Math.min(492,Math.tan(particle.t/2)*24));
var theta = Math.floor(Math.random() * 6.0) / 6.0;
theta *= 2.0*Math.PI;
theta += sys.convert(sys.petalRotation);
particle.initialVX = petalLength * Math.cos(theta);
particle.initialVY = petalLength * Math.sin(theta);
particle.initialAX = particle.initialVX * -0.5;
particle.initialAY = particle.initialVY * -0.5;
onEmitParticles:{
for (var i=0; i<particles.length; i++) {
var particle = particles[i];
particle.startSize = Math.max(02,Math.min(492,Math.tan(particle.t/2)*24));
var theta = Math.floor(Math.random() * 6.0) / 6.0;
theta *= 2.0*Math.PI;
theta += sys.convert(sys.petalRotation);
particle.initialVX = petalLength * Math.cos(theta);
particle.initialVY = petalLength * Math.sin(theta);
particle.initialAX = particle.initialVX * -0.5;
particle.initialAY = particle.initialVY * -0.5;
}
}
}
ImageParticle{

View File

@ -40,15 +40,18 @@
****************************************************************************/
#include "qsgcustomaffector_p.h"
#include <private/qv8engine_p.h>
#include <private/qdeclarativeengine_p.h>
#include <QDeclarativeEngine>
#include <QDebug>
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<QSGParticleData*> 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<v8::Array> array = v8::Array::New(toAffect.size());
for (int i=0; i<toAffect.size(); i++)
array->Set(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

View File

@ -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:
};

View File

@ -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

View File

@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgparticleemitter_p.h"
#include <private/qdeclarativeengine_p.h>
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)
This handler is called when a particle is emitted. You can modify particle
attributes from within the handler.
/*!
\qmlsignal QtQuick.Particles2::Emitter::onEmitParticles(Array particles)
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<QSGParticleData*> 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<v8::Array> array = v8::Array::New(toEmit.size());
for (int i=0; i<toEmit.size(); i++)
array->Set(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;

View File

@ -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);

View File

@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgtrailemitter_p.h"
#include <private/qdeclarativeengine_p.h>
#include <cmath>
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<QSGParticleData*> 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<v8::Array> array = v8::Array::New(toEmit.size());
for (int i=0; i<toEmit.size(); i++)
array->Set(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;
}

View File

@ -94,7 +94,7 @@ public:
}
signals:
void emitFollowParticle(QDeclarativeV8Handle group, QDeclarativeV8Handle followed);
void emitFollowParticles(QDeclarativeV8Handle particles, QDeclarativeV8Handle followed);
void particlesPerParticlePerSecondChanged(int arg);