aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports/particles
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2011-05-18 21:10:00 +1000
committerAlan Alpert <alan.alpert@nokia.com>2011-05-18 21:10:00 +1000
commitb8338a188160651fec238edb4d7fd59417eefe6d (patch)
tree1a1fe76f449f5240a62d6c00c4ebf8a4616515b7 /src/imports/particles
parentab858bc8e650f1120495f968379f37257c774b5f (diff)
Add UltraParticle
They're not as cool as they sound. Includes example, and the now pointless SuperParticle (for possible performance comparisions).
Diffstat (limited to 'src/imports/particles')
-rw-r--r--src/imports/particles/main.cpp4
-rw-r--r--src/imports/particles/particles.pro12
-rw-r--r--src/imports/particles/resources/superfragment.shader11
-rw-r--r--src/imports/particles/resources/supervertex.shader57
-rw-r--r--src/imports/particles/resources/ultrafragment.shader16
-rw-r--r--src/imports/particles/resources/ultravertex.shader94
-rw-r--r--src/imports/particles/spriteparticles.qrc4
-rw-r--r--src/imports/particles/superparticle.cpp511
-rw-r--r--src/imports/particles/superparticle.h389
-rw-r--r--src/imports/particles/ultraparticle.cpp603
-rw-r--r--src/imports/particles/ultraparticle.h409
11 files changed, 2106 insertions, 4 deletions
diff --git a/src/imports/particles/main.cpp b/src/imports/particles/main.cpp
index b2d5c27306..9382f48f66 100644
--- a/src/imports/particles/main.cpp
+++ b/src/imports/particles/main.cpp
@@ -70,6 +70,8 @@
#include "coloredparticle.h"
#include "spriteparticle.h"
#include "modelparticle.h"
+#include "superparticle.h"
+#include "ultraparticle.h"
//#include "pairedparticle.h"
#include "spriteimage.h"
#include "followemitter.h"
@@ -108,6 +110,8 @@ void ParticlesPlugin::registerTypes(const char *uri)
qmlRegisterType<ModelParticle>(uri, 2, 0, "ModelParticle");
//qmlRegisterType<PairedParticle>(uri, 2, 0, "PairedParticle");
qmlRegisterType<DeformableParticle>(uri, 2, 0, "DeformableParticle");
+ qmlRegisterType<SuperParticle>(uri, 2, 0, "SuperParticle");
+ qmlRegisterType<UltraParticle>(uri, 2, 0, "UltraParticle");
qmlRegisterType<ParticleEmitter>(uri, 2, 0, "ParticleEmitter");
qmlRegisterType<TrailsEmitter>(uri, 2, 0, "TrailEmitter");
diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro
index 56474b4b37..74820e1799 100644
--- a/src/imports/particles/particles.pro
+++ b/src/imports/particles/particles.pro
@@ -46,9 +46,9 @@ HEADERS += \
lineextruder.h \
resetaffector.h \
deformableparticle.h \
- pictureaffector.h
-
-QT += core-private gui-private declarative-private script-private
+ pictureaffector.h \
+ superparticle.h \
+ ultraparticle.h
SOURCES += \
V1/qdeclarativeparticles.cpp \
@@ -94,9 +94,13 @@ SOURCES += \
lineextruder.cpp \
resetaffector.cpp \
deformableparticle.cpp \
- pictureaffector.cpp
+ pictureaffector.cpp \
+ superparticle.cpp \
+ ultraparticle.cpp
QT += declarative opengl
+#Because we use QDeclarativePixmapCache once...
+QT += core-private gui-private declarative-private script-private
OTHER_FILES += \
diff --git a/src/imports/particles/resources/superfragment.shader b/src/imports/particles/resources/superfragment.shader
new file mode 100644
index 0000000000..a17f5841ca
--- /dev/null
+++ b/src/imports/particles/resources/superfragment.shader
@@ -0,0 +1,11 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor * texture2D(colortable, vec2(tt, 0.5)) *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/imports/particles/resources/supervertex.shader b/src/imports/particles/resources/supervertex.shader
new file mode 100644
index 0000000000..432a23ce05
--- /dev/null
+++ b/src/imports/particles/resources/supervertex.shader
@@ -0,0 +1,57 @@
+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
+attribute lowp vec4 vColor;
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform sampler2D sizetable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+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) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos;
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/imports/particles/resources/ultrafragment.shader b/src/imports/particles/resources/ultrafragment.shader
new file mode 100644
index 0000000000..0627d0f1e8
--- /dev/null
+++ b/src/imports/particles/resources/ultrafragment.shader
@@ -0,0 +1,16 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress)
+ * fColor
+ * texture2D(colortable, vec2(tt, 0.5))
+ *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/imports/particles/resources/ultravertex.shader b/src/imports/particles/resources/ultravertex.shader
new file mode 100644
index 0000000000..65a1a3077a
--- /dev/null
+++ b/src/imports/particles/resources/ultravertex.shader
@@ -0,0 +1,94 @@
+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
+attribute lowp vec4 vColor;
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+uniform sampler2D sizetable;
+
+varying lowp float tt;
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+
+void main() {
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex = vTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ //### Should the next anim be precalculated to allow for interpolation there?
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+ highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos;
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/imports/particles/spriteparticles.qrc b/src/imports/particles/spriteparticles.qrc
index c0c7a52036..b1ebc27672 100644
--- a/src/imports/particles/spriteparticles.qrc
+++ b/src/imports/particles/spriteparticles.qrc
@@ -12,5 +12,9 @@
<file>resources/defaultFadeInOut.png</file>
<file>resources/deformablefragment.shader</file>
<file>resources/deformablevertex.shader</file>
+ <file>resources/ultravertex.shader</file>
+ <file>resources/ultrafragment.shader</file>
+ <file>resources/supervertex.shader</file>
+ <file>resources/superfragment.shader</file>
</qresource>
</RCC>
diff --git a/src/imports/particles/superparticle.cpp b/src/imports/particles/superparticle.cpp
new file mode 100644
index 0000000000..811b6a4ba8
--- /dev/null
+++ b/src/imports/particles/superparticle.cpp
@@ -0,0 +1,511 @@
+/****************************************************************************
+**
+** 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 <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "superparticle.h"
+#include "particleemitter.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+const float CONV = 0.017453292519943295;
+class SuperMaterial : public QSGMaterial
+{
+public:
+ SuperMaterial()
+ : timestamp(0)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~SuperMaterial()
+ {
+ delete texture;
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const SuperMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+
+ qreal timestamp;
+};
+
+
+class SuperMaterialData : public QSGMaterialShader
+{
+public:
+ SuperMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/supervertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/superfragment.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 *)
+ {
+ SuperMaterial *m = static_cast<SuperMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE1);
+ m->colortable->bind();
+ program()->setUniformValue(m_colortable_id, 1);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE2);
+ m->sizetable->bind();
+ program()->setUniformValue(m_sizetable_id, 2);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE3);
+ m->opacitytable->bind();
+ program()->setUniformValue(m_opacitytable_id, 3);
+
+ 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_colortable_id = program()->uniformLocation("colortable");
+ m_sizetable_id = program()->uniformLocation("sizetable");
+ m_opacitytable_id = program()->uniformLocation("opacitytable");
+ 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",
+ "vColor",
+ "vDeformVec",
+ "vRotation",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_colortable_id;
+ int m_sizetable_id;
+ int m_opacitytable_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SuperMaterialData::chunkOfBytes[1024];
+
+
+QSGMaterialShader *SuperMaterial::createShader() const
+{
+ return new SuperMaterialData;
+}
+
+SuperParticle::SuperParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_color(Qt::white)
+ , m_color_variation(0.5)
+ , m_node(0)
+ , m_material(0)
+ , m_alphaVariation(0.0)
+ , m_alpha(1.0)
+ , m_redVariation(0.0)
+ , m_greenVariation(0.0)
+ , m_blueVariation(0.0)
+{
+ setFlag(ItemHasContents);
+}
+
+void SuperParticle::setImage(const QUrl &image)
+{
+ if (image == m_image_name)
+ return;
+ m_image_name = image;
+ emit imageChanged();
+ reset();
+}
+
+
+void SuperParticle::setColortable(const QUrl &table)
+{
+ if (table == m_colortable_name)
+ return;
+ m_colortable_name = table;
+ emit colortableChanged();
+ reset();
+}
+
+void SuperParticle::setSizetable(const QUrl &table)
+{
+ if (table == m_sizetable_name)
+ return;
+ m_sizetable_name = table;
+ emit sizetableChanged();
+ reset();
+}
+
+void SuperParticle::setOpacitytable(const QUrl &table)
+{
+ if (table == m_opacitytable_name)
+ return;
+ m_opacitytable_name = table;
+ emit opacitytableChanged();
+ reset();
+}
+
+void SuperParticle::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ emit colorChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void SuperParticle::setColorVariation(qreal var)
+{
+ if (var == m_color_variation)
+ return;
+ m_color_variation = var;
+ emit colorVariationChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void SuperParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void SuperParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute SuperParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_UNSIGNED_BYTE }, // Colors
+ { 5, 4, GL_FLOAT }, // DeformationVectors
+ { 6, 3, GL_FLOAT } // Rotation
+};
+
+static QSGGeometry::AttributeSet SuperParticle_AttributeSet =
+{
+ 7, // Attribute Count
+ (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
+ SuperParticle_Attributes
+};
+
+QSGGeometryNode* SuperParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("SuperParticle: Too many particles... \n");
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("SuperParticle: Too few particles... \n");
+ return 0;
+ }
+
+ QImage image(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("SuperParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(SuperParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SuperVertex *vertices = (SuperVertex *) 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[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[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;
+ }
+
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ m_material = new SuperMaterial();
+ if(colortable.isNull())
+ colortable = QImage(":resources/identitytable.png");
+ if(sizetable.isNull())
+ sizetable = QImage(":resources/identitytable.png");
+ if(opacitytable.isNull())
+ opacitytable = QImage(":resources/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *SuperParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void SuperParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+}
+
+void SuperParticle::reloadColor(const Color4ub &c, ParticleData* d)
+{
+ SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ SuperVertices &p = particles[pos];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
+}
+
+void SuperParticle::vertexCopy(SuperVertex &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;
+}
+
+void SuperParticle::reload(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
+
+ int pos = particleTypeIndex(d);
+
+ SuperVertices &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);
+}
+
+void SuperParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ //Color initialization
+ // Particle color
+ 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;
+ SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
+ SuperVertices &p = particles[particleTypeIndex(d)];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
+ 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;
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/superparticle.h b/src/imports/particles/superparticle.h
new file mode 100644
index 0000000000..ac2f9860ef
--- /dev/null
+++ b/src/imports/particles/superparticle.h
@@ -0,0 +1,389 @@
+/****************************************************************************
+**
+** 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 SUPERPARTICLE_H
+#define SUPERPARTICLE_H
+#include "particle.h"
+#include "varyingvector.h"
+
+#include "coloredparticle.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SuperMaterial;
+class QSGGeometryNode;
+
+/*struct Color4ub {//in coloredparticle
+ uchar r;
+ uchar g;
+ uchar b;
+ uchar a;
+};*/
+
+struct SuperVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ Color4ub color;
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ float rotation;
+ float rotationSpeed;
+ float autoRotate;//Assume that GPUs prefer floats to bools
+};
+
+struct SuperVertices {
+ SuperVertex v1;
+ SuperVertex v2;
+ SuperVertex v3;
+ SuperVertex v4;
+};
+
+class SuperParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ 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)
+ Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
+ Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
+ Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
+ //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
+ Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
+ Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
+ //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
+ //to 180 will lead to facing away from the direction of motion
+ Q_PROPERTY(bool autoRotation READ autoRotation WRITE autoRotation NOTIFY autoRotationChanged)
+
+ //###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
+ //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
+ Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
+ //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)
+public:
+ explicit SuperParticle(QSGItem *parent = 0);
+ virtual ~SuperParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QUrl image() const { return m_image_name; }
+ void setImage(const QUrl &image);
+
+ QUrl colortable() const { return m_colortable_name; }
+ void setColortable(const QUrl &table);
+
+ QUrl sizetable() const { return m_sizetable_name; }
+ void setSizetable (const QUrl &table);
+
+ QUrl opacitytable() const { return m_opacitytable_name; }
+ void setOpacitytable(const QUrl &table);
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+
+ qreal colorVariation() const { return m_color_variation; }
+ void setColorVariation(qreal var);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ qreal alphaVariation() const
+ {
+ return m_alphaVariation;
+ }
+
+ qreal alpha() const
+ {
+ return m_alpha;
+ }
+
+ qreal redVariation() const
+ {
+ return m_redVariation;
+ }
+
+ qreal greenVariation() const
+ {
+ return m_greenVariation;
+ }
+
+ qreal blueVariation() const
+ {
+ return m_blueVariation;
+ }
+
+ qreal rotation() const
+ {
+ return m_rotation;
+ }
+
+ qreal rotationVariation() const
+ {
+ return m_rotationVariation;
+ }
+
+ qreal rotationSpeed() const
+ {
+ return m_rotationSpeed;
+ }
+
+ qreal rotationSpeedVariation() const
+ {
+ return m_rotationSpeedVariation;
+ }
+
+ bool autoRotation() const
+ {
+ return m_autoRotation;
+ }
+
+ VaryingVector* xVector() const
+ {
+ return m_xVector;
+ }
+
+ VaryingVector* yVector() const
+ {
+ return m_yVector;
+ }
+
+signals:
+
+ void imageChanged();
+ void colortableChanged();
+ void sizetableChanged();
+ void opacitytableChanged();
+
+ void colorChanged();
+ void colorVariationChanged();
+
+ void particleDurationChanged();
+ void alphaVariationChanged(qreal arg);
+
+ void alphaChanged(qreal arg);
+
+ void redVariationChanged(qreal arg);
+
+ void greenVariationChanged(qreal arg);
+
+ void blueVariationChanged(qreal arg);
+
+ void rotationChanged(qreal arg);
+
+ void rotationVariationChanged(qreal arg);
+
+ void rotationSpeedChanged(qreal arg);
+
+ void rotationSpeedVariationChanged(qreal arg);
+
+ void autoRotationChanged(bool arg);
+
+ void xVectorChanged(VaryingVector* arg);
+
+ void yVectorChanged(VaryingVector* arg);
+
+public slots:
+ void setAlphaVariation(qreal arg)
+ {
+ if (m_alphaVariation != arg) {
+ m_alphaVariation = arg;
+ emit alphaVariationChanged(arg);
+ }
+ }
+
+ void setAlpha(qreal arg)
+ {
+ if (m_alpha != arg) {
+ m_alpha = arg;
+ emit alphaChanged(arg);
+ }
+ }
+
+ void setRedVariation(qreal arg)
+ {
+ if (m_redVariation != arg) {
+ m_redVariation = arg;
+ emit redVariationChanged(arg);
+ }
+ }
+
+ void setGreenVariation(qreal arg)
+ {
+ if (m_greenVariation != arg) {
+ m_greenVariation = arg;
+ emit greenVariationChanged(arg);
+ }
+ }
+
+ void setBlueVariation(qreal arg)
+ {
+ if (m_blueVariation != arg) {
+ m_blueVariation = arg;
+ emit blueVariationChanged(arg);
+ }
+ }
+
+ void reloadColor(const Color4ub &c, ParticleData* d);
+ void setRotation(qreal arg)
+ {
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+ }
+
+ void setRotationVariation(qreal arg)
+ {
+ if (m_rotationVariation != arg) {
+ m_rotationVariation = arg;
+ emit rotationVariationChanged(arg);
+ }
+ }
+
+ void setRotationSpeed(qreal arg)
+ {
+ if (m_rotationSpeed != arg) {
+ m_rotationSpeed = arg;
+ emit rotationSpeedChanged(arg);
+ }
+ }
+
+ void setRotationSpeedVariation(qreal arg)
+ {
+ if (m_rotationSpeedVariation != arg) {
+ m_rotationSpeedVariation = arg;
+ emit rotationSpeedVariationChanged(arg);
+ }
+ }
+
+ void autoRotation(bool arg)
+ {
+ if (m_autoRotation != arg) {
+ m_autoRotation = arg;
+ emit autoRotationChanged(arg);
+ }
+ }
+
+ void setXVector(VaryingVector* arg)
+ {
+ if (m_xVector != arg) {
+ m_xVector = arg;
+ emit xVectorChanged(arg);
+ }
+ }
+
+ void setYVector(VaryingVector* arg)
+ {
+ if (m_yVector != arg) {
+ m_yVector = arg;
+ emit yVectorChanged(arg);
+ }
+ }
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private:
+ void vertexCopy(SuperVertex &b,const ParticleVertex& a);
+ bool m_do_reset;
+
+ QUrl m_image_name;
+ QUrl m_colortable_name;
+ QUrl m_sizetable_name;
+ QUrl m_opacitytable_name;
+
+
+ QColor m_color;
+ qreal m_color_variation;
+ qreal m_particleDuration;
+
+ QSGGeometryNode *m_node;
+ SuperMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ qreal m_alphaVariation;
+ qreal m_alpha;
+ qreal m_redVariation;
+ qreal m_greenVariation;
+ qreal m_blueVariation;
+ qreal m_rotation;
+ qreal m_rotationVariation;
+ qreal m_rotationSpeed;
+ qreal m_rotationSpeedVariation;
+ bool m_autoRotation;
+ VaryingVector* m_xVector;
+ VaryingVector* m_yVector;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // SUPERPARTICLE_H
diff --git a/src/imports/particles/ultraparticle.cpp b/src/imports/particles/ultraparticle.cpp
new file mode 100644
index 0000000000..6dd05aa597
--- /dev/null
+++ b/src/imports/particles/ultraparticle.cpp
@@ -0,0 +1,603 @@
+/****************************************************************************
+**
+** 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 <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "ultraparticle.h"
+#include "particleemitter.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+const float CONV = 0.017453292519943295;
+class UltraMaterial : public QSGMaterial
+{
+public:
+ UltraMaterial()
+ : timestamp(0)
+ , framecount(1)
+ , animcount(1)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~UltraMaterial()
+ {
+ delete texture;
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const UltraMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+
+ qreal timestamp;
+ int framecount;
+ int animcount;
+};
+
+
+class UltraMaterialData : public QSGMaterialShader
+{
+public:
+ UltraMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/ultravertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/ultrafragment.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_TEXTURE1);
+ m->colortable->bind();
+ program()->setUniformValue(m_colortable_id, 1);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE2);
+ m->sizetable->bind();
+ program()->setUniformValue(m_sizetable_id, 2);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE3);
+ m->opacitytable->bind();
+ program()->setUniformValue(m_opacitytable_id, 3);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);//Investigate why this screws up Text{} if placed before 1
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+ program()->setUniformValue(m_framecount_id, (float) m->framecount);
+ program()->setUniformValue(m_animcount_id, (float) m->animcount);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_colortable_id = program()->uniformLocation("colortable");
+ m_sizetable_id = program()->uniformLocation("sizetable");
+ m_opacitytable_id = program()->uniformLocation("opacitytable");
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ m_framecount_id = program()->uniformLocation("framecount");
+ m_animcount_id = program()->uniformLocation("animcount");
+ }
+
+ 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",
+ "vColor",
+ "vDeformVec",
+ "vRotation",
+ "vAnimData",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_colortable_id;
+ int m_sizetable_id;
+ int m_opacitytable_id;
+ int m_framecount_id;
+ int m_animcount_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float UltraMaterialData::chunkOfBytes[1024];
+
+
+QSGMaterialShader *UltraMaterial::createShader() const
+{
+ return new UltraMaterialData;
+}
+
+UltraParticle::UltraParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_color(Qt::white)
+ , m_color_variation(0.5)
+ , m_node(0)
+ , m_material(0)
+ , m_alphaVariation(0.0)
+ , m_alpha(1.0)
+ , m_redVariation(0.0)
+ , m_greenVariation(0.0)
+ , m_blueVariation(0.0)
+ , m_rotation(0)
+ , m_autoRotation(false)
+ , m_xVector(0)
+ , m_yVector(0)
+ , m_rotationVariation(0)
+ , m_rotationSpeed(0)
+ , m_rotationSpeedVariation(0)
+ , m_spriteEngine(0)
+{
+ setFlag(ItemHasContents);
+}
+
+QDeclarativeListProperty<SpriteState> UltraParticle::sprites()
+{
+ return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
+
+void UltraParticle::setImage(const QUrl &image)
+{
+ if (image == m_image_name)
+ return;
+ m_image_name = image;
+ emit imageChanged();
+ reset();
+}
+
+
+void UltraParticle::setColortable(const QUrl &table)
+{
+ if (table == m_colortable_name)
+ return;
+ m_colortable_name = table;
+ emit colortableChanged();
+ reset();
+}
+
+void UltraParticle::setSizetable(const QUrl &table)
+{
+ if (table == m_sizetable_name)
+ return;
+ m_sizetable_name = table;
+ emit sizetableChanged();
+ reset();
+}
+
+void UltraParticle::setOpacitytable(const QUrl &table)
+{
+ if (table == m_opacitytable_name)
+ return;
+ m_opacitytable_name = table;
+ emit opacitytableChanged();
+ reset();
+}
+
+void UltraParticle::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ emit colorChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void UltraParticle::setColorVariation(qreal var)
+{
+ if (var == m_color_variation)
+ return;
+ m_color_variation = var;
+ emit colorVariationChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void UltraParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void UltraParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+void UltraParticle::createEngine()
+{
+ if(m_spriteEngine)
+ delete m_spriteEngine;
+ if(m_sprites.count())
+ m_spriteEngine = new SpriteEngine(m_sprites, this);
+ else
+ m_spriteEngine = 0;
+ reset();//###this is probably out of updatePaintNode and shouldn't be
+}
+
+static QSGGeometry::Attribute UltraParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_UNSIGNED_BYTE }, // Colors
+ { 5, 4, GL_FLOAT }, // DeformationVectors
+ { 6, 3, GL_FLOAT }, // Rotation
+ { 7, 4, GL_FLOAT } // Anim Data
+};
+
+static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
+{
+ 8, // Attribute Count
+ (2 + 2 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
+ UltraParticle_Attributes
+};
+
+QSGGeometryNode* UltraParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("UltraParticle: Too many particles... \n");
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("UltraParticle: Too few particles... \n");
+ return 0;
+ }
+
+ QImage image;
+ 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
+ return 0;
+ }else{
+ 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;
+
+ QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ UltraVertex *vertices = (UltraVertex *) 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[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 = 1;
+ vertices[i].frameCount = 1;
+ vertices[i].animT = -1;
+ }
+
+ 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;
+ }
+
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ m_material = new UltraMaterial();
+ if(colortable.isNull())
+ colortable = QImage(":resources/identitytable.png");
+ if(sizetable.isNull())
+ sizetable = QImage(":resources/identitytable.png");
+ if(opacitytable.isNull())
+ opacitytable = QImage(":resources/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_material->framecount = 1;
+ 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);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *UltraParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void UltraParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+
+ //Advance State
+ if(m_spriteEngine){
+ m_material->animcount = m_spriteEngine->stateCount();
+ 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->state(curIdx)->frames();
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
+ }
+ }
+ }else{
+ m_material->animcount = 1;
+ }
+}
+
+void UltraParticle::reloadColor(const Color4ub &c, ParticleData* 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 UltraParticle::vertexCopy(UltraVertex &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;
+}
+
+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];
+
+ //Perhaps we could be more efficient?
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+void UltraParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ //Color initialization
+ // Particle color
+ 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;
+ }
+
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/ultraparticle.h b/src/imports/particles/ultraparticle.h
new file mode 100644
index 0000000000..2001f09233
--- /dev/null
+++ b/src/imports/particles/ultraparticle.h
@@ -0,0 +1,409 @@
+/****************************************************************************
+**
+** 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 ULTRAPARTICLE_H
+#define ULTRAPARTICLE_H
+#include "particle.h"
+#include "varyingvector.h"
+#include <QDeclarativeListProperty>
+
+#include "coloredparticle.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class UltraMaterial;
+class QSGGeometryNode;
+
+class SpriteState;
+class SpriteEngine;
+
+/*struct Color4ub {//in coloredparticle
+ uchar r;
+ uchar g;
+ uchar b;
+ uchar a;
+};*/
+
+struct UltraVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ 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;
+};
+
+struct UltraVertices {
+ UltraVertex v1;
+ UltraVertex v2;
+ UltraVertex v3;
+ UltraVertex v4;
+};
+
+class UltraParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ 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)
+ Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
+ Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
+ Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
+ //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
+ Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
+ Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
+ //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
+ //to 180 will lead to facing away from the direction of motion
+ Q_PROPERTY(bool autoRotation READ autoRotation WRITE autoRotation NOTIFY autoRotationChanged)
+
+ //###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
+ //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
+ Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
+ //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)
+public:
+ explicit UltraParticle(QSGItem *parent = 0);
+ virtual ~UltraParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QDeclarativeListProperty<SpriteState> sprites();
+ SpriteEngine* spriteEngine() {return m_spriteEngine;}
+
+ QUrl image() const { return m_image_name; }
+ void setImage(const QUrl &image);
+
+ QUrl colortable() const { return m_colortable_name; }
+ void setColortable(const QUrl &table);
+
+ QUrl sizetable() const { return m_sizetable_name; }
+ void setSizetable (const QUrl &table);
+
+ QUrl opacitytable() const { return m_opacitytable_name; }
+ void setOpacitytable(const QUrl &table);
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+
+ qreal colorVariation() const { return m_color_variation; }
+ void setColorVariation(qreal var);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ qreal alphaVariation() const
+ {
+ return m_alphaVariation;
+ }
+
+ qreal alpha() const
+ {
+ return m_alpha;
+ }
+
+ qreal redVariation() const
+ {
+ return m_redVariation;
+ }
+
+ qreal greenVariation() const
+ {
+ return m_greenVariation;
+ }
+
+ qreal blueVariation() const
+ {
+ return m_blueVariation;
+ }
+
+ qreal rotation() const
+ {
+ return m_rotation;
+ }
+
+ qreal rotationVariation() const
+ {
+ return m_rotationVariation;
+ }
+
+ qreal rotationSpeed() const
+ {
+ return m_rotationSpeed;
+ }
+
+ qreal rotationSpeedVariation() const
+ {
+ return m_rotationSpeedVariation;
+ }
+
+ bool autoRotation() const
+ {
+ return m_autoRotation;
+ }
+
+ VaryingVector* xVector() const
+ {
+ return m_xVector;
+ }
+
+ VaryingVector* yVector() const
+ {
+ return m_yVector;
+ }
+
+signals:
+
+ void imageChanged();
+ void colortableChanged();
+ void sizetableChanged();
+ void opacitytableChanged();
+
+ void colorChanged();
+ void colorVariationChanged();
+
+ void particleDurationChanged();
+ void alphaVariationChanged(qreal arg);
+
+ void alphaChanged(qreal arg);
+
+ void redVariationChanged(qreal arg);
+
+ void greenVariationChanged(qreal arg);
+
+ void blueVariationChanged(qreal arg);
+
+ void rotationChanged(qreal arg);
+
+ void rotationVariationChanged(qreal arg);
+
+ void rotationSpeedChanged(qreal arg);
+
+ void rotationSpeedVariationChanged(qreal arg);
+
+ void autoRotationChanged(bool arg);
+
+ void xVectorChanged(VaryingVector* arg);
+
+ void yVectorChanged(VaryingVector* arg);
+
+public slots:
+ void setAlphaVariation(qreal arg)
+ {
+ if (m_alphaVariation != arg) {
+ m_alphaVariation = arg;
+ emit alphaVariationChanged(arg);
+ }
+ }
+
+ void setAlpha(qreal arg)
+ {
+ if (m_alpha != arg) {
+ m_alpha = arg;
+ emit alphaChanged(arg);
+ }
+ }
+
+ void setRedVariation(qreal arg)
+ {
+ if (m_redVariation != arg) {
+ m_redVariation = arg;
+ emit redVariationChanged(arg);
+ }
+ }
+
+ void setGreenVariation(qreal arg)
+ {
+ if (m_greenVariation != arg) {
+ m_greenVariation = arg;
+ emit greenVariationChanged(arg);
+ }
+ }
+
+ void setBlueVariation(qreal arg)
+ {
+ if (m_blueVariation != arg) {
+ m_blueVariation = arg;
+ emit blueVariationChanged(arg);
+ }
+ }
+
+ void reloadColor(const Color4ub &c, ParticleData* d);
+ void setRotation(qreal arg)
+ {
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+ }
+
+ void setRotationVariation(qreal arg)
+ {
+ if (m_rotationVariation != arg) {
+ m_rotationVariation = arg;
+ emit rotationVariationChanged(arg);
+ }
+ }
+
+ void setRotationSpeed(qreal arg)
+ {
+ if (m_rotationSpeed != arg) {
+ m_rotationSpeed = arg;
+ emit rotationSpeedChanged(arg);
+ }
+ }
+
+ void setRotationSpeedVariation(qreal arg)
+ {
+ if (m_rotationSpeedVariation != arg) {
+ m_rotationSpeedVariation = arg;
+ emit rotationSpeedVariationChanged(arg);
+ }
+ }
+
+ void autoRotation(bool arg)
+ {
+ if (m_autoRotation != arg) {
+ m_autoRotation = arg;
+ emit autoRotationChanged(arg);
+ }
+ }
+
+ void setXVector(VaryingVector* arg)
+ {
+ if (m_xVector != arg) {
+ m_xVector = arg;
+ emit xVectorChanged(arg);
+ }
+ }
+
+ void setYVector(VaryingVector* arg)
+ {
+ if (m_yVector != arg) {
+ m_yVector = arg;
+ emit yVectorChanged(arg);
+ }
+ }
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+
+private slots:
+ void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
+
+private:
+ void vertexCopy(UltraVertex &b,const ParticleVertex& a);
+ bool m_do_reset;
+
+ QUrl m_image_name;
+ QUrl m_colortable_name;
+ QUrl m_sizetable_name;
+ QUrl m_opacitytable_name;
+
+
+ QColor m_color;
+ qreal m_color_variation;
+ qreal m_particleDuration;
+
+ QSGGeometryNode *m_node;
+ UltraMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ qreal m_alphaVariation;
+ qreal m_alpha;
+ qreal m_redVariation;
+ qreal m_greenVariation;
+ qreal m_blueVariation;
+ qreal m_rotation;
+ qreal m_rotationVariation;
+ qreal m_rotationSpeed;
+ qreal m_rotationSpeedVariation;
+ bool m_autoRotation;
+ VaryingVector* m_xVector;
+ VaryingVector* m_yVector;
+
+ QList<SpriteState*> m_sprites;
+ SpriteEngine* m_spriteEngine;
+
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ULTRAPARTICLE_H