diff options
author | Alan Alpert <alan.alpert@nokia.com> | 2011-06-21 12:02:08 +1000 |
---|---|---|
committer | Alan Alpert <alan.alpert@nokia.com> | 2011-06-21 12:02:08 +1000 |
commit | f0ab52c313076fce7e854fd494b88c5dd0f71af5 (patch) | |
tree | 5e1ccd832abe0eae761c69627fd20a039ffd362c /src/declarative/particles | |
parent | 7126b27f5dfeba005cc7f17610bcc09cf0003b52 (diff) |
Rewrite last rewrite
Also rewrite to have all particle state shared, not just common
elements.
Diffstat (limited to 'src/declarative/particles')
18 files changed, 459 insertions, 672 deletions
diff --git a/src/declarative/particles/qsgcustomparticle.cpp b/src/declarative/particles/qsgcustomparticle.cpp index f91307ed5c..09cfdda143 100644 --- a/src/declarative/particles/qsgcustomparticle.cpp +++ b/src/declarative/particles/qsgcustomparticle.cpp @@ -123,36 +123,8 @@ QSGCustomParticle::QSGCustomParticle(QSGItem* parent) : QSGParticlePainter(parent) , m_pleaseReset(true) , m_dirtyData(true) - , m_resizePending(false) { setFlag(QSGItem::ItemHasContents); - m_defaultVertices = new PlainVertices; - PlainVertex* vertices = (PlainVertex*) m_defaultVertices; - for (int i=0; i<4; ++i) { - vertices[i].x = 0; - vertices[i].y = 0; - vertices[i].t = -1; - vertices[i].lifeSpan = 0; - vertices[i].size = 0; - vertices[i].endSize = 0; - vertices[i].sx = 0; - vertices[i].sy = 0; - vertices[i].ax = 0; - vertices[i].ay = 0; - vertices[i].r = 0; - } - - vertices[0].tx = 0; - vertices[0].ty = 0; - - vertices[1].tx = 1; - vertices[1].ty = 0; - - vertices[2].tx = 0; - vertices[2].ty = 1; - - vertices[3].tx = 1; - vertices[3].ty = 1; } void QSGCustomParticle::componentComplete() @@ -202,19 +174,6 @@ void QSGCustomParticle::setVertexShader(const QByteArray &code) emit vertexShaderChanged(); } -void QSGCustomParticle::resize(int oldCount, int newCount) -{ - if(!m_node) - return; - if(!m_resizePending){ - m_pendingResizeVector.resize(oldCount); - PlainVertices *particles = (PlainVertices *) m_node->geometry()->vertexData(); - for(int i=0; i<oldCount; i++) - m_pendingResizeVector[i] = &particles[i]; - } - groupShuffle(m_pendingResizeVector, m_defaultVertices); -} - void QSGCustomParticle::reset() { disconnectPropertySignals(); @@ -411,8 +370,6 @@ QSGNode *QSGCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat m_pleaseReset = false; m_dirtyData = false; } - if(m_resizePending) - performPendingResize(); if(m_system && m_system->isRunning()) prepareNextFrame(); @@ -437,32 +394,6 @@ void QSGCustomParticle::prepareNextFrame(){ buildData(); } -void QSGCustomParticle::performPendingResize() -{ - m_resizePending = false; - if(!m_node) - return; - Q_ASSERT(m_pendingResizeVector.size() == m_count);//XXX - PlainVertices tmp[m_count];//###More vast memcpys that will decrease performance - for(int i=0; i<m_count; i++) - tmp[i] = *m_pendingResizeVector[i]; - m_node->setFlag(QSGNode::OwnsGeometry, false); - m_node->geometry()->allocate(m_count*4, m_count*6); - memcpy(m_node->geometry()->vertexData(), tmp, sizeof(PlainVertices) * m_count); - quint16 *indices = m_node->geometry()->indexDataAsUShort(); - for (int i=0; i<m_count; ++i) { - int o = i * 4; - indices[0] = o; - indices[1] = o + 1; - indices[2] = o + 2; - indices[3] = o + 1; - indices[4] = o + 3; - indices[5] = o + 2; - indices += 6; - } - m_node->setFlag(QSGNode::OwnsGeometry, true); -} - QSGShaderEffectNode* QSGCustomParticle::buildCustomNode() { if (m_count * 4 > 0xffff) { @@ -475,8 +406,6 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNode() return 0; } - m_resizePending = false;//reset resizes as well. - //Create Particle Geometry int vCount = m_count * 4; int iCount = m_count * 6; @@ -484,10 +413,18 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNode() g->setDrawingMode(GL_TRIANGLES); PlainVertex *vertices = (PlainVertex *) g->vertexData(); for (int p=0; p<m_count; ++p) { - double r = rand()/(double)RAND_MAX;//TODO: Seed? - memcpy(vertices, m_defaultVertices, sizeof(PlainVertices)); - for(int i=0; i<4; i++) - vertices[i].r = r; + reload(p); + vertices[0].tx = 0; + vertices[0].ty = 0; + + vertices[1].tx = 1; + vertices[1].ty = 0; + + vertices[2].tx = 0; + vertices[2].ty = 1; + + vertices[3].tx = 1; + vertices[3].ty = 1; vertices += 4; } quint16 *indices = g->indexDataAsUShort(); @@ -553,28 +490,31 @@ void QSGCustomParticle::buildData() m_dirtyData = false; } -void QSGCustomParticle::load(QSGParticleData *d) +void QSGCustomParticle::initialize(int idx) { - reload(d);//We don't do anything special in C++ here. + m_data[idx]->r = rand()/(qreal)RAND_MAX; } -void QSGCustomParticle::reload(QSGParticleData *d) +void QSGCustomParticle::reload(int idx) { if (m_node == 0) return; PlainVertices *particles = (PlainVertices *) m_node->geometry()->vertexData(); - - int pos = particleTypeIndex(d); - - PlainVertices &p = particles[pos]; - - //Perhaps we could be more efficient? - vertexCopy(p.v1, d->pv); - vertexCopy(p.v2, d->pv); - vertexCopy(p.v3, d->pv); - vertexCopy(p.v4, d->pv); - + PlainVertex *vertices = (PlainVertex *)&particles[idx]; + for (int i=0; i<4; ++i) { + vertices[i].x = m_data[idx]->x - m_systemOffset.x(); + vertices[i].y = m_data[idx]->y - m_systemOffset.y(); + vertices[i].t = m_data[idx]->t; + vertices[i].lifeSpan = m_data[idx]->lifeSpan; + vertices[i].size = m_data[idx]->size; + vertices[i].endSize = m_data[idx]->endSize; + vertices[i].sx = m_data[idx]->sx; + vertices[i].sy = m_data[idx]->sy; + vertices[i].ax = m_data[idx]->ax; + vertices[i].ay = m_data[idx]->ay; + vertices[i].r = m_data[idx]->r; + } } QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgcustomparticle_p.h b/src/declarative/particles/qsgcustomparticle_p.h index 863da052f3..50ff37a2a0 100644 --- a/src/declarative/particles/qsgcustomparticle_p.h +++ b/src/declarative/particles/qsgcustomparticle_p.h @@ -62,8 +62,6 @@ class QSGCustomParticle : public QSGParticlePainter public: explicit QSGCustomParticle(QSGItem* parent=0); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); QByteArray fragmentShader() const { return m_source.fragmentCode; } void setFragmentShader(const QByteArray &code); @@ -77,6 +75,9 @@ Q_SIGNALS: void fragmentShaderChanged(); void vertexShaderChanged(); protected: + virtual void initialize(int idx); + virtual void reload(int idx); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); void prepareNextFrame(); void setSource(const QVariant &var, int index); @@ -108,9 +109,6 @@ private: QSGShaderEffectNode* m_node; qreal m_lastTime; - bool m_resizePending; - QVector<PlainVertices*> m_pendingResizeVector; - PlainVertices* m_defaultVertices; }; QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgemitter.cpp b/src/declarative/particles/qsgemitter.cpp index 081dd8dec5..c3ec3ffc9e 100644 --- a/src/declarative/particles/qsgemitter.cpp +++ b/src/declarative/particles/qsgemitter.cpp @@ -124,7 +124,6 @@ void QSGBasicEmitter::emitWindow(int timeStamp) QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle]); if(datum){//actually emit(otherwise we've been asked to skip this one) datum->e = this;//###useful? - ParticleVertex &p = datum->pv; qreal t = 1 - (pt - opt) / dt; qreal vx = - 2 * ax * (1 - t) @@ -137,8 +136,8 @@ void QSGBasicEmitter::emitWindow(int timeStamp) // Particle timestamp - p.t = pt; - p.lifeSpan = //TODO:Promote to base class? + datum->t = pt; + datum->lifeSpan = //TODO:Promote to base class? (m_particleDuration + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) / 1000.0; @@ -153,20 +152,20 @@ void QSGBasicEmitter::emitWindow(int timeStamp) , width(), height()); } QPointF newPos = effectiveExtruder()->extrude(boundsRect); - p.x = newPos.x(); - p.y = newPos.y(); + datum->x = newPos.x(); + datum->y = newPos.y(); // Particle speed const QPointF &speed = m_speed->sample(newPos); - p.sx = speed.x() + datum->sx = speed.x() + m_speed_from_movement * vx; - p.sy = speed.y() + datum->sy = speed.y() + m_speed_from_movement * vy; // Particle acceleration const QPointF &accel = m_acceleration->sample(newPos); - p.ax = accel.x(); - p.ay = accel.y(); + datum->ax = accel.x(); + datum->ay = accel.y(); // Particle size float sizeVariation = -m_particleSizeVariation @@ -175,8 +174,8 @@ void QSGBasicEmitter::emitWindow(int timeStamp) float size = qMax((qreal)0.0 , m_particleSize + sizeVariation); float endSize = qMax((qreal)0.0 , sizeAtEnd + sizeVariation); - p.size = size;// * float(m_emitting); - p.endSize = endSize;// * float(m_emitting); + datum->size = size;// * float(m_emitting); + datum->endSize = endSize;// * float(m_emitting); m_system->emitParticle(datum); } diff --git a/src/declarative/particles/qsgfollowemitter.cpp b/src/declarative/particles/qsgfollowemitter.cpp index 28a082f776..ba31e8f834 100644 --- a/src/declarative/particles/qsgfollowemitter.cpp +++ b/src/declarative/particles/qsgfollowemitter.cpp @@ -116,8 +116,8 @@ void QSGFollowEmitter::emitWindow(int timeStamp) if(!d || !d->stillAlive()) continue; pt = m_lastEmission[d->index]; - if(pt < d->pv.t) - pt = d->pv.t; + if(pt < d->t) + pt = d->t; if(!effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){ m_lastEmission[d->index] = time;//jump over this time period without emitting, because it's outside @@ -127,45 +127,44 @@ void QSGFollowEmitter::emitWindow(int timeStamp) QSGParticleData* datum = m_system->newDatum(gId2); if(datum){//else, skip this emission datum->e = this;//###useful? - ParticleVertex &p = datum->pv; // Particle timestamp - p.t = pt; - p.lifeSpan = + datum->t = pt; + datum->lifeSpan = (m_particleDuration + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) / 1000.0; // Particle position // Note that burst location doesn't get used for follow emitter - qreal followT = pt - d->pv.t; + qreal followT = pt - d->t; qreal followT2 = followT * followT * 0.5; - qreal sizeOffset = d->pv.size/2;//TODO: Current size? As an option + qreal sizeOffset = d->size/2;//TODO: Current size? As an option //TODO: Set variations //Subtract offset, because PS expects this in emitter coordinates - QRectF boundsRect(d->pv.x - offset.x() + d->pv.sx * followT + d->pv.ax * followT2 - m_emitterXVariation/2, - d->pv.y - offset.y() + d->pv.sy * followT + d->pv.ay * followT2 - m_emitterYVariation/2, + QRectF boundsRect(d->x - offset.x() + d->sx * followT + d->ax * followT2 - m_emitterXVariation/2, + d->y - offset.y() + d->sy * followT + d->ay * followT2 - m_emitterYVariation/2, m_emitterXVariation, m_emitterYVariation); - // QRectF boundsRect(d->pv.x + d->pv.sx * followT + d->pv.ax * followT2 + offset.x() - sizeOffset, - // d->pv.y + d->pv.sy * followT + d->pv.ay * followT2 + offset.y() - sizeOffset, + // QRectF boundsRect(d->x + d->sx * followT + d->ax * followT2 + offset.x() - sizeOffset, + // d->y + d->sy * followT + d->ay * followT2 + offset.y() - sizeOffset, // sizeOffset*2, // sizeOffset*2); QSGParticleExtruder* effectiveEmissionExtruder = m_emissionExtruder ? m_emissionExtruder : m_defaultEmissionExtruder; const QPointF &newPos = effectiveEmissionExtruder->extrude(boundsRect); - p.x = newPos.x(); - p.y = newPos.y(); + datum->x = newPos.x(); + datum->y = newPos.y(); // Particle speed const QPointF &speed = m_speed->sample(newPos); - p.sx = speed.x(); - p.sy = speed.y(); + datum->sx = speed.x(); + datum->sy = speed.y(); // Particle acceleration const QPointF &accel = m_acceleration->sample(newPos); - p.ax = accel.x(); - p.ay = accel.y(); + datum->ax = accel.x(); + datum->ay = accel.y(); // Particle size float sizeVariation = -m_particleSizeVariation @@ -174,8 +173,8 @@ void QSGFollowEmitter::emitWindow(int timeStamp) float size = qMax((qreal)0.0, m_particleSize + sizeVariation); float endSize = qMax((qreal)0.0, sizeAtEnd + sizeVariation); - p.size = size * float(m_emitting); - p.endSize = endSize * float(m_emitting); + datum->size = size * float(m_emitting); + datum->endSize = endSize * float(m_emitting); m_system->emitParticle(datum); } diff --git a/src/declarative/particles/qsggravity.cpp b/src/declarative/particles/qsggravity.cpp index de735da5ad..b1cf3e9481 100644 --- a/src/declarative/particles/qsggravity.cpp +++ b/src/declarative/particles/qsggravity.cpp @@ -64,11 +64,11 @@ bool QSGGravityAffector::affectParticle(QSGParticleData *d, qreal dt) { Q_UNUSED(dt); bool changed = false; - if(d->pv.ax != m_xAcc){ + if(d->ax != m_xAcc){ d->setInstantaneousAX(m_xAcc); changed = true; } - if(d->pv.ay != m_yAcc){ + if(d->ay != m_yAcc){ d->setInstantaneousAY(m_yAcc); changed = true; } diff --git a/src/declarative/particles/qsgimageparticle.cpp b/src/declarative/particles/qsgimageparticle.cpp index 15bc88b4c3..836236c13e 100644 --- a/src/declarative/particles/qsgimageparticle.cpp +++ b/src/declarative/particles/qsgimageparticle.cpp @@ -305,62 +305,6 @@ QSGImageParticle::QSGImageParticle(QSGItem* parent) , m_lastLevel(Unknown) { setFlag(ItemHasContents); - //TODO: Clean up defaults here and in custom - m_defaultUltra = new UltraVertices; - m_defaultSimple = new SimpleVertices; - UltraVertex *vertices = (UltraVertex *) m_defaultUltra; - SimpleVertex *vertices2 = (SimpleVertex *) m_defaultSimple; - for (int i=0; i<4; ++i) { - vertices2[i].x = vertices[i].x = 0; - vertices2[i].y = vertices[i].y = 0; - vertices2[i].t = vertices[i].t = -1; - vertices2[i].lifeSpan = vertices[i].lifeSpan = 0; - vertices2[i].size = vertices[i].size = 0; - vertices2[i].endSize = vertices[i].endSize = 0; - vertices2[i].sx = vertices[i].sx = 0; - vertices2[i].sy = vertices[i].sy = 0; - vertices2[i].ax = vertices[i].ax = 0; - vertices2[i].ay = vertices[i].ay = 0; - vertices[i].xx = 1; - vertices[i].xy = 0; - vertices[i].yx = 0; - vertices[i].yy = 1; - vertices[i].rotation = 0; - vertices[i].rotationSpeed = 0; - vertices[i].autoRotate = 0; - vertices[i].animIdx = -1; - vertices[i].frameDuration = 1; - vertices[i].frameCount = 0; - vertices[i].animT = -1; - vertices[i].color.r = 255; - vertices[i].color.g = 255; - vertices[i].color.b = 255; - vertices[i].color.a = 255; - } - - vertices[0].tx = 0; - vertices[0].ty = 0; - - vertices[1].tx = 1; - vertices[1].ty = 0; - - vertices[2].tx = 0; - vertices[2].ty = 1; - - vertices[3].tx = 1; - vertices[3].ty = 1; - - vertices2[0].tx = 0; - vertices2[0].ty = 0; - - vertices2[1].tx = 1; - vertices2[1].ty = 0; - - vertices2[2].tx = 0; - vertices2[2].ty = 1; - - vertices2[3].tx = 1; - vertices2[3].ty = 1; } QDeclarativeListProperty<QSGSprite> QSGImageParticle::sprites() @@ -411,7 +355,7 @@ void QSGImageParticle::setColor(const QColor &color) return; m_color = color; emit colorChanged(); - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -421,7 +365,7 @@ void QSGImageParticle::setColorVariation(qreal var) return; m_color_variation = var; emit colorVariationChanged(); - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -431,7 +375,7 @@ void QSGImageParticle::setAlphaVariation(qreal arg) m_alphaVariation = arg; emit alphaVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -441,7 +385,7 @@ void QSGImageParticle::setAlpha(qreal arg) m_alpha = arg; emit alphaChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -451,7 +395,7 @@ void QSGImageParticle::setRedVariation(qreal arg) m_redVariation = arg; emit redVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -461,7 +405,7 @@ void QSGImageParticle::setGreenVariation(qreal arg) m_greenVariation = arg; emit greenVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -471,7 +415,7 @@ void QSGImageParticle::setBlueVariation(qreal arg) m_blueVariation = arg; emit blueVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -619,9 +563,34 @@ QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode() QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount); g->setDrawingMode(GL_TRIANGLES); - SimpleVertices *vertices = (SimpleVertices *) g->vertexData(); - for (int p=0; p<m_count; ++p) - memcpy(vertices++, m_defaultSimple, sizeof(SimpleVertices)); + SimpleVertex *vertices = (SimpleVertex *) g->vertexData(); + for (int p=0; p<m_count; ++p){ + for(int i=0; i<4; i++){ + vertices[i].x = m_data[p]->x; + vertices[i].y = m_data[p]->y; + vertices[i].t = m_data[p]->t; + vertices[i].size = m_data[p]->size; + vertices[i].endSize = m_data[p]->endSize; + vertices[i].sx = m_data[p]->sx; + vertices[i].sy = m_data[p]->sy; + vertices[i].ax = m_data[p]->ax; + vertices[i].ay = m_data[p]->ay; + } + //reload(p); + vertices[0].tx = 0; + vertices[0].ty = 0; + + vertices[1].tx = 1; + vertices[1].ty = 0; + + vertices[2].tx = 0; + vertices[2].ty = 1; + + vertices[3].tx = 1; + vertices[3].ty = 1; + + vertices += 4; + } quint16 *indices = g->indexDataAsUShort(); for (int i=0; i<m_count; ++i) { @@ -635,6 +604,9 @@ QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode() indices += 6; } + m_node = new QSGGeometryNode(); + m_node->setGeometry(g); + if (m_material) { delete m_material; m_material = 0; @@ -644,28 +616,24 @@ QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode() m_material->texture = sceneGraphEngine()->createTextureFromImage(image); m_material->texture->setFiltering(QSGTexture::Linear); m_material->framecount = 1; - m_node = new QSGGeometryNode(); - m_node->setGeometry(g); m_node->setMaterial(m_material); m_last_particle = 0; - return m_node; } QSGGeometryNode* QSGImageParticle::buildParticleNode() { if (m_count * 4 > 0xffff) { - printf("UltraParticle: Too many particles... \n");//####Why is this here? + printf("UltraParticle: Too many particles... \n");//### Why is this here? return 0; } if(m_count <= 0) { - printf("UltraParticle: Too few particles... \n"); + qDebug() << "UltraParticle: Too few particles... \n";//XXX: Is now a vaild intermediate state... return 0; } - m_resizePending = false; if(!m_sprites.count() && !m_bloat && m_colortable_name.isEmpty() && m_sizetable_name.isEmpty() @@ -705,38 +673,29 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode() QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount); g->setDrawingMode(GL_TRIANGLES); + m_node = new QSGGeometryNode(); + m_node->setGeometry(g); UltraVertex *vertices = (UltraVertex *) g->vertexData(); - SimpleVertex *oldSimple = (SimpleVertex *) m_lastData;//TODO: Other levels - if(m_lastLevel == 1) - qDebug() << "Theta" << m_lastLevel << oldSimple[0].x << oldSimple[0].y << oldSimple[0].t; for (int p=0; p<m_count; ++p) { - memcpy(vertices, m_defaultUltra, sizeof(UltraVertices)); - if (m_lastLevel == 1 && m_lastCount > p) {//Transplant/IntermediateVertices? - for (int i=0; i<4; ++i) { - vertices[i].x = oldSimple[i].x; - vertices[i].y = oldSimple[i].y; - vertices[i].t = oldSimple[i].t; - vertices[i].lifeSpan = oldSimple[i].lifeSpan; - vertices[i].size = oldSimple[i].size; - vertices[i].endSize = oldSimple[i].endSize; - vertices[i].sx = oldSimple[i].sx; - vertices[i].sy = oldSimple[i].sy; - vertices[i].ax = oldSimple[i].ax; - vertices[i].ay = oldSimple[i].ay; - /* - vertices[i].frameDuration = oldSimple[i].lifeSpan; - vertices[i].frameCount = 1; - vertices[i].animT = oldSimple[i].t; - */ - } - } + reload(p);//reload gets geometry from node + + vertices[0].tx = 0; + vertices[0].ty = 0; + + vertices[1].tx = 1; + vertices[1].ty = 0; + + vertices[2].tx = 0; + vertices[2].ty = 1; + + vertices[3].tx = 1; + vertices[3].ty = 1; vertices += 4; - oldSimple += 4; } - quint16 *indices = g->indexDataAsUShort();//TODO: Speed gains by copying this over if count unchanged? + quint16 *indices = g->indexDataAsUShort(); for (int i=0; i<m_count; ++i) { int o = i * 4; indices[0] = o; @@ -780,8 +739,6 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode() m_spriteEngine->setCount(m_count); } - m_node = new QSGGeometryNode(); - m_node->setGeometry(g); m_node->setMaterial(m_material); m_last_particle = 0; @@ -789,92 +746,11 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode() return m_node; } -void QSGImageParticle::resize(int oldCount, int newCount) -{ - //If perf level changes at the same time as a resize, we reset instead of doing pending resize - if(!m_node) - return; - switch(perfLevel){ - default: - case Sprites: - if(m_spriteEngine) - reset();//TODO: Handle sprite resizeing (have to shuffle the engine too...) - case Coloured: - case Deformable: - case Tabled: - if(!m_resizePending){ - m_resizePendingUltra.resize(oldCount); - UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData(); - for(int i=0; i<oldCount; i++) - m_resizePendingUltra[i] = &particles[i]; - } - groupShuffle(m_resizePendingUltra, m_defaultUltra); - break; - case Simple: - if(!m_resizePending){ - m_resizePendingSimple.resize(oldCount); - SimpleVertices *particles = (SimpleVertices *) m_node->geometry()->vertexData(); - for(int i=0; i<oldCount; i++) - m_resizePendingSimple[i] = &particles[i]; - } - groupShuffle(m_resizePendingSimple, m_defaultSimple); - break; - } - m_resizePending = true; -} - -void QSGImageParticle::performPendingResize() -{ - m_resizePending = false; - if(!m_node) - return; - UltraVertices tmp1[m_count];//###More vast memcpys that will decrease performance - SimpleVertices tmp2[m_count];//###More vast memcpys that will decrease performance - switch(perfLevel){ - case Sprites: - case Coloured: - case Deformable: - case Tabled: - Q_ASSERT(m_resizePendingUltra.size() == m_count);//XXX - for(int i=0; i<m_count; i++){ - Q_ASSERT(m_resizePendingUltra[i]); - tmp1[i] = *m_resizePendingUltra[i]; - } - m_node->setFlag(QSGNode::OwnsGeometry, false); - m_node->geometry()->allocate(m_count*4, m_count*6); - memcpy(m_node->geometry()->vertexData(), tmp1, sizeof(UltraVertices) * m_count); - m_node->setFlag(QSGNode::OwnsGeometry, true); - break; - case Simple: - Q_ASSERT(m_resizePendingSimple.size() == m_count);//XXX - for(int i=0; i<m_count; i++) - tmp2[i] = *m_resizePendingSimple[i]; - m_node->setFlag(QSGNode::OwnsGeometry, false); - m_node->geometry()->allocate(m_count*4, m_count*6); - memcpy(m_node->geometry()->vertexData(), tmp2, sizeof(SimpleVertices) * m_count); - m_node->setFlag(QSGNode::OwnsGeometry, true); - break; - } - quint16 *indices = m_node->geometry()->indexDataAsUShort(); - for (int i=0; i<m_count; ++i) { - int o = i * 4; - indices[0] = o; - indices[1] = o + 1; - indices[2] = o + 2; - indices[3] = o + 1; - indices[4] = o + 3; - indices[5] = o + 2; - indices += 6; - } - m_node->setFlag(QSGNode::OwnsGeometry, true); -} - QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *) { if(m_pleaseReset){ if(m_node){ if(perfLevel == 1){ - qDebug() << "Beta"; m_lastCount = m_node->geometry()->vertexCount() / 4; m_lastData = qMalloc(m_lastCount*sizeof(SimpleVertices)); memcpy(m_lastData, m_node->geometry()->vertexData(), m_lastCount * sizeof(SimpleVertices));//TODO: Multiple levels @@ -889,8 +765,6 @@ QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *) m_material = 0; m_pleaseReset = false; } - if(m_resizePending) - performPendingResize(); if(m_system && m_system->isRunning()) prepareNextFrame(); @@ -904,7 +778,7 @@ QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *) void QSGImageParticle::prepareNextFrame() { - if (m_node == 0){ //TODO: Staggered loading (as emitted) + if (m_node == 0){//TODO: Staggered loading (as emitted) m_node = buildParticleNode(); if(m_node == 0) return; @@ -935,67 +809,14 @@ void QSGImageParticle::prepareNextFrame() } } -template <typename VT> -IntermediateVertices* transplant(IntermediateVertices* iv, VT &v) -{//Deliberate typemangling cast - iv->v1 = (UltraVertex*)&(v.v1); - iv->v2 = (UltraVertex*)&(v.v2); - iv->v3 = (UltraVertex*)&(v.v3); - iv->v4 = (UltraVertex*)&(v.v4); - return iv; -} - -IntermediateVertices* QSGImageParticle::fetchIntermediateVertices(int pos) -{ - //Note that this class ruins typesafety for you. Maybe even thread safety. - //TODO: Something better, possibly with templates or inheritance - static IntermediateVertices iv; - SimpleVertices *sv; - UltraVertices *uv; - switch(perfLevel){ - case Simple: - sv = (SimpleVertices *) m_node->geometry()->vertexData(); - return transplant(&iv, sv[pos]); - case Coloured: - case Deformable: - case Tabled: - case Sprites: - default: - uv = (UltraVertices *) m_node->geometry()->vertexData(); - return transplant(&iv,uv[pos]); - } -} - void QSGImageParticle::reloadColor(const Color4ub &c, QSGParticleData* d) { - UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData(); - int pos = particleTypeIndex(d); - UltraVertices &p = particles[pos]; - p.v1.color = p.v2.color = p.v3.color = p.v4.color = c; + d->color = c; + //TODO: get index for reload - or make function take an index } -void QSGImageParticle::reload(QSGParticleData *d) +void QSGImageParticle::initialize(int idx) { - if (m_node == 0) - return; - - int pos = particleTypeIndex(d); - IntermediateVertices* p = fetchIntermediateVertices(pos); - - //Perhaps we could be more efficient? - vertexCopy(*p->v1, d->pv); - vertexCopy(*p->v2, d->pv); - vertexCopy(*p->v3, d->pv); - vertexCopy(*p->v4, d->pv); -} - -void QSGImageParticle::load(QSGParticleData *d) -{ - if (m_node == 0) - return; - - int pos = particleTypeIndex(d); - IntermediateVertices* p = fetchIntermediateVertices(pos);//Remember this removes typesafety! Color4ub color; qreal redVariation = m_color_variation + m_redVariation; qreal greenVariation = m_color_variation + m_greenVariation; @@ -1003,66 +824,111 @@ void QSGImageParticle::load(QSGParticleData *d) switch(perfLevel){//Fall-through is intended on all of them case Sprites: // Initial Sprite State - p->v1->animT = p->v2->animT = p->v3->animT = p->v4->animT = p->v1->t; - p->v1->animIdx = p->v2->animIdx = p->v3->animIdx = p->v4->animIdx = 0; + m_data[idx]->animT = m_data[idx]->t; + m_data[idx]->animIdx = 0; if(m_spriteEngine){ - m_spriteEngine->startSprite(pos); - p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = m_spriteEngine->spriteFrames(pos); - p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = m_spriteEngine->spriteDuration(pos); + m_spriteEngine->startSprite(idx); + m_data[idx]->frameCount = m_spriteEngine->spriteFrames(idx); + m_data[idx]->frameDuration = m_spriteEngine->spriteDuration(idx); }else{ - p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = 1; - p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = 9999; + m_data[idx]->frameCount = 1; + m_data[idx]->frameDuration = 9999; } case Tabled: case Deformable: //Initial Rotation if(m_xVector){ - const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y)); - p->v1->xx = p->v2->xx = p->v3->xx = p->v4->xx = ret.x(); - p->v1->xy = p->v2->xy = p->v3->xy = p->v4->xy = ret.y(); + const QPointF &ret = m_xVector->sample(QPointF(m_data[idx]->x, m_data[idx]->y)); + m_data[idx]->xx = ret.x(); + m_data[idx]->xy = ret.y(); } if(m_yVector){ - const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y)); - p->v1->yx = p->v2->yx = p->v3->yx = p->v4->yx = ret.x(); - p->v1->yy = p->v2->yy = p->v3->yy = p->v4->yy = ret.y(); + const QPointF &ret = m_yVector->sample(QPointF(m_data[idx]->x, m_data[idx]->y)); + m_data[idx]->yx = ret.x(); + m_data[idx]->yy = ret.y(); } - p->v1->rotation = p->v2->rotation = p->v3->rotation = p->v4->rotation = + m_data[idx]->rotation = (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV; - p->v1->rotationSpeed = p->v2->rotationSpeed = p->v3->rotationSpeed = p->v4->rotationSpeed = + m_data[idx]->rotationSpeed = (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV; - p->v1->autoRotate = p->v2->autoRotate = p->v3->autoRotate = p->v4->autoRotate = m_autoRotation?1.0:0.0; - case Coloured: + m_data[idx]->autoRotate = m_autoRotation?1.0:0.0; + case Colored: //Color initialization // Particle color color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation; color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation; color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation; color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation; - p->v1->color = p->v2->color = p->v3->color = p->v4->color = color; + m_data[idx]->color = color; default: break; } - - vertexCopy(*p->v1, d->pv); - vertexCopy(*p->v2, d->pv); - vertexCopy(*p->v3, d->pv); - vertexCopy(*p->v4, d->pv); } -/* -void QSGImageParticle::verticesUpgrade(void *prev, void *next) +void QSGImageParticle::reload(int idx) { - PerformanceLevel copyLevel = qMin(perfLevel, m_lastLevel); - switch(perfLevel){//Intentional fall-through - case Sprites: - if(copyLevel >= Sprites) - case Tabled: - case Deformable: - case Coloured: + if(!m_node) + return; + + m_node->setFlag(QSGNode::OwnsGeometry, false); + UltraVertex *ultraVertices = (UltraVertex *) m_node->geometry()->vertexData(); + SimpleVertex *simpleVertices = (SimpleVertex *) m_node->geometry()->vertexData(); + switch(perfLevel){ + case Sprites: + ultraVertices += idx*4; + for(int i=0; i<4; i++){ + ultraVertices[i].x = m_data[idx]->x - m_systemOffset.x(); + ultraVertices[i].y = m_data[idx]->y - m_systemOffset.y(); + ultraVertices[i].t = m_data[idx]->t; + ultraVertices[i].lifeSpan = m_data[idx]->lifeSpan; + ultraVertices[i].size = m_data[idx]->size; + ultraVertices[i].endSize = m_data[idx]->endSize; + ultraVertices[i].sx = m_data[idx]->sx; + ultraVertices[i].sy = m_data[idx]->sy; + ultraVertices[i].ax = m_data[idx]->ax; + ultraVertices[i].ay = m_data[idx]->ay; + ultraVertices[i].xx = m_data[idx]->xx; + ultraVertices[i].xy = m_data[idx]->xy; + ultraVertices[i].yx = m_data[idx]->yx; + ultraVertices[i].yy = m_data[idx]->yy; + ultraVertices[i].rotation = m_data[idx]->rotation; + ultraVertices[i].rotationSpeed = m_data[idx]->rotationSpeed; + ultraVertices[i].autoRotate = m_data[idx]->autoRotate; + ultraVertices[i].animIdx = m_data[idx]->animIdx; + ultraVertices[i].frameDuration = m_data[idx]->frameDuration; + ultraVertices[i].frameCount = m_data[idx]->frameCount; + ultraVertices[i].animT = m_data[idx]->animT; + ultraVertices[i].color.r = m_data[idx]->color.r; + ultraVertices[i].color.g = m_data[idx]->color.g; + ultraVertices[i].color.b = m_data[idx]->color.b; + ultraVertices[i].color.a = m_data[idx]->color.a; + } + break; + case Tabled://TODO: Us + case Deformable: + case Colored: + case Simple: + simpleVertices += idx*4; + for(int i=0; i<4; i++){ + simpleVertices[i].x = m_data[idx]->x - m_systemOffset.x(); + simpleVertices[i].y = m_data[idx]->y - m_systemOffset.y(); + simpleVertices[i].t = m_data[idx]->t; + simpleVertices[i].lifeSpan = m_data[idx]->lifeSpan; + simpleVertices[i].size = m_data[idx]->size; + simpleVertices[i].endSize = m_data[idx]->endSize; + simpleVertices[i].sx = m_data[idx]->sx; + simpleVertices[i].sy = m_data[idx]->sy; + simpleVertices[i].ax = m_data[idx]->ax; + simpleVertices[i].ay = m_data[idx]->ay; + } + break; + default: + break; } + m_node->setFlag(QSGNode::OwnsGeometry, true); } -*/ + QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgimageparticle_p.h b/src/declarative/particles/qsgimageparticle_p.h index a644dd4216..dc79c5910e 100644 --- a/src/declarative/particles/qsgimageparticle_p.h +++ b/src/declarative/particles/qsgimageparticle_p.h @@ -57,13 +57,6 @@ class QSGGeometryNode; class QSGSprite; class QSGSpriteEngine; -struct Color4ub { - uchar r; - uchar g; - uchar b; - uchar a; -}; - struct SimpleVertex { float x; float y; @@ -165,8 +158,6 @@ public: explicit QSGImageParticle(QSGItem *parent = 0); virtual ~QSGImageParticle(){} - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); QDeclarativeListProperty<QSGSprite> sprites(); QSGSpriteEngine* spriteEngine() {return m_spriteEngine;} @@ -174,7 +165,7 @@ public: enum PerformanceLevel{//TODO: Expose? Unknown = 0, Simple, - Coloured, + Colored, Deformable, Tabled, Sprites @@ -292,20 +283,19 @@ public slots: void setBloat(bool arg); protected: - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); void reset(); + virtual void initialize(int idx); + virtual void reload(int idx); + + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); void prepareNextFrame(); QSGGeometryNode* buildParticleNode(); QSGGeometryNode* buildSimpleParticleNode(); - void resize(int oldCount, int newCount); - void performPendingResize(); private slots: void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty private: - //template <class T> void verticesUpgrade(IntermediateVertices* prev, T* next);//### Loses typessafety again... - IntermediateVertices* fetchIntermediateVertices(int pos); bool m_do_reset; QUrl m_image_name; @@ -347,13 +337,6 @@ private: PerformanceLevel m_lastLevel; void* m_lastData; int m_lastCount; - - //TODO: Some smart method that scales to multiple types better - bool m_resizePending; - QVector<UltraVertices*> m_resizePendingUltra; - QVector<SimpleVertices*> m_resizePendingSimple; - UltraVertices* m_defaultUltra; - SimpleVertices* m_defaultSimple; }; QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgitemparticle.cpp b/src/declarative/particles/qsgitemparticle.cpp index 1c6a8c4db5..5e324cd43d 100644 --- a/src/declarative/particles/qsgitemparticle.cpp +++ b/src/declarative/particles/qsgitemparticle.cpp @@ -85,12 +85,13 @@ void QSGItemParticle::give(QSGItem *item) //TODO: This } -void QSGItemParticle::load(QSGParticleData* d) +void QSGItemParticle::initialize(int idx) +{ + m_loadables << idx;//defer to other thread +} + +void QSGItemParticle::reload(int idx) { - Q_ASSERT(d); - int pos = particleTypeIndex(d); - m_data[pos] = d; - m_loadables << pos; } void QSGItemParticle::tick() @@ -107,56 +108,41 @@ void QSGItemParticle::tick() m_deletables.clear(); foreach(int pos, m_loadables){ - if(m_stasis.contains(m_items[pos])) + if(m_stasis.contains(m_data[pos]->delegate)) qWarning() << "Current model particles prefers overwrite:false"; //remove old item from the particle that is dying to make room for this one - if(m_items[pos]){ - m_deletables << m_items[pos]; + if(m_data[pos]->delegate){ + m_deletables << m_data[pos]->delegate; m_activeCount--; } - m_items[pos] = 0; + m_data[pos]->delegate = 0; if(!m_pendingItems.isEmpty()){ - m_items[pos] = m_pendingItems.front(); + m_data[pos]->delegate = m_pendingItems.front(); m_pendingItems.pop_front(); }else if(m_delegate){ - m_items[pos] = qobject_cast<QSGItem*>(m_delegate->create(qmlContext(this))); + m_data[pos]->delegate = qobject_cast<QSGItem*>(m_delegate->create(qmlContext(this))); } - if(m_items[pos] && m_data[pos]){//###Data can be zero if creating an item leads to a reset - this screws things up. - m_items[pos]->setX(m_data[pos]->curX() - m_items[pos]->width()/2);//TODO: adjust for system? - m_items[pos]->setY(m_data[pos]->curY() - m_items[pos]->height()/2); - QSGItemParticleAttached* mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(m_items[pos])); + if(m_data[pos]->delegate && m_data[pos]){//###Data can be zero if creating an item leads to a reset - this screws things up. + m_data[pos]->delegate->setX(m_data[pos]->curX() - m_data[pos]->delegate->width()/2);//TODO: adjust for system? + m_data[pos]->delegate->setY(m_data[pos]->curY() - m_data[pos]->delegate->height()/2); + QSGItemParticleAttached* mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(m_data[pos]->delegate)); if(mpa){ mpa->m_mp = this; mpa->attach(); } - m_items[pos]->setParentItem(this); + m_data[pos]->delegate->setParentItem(this); if(m_fade) - m_items[pos]->setOpacity(0.); + m_data[pos]->delegate->setOpacity(0.); m_activeCount++; } } m_loadables.clear(); } -void QSGItemParticle::reload(QSGParticleData* d) -{ - //No-op unless we start copying the data. -} - -void QSGItemParticle::resize(int oldCount, int newCount) -{ - if(!m_system) - return; - groupShuffle(m_items, (QSGItem*)0); - groupShuffle(m_data, (QSGParticleData*)0); -} - void QSGItemParticle::reset() { QSGParticlePainter::reset(); //TODO: Cleanup items? - m_items.fill(0); - m_data.fill(0); m_loadables.clear(); //deletables? } @@ -188,19 +174,18 @@ void QSGItemParticle::prepareNextFrame() //TODO: Size, better fade? for(int i=0; i<count(); i++){ - QSGItem* item = m_items[i]; QSGParticleData* data = m_data[i]; - if(!item || !data) + QSGItem* item = data->delegate; + if(!item) continue; - qreal t = ((timeStamp/1000.0) - data->pv.t) / data->pv.lifeSpan; + qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan; if(m_stasis.contains(item)) { - m_data[i]->pv.t += dt;//Stasis effect + m_data[i]->t += dt;//Stasis effect continue; } if(t >= 1.0){//Usually happens from load m_deletables << item; - m_items[i] = 0; - m_data[i] = 0; + m_data[i]->delegate = 0; m_activeCount--; }else{//Fade if(m_fade){ @@ -214,8 +199,8 @@ void QSGItemParticle::prepareNextFrame() item->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on } } - item->setX(data->curX() - item->width()/2); - item->setY(data->curY() - item->height()/2); + item->setX(data->curX() - item->width()/2 - m_systemOffset.x()); + item->setY(data->curY() - item->height()/2 - m_systemOffset.y()); } } diff --git a/src/declarative/particles/qsgitemparticle_p.h b/src/declarative/particles/qsgitemparticle_p.h index 7cea63baa1..24bbcf97d8 100644 --- a/src/declarative/particles/qsgitemparticle_p.h +++ b/src/declarative/particles/qsgitemparticle_p.h @@ -63,8 +63,6 @@ public: bool fade() const { return m_fade; } virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); static QSGItemParticleAttached *qmlAttachedProperties(QObject *object); QDeclarativeComponent* delegate() const @@ -95,7 +93,8 @@ public slots: protected: virtual void reset(); - virtual void resize(int oldCount, int newCount); + virtual void reload(int idx); + virtual void initialize(int idx); void prepareNextFrame(); private slots: void tick(); @@ -105,9 +104,6 @@ private: bool m_fade; QList<QSGItem*> m_pendingItems; - QVector<QSGItem*> m_items; - QVector<QSGParticleData*> m_data; - QVector<int> m_idx; QList<int> m_available; QSet<QSGItem*> m_stasis; qreal m_lastT; diff --git a/src/declarative/particles/qsgkill.cpp b/src/declarative/particles/qsgkill.cpp index 1321898dc9..eb3a55d402 100644 --- a/src/declarative/particles/qsgkill.cpp +++ b/src/declarative/particles/qsgkill.cpp @@ -52,7 +52,7 @@ bool QSGKillAffector::affectParticle(QSGParticleData *d, qreal dt) { Q_UNUSED(dt); if(d->stillAlive()){ - d->pv.t -= d->pv.lifeSpan + 1; + d->t -= d->lifeSpan + 1; return true; } } diff --git a/src/declarative/particles/qsgmodelparticle.cpp b/src/declarative/particles/qsgmodelparticle.cpp index aba68c6ce4..47b8844ad5 100644 --- a/src/declarative/particles/qsgmodelparticle.cpp +++ b/src/declarative/particles/qsgmodelparticle.cpp @@ -149,26 +149,13 @@ void QSGModelParticle::unfreeze(QSGItem* item) m_stasis.remove(item); } -void QSGModelParticle::load(QSGParticleData* d) +void QSGModelParticle::initialize(int idx) { if(!m_model || !m_model->count()) return; - int pos = particleTypeIndex(d); if(m_available.isEmpty()) return; - if(m_items[pos]){ - if(m_stasis.contains(m_items[pos])) - qWarning() << "Current model particles prefers overwrite:false"; - //remove old item from the particle that is dying to make room for this one - m_deletables << m_items[pos]; - m_available << m_idx[pos]; - m_idx[pos] = -1; - m_items[pos] = 0; - m_data[pos] = 0; - m_activeCount--; - } - m_requests << pos; - m_data[pos] = d; + m_requests << idx; m_activeCount++; } @@ -181,40 +168,42 @@ void QSGModelParticle::processPending() m_deletables.clear(); foreach(int pos, m_requests){ + if(m_data[pos]->delegate){ + if(m_stasis.contains(m_data[pos]->delegate)) + qWarning() << "Current model particles prefers overwrite:false"; + //remove old item from the particle that is dying to make room for this one + m_deletables << m_data[pos]->delegate; + m_available << m_data[pos]->modelIndex; + m_data[pos]->modelIndex = -1; + m_data[pos]->delegate = 0; + m_data[pos] = 0; + m_activeCount--; + } + if(!m_available.isEmpty()){ - m_items[pos] = m_model->item(m_available.first()); - m_idx[pos] = m_available.first(); + m_data[pos]->delegate = m_model->item(m_available.first()); + m_data[pos]->modelIndex = m_available.first(); m_available.pop_front(); - QSGModelParticleAttached* mpa = qobject_cast<QSGModelParticleAttached*>(qmlAttachedPropertiesObject<QSGModelParticle>(m_items[pos])); + QSGModelParticleAttached* mpa = qobject_cast<QSGModelParticleAttached*>(qmlAttachedPropertiesObject<QSGModelParticle>(m_data[pos]->delegate)); if(mpa){ mpa->m_mp = this; mpa->attach(); } - m_items[pos]->setParentItem(this); + m_data[pos]->delegate->setParentItem(this); } } m_requests.clear(); } -void QSGModelParticle::reload(QSGParticleData* d) +void QSGModelParticle::reload(int idx) { //No-op unless we start copying the data. } -void QSGModelParticle::resize(int oldCount, int newCount) -{ - groupShuffle(m_items, (QSGItem *) 0); - groupShuffle(m_data, (QSGParticleData*) 0); - groupShuffle(m_idx, -1); -} - void QSGModelParticle::reset() { QSGParticlePainter::reset(); //TODO: Cleanup items? - m_items.fill(0); - m_data.fill(0); - m_idx.fill(-1); //m_available.clear();//Should this be reset too? //m_pendingItems.clear();//TODO: Should this be done? If so, Emit signal? } @@ -246,20 +235,19 @@ void QSGModelParticle::prepareNextFrame() //TODO: Size, better fade? for(int i=0; i<count(); i++){ - QSGItem* item = m_items[i]; QSGParticleData* data = m_data[i]; - if(!item || !data) + if(!data->delegate) continue; - qreal t = ((timeStamp/1000.0) - data->pv.t) / data->pv.lifeSpan; - if(m_stasis.contains(item)) { - m_data[i]->pv.t += dt;//Stasis effect + qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan; + if(m_stasis.contains(m_data[i]->delegate)) { + m_data[i]->t += dt;//Stasis effect continue; } if(t >= 1.0){//Usually happens from load - m_available << m_idx[i]; - m_deletables << item; - m_idx[i] = -1; - m_items[i] = 0; + m_available << m_data[i]->modelIndex; + m_deletables << m_data[i]->delegate; + m_data[i]->modelIndex = -1; + m_data[i]->delegate = 0; m_data[i] = 0; m_activeCount--; }else{//Fade @@ -269,13 +257,13 @@ void QSGModelParticle::prepareNextFrame() o = t*5; if(t>0.8) o = (1-t)*5; - item->setOpacity(o); + m_data[i]->delegate->setOpacity(o); }else{ - item->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on + m_data[i]->delegate->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on } } - item->setX(data->curX() - item->width()/2); - item->setY(data->curY() - item->height()/2); + m_data[i]->delegate->setX(data->curX() - m_data[i]->delegate->width()/2 - m_systemOffset.x()); + m_data[i]->delegate->setY(data->curY() - m_data[i]->delegate->height()/2 - m_systemOffset.y()); } } diff --git a/src/declarative/particles/qsgmodelparticle_p.h b/src/declarative/particles/qsgmodelparticle_p.h index cef2008b1a..31e4025bb4 100644 --- a/src/declarative/particles/qsgmodelparticle_p.h +++ b/src/declarative/particles/qsgmodelparticle_p.h @@ -74,8 +74,6 @@ public: bool fade() const { return m_fade; } virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); static QSGModelParticleAttached *qmlAttachedProperties(QObject *object); signals: @@ -91,7 +89,8 @@ public slots: void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();} protected: virtual void reset(); - virtual void resize(int oldCount, int newCount); + virtual void reload(int idx); + virtual void initialize(int idx); void prepareNextFrame(); private slots: void updateCount(); @@ -106,9 +105,6 @@ private: bool m_fade; QList<QSGItem*> m_pendingItems; - QVector<QSGItem*> m_items; - QVector<QSGParticleData*> m_data; - QVector<int> m_idx; QList<int> m_available; QSet<QSGItem*> m_stasis; qreal m_lastT; diff --git a/src/declarative/particles/qsgparticlepainter.cpp b/src/declarative/particles/qsgparticlepainter.cpp index 0d369fd4d8..cf1d3c2894 100644 --- a/src/declarative/particles/qsgparticlepainter.cpp +++ b/src/declarative/particles/qsgparticlepainter.cpp @@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE QSGParticlePainter::QSGParticlePainter(QSGItem *parent) : QSGItem(parent), - m_system(0), m_count(0), m_lastStart(0) + m_system(0), m_count(0), m_lastStart(0), m_sentinel(new QSGParticleData) { connect(this, SIGNAL(xChanged()), this, SLOT(calcSystemOffset())); @@ -78,23 +78,70 @@ void QSGParticlePainter::setSystem(QSGParticleSystem *arg) } } -void QSGParticlePainter::load(QSGParticleData*) +void QSGParticlePainter::load(QSGParticleData* d) { + int idx = particleTypeIndex(d); + m_data[idx] = d; + initialize(idx); + reload(idx); } -void QSGParticlePainter::reload(QSGParticleData*) +void QSGParticlePainter::reload(QSGParticleData* d) { + reload(particleTypeIndex(d)); } void QSGParticlePainter::reset() { //Have to every time because what it's emitting may have changed and that affects particleTypeIndex - if(m_system) - updateParticleStarts(); + if(m_system && !m_inResize) + resize(0,1);//###Fix this by making resize take sensible arguments + //###This also means double resets. Make reset not virtual? } -void QSGParticlePainter::resize(int, int) +void QSGParticlePainter::resize(int oldSize, int newSize) { + if(newSize == oldSize)//TODO: What if particles switched so indices change but total count is the same? + return; + + QHash<int, QPair<int, int> > oldStarts(m_particleStarts); + //Update particle starts datastore + m_particleStarts.clear(); + m_lastStart = 0; + QList<int> particleList; + if(m_particles.isEmpty()) + particleList << 0; + foreach(const QString &s, m_particles) + particleList << m_system->m_groupIds[s]; + foreach(int gIdx, particleList){ + QSGParticleGroupData *gd = m_system->m_groupData[gIdx]; + m_particleStarts.insert(gIdx, qMakePair<int, int>(gd->size, m_lastStart)); + m_lastStart += gd->size; + } + + //Shuffle stuff around + //TODO: In place shuffling because it's faster + QVector<QSGParticleData*> oldData(m_data); + QVector<QObject*> oldAttached(m_attachedData); + m_data.clear(); + m_data.resize(m_count); + m_attachedData.resize(m_count); + foreach(int gIdx, particleList){ + QSGParticleGroupData *gd = m_system->m_groupData[gIdx]; + for(int i=0; i<gd->data.size(); i++){//TODO: When group didn't exist before + int newIdx = m_particleStarts[gIdx].second + i; + int oldIdx = oldStarts[gIdx].second + i; + if(i >= oldStarts[gIdx].first || oldData.size() <= oldIdx){ + m_data[newIdx] = m_sentinel; + }else{ + m_data[newIdx] = oldData[oldIdx]; + m_attachedData[newIdx] = oldAttached[oldIdx]; + } + } + } + m_inResize = true; + reset(); + m_inResize = false; } @@ -105,8 +152,7 @@ void QSGParticlePainter::setCount(int c) return; int lastCount = m_count; m_count = c; - resize(lastCount, m_count);//### is virtual needed? Or should I just use the signal? - updateParticleStarts(); + resize(lastCount, m_count); emit countChanged(); } @@ -115,23 +161,6 @@ int QSGParticlePainter::count() return m_count; } - -void QSGParticlePainter::updateParticleStarts() -{ - m_particleStarts.clear(); - m_lastStart = 0; - QList<int> particleList; - if(m_particles.isEmpty()) - particleList << 0; - foreach(const QString &s, m_particles) - particleList << m_system->m_groupIds[s]; - foreach(int gIdx, particleList){ - QSGParticleGroupData *gd = m_system->m_groupData[gIdx]; - m_particleStarts.insert(gIdx, qMakePair<int, int>(gd->size, m_lastStart)); - m_lastStart += gd->size; - } -} - int QSGParticlePainter::particleTypeIndex(QSGParticleData* d) { Q_ASSERT(d && m_particleStarts.contains(d->group));//XXX diff --git a/src/declarative/particles/qsgparticlepainter_p.h b/src/declarative/particles/qsgparticlepainter_p.h index 6657d57501..e506018f53 100644 --- a/src/declarative/particles/qsgparticlepainter_p.h +++ b/src/declarative/particles/qsgparticlepainter_p.h @@ -61,8 +61,9 @@ class QSGParticlePainter : public QSGItem public: explicit QSGParticlePainter(QSGItem *parent = 0); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); + //Data Interface to system + void load(QSGParticleData*); + void reload(QSGParticleData*); void setCount(int c); int count(); QSGParticleSystem* system() const @@ -94,68 +95,38 @@ void setParticles(QStringList arg) } private slots: void calcSystemOffset(); - void updateParticleStarts(); protected: + /* Reset resets all your internal data structures. But anything attached to a particle should + be in attached data. So reset + reloads should have no visible effect. + ###Hunt down all cases where we do a complete reset for convenience and be more targeted + */ virtual void reset(); - virtual void componentComplete(); + virtual void componentComplete(); + //Data interface to painters + QVector<QSGParticleData*> m_data; //Actually stored in arbitrary order, + QVector<QObject*> m_attachedData; //This data will be moved along with m_data in resizes (but you own it) + virtual void initialize(int){} + virtual void reload(int){}//If you need to do something on size changed, check m_data size in this? Or we reset you every time? QSGParticleSystem* m_system; friend class QSGParticleSystem; int m_count; bool m_pleaseReset; QStringList m_particles; - QHash<int,QPair<int, int> > m_particleStarts; //Group, size, idx - int m_lastStart; QPointF m_systemOffset; - template <typename VertexStruct>//just convenience - void vertexCopy(VertexStruct &b, const ParticleVertex& a) - { - b.x = a.x - m_systemOffset.x(); - b.y = a.y - m_systemOffset.y(); - b.t = a.t; - b.lifeSpan = a.lifeSpan; - b.size = a.size; - b.endSize = a.endSize; - b.sx = a.sx; - b.sy = a.sy; - b.ax = a.ax; - b.ay = a.ay; - } - - //###Abstracted primarily for code reuse. Demote to subclasses? - int particleTypeIndex(QSGParticleData*); - virtual void resize(int oldCount, int newCount); - template <typename T> - void groupShuffle(QVector<T> &v, const T& zero)//Must be called inside resize - { - //TODO: In place shuffling because it's faster - QVector<T> v0(v); - v.clear(); - v.resize(m_count); - int lastStart = 0; - QList<int> particleList; - if(m_particles.isEmpty()) - particleList << 0; - foreach(const QString &s, m_particles) - particleList << m_system->m_groupIds[s]; - - foreach(int gIdx, particleList){ - QSGParticleGroupData *gd = m_system->m_groupData[gIdx]; - for(int i=0; i<gd->data.size(); i++){//TODO: When group didn't exist before - int newIdx = lastStart + i;//Have to make the same way as in updateParticleStarts - if(i >= m_particleStarts[gIdx].first || v0.size() <= m_particleStarts[gIdx].second + i) - v[newIdx] = zero; - else - v[newIdx] = v0[m_particleStarts[gIdx].second + i]; - } - lastStart += gd->size; - } - } private: + int m_lastStart; + QHash<int, QPair<int, int> > m_particleStarts; + int particleTypeIndex(QSGParticleData* d);//Now private + void resize(int, int); + + QSGParticleData* m_sentinel; + //QVector<QSGParticleData*> m_shadowData;//For when we implement overwrite: false + bool m_inResize; }; QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index a93f2a5eba..2dc21299cf 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -54,15 +54,33 @@ QSGParticleData::QSGParticleData() , e(0) , index(0) { - pv.x = 0; - pv.y = 0; - pv.t = -1; - pv.size = 0; - pv.endSize = 0; - pv.sx = 0; - pv.sy = 0; - pv.ax = 0; - pv.ay = 0; + x = 0; + y = 0; + t = -1; + size = 0; + endSize = 0; + sx = 0; + sy = 0; + ax = 0; + ay = 0; + xx = 1; + xy = 0; + yx = 0; + yy = 1; + rotation = 0; + rotationSpeed = 0; + autoRotate = 0; + animIdx = -1; + frameDuration = 1; + frameCount = 0; + animT = -1; + color.r = 255; + color.g = 255; + color.b = 255; + color.a = 255; + r = 0; + delegate = 0; + modelIndex = -1; } QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : @@ -275,8 +293,8 @@ void QSGParticleSystem::emitParticle(QSGParticleData* pd) //Account for relative emitter position QPointF offset = this->mapFromItem(pd->e, QPointF(0, 0)); if(!offset.isNull()){ - pd->pv.x += offset.x(); - pd->pv.y += offset.y(); + pd->x += offset.x(); + pd->y += offset.y(); } foreach(QSGParticleAffector *a, m_affectors) @@ -323,107 +341,107 @@ qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p) //sets the x accleration without affecting the instantaneous x velocity or position void QSGParticleData::setInstantaneousAX(qreal ax) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - qreal sx = (pv.sx + t*pv.ax) - t*ax; - qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + qreal sx = (this->sx + t*this->ax) - t*ax; + qreal ex = this->x + this->sx * t + 0.5 * this->ax * t * t; qreal x = ex - t*sx - 0.5 * t*t*ax; - pv.ax = ax; - pv.sx = sx; - pv.x = x; + this->ax = ax; + this->sx = sx; + this->x = x; } //sets the x velocity without affecting the instantaneous x postion void QSGParticleData::setInstantaneousSX(qreal vx) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - qreal sx = vx - t*pv.ax; - qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t; - qreal x = ex - t*sx - 0.5 * t*t*pv.ax; + qreal t = (system->m_timeInt / 1000.0) - this->t; + qreal sx = vx - t*this->ax; + qreal ex = this->x + this->sx * t + 0.5 * this->ax * t * t; + qreal x = ex - t*sx - 0.5 * t*t*this->ax; - pv.sx = sx; - pv.x = x; + this->sx = sx; + this->x = x; } //sets the instantaneous x postion void QSGParticleData::setInstantaneousX(qreal x) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - pv.x = x - t*pv.sx - 0.5 * t*t*pv.ax; + qreal t = (system->m_timeInt / 1000.0) - this->t; + this->x = x - t*this->sx - 0.5 * t*t*this->ax; } //sets the y accleration without affecting the instantaneous y velocity or position void QSGParticleData::setInstantaneousAY(qreal ay) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - qreal sy = (pv.sy + t*pv.ay) - t*ay; - qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + qreal sy = (this->sy + t*this->ay) - t*ay; + qreal ey = this->y + this->sy * t + 0.5 * this->ay * t * t; qreal y = ey - t*sy - 0.5 * t*t*ay; - pv.ay = ay; - pv.sy = sy; - pv.y = y; + this->ay = ay; + this->sy = sy; + this->y = y; } //sets the y velocity without affecting the instantaneous y position void QSGParticleData::setInstantaneousSY(qreal vy) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - //qDebug() << t << (system->m_timeInt/1000.0) << pv.x << pv.sx << pv.ax << pv.x + pv.sx * t + 0.5 * pv.ax * t * t; - qreal sy = vy - t*pv.ay; - qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t; - qreal y = ey - t*sy - 0.5 * t*t*pv.ay; - - pv.sy = sy; - pv.y = y; + qreal t = (system->m_timeInt / 1000.0) - this->t; + //qDebug() << t << (system->m_timeInt/1000.0) << this->x << this->sx << this->ax << this->x + this->sx * t + 0.5 * this->ax * t * t; + qreal sy = vy - t*this->ay; + qreal ey = this->y + this->sy * t + 0.5 * this->ay * t * t; + qreal y = ey - t*sy - 0.5 * t*t*this->ay; + + this->sy = sy; + this->y = y; } //sets the instantaneous Y position void QSGParticleData::setInstantaneousY(qreal y) { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - pv.y = y - t*pv.sy - 0.5 * t*t*pv.ay; + qreal t = (system->m_timeInt / 1000.0) - this->t; + this->y = y - t*this->sy - 0.5 * t*t*this->ay; } qreal QSGParticleData::curX() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.x + pv.sx * t + 0.5 * pv.ax * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return this->x + this->sx * t + 0.5 * this->ax * t * t; } qreal QSGParticleData::curSX() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.sx + t*pv.ax; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return this->sx + t*this->ax; } qreal QSGParticleData::curY() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.y + pv.sy * t + 0.5 * pv.ay * t * t; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return y + sy * t + 0.5 * ay * t * t; } qreal QSGParticleData::curSY() const { - qreal t = (system->m_timeInt / 1000.0) - pv.t; - return pv.sy + t*pv.ay; + qreal t = (system->m_timeInt / 1000.0) - this->t; + return sy + t*ay; } void QSGParticleData::debugDump() { qDebug() << "Particle" << group - << "Pos: " << pv.x << "," << pv.y - << "Vel: " << pv.sx << "," << pv.sy - << "Acc: " << pv.ax << "," << pv.ay - << "Size: " << pv.size << "," << pv.endSize - << "Time: " << pv.t << "," <<pv.lifeSpan; + << "Pos: " << x << "," << y + << "Vel: " << sx << "," << sy + << "Acc: " << ax << "," << ay + << "Size: " << size << "," << endSize + << "Time: " << t << "," <<lifeSpan; } bool QSGParticleData::stillAlive() { if(!system) return false; - return (pv.t + pv.lifeSpan) > (system->m_timeInt/1000.0); + return (t + lifeSpan) > (system->m_timeInt/1000.0); } QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h index 4c690ff7a8..45b4e164f1 100644 --- a/src/declarative/particles/qsgparticlesystem_p.h +++ b/src/declarative/particles/qsgparticlesystem_p.h @@ -173,28 +173,18 @@ private: QSignalMapper m_emitterMapper; }; -//TODO: Clean up all this into ParticleData - -struct ParticleVertex { - float x; - float y; - float t; - float lifeSpan; - float size; - float endSize; - float sx; - float sy; - float ax; - float ay; - //TODO: Need opacity over life control. More variable size over life? +struct Color4ub { + uchar r; + uchar g; + uchar b; + uchar a; }; class QSGParticleData{ public: + //TODO: QObject like memory management (without the cost, just attached to system) QSGParticleData(); - ParticleVertex pv; - //Convenience functions for working backwards, because parameters are from the start of particle life //If setting multiple parameters at once, doing the conversion yourself will be faster. @@ -222,6 +212,35 @@ public: QSGParticleSystem* system; int index; + //General Position Stuff + float x; + float y; + float t; + float lifeSpan; + float size; + float endSize; + float sx; + float sy; + float ax; + float ay; + + //Other stuff, now universally shared + Color4ub color; + float xx; + float xy; + float yx; + float yy; + float rotation; + float rotationSpeed; + float autoRotate;//Assume that GPUs prefer floats to bools + float animIdx; + float frameDuration; + float frameCount; + float animT; + float r; + QSGItem* delegate; + int modelIndex; + void debugDump(); bool stillAlive(); }; diff --git a/src/declarative/particles/qsgpointattractor.cpp b/src/declarative/particles/qsgpointattractor.cpp index 4c675237ba..0ee2fa4c27 100644 --- a/src/declarative/particles/qsgpointattractor.cpp +++ b/src/declarative/particles/qsgpointattractor.cpp @@ -70,17 +70,17 @@ bool QSGPointAttractorAffector::affectParticle(QSGParticleData *d, qreal dt) dy = ds * sin(theta); switch(m_physics){ case Position: - d->pv.x = (d->pv.x + dx); - d->pv.y = (d->pv.y + dy); + d->x = (d->x + dx); + d->y = (d->y + dy); break; case Acceleration: - d->setInstantaneousAX(d->pv.ax + dx); - d->setInstantaneousAY(d->pv.ay + dy); + d->setInstantaneousAX(d->ax + dx); + d->setInstantaneousAY(d->ay + dy); break; case Velocity: //also default default: - d->setInstantaneousSX(d->pv.sx + dx); - d->setInstantaneousSY(d->pv.sy + dy); + d->setInstantaneousSX(d->sx + dx); + d->setInstantaneousSY(d->sy + dy); } return true; diff --git a/src/declarative/particles/qsgwander.cpp b/src/declarative/particles/qsgwander.cpp index 6e56d6a05b..26bea4ee04 100644 --- a/src/declarative/particles/qsgwander.cpp +++ b/src/declarative/particles/qsgwander.cpp @@ -116,10 +116,10 @@ bool QSGWanderAffector::affectParticle(QSGParticleData* data, qreal dt) case Position: newX = data->curX() + dx; if(m_xVariance > qAbs(newX) ) - data->pv.x += dx; + data->x += dx; newY = data->curY() + dy; if(m_yVariance > qAbs(newY) ) - data->pv.y += dy; + data->y += dy; break; default: case Velocity: @@ -131,10 +131,10 @@ bool QSGWanderAffector::affectParticle(QSGParticleData* data, qreal dt) data->setInstantaneousSY(newY); break; case Acceleration: - newX = data->pv.ax + dx; + newX = data->ax + dx; if(m_xVariance > qAbs(newX) ) data->setInstantaneousAX(newX); - newY = data->pv.ay + dy; + newY = data->ay + dy; if(m_yVariance > qAbs(newY) ) data->setInstantaneousAY(newY); break; |