From: Alan Alpert Date: Thu, 20 Oct 2011 06:58:06 +0000 (+1000) Subject: Affectors now simulate with a minimum granularity X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=34cefb69b3f36d7eed9f50a2190459fbae0681de;p=konrad%2Fqtdeclarative.git 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 --- diff --git a/examples/declarative/particles/affectors/attractor.qml b/examples/declarative/particles/affectors/attractor.qml index d6660d6..c5bc4fd 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 a3a8c90..4663c17 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 ffa86aa..28b220d 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 array = v8::Array::New(toAffect.size()); for (int i=0; iSet(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 78fa786..b83c61f 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 2758e93..e31f8ff 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 bc6864e..10c1cf0 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 m_groupIds; QSet > m_onceOffed; diff --git a/src/declarative/particles/qsgparticlesmodule.cpp b/src/declarative/particles/qsgparticlesmodule.cpp index 9e73b82..6e170b1 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(uri, 2, 0, "SpriteGoal"); qmlRegisterType(uri, 2, 0, "GroupGoal"); qmlRegisterType(uri, 2, 0 , "Turbulence"); - qmlRegisterType(uri, 2, 0 , "Target"); qmlRegisterType(uri, 2, 0, "Move"); //Exposed just for completeness diff --git a/src/declarative/particles/qsgspritegoal.cpp b/src/declarative/particles/qsgspritegoal.cpp index 4765eb2..6d4c0a3 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 86f3250..0000000 --- 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 - -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(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(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(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 264ba30..0000000 --- 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, QPointF> m_targets; -}; - -#endif // QSGTARGETAFFECTOR_H