Add BurstEmitter, and a simple render path for UltraParticles
authorAlan Alpert <alan.alpert@nokia.com>
Thu, 19 May 2011 08:43:12 +0000 (18:43 +1000)
committerAlan Alpert <alan.alpert@nokia.com>
Thu, 19 May 2011 08:43:12 +0000 (18:43 +1000)
None of the intermediate paths are written though. It's all or virtually
nothing.

src/imports/particles/burstemitter.cpp [new file with mode: 0644]
src/imports/particles/burstemitter.h [new file with mode: 0644]
src/imports/particles/main.cpp
src/imports/particles/particle.h
src/imports/particles/particles.pro
src/imports/particles/resources/simplefragment.shader [new file with mode: 0644]
src/imports/particles/resources/simplevertex.shader [new file with mode: 0644]
src/imports/particles/spriteparticles.qrc
src/imports/particles/ultraparticle.cpp
src/imports/particles/ultraparticle.h

diff --git a/src/imports/particles/burstemitter.cpp b/src/imports/particles/burstemitter.cpp
new file mode 100644 (file)
index 0000000..a817172
--- /dev/null
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "burstemitter.h"
+QT_BEGIN_NAMESPACE
+
+void BurstEmitter::burst(int count, qreal x, qreal y)
+{
+    qreal oldX = QSGItem::x();
+    qreal oldY = QSGItem::y();
+    setX(x);
+    setY(y);
+    TrailsEmitter::burst(count);
+    setX(oldX);
+    setY(oldY);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/burstemitter.h b/src/imports/particles/burstemitter.h
new file mode 100644 (file)
index 0000000..cffa791
--- /dev/null
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BURSTEMITTER_H
+#define BURSTEMITTER_H
+
+#include "trailsemitter.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+//Convenience Class - can't do function overloads in QML?
+class BurstEmitter : public TrailsEmitter
+{
+    Q_OBJECT
+public:
+    explicit BurstEmitter(QSGItem* parent = 0):TrailsEmitter(parent){}
+public slots:
+    void burst(int count, qreal x, qreal y);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
index 9382f48..3343d9a 100644 (file)
@@ -66,6 +66,7 @@
 #include "particleemitter.h"
 //#include "spriteemitter.h"
 #include "trailsemitter.h"
+#include "burstemitter.h"
 #include "particle.h"
 #include "coloredparticle.h"
 #include "spriteparticle.h"
@@ -115,6 +116,7 @@ void ParticlesPlugin::registerTypes(const char *uri)
 
     qmlRegisterType<ParticleEmitter>(uri, 2, 0, "ParticleEmitter");
     qmlRegisterType<TrailsEmitter>(uri, 2, 0, "TrailEmitter");
+    qmlRegisterType<TrailsEmitter>(uri, 2, 0, "BurstEmitter");
 
     qmlRegisterType<FollowEmitter>(uri, 2, 0, "FollowEmitter");
     qmlRegisterType<ParticleExtruder>(uri, 2, 0, "Box");
index 324a7e5..fbb9665 100644 (file)
@@ -112,6 +112,22 @@ protected:
     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:
 };
 
index 74820e1..91cf5ba 100644 (file)
@@ -48,7 +48,8 @@ HEADERS += \
     deformableparticle.h \
     pictureaffector.h \
     superparticle.h \
-    ultraparticle.h
+    ultraparticle.h \
+    burstemitter.h
 
 SOURCES += \
     V1/qdeclarativeparticles.cpp \
@@ -96,7 +97,8 @@ SOURCES += \
     deformableparticle.cpp \
     pictureaffector.cpp \
     superparticle.cpp \
-    ultraparticle.cpp
+    ultraparticle.cpp \
+    burstemitter.cpp
 
 QT += declarative opengl
 #Because we use QDeclarativePixmapCache once...
diff --git a/src/imports/particles/resources/simplefragment.shader b/src/imports/particles/resources/simplefragment.shader
new file mode 100644 (file)
index 0000000..494053e
--- /dev/null
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+    gl_FragColor = (texture2D(texture, fTex)) * fFade;
+}
diff --git a/src/imports/particles/resources/simplevertex.shader b/src/imports/particles/resources/simplevertex.shader
new file mode 100644 (file)
index 0000000..f185ef0
--- /dev/null
@@ -0,0 +1,36 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; //  x = time,  y = lifeSpan, z = size,  w = endSize
+attribute highp vec4 vVec; // x,y = constant speed,  z,w = acceleration
+
+uniform highp mat4 matrix;                              
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;                                
+varying lowp float fFade;
+
+void main() {                                           
+    fTex = vTex;                                        
+    highp float size = vData.z;
+    highp float endSize = vData.w;
+
+    highp float t = (timestamp - vData.x) / vData.y;
+
+    highp float currentSize = mix(size, endSize, t * t);
+
+    if (t < 0. || t > 1.)
+        currentSize = 0.;
+
+    highp vec2 pos = vPos
+                   - currentSize / 2. + currentSize * vTex          // adjust size
+                   + vVec.xy * t * vData.y         // apply speed vector..
+                   + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+    gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+    highp float fadeIn = min(t * 10., 1.);
+    highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+    fFade = fadeIn * fadeOut * opacity;
+}
index b1ebc27..0232c3c 100644 (file)
@@ -16,5 +16,7 @@
         <file>resources/ultrafragment.shader</file>
         <file>resources/supervertex.shader</file>
         <file>resources/superfragment.shader</file>
+        <file>resources/simplevertex.shader</file>
+        <file>resources/simplefragment.shader</file>
     </qresource>
 </RCC>
index 6dd05aa..d516f99 100644 (file)
@@ -58,10 +58,11 @@ const float CONV = 0.017453292519943295;
 class UltraMaterial : public QSGMaterial
 {
 public:
-    UltraMaterial()
+    UltraMaterial(bool withSprites=false)
         : timestamp(0)
         , framecount(1)
         , animcount(1)
+        , usesSprites(withSprites)
     {
         setFlag(Blending, true);
     }
@@ -89,9 +90,8 @@ public:
     qreal timestamp;
     int framecount;
     int animcount;
+    bool usesSprites;
 };
-
-
 class UltraMaterialData : public QSGMaterialShader
 {
 public:
@@ -191,17 +191,99 @@ public:
 };
 float UltraMaterialData::chunkOfBytes[1024];
 
-
 QSGMaterialShader *UltraMaterial::createShader() const
 {
-    return new UltraMaterialData;
+    if(usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
+        return new UltraMaterialData;
+    else
+        return new UltraMaterialData;
+}
+
+
+class SimpleMaterial : public UltraMaterial
+{
+    virtual QSGMaterialShader *createShader() const;
+};
+
+class SimpleMaterialData : public QSGMaterialShader
+{
+public:
+    SimpleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+    {
+        QFile vf(vertexFile ? vertexFile : ":resources/simplevertex.shader");
+        vf.open(QFile::ReadOnly);
+        m_vertex_code = vf.readAll();
+
+        QFile ff(fragmentFile ? fragmentFile : ":resources/simplefragment.shader");
+        ff.open(QFile::ReadOnly);
+        m_fragment_code = ff.readAll();
+
+        Q_ASSERT(!m_vertex_code.isNull());
+        Q_ASSERT(!m_fragment_code.isNull());
+    }
+
+    void deactivate() {
+        QSGMaterialShader::deactivate();
+
+        for (int i=0; i<8; ++i) {
+            program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+        }
+    }
+
+    virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+    {
+        UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
+        state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+        m->texture->bind();
+
+        program()->setUniformValue(m_opacity_id, state.opacity());
+        program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+        if (state.isMatrixDirty())
+            program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+    }
+
+    virtual void initialize() {
+        m_matrix_id = program()->uniformLocation("matrix");
+        m_opacity_id = program()->uniformLocation("opacity");
+        m_timestamp_id = program()->uniformLocation("timestamp");
+    }
+
+    virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+    virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+    virtual char const *const *attributeNames() const {
+        static const char *attr[] = {
+            "vPos",
+            "vTex",
+            "vData",
+            "vVec",
+            0
+        };
+        return attr;
+    }
+
+    virtual bool isColorTable() const { return false; }
+
+    int m_matrix_id;
+    int m_opacity_id;
+    int m_timestamp_id;
+
+    QByteArray m_vertex_code;
+    QByteArray m_fragment_code;
+
+    static float chunkOfBytes[1024];
+};
+float SimpleMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SimpleMaterial::createShader() const {
+    return new SimpleMaterialData;
 }
 
 UltraParticle::UltraParticle(QSGItem* parent)
     : ParticleType(parent)
     , m_do_reset(false)
-    , m_color(Qt::white)
-    , m_color_variation(0.5)
+    , m_color_variation(0.0)
     , m_node(0)
     , m_material(0)
     , m_alphaVariation(0.0)
@@ -217,6 +299,8 @@ UltraParticle::UltraParticle(QSGItem* parent)
     , m_rotationSpeed(0)
     , m_rotationSpeedVariation(0)
     , m_spriteEngine(0)
+    , m_bloat(false)
+    , perfLevel(Unknown)
 {
     setFlag(ItemHasContents);
 }
@@ -269,7 +353,6 @@ void UltraParticle::setColor(const QColor &color)
         return;
     m_color = color;
     emit colorChanged();
-    //m_system->pleaseReset();//XXX
 }
 
 void UltraParticle::setColorVariation(qreal var)
@@ -278,7 +361,6 @@ void UltraParticle::setColorVariation(qreal var)
         return;
     m_color_variation = var;
     emit colorVariationChanged();
-    //m_system->pleaseReset();//XXX
 }
 
 void UltraParticle::setCount(int c)
@@ -301,9 +383,23 @@ void UltraParticle::createEngine()
         m_spriteEngine = new SpriteEngine(m_sprites, this);
     else
         m_spriteEngine = 0;
-    reset();//###this is probably out of updatePaintNode and shouldn't be
+    reset();
 }
 
+static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
+    { 0, 2, GL_FLOAT },             // Position
+    { 1, 2, GL_FLOAT },             // TexCoord
+    { 2, 4, GL_FLOAT },             // Data
+    { 3, 4, GL_FLOAT }             // Vectors
+};
+
+static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
+{
+    4, // Attribute Count
+    (2 + 2 + 4 + 4 ) * sizeof(float),
+    SimpleParticle_Attributes
+};
+
 static QSGGeometry::Attribute UltraParticle_Attributes[] = {
     { 0, 2, GL_FLOAT },             // Position
     { 1, 2, GL_FLOAT },             // TexCoord
@@ -322,10 +418,85 @@ static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
     UltraParticle_Attributes
 };
 
+QSGGeometryNode* UltraParticle::buildSimpleParticleNode()
+{
+    perfLevel = Simple;//TODO: Intermediate levels
+    QImage image = QImage(m_image_name.toLocalFile());
+    if (image.isNull()) {
+        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;
+        m_material = 0;
+    }
+
+    m_material = new SimpleMaterial();
+    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* UltraParticle::buildParticleNode()
 {
     if (m_count * 4 > 0xffff) {
-        printf("UltraParticle: Too many particles... \n");
+        printf("UltraParticle: Too many particles... \n");//####Why is this here?
         return 0;
     }
 
@@ -334,6 +505,21 @@ QSGGeometryNode* UltraParticle::buildParticleNode()
         return 0;
     }
 
+    qDebug() << m_colortable_name.isEmpty() << !m_color.isValid();
+    if(!m_sprites.count() && !m_bloat
+            && m_colortable_name.isEmpty()
+            && m_sizetable_name.isEmpty()
+            && m_opacitytable_name.isEmpty()
+            && !m_rotation && !m_rotationVariation
+            && !m_rotationSpeed && !m_rotationSpeedVariation
+            && !m_alphaVariation && m_alpha == 1.0
+            && !m_redVariation && !m_blueVariation && !m_greenVariation
+            && !m_color.isValid()
+            )
+        return buildSimpleParticleNode();
+    perfLevel = Sprites;//TODO: intermediate levels
+    qDebug() << "Complex Case";
+
     QImage image;
     if(m_sprites.count()){
         if (!m_spriteEngine) {
@@ -480,6 +666,7 @@ void UltraParticle::prepareNextFrame()
         m_node = buildParticleNode();
         if(m_node == 0)
             return;
+        qDebug() << "Feature level: " << perfLevel;
     }
     qint64 timeStamp = m_system->systemSync(this);
 
@@ -487,7 +674,7 @@ void UltraParticle::prepareNextFrame()
     m_material->timestamp = time;
 
     //Advance State
-    if(m_spriteEngine){
+    if(m_spriteEngine){//perfLevel == Sprites?
         m_material->animcount = m_spriteEngine->stateCount();
         UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
         m_spriteEngine->updateSprites(timeStamp);
@@ -506,6 +693,37 @@ void UltraParticle::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* UltraParticle::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 UltraParticle::reloadColor(const Color4ub &c, ParticleData* d)
 {
     UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
@@ -514,6 +732,7 @@ void UltraParticle::reloadColor(const Color4ub &c, ParticleData* d)
     p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
 }
 
+/*Repalced by superclass templated function
 void UltraParticle::vertexCopy(UltraVertex &b,const ParticleVertex& a)
 {
     b.x = a.x - m_systemOffset.x();
@@ -527,23 +746,22 @@ void UltraParticle::vertexCopy(UltraVertex &b,const ParticleVertex& a)
     b.ax = a.ax;
     b.ay = a.ay;
 }
+*/
+
 
 void UltraParticle::reload(ParticleData *d)
 {
     if (m_node == 0)
         return;
 
-    UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
-
     int pos = particleTypeIndex(d);
-
-    UltraVertices &p = particles[pos];
+    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);
+    vertexCopy(*p->v1, d->pv);
+    vertexCopy(*p->v2, d->pv);
+    vertexCopy(*p->v3, d->pv);
+    vertexCopy(*p->v4, d->pv);
 }
 
 void UltraParticle::load(ParticleData *d)
@@ -551,53 +769,60 @@ void UltraParticle::load(ParticleData *d)
     if (m_node == 0)
         return;
 
-    //Color initialization
-    // Particle color
+    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;
     qreal blueVariation = m_color_variation + m_blueVariation;
-    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;
-    UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
-    UltraVertices &p = particles[particleTypeIndex(d)];
-    p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
-    //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_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();
-    }
-    p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.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_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;
-    // 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){
-        SpriteState* state = m_spriteEngine->state(0);
-        p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = state->frames();
-        p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = state->duration();
-        m_spriteEngine->startSprite(particleTypeIndex(d));
-    }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;
+    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){
+                SpriteState* state = m_spriteEngine->state(0);
+                p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = state->frames();
+                p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = state->duration();
+                m_spriteEngine->startSprite(pos);
+            }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;
+            }
+        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_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();
+            }
+            p->v1->rotation = p->v2->rotation = p->v3->rotation = p->v4->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_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:
+            //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;
+        default:
+            break;
     }
 
-
-    vertexCopy(p.v1, d->pv);
-    vertexCopy(p.v2, d->pv);
-    vertexCopy(p.v3, d->pv);
-    vertexCopy(p.v4, d->pv);
+    vertexCopy(*p->v1, d->pv);
+    vertexCopy(*p->v2, d->pv);
+    vertexCopy(*p->v3, d->pv);
+    vertexCopy(*p->v4, d->pv);
 }
 
 QT_END_NAMESPACE
index 2001f09..73fc3bd 100644 (file)
@@ -66,6 +66,28 @@ class SpriteEngine;
     uchar a;
 };*/
 
+struct SimpleVertex {
+    float x;
+    float y;
+    float tx;
+    float ty;
+    float t;
+    float lifeSpan;
+    float size;
+    float endSize;
+    float sx;
+    float sy;
+    float ax;
+    float ay;
+};
+
+struct SimpleVertices {
+    SimpleVertex v1;
+    SimpleVertex v2;
+    SimpleVertex v3;
+    SimpleVertex v4;
+};
+
 struct UltraVertex {
     float x;
     float y;
@@ -100,6 +122,13 @@ struct UltraVertices {
     UltraVertex v4;
 };
 
+struct IntermediateVertices {
+    UltraVertex* v1;
+    UltraVertex* v2;
+    UltraVertex* v3;
+    UltraVertex* v4;
+};
+
 class UltraParticle : public ParticleType
 {
     Q_OBJECT
@@ -108,6 +137,7 @@ class UltraParticle : public ParticleType
     Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
     Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
 
+    //###Now just colorize - add a flag for 'solid' color particles(where the img is just a mask?)?
     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
     //Stacks (added) with individual colorVariations
     Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
@@ -132,6 +162,7 @@ class UltraParticle : public ParticleType
     //yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
     Q_PROPERTY(VaryingVector* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
     Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+    Q_PROPERTY(bool bloat READ bloat WRITE setBloat NOTIFY bloatChanged)//Just a debugging property to bypass optimizations
 public:
     explicit UltraParticle(QSGItem *parent = 0);
     virtual ~UltraParticle(){}
@@ -143,6 +174,15 @@ public:
     QDeclarativeListProperty<SpriteState> sprites();
     SpriteEngine* spriteEngine() {return m_spriteEngine;}
 
+    enum PerformanceLevel{//TODO: Expose?
+        Unknown = 0,
+        Simple,
+        Coloured,
+        Deformable,
+        Tabled,
+        Sprites
+    };
+
     QUrl image() const { return m_image_name; }
     void setImage(const QUrl &image);
 
@@ -223,6 +263,11 @@ public:
         return m_yVector;
     }
 
+    bool bloat() const
+    {
+        return m_bloat;
+    }
+
 signals:
 
     void imageChanged();
@@ -258,6 +303,8 @@ signals:
 
     void yVectorChanged(VaryingVector* arg);
 
+    void bloatChanged(bool arg);
+
 public slots:
     void setAlphaVariation(qreal arg)
     {
@@ -356,17 +403,27 @@ public slots:
         }
     }
 
+    void setBloat(bool arg)
+    {
+        if (m_bloat != arg) {
+            m_bloat = arg;
+            emit bloatChanged(arg);
+        }
+    }
+
 protected:
     QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
     void reset();
     void prepareNextFrame();
     QSGGeometryNode* buildParticleNode();
+    QSGGeometryNode* buildSimpleParticleNode();
 
 private slots:
     void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
 
 private:
-    void vertexCopy(UltraVertex &b,const ParticleVertex& a);
+    //void vertexCopy(UltraVertex &b,const ParticleVertex& a);
+    IntermediateVertices* fetchIntermediateVertices(int pos);
     bool m_do_reset;
 
     QUrl m_image_name;
@@ -402,6 +459,8 @@ private:
     QList<SpriteState*> m_sprites;
     SpriteEngine* m_spriteEngine;
 
+    bool m_bloat;
+    PerformanceLevel perfLevel;
 };
 
 QT_END_NAMESPACE