diff options
Diffstat (limited to 'src')
25 files changed, 635 insertions, 333 deletions
diff --git a/src/declarative/items/qsgsprite.cpp b/src/declarative/items/qsgsprite.cpp index 806f7a9ad8..63d1951b7c 100644 --- a/src/declarative/items/qsgsprite.cpp +++ b/src/declarative/items/qsgsprite.cpp @@ -40,42 +40,17 @@ ****************************************************************************/ #include "qsgsprite_p.h" -//TODO: Split out particle system dependency -#include "qsgparticlesystem_p.h" #include <QDebug> QT_BEGIN_NAMESPACE QSGSprite::QSGSprite(QObject *parent) : - QObject(parent) + QSGStochasticState(parent) , m_generatedCount(0) , m_framesPerRow(0) - , m_frames(1) , m_frameHeight(0) , m_frameWidth(0) - , m_duration(1000) { } -void redirectError(QDeclarativeListProperty<QObject> *prop, QObject *value) -{ - qWarning() << "Could not add " << value << " to state" << prop->object << "as it is not associated with a particle system."; -} - -QDeclarativeListProperty<QObject> QSGSprite::particleChildren() -{ - QSGParticleSystem* system = qobject_cast<QSGParticleSystem*>(parent()); - if (system) - return QDeclarativeListProperty<QObject>(this, 0, &QSGParticleSystem::stateRedirect); - else - return QDeclarativeListProperty<QObject>(this, 0, &redirectError); -} - -int QSGSprite::variedDuration() const -{ - return m_duration - + (m_durationVariance * ((qreal)qrand()/RAND_MAX) * 2) - - m_durationVariance; -} - QT_END_NAMESPACE diff --git a/src/declarative/items/qsgsprite_p.h b/src/declarative/items/qsgsprite_p.h index c18e9b4505..ed7c6c4be4 100644 --- a/src/declarative/items/qsgsprite_p.h +++ b/src/declarative/items/qsgsprite_p.h @@ -46,6 +46,7 @@ #include <QUrl> #include <QVariantMap> #include <QDeclarativeListProperty> +#include "qsgspriteengine_p.h" QT_BEGIN_HEADER @@ -54,38 +55,23 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QSGSprite : public QObject +class QSGSprite : public QSGStochasticState { Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged) - //If frame height or width is not specified, it is assumed to be a single long row of frames. + //If frame height or width is not specified, it is assumed to be a single long row of square frames. //Otherwise, it can be multiple contiguous rows, when one row runs out the next will be used. Q_PROPERTY(int frameHeight READ frameHeight WRITE setFrameHeight NOTIFY frameHeightChanged) Q_PROPERTY(int frameWidth READ frameWidth WRITE setFrameWidth NOTIFY frameWidthChanged) - Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged) - Q_PROPERTY(int durationVariation READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged) - Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged) - Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged) - Q_PROPERTY(QDeclarativeListProperty<QObject> particleChildren READ particleChildren DESIGNABLE false)//### Hidden property for in-state system definitions - ought not to be used in actual "Sprite" states - Q_CLASSINFO("DefaultProperty", "particleChildren") public: explicit QSGSprite(QObject *parent = 0); - QDeclarativeListProperty<QObject> particleChildren(); - QUrl source() const { return m_source; } - int frames() const - { - return m_frames; - } - int frameHeight() const { return m_frameHeight; @@ -96,55 +82,15 @@ public: return m_frameWidth; } - int duration() const - { - return m_duration; - } - - QString name() const - { - return m_name; - } - - QVariantMap to() const - { - return m_to; - } - - qreal speedModifer() const - { - return m_speedModifier; - } - - int durationVariance() const - { - return m_durationVariance; - } - - int variedDuration() const; signals: void sourceChanged(QUrl arg); - void framesChanged(int arg); - void frameHeightChanged(int arg); void frameWidthChanged(int arg); - void durationChanged(int arg); - - void nameChanged(QString arg); - - void toChanged(QVariantMap arg); - - void speedModifierChanged(qreal arg); - - void durationVarianceChanged(int arg); - - void entered();//### Just playing around - don't expect full state API - public slots: void setSource(QUrl arg) @@ -155,14 +101,6 @@ public slots: } } - void setFrames(int arg) - { - if (m_frames != arg) { - m_frames = arg; - emit framesChanged(arg); - } - } - void setFrameHeight(int arg) { if (m_frameHeight != arg) { @@ -179,60 +117,16 @@ public slots: } } - void setDuration(int arg) - { - if (m_duration != arg) { - m_duration = arg; - emit durationChanged(arg); - } - } - - void setName(QString arg) - { - if (m_name != arg) { - m_name = arg; - emit nameChanged(arg); - } - } - - void setTo(QVariantMap arg) - { - if (m_to != arg) { - m_to = arg; - emit toChanged(arg); - } - } - - void setSpeedModifier(qreal arg) - { - if (m_speedModifier != arg) { - m_speedModifier = arg; - emit speedModifierChanged(arg); - } - } - - void setDurationVariance(int arg) - { - if (m_durationVariance != arg) { - m_durationVariance = arg; - emit durationVarianceChanged(arg); - } - } private: friend class QSGImageParticle; friend class QSGSpriteEngine; + friend class QSGStochasticEngine; int m_generatedCount; int m_framesPerRow; QUrl m_source; - int m_frames; int m_frameHeight; int m_frameWidth; - int m_duration; - QString m_name; - QVariantMap m_to; - qreal m_speedModifier; - int m_durationVariance; }; diff --git a/src/declarative/items/qsgspriteengine.cpp b/src/declarative/items/qsgspriteengine.cpp index 1915db6000..0391ce1281 100644 --- a/src/declarative/items/qsgspriteengine.cpp +++ b/src/declarative/items/qsgspriteengine.cpp @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE Also solve the state data initialization/transfer issue so as to not need to make friends */ -QSGSpriteEngine::QSGSpriteEngine(QObject *parent) : +QSGStochasticEngine::QSGStochasticEngine(QObject *parent) : QObject(parent), m_timeOffset(0) { //Default size 1 @@ -61,7 +61,7 @@ QSGSpriteEngine::QSGSpriteEngine(QObject *parent) : m_advanceTime.start(); } -QSGSpriteEngine::QSGSpriteEngine(QList<QSGSprite*> states, QObject *parent) : +QSGStochasticEngine::QSGStochasticEngine(QList<QSGStochasticState*> states, QObject *parent) : QObject(parent), m_states(states), m_timeOffset(0) { //Default size 1 @@ -69,10 +69,27 @@ QSGSpriteEngine::QSGSpriteEngine(QList<QSGSprite*> states, QObject *parent) : m_advanceTime.start(); } +QSGStochasticEngine::~QSGStochasticEngine() +{ +} + +QSGSpriteEngine::QSGSpriteEngine(QObject *parent) + : QSGStochasticEngine(parent) +{ +} + +QSGSpriteEngine::QSGSpriteEngine(QList<QSGSprite*> sprites, QObject *parent) + : QSGStochasticEngine(parent) +{ + foreach (QSGSprite* sprite, sprites) + m_states << (QSGStochasticState*)sprite; +} + QSGSpriteEngine::~QSGSpriteEngine() { } + int QSGSpriteEngine::maxFrames() { return m_maxFrames; @@ -87,46 +104,46 @@ TODO: Above idea needs to have the varying duration offset added to it */ int QSGSpriteEngine::spriteState(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) return state; - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; return state + extra; } int QSGSpriteEngine::spriteStart(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) return m_startTimes[sprite]; - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; return state + extra*rowDuration; } int QSGSpriteEngine::spriteFrames(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) - return m_states[state]->frames(); - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) + return m_sprites[state]->frames(); + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; - if (extra == m_states[state]->m_generatedCount - 1)//last state - return m_states[state]->frames() % m_states[state]->m_framesPerRow; + if (extra == m_sprites[state]->m_generatedCount - 1)//last state + return m_sprites[state]->frames() % m_sprites[state]->m_framesPerRow; else - return m_states[state]->m_framesPerRow; + return m_sprites[state]->m_framesPerRow; } int QSGSpriteEngine::spriteDuration(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) return m_duration[sprite]; - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; - if (extra == m_states[state]->m_generatedCount - 1)//last state - return (m_duration[sprite] * m_states[state]->frames()) % rowDuration; + if (extra == m_sprites[state]->m_generatedCount - 1)//last state + return (m_duration[sprite] * m_sprites[state]->frames()) % rowDuration; else return rowDuration; } @@ -136,21 +153,21 @@ int QSGSpriteEngine::spriteCount()//TODO: Actually image state count, need to re return m_imageStateCount; } -void QSGSpriteEngine::setGoal(int state, int sprite, bool jump) +void QSGStochasticEngine::setGoal(int state, int sprite, bool jump) { - if (sprite >= m_sprites.count() || state >= m_states.count()) + if (sprite >= m_things.count() || state >= m_states.count()) return; if (!jump){ m_goals[sprite] = state; return; } - if (m_sprites[sprite] == state) + if (m_things[sprite] == state) return;//Already there - m_sprites[sprite] = state; + m_things[sprite] = state; m_duration[sprite] = m_states[state]->variedDuration(); m_goals[sprite] = -1; - restartSprite(sprite); + restart(sprite); emit stateChanged(sprite); emit m_states[state]->entered(); return; @@ -165,8 +182,15 @@ QImage QSGSpriteEngine::assembledImage() int maxSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); + foreach (QSGStochasticState* s, m_states){ + QSGSprite* sprite = qobject_cast<QSGSprite*>(s); + if (sprite) + m_sprites << sprite; + else + qDebug() << "Error: Non-sprite in QSGSpriteEngine"; + } - foreach (QSGSprite* state, m_states){ + foreach (QSGSprite* state, m_sprites){ if (state->frames() > m_maxFrames) m_maxFrames = state->frames(); @@ -224,7 +248,7 @@ QImage QSGSpriteEngine::assembledImage() image.fill(0); QPainter p(&image); int y = 0; - foreach (QSGSprite* state, m_states){ + foreach (QSGSprite* state, m_sprites){ QImage img(state->source().toLocalFile()); if (img.height() == frameHeight && img.width() < maxSize){//Simple case p.drawImage(0,y,img); @@ -271,51 +295,51 @@ QImage QSGSpriteEngine::assembledImage() return image; } -void QSGSpriteEngine::setCount(int c) +void QSGStochasticEngine::setCount(int c) { - m_sprites.resize(c); + m_things.resize(c); m_goals.resize(c); m_duration.resize(c); m_startTimes.resize(c); } -void QSGSpriteEngine::startSprite(int index, int state) +void QSGStochasticEngine::start(int index, int state) { - if (index >= m_sprites.count()) + if (index >= m_things.count()) return; - m_sprites[index] = state; + m_things[index] = state; m_duration[index] = m_states[state]->variedDuration(); m_goals[index] = -1; - restartSprite(index); + restart(index); } -void QSGSpriteEngine::stopSprite(int index) +void QSGStochasticEngine::stop(int index) { - if (index >= m_sprites.count()) + if (index >= m_things.count()) return; //Will never change until start is called again with a new state - this is not a 'pause' for (int i=0; i<m_stateUpdates.count(); i++) m_stateUpdates[i].second.removeAll(index); } -void QSGSpriteEngine::restartSprite(int index) +void QSGStochasticEngine::restart(int index) { m_startTimes[index] = m_timeOffset + m_advanceTime.elapsed(); - int time = m_duration[index] * m_states[m_sprites[index]]->frames() + m_startTimes[index]; + int time = m_duration[index] * m_states[m_things[index]]->frames() + m_startTimes[index]; for (int i=0; i<m_stateUpdates.count(); i++) m_stateUpdates[i].second.removeAll(index); addToUpdateList(time, index); } -uint QSGSpriteEngine::updateSprites(uint time)//### would returning a list of changed idxs be faster than signals? +uint QSGStochasticEngine::updateSprites(uint time)//### would returning a list of changed idxs be faster than signals? { //Sprite State Update; QSet<int> changedIndexes; while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){ foreach (int idx, m_stateUpdates.first().second){ - if (idx >= m_sprites.count()) + if (idx >= m_things.count()) continue;//TODO: Proper fix(because this does happen and I'm just ignoring it) - int stateIdx = m_sprites[idx]; + int stateIdx = m_things[idx]; int nextIdx = -1; int goalPath = goalSeek(stateIdx, idx); if (goalPath == -1){//Random @@ -347,7 +371,7 @@ uint QSGSpriteEngine::updateSprites(uint time)//### would returning a list of ch if (nextIdx == -1)//No to states means stay here nextIdx = stateIdx; - m_sprites[idx] = nextIdx; + m_things[idx] = nextIdx; m_duration[idx] = m_states[nextIdx]->variedDuration(); m_startTimes[idx] = time; if (nextIdx != stateIdx){ @@ -370,7 +394,7 @@ uint QSGSpriteEngine::updateSprites(uint time)//### would returning a list of ch return m_stateUpdates.first().first; } -int QSGSpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist) +int QSGStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist) { QString goalName; if (m_goals[spriteIdx] != -1) @@ -386,7 +410,7 @@ int QSGSpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist) return curIdx; if (dist < 0) dist = m_states.count(); - QSGSprite* curState = m_states[curIdx]; + QSGStochasticState* curState = m_states[curIdx]; for (QVariantMap::const_iterator iter = curState->m_to.constBegin(); iter!=curState->m_to.constEnd(); iter++){ if (iter.key() == goalName) @@ -445,7 +469,7 @@ int QSGSpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist) return -1; } -void QSGSpriteEngine::addToUpdateList(uint t, int idx) +void QSGStochasticEngine::addToUpdateList(uint t, int idx) { for (int i=0; i<m_stateUpdates.count(); i++){ if (m_stateUpdates[i].first==t){ diff --git a/src/declarative/items/qsgspriteengine_p.h b/src/declarative/items/qsgspriteengine_p.h index 10860a51f1..b2a06f2c87 100644 --- a/src/declarative/items/qsgspriteengine_p.h +++ b/src/declarative/items/qsgspriteengine_p.h @@ -58,48 +58,171 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QSGSprite; +class QSGStochasticState : public QObject //For internal use +{ + Q_OBJECT + Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged) + Q_PROPERTY(int durationVariation READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged) + Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged) + Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged) + +public: + QSGStochasticState(QObject* parent = 0) + : QObject(parent) + , m_frames(1) + , m_duration(1000) + { + } + + int duration() const + { + return m_duration; + } + + QString name() const + { + return m_name; + } + + QVariantMap to() const + { + return m_to; + } + + qreal speedModifer() const + { + return m_speedModifier; + } + + int durationVariance() const + { + return m_durationVariance; + } + + + int variedDuration() const + { + return m_duration + + (m_durationVariance * ((qreal)qrand()/RAND_MAX) * 2) + - m_durationVariance; + } -class QSGSpriteEngine : public QObject + int frames() const + { + return m_frames; + } + +signals: + void durationChanged(int arg); + + void nameChanged(QString arg); + + void toChanged(QVariantMap arg); + + void speedModifierChanged(qreal arg); + + void durationVarianceChanged(int arg); + + void entered();//### Just playing around - don't expect full state API + void framesChanged(int arg); + +public slots: + void setDuration(int arg) + { + if (m_duration != arg) { + m_duration = arg; + emit durationChanged(arg); + } + } + + void setName(QString arg) + { + if (m_name != arg) { + m_name = arg; + emit nameChanged(arg); + } + } + + void setTo(QVariantMap arg) + { + if (m_to != arg) { + m_to = arg; + emit toChanged(arg); + } + } + + void setSpeedModifier(qreal arg) + { + if (m_speedModifier != arg) { + m_speedModifier = arg; + emit speedModifierChanged(arg); + } + } + + void setDurationVariance(int arg) + { + if (m_durationVariance != arg) { + m_durationVariance = arg; + emit durationVarianceChanged(arg); + } + } + + void setFrames(int arg) + { + if (m_frames != arg) { + m_frames = arg; + emit framesChanged(arg); + } + } + +private: + QString m_name; + int m_frames; + QVariantMap m_to; + int m_duration; + qreal m_speedModifier; + int m_durationVariance; + + friend class QSGStochasticEngine; +}; + +class QSGStochasticEngine : public QObject { Q_OBJECT - //TODO: Optimize single sprite case - Q_PROPERTY(QDeclarativeListProperty<QSGSprite> sprites READ sprites) + //TODO: Optimize single state case? Q_PROPERTY(QString globalGoal READ globalGoal WRITE setGlobalGoal NOTIFY globalGoalChanged) + Q_PROPERTY(QDeclarativeListProperty<QSGStochasticState> states READ states) public: - explicit QSGSpriteEngine(QObject *parent = 0); - QSGSpriteEngine(QList<QSGSprite*> sprites, QObject *parent=0); - ~QSGSpriteEngine(); + explicit QSGStochasticEngine(QObject *parent = 0); + QSGStochasticEngine(QList<QSGStochasticState*> states, QObject *parent=0); + ~QSGStochasticEngine(); - QDeclarativeListProperty<QSGSprite> sprites() + QDeclarativeListProperty<QSGStochasticState> states() { - return QDeclarativeListProperty<QSGSprite>(this, m_states); + return QDeclarativeListProperty<QSGStochasticState>(this, m_states); } + QString globalGoal() const { return m_globalGoal; } - int count() const {return m_sprites.count();} + int count() const {return m_things.count();} void setCount(int c); - int spriteState(int sprite=0);// {return m_sprites[sprite];} - int spriteStart(int sprite=0);// {return m_startTimes[sprite];} - int spriteFrames(int sprite=0); - int spriteDuration(int sprite=0); - int spriteCount();//Like state count, but for the image states - int maxFrames(); - void setGoal(int state, int sprite=0, bool jump=false); - QImage assembledImage(); - void startSprite(int index=0, int state=0); - void stopSprite(int index=0); + void setGoal(int state, int sprite=0, bool jump=false); + void start(int index=0, int state=0); + void stop(int index=0); + int curState(int index=0) {return m_things[index];} -private://Nothing outside should use this? - friend class QSGSpriteGoalAffector;//XXX: Fix interface + QSGStochasticState* state(int idx){return m_states[idx];} + int stateIndex(QSGStochasticState* s){return m_states.indexOf(s);} int stateCount() {return m_states.count();} - int stateIndex(QSGSprite* s){return m_states.indexOf(s);}//TODO: Does this need to be hidden? - QSGSprite* state(int idx){return m_states[idx];}//Used by spritegoal affector +private: signals: void globalGoalChanged(QString arg); @@ -116,14 +239,14 @@ public slots: uint updateSprites(uint time); -private: +protected: friend class QSGParticleSystem; - void restartSprite(int sprite); + void restart(int index); void addToUpdateList(uint t, int idx); - int goalSeek(int curState, int spriteIdx, int dist=-1); - QList<QSGSprite*> m_states; + int goalSeek(int curState, int idx, int dist=-1); + QList<QSGStochasticState*> m_states; //### Consider struct or class for the four data variables? - QVector<int> m_sprites;//int is the index in m_states of the current state + QVector<int> m_things;//int is the index in m_states of the current state QVector<int> m_goals; QVector<int> m_duration; QVector<int> m_startTimes; @@ -136,6 +259,31 @@ private: int m_imageStateCount; }; +class QSGSpriteEngine : public QSGStochasticEngine +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeListProperty<QSGSprite> sprites READ sprites) +public: + explicit QSGSpriteEngine(QObject *parent = 0); + QSGSpriteEngine(QList<QSGSprite*> sprites, QObject *parent=0); + ~QSGSpriteEngine(); + QDeclarativeListProperty<QSGSprite> sprites() + { + return QDeclarativeListProperty<QSGSprite>(this, m_sprites); + } + + + int spriteState(int sprite=0); + int spriteStart(int sprite=0); + int spriteFrames(int sprite=0); + int spriteDuration(int sprite=0); + int spriteCount();//Like state count, but for the image states + int maxFrames(); + QImage assembledImage(); +private: + QList<QSGSprite*> m_sprites; +}; + //Common use is to have your own list property which is transparently an engine inline void spriteAppend(QDeclarativeListProperty<QSGSprite> *p, QSGSprite* s) { diff --git a/src/declarative/items/qsgspriteimage.cpp b/src/declarative/items/qsgspriteimage.cpp index afa80e4aa1..5557ea564a 100644 --- a/src/declarative/items/qsgspriteimage.cpp +++ b/src/declarative/items/qsgspriteimage.cpp @@ -263,7 +263,7 @@ QSGGeometryNode* QSGSpriteImage::buildNode() g->setDrawingMode(GL_TRIANGLES); SpriteVertices *p = (SpriteVertices *) g->vertexData(); - m_spriteEngine->startSprite(0); + m_spriteEngine->start(0); p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = 0; p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = 0; p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames(); diff --git a/src/declarative/particles/particles.pri b/src/declarative/particles/particles.pri index 527bd9ae61..8676e52172 100644 --- a/src/declarative/particles/particles.pri +++ b/src/declarative/particles/particles.pri @@ -29,7 +29,8 @@ HEADERS += \ $$PWD/qsgtargetaffector_p.h \ $$PWD/qsgcumulativedirection_p.h \ $$PWD/qsgv8particledata_p.h \ - $$PWD/qsgrectangleextruder_p.h + $$PWD/qsgrectangleextruder_p.h \ + $$PWD/qsgparticlegroup_p.h SOURCES += \ $$PWD/qsgangledirection.cpp \ @@ -60,7 +61,8 @@ SOURCES += \ $$PWD/qsgtargetaffector.cpp \ $$PWD/qsgcumulativedirection.cpp \ $$PWD/qsgv8particledata.cpp \ - $$PWD/qsgrectangleextruder.cpp + $$PWD/qsgrectangleextruder.cpp \ + $$PWD/qsgparticlegroup.cpp RESOURCES += \ $$PWD/particles.qrc diff --git a/src/declarative/particles/qsgcustomparticle.cpp b/src/declarative/particles/qsgcustomparticle.cpp index ab4cfa0a3a..a1d65a5360 100644 --- a/src/declarative/particles/qsgcustomparticle.cpp +++ b/src/declarative/particles/qsgcustomparticle.cpp @@ -465,7 +465,7 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNodes() s.vertexCode = qt_particles_default_vertex_code; s.vertexCode = qt_particles_template_vertex_code + s.vertexCode; m_material.setProgramSource(s); - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); //Create Particle Geometry diff --git a/src/declarative/particles/qsgimageparticle.cpp b/src/declarative/particles/qsgimageparticle.cpp index 581024d578..b1aef784e8 100644 --- a/src/declarative/particles/qsgimageparticle.cpp +++ b/src/declarative/particles/qsgimageparticle.cpp @@ -1021,7 +1021,7 @@ QSGGeometryNode* QSGImageParticle::buildParticleNodes() m_material->setFlag(QSGMaterial::Blending); } - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); QSGGeometryNode* node = new QSGGeometryNode(); @@ -1151,7 +1151,7 @@ void QSGImageParticle::prepareNextFrame() //Advance State getState<ImageMaterialData>(m_material)->animcount = m_spriteEngine->spriteCount(); m_spriteEngine->updateSprites(timeStamp); - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); @@ -1199,7 +1199,7 @@ void QSGImageParticle::initialize(int gIdx, int pIdx) datum->animT = datum->t; datum->animIdx = 0; if (m_spriteEngine){ - m_spriteEngine->startSprite(spriteIdx); + m_spriteEngine->start(spriteIdx); datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx); datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx); }else{ diff --git a/src/declarative/particles/qsgimageparticle_p.h b/src/declarative/particles/qsgimageparticle_p.h index 01eacbad99..1f87b16f63 100644 --- a/src/declarative/particles/qsgimageparticle_p.h +++ b/src/declarative/particles/qsgimageparticle_p.h @@ -56,7 +56,7 @@ class ImageMaterialData; class QSGGeometryNode; class QSGSprite; -class QSGSpriteEngine; +class QSGStochasticEngine; struct SimpleVertex { float x; @@ -186,7 +186,7 @@ public: QDeclarativeListProperty<QSGSprite> sprites(); - QSGSpriteEngine* spriteEngine() {return m_spriteEngine;} + QSGStochasticEngine* spriteEngine() {return m_spriteEngine;} enum EntryEffect { None = 0, diff --git a/src/declarative/particles/qsgitemparticle.cpp b/src/declarative/particles/qsgitemparticle.cpp index c330880980..2572d67783 100644 --- a/src/declarative/particles/qsgitemparticle.cpp +++ b/src/declarative/particles/qsgitemparticle.cpp @@ -226,7 +226,7 @@ void QSGItemParticle::prepareNextFrame() return; //TODO: Size, better fade? - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); diff --git a/src/declarative/particles/qsgparticleaffector.cpp b/src/declarative/particles/qsgparticleaffector.cpp index cff3c29444..7cb4869f3e 100644 --- a/src/declarative/particles/qsgparticleaffector.cpp +++ b/src/declarative/particles/qsgparticleaffector.cpp @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE If the Affector is a direct child of a ParticleSystem, it will automatically be associated with it. */ /*! - \qmlproperty list<string> QtQuick.Particles2::Affector::particles + \qmlproperty list<string> QtQuick.Particles2::Affector::groups Which logical particle groups will be affected. If empty, it will affect all particles. @@ -100,9 +100,9 @@ QT_BEGIN_NAMESPACE x,y are the coordinates of the affected particle, relative to the ParticleSystem. */ -//TODO: Document particle 'type' + /*! - \qmlsignal QtQuick.Particles2::Affector::affectParticle(particle, dt) + \qmlsignal QtQuick.Particles2::Affector::affectParticle(particle particle, real dt) This handler is called when particles are selected to be affected. @@ -113,7 +113,7 @@ QT_BEGIN_NAMESPACE high-volume particle systems. */ /*! - \qmlsignal QtQuick.Particles2::Affector::affected(x, y) + \qmlsignal QtQuick.Particles2::Affector::affected(real x, real y) This handler is called when a particle is selected to be affected. It will only be called if signal is set to true. @@ -142,12 +142,12 @@ void QSGParticleAffector::componentComplete() bool QSGParticleAffector::activeGroup(int g) { if (m_updateIntSet){ - m_groups.clear(); - foreach (const QString &p, m_particles) - m_groups << m_system->m_groupIds[p];//###Can this occur before group ids are properly assigned? + m_groupIds.clear(); + foreach (const QString &p, m_groups) + m_groupIds << m_system->m_groupIds[p];//###Can this occur before group ids are properly assigned? m_updateIntSet = false; } - return m_groups.isEmpty() || m_groups.contains(g); + return m_groupIds.isEmpty() || m_groupIds.contains(g); } void QSGParticleAffector::affectSystem(qreal dt) @@ -195,7 +195,7 @@ bool QSGParticleAffector::affectParticle(QSGParticleData *, qreal ) void QSGParticleAffector::reset(QSGParticleData* pd) {//TODO: This, among other ones, should be restructured so they don't all need to remember to call the superclass if (m_onceOff) - if (m_groups.isEmpty() || m_groups.contains(pd->group)) + if (m_groups.isEmpty() || m_groupIds.contains(pd->group)) m_onceOffed.remove(qMakePair(pd->group, pd->index)); } diff --git a/src/declarative/particles/qsgparticleaffector_p.h b/src/declarative/particles/qsgparticleaffector_p.h index 5700969aad..0dadeff6a7 100644 --- a/src/declarative/particles/qsgparticleaffector_p.h +++ b/src/declarative/particles/qsgparticleaffector_p.h @@ -56,7 +56,7 @@ class QSGParticleAffector : public QSGItem { Q_OBJECT Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) - Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged) + Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged) Q_PROPERTY(QStringList whenCollidingWith READ whenCollidingWith WRITE setWhenCollidingWith NOTIFY whenCollidingWithChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool once READ onceOff WRITE setOnceOff NOTIFY onceChanged) @@ -71,9 +71,9 @@ public: return m_system; } - QStringList particles() const + QStringList groups() const { - return m_particles; + return m_groups; } bool enabled() const @@ -100,7 +100,7 @@ signals: void systemChanged(QSGParticleSystem* arg); - void particlesChanged(QStringList arg); + void groupsChanged(QStringList arg); void enabledChanged(bool arg); @@ -122,12 +122,12 @@ void setSystem(QSGParticleSystem* arg) } } -void setParticles(QStringList arg) +void setGroups(QStringList arg) { - if (m_particles != arg) { - m_particles = arg; + if (m_groups != arg) { + m_groups = arg; m_updateIntSet = true; - emit particlesChanged(arg); + emit groupsChanged(arg); } } @@ -169,14 +169,14 @@ protected: virtual bool affectParticle(QSGParticleData *d, qreal dt); bool m_needsReset;//### What is this really saving? QSGParticleSystem* m_system; - QStringList m_particles; + QStringList m_groups; bool activeGroup(int g); bool m_enabled; virtual void componentComplete(); QPointF m_offset; bool isAffectedConnected(); private: - QSet<int> m_groups; + QSet<int> m_groupIds; QSet<QPair<int, int> > m_onceOffed; bool m_updateIntSet; diff --git a/src/declarative/particles/qsgparticleemitter.cpp b/src/declarative/particles/qsgparticleemitter.cpp index 13ab3e6185..fdba3def41 100644 --- a/src/declarative/particles/qsgparticleemitter.cpp +++ b/src/declarative/particles/qsgparticleemitter.cpp @@ -68,9 +68,9 @@ QT_BEGIN_NAMESPACE This can be omitted if the Emitter is a direct child of the ParticleSystem */ /*! - \qmlproperty string QtQuick.Particles2::Emitter::particle + \qmlproperty string QtQuick.Particles2::Emitter::group - This is the type of logical particle which it will emit. + This is the logical particle group which it will emit into. Default value is "" (empty string). */ @@ -396,7 +396,7 @@ void QSGParticleEmitter::emitWindow(int timeStamp) pt = time; 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_particle], !m_overwrite); + QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_group], !m_overwrite); if (datum){//actually emit(otherwise we've been asked to skip this one) datum->e = this;//###useful? qreal t = 1 - (pt - opt) / dt; diff --git a/src/declarative/particles/qsgparticleemitter_p.h b/src/declarative/particles/qsgparticleemitter_p.h index 8ed7ee7053..8bd205b207 100644 --- a/src/declarative/particles/qsgparticleemitter_p.h +++ b/src/declarative/particles/qsgparticleemitter_p.h @@ -61,7 +61,7 @@ class QSGParticleEmitter : public QSGItem { Q_OBJECT Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) - Q_PROPERTY(QString particle READ particle WRITE setParticle NOTIFY particleChanged) + Q_PROPERTY(QString group READ group WRITE setGroup NOTIFY groupChanged) Q_PROPERTY(QSGParticleExtruder* shape READ extruder WRITE setExtruder NOTIFY extruderChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged) @@ -109,9 +109,9 @@ public: return m_system; } - QString particle() const + QString group() const { - return m_particle; + return m_group; } int particleDurationVariation() const @@ -130,7 +130,7 @@ signals: void systemChanged(QSGParticleSystem* arg); - void particleChanged(QString arg); + void groupChanged(QString arg); void particleDurationVariationChanged(int arg); @@ -185,11 +185,11 @@ public slots: } } - void setParticle(QString arg) + void setGroup(QString arg) { - if (m_particle != arg) { - m_particle = arg; - emit particleChanged(arg); + if (m_group != arg) { + m_group = arg; + emit groupChanged(arg); } } @@ -308,7 +308,7 @@ protected: int m_particleDurationVariation; bool m_enabled; QSGParticleSystem* m_system; - QString m_particle; + QString m_group; QSGParticleExtruder* m_extruder; QSGParticleExtruder* m_defaultExtruder; QSGParticleExtruder* effectiveExtruder(); diff --git a/src/declarative/particles/qsgparticlegroup.cpp b/src/declarative/particles/qsgparticlegroup.cpp new file mode 100644 index 0000000000..28eb4d2c85 --- /dev/null +++ b/src/declarative/particles/qsgparticlegroup.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 "qsgparticlegroup_p.h" + +/*! + \qmlclass ParticleGroup QSGParticleGroup + \inqmlmodule QtQuick.Particles 2 + \brief ParticleGroup elements allow you to set attributes on a logical particle group. + + This element allows you to set timed transitions on particle groups. + + You can also use this element to group particle system elements related to the logical + particle group. Emitters, Affectors and Painters set as direct children of a ParticleGroup + will automatically apply to that logical particle group. TrailEmitters will automatically follow + the group. + + If a ParticleGroup element is not defined for a group, the group will function normally as if + none of the transition properties were set. +*/ +/*! + \qmlproperty ParticleSystem QtQuick.Particles2::ParticleGroup::system + This is the system which will contain the group. + + If the ParticleGroup is a direct child of a ParticleSystem, it will automatically be associated with it. +*/ +/*! + \qmlproperty string QtQuick.Particles2::ParticleGroup::name + This is the name of the particle group, and how it is generally referred to by other elements. + + If elements refer to a name which does not have an explicit ParticleGroup created, it will + work normally (with no transitions specified for the group). If you do not need to assign + duration based transitions to a group, you do not need to create a ParticleGroup with that name (although you may). +*/ +/*! + \qmlproperty int QtQuick.Particles2::ParticleGroup::duration + The time in milliseconds before the group will attempt to transition. + +*/ +/*! + \qmlproperty ParticleSystem QtQuick.Particles2::ParticleGroup::durationVariation + The maximum number of milliseconds that the duration of the transition cycle varies per particle in the group. + + Default value is zero. +*/ +/*! + \qmlproperty ParticleSystem QtQuick.Particles2::ParticleGroup::to + The weighted list of transitions valid for this group. + + If the chosen transition stays in this group, another duration (+/- up to durationVariation) + milliseconds will occur before another transition is attempted. +*/ + +QSGParticleGroup::QSGParticleGroup(QObject* parent) + : QSGStochasticState(parent) +{ + +} + +void delayedRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value) +{ + QSGParticleGroup* pg = qobject_cast<QSGParticleGroup*>(prop->object); + if (pg) + pg->delayRedirect(value); +} + +QDeclarativeListProperty<QObject> QSGParticleGroup::particleChildren() +{ + QSGParticleSystem* system = qobject_cast<QSGParticleSystem*>(parent()); + if (system) + return QDeclarativeListProperty<QObject>(this, 0, &QSGParticleSystem::statePropertyRedirect); + else + return QDeclarativeListProperty<QObject>(this, 0, &delayedRedirect); +} + +void QSGParticleGroup::setSystem(QSGParticleSystem* arg) +{ + if (m_system != arg) { + m_system = arg; + m_system->registerParticleGroup(this); + performDelayedRedirects(); + emit systemChanged(arg); + } +} + +void QSGParticleGroup::delayRedirect(QObject *obj) +{ + m_delayedRedirects << obj; +} + +void QSGParticleGroup::performDelayedRedirects() +{ + if (!m_system) + return; + foreach (QObject* obj, m_delayedRedirects) + m_system->stateRedirect(this, m_system, obj); + + m_delayedRedirects.clear(); +} + +void QSGParticleGroup::componentComplete(){ + if (!m_system && qobject_cast<QSGParticleSystem*>(parent())) + setSystem(qobject_cast<QSGParticleSystem*>(parent())); +} diff --git a/src/declarative/particles/qsgparticlegroup_p.h b/src/declarative/particles/qsgparticlegroup_p.h new file mode 100644 index 0000000000..346b4ab77e --- /dev/null +++ b/src/declarative/particles/qsgparticlegroup_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 QSGPARTICLEGROUP +#define QSGPARTICLEGROUP +#include "qsgspriteengine_p.h" +#include "qsgparticlesystem_p.h" +#include "qdeclarativeparserstatus.h" + +class QSGParticleGroup : public QSGStochasticState, public QDeclarativeParserStatus +{ + Q_OBJECT + //### Would setting limits per group be useful? Or clutter the API? + //Q_PROPERTY(int maximumAlive READ maximumAlive WRITE setMaximumAlive NOTIFY maximumAliveChanged) + + Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) + + //Intercept children requests and assign to the group & system + Q_PROPERTY(QDeclarativeListProperty<QObject> particleChildren READ particleChildren DESIGNABLE false)//### Hidden property for in-state system definitions - ought not to be used in actual "Sprite" states + Q_CLASSINFO("DefaultProperty", "particleChildren") + +public: + explicit QSGParticleGroup(QObject* parent = 0); + + QDeclarativeListProperty<QObject> particleChildren(); + + int maximumAlive() const + { + return m_maximumAlive; + } + + QSGParticleSystem* system() const + { + return m_system; + } + +public slots: + + void setMaximumAlive(int arg) + { + if (m_maximumAlive != arg) { + m_maximumAlive = arg; + emit maximumAliveChanged(arg); + } + } + + void setSystem(QSGParticleSystem* arg); + + void delayRedirect(QObject* obj); + +signals: + + void maximumAliveChanged(int arg); + + void systemChanged(QSGParticleSystem* arg); + +protected: + virtual void componentComplete(); + virtual void classBegin(){;} + +private: + + void performDelayedRedirects(); + + int m_maximumAlive; + QSGParticleSystem* m_system; + QList<QObject*> m_delayedRedirects; +}; + +#endif diff --git a/src/declarative/particles/qsgparticlepainter.cpp b/src/declarative/particles/qsgparticlepainter.cpp index f4639c20a2..670c1f2118 100644 --- a/src/declarative/particles/qsgparticlepainter.cpp +++ b/src/declarative/particles/qsgparticlepainter.cpp @@ -58,10 +58,10 @@ QT_BEGIN_NAMESPACE If the ParticlePainter is a direct child of a ParticleSystem, it will automatically be associated with it. */ /*! - \qmlproperty list<string> QtQuick.Particles2::ParticlePainter::particles + \qmlproperty list<string> QtQuick.Particles2::ParticlePainter::groups Which logical particle groups will be painted. - If empty, it will paint the default particle (""). + If empty, it will paint the default particle group (""). */ QSGParticlePainter::QSGParticlePainter(QSGItem *parent) : QSGItem(parent), @@ -144,7 +144,7 @@ void QSGParticlePainter::calcSystemOffset(bool resetPending) m_systemOffset = -1 * this->mapFromItem(m_system, QPointF(0.0, 0.0)); if (lastOffset != m_systemOffset && !resetPending){ //Reload all particles//TODO: Necessary? - foreach (const QString &g, m_particles){ + foreach (const QString &g, m_groups){ int gId = m_system->m_groupIds[g]; foreach (QSGParticleData* d, m_system->m_groupData[gId]->data) reload(d); diff --git a/src/declarative/particles/qsgparticlepainter_p.h b/src/declarative/particles/qsgparticlepainter_p.h index 08ae3aede8..d469947453 100644 --- a/src/declarative/particles/qsgparticlepainter_p.h +++ b/src/declarative/particles/qsgparticlepainter_p.h @@ -58,7 +58,7 @@ class QSGParticlePainter : public QSGItem { Q_OBJECT Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) - Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged) + Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged) public: explicit QSGParticlePainter(QSGItem *parent = 0); @@ -74,25 +74,25 @@ public: } - QStringList particles() const + QStringList groups() const { - return m_particles; + return m_groups; } signals: void countChanged(); void systemChanged(QSGParticleSystem* arg); - void particlesChanged(QStringList arg); + void groupsChanged(QStringList arg); public slots: void setSystem(QSGParticleSystem* arg); -void setParticles(QStringList arg) +void setGroups(QStringList arg) { - if (m_particles != arg) { - m_particles = arg; - emit particlesChanged(arg); + if (m_groups != arg) { + m_groups = arg; + emit groupsChanged(arg); } } @@ -121,7 +121,7 @@ protected: friend class QSGParticleSystem; int m_count; bool m_pleaseReset; - QStringList m_particles; + QStringList m_groups; QPointF m_systemOffset; private: diff --git a/src/declarative/particles/qsgparticlesmodule.cpp b/src/declarative/particles/qsgparticlesmodule.cpp index 9fa0ebad97..f880842acb 100644 --- a/src/declarative/particles/qsgparticlesmodule.cpp +++ b/src/declarative/particles/qsgparticlesmodule.cpp @@ -67,6 +67,7 @@ #include "qsgcumulativedirection_p.h" #include "qsgcustomaffector_p.h" #include "qsgrectangleextruder_p.h" +#include "qsgparticlegroup_p.h" QT_BEGIN_NAMESPACE @@ -75,6 +76,7 @@ void QSGParticlesModule::defineModule() const char* uri = "QtQuick.Particles"; qmlRegisterType<QSGParticleSystem>(uri, 2, 0, "ParticleSystem"); + qmlRegisterType<QSGParticleGroup>(uri, 2, 0, "ParticleGroup"); qmlRegisterType<QSGImageParticle>(uri, 2, 0, "ImageParticle"); qmlRegisterType<QSGCustomParticle>(uri, 2, 0, "CustomParticle"); diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index 085e6afe64..bc27073142 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -47,6 +47,7 @@ #include "qsgspriteengine_p.h" #include "qsgsprite_p.h" #include "qsgv8particledata_p.h" +#include "qsgparticlegroup_p.h" #include "qsgtrailemitter_p.h"//###For auto-follow on states, perhaps should be in emitter? #include <private/qdeclarativeengine_p.h> @@ -549,8 +550,8 @@ void QSGParticleData::debugDump() { qDebug() << "Particle" << systemIndex << group << "/" << index << stillAlive() << "Pos: " << x << "," << y - //<< "Vel: " << vx << "," << sy - //<< "Acc: " << ax << "," << ay + << "Vel: " << vx << "," << vy + << "Acc: " << ax << "," << ay << "Size: " << size << "," << endSize << "Time: " << t << "," <<lifeSpan << ";" << (system->m_timeInt / 1000.0) ; } @@ -559,7 +560,6 @@ bool QSGParticleData::stillAlive() { if (!system) return false; - //fprintf(stderr, "%.9lf %.9lf\n",((qreal)system->m_timeInt/1000.0), (t+lifeSpan)); return (t + lifeSpan - EPSILON) > ((qreal)system->m_timeInt/1000.0); } @@ -601,7 +601,7 @@ void QSGParticleData::extendLife(float time) QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : QSGItem(parent), m_particle_count(0), m_running(true), m_paused(false) - , m_nextIndex(0), m_componentComplete(false), m_spriteEngine(0) + , m_nextIndex(0), m_componentComplete(false), m_stateEngine(0) { connect(&m_painterMapper, SIGNAL(mapped(QObject*)), this, SLOT(loadPainter(QObject*))); @@ -630,16 +630,11 @@ void QSGParticleSystem::initGroups() m_nextGroupId = 1; } - QDeclarativeListProperty<QSGSprite> QSGParticleSystem::particleStates() -{ - return QDeclarativeListProperty<QSGSprite>(this, &m_states, spriteAppend, spriteCount, spriteAt, spriteClear); -} - void QSGParticleSystem::registerParticlePainter(QSGParticlePainter* p) { //TODO: a way to Unregister emitters, painters and affectors m_painters << QPointer<QSGParticlePainter>(p);//###Set or uniqueness checking? - connect(p, SIGNAL(particlesChanged(QStringList)), + connect(p, SIGNAL(groupsChanged(QStringList)), &m_painterMapper, SLOT(map())); loadPainter(p); } @@ -649,7 +644,7 @@ void QSGParticleSystem::registerParticleEmitter(QSGParticleEmitter* e) m_emitters << QPointer<QSGParticleEmitter>(e);//###How to get them out? connect(e, SIGNAL(particleCountChanged()), this, SLOT(emittersChanged())); - connect(e, SIGNAL(particleChanged(QString)), + connect(e, SIGNAL(groupChanged(QString)), this, SLOT(emittersChanged())); emittersChanged(); e->reset();//Start, so that starttime factors appropriately @@ -660,6 +655,12 @@ void QSGParticleSystem::registerParticleAffector(QSGParticleAffector* a) m_affectors << QPointer<QSGParticleAffector>(a); } +void QSGParticleSystem::registerParticleGroup(QSGParticleGroup* g) +{ + m_groups << QPointer<QSGParticleGroup>(g); + createEngine(); +} + void QSGParticleSystem::setRunning(bool arg) { if (m_running != arg) { @@ -685,40 +686,45 @@ void QSGParticleSystem::setPaused(bool arg){ } } -void QSGParticleSystem::stateRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value) +void QSGParticleSystem::statePropertyRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value) { //Hooks up automatic state-associated stuff QSGParticleSystem* sys = qobject_cast<QSGParticleSystem*>(prop->object->parent()); - QSGSprite* sprite = qobject_cast<QSGSprite*>(prop->object); - if (!sprite || !sys) + QSGParticleGroup* group = qobject_cast<QSGParticleGroup*>(prop->object); + if (!group || !sys || !value) return; + stateRedirect(group, sys, value); +} + +void QSGParticleSystem::stateRedirect(QSGParticleGroup* group, QSGParticleSystem* sys, QObject *value) +{ QStringList list; - list << sprite->name(); + list << group->name(); QSGParticleAffector* a = qobject_cast<QSGParticleAffector*>(value); if (a){ a->setParentItem(sys); - a->setParticles(list); + a->setGroups(list); a->setSystem(sys); return; } QSGTrailEmitter* fe = qobject_cast<QSGTrailEmitter*>(value); if (fe){ fe->setParentItem(sys); - fe->setFollow(sprite->name()); + fe->setFollow(group->name()); fe->setSystem(sys); return; } QSGParticleEmitter* e = qobject_cast<QSGParticleEmitter*>(value); if (e){ e->setParentItem(sys); - e->setParticle(sprite->name()); + e->setGroup(group->name()); e->setSystem(sys); return; } QSGParticlePainter* p = qobject_cast<QSGParticlePainter*>(value); if (p){ p->setParentItem(sys); - p->setParticles(list); + p->setGroups(list); p->setSystem(sys); return; } @@ -785,14 +791,14 @@ void QSGParticleSystem::loadPainter(QObject *p) foreach (QSGParticleGroupData* sg, m_groupData) sg->painters.remove(painter); int particleCount = 0; - if (painter->particles().isEmpty()){//Uses default particle + if (painter->groups().isEmpty()){//Uses default particle QStringList def; def << ""; - painter->setParticles(def); + painter->setGroups(def); particleCount += m_groupData[0]->size(); m_groupData[0]->painters << painter; }else{ - foreach (const QString &group, painter->particles()){ + foreach (const QString &group, painter->groups()){ if (group != QLatin1String("") && !m_groupIds[group]){//new group int id = m_nextGroupId++; QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); @@ -824,16 +830,16 @@ void QSGParticleSystem::emittersChanged() } foreach (QSGParticleEmitter* e, m_emitters){//Populate groups and set sizes. - if (!m_groupIds.contains(e->particle()) - || (!e->particle().isEmpty() && !m_groupIds[e->particle()])){//or it was accidentally inserted by a failed lookup earlier + if (!m_groupIds.contains(e->group()) + || (!e->group().isEmpty() && !m_groupIds[e->group()])){//or it was accidentally inserted by a failed lookup earlier int id = m_nextGroupId++; QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); - m_groupIds.insert(e->particle(), id); + m_groupIds.insert(e->group(), id); m_groupData.insert(id, gd); previousSizes << 0; newSizes << 0; } - newSizes[m_groupIds[e->particle()]] += e->particleCount(); + newSizes[m_groupIds[e->group()]] += e->particleCount(); //###: Cull emptied groups? } @@ -850,7 +856,7 @@ void QSGParticleSystem::emittersChanged() foreach (QSGParticlePainter *p, m_painters) loadPainter(p); - if (!m_states.isEmpty()) + if (!m_groups.isEmpty()) createEngine(); if (m_debugMode) @@ -861,58 +867,63 @@ void QSGParticleSystem::createEngine() { if (!m_componentComplete) return; + if (m_stateEngine && m_debugMode) + qDebug() << "Resetting Existing Sprite Engine..."; //### Solve the losses if size/states go down - foreach (QSGSprite* sprite, m_states){ + foreach (QSGParticleGroup* group, m_groups){ bool exists = false; foreach (const QString &name, m_groupIds.keys()) - if (sprite->name() == name) + if (group->name() == name) exists = true; if (!exists){ int id = m_nextGroupId++; QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); - m_groupIds.insert(sprite->name(), id); + m_groupIds.insert(group->name(), id); m_groupData.insert(id, gd); } } - if (m_states.count()){ - //Reorder Sprite List so as to have the same order as groups - QList<QSGSprite*> newList; + if (m_groups.count()){ + //Reorder groups List so as to have the same order as groupData + QList<QSGParticleGroup*> newList; for (int i=0; i<m_nextGroupId; i++){ bool exists = false; QString name = m_groupData[i]->name(); - foreach (QSGSprite* existing, m_states){ + foreach (QSGParticleGroup* existing, m_groups){ if (existing->name() == name){ newList << existing; exists = true; } } if (!exists){ - newList << new QSGSprite(this); + newList << new QSGParticleGroup(this); newList.back()->setName(name); } } - m_states = newList; + m_groups = newList; + QList<QSGStochasticState*> states; + foreach (QSGParticleGroup* g, m_groups) + states << (QSGStochasticState*)g; - if (!m_spriteEngine) - m_spriteEngine = new QSGSpriteEngine(this); - m_spriteEngine->setCount(m_particle_count); - m_spriteEngine->m_states = m_states; + if (!m_stateEngine) + m_stateEngine = new QSGStochasticEngine(this); + m_stateEngine->setCount(m_particle_count); + m_stateEngine->m_states = states; - connect(m_spriteEngine, SIGNAL(stateChanged(int)), + connect(m_stateEngine, SIGNAL(stateChanged(int)), this, SLOT(particleStateChange(int))); }else{ - if (m_spriteEngine) - delete m_spriteEngine; - m_spriteEngine = 0; + if (m_stateEngine) + delete m_stateEngine; + m_stateEngine = 0; } } void QSGParticleSystem::particleStateChange(int idx) { - moveGroups(m_bySysIdx[idx], m_spriteEngine->spriteState(idx)); + moveGroups(m_bySysIdx[idx], m_stateEngine->curState(idx)); } void QSGParticleSystem::moveGroups(QSGParticleData *d, int newGIdx) @@ -934,8 +945,8 @@ int QSGParticleSystem::nextSystemIndex() } if (m_nextIndex >= m_bySysIdx.size()){ m_bySysIdx.resize(m_bySysIdx.size() < 10 ? 10 : m_bySysIdx.size()*1.1);//###+1,10%,+10? Choose something non-arbitrarily - if (m_spriteEngine) - m_spriteEngine->setCount(m_bySysIdx.size()); + if (m_stateEngine) + m_stateEngine->setCount(m_bySysIdx.size()); } return m_nextIndex++; @@ -954,8 +965,8 @@ QSGParticleData* QSGParticleSystem::newDatum(int groupId, bool respectLimits, in ret->systemIndex = nextSystemIndex(); }else{ if (ret->systemIndex != -1){ - if (m_spriteEngine) - m_spriteEngine->stopSprite(ret->systemIndex); + if (m_stateEngine) + m_stateEngine->stop(ret->systemIndex); m_reusableIndexes << ret->systemIndex; m_bySysIdx[ret->systemIndex] = 0; } @@ -963,8 +974,8 @@ QSGParticleData* QSGParticleSystem::newDatum(int groupId, bool respectLimits, in } m_bySysIdx[ret->systemIndex] = ret; - if (m_spriteEngine) - m_spriteEngine->startSprite(ret->systemIndex, ret->group); + if (m_stateEngine) + m_stateEngine->start(ret->systemIndex, ret->group); m_empty = false; return ret; @@ -1011,8 +1022,8 @@ void QSGParticleSystem::updateCurrentTime( int currentTime ) foreach (QSGParticleGroupData* gd, m_groupData)//Recycle all groups and see if they're out of live particles m_empty = gd->recycle() && m_empty; - if (m_spriteEngine) - m_spriteEngine->updateSprites(m_timeInt); + if (m_stateEngine) + m_stateEngine->updateSprites(m_timeInt); foreach (QSGParticleEmitter* emitter, m_emitters) if (emitter) diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h index 25a0c87f53..f531e7fcf9 100644 --- a/src/declarative/particles/qsgparticlesystem_p.h +++ b/src/declarative/particles/qsgparticlesystem_p.h @@ -65,9 +65,10 @@ class QSGParticleEmitter; class QSGParticlePainter; class QSGParticleData; class QSGParticleSystemAnimation; -class QSGSpriteEngine; +class QSGStochasticEngine; class QSGSprite; class QSGV8ParticleData; +class QSGParticleGroup; struct QSGParticleDataHeapNode{ int time;//in ms @@ -223,12 +224,10 @@ class QSGParticleSystem : public QSGItem Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged) - Q_PROPERTY(QDeclarativeListProperty<QSGSprite> particleStates READ particleStates) public: explicit QSGParticleSystem(QSGItem *parent = 0); ~QSGParticleSystem(); - QDeclarativeListProperty<QSGSprite> particleStates(); //TODO: Hook up running and temporal manipulators to the animation bool isRunning() const @@ -286,7 +285,7 @@ public://###but only really for related class usage. Perhaps we should all be fr QVector<QSGParticleData*> m_bySysIdx; //Another reference to the data (data owned by group), but by sysIdx QHash<QString, int> m_groupIds; QHash<int, QSGParticleGroupData*> m_groupData; - QSGSpriteEngine* m_spriteEngine; + QSGStochasticEngine* m_stateEngine; int m_timeInt; bool m_initialized; @@ -294,9 +293,11 @@ public://###but only really for related class usage. Perhaps we should all be fr void registerParticlePainter(QSGParticlePainter* p); void registerParticleEmitter(QSGParticleEmitter* e); void registerParticleAffector(QSGParticleAffector* a); + void registerParticleGroup(QSGParticleGroup* g); int m_particle_count; - static void stateRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value);//From QSGSprite + static void statePropertyRedirect(QDeclarativeListProperty<QObject> *prop, QObject *value); + static void stateRedirect(QSGParticleGroup* group, QSGParticleSystem* sys, QObject *value); bool isPaused() const { return m_paused; @@ -315,11 +316,11 @@ private: QList<QPointer<QSGParticleAffector> > m_affectors; QList<QPointer<QSGParticlePainter> > m_painters; QList<QPointer<QSGParticlePainter> > m_syncList; + QList<QSGParticleGroup*> m_groups; int m_nextGroupId; int m_nextIndex; QSet<int> m_reusableIndexes; bool m_componentComplete; - QList<QSGSprite*> m_states; QSignalMapper m_painterMapper; QSignalMapper m_emitterMapper; diff --git a/src/declarative/particles/qsgspritegoal.cpp b/src/declarative/particles/qsgspritegoal.cpp index 1837167813..ec2be02326 100644 --- a/src/declarative/particles/qsgspritegoal.cpp +++ b/src/declarative/particles/qsgspritegoal.cpp @@ -64,16 +64,12 @@ QT_BEGIN_NAMESPACE \qmlproperty bool QtQuick.Particles2::SpriteGoal::systemStates */ - Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged) - Q_PROPERTY(bool jump READ jump WRITE setJump NOTIFY jumpChanged) - Q_PROPERTY(bool systemStates READ systemStates WRITE setSystemStates NOTIFY systemStatesChanged) - QSGSpriteGoalAffector::QSGSpriteGoalAffector(QSGItem *parent) : QSGParticleAffector(parent), m_goalIdx(-1), m_jump(false), m_systemStates(false), m_lastEngine(0), m_notUsingEngine(false) { } -void QSGSpriteGoalAffector::updateStateIndex(QSGSpriteEngine* e) +void QSGSpriteGoalAffector::updateStateIndex(QSGStochasticEngine* e) { if (m_systemStates){ m_goalIdx = m_system->m_groupIds[m_goalState]; @@ -104,14 +100,14 @@ void QSGSpriteGoalAffector::setGoalState(QString arg) bool QSGSpriteGoalAffector::affectParticle(QSGParticleData *d, qreal dt) { Q_UNUSED(dt); - QSGSpriteEngine *engine = 0; + QSGStochasticEngine *engine = 0; if (!m_systemStates){ //TODO: Affect all engines foreach (QSGParticlePainter *p, m_system->m_groupData[d->group]->painters) if (qobject_cast<QSGImageParticle*>(p)) engine = qobject_cast<QSGImageParticle*>(p)->spriteEngine(); }else{ - engine = m_system->m_spriteEngine; + engine = m_system->m_stateEngine; if (!engine) m_notUsingEngine = true; } @@ -126,7 +122,7 @@ bool QSGSpriteGoalAffector::affectParticle(QSGParticleData *d, qreal dt) if (m_notUsingEngine){//systemStates && no stochastic states defined. So cut out the engine //TODO: It's possible to move to a group that is intermediate and not used by painters or emitters - but right now that will redirect to the default group m_system->moveGroups(d, m_goalIdx); - }else if (engine->spriteState(index) != m_goalIdx){ + }else if (engine->curState(index) != m_goalIdx){ engine->setGoal(m_goalIdx, index, m_jump); emit affected(QPointF(d->curX(), d->curY()));//###Expensive if unconnected? Move to Affector? return true; //Doesn't affect particle data, but necessary for onceOff diff --git a/src/declarative/particles/qsgspritegoal_p.h b/src/declarative/particles/qsgspritegoal_p.h index 7c799b13b1..043970b90b 100644 --- a/src/declarative/particles/qsgspritegoal_p.h +++ b/src/declarative/particles/qsgspritegoal_p.h @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QSGSpriteEngine; +class QSGStochasticEngine; class QSGSpriteGoalAffector : public QSGParticleAffector { @@ -106,10 +106,10 @@ void setSystemStates(bool arg) } private: - void updateStateIndex(QSGSpriteEngine* e); + void updateStateIndex(QSGStochasticEngine* e); QString m_goalState; int m_goalIdx; - QSGSpriteEngine* m_lastEngine; + QSGStochasticEngine* m_lastEngine; bool m_jump; bool m_systemStates; diff --git a/src/declarative/particles/qsgtrailemitter.cpp b/src/declarative/particles/qsgtrailemitter.cpp index 427b587caf..5a19ac508b 100644 --- a/src/declarative/particles/qsgtrailemitter.cpp +++ b/src/declarative/particles/qsgtrailemitter.cpp @@ -166,7 +166,7 @@ void QSGTrailEmitter::emitWindow(int timeStamp) qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize; int gId = m_system->m_groupIds[m_follow]; - int gId2 = m_system->m_groupIds[m_particle]; + int gId2 = m_system->m_groupIds[m_group]; foreach (QSGParticleData *d, m_system->m_groupData[gId]->data){ if (!d || !d->stillAlive()){ m_lastEmission[d->index] = time; //Should only start emitting when it returns to life diff --git a/src/declarative/particles/qsgtrailemitter_p.h b/src/declarative/particles/qsgtrailemitter_p.h index 5ab6f24270..009ccd508c 100644 --- a/src/declarative/particles/qsgtrailemitter_p.h +++ b/src/declarative/particles/qsgtrailemitter_p.h @@ -94,7 +94,7 @@ public: } signals: - void emitFollowParticle(QDeclarativeV8Handle particle, QDeclarativeV8Handle followed); + void emitFollowParticle(QDeclarativeV8Handle group, QDeclarativeV8Handle followed); void particlesPerParticlePerSecondChanged(int arg); |