diff options
Diffstat (limited to 'src/declarative/particles')
22 files changed, 660 insertions, 714 deletions
diff --git a/src/declarative/particles/qsgcustomparticle.cpp b/src/declarative/particles/qsgcustomparticle.cpp index 808ff1c427..09cfdda143 100644 --- a/src/declarative/particles/qsgcustomparticle.cpp +++ b/src/declarative/particles/qsgcustomparticle.cpp @@ -44,16 +44,8 @@ #include <cstdlib> QT_BEGIN_NAMESPACE -/* - "uniform highp mat4 qt_ModelViewProjectionMatrix; \n" - "attribute highp vec4 qt_Vertex; \n" - "attribute highp vec2 qt_MultiTexCoord0; \n" - "varying highp vec2 qt_TexCoord0; \n" - "void main() { \n" - " qt_TexCoord0 = qt_MultiTexCoord0; \n" - " gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex; \n" - "}"; -*/ + +//TODO: Can we make the code such that you don't have to copy the whole vertex shader just to add one little calculation? //Includes comments because the code isn't self explanatory static const char qt_particles_default_vertex_code[] = "attribute highp vec2 vPos; \n" @@ -86,23 +78,6 @@ static const char qt_particles_default_fragment_code[] =//TODO: Default frag req " gl_FragColor = texture2D(source, fTex) * qt_Opacity; \n" "}"; -/* -static const char qt_particles_default_vertex_code[] = - "attribute highp vec2 vPos; \n" - "attribute highp vec2 vTex; \n" - "uniform highp mat4 qt_ModelViewProjectionMatrix; \n" - "void main() { \n" - " highp float currentSize = 1000.0; \n" - " highp vec2 pos = vec2(100.0,100.0) \n" - " - currentSize / 2. + currentSize * vTex; // adjust size \n" - " gl_Position = qt_ModelViewProjectionMatrix * vec4(pos.x, pos.y, 0, 1); \n" - "}"; -static const char qt_particles_default_fragment_code[] =//TODO: Default frag requires source? - "void main() { \n" - " gl_FragColor = vec4(0,255,0,255); \n" - "}"; -*/ - static const char qt_position_attribute_name[] = "qt_Vertex"; static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0"; @@ -199,12 +174,6 @@ void QSGCustomParticle::setVertexShader(const QByteArray &code) emit vertexShaderChanged(); } -void QSGCustomParticle::setCount(int c) -{ - QSGParticlePainter::setCount(c); - m_pleaseReset = true; -} - void QSGCustomParticle::reset() { disconnectPropertySignals(); @@ -437,7 +406,6 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNode() return 0; } - //Create Particle Geometry int vCount = m_count * 4; int iCount = m_count * 6; @@ -445,21 +413,7 @@ 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? - 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 = r; - } - + reload(p); vertices[0].tx = 0; vertices[0].ty = 0; @@ -471,7 +425,6 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNode() vertices[3].tx = 1; vertices[3].ty = 1; - vertices += 4; } quint16 *indices = g->indexDataAsUShort(); @@ -493,23 +446,6 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNode() node->setGeometry(g); node->setMaterial(&m_material); - /* - //For debugging, just use grid vertices like ShaderEffect - node->setGeometry(0); - QSGShaderEffectMesh* mesh = new QSGGridMesh(); - node->setFlag(QSGNode::OwnsGeometry, false); - - qDebug() << m_source.attributeNames; - QSGGeometry* geometry = node->geometry(); - geometry = mesh->updateGeometry(geometry, m_source.attributeNames, QRectF(0,0,width(),height())); - if(!geometry) - qDebug() << "Should have written the error handling"; - else - qDebug() << "Mesh Loaded"; - node->setGeometry(geometry); - qDebug() << QString("INIT") << geometry << (QObject*)node; - node->setFlag(QSGNode::OwnsGeometry, true); - */ QSGShaderEffectProgram s = m_source; if (s.fragmentCode.isEmpty()) s.fragmentCode = qt_particles_default_fragment_code; @@ -554,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 95144ef638..50ff37a2a0 100644 --- a/src/declarative/particles/qsgcustomparticle_p.h +++ b/src/declarative/particles/qsgcustomparticle_p.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QSGNode; - +struct PlainVertices; //Genealogy: Hybrid of UltraParticle and ShaderEffectItem class QSGCustomParticle : public QSGParticlePainter { @@ -62,9 +62,6 @@ class QSGCustomParticle : public QSGParticlePainter public: explicit QSGCustomParticle(QSGItem* parent=0); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); - virtual void setCount(int c); QByteArray fragmentShader() const { return m_source.fragmentCode; } void setFragmentShader(const QByteArray &code); @@ -78,20 +75,26 @@ 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); void disconnectPropertySignals(); void connectPropertySignals(); void reset(); + void resize(int oldCount, int newCount); void updateProperties(); void lookThroughShaderCode(const QByteArray &code); virtual void componentComplete(); QSGShaderEffectNode *buildCustomNode(); + void performPendingResize(); private: void buildData(); + bool m_pleaseReset; bool m_dirtyData; QSGShaderEffectProgram m_source; @@ -105,6 +108,7 @@ private: QSGShaderEffectMaterial m_material; QSGShaderEffectNode* m_node; qreal m_lastTime; + }; 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 442cff9ec8..ba31e8f834 100644 --- a/src/declarative/particles/qsgfollowemitter.cpp +++ b/src/declarative/particles/qsgfollowemitter.cpp @@ -54,6 +54,7 @@ QSGFollowEmitter::QSGFollowEmitter(QSGItem *parent) : , m_emissionExtruder(0) , m_defaultEmissionExtruder(new QSGParticleExtruder(this)) { + //TODO: If followed increased their size connect(this, SIGNAL(followChanged(QString)), this, SLOT(recalcParticlesPerSecond())); connect(this, SIGNAL(particleDurationChanged(int)), @@ -67,7 +68,7 @@ void QSGFollowEmitter::recalcParticlesPerSecond(){ return; m_followCount = m_system->m_groupData[m_system->m_groupIds[m_follow]]->size; if(!m_followCount){ - setParticlesPerSecond(1000);//XXX: Fix this horrendous hack, needed so they aren't turned off from start (causes crashes - test that when gone you don't crash with 0 PPPS) + setParticlesPerSecond(1);//XXX: Fix this horrendous hack, needed so they aren't turned off from start (causes crashes - test that when gone you don't crash with 0 PPPS) }else{ setParticlesPerSecond(m_particlesPerParticlePerSecond * m_followCount); m_lastEmission.resize(m_followCount); @@ -111,61 +112,59 @@ void QSGFollowEmitter::emitWindow(int timeStamp) int gId = m_system->m_groupIds[m_follow]; int gId2 = m_system->m_groupIds[m_particle]; - for(int i=0; i<m_system->m_groupData[gId]->size; i++){ - pt = m_lastEmission[i]; - QSGParticleData* d = m_system->m_data[i + m_system->m_groupData[gId]->start]; + foreach(QSGParticleData *d, m_system->m_groupData[gId]->data){ if(!d || !d->stillAlive()) continue; - if(pt < d->pv.t) - pt = d->pv.t; + pt = m_lastEmission[d->index]; + if(pt < d->t) + pt = d->t; if(!effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){ - m_lastEmission[i] = time;//jump over this time period without emitting, because it's outside + m_lastEmission[d->index] = time;//jump over this time period without emitting, because it's outside continue; } while(pt < time || !m_burstQueue.isEmpty()){ 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); } @@ -187,7 +186,7 @@ void QSGFollowEmitter::emitWindow(int timeStamp) pt += particleRatio; } } - m_lastEmission[i] = pt; + m_lastEmission[d->index] = pt; } m_lastTimeStamp = time; 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 c9df5f4dbd..836236c13e 100644 --- a/src/declarative/particles/qsgimageparticle.cpp +++ b/src/declarative/particles/qsgimageparticle.cpp @@ -355,7 +355,7 @@ void QSGImageParticle::setColor(const QColor &color) return; m_color = color; emit colorChanged(); - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -365,7 +365,7 @@ void QSGImageParticle::setColorVariation(qreal var) return; m_color_variation = var; emit colorVariationChanged(); - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -375,7 +375,7 @@ void QSGImageParticle::setAlphaVariation(qreal arg) m_alphaVariation = arg; emit alphaVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -385,7 +385,7 @@ void QSGImageParticle::setAlpha(qreal arg) m_alpha = arg; emit alphaChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -395,7 +395,7 @@ void QSGImageParticle::setRedVariation(qreal arg) m_redVariation = arg; emit redVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -405,7 +405,7 @@ void QSGImageParticle::setGreenVariation(qreal arg) m_greenVariation = arg; emit greenVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -415,7 +415,7 @@ void QSGImageParticle::setBlueVariation(qreal arg) m_blueVariation = arg; emit blueVariationChanged(arg); } - if(perfLevel < Coloured) + if(perfLevel < Colored) reset(); } @@ -498,11 +498,6 @@ void QSGImageParticle::setBloat(bool arg) if(perfLevel < 9999) reset(); } -void QSGImageParticle::setCount(int c) -{ - QSGParticlePainter::setCount(c); - m_pleaseReset = true; -} void QSGImageParticle::reset() { @@ -569,20 +564,19 @@ QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode() g->setDrawingMode(GL_TRIANGLES); SimpleVertex *vertices = (SimpleVertex *) g->vertexData(); - for (int p=0; p<m_count; ++p) { - 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; + 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; @@ -610,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; @@ -619,24 +616,21 @@ 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; } @@ -679,70 +673,12 @@ 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) { - - if (m_lastLevel == 1) {//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].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 = 0; - vertices[i].frameDuration = oldSimple[i].lifeSpan; - vertices[i].frameCount = 1; - vertices[i].animT = oldSimple[i].t; - vertices[i].color.r = 255; - vertices[i].color.g = 255; - vertices[i].color.b = 255; - vertices[i].color.a = 255; - } - } else { - 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].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 = 0;//TODO:Some things never get used uninitialized. Consider dropping them here? - vertices[i].color.g = 0; - vertices[i].color.b = 0; - vertices[i].color.a = 0; - } - } + reload(p);//reload gets geometry from node vertices[0].tx = 0; vertices[0].ty = 0; @@ -757,10 +693,9 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode() 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; @@ -804,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; @@ -818,9 +751,9 @@ QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *) if(m_pleaseReset){ if(m_node){ if(perfLevel == 1){ - qDebug() << "Beta"; - m_lastData = qMalloc(m_count*sizeof(SimpleVertices));//TODO: Account for count_changed possibility - memcpy(m_lastData, m_node->geometry()->vertexData(), m_count * sizeof(SimpleVertices));//TODO: Multiple levels + 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 } m_lastLevel = perfLevel; delete m_node; @@ -845,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; @@ -876,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; -} - -void QSGImageParticle::reload(QSGParticleData *d) -{ - 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); + d->color = c; + //TODO: get index for reload - or make function take an index } -void QSGImageParticle::load(QSGParticleData *d) +void QSGImageParticle::initialize(int idx) { - 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; @@ -944,50 +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; } +} + +void QSGImageParticle::reload(int idx) +{ + 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; + } - vertexCopy(*p->v1, d->pv); - vertexCopy(*p->v2, d->pv); - vertexCopy(*p->v3, d->pv); - vertexCopy(*p->v4, d->pv); + 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 c6ec4c2c6a..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,9 +158,6 @@ public: explicit QSGImageParticle(QSGItem *parent = 0); virtual ~QSGImageParticle(){} - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); - virtual void setCount(int c); QDeclarativeListProperty<QSGSprite> sprites(); QSGSpriteEngine* spriteEngine() {return m_spriteEngine;} @@ -175,7 +165,7 @@ public: enum PerformanceLevel{//TODO: Expose? Unknown = 0, Simple, - Coloured, + Colored, Deformable, Tabled, Sprites @@ -293,8 +283,11 @@ 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(); @@ -303,8 +296,6 @@ private slots: void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty private: - //void vertexCopy(UltraVertex &b,const ParticleVertex& a); - IntermediateVertices* fetchIntermediateVertices(int pos); bool m_do_reset; QUrl m_image_name; @@ -345,6 +336,7 @@ private: PerformanceLevel m_lastLevel; void* m_lastData; + int m_lastCount; }; QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgitemparticle.cpp b/src/declarative/particles/qsgitemparticle.cpp index 42f0062148..5e324cd43d 100644 --- a/src/declarative/particles/qsgitemparticle.cpp +++ b/src/declarative/particles/qsgitemparticle.cpp @@ -85,11 +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) { - int pos = particleTypeIndex(d); - m_data[pos] = d; - m_loadables << pos; } void QSGItemParticle::tick() @@ -106,63 +108,43 @@ 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_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::setCount(int c) -{ - QSGParticlePainter::setCount(c);//###Do we need our own? - m_particleCount = c; - reset(); -} - -int QSGItemParticle::count() -{ - return m_particleCount; -} - void QSGItemParticle::reset() { QSGParticlePainter::reset(); //TODO: Cleanup items? - m_items.resize(m_particleCount); - m_data.resize(m_particleCount); - m_items.fill(0); - m_data.fill(0); - //m_pendingItems.clear();//TODO: Should this be done? If so, Emit signal? + m_loadables.clear(); + //deletables? } @@ -191,20 +173,19 @@ void QSGItemParticle::prepareNextFrame() return; //TODO: Size, better fade? - for(int i=0; i<m_particleCount; i++){ - QSGItem* item = m_items[i]; + for(int i=0; i<count(); 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){ @@ -218,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 3b7db519de..24bbcf97d8 100644 --- a/src/declarative/particles/qsgitemparticle_p.h +++ b/src/declarative/particles/qsgitemparticle_p.h @@ -63,10 +63,6 @@ public: bool fade() const { return m_fade; } virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); - virtual void setCount(int c); - virtual int count(); static QSGItemParticleAttached *qmlAttachedProperties(QObject *object); QDeclarativeComponent* delegate() const @@ -97,19 +93,17 @@ public slots: protected: virtual void reset(); + virtual void reload(int idx); + virtual void initialize(int idx); void prepareNextFrame(); private slots: void tick(); private: QList<QSGItem* > m_deletables; QList< int > m_loadables; - int m_particleCount; 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 f87c0d31b9..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,48 +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::setCount(int c) -{ - QSGParticlePainter::setCount(c);//###Do we need our own? - m_particleCount = c; - reset(); -} - -int QSGModelParticle::count() -{ - return m_particleCount; -} - void QSGModelParticle::reset() { QSGParticlePainter::reset(); //TODO: Cleanup items? - m_items.resize(m_particleCount); - m_data.resize(m_particleCount); - m_idx.resize(m_particleCount); - 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? } @@ -253,21 +234,20 @@ void QSGModelParticle::prepareNextFrame() return; //TODO: Size, better fade? - for(int i=0; i<m_particleCount; i++){ - QSGItem* item = m_items[i]; + for(int i=0; i<count(); 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 @@ -277,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 04533a73ce..31e4025bb4 100644 --- a/src/declarative/particles/qsgmodelparticle_p.h +++ b/src/declarative/particles/qsgmodelparticle_p.h @@ -74,10 +74,6 @@ public: bool fade() const { return m_fade; } virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); - virtual void setCount(int c); - virtual int count(); static QSGModelParticleAttached *qmlAttachedProperties(QObject *object); signals: @@ -93,6 +89,8 @@ public slots: void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();} protected: virtual void reset(); + virtual void reload(int idx); + virtual void initialize(int idx); void prepareNextFrame(); private slots: void updateCount(); @@ -104,13 +102,9 @@ private: QVariant m_dataSource; QList<QSGItem*> m_deletables; QList< int > m_requests; - int m_particleCount; 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/qsgparticleaffector.cpp b/src/declarative/particles/qsgparticleaffector.cpp index 96c5cfb25b..5b0936cc40 100644 --- a/src/declarative/particles/qsgparticleaffector.cpp +++ b/src/declarative/particles/qsgparticleaffector.cpp @@ -79,22 +79,22 @@ void QSGParticleAffector::affectSystem(qreal dt) m_groups << m_system->m_groupIds[p];//###Can this occur before group ids are properly assigned? m_updateIntSet = false; } - //foreach(ParticleData* d, m_system->m_data){ - for(int i=0; i<m_system->m_particle_count; i++){ - QSGParticleData* d = m_system->m_data[i]; - if(!d || (m_onceOff && m_onceOffed.contains(d->systemIndex))) - continue; - if(m_groups.isEmpty() || m_groups.contains(d->group)){ - //Need to have previous location for affected. if signal || shape might be faster? - QPointF curPos = QPointF(d->curX(), d->curY()); - if(width() == 0 || height() == 0 - || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()),curPos)){ - if(affectParticle(d, dt)){ - m_system->m_needsReset << d; - if(m_onceOff) - m_onceOffed << d->systemIndex; - if(m_signal) - emit affected(curPos.x(), curPos.y()); + foreach(QSGParticleGroupData* gd, m_system->m_groupData){ + foreach(QSGParticleData* d, gd->data){ + if(!d || (m_onceOff && m_onceOffed.contains(qMakePair(d->group, d->index)))) + continue; + if(m_groups.isEmpty() || m_groups.contains(d->group)){ + //Need to have previous location for affected. if signal || shape might be faster? + QPointF curPos = QPointF(d->curX(), d->curY()); + if(width() == 0 || height() == 0 + || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()),curPos)){ + if(affectParticle(d, dt)){ + m_system->m_needsReset << d; + if(m_onceOff) + m_onceOffed << qMakePair(d->group, d->index); + if(m_signal) + emit affected(curPos.x(), curPos.y()); + } } } } @@ -108,10 +108,10 @@ bool QSGParticleAffector::affectParticle(QSGParticleData *d, qreal dt) return false; } -void QSGParticleAffector::reset(int idx) +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) - m_onceOffed.remove(idx); + m_onceOffed.remove(qMakePair(pd->group, pd->index)); } void QSGParticleAffector::updateOffsets() diff --git a/src/declarative/particles/qsgparticleaffector_p.h b/src/declarative/particles/qsgparticleaffector_p.h index b299158069..7418760941 100644 --- a/src/declarative/particles/qsgparticleaffector_p.h +++ b/src/declarative/particles/qsgparticleaffector_p.h @@ -65,7 +65,7 @@ class QSGParticleAffector : public QSGItem public: explicit QSGParticleAffector(QSGItem *parent = 0); virtual void affectSystem(qreal dt); - virtual void reset(int systemIdx);//As some store their own data per idx? + virtual void reset(QSGParticleData*);//As some store their own data per particle? QSGParticleSystem* system() const { return m_system; @@ -108,7 +108,7 @@ signals: void shapeChanged(QSGParticleExtruder* arg); - void affected(qreal x, qreal y);//###Idx too? + void affected(qreal x, qreal y); void signalChanged(bool arg); public slots: @@ -174,7 +174,7 @@ protected: QPointF m_offset; private: QSet<int> m_groups; - QSet<int> m_onceOffed; + QSet<QPair<int, int> > m_onceOffed; bool m_updateIntSet; bool m_onceOff; diff --git a/src/declarative/particles/qsgparticlepainter.cpp b/src/declarative/particles/qsgparticlepainter.cpp index a5e8c0a3e6..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_system(0), m_count(0), m_lastStart(0), m_sentinel(new QSGParticleData) { connect(this, SIGNAL(xChanged()), this, SLOT(calcSystemOffset())); @@ -67,7 +67,7 @@ void QSGParticlePainter::setSystem(QSGParticleSystem *arg) if (m_system != arg) { m_system = arg; if(m_system){ - m_system->registerParticleType(this); + m_system->registerParticlePainter(this); connect(m_system, SIGNAL(xChanged()), this, SLOT(calcSystemOffset())); connect(m_system, SIGNAL(yChanged()), @@ -78,26 +78,81 @@ 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 && !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 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; } + void QSGParticlePainter::setCount(int c) { + Q_ASSERT(c >= 0); //XXX if(c == m_count) return; + int lastCount = m_count; m_count = c; + resize(lastCount, m_count); emit countChanged(); } @@ -106,15 +161,11 @@ int QSGParticlePainter::count() return m_count; } - int QSGParticlePainter::particleTypeIndex(QSGParticleData* d) { - if(!m_particleStarts.contains(d->group)){ - m_particleStarts.insert(d->group, m_lastStart); - m_lastStart += m_system->m_groupData[d->group]->size; - } - int ret = m_particleStarts[d->group] + d->particleIndex; - Q_ASSERT(ret >=0 && ret < m_count);//XXX: Possibly shouldn't assert, but bugs here were hard to find in the past + Q_ASSERT(d && m_particleStarts.contains(d->group));//XXX + int ret = m_particleStarts[d->group].second + d->index; + Q_ASSERT(ret >=0 && ret < m_count);//XXX:shouldn't assert, but bugs here were hard to find in the past return ret; } @@ -129,8 +180,8 @@ void QSGParticlePainter::calcSystemOffset() //Reload all particles//TODO: Necessary? foreach(const QString &g, m_particles){ int gId = m_system->m_groupIds[g]; - for(int i=0; i<m_system->m_groupData[gId]->size; i++) - reload(m_system->m_data[m_system->m_groupData[gId]->start + i]); + 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 8f1e13b70f..e506018f53 100644 --- a/src/declarative/particles/qsgparticlepainter_p.h +++ b/src/declarative/particles/qsgparticlepainter_p.h @@ -61,10 +61,11 @@ class QSGParticlePainter : public QSGItem public: explicit QSGParticlePainter(QSGItem *parent = 0); - virtual void load(QSGParticleData*); - virtual void reload(QSGParticleData*); - virtual void setCount(int c); - virtual int count(); + //Data Interface to system + void load(QSGParticleData*); + void reload(QSGParticleData*); + void setCount(int c); + int count(); QSGParticleSystem* system() const { return m_system; @@ -76,7 +77,6 @@ public: return m_particles; } - int particleTypeIndex(QSGParticleData*); signals: void countChanged(); void systemChanged(QSGParticleSystem* arg); @@ -95,40 +95,38 @@ void setParticles(QStringList arg) } private slots: void calcSystemOffset(); + 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 QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *){ -// qDebug() << "Shouldn't be here..." << this; -// return 0; -// } + 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,int> m_particleStarts; - int m_lastStart; QPointF m_systemOffset; - template <typename VertexStruct> - 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; - } 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 4a8f75bb04..2dc21299cf 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -52,18 +52,35 @@ QT_BEGIN_NAMESPACE QSGParticleData::QSGParticleData() : group(0) , e(0) - , particleIndex(0) - , systemIndex(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) : @@ -71,174 +88,202 @@ QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : , m_startTime(0), m_overwrite(false) , m_componentComplete(false) { - m_groupIds = QHash<QString, int>(); + QSGParticleGroupData* gd = new QSGParticleGroupData;//Default group + m_groupData.insert(0,gd); + m_groupIds.insert("",0); + m_nextGroupId = 1; + + connect(&m_painterMapper, SIGNAL(mapped(QObject*)), + this, SLOT(loadPainter(QObject*))); } -void QSGParticleSystem::registerParticleType(QSGParticlePainter* p) +void QSGParticleSystem::registerParticlePainter(QSGParticlePainter* p) { - m_particles << QPointer<QSGParticlePainter>(p);//###Set or uniqueness checking? - reset(); + //TODO: a way to Unregister emitters, painters and affectors + m_particlePainters << QPointer<QSGParticlePainter>(p);//###Set or uniqueness checking? + connect(p, SIGNAL(particlesChanged(QStringList)), + &m_painterMapper, SLOT(map())); + loadPainter(p); + p->update();//###Initial update here? } void QSGParticleSystem::registerParticleEmitter(QSGParticleEmitter* e) { m_emitters << QPointer<QSGParticleEmitter>(e);//###How to get them out? connect(e, SIGNAL(particleCountChanged()), - this, SLOT(countChanged())); + this, SLOT(emittersChanged())); connect(e, SIGNAL(particleChanged(QString)), - this, SLOT(countChanged())); - reset(); + this, SLOT(emittersChanged())); + emittersChanged(); + e->reset();//Start, so that starttime factors appropriately } void QSGParticleSystem::registerParticleAffector(QSGParticleAffector* a) { m_affectors << QPointer<QSGParticleAffector>(a); - //reset();//TODO: Slim down the huge batch of resets at the start } -void QSGParticleSystem::countChanged() +void QSGParticleSystem::loadPainter(QObject *p) { - reset();//Need to give Particles new Count -} + if(!m_componentComplete) + return; -void QSGParticleSystem::setRunning(bool arg) -{ - if (m_running != arg) { - m_running = arg; - emit runningChanged(arg); - reset(); + QSGParticlePainter* painter = qobject_cast<QSGParticlePainter*>(p); + Q_ASSERT(painter);//XXX + foreach(QSGParticleGroupData* sg, m_groupData) + sg->painters.remove(painter); + int particleCount = 0; + if(painter->particles().isEmpty()){//Uses default particle + particleCount += m_groupData[0]->size; + m_groupData[0]->painters << painter; + }else{ + foreach(const QString &group, painter->particles()){ + particleCount += m_groupData[m_groupIds[group]]->size; + m_groupData[m_groupIds[group]]->painters << painter; + } } + painter->setCount(particleCount); + painter->update();//###Initial update here? + return; } -void QSGParticleSystem::componentComplete() -{ - QSGItem::componentComplete(); - m_componentComplete = true; - if(!m_emitters.isEmpty() && !m_particles.isEmpty()) - reset(); -} - -void QSGParticleSystem::initializeSystem() +void QSGParticleSystem::emittersChanged() { - int oldCount = m_particle_count; - m_particle_count = 0;//TODO: Only when changed? - - //### Reset the data too? - for(int i=0; i<oldCount; i++){ - if(m_data[i]){ - delete m_data[i]; - m_data[i] = 0; - } - } + if(!m_componentComplete) + return; - for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++) - delete (*iter); - m_groupData.clear(); - m_groupIds.clear(); + m_emitters.removeAll(0); - GroupData* gd = new GroupData;//Default group - gd->size = 0; - gd->start = -1; - gd->nextIdx = 0; - m_groupData.insert(0,gd); - m_groupIds.insert("",0); - m_nextGroupId = 1; + //Recalculate all counts, as emitter 'particle' may have changed as well + //### Worth tracking previous 'particle' per emitter to do partial recalculations? + m_particle_count = 0; - if(!m_emitters.count() || !m_particles.count()) - return; + int previousGroups = m_nextGroupId; + QVector<int> previousSizes; + previousSizes.resize(previousGroups); + for(int i=0; i<previousGroups; i++) + previousSizes[i] = m_groupData[i]->size; + for(int i=0; i<previousGroups; i++) + m_groupData[i]->size = 0; - foreach(QSGParticleEmitter* e, m_emitters){ + 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 - GroupData* gd = new GroupData; - gd->size = 0; - gd->start = -1; - gd->nextIdx = 0; + QSGParticleGroupData* gd = new QSGParticleGroupData; int id = m_nextGroupId++; m_groupIds.insert(e->particle(), id); m_groupData.insert(id, gd); } m_groupData[m_groupIds[e->particle()]]->size += e->particleCount(); + m_particle_count += e->particleCount(); + //###: Cull emptied groups? } - for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++){ - (*iter)->start = m_particle_count; - m_particle_count += (*iter)->size; - } - m_data.resize(m_particle_count); - for(int i=oldCount; i<m_particle_count; i++) - m_data[i] = 0;//setup new ones - - if(m_particle_count > 16000) - qWarning() << "Particle system contains a vast number of particles (>16000). Expect poor performance"; - - foreach(QSGParticlePainter* particle, m_particles){ - int particleCount = 0; - if(particle->particles().isEmpty()){//Uses default particle - particleCount += m_groupData[0]->size; - m_groupData[0]->types << particle; - }else{ - foreach(const QString &group, particle->particles()){ - particleCount += m_groupData[m_groupIds[group]]->size; - m_groupData[m_groupIds[group]]->types << particle; + foreach(QSGParticleGroupData* gd, m_groupData){//resize groups and update painters + int id = m_groupData.key(gd); + + //TODO: Shrink back down! (but it has the problem of trying to remove the dead particles while maintaining integrity) + gd->size = qMax(gd->size, id < previousGroups?previousSizes[id]:0); + + gd->data.resize(gd->size); + if(id < previousGroups){ + for(int i=previousSizes[id]; i<gd->size; i++) + gd->data[i] = 0; + /*TODO:Consider salvaging partial updates, but have to batch changes to a single painter + int delta = 0; + delta = gd->size - previousSizes[id]; + foreach(QSGParticlePainter* painter, gd->painters){ + if(!painter->count() && delta){ + painter->reset(); + painter->update(); + } + qDebug() << "Phi" << painter << painter->count() << delta; + painter->setCount(painter->count() + delta); } + */ } - particle->setCount(particleCount); - particle->m_pleaseReset = true; } + foreach(QSGParticlePainter *p, m_particlePainters) + loadPainter(p); - m_timestamp.start(); - m_initialized = true; - emit systemInitialized(); - qDebug() << "System Initialized. Size:" << m_particle_count; + if(m_particle_count > 16000)//###Investigate if these limits are worth warning about? + qWarning() << "Particle system arbitarily believes it has a vast number of particles (>16000). Expect poor performance"; +} + +void QSGParticleSystem::setRunning(bool arg) +{ + if (m_running != arg) { + m_running = arg; + emit runningChanged(arg); + reset(); + } } -void QSGParticleSystem::reset() +void QSGParticleSystem::componentComplete() +{ + QSGItem::componentComplete(); + m_componentComplete = true; + //if(!m_emitters.isEmpty() && !m_particlePainters.isEmpty()) + reset(); +} + +void QSGParticleSystem::reset()//TODO: Needed? { if(!m_componentComplete) - return;//Batch starting reset()s a little + return; + //Clear guarded pointers which have been deleted int cleared = 0; cleared += m_emitters.removeAll(0); - cleared += m_particles.removeAll(0); + cleared += m_particlePainters.removeAll(0); cleared += m_affectors.removeAll(0); //qDebug() << "Reset" << m_emitters.count() << m_particles.count() << "Cleared" << cleared; - foreach(QSGParticlePainter* p, m_particles) - p->reset(); - foreach(QSGParticleEmitter* e, m_emitters) - e->reset(); + + emittersChanged(); + + //TODO: Reset data +// foreach(QSGParticlePainter* p, m_particlePainters) +// p->reset(); +// foreach(QSGParticleEmitter* e, m_emitters) +// e->reset(); + //### Do affectors need reset too? + if(!m_running) return; - initializeSystem(); - foreach(QSGParticlePainter* p, m_particles) - p->update(); - foreach(QSGParticleEmitter* e, m_emitters) - e->emitWindow(0);//Start, so that starttime factors appropriately + + foreach(QSGParticlePainter *p, m_particlePainters){ + loadPainter(p); + p->reset(); + } + + m_timestamp.start();//TODO: Better placement + m_initialized = true; } QSGParticleData* QSGParticleSystem::newDatum(int groupId) { + Q_ASSERT(groupId < m_groupData.count());//XXX shouldn't really be an assert Q_ASSERT(m_groupData[groupId]->size); - int nextIdx = m_groupData[groupId]->start + m_groupData[groupId]->nextIdx++; + if( m_groupData[groupId]->nextIdx >= m_groupData[groupId]->size) m_groupData[groupId]->nextIdx = 0; + int nextIdx = m_groupData[groupId]->nextIdx++; - Q_ASSERT(nextIdx < m_data.size()); + Q_ASSERT(nextIdx < m_groupData[groupId]->size); QSGParticleData* ret; - if(m_data[nextIdx]){//Recycle, it's faster. - ret = m_data[nextIdx]; + if(m_groupData[groupId]->data[nextIdx]){//Recycle, it's faster. + ret = m_groupData[groupId]->data[nextIdx]; if(!m_overwrite && ret->stillAlive()){ return 0;//Artificial longevity (or too fast emission) means this guy hasn't died. To maintain count, don't emit a new one }//###Reset? }else{ ret = new QSGParticleData; - m_data[nextIdx] = ret; + m_groupData[groupId]->data[nextIdx] = ret; } ret->system = this; - ret->systemIndex = nextIdx; - ret->particleIndex = nextIdx - m_groupData[groupId]->start; + ret->index = nextIdx; ret->group = groupId; return ret; } @@ -248,14 +293,14 @@ 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) if(a && a->m_needsReset) - a->reset(pd->systemIndex); - foreach(QSGParticlePainter* p, m_groupData[pd->group]->types) + a->reset(pd); + foreach(QSGParticlePainter* p, m_groupData[pd->group]->painters) if(p) p->load(pd); } @@ -285,7 +330,7 @@ qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p) if(a) a->affectSystem(dt); foreach(QSGParticleData* d, m_needsReset) - foreach(QSGParticlePainter* p, m_groupData[d->group]->types) + foreach(QSGParticlePainter* p, m_groupData[d->group]->painters) if(p && d) p->reload(d); } @@ -296,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 9730ff35e8..45b4e164f1 100644 --- a/src/declarative/particles/qsgparticlesystem_p.h +++ b/src/declarative/particles/qsgparticlesystem_p.h @@ -47,6 +47,7 @@ #include <QVector> #include <QHash> #include <QPointer> +#include <QSignalMapper> QT_BEGIN_HEADER @@ -61,11 +62,14 @@ class QSGParticlePainter; class QSGParticleData; -struct GroupData{ +class QSGParticleGroupData{ +public: + QSGParticleGroupData():size(0),nextIdx(0) + {} int size; - int start; int nextIdx; - QList<QSGParticlePainter*> types; + QSet<QSGParticlePainter*> painters; + QVector<QSGParticleData*> data; }; class QSGParticleSystem : public QSGItem @@ -131,20 +135,20 @@ protected: void componentComplete(); private slots: - void countChanged(); + void emittersChanged(); + void loadPainter(QObject* p); public://but only really for related class usage. Perhaps we should all be friends? void emitParticle(QSGParticleData* p); QSGParticleData* newDatum(int groupId); qint64 systemSync(QSGParticlePainter* p); QElapsedTimer m_timestamp; - QVector<QSGParticleData*> m_data; QSet<QSGParticleData*> m_needsReset; QHash<QString, int> m_groupIds; - QHash<int, GroupData*> m_groupData;//id, size, start + QHash<int, QSGParticleGroupData*> m_groupData; qint64 m_timeInt; bool m_initialized; - void registerParticleType(QSGParticlePainter* p); + void registerParticlePainter(QSGParticlePainter* p); void registerParticleEmitter(QSGParticleEmitter* e); void registerParticleAffector(QSGParticleAffector* a); bool overwrite() const @@ -158,36 +162,29 @@ private: bool m_running; QList<QPointer<QSGParticleEmitter> > m_emitters; QList<QPointer<QSGParticleAffector> > m_affectors; - QList<QPointer<QSGParticlePainter> > m_particles; + QList<QPointer<QSGParticlePainter> > m_particlePainters; QList<QPointer<QSGParticlePainter> > m_syncList; qint64 m_startTime; int m_nextGroupId; bool m_overwrite; bool m_componentComplete; -}; -//TODO: Clean up all this into ParticleData + QSignalMapper m_painterMapper; + QSignalMapper m_emitterMapper; +}; -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. @@ -211,10 +208,38 @@ public: qreal curSY() const; int group; - QSGParticleEmitter* e; + QSGParticleEmitter* e;//### Needed? QSGParticleSystem* system; - int particleIndex; - int systemIndex; + 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..6f57ecaa36 100644 --- a/src/declarative/particles/qsgpointattractor.cpp +++ b/src/declarative/particles/qsgpointattractor.cpp @@ -60,27 +60,27 @@ bool QSGPointAttractorAffector::affectParticle(QSGParticleData *d, qreal dt) qreal ds = 0; switch(m_proportionalToDistance){ case Quadratic: - ds = (m_strength / qMax(1.,r*r)) * dt; + ds = (m_strength / qMax<qreal>(1.,r*r)) * dt; break; case Linear://also default default: - ds = (m_strength / qMax(1.,r)) * dt; + ds = (m_strength / qMax<qreal>(1.,r)) * dt; } dx = ds * cos(theta); 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/qsgspritegoal.cpp b/src/declarative/particles/qsgspritegoal.cpp index 8dc98ae314..c97bfd1f26 100644 --- a/src/declarative/particles/qsgspritegoal.cpp +++ b/src/declarative/particles/qsgspritegoal.cpp @@ -81,7 +81,7 @@ bool QSGSpriteGoalAffector::affectParticle(QSGParticleData *d, qreal dt) Q_UNUSED(dt); //TODO: Affect all engines QSGSpriteEngine *engine = 0; - foreach(QSGParticlePainter *p, m_system->m_groupData[d->group]->types) + foreach(QSGParticlePainter *p, m_system->m_groupData[d->group]->painters) if(qobject_cast<QSGImageParticle*>(p)) engine = qobject_cast<QSGImageParticle*>(p)->spriteEngine(); if(!engine) @@ -89,8 +89,8 @@ bool QSGSpriteGoalAffector::affectParticle(QSGParticleData *d, qreal dt) if(m_goalIdx == -2 || engine != m_lastEngine) updateStateIndex(engine); - if(engine->spriteState(d->particleIndex) != m_goalIdx){ - engine->setGoal(m_goalIdx, d->particleIndex, m_jump); + if(engine->spriteState(d->index) != m_goalIdx){ + engine->setGoal(m_goalIdx, d->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/qsgturbulence.cpp b/src/declarative/particles/qsgturbulence.cpp index 476db9c4b0..bb46b99f0d 100644 --- a/src/declarative/particles/qsgturbulence.cpp +++ b/src/declarative/particles/qsgturbulence.cpp @@ -128,30 +128,34 @@ void QSGTurbulenceAffector::affectSystem(qreal dt) m_lastT += period; } - foreach(QSGParticleData *d, m_system->m_data){ - if(!d || !activeGroup(d->group)) + foreach(QSGParticleGroupData *gd, m_system->m_groupData){ + if(!activeGroup(m_system->m_groupData.key(gd)))//TODO: Surely this can be done better return; - qreal fx = 0.0; - qreal fy = 0.0; - QPointF pos = QPointF(d->curX() - x(), d->curY() - y());//TODO: Offset - QPointF nodePos = QPointF(pos.x() / m_spacing.x(), pos.y() / m_spacing.y()); - QSet<QPair<int, int> > nodes; - nodes << qMakePair((int)ceil(nodePos.x()), (int)ceil(nodePos.y())); - nodes << qMakePair((int)ceil(nodePos.x()), (int)floor(nodePos.y())); - nodes << qMakePair((int)floor(nodePos.x()), (int)ceil(nodePos.y())); - nodes << qMakePair((int)floor(nodePos.x()), (int)floor(nodePos.y())); - typedef QPair<int, int> intPair; - foreach(const intPair &p, nodes){ - if(!QRect(0,0,m_gridSize-1,m_gridSize-1).contains(QPoint(p.first, p.second))) - continue; - qreal dist = magnitude(pos.x() - p.first*m_spacing.x(), pos.y() - p.second*m_spacing.y());//TODO: Mathematically valid - fx += m_field[p.first][p.second].x() * ((m_magSum - dist)/m_magSum);//Proportionally weight nodes - fy += m_field[p.first][p.second].y() * ((m_magSum - dist)/m_magSum); - } - if(fx || fy){ - d->setInstantaneousSX(d->curSX()+ fx * dt); - d->setInstantaneousSY(d->curSY()+ fy * dt); - m_system->m_needsReset << d; + foreach(QSGParticleData *d, gd->data){ + if(!d || !activeGroup(d->group)) + return; + qreal fx = 0.0; + qreal fy = 0.0; + QPointF pos = QPointF(d->curX() - x(), d->curY() - y());//TODO: Offset + QPointF nodePos = QPointF(pos.x() / m_spacing.x(), pos.y() / m_spacing.y()); + QSet<QPair<int, int> > nodes; + nodes << qMakePair((int)ceil(nodePos.x()), (int)ceil(nodePos.y())); + nodes << qMakePair((int)ceil(nodePos.x()), (int)floor(nodePos.y())); + nodes << qMakePair((int)floor(nodePos.x()), (int)ceil(nodePos.y())); + nodes << qMakePair((int)floor(nodePos.x()), (int)floor(nodePos.y())); + typedef QPair<int, int> intPair; + foreach(const intPair &p, nodes){ + if(!QRect(0,0,m_gridSize-1,m_gridSize-1).contains(QPoint(p.first, p.second))) + continue; + qreal dist = magnitude(pos.x() - p.first*m_spacing.x(), pos.y() - p.second*m_spacing.y());//TODO: Mathematically valid + fx += m_field[p.first][p.second].x() * ((m_magSum - dist)/m_magSum);//Proportionally weight nodes + fy += m_field[p.first][p.second].y() * ((m_magSum - dist)/m_magSum); + } + if(fx || fy){ + d->setInstantaneousSX(d->curSX()+ fx * dt); + d->setInstantaneousSY(d->curSY()+ fy * dt); + m_system->m_needsReset << d; + } } } } 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; |