aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2011-10-20 16:58:06 +1000
committerQt by Nokia <qt-info@nokia.com>2011-10-24 12:36:29 +0200
commit34cefb69b3f36d7eed9f50a2190459fbae0681de (patch)
tree11c3727eb27f8bb02df1f63d779ad4ede6ee1a7c
parent89fb0fb65d0071e88f24b8022eb7070956a7a1a7 (diff)
Affectors now simulate with a minimum granularity
Since all time is sourced from the ParticleSystem, the easiest way is to alter the common time point while doing the multiple simulation runs. Also removes the experimental TargetAffector. Change-Id: Ieb52f8990445fe95f94070175a0f9beb6686324a Reviewed-by: Martin Jones <martin.jones@nokia.com>
-rw-r--r--examples/declarative/particles/affectors/attractor.qml48
-rw-r--r--src/declarative/particles/particles.pri2
-rw-r--r--src/declarative/particles/qsgcustomaffector.cpp19
-rw-r--r--src/declarative/particles/qsggroupgoal.cpp1
-rw-r--r--src/declarative/particles/qsgparticleaffector.cpp45
-rw-r--r--src/declarative/particles/qsgparticleaffector_p.h3
-rw-r--r--src/declarative/particles/qsgparticlesmodule.cpp2
-rw-r--r--src/declarative/particles/qsgspritegoal.cpp1
-rw-r--r--src/declarative/particles/qsgtargetaffector.cpp92
-rw-r--r--src/declarative/particles/qsgtargetaffector_p.h168
10 files changed, 86 insertions, 295 deletions
diff --git a/examples/declarative/particles/affectors/attractor.qml b/examples/declarative/particles/affectors/attractor.qml
index d6660d6a0d..c5bc4fdd5f 100644
--- a/examples/declarative/particles/affectors/attractor.qml
+++ b/examples/declarative/particles/affectors/attractor.qml
@@ -178,29 +178,31 @@ Rectangle {
drag.axis: Drag.XandYAxis
drag.target: ship
}
- Emitter {
- group: "engine"
- system: particles
- emitRate: 200
- lifeSpan: 1000
- size: 10
- endSize: 4
- sizeVariation: 4
- speed: PointDirection { x: -128; xVariation: 32 }
- height: parent.height
- width: 20
- }
- Emitter {
- group: "shot"
- system: particles
- emitRate: 32
- lifeSpan: 2000
- enabled: spacePressed
- size: 40
- speed: PointDirection { x: 256; }
- x: parent.width
- y: parent.height/2
- }
+ }
+ Emitter {
+ group: "engine"
+ system: particles
+ emitRate: 200
+ lifeSpan: 1000
+ size: 10
+ endSize: 4
+ sizeVariation: 4
+ speed: PointDirection { x: -128; xVariation: 32 }
+ height: ship.height
+ y: ship.y
+ x: ship.x
+ width: 20
+ }
+ Emitter {
+ group: "shot"
+ system: particles
+ emitRate: 32
+ lifeSpan: 2000
+ enabled: spacePressed
+ size: 40
+ speed: PointDirection { x: 256; }
+ x: ship.x + ship.width
+ y: ship.y + ship.height/2
}
Text {
diff --git a/src/declarative/particles/particles.pri b/src/declarative/particles/particles.pri
index a3a8c90d85..4663c17981 100644
--- a/src/declarative/particles/particles.pri
+++ b/src/declarative/particles/particles.pri
@@ -24,7 +24,6 @@ HEADERS += \
$$PWD/qsgtargetdirection_p.h \
$$PWD/qsgturbulence_p.h \
$$PWD/qsgwander_p.h \
- $$PWD/qsgtargetaffector_p.h \
$$PWD/qsgcumulativedirection_p.h \
$$PWD/qsgv8particledata_p.h \
$$PWD/qsgrectangleextruder_p.h \
@@ -58,7 +57,6 @@ SOURCES += \
$$PWD/qsgtargetdirection.cpp \
$$PWD/qsgturbulence.cpp \
$$PWD/qsgwander.cpp \
- $$PWD/qsgtargetaffector.cpp \
$$PWD/qsgcumulativedirection.cpp \
$$PWD/qsgv8particledata.cpp \
$$PWD/qsgrectangleextruder.cpp \
diff --git a/src/declarative/particles/qsgcustomaffector.cpp b/src/declarative/particles/qsgcustomaffector.cpp
index ffa86aae97..28b220d45c 100644
--- a/src/declarative/particles/qsgcustomaffector.cpp
+++ b/src/declarative/particles/qsgcustomaffector.cpp
@@ -87,13 +87,30 @@ void QSGCustomAffector::affectSystem(qreal dt)
if (shouldAffect(d))
toAffect << d;
+ if (toAffect.isEmpty())
+ return;
+
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);
+ if (dt >= simulationCutoff || dt <= simulationDelta) {
+ emit affectParticles(QDeclarativeV8Handle::fromHandle(array), dt);
+ } else {
+ int realTime = m_system->timeInt;
+ m_system->timeInt -= dt * 1000.0;
+ while (dt > simulationDelta) {
+ m_system->timeInt += simulationDelta * 1000.0;
+ dt -= simulationDelta;
+ emit affectParticles(QDeclarativeV8Handle::fromHandle(array), simulationDelta);
+ }
+ m_system->timeInt = realTime;
+ if (dt > 0.0) {
+ emit affectParticles(QDeclarativeV8Handle::fromHandle(array), dt);
+ }
+ }
foreach (QSGParticleData* d, toAffect)
if (d->update == 1.0)
diff --git a/src/declarative/particles/qsggroupgoal.cpp b/src/declarative/particles/qsggroupgoal.cpp
index 78fa7866bc..b83c61fd85 100644
--- a/src/declarative/particles/qsggroupgoal.cpp
+++ b/src/declarative/particles/qsggroupgoal.cpp
@@ -77,6 +77,7 @@ QT_BEGIN_NAMESPACE
QSGGroupGoalAffector::QSGGroupGoalAffector(QQuickItem *parent) :
QSGParticleAffector(parent), m_jump(false)
{
+ m_ignoresTime = true;
}
void QSGGroupGoalAffector::setGoalState(QString arg)
diff --git a/src/declarative/particles/qsgparticleaffector.cpp b/src/declarative/particles/qsgparticleaffector.cpp
index 2758e93a5f..e31f8ff89c 100644
--- a/src/declarative/particles/qsgparticleaffector.cpp
+++ b/src/declarative/particles/qsgparticleaffector.cpp
@@ -52,6 +52,16 @@ QT_BEGIN_NAMESPACE
when a particle meets certain conditions.
If an affector has a defined size, then it will only affect particles within its size and position on screen.
+
+ Affectors have different performance characteristics to the other particle system elements. In particular,
+ they have some simplifications to try to maintain a simulation at real-time or faster. When running a system
+ with Affectors, irregular frame timings that grow too large ( > one second per frame) will cause the Affectors
+ to try and cut corners with a faster but less accurate simulation. If the system has multiple affectors the order
+ in which they are applied is not guaranteed, and when simulating larger time shifts they will simulate the whole
+ shift each, which can lead to different results compared to smaller time shifts.
+
+ Accurate simulation for large numbers of particles (hundreds) with multiple affectors may be possible on some hardware,
+ but on less capable hardware you should expect small irregularties in the simulation as simulates with worse granularity.
*/
/*!
\qmlproperty ParticleSystem QtQuick.Particles2::Affector::system
@@ -127,7 +137,7 @@ QT_BEGIN_NAMESPACE
x,y is the particles current position.
*/
QSGParticleAffector::QSGParticleAffector(QQuickItem *parent) :
- QQuickItem(parent), m_needsReset(false), m_system(0), m_enabled(true)
+ QQuickItem(parent), m_needsReset(false), m_ignoresTime(false), m_system(0), m_enabled(true)
, m_updateIntSet(false), m_shape(new QSGParticleExtruder(this))
{
}
@@ -185,19 +195,40 @@ void QSGParticleAffector::postAffect(QSGParticleData* d)
emit affected(d->curX(), d->curY());
}
+const qreal QSGParticleAffector::simulationDelta = 0.020;
+const qreal QSGParticleAffector::simulationCutoff = 1.000;
+
void QSGParticleAffector::affectSystem(qreal dt)
{
if (!m_enabled)
return;
- //If not reimplemented, calls affect particle per particle
+ //If not reimplemented, calls affectParticle per particle
//But only on particles in targeted system/area
updateOffsets();//### Needed if an ancestor is transformed.
- foreach (QSGParticleGroupData* gd, m_system->groupData)
- if (activeGroup(m_system->groupData.key(gd)))
- foreach (QSGParticleData* d, gd->data)
- if (shouldAffect(d))
- if (affectParticle(d, dt))
+ foreach (QSGParticleGroupData* gd, m_system->groupData) {
+ if (activeGroup(m_system->groupData.key(gd))) {
+ foreach (QSGParticleData* d, gd->data) {
+ if (shouldAffect(d)) {
+ bool affected = false;
+ qreal myDt = dt;
+ if (!m_ignoresTime && myDt < simulationCutoff) {
+ int realTime = m_system->timeInt;
+ m_system->timeInt -= myDt * 1000.0;
+ while (myDt > simulationDelta) {
+ m_system->timeInt += simulationDelta * 1000.0;
+ affected = affectParticle(d, simulationDelta) || affected;
+ myDt -= simulationDelta;
+ }
+ m_system->timeInt = realTime;
+ }
+ if (myDt > 0.0)
+ affected = affectParticle(d, myDt) || affected;
+ if (affected)
postAffect(d);
+ }
+ }
+ }
+ }
}
bool QSGParticleAffector::affectParticle(QSGParticleData *, qreal )
diff --git a/src/declarative/particles/qsgparticleaffector_p.h b/src/declarative/particles/qsgparticleaffector_p.h
index bc6864e415..10c1cf095a 100644
--- a/src/declarative/particles/qsgparticleaffector_p.h
+++ b/src/declarative/particles/qsgparticleaffector_p.h
@@ -170,6 +170,7 @@ protected:
friend class QSGParticleSystem;
virtual bool affectParticle(QSGParticleData *d, qreal dt);
bool m_needsReset;//### What is this really saving?
+ bool m_ignoresTime;
QSGParticleSystem* m_system;
QStringList m_groups;
bool activeGroup(int g);
@@ -179,6 +180,8 @@ protected:
virtual void componentComplete();
QPointF m_offset;
bool isAffectedConnected();
+ static const qreal simulationDelta;
+ static const qreal simulationCutoff;
private:
QSet<int> m_groupIds;
QSet<QPair<int, int> > m_onceOffed;
diff --git a/src/declarative/particles/qsgparticlesmodule.cpp b/src/declarative/particles/qsgparticlesmodule.cpp
index 9e73b82527..6e170b1e1c 100644
--- a/src/declarative/particles/qsgparticlesmodule.cpp
+++ b/src/declarative/particles/qsgparticlesmodule.cpp
@@ -63,7 +63,6 @@
#include "qsgtargetdirection_p.h"
#include "qsgturbulence_p.h"
#include "qsgwander_p.h"
-#include "qsgtargetaffector_p.h"
#include "qsgcumulativedirection_p.h"
#include "qsgcustomaffector_p.h"
#include "qsgrectangleextruder_p.h"
@@ -106,7 +105,6 @@ void QSGParticlesModule::defineModule()
qmlRegisterType<QSGSpriteGoalAffector>(uri, 2, 0, "SpriteGoal");
qmlRegisterType<QSGGroupGoalAffector>(uri, 2, 0, "GroupGoal");
qmlRegisterType<QSGTurbulenceAffector>(uri, 2, 0 , "Turbulence");
- qmlRegisterType<QSGTargetAffector>(uri, 2, 0 , "Target");
qmlRegisterType<QSGMoveAffector>(uri, 2, 0, "Move");
//Exposed just for completeness
diff --git a/src/declarative/particles/qsgspritegoal.cpp b/src/declarative/particles/qsgspritegoal.cpp
index 4765eb2331..6d4c0a309c 100644
--- a/src/declarative/particles/qsgspritegoal.cpp
+++ b/src/declarative/particles/qsgspritegoal.cpp
@@ -87,6 +87,7 @@ QSGSpriteGoalAffector::QSGSpriteGoalAffector(QQuickItem *parent) :
m_systemStates(false),
m_notUsingEngine(false)
{
+ m_ignoresTime = true;
}
void QSGSpriteGoalAffector::updateStateIndex(QQuickStochasticEngine* e)
diff --git a/src/declarative/particles/qsgtargetaffector.cpp b/src/declarative/particles/qsgtargetaffector.cpp
deleted file mode 100644
index 86f325075e..0000000000
--- a/src/declarative/particles/qsgtargetaffector.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Declarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsgtargetaffector_p.h"
-#include <QDebug>
-
-QSGTargetAffector::QSGTargetAffector(QQuickItem *parent) :
- QSGParticleAffector(parent), m_targetX(0), m_targetY(0),
- m_targetWidth(0), m_targetHeight(0), m_defaultShape(new QSGParticleExtruder(this)),
- m_targetShape(m_defaultShape), m_targetTime(-1)
-{
- m_needsReset = true;
-}
-
-void QSGTargetAffector::reset(QSGParticleData* d)
-{
- QSGParticleAffector::reset(d);
- m_targets[qMakePair<int,int>(d->group, d->index)] = m_targetShape->extrude(QRectF(m_targetX, m_targetY, m_targetWidth, m_targetHeight));
-}
-
-bool QSGTargetAffector::affectParticle(QSGParticleData *d, qreal dt)
-{
- Q_UNUSED(dt);
- QPointF target = m_targets[qMakePair<int,int>(d->group, d->index)];
- if (target.isNull())
- return false;
- qreal tt = m_targetTime==-1?d->lifeSpan:(m_targetTime / 1000.0);
- qreal t = tt - (d->lifeSpan - d->lifeLeft());
- if (t <= 0)
- return false;
- qreal tx = d->x + d->vx * tt + 0.5 * d->ax * tt * tt;
- qreal ty = d->y + d->vy * tt + 0.5 * d->ay * tt * tt;
-
- if (QPointF(tx,ty) == target)
- return false;
-
- qreal vX = (target.x() - d->x) / tt;
- qreal vY = (target.y() - d->y) / tt;
-
- qreal w = 1 - (t / tt) + 0.05;
- w = qMin<qreal>(w, 1.0);
- qreal wvX = vX * w + d->vx * (1 - w);
- qreal wvY = vY * w + d->vy * (1 - w);
- //Screws with the acceleration so that the given start pos with the chosen weighted velocity will still end at the target coordinates
- qreal ax = (2*(target.x() - d->x - wvX*tt)) / (tt*tt);
- qreal ay = (2*(target.y() - d->y - wvY*tt)) / (tt*tt);
-
- d->vx = wvX;
- d->vy = wvY;
- d->ax = ax;
- d->ay = ay;
-
- return true;
-}
diff --git a/src/declarative/particles/qsgtargetaffector_p.h b/src/declarative/particles/qsgtargetaffector_p.h
deleted file mode 100644
index 264ba30504..0000000000
--- a/src/declarative/particles/qsgtargetaffector_p.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Declarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSGTARGETAFFECTOR_H
-#define QSGTARGETAFFECTOR_H
-
-#include "qsgparticleaffector_p.h"
-
-class QSGTargetAffector : public QSGParticleAffector
-{
- Q_OBJECT
- Q_PROPERTY(int targetX READ targetX WRITE setTargetX NOTIFY targetXChanged)
- Q_PROPERTY(int targetY READ targetY WRITE setTargetY NOTIFY targetYChanged)
- Q_PROPERTY(int targetWidth READ targetWidth WRITE setTargetWidth NOTIFY targetWidthChanged)
- Q_PROPERTY(int targetHeight READ targetHeight WRITE setTargetHeight NOTIFY targetHeightChanged)
- Q_PROPERTY(QSGParticleExtruder* targetShape READ targetShape WRITE setTargetShape NOTIFY targetShapeChanged)
- Q_PROPERTY(int targetTime READ targetTime WRITE setTargetTime NOTIFY targetTimeChanged)
-
-public:
- explicit QSGTargetAffector(QQuickItem *parent = 0);
-
- int targetX() const
- {
- return m_targetX;
- }
-
- int targetY() const
- {
- return m_targetY;
- }
-
- int targetWidth() const
- {
- return m_targetWidth;
- }
-
- int targetHeight() const
- {
- return m_targetHeight;
- }
-
- QSGParticleExtruder* targetShape() const
- {
- return m_targetShape;
- }
-
- int targetTime() const
- {
- return m_targetTime;
- }
-
-signals:
-
- void targetXChanged(int arg);
-
- void targetYChanged(int arg);
-
- void targetWidthChanged(int arg);
-
- void targetHeightChanged(int arg);
-
- void targetShapeChanged(QSGParticleExtruder* arg);
-
- void targetTimeChanged(int arg);
-
-public slots:
- void setTargetX(int arg)
- {
- if (m_targetX != arg) {
- m_targetX = arg;
- emit targetXChanged(arg);
- }
- }
-
- void setTargetY(int arg)
- {
- if (m_targetY != arg) {
- m_targetY = arg;
- emit targetYChanged(arg);
- }
- }
-
- void setTargetWidth(int arg)
- {
- if (m_targetWidth != arg) {
- m_targetWidth = arg;
- emit targetWidthChanged(arg);
- }
- }
-
- void setTargetHeight(int arg)
- {
- if (m_targetHeight != arg) {
- m_targetHeight = arg;
- emit targetHeightChanged(arg);
- }
- }
-
- void setTargetShape(QSGParticleExtruder* arg)
- {
- if (m_targetShape != arg) {
- m_targetShape = arg;
- emit targetShapeChanged(arg);
- }
- }
-
- void setTargetTime(int arg)
- {
- if (m_targetTime != arg) {
- m_targetTime = arg;
- emit targetTimeChanged(arg);
- }
- }
-
-protected:
- virtual void reset(QSGParticleData*);
- virtual bool affectParticle(QSGParticleData *d, qreal dt);
-private:
- int m_targetX;
- int m_targetY;
- int m_targetWidth;
- int m_targetHeight;
- QSGParticleExtruder* m_defaultShape;
- QSGParticleExtruder* m_targetShape;
- int m_targetTime;
-
- QHash<QPair<int, int>, QPointF> m_targets;
-};
-
-#endif // QSGTARGETAFFECTOR_H