aboutsummaryrefslogtreecommitdiffstats
path: root/src/particles/qquickparticlesystem_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/particles/qquickparticlesystem_p.h')
-rw-r--r--src/particles/qquickparticlesystem_p.h327
1 files changed, 276 insertions, 51 deletions
diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h
index 96bd655793..b57d55bd98 100644
--- a/src/particles/qquickparticlesystem_p.h
+++ b/src/particles/qquickparticlesystem_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -55,9 +61,35 @@
#include <QAbstractAnimation>
#include <QtQml/qqml.h>
#include <private/qv8engine_p.h> //For QQmlV4Handle
+#include <private/qv4util_p.h>
+#include "qtquickparticlesglobal_p.h"
QT_BEGIN_NAMESPACE
+template<class T, int Prealloc>
+class QQuickParticleVarLengthArray: public QVarLengthArray<T, Prealloc>
+{
+public:
+ void insert(const T &element)
+ {
+ if (!this->contains(element)) {
+ this->append(element);
+ }
+ }
+
+ bool removeOne(const T &element)
+ {
+ for (int i = 0; i < this->size(); ++i) {
+ if (this->at(i) == element) {
+ this->remove(i);
+ return true;
+ }
+ }
+
+ return false;
+ }
+};
+
class QQuickParticleSystem;
class QQuickParticleAffector;
class QQuickParticleEmitter;
@@ -75,7 +107,7 @@ struct QQuickParticleDataHeapNode{
QSet<QQuickParticleData*> data;//Set ptrs instead?
};
-class QQuickParticleDataHeap {
+class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleDataHeap {
//Idea is to do a binary heap, but which also stores a set of int,Node* so that if the int already exists, you can
//add it to the data* list. Pops return the whole list at once.
public:
@@ -102,23 +134,88 @@ private:
QHash<int,int> m_lookups;
};
-class Q_AUTOTEST_EXPORT QQuickParticleGroupData {
+class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleGroupData {
+ class FreeList
+ {
+ public:
+ FreeList()
+ : firstUnused(UINT_MAX)
+ , allocated(0)
+ {}
+
+ void resize(int newSize)
+ {
+ Q_ASSERT(newSize >= 0);
+ int oldSize = isUnused.size();
+ isUnused.resize(newSize, true);
+ if (newSize > oldSize) {
+ if (firstUnused == UINT_MAX) {
+ firstUnused = oldSize;
+ } else {
+ firstUnused = std::min(firstUnused, unsigned(oldSize));
+ }
+ } else if (firstUnused >= unsigned(newSize)) {
+ firstUnused = UINT_MAX;
+ }
+ }
+
+ void free(int index)
+ {
+ isUnused.setBit(index);
+ firstUnused = std::min(firstUnused, unsigned(index));
+ --allocated;
+ }
+
+ int count() const
+ { return allocated; }
+
+ bool hasUnusedEntries() const
+ { return firstUnused != UINT_MAX; }
+
+ int alloc()
+ {
+ if (hasUnusedEntries()) {
+ int nextFree = firstUnused;
+ isUnused.clearBit(firstUnused);
+ firstUnused = isUnused.findNext(firstUnused, true, false);
+ if (firstUnused >= unsigned(isUnused.size())) {
+ firstUnused = UINT_MAX;
+ }
+ ++allocated;
+ return nextFree;
+ } else {
+ return -1;
+ }
+ }
+
+ private:
+ QV4::BitVector isUnused;
+ unsigned firstUnused;
+ int allocated;
+ };
+
+public: // types
+ typedef int ID;
+ enum { InvalidID = -1, DefaultGroupID = 0 };
+
public:
- QQuickParticleGroupData(int id, QQuickParticleSystem* sys);
+ QQuickParticleGroupData(const QString &name, QQuickParticleSystem* sys);
~QQuickParticleGroupData();
- int size();
+ int size()
+ { return m_size; }
+
QString name();
void setSize(int newSize);
- int index;
- QSet<QQuickParticlePainter*> painters;//TODO: What if they are dynamically removed?
+ const ID index;
+ QQuickParticleVarLengthArray<QQuickParticlePainter*, 4> painters;//TODO: What if they are dynamically removed?
//TODO: Refactor particle data list out into a separate class
QVector<QQuickParticleData*> data;
+ FreeList freeList;
QQuickParticleDataHeap dataHeap;
- QSet<int> reusableIndexes;
bool recycle(); //Force recycling round, returns true if all indexes are now reusable
void initList();
@@ -142,10 +239,10 @@ struct Color4ub {
uchar a;
};
-class Q_AUTOTEST_EXPORT QQuickParticleData {
+class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleData {
public:
//TODO: QObject like memory management (without the cost, just attached to system)
- QQuickParticleData(QQuickParticleSystem* sys);
+ QQuickParticleData();
~QQuickParticleData();
QQuickParticleData(const QQuickParticleData &other);
@@ -155,28 +252,28 @@ public:
//If setting multiple parameters at once, doing the conversion yourself will be faster.
//sets the x accleration without affecting the instantaneous x velocity or position
- void setInstantaneousAX(qreal ax);
+ void setInstantaneousAX(float ax, QQuickParticleSystem *particleSystem);
//sets the x velocity without affecting the instantaneous x postion
- void setInstantaneousVX(qreal vx);
+ void setInstantaneousVX(float vx, QQuickParticleSystem *particleSystem);
//sets the instantaneous x postion
- void setInstantaneousX(qreal x);
+ void setInstantaneousX(float x, QQuickParticleSystem *particleSystem);
//sets the y accleration without affecting the instantaneous y velocity or position
- void setInstantaneousAY(qreal ay);
+ void setInstantaneousAY(float ay, QQuickParticleSystem *particleSystem);
//sets the y velocity without affecting the instantaneous y postion
- void setInstantaneousVY(qreal vy);
+ void setInstantaneousVY(float vy, QQuickParticleSystem *particleSystem);
//sets the instantaneous Y postion
- void setInstantaneousY(qreal y);
+ void setInstantaneousY(float y, QQuickParticleSystem *particleSystem);
//TODO: Slight caching?
- qreal curX() const;
- qreal curVX() const;
- qreal curAX() const { return ax; }
- qreal curY() const;
- qreal curVY() const;
- qreal curAY() const { return ay; }
-
- QQuickParticleEmitter* e;//### Needed?
- QQuickParticleSystem* system;
+ float curX(QQuickParticleSystem *particleSystem) const;
+ float curVX(QQuickParticleSystem *particleSystem) const;
+ float curAX() const { return ax; }
+ float curAX(QQuickParticleSystem *) const { return ax; } // used by the macros in qquickv4particledata.cpp
+ float curY(QQuickParticleSystem *particleSystem) const;
+ float curVY(QQuickParticleSystem *particleSystem) const;
+ float curAY() const { return ay; }
+ float curAY(QQuickParticleSystem *) const { return ay; } // used by the macros in qquickv4particledata.cpp
+
int index;
int systemIndex;
@@ -214,7 +311,7 @@ public:
float animWidth;
float animHeight;
- int group;
+ QQuickParticleGroupData::ID groupId;
//Used by ImageParticle data shadowing
QQuickImageParticle* colorOwner;
@@ -233,19 +330,23 @@ public:
// 4 bytes wasted
- void debugDump();
- bool stillAlive();//Only checks end, because usually that's all you need and it's a little faster.
- bool alive();
- float lifeLeft();
- float curSize();
+ void debugDump(QQuickParticleSystem *particleSystem) const;
+ bool stillAlive(QQuickParticleSystem *particleSystem) const; //Only checks end, because usually that's all you need and it's a little faster.
+ bool alive(QQuickParticleSystem *particleSystem) const;
+ float lifeLeft(QQuickParticleSystem *particleSystem) const;
+
+ float curSize(QQuickParticleSystem *particleSystem) const;
void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index
- QQmlV4Handle v4Value();
- void extendLife(float time);
+ QQmlV4Handle v4Value(QQuickParticleSystem *particleSystem);
+ void extendLife(float time, QQuickParticleSystem *particleSystem);
+
+ static inline Q_DECL_CONSTEXPR float EPSILON() Q_DECL_NOTHROW { return 0.001f; }
+
private:
QQuickV4ParticleData* v8Datum;
};
-class Q_AUTOTEST_EXPORT QQuickParticleSystem : public QQuickItem
+class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleSystem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
@@ -298,7 +399,7 @@ private Q_SLOTS:
public:
//These can be called multiple times per frame, performance critical
- void emitParticle(QQuickParticleData* p);
+ void emitParticle(QQuickParticleData* p, QQuickParticleEmitter *particleEmitter);
QQuickParticleData* newDatum(int groupId, bool respectLimits = true, int sysIdx = -1);
void finishNewDatum(QQuickParticleData*);
void moveGroups(QQuickParticleData *d, int newGIdx);
@@ -310,10 +411,13 @@ public:
//Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize
QSet<QQuickParticleData*> needsReset;
QVector<QQuickParticleData*> bySysIdx; //Another reference to the data (data owned by group), but by sysIdx
- QHash<QString, int> groupIds;
- QHash<int, QQuickParticleGroupData*> groupData;
QQuickStochasticEngine* stateEngine;
+ QHash<QString, int> groupIds;
+ QVarLengthArray<QQuickParticleGroupData*, 32> groupData;
+ int nextFreeGroupId;
+ int registerParticleGroupData(const QString &name, QQuickParticleGroupData *pgd);
+
//Also only here for auto-test usage
void updateCurrentTime( int currentTime );
QQuickParticleSystemAnimation* m_animation;
@@ -326,6 +430,7 @@ public:
void registerParticlePainter(QQuickParticlePainter* p);
void registerParticleEmitter(QQuickParticleEmitter* e);
+ void finishRegisteringParticleEmitter(QQuickParticleEmitter *e);
void registerParticleAffector(QQuickParticleAffector* a);
void registerParticleGroup(QQuickParticleGroup* g);
@@ -342,6 +447,9 @@ public:
}
private:
+ void searchNextFreeGroupId();
+
+private:
void initializeSystem();
void initGroups();
QList<QPointer<QQuickParticleEmitter> > m_emitters;
@@ -349,7 +457,6 @@ private:
QList<QPointer<QQuickParticlePainter> > m_painters;
QList<QPointer<QQuickParticlePainter> > m_syncList;
QList<QQuickParticleGroup*> m_groups;
- int m_nextGroupId;
int m_nextIndex;
QSet<int> m_reusableIndexes;
bool m_componentComplete;
@@ -384,6 +491,124 @@ private:
QQuickParticleSystem* m_system;
};
+inline void QQuickParticleData::setInstantaneousAX(float ax, QQuickParticleSystem* particleSystem)
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ float vx = (this->vx + t * this->ax) - t * ax;
+ float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq;
+ float x = ex - t * vx - 0.5f * t_sq * ax;
+
+ this->ax = ax;
+ this->vx = vx;
+ this->x = x;
+}
+
+inline void QQuickParticleData::setInstantaneousVX(float vx, QQuickParticleSystem* particleSystem)
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ float evx = vx - t * this->ax;
+ float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq;
+ float x = ex - t * evx - 0.5f * t_sq * this->ax;
+
+ this->vx = evx;
+ this->x = x;
+}
+
+inline void QQuickParticleData::setInstantaneousX(float x, QQuickParticleSystem* particleSystem)
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ this->x = x - t * this->vx - 0.5f * t_sq * this->ax;
+}
+
+inline void QQuickParticleData::setInstantaneousAY(float ay, QQuickParticleSystem* particleSystem)
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ float vy = (this->vy + t * this->ay) - t * ay;
+ float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq;
+ float y = ey - t * vy - 0.5f * t_sq * ay;
+
+ this->ay = ay;
+ this->vy = vy;
+ this->y = y;
+}
+
+inline void QQuickParticleData::setInstantaneousVY(float vy, QQuickParticleSystem* particleSystem)
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ float evy = vy - t * this->ay;
+ float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq;
+ float y = ey - t*evy - 0.5f * t_sq * this->ay;
+
+ this->vy = evy;
+ this->y = y;
+}
+
+inline void QQuickParticleData::setInstantaneousY(float y, QQuickParticleSystem *particleSystem)
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ this->y = y - t * this->vy - 0.5f * t_sq * this->ay;
+}
+
+inline float QQuickParticleData::curX(QQuickParticleSystem *particleSystem) const
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ return this->x + this->vx * t + 0.5f * this->ax * t_sq;
+}
+
+inline float QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) const
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ return this->vx + t * this->ax;
+}
+
+inline float QQuickParticleData::curY(QQuickParticleSystem *particleSystem) const
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ float t_sq = t * t;
+ return y + vy * t + 0.5f * ay * t_sq;
+}
+
+inline float QQuickParticleData::curVY(QQuickParticleSystem *particleSystem) const
+{
+ float t = (particleSystem->timeInt / 1000.0f) - this->t;
+ return vy + t*ay;
+}
+
+inline bool QQuickParticleData::stillAlive(QQuickParticleSystem* system) const
+{
+ if (!system)
+ return false;
+ return (t + lifeSpan - EPSILON()) > (system->timeInt / 1000.0f);
+}
+
+inline bool QQuickParticleData::alive(QQuickParticleSystem* system) const
+{
+ if (!system)
+ return false;
+ float st = (system->timeInt / 1000.0f);
+ return (t + EPSILON()) < st && (t + lifeSpan - EPSILON()) > st;
+}
+
+inline float QQuickParticleData::lifeLeft(QQuickParticleSystem *particleSystem) const
+{
+ if (!particleSystem)
+ return 0.0f;
+ return (t + lifeSpan) - (particleSystem->timeInt / 1000.0f);
+}
+
+inline float QQuickParticleData::curSize(QQuickParticleSystem *particleSystem) const
+{
+ if (!particleSystem || lifeSpan == 0.0f)
+ return 0.0f;
+ return size + (endSize - size) * (1 - (lifeLeft(particleSystem) / lifeSpan));
+}
QT_END_NAMESPACE