Update licenseheader text in source files for qtdeclarative Qt module
[profile/ivi/qtdeclarative.git] / src / declarative / particles / qsgimageparticle.cpp
index c9df5f4..a910cc6 100644 (file)
@@ -7,29 +7,29 @@
 ** This file is part of the Declarative module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
 ** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
 **
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
 **
 **
 **
@@ -193,7 +193,7 @@ float UltraMaterialData::chunkOfBytes[1024];
 
 QSGMaterialShader *UltraMaterial::createShader() const
 {
-    if(usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
+    if (usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
         return new UltraMaterialData;
     else
         return new UltraMaterialData;
@@ -285,7 +285,7 @@ QSGImageParticle::QSGImageParticle(QSGItem* parent)
     : QSGParticlePainter(parent)
     , m_do_reset(false)
     , m_color_variation(0.0)
-    , m_node(0)
+    , m_rootNode(0)
     , m_material(0)
     , m_alphaVariation(0.0)
     , m_alpha(1.0)
@@ -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();
 }
 
@@ -425,7 +425,7 @@ void QSGImageParticle::setRotation(qreal arg)
         m_rotation = arg;
         emit rotationChanged(arg);
     }
-    if(perfLevel < Deformable)
+    if (perfLevel < Deformable)
         reset();
 }
 
@@ -435,7 +435,7 @@ void QSGImageParticle::setRotationVariation(qreal arg)
         m_rotationVariation = arg;
         emit rotationVariationChanged(arg);
     }
-    if(perfLevel < Deformable)
+    if (perfLevel < Deformable)
         reset();
 }
 
@@ -445,7 +445,7 @@ void QSGImageParticle::setRotationSpeed(qreal arg)
         m_rotationSpeed = arg;
         emit rotationSpeedChanged(arg);
     }
-    if(perfLevel < Deformable)
+    if (perfLevel < Deformable)
         reset();
 }
 
@@ -455,7 +455,7 @@ void QSGImageParticle::setRotationSpeedVariation(qreal arg)
         m_rotationSpeedVariation = arg;
         emit rotationSpeedVariationChanged(arg);
     }
-    if(perfLevel < Deformable)
+    if (perfLevel < Deformable)
         reset();
 }
 
@@ -465,7 +465,7 @@ void QSGImageParticle::setAutoRotation(bool arg)
         m_autoRotation = arg;
         emit autoRotationChanged(arg);
     }
-    if(perfLevel < Deformable)
+    if (perfLevel < Deformable)
         reset();
 }
 
@@ -475,7 +475,7 @@ void QSGImageParticle::setXVector(QSGStochasticDirection* arg)
         m_xVector = arg;
         emit xVectorChanged(arg);
     }
-    if(perfLevel < Deformable)
+    if (perfLevel < Deformable)
         reset();
 }
 
@@ -485,7 +485,7 @@ void QSGImageParticle::setYVector(QSGStochasticDirection* arg)
         m_yVector = arg;
         emit yVectorChanged(arg);
     }
-    if(perfLevel < Deformable)
+    if (perfLevel < Deformable)
         reset();
 }
 
@@ -495,26 +495,22 @@ void QSGImageParticle::setBloat(bool arg)
         m_bloat = arg;
         emit bloatChanged(arg);
     }
-    if(perfLevel < 9999)
+    if (perfLevel < 9999)
         reset();
 }
-void QSGImageParticle::setCount(int c)
-{
-    QSGParticlePainter::setCount(c);
-    m_pleaseReset = true;
-}
 
 void QSGImageParticle::reset()
 {
     QSGParticlePainter::reset();
-     m_pleaseReset = true;
+    m_pleaseReset = true;
+    update();
 }
 
 void QSGImageParticle::createEngine()
 {
-    if(m_spriteEngine)
+    if (m_spriteEngine)
         delete m_spriteEngine;
-    if(m_sprites.count())
+    if (m_sprites.count())
         m_spriteEngine = new QSGSpriteEngine(m_sprites, this);
     else
         m_spriteEngine = 0;
@@ -553,7 +549,7 @@ static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
     UltraParticle_Attributes
 };
 
-QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode()
+QSGGeometryNode* QSGImageParticle::buildSimpleParticleNodes()
 {
     perfLevel = Simple;//TODO: Intermediate levels
     QImage image = QImage(m_image_name.toLocalFile());
@@ -561,54 +557,6 @@ QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode()
         printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
         return 0;
     }
-    int vCount = m_count * 4;
-    int iCount = m_count * 6;
-    qDebug() << "Simple Case";
-
-    QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
-    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;
-        }
-
-        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) {
-        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;
-    }
 
     if (m_material) {
         delete m_material;
@@ -619,28 +567,73 @@ 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;
+    foreach (const QString &str, m_particles){
+        int gIdx = m_system->m_groupIds[str];
+        int count = m_system->m_groupData[gIdx]->size();
+
+        QSGGeometryNode* node = new QSGGeometryNode();
+        m_nodes.insert(gIdx, node);
+        node->setMaterial(m_material);
+
+        int vCount = count * 4;
+        int iCount = count * 6;
 
-    return m_node;
+        QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
+        node->setGeometry(g);
+        g->setDrawingMode(GL_TRIANGLES);
+
+        SimpleVertex *vertices = (SimpleVertex *) g->vertexData();
+        for (int p=0; p < count; ++p){
+            commit(gIdx, 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 < 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;
+        }
+    }
+
+    foreach (QSGGeometryNode* node, m_nodes){
+        if (node == *(m_nodes.begin()))
+                continue;
+        (*(m_nodes.begin()))->appendChildNode(node);
+    }
+
+    return *(m_nodes.begin());
 }
 
-QSGGeometryNode* QSGImageParticle::buildParticleNode()
+QSGGeometryNode* QSGImageParticle::buildParticleNodes()
 {
     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");
+    if (count() <= 0)
         return 0;
-    }
 
-    if(!m_sprites.count() && !m_bloat
+    if (!m_sprites.count() && !m_bloat
             && m_colortable_name.isEmpty()
             && m_sizetable_name.isEmpty()
             && m_opacitytable_name.isEmpty()
@@ -651,20 +644,19 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode()
             && !m_redVariation && !m_blueVariation && !m_greenVariation
             && !m_color.isValid()
             )
-        return buildSimpleParticleNode();
+        return buildSimpleParticleNodes();
     perfLevel = Sprites;//TODO: intermediate levels
-    if(!m_color.isValid())//But we're in colored level (or higher)
+    if (!m_color.isValid())//But we're in colored level (or higher)
         m_color = QColor(Qt::white);
-    qDebug() << "Complex Case";
 
     QImage image;
-    if(m_sprites.count()){
+    if (m_sprites.count()){
         if (!m_spriteEngine) {
             qWarning() << "UltraParticle: No sprite engine...";
             return 0;
         }
         image = m_spriteEngine->assembledImage();
-        if(image.isNull())//Warning is printed in engine
+        if (image.isNull())//Warning is printed in engine
             return 0;
     }else{
         image = QImage(m_image_name.toLocalFile());
@@ -674,105 +666,6 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode()
         }
     }
 
-    int vCount = m_count * 4;
-    int iCount = m_count * 6;
-
-    QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
-    g->setDrawingMode(GL_TRIANGLES);
-
-    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;
-            }
-        }
-
-        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?
-    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;
-    }
-
-    qFree(m_lastData);
     if (m_material) {
         delete m_material;
         m_material = 0;
@@ -782,11 +675,11 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode()
     QImage sizetable(m_sizetable_name.toLocalFile());
     QImage opacitytable(m_opacitytable_name.toLocalFile());
     m_material = new UltraMaterial();
-    if(colortable.isNull())
+    if (colortable.isNull())
         colortable = QImage(":defaultshaders/identitytable.png");
-    if(sizetable.isNull())
+    if (sizetable.isNull())
         sizetable = QImage(":defaultshaders/identitytable.png");
-    if(opacitytable.isNull())
+    if (opacitytable.isNull())
         opacitytable = QImage(":defaultshaders/defaultFadeInOut.png");
     Q_ASSERT(!colortable.isNull());
     Q_ASSERT(!sizetable.isNull());
@@ -799,57 +692,109 @@ QSGGeometryNode* QSGImageParticle::buildParticleNode()
     m_material->texture->setFiltering(QSGTexture::Linear);
 
     m_material->framecount = 1;
-    if(m_spriteEngine){
+    if (m_spriteEngine){
         m_material->framecount = m_spriteEngine->maxFrames();
         m_spriteEngine->setCount(m_count);
     }
 
-    m_node = new QSGGeometryNode();
-    m_node->setGeometry(g);
-    m_node->setMaterial(m_material);
+    foreach (const QString &str, m_particles){
+        int gIdx = m_system->m_groupIds[str];
+        int count = m_system->m_groupData[gIdx]->size();
+        QSGGeometryNode* node = new QSGGeometryNode();
+        node->setMaterial(m_material);
+
+        m_nodes.insert(gIdx, node);
+        m_idxStarts.insert(gIdx, m_lastIdxStart);
+        m_lastIdxStart += count;
+
+        //Create Particle Geometry
+        int vCount = count * 4;
+        int iCount = count * 6;
+
+        QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
+        node->setGeometry(g);
+        g->setDrawingMode(GL_TRIANGLES);
+
+        UltraVertex *vertices = (UltraVertex *) g->vertexData();
+        for (int p=0; p < count; ++p) {
+            commit(gIdx, p);//commit sets geometry for the node
 
-    m_last_particle = 0;
+            vertices[0].tx = 0;
+            vertices[0].ty = 0;
 
-    return m_node;
+            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 < 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;
+        }
+
+    }
+
+    foreach (QSGGeometryNode* node, m_nodes){
+        if (node == *(m_nodes.begin()))
+            continue;
+        (*(m_nodes.begin()))->appendChildNode(node);
+    }
+
+    return *(m_nodes.begin());
 }
 
 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_lastLevel = perfLevel;
-            delete m_node;
-        }
-        if(m_material)
-            delete m_material;
+    if (m_pleaseReset){
+        m_lastLevel = perfLevel;
+
+        delete m_rootNode;//Automatically deletes children
+        m_rootNode = 0;
+        m_nodes.clear();
 
-        m_node = 0;
+        m_idxStarts.clear();
+        m_lastIdxStart = 0;
+
+        if (m_material)
+            delete m_material;
         m_material = 0;
+
         m_pleaseReset = false;
     }
 
-    if(m_system && m_system->isRunning())
+    if (m_system && m_system->isRunning())
         prepareNextFrame();
-    if (m_node){
+    if (m_rootNode){
         update();
-        m_node->markDirty(QSGNode::DirtyMaterial);
+        //### Should I be using dirty geometry too/instead?
+        foreach (QSGGeometryNode* node, m_nodes)
+            node->markDirty(QSGNode::DirtyMaterial);
     }
 
-    return m_node;
+    return m_rootNode;
 }
 
 void QSGImageParticle::prepareNextFrame()
 {
-    if (m_node == 0){    //TODO: Staggered loading (as emitted)
-        m_node = buildParticleNode();
-        if(m_node == 0)
+    if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
+        m_rootNode = buildParticleNodes();
+        if (m_rootNode == 0)
             return;
-        qDebug() << "Feature level: " << perfLevel;
+        //qDebug() << "Feature level: " << perfLevel;
     }
     qint64 timeStamp = m_system->systemSync(this);
 
@@ -857,18 +802,25 @@ void QSGImageParticle::prepareNextFrame()
     m_material->timestamp = time;
 
     //Advance State
-    if(m_spriteEngine){//perfLevel == Sprites?
+    if (m_spriteEngine){//perfLevel == Sprites?//TODO: use signals?
+
         m_material->animcount = m_spriteEngine->spriteCount();
-        UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
         m_spriteEngine->updateSprites(timeStamp);
-        for(int i=0; i<m_count; i++){
-            UltraVertices &p = particles[i];
-            int curIdx = m_spriteEngine->spriteState(i);
-            if(curIdx != p.v1.animIdx){
-                p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
-                p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
-                p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
-                p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
+        foreach (const QString &str, m_particles){
+            int gIdx = m_system->m_groupIds[str];
+            int count = m_system->m_groupData[gIdx]->size();
+
+            UltraVertices *particles = (UltraVertices *) m_nodes[gIdx]->geometry()->vertexData();
+            for (int i=0; i < count; i++){
+                int spriteIdx = m_idxStarts[gIdx] + i;
+                UltraVertices &p = particles[i];
+                int curIdx = m_spriteEngine->spriteState(spriteIdx);
+                if (curIdx != p.v1.animIdx){
+                    p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
+                    p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
+                    p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
+                    p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
+                }
             }
         }
     }else{
@@ -876,118 +828,132 @@ 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 gIdx, int pIdx)
 {
-    if (m_node == 0)
-        return;
-
-    int pos = particleTypeIndex(d);
-    IntermediateVertices* p = fetchIntermediateVertices(pos);//Remember this removes typesafety!
     Color4ub color;
+    QSGParticleData* datum = m_system->m_groupData[gIdx]->data[pIdx];
     qreal redVariation = m_color_variation + m_redVariation;
     qreal greenVariation = m_color_variation + m_greenVariation;
     qreal blueVariation = m_color_variation + m_blueVariation;
-    switch(perfLevel){//Fall-through is intended on all of them
+    int spriteIdx = m_idxStarts[gIdx] + datum->index;
+    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;
-            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);
+            datum->animT = datum->t;
+            datum->animIdx = 0;
+            if (m_spriteEngine){
+                m_spriteEngine->startSprite(spriteIdx);
+                datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
+                datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
             }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;
+                datum->frameCount = 1;
+                datum->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();
+            if (m_xVector){
+                const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
+                datum->xx = ret.x();
+                datum->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();
+            if (m_yVector){
+                const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
+                datum->yx = ret.x();
+                datum->yy = ret.y();
             }
-            p->v1->rotation = p->v2->rotation = p->v3->rotation = p->v4->rotation =
+            datum->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 =
+            datum->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:
+            datum->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;
+            datum->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::commit(int gIdx, int pIdx)
+{
+    if (m_pleaseReset)
+        return;
+    QSGGeometryNode *node = m_nodes[gIdx];
+    if (!node)
+        return;
+    QSGParticleData* datum = m_system->m_groupData[gIdx]->data[pIdx];
+
+    node->setFlag(QSGNode::OwnsGeometry, false);
+    UltraVertex *ultraVertices = (UltraVertex *) node->geometry()->vertexData();
+    SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
+    switch (perfLevel){
+    case Sprites:
+        ultraVertices += pIdx*4;
+        for (int i=0; i<4; i++){
+            ultraVertices[i].x = datum->x  - m_systemOffset.x();
+            ultraVertices[i].y = datum->y  - m_systemOffset.y();
+            ultraVertices[i].t = datum->t;
+            ultraVertices[i].lifeSpan = datum->lifeSpan;
+            ultraVertices[i].size = datum->size;
+            ultraVertices[i].endSize = datum->endSize;
+            ultraVertices[i].sx = datum->sx;
+            ultraVertices[i].sy = datum->sy;
+            ultraVertices[i].ax = datum->ax;
+            ultraVertices[i].ay = datum->ay;
+            ultraVertices[i].xx = datum->xx;
+            ultraVertices[i].xy = datum->xy;
+            ultraVertices[i].yx = datum->yx;
+            ultraVertices[i].yy = datum->yy;
+            ultraVertices[i].rotation = datum->rotation;
+            ultraVertices[i].rotationSpeed = datum->rotationSpeed;
+            ultraVertices[i].autoRotate = datum->autoRotate;
+            ultraVertices[i].animIdx = datum->animIdx;
+            ultraVertices[i].frameDuration = datum->frameDuration;
+            ultraVertices[i].frameCount = datum->frameCount;
+            ultraVertices[i].animT = datum->animT;
+            ultraVertices[i].color.r = datum->color.r;
+            ultraVertices[i].color.g = datum->color.g;
+            ultraVertices[i].color.b = datum->color.b;
+            ultraVertices[i].color.a = datum->color.a;
+        }
+        break;
+    case Tabled://TODO: Us
+    case Deformable:
+    case Colored:
+    case Simple:
+        simpleVertices += pIdx*4;
+        for (int i=0; i<4; i++){
+            simpleVertices[i].x = datum->x - m_systemOffset.x();
+            simpleVertices[i].y = datum->y - m_systemOffset.y();
+            simpleVertices[i].t = datum->t;
+            simpleVertices[i].lifeSpan = datum->lifeSpan;
+            simpleVertices[i].size = datum->size;
+            simpleVertices[i].endSize = datum->endSize;
+            simpleVertices[i].sx = datum->sx;
+            simpleVertices[i].sy = datum->sy;
+            simpleVertices[i].ax = datum->ax;
+            simpleVertices[i].ay = datum->ay;
+        }
+        break;
+    default:
+        break;
+    }
+
+    node->setFlag(QSGNode::OwnsGeometry, true);
 }
 
+
+
 QT_END_NAMESPACE