e910c9451319c02caa8238afc1a9ee809a6c10d3
[profile/ivi/qtdeclarative.git] / src / quick / particles / qquickimageparticle.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the Declarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtQuick/private/qsgcontext_p.h>
43 #include <private/qsgadaptationlayer_p.h>
44 #include <QtQuick/qsgnode.h>
45 #include <QtQuick/qsgtexturematerial.h>
46 #include <QtQuick/qsgtexture.h>
47 #include <QFile>
48 #include "qquickimageparticle_p.h"
49 #include "qquickparticleemitter_p.h"
50 #include <private/qquicksprite_p.h>
51 #include <private/qquickspriteengine_p.h>
52 #include <QOpenGLFunctions>
53 #include <QtQuick/qsgengine.h>
54 #include <QtQuick/private/qsgtexture_p.h>
55 #include <private/qdeclarativeglobal_p.h>
56 #include <cmath>
57
58 QT_BEGIN_NAMESPACE
59
60 #ifndef QT_OPENGL_ES_2
61 #define SHADER_DEFINES "#version 120\n"
62 #else
63 #define SHADER_DEFINES ""
64 #endif
65
66 //TODO: Make it larger on desktop? Requires fixing up shader code with the same define
67 #define UNIFORM_ARRAY_SIZE 64
68
69 static const char vertexShaderCode[] =
70     "#if defined(DEFORM)\n"
71     "attribute highp vec4 vPosTex;\n"
72     "#else\n"
73     "attribute highp vec2 vPos;\n"
74     "#endif\n"
75     "attribute highp vec4 vData; //  x = time,  y = lifeSpan, z = size,  w = endSize\n"
76     "attribute highp vec4 vVec; // x,y = constant speed,  z,w = acceleration\n"
77     "uniform highp float entry;\n"
78     "#if defined(COLOR)\n"
79     "attribute highp vec4 vColor;\n"
80     "#endif\n"
81     "#if defined(DEFORM)\n"
82     "attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector\n"
83     "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate\n"
84     "#endif\n"
85     "#if defined(SPRITE)\n"
86     "attribute highp vec3 vAnimData;// w,h(premultiplied of anim), interpolation progress\n"
87     "attribute highp vec4 vAnimPos;//x,y, x,y (two frames for interpolation)\n"
88     "#endif\n"
89     "\n"
90     "uniform highp mat4 qt_Matrix;\n"
91     "uniform highp float timestamp;\n"
92     "#if defined(TABLE)\n"
93     "varying lowp vec2 tt;//y is progress if Sprite mode\n"
94     "uniform highp float sizetable[64];\n"
95     "uniform highp float opacitytable[64];\n"
96     "#endif\n"
97     "#if defined(SPRITE)\n"
98     "varying highp vec4 fTexS;\n"
99     "#elif defined(DEFORM)\n"
100     "varying highp vec2 fTex;\n"
101     "#endif\n"
102     "#if defined(COLOR)\n"
103     "varying lowp vec4 fColor;\n"
104     "#else\n"
105     "varying lowp float fFade;\n"
106     "#endif\n"
107     "\n"
108     "\n"
109     "void main() {\n"
110     "\n"
111     "    highp float t = (timestamp - vData.x) / vData.y;\n"
112     "    if (t < 0. || t > 1.) {\n"
113     "#if defined(DEFORM)\n"
114     "        gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
115     "#else\n"
116     "        gl_PointSize = 0.;\n"
117     "#endif\n"
118     "    } else {\n"
119     "#if defined(SPRITE)\n"
120     "        tt.y = vAnimData.z;\n"
121     "        //Calculate frame location in texture\n"
122     "        fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;\n"
123     "        //Next frame is also passed, for interpolation\n"
124     "        fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;\n"
125     "\n"
126     "#elif defined(DEFORM)\n"
127     "        fTex = vPosTex.zw;\n"
128     "#endif\n"
129     "        highp float currentSize = mix(vData.z, vData.w, t * t);\n"
130     "        lowp float fade = 1.;\n"
131     "        highp float fadeIn = min(t * 10., 1.);\n"
132     "        highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);\n"
133     "\n"
134     "#if defined(TABLE)\n"
135     "        currentSize = currentSize * sizetable[int(floor(t*64.))];\n"
136     "        fade = fade * opacitytable[int(floor(t*64.))];\n"
137     "#endif\n"
138     "\n"
139     "        if (entry == 1.)\n"
140     "            fade = fade * fadeIn * fadeOut;\n"
141     "        else if (entry == 2.)\n"
142     "            currentSize = currentSize * fadeIn * fadeOut;\n"
143     "\n"
144     "        if (currentSize <= 0.) {\n"
145     "#if defined(DEFORM)\n"
146     "            gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
147     "#else\n"
148     "            gl_PointSize = 0.;\n"
149     "#endif\n"
150     "        } else {\n"
151     "            if (currentSize < 3.)//Sizes too small look jittery as they move\n"
152     "                currentSize = 3.;\n"
153     "\n"
154     "            highp vec2 pos;\n"
155     "#if defined(DEFORM)\n"
156     "            highp float rotation = vRotation.x + vRotation.y * t * vData.y;\n"
157     "            if (vRotation.z == 1.0){\n"
158     "                highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;\n"
159     "                rotation += atan(curVel.y, curVel.x);\n"
160     "            }\n"
161     "            highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));\n"
162     "            highp vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);\n"
163     "            highp vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;\n"
164     "            rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));\n"
165     "            /* The readable version:\n"
166     "            highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);\n"
167     "            highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);\n"
168     "            highp vec2 xRotatedDeform;\n"
169     "            xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;\n"
170     "            xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;\n"
171     "            highp vec2 yRotatedDeform;\n"
172     "            yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;\n"
173     "            yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;\n"
174     "            */\n"
175     "            pos = vPosTex.xy\n"
176     "                  + rotatedDeform.xy\n"
177     "                  + rotatedDeform.zw\n"
178     "                  + vVec.xy * t * vData.y         // apply speed\n"
179     "                  + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration\n"
180     "#else\n"
181     "            pos = vPos\n"
182     "                  + vVec.xy * t * vData.y         // apply speed vector..\n"
183     "                  + 0.5 * vVec.zw * pow(t * vData.y, 2.);\n"
184     "            gl_PointSize = currentSize;\n"
185     "#endif\n"
186     "            gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);\n"
187     "\n"
188     "#if defined(COLOR)\n"
189     "            fColor = vColor * fade;\n"
190     "#else\n"
191     "            fFade = fade;\n"
192     "#endif\n"
193     "#if defined(TABLE)\n"
194     "            tt.x = t;\n"
195     "#endif\n"
196     "        }\n"
197     "    }\n"
198     "}\n";
199
200 static const char fragmentShaderCode[] =
201     "uniform sampler2D texture;\n"
202     "uniform lowp float qt_Opacity;\n"
203     "\n"
204     "#if defined(SPRITE)\n"
205     "varying highp vec4 fTexS;\n"
206     "#elif defined(DEFORM)\n"
207     "varying highp vec2 fTex;\n"
208     "#endif\n"
209     "#if defined(COLOR)\n"
210     "varying lowp vec4 fColor;\n"
211     "#else\n"
212     "varying lowp float fFade;\n"
213     "#endif\n"
214     "#if defined(TABLE)\n"
215     "varying lowp vec2 tt;\n"
216     "uniform sampler2D colortable;\n"
217     "#endif\n"
218     "\n"
219     "void main() {\n"
220     "#if defined(SPRITE)\n"
221     "    gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), tt.y)\n"
222     "            * fColor\n"
223     "            * texture2D(colortable, tt)\n"
224     "            * qt_Opacity;\n"
225     "#elif defined(TABLE)\n"
226     "    gl_FragColor = texture2D(texture, fTex)\n"
227     "            * fColor\n"
228     "            * texture2D(colortable, tt)\n"
229     "            * qt_Opacity;\n"
230     "#elif defined(DEFORM)\n"
231     "    gl_FragColor = (texture2D(texture, fTex)) * fColor * qt_Opacity;\n"
232     "#elif defined(COLOR)\n"
233     "    gl_FragColor = (texture2D(texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
234     "#else\n"
235     "    gl_FragColor = texture2D(texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
236     "#endif\n"
237     "}\n";
238
239 const qreal CONV = 0.017453292519943295;
240 class ImageMaterialData
241 {
242     public:
243     ImageMaterialData()
244         : texture(0), colorTable(0)
245     {}
246
247     ~ImageMaterialData(){
248         delete texture;
249         delete colorTable;
250     }
251
252     QSGTexture *texture;
253     QSGTexture *colorTable;
254     float sizeTable[UNIFORM_ARRAY_SIZE];
255     float opacityTable[UNIFORM_ARRAY_SIZE];
256
257     qreal timestamp;
258     qreal entry;
259     QSizeF animSheetSize;
260 };
261
262 class TabledMaterialData : public ImageMaterialData {};
263 class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
264 {
265     QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
266
267 public:
268     TabledMaterial()
269     {
270         m_vertex_code = QByteArray(SHADER_DEFINES)
271             + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
272             + vertexShaderCode;
273
274         m_fragment_code = QByteArray(SHADER_DEFINES)
275             + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
276             + fragmentShaderCode;
277
278         Q_ASSERT(!m_vertex_code.isNull());
279         Q_ASSERT(!m_fragment_code.isNull());
280     }
281
282     const char *vertexShader() const { return m_vertex_code.constData(); }
283     const char *fragmentShader() const { return m_fragment_code.constData(); }
284
285     QList<QByteArray> attributes() const {
286         return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
287             << "vColor" << "vDeformVec" << "vRotation";
288     };
289
290     void initialize() {
291         QSGSimpleMaterialShader<TabledMaterialData>::initialize();
292         program()->bind();
293         program()->setUniformValue("texture", 0);
294         program()->setUniformValue("colortable", 1);
295         glFuncs = QOpenGLContext::currentContext()->functions();
296         m_timestamp_id = program()->uniformLocation("timestamp");
297         m_entry_id = program()->uniformLocation("entry");
298         m_sizetable_id = program()->uniformLocation("sizetable");
299         m_opacitytable_id = program()->uniformLocation("opacitytable");
300     }
301
302     void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
303         glFuncs->glActiveTexture(GL_TEXTURE1);
304         d->colorTable->bind();
305
306         glFuncs->glActiveTexture(GL_TEXTURE0);
307         d->texture->bind();
308
309         program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
310         program()->setUniformValue(m_entry_id, (float) d->entry);
311         program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1);
312         program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
313     }
314
315     int m_entry_id;
316     int m_timestamp_id;
317     int m_sizetable_id;
318     int m_opacitytable_id;
319     QByteArray m_vertex_code;
320     QByteArray m_fragment_code;
321     QOpenGLFunctions* glFuncs;
322 };
323
324 class DeformableMaterialData : public ImageMaterialData {};
325 class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData>
326 {
327     QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData)
328
329 public:
330     DeformableMaterial()
331     {
332         m_vertex_code = QByteArray(SHADER_DEFINES)
333             + QByteArray("#define DEFORM\n#define COLOR\n")
334             + vertexShaderCode;
335
336         m_fragment_code = QByteArray(SHADER_DEFINES)
337             + QByteArray("#define DEFORM\n#define COLOR\n")
338             + fragmentShaderCode;
339
340         Q_ASSERT(!m_vertex_code.isNull());
341         Q_ASSERT(!m_fragment_code.isNull());
342     }
343
344     const char *vertexShader() const { return m_vertex_code.constData(); }
345     const char *fragmentShader() const { return m_fragment_code.constData(); }
346
347     QList<QByteArray> attributes() const {
348         return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
349             << "vColor" << "vDeformVec" << "vRotation";
350     };
351
352     void initialize() {
353         QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
354         program()->bind();
355         program()->setUniformValue("texture", 0);
356         glFuncs = QOpenGLContext::currentContext()->functions();
357         m_timestamp_id = program()->uniformLocation("timestamp");
358         m_entry_id = program()->uniformLocation("entry");
359     }
360
361     void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) {
362         glFuncs->glActiveTexture(GL_TEXTURE0);
363         d->texture->bind();
364
365         program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
366         program()->setUniformValue(m_entry_id, (float) d->entry);
367     }
368
369     int m_entry_id;
370     int m_timestamp_id;
371     QByteArray m_vertex_code;
372     QByteArray m_fragment_code;
373     QOpenGLFunctions* glFuncs;
374 };
375
376 class SpriteMaterialData : public ImageMaterialData {};
377 class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
378 {
379     QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData)
380
381 public:
382     SpriteMaterial()
383     {
384         m_vertex_code = QByteArray(SHADER_DEFINES)
385             + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
386             + vertexShaderCode;
387
388         m_fragment_code = QByteArray(SHADER_DEFINES)
389             + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
390             + fragmentShaderCode;
391
392         Q_ASSERT(!m_vertex_code.isNull());
393         Q_ASSERT(!m_fragment_code.isNull());
394     }
395
396     const char *vertexShader() const { return m_vertex_code.constData(); }
397     const char *fragmentShader() const { return m_fragment_code.constData(); }
398
399     QList<QByteArray> attributes() const {
400         return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
401             << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
402     };
403
404     void initialize() {
405         QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
406         program()->bind();
407         program()->setUniformValue("texture", 0);
408         program()->setUniformValue("colortable", 1);
409         glFuncs = QOpenGLContext::currentContext()->functions();
410         //Don't actually expose the animSheetSize in the shader, it's currently only used for CPU calculations.
411         m_timestamp_id = program()->uniformLocation("timestamp");
412         m_entry_id = program()->uniformLocation("entry");
413         m_sizetable_id = program()->uniformLocation("sizetable");
414         m_opacitytable_id = program()->uniformLocation("opacitytable");
415     }
416
417     void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) {
418         glFuncs->glActiveTexture(GL_TEXTURE1);
419         d->colorTable->bind();
420
421         // make sure we end by setting GL_TEXTURE0 as active texture
422         glFuncs->glActiveTexture(GL_TEXTURE0);
423         d->texture->bind();
424
425         program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
426         program()->setUniformValue(m_entry_id, (float) d->entry);
427         program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, 64, 1);
428         program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
429     }
430
431     int m_timestamp_id;
432     int m_entry_id;
433     int m_sizetable_id;
434     int m_opacitytable_id;
435     QByteArray m_vertex_code;
436     QByteArray m_fragment_code;
437     QOpenGLFunctions* glFuncs;
438 };
439
440 class ColoredMaterialData : public ImageMaterialData {};
441 class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
442 {
443     QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData)
444
445 public:
446     ColoredMaterial()
447     {
448         m_vertex_code = QByteArray(SHADER_DEFINES)
449             + QByteArray("#define COLOR\n")
450             + vertexShaderCode;
451
452         m_fragment_code = QByteArray(SHADER_DEFINES)
453             + QByteArray("#define COLOR\n")
454             + fragmentShaderCode;
455
456         Q_ASSERT(!m_vertex_code.isNull());
457         Q_ASSERT(!m_fragment_code.isNull());
458     }
459
460     const char *vertexShader() const { return m_vertex_code.constData(); }
461     const char *fragmentShader() const { return m_fragment_code.constData(); }
462
463     void activate() {
464         QSGSimpleMaterialShader<ColoredMaterialData>::activate();
465 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
466         glEnable(GL_POINT_SPRITE);
467         glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
468 #endif
469     }
470
471     void deactivate() {
472         QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
473 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
474         glDisable(GL_POINT_SPRITE);
475         glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
476 #endif
477     }
478
479     QList<QByteArray> attributes() const {
480         return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
481     }
482
483     void initialize() {
484         QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
485         program()->bind();
486         program()->setUniformValue("texture", 0);
487         glFuncs = QOpenGLContext::currentContext()->functions();
488         m_timestamp_id = program()->uniformLocation("timestamp");
489         m_entry_id = program()->uniformLocation("entry");
490     }
491
492     void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) {
493         glFuncs->glActiveTexture(GL_TEXTURE0);
494         d->texture->bind();
495
496         program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
497         program()->setUniformValue(m_entry_id, (float) d->entry);
498     }
499
500     int m_timestamp_id;
501     int m_entry_id;
502     QByteArray m_vertex_code;
503     QByteArray m_fragment_code;
504     QOpenGLFunctions* glFuncs;
505 };
506
507 class SimpleMaterialData : public ImageMaterialData {};
508 class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
509 {
510     QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData)
511
512 public:
513     SimpleMaterial()
514     {
515         m_vertex_code = QByteArray(SHADER_DEFINES)
516             + vertexShaderCode;
517
518         m_fragment_code = QByteArray(SHADER_DEFINES)
519             + fragmentShaderCode;
520
521         Q_ASSERT(!m_vertex_code.isNull());
522         Q_ASSERT(!m_fragment_code.isNull());
523     }
524
525     const char *vertexShader() const { return m_vertex_code.constData(); }
526     const char *fragmentShader() const { return m_fragment_code.constData(); }
527
528     void activate() {
529         QSGSimpleMaterialShader<SimpleMaterialData>::activate();
530 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
531         glEnable(GL_POINT_SPRITE);
532         glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
533 #endif
534     }
535
536     void deactivate() {
537         QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
538 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
539         glDisable(GL_POINT_SPRITE);
540         glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
541 #endif
542     }
543
544     QList<QByteArray> attributes() const {
545         return QList<QByteArray>() << "vPos" << "vData" << "vVec";
546     }
547
548     void initialize() {
549         QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
550         program()->bind();
551         program()->setUniformValue("texture", 0);
552         glFuncs = QOpenGLContext::currentContext()->functions();
553         m_timestamp_id = program()->uniformLocation("timestamp");
554         m_entry_id = program()->uniformLocation("entry");
555     }
556
557     void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) {
558         glFuncs->glActiveTexture(GL_TEXTURE0);
559         d->texture->bind();
560
561         program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
562         program()->setUniformValue(m_entry_id, (float) d->entry);
563     }
564
565     int m_timestamp_id;
566     int m_entry_id;
567     QByteArray m_vertex_code;
568     QByteArray m_fragment_code;
569     QOpenGLFunctions* glFuncs;
570 };
571
572 void fillUniformArrayFromImage(float* array, const QImage& img, int size)
573 {
574     if (img.isNull()){
575         for (int i=0; i<size; i++)
576             array[i] = 1.0;
577         return;
578     }
579     QImage scaled = img.scaled(size,1);
580     for (int i=0; i<size; i++)
581         array[i] = qAlpha(scaled.pixel(i,0))/255.0;
582 }
583
584 /*!
585     \qmlclass ImageParticle QQuickImageParticle
586     \inqmlmodule QtQuick.Particles 2
587     \inherits ParticlePainter
588     \brief The ImageParticle element visualizes logical particles using an image
589
590     This element renders a logical particle as an image. The image can be
591     \list
592     \o colorized
593     \o rotated
594     \o deformed
595     \o a sprite-based animation
596     \endlist
597
598     ImageParticles implictly share data on particles if multiple ImageParticles are painting
599     the same logical particle group. This is broken down along the four capabilities listed
600     above. So if one ImageParticle defines data for rendering the particles in one of those
601     capabilities, and the other does not, then both will draw the particles the same in that
602     aspect automatically. This is primarily useful when there is some random variation on
603     the particle which is supposed to stay with it when switching painters. If both ImageParticles
604     define how they should appear for that aspect, they diverge and each appears as it is defined.
605
606     This sharing of data happens behind the scenes based off of whether properties were implicitly or explicitly
607     set. One drawback of the current implementation is that it is only possible to reset the capabilities as a whole.
608     So if you explicity set an attribute affecting color, such as redVariation, and then reset it (by setting redVariation
609     to undefined), all color data will be reset and it will begin to have an implicit value of any shared color from
610     other ImageParticles.
611 */
612 /*!
613     \qmlproperty url QtQuick.Particles2::ImageParticle::source
614
615     The source image to be used.
616
617     If the image is a sprite animation, use the sprite property instead.
618 */
619 /*!
620     \qmlproperty list<Sprite> QtQuick.Particles2::ImageParticle::sprites
621
622     The sprite or sprites used to draw this particle.
623
624     Note that the sprite image will be scaled to a square based on the size of
625     the particle being rendered.
626 */
627 /*!
628     \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable
629
630     An image whose color will be used as a 1D texture to determine color over life. E.g. when
631     the particle is halfway through its lifetime, it will have the color specified halfway
632     across the image.
633
634     This color is blended with the color property and the color of the source image.
635 */
636 /*!
637     \qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
638
639     An image whose opacity will be used as a 1D texture to determine size over life.
640
641     This property is expected to be removed shortly, in favor of custom easing curves to determine size over life.
642 */
643 /*!
644     \qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
645
646     An image whose opacity will be used as a 1D texture to determine size over life.
647
648     This property is expected to be removed shortly, in favor of custom easing curves to determine opacity over life.
649 */
650 /*!
651     \qmlproperty color QtQuick.Particles2::ImageParticle::color
652
653     If a color is specified, the provided image will be colorized with it.
654
655     Default is white (no change).
656 */
657 /*!
658     \qmlproperty real QtQuick.Particles2::ImageParticle::colorVariation
659
660     This number represents the color variation applied to individual particles.
661     Setting colorVariation is the same as setting redVariation, greenVariation,
662     and blueVariation to the same number.
663
664     Each channel can vary between particle by up to colorVariation from its usual color.
665
666     Color is measured, per channel, from 0.0 to 1.0.
667
668     Default is 0.0
669 */
670 /*!
671     \qmlproperty real QtQuick.Particles2::ImageParticle::redVariation
672     The variation in the red color channel between particles.
673
674     Color is measured, per channel, from 0.0 to 1.0.
675
676     Default is 0.0
677 */
678 /*!
679     \qmlproperty real QtQuick.Particles2::ImageParticle::greenVariation
680     The variation in the green color channel between particles.
681
682     Color is measured, per channel, from 0.0 to 1.0.
683
684     Default is 0.0
685 */
686 /*!
687     \qmlproperty real QtQuick.Particles2::ImageParticle::blueVariation
688     The variation in the blue color channel between particles.
689
690     Color is measured, per channel, from 0.0 to 1.0.
691
692     Default is 0.0
693 */
694 /*!
695     \qmlproperty real QtQuick.Particles2::ImageParticle::alpha
696     An alpha to be applied to the image. This value is multiplied by the value in
697     the image, and the value in the color property.
698
699     Particles have additive blending, so lower alpha on single particles leads
700     to stronger effects when multiple particles overlap.
701
702     Alpha is measured from 0.0 to 1.0.
703
704     Default is 1.0
705 */
706 /*!
707     \qmlproperty real QtQuick.Particles2::ImageParticle::alphaVariation
708     The variation in the alpha channel between particles.
709
710     Alpha is measured from 0.0 to 1.0.
711
712     Default is 0.0
713 */
714 /*!
715     \qmlproperty real QtQuick.Particles2::ImageParticle::rotation
716
717     If set the image will be rotated by this many degrees before it is drawn.
718
719     The particle coordinates are not transformed.
720 */
721 /*!
722     \qmlproperty real QtQuick.Particles2::ImageParticle::rotationVariation
723
724     If set the rotation of individual particles will vary by up to this much
725     between particles.
726
727 */
728 /*!
729     \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeed
730
731     If set particles will rotate at this speed in degrees/second.
732 */
733 /*!
734     \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeedVariation
735
736     If set the rotationSpeed of individual particles will vary by up to this much
737     between particles.
738
739 */
740 /*!
741     \qmlproperty bool QtQuick.Particles2::ImageParticle::autoRotation
742
743     If set to true then a rotation will be applied on top of the particles rotation, so
744     that it faces the direction of travel. So to face away from the direction of travel,
745     set autoRotation to true and rotation to 180.
746
747     Default is false
748 */
749 /*!
750     \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::xVector
751
752     Allows you to deform the particle image when drawn. The rectangular image will
753     be deformed so that the horizontal sides are in the shape of this vector instead
754     of (1,0).
755 */
756 /*!
757     \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::yVector
758
759     Allows you to deform the particle image when drawn. The rectangular image will
760     be deformed so that the vertical sides are in the shape of this vector instead
761     of (0,1).
762 */
763 /*!
764     \qmlproperty EntryEffect QtQuick.Particles2::ImageParticle::entryEffect
765
766     This property provides basic and cheap entrance and exit effects for the particles.
767     For fine-grained control, see sizeTable and opacityTable.
768
769     Acceptable values are
770     \list
771     \o None: Particles just appear and disappear.
772     \o Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
773     \o Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end.
774     \endlist
775
776     Default value is Fade.
777 */
778 /*!
779     \qmlproperty bool QtQuick.Particles2::ImageParticle::spritesInterpolate
780
781     If set to true, sprite particles will interpolate between sprite frames each rendered frame, making
782     the sprites look smoother.
783
784     Default is true.
785 */
786
787
788 QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
789     : QQuickParticlePainter(parent)
790     , m_color_variation(0.0)
791     , m_rootNode(0)
792     , m_material(0)
793     , m_alphaVariation(0.0)
794     , m_alpha(1.0)
795     , m_redVariation(0.0)
796     , m_greenVariation(0.0)
797     , m_blueVariation(0.0)
798     , m_rotation(0)
799     , m_rotationVariation(0)
800     , m_rotationSpeed(0)
801     , m_rotationSpeedVariation(0)
802     , m_autoRotation(false)
803     , m_xVector(0)
804     , m_yVector(0)
805     , m_spriteEngine(0)
806     , m_spritesInterpolate(true)
807     , m_explicitColor(false)
808     , m_explicitRotation(false)
809     , m_explicitDeformation(false)
810     , m_explicitAnimation(false)
811     , m_bypassOptimizations(false)
812     , perfLevel(Unknown)
813     , m_lastLevel(Unknown)
814     , m_debugMode(false)
815     , m_entryEffect(Fade)
816 {
817     setFlag(ItemHasContents);
818 }
819
820 QQuickImageParticle::~QQuickImageParticle()
821 {
822 }
823
824 QDeclarativeListProperty<QQuickSprite> QQuickImageParticle::sprites()
825 {
826     return QDeclarativeListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
827 }
828
829 void QQuickImageParticle::setImage(const QUrl &image)
830 {
831     if (image == m_image_name)
832         return;
833     m_image_name = image;
834     emit imageChanged();
835     reset();
836 }
837
838
839 void QQuickImageParticle::setColortable(const QUrl &table)
840 {
841     if (table == m_colortable_name)
842         return;
843     m_colortable_name = table;
844     emit colortableChanged();
845     reset();
846 }
847
848 void QQuickImageParticle::setSizetable(const QUrl &table)
849 {
850     if (table == m_sizetable_name)
851         return;
852     m_sizetable_name = table;
853     emit sizetableChanged();
854     reset();
855 }
856
857 void QQuickImageParticle::setOpacitytable(const QUrl &table)
858 {
859     if (table == m_opacitytable_name)
860         return;
861     m_opacitytable_name = table;
862     emit opacitytableChanged();
863     reset();
864 }
865
866 void QQuickImageParticle::setColor(const QColor &color)
867 {
868     if (color == m_color)
869         return;
870     m_color = color;
871     emit colorChanged();
872     m_explicitColor = true;
873     if (perfLevel < Colored)
874         reset();
875 }
876
877 void QQuickImageParticle::setColorVariation(qreal var)
878 {
879     if (var == m_color_variation)
880         return;
881     m_color_variation = var;
882     emit colorVariationChanged();
883     m_explicitColor = true;
884     if (perfLevel < Colored)
885         reset();
886 }
887
888 void QQuickImageParticle::setAlphaVariation(qreal arg)
889 {
890     if (m_alphaVariation != arg) {
891         m_alphaVariation = arg;
892         emit alphaVariationChanged(arg);
893     }
894     m_explicitColor = true;
895     if (perfLevel < Colored)
896         reset();
897 }
898
899 void QQuickImageParticle::setAlpha(qreal arg)
900 {
901     if (m_alpha != arg) {
902         m_alpha = arg;
903         emit alphaChanged(arg);
904     }
905     m_explicitColor = true;
906     if (perfLevel < Colored)
907         reset();
908 }
909
910 void QQuickImageParticle::setRedVariation(qreal arg)
911 {
912     if (m_redVariation != arg) {
913         m_redVariation = arg;
914         emit redVariationChanged(arg);
915     }
916     m_explicitColor = true;
917     if (perfLevel < Colored)
918         reset();
919 }
920
921 void QQuickImageParticle::setGreenVariation(qreal arg)
922 {
923     if (m_greenVariation != arg) {
924         m_greenVariation = arg;
925         emit greenVariationChanged(arg);
926     }
927     m_explicitColor = true;
928     if (perfLevel < Colored)
929         reset();
930 }
931
932 void QQuickImageParticle::setBlueVariation(qreal arg)
933 {
934     if (m_blueVariation != arg) {
935         m_blueVariation = arg;
936         emit blueVariationChanged(arg);
937     }
938     m_explicitColor = true;
939     if (perfLevel < Colored)
940         reset();
941 }
942
943 void QQuickImageParticle::setRotation(qreal arg)
944 {
945     if (m_rotation != arg) {
946         m_rotation = arg;
947         emit rotationChanged(arg);
948     }
949     m_explicitRotation = true;
950     if (perfLevel < Deformable)
951         reset();
952 }
953
954 void QQuickImageParticle::setRotationVariation(qreal arg)
955 {
956     if (m_rotationVariation != arg) {
957         m_rotationVariation = arg;
958         emit rotationVariationChanged(arg);
959     }
960     m_explicitRotation = true;
961     if (perfLevel < Deformable)
962         reset();
963 }
964
965 void QQuickImageParticle::setRotationSpeed(qreal arg)
966 {
967     if (m_rotationSpeed != arg) {
968         m_rotationSpeed = arg;
969         emit rotationSpeedChanged(arg);
970     }
971     m_explicitRotation = true;
972     if (perfLevel < Deformable)
973         reset();
974 }
975
976 void QQuickImageParticle::setRotationSpeedVariation(qreal arg)
977 {
978     if (m_rotationSpeedVariation != arg) {
979         m_rotationSpeedVariation = arg;
980         emit rotationSpeedVariationChanged(arg);
981     }
982     m_explicitRotation = true;
983     if (perfLevel < Deformable)
984         reset();
985 }
986
987 void QQuickImageParticle::setAutoRotation(bool arg)
988 {
989     if (m_autoRotation != arg) {
990         m_autoRotation = arg;
991         emit autoRotationChanged(arg);
992     }
993     m_explicitRotation = true;
994     if (perfLevel < Deformable)
995         reset();
996 }
997
998 void QQuickImageParticle::setXVector(QQuickDirection* arg)
999 {
1000     if (m_xVector != arg) {
1001         m_xVector = arg;
1002         emit xVectorChanged(arg);
1003     }
1004     m_explicitDeformation = true;
1005     if (perfLevel < Deformable)
1006         reset();
1007 }
1008
1009 void QQuickImageParticle::setYVector(QQuickDirection* arg)
1010 {
1011     if (m_yVector != arg) {
1012         m_yVector = arg;
1013         emit yVectorChanged(arg);
1014     }
1015     m_explicitDeformation = true;
1016     if (perfLevel < Deformable)
1017         reset();
1018 }
1019
1020 void QQuickImageParticle::setSpritesInterpolate(bool arg)
1021 {
1022     if (m_spritesInterpolate != arg) {
1023         m_spritesInterpolate = arg;
1024         emit spritesInterpolateChanged(arg);
1025     }
1026 }
1027
1028 void QQuickImageParticle::setBypassOptimizations(bool arg)
1029 {
1030     if (m_bypassOptimizations != arg) {
1031         m_bypassOptimizations = arg;
1032         emit bypassOptimizationsChanged(arg);
1033     }
1034     if (perfLevel < 9999)
1035         reset();
1036 }
1037
1038 void QQuickImageParticle::setEntryEffect(EntryEffect arg)
1039 {
1040     if (m_entryEffect != arg) {
1041         m_entryEffect = arg;
1042         if (m_material)
1043             getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1044         emit entryEffectChanged(arg);
1045     }
1046 }
1047
1048 void QQuickImageParticle::resetColor()
1049 {
1050     m_explicitColor = false;
1051     foreach (const QString &str, m_groups)
1052         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1053             if (d->colorOwner == this)
1054                 d->colorOwner = 0;
1055     m_color = QColor();
1056     m_color_variation = 0.0f;
1057     m_redVariation = 0.0f;
1058     m_blueVariation = 0.0f;
1059     m_greenVariation = 0.0f;
1060     m_alpha = 1.0f;
1061     m_alphaVariation = 0.0f;
1062 }
1063
1064 void QQuickImageParticle::resetRotation()
1065 {
1066     m_explicitRotation = false;
1067     foreach (const QString &str, m_groups)
1068         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1069             if (d->rotationOwner == this)
1070                 d->rotationOwner = 0;
1071     m_rotation = 0;
1072     m_rotationVariation = 0;
1073     m_rotationSpeed = 0;
1074     m_rotationSpeedVariation = 0;
1075     m_autoRotation = false;
1076 }
1077
1078 void QQuickImageParticle::resetDeformation()
1079 {
1080     m_explicitDeformation = false;
1081     foreach (const QString &str, m_groups)
1082         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1083             if (d->deformationOwner == this)
1084                 d->deformationOwner = 0;
1085     if (m_xVector)
1086         delete m_xVector;
1087     if (m_yVector)
1088         delete m_yVector;
1089     m_xVector = 0;
1090     m_yVector = 0;
1091 }
1092
1093 void QQuickImageParticle::reset()
1094 {
1095     QQuickParticlePainter::reset();
1096     m_pleaseReset = true;
1097     update();
1098 }
1099
1100 void QQuickImageParticle::createEngine()
1101 {
1102     if (m_spriteEngine)
1103         delete m_spriteEngine;
1104     if (m_sprites.count()) {
1105         m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1106         connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1107                 this, SLOT(spriteAdvance(int)), Qt::DirectConnection);
1108         m_explicitAnimation = true;
1109     } else {
1110         m_spriteEngine = 0;
1111         m_explicitAnimation = false;
1112     }
1113     reset();
1114 }
1115
1116 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
1117     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
1118     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1119     QSGGeometry::Attribute::create(2, 4, GL_FLOAT)             // Vectors
1120 };
1121
1122 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
1123 {
1124     3, // Attribute Count
1125     ( 2 + 4 + 4 ) * sizeof(float),
1126     SimpleParticle_Attributes
1127 };
1128
1129 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
1130     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
1131     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1132     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1133     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1134 };
1135
1136 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
1137 {
1138     4, // Attribute Count
1139     ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1140     ColoredParticle_Attributes
1141 };
1142
1143 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
1144     QSGGeometry::Attribute::create(0, 4, GL_FLOAT),             // Position & TexCoord
1145     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1146     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1147     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1148     QSGGeometry::Attribute::create(4, 4, GL_FLOAT),             // DeformationVectors
1149     QSGGeometry::Attribute::create(5, 3, GL_FLOAT),             // Rotation
1150 };
1151
1152 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1153 {
1154     6, // Attribute Count
1155     (4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1156     DeformableParticle_Attributes
1157 };
1158
1159 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1160     QSGGeometry::Attribute::create(0, 4, GL_FLOAT),       // Position & TexCoord
1161     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1162     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1163     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1164     QSGGeometry::Attribute::create(4, 4, GL_FLOAT),             // DeformationVectors
1165     QSGGeometry::Attribute::create(5, 3, GL_FLOAT),             // Rotation
1166     QSGGeometry::Attribute::create(6, 3, GL_FLOAT),             // Anim Data
1167     QSGGeometry::Attribute::create(7, 4, GL_FLOAT)              // Anim Pos
1168 };
1169
1170 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1171 {
1172     8, // Attribute Count
1173     (4 + 4 + 4 + 4 + 3 + 3 + 4) * sizeof(float) + 4 * sizeof(uchar),
1174     SpriteParticle_Attributes
1175 };
1176
1177 void QQuickImageParticle::clearShadows()
1178 {
1179     foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1180         qDeleteAll(data);
1181     m_shadowData.clear();
1182 }
1183
1184 //Only call if you need to, may initialize the whole array first time
1185 QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1186 {
1187     QQuickParticleGroupData* gd = m_system->groupData[datum->group];
1188     if (!m_shadowData.contains(datum->group)) {
1189         QVector<QQuickParticleData*> data;
1190         for (int i=0; i<gd->size(); i++){
1191             QQuickParticleData* datum = new QQuickParticleData(m_system);
1192             *datum = *(gd->data[i]);
1193             data << datum;
1194         }
1195         m_shadowData.insert(datum->group, data);
1196     }
1197     //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1198
1199     return m_shadowData[datum->group][datum->index];
1200 }
1201
1202 QSGGeometryNode* QQuickImageParticle::buildParticleNodes()
1203 {
1204 #ifdef QT_OPENGL_ES_2
1205     if (m_count * 4 > 0xffff) {
1206         printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1207         return 0;
1208     }
1209 #endif
1210
1211     if (count() <= 0)
1212         return 0;
1213
1214     m_debugMode = m_system->m_debugMode;
1215
1216     if (m_sprites.count() || m_bypassOptimizations) {
1217         perfLevel = Sprites;
1218     } else if (!m_colortable_name.isEmpty() || !m_sizetable_name.isEmpty()
1219                || !m_opacitytable_name.isEmpty()) {
1220         perfLevel = Tabled;
1221     } else if (m_autoRotation || m_rotation || m_rotationVariation
1222                || m_rotationSpeed || m_rotationSpeedVariation
1223                || m_xVector || m_yVector) {
1224         perfLevel = Deformable;
1225     } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1226                || m_redVariation || m_blueVariation || m_greenVariation) {
1227         perfLevel = Colored;
1228     } else {
1229         perfLevel = Simple;
1230     }
1231
1232     foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1233         int gIdx = m_system->groupIds[str];
1234         foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){
1235             QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1236             if (other){
1237                 if (other->perfLevel > perfLevel) {
1238                     if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1239                         if (perfLevel < Deformable)
1240                             perfLevel = Deformable;
1241                     } else {
1242                         perfLevel = other->perfLevel;
1243                     }
1244                 } else if (other->perfLevel < perfLevel) {
1245                     other->reset();
1246                 }
1247             }
1248         }
1249     }
1250
1251     if (perfLevel >= Colored  && !m_color.isValid())
1252         m_color = QColor(Qt::white);//Hidden default, but different from unset
1253
1254     QImage image;
1255     if (perfLevel >= Sprites){
1256         if (!m_spriteEngine) {
1257             qWarning() << "ImageParticle: No sprite engine...";
1258             //Sprite performance mode with static image is supported, but not advised
1259             //Note that in this case it always uses shadow data
1260         } else {
1261             image = m_spriteEngine->assembledImage();
1262             if (image.isNull())//Warning is printed in engine
1263                 return 0;
1264         }
1265     }
1266
1267     if ( image.isNull() ) {
1268         image = QImage(m_image_name.toLocalFile());
1269         if (image.isNull()) {
1270             printf("ImageParticle: loading image failed '%s'\n", qPrintable(m_image_name.toLocalFile()));
1271             return 0;
1272         }
1273     }
1274
1275     clearShadows();
1276     if (m_material)
1277         m_material = 0;
1278
1279     //Setup material
1280     QImage colortable;
1281     QImage sizetable;
1282     QImage opacitytable;
1283     switch (perfLevel) {//Fallthrough intended
1284     case Sprites:
1285         m_material = SpriteMaterial::createMaterial();
1286         getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1287         if (m_spriteEngine)
1288             m_spriteEngine->setCount(m_count);
1289     case Tabled:
1290         if (!m_material)
1291             m_material = TabledMaterial::createMaterial();
1292         colortable = QImage(m_colortable_name.toLocalFile());
1293         sizetable = QImage(m_sizetable_name.toLocalFile());
1294         opacitytable = QImage(m_opacitytable_name.toLocalFile());
1295         if (colortable.isNull()){
1296             colortable = QImage(1,1,QImage::Format_ARGB32);
1297             colortable.fill(Qt::white);
1298         }
1299         Q_ASSERT(!colortable.isNull());
1300         getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1301         fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1302         fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1303     case Deformable:
1304         if (!m_material)
1305             m_material = DeformableMaterial::createMaterial();
1306     case Colored:
1307         if (!m_material)
1308             m_material = ColoredMaterial::createMaterial();
1309     default://Also Simple
1310         if (!m_material)
1311             m_material = SimpleMaterial::createMaterial();
1312         getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1313         getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1314         getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1315         m_material->setFlag(QSGMaterial::Blending);
1316     }
1317
1318     m_nodes.clear();
1319     foreach (const QString &str, m_groups){
1320         int gIdx = m_system->groupIds[str];
1321         int count = m_system->groupData[gIdx]->size();
1322         QSGGeometryNode* node = new QSGGeometryNode();
1323         node->setMaterial(m_material);
1324         node->markDirty(QSGNode::DirtyMaterial);
1325
1326         m_nodes.insert(gIdx, node);
1327         m_idxStarts.insert(gIdx, m_lastIdxStart);
1328         m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx));
1329         m_lastIdxStart += count;
1330
1331         //Create Particle Geometry
1332         int vCount = count * 4;
1333         int iCount = count * 6;
1334
1335         QSGGeometry *g;
1336         if (perfLevel == Sprites)
1337             g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1338         else if (perfLevel == Tabled)
1339             g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1340         else if (perfLevel == Deformable)
1341             g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1342         else if (perfLevel == Colored)
1343             g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1344         else //Simple
1345             g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1346
1347         node->setGeometry(g);
1348         if (perfLevel <= Colored){
1349             g->setDrawingMode(GL_POINTS);
1350             if (m_debugMode){
1351                 GLfloat pointSizeRange[2];
1352                 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1353                 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1354             }
1355         }else
1356             g->setDrawingMode(GL_TRIANGLES);
1357
1358         for (int p=0; p < count; ++p)
1359             commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1360
1361         if (perfLevel == Sprites)
1362             initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1363         else if (perfLevel == Tabled)
1364             initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1365         else if (perfLevel == Deformable)
1366             initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1367
1368         if (perfLevel > Colored){
1369             quint16 *indices = g->indexDataAsUShort();
1370             for (int i=0; i < count; ++i) {
1371                 int o = i * 4;
1372                 indices[0] = o;
1373                 indices[1] = o + 1;
1374                 indices[2] = o + 2;
1375                 indices[3] = o + 1;
1376                 indices[4] = o + 3;
1377                 indices[5] = o + 2;
1378                 indices += 6;
1379             }
1380         }
1381     }
1382
1383     if (perfLevel == Sprites)
1384         spritesUpdate();//Gives all vertexes the initial sprite data, then maintained per frame
1385
1386     foreach (QSGGeometryNode* node, m_nodes){
1387         if (node == *(m_nodes.begin()))
1388             node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1389         else
1390             (*(m_nodes.begin()))->appendChildNode(node);
1391     }
1392
1393     return *(m_nodes.begin());
1394 }
1395
1396 QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1397 {
1398     if (m_pleaseReset){
1399         m_lastLevel = perfLevel;
1400
1401         delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1402         m_rootNode = 0;
1403         m_nodes.clear();
1404
1405         m_idxStarts.clear();
1406         m_startsIdx.clear();
1407         m_lastIdxStart = 0;
1408
1409         m_material = 0;
1410
1411         m_pleaseReset = false;
1412     }
1413
1414     if (m_system && m_system->isRunning() && !m_system->isPaused()){
1415         prepareNextFrame();
1416         if (m_rootNode) {
1417             update();
1418             foreach (QSGGeometryNode* node, m_nodes)
1419                 node->markDirty(QSGNode::DirtyGeometry);
1420         }
1421     }
1422
1423     return m_rootNode;
1424 }
1425
1426 void QQuickImageParticle::prepareNextFrame()
1427 {
1428     if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1429         m_rootNode = buildParticleNodes();
1430         if (m_debugMode) {
1431             qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1432             qDebug() << "QQuickImageParticle Nodes: ";
1433             int count = 0;
1434             foreach (int i, m_nodes.keys()) {
1435                 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1436                 count += m_system->groupData[i]->size();
1437             }
1438             qDebug() << "Total count: " << count;
1439         }
1440         if (m_rootNode == 0)
1441             return;
1442     }
1443     qint64 timeStamp = m_system->systemSync(this);
1444
1445     qreal time = timeStamp / 1000.;
1446
1447     switch (perfLevel){//Fall-through intended
1448     case Sprites:
1449         //Advance State
1450         if (m_spriteEngine)
1451             m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed
1452         spritesUpdate(time);
1453     case Tabled:
1454     case Deformable:
1455     case Colored:
1456     case Simple:
1457     default: //Also Simple
1458         getState<ImageMaterialData>(m_material)->timestamp = time;
1459         break;
1460     }
1461     foreach (QSGGeometryNode* node, m_nodes)
1462         node->markDirty(QSGNode::DirtyMaterial);
1463 }
1464
1465 void QQuickImageParticle::spritesUpdate(qreal time)
1466 {
1467     // Sprite progression handled CPU side, so as to have per-frame control.
1468     foreach (const QString &str, m_groups) {
1469         int gIdx = m_system->groupIds[str];
1470         foreach (QQuickParticleData* mainDatum, m_system->groupData[gIdx]->data) {
1471             QSGGeometryNode *node = m_nodes[gIdx];
1472             if (!node)
1473                 continue;
1474             //TODO: Interpolate between two different animations if it's going to transition next frame
1475             //      This is particularly important for cut-up sprites.
1476             QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1477             int spriteIdx = 0;
1478             for (int i = 0; i<m_startsIdx.count(); i++) {
1479                 if (m_startsIdx[i].second == gIdx){
1480                     spriteIdx = m_startsIdx[i].first + datum->index;
1481                     break;
1482                 }
1483             }
1484
1485             double frameAt;
1486             qreal progress = 0;
1487
1488             if (datum->frameDuration > 0) {
1489                 qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0);
1490                 frame = qBound((qreal)0.0, frame, (qreal)((qreal)datum->frameCount - 1.0));//Stop at count-1 frames until we have between anim interpolation
1491                 if (m_spritesInterpolate)
1492                     progress = modf(frame,&frameAt);
1493                 else
1494                     modf(frame,&frameAt);
1495             } else {
1496                 datum->frameAt++;
1497                 if (datum->frameAt >= datum->frameCount){
1498                     datum->frameAt = 0;
1499                     m_spriteEngine->advance(spriteIdx);
1500                 }
1501                 frameAt = datum->frameAt;
1502             }
1503             if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too?
1504                 frameAt = (datum->frameCount - 1) - frameAt;
1505             QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize;
1506             qreal y = datum->animY / sheetSize.height();
1507             qreal w = datum->animWidth / sheetSize.width();
1508             qreal h = datum->animHeight / sheetSize.height();
1509             qreal x1 = datum->animX / sheetSize.width();
1510             x1 += frameAt * w;
1511             qreal x2 = x1;
1512             if (frameAt < (datum->frameCount-1))
1513                 x2 += w;
1514
1515             node->setFlag(QSGNode::OwnsGeometry, false);
1516             SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1517             spriteVertices += datum->index*4;
1518             for (int i=0; i<4; i++) {
1519                 spriteVertices[i].animX1 = x1;
1520                 spriteVertices[i].animY1 = y;
1521                 spriteVertices[i].animX2 = x2;
1522                 spriteVertices[i].animY2 = y;
1523                 spriteVertices[i].animW = w;
1524                 spriteVertices[i].animH = h;
1525                 spriteVertices[i].animProgress = progress;
1526             }
1527             node->setFlag(QSGNode::OwnsGeometry, true);
1528         }
1529     }
1530 }
1531
1532 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1533 {
1534     if (!m_startsIdx.count())//Probably overly defensive
1535         return;
1536
1537     int gIdx = -1;
1538     int i;
1539     for (i = 0; i<m_startsIdx.count(); i++) {
1540         if (spriteIdx < m_startsIdx[i].first) {
1541             gIdx = m_startsIdx[i-1].second;
1542             break;
1543         }
1544     }
1545     if (gIdx == -1)
1546         gIdx = m_startsIdx[i-1].second;
1547     int pIdx = spriteIdx - m_startsIdx[i-1].first;
1548
1549     QQuickParticleData* mainDatum = m_system->groupData[gIdx]->data[pIdx];
1550     QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1551
1552     datum->animIdx = m_spriteEngine->spriteState(spriteIdx);
1553     datum->animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1554     datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1555     datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / datum->frameCount;
1556     datum->animX = m_spriteEngine->spriteX(spriteIdx);
1557     datum->animY = m_spriteEngine->spriteY(spriteIdx);
1558     datum->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1559     datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1560 }
1561
1562 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1563 {
1564     d->color = c;
1565     //TODO: get index for reload - or make function take an index
1566 }
1567
1568 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1569 {
1570     Color4ub color;
1571     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1572     qreal redVariation = m_color_variation + m_redVariation;
1573     qreal greenVariation = m_color_variation + m_greenVariation;
1574     qreal blueVariation = m_color_variation + m_blueVariation;
1575     int spriteIdx = 0;
1576     if (m_spriteEngine) {
1577         spriteIdx = m_idxStarts[gIdx] + datum->index;
1578         if (spriteIdx >= m_spriteEngine->count())
1579             m_spriteEngine->setCount(spriteIdx+1);
1580     }
1581
1582     float rotation;
1583     float rotationSpeed;
1584     float autoRotate;
1585     switch (perfLevel){//Fall-through is intended on all of them
1586         case Sprites:
1587             // Initial Sprite State
1588             if (m_explicitAnimation && m_spriteEngine){
1589                 if (!datum->animationOwner)
1590                     datum->animationOwner = this;
1591                 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1592                 writeTo->animT = writeTo->t;
1593                 //writeTo->animInterpolate = m_spritesInterpolate;
1594                 if (m_spriteEngine){
1595                     m_spriteEngine->start(spriteIdx);
1596                     writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1597                     writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / writeTo->frameCount;
1598                     writeTo->animIdx = 0;//Always starts at 0
1599                     writeTo->frameAt = -1;
1600                     writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1601                     writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1602                     writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1603                     writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1604                 }
1605             } else {
1606                 QQuickParticleData* writeTo = getShadowDatum(datum);
1607                 writeTo->animT = datum->t;
1608                 writeTo->frameCount = 1;
1609                 writeTo->frameDuration = 60000000.0;
1610                 writeTo->frameAt = -1;
1611                 writeTo->animIdx = 0;
1612                 writeTo->animT = 0;
1613                 writeTo->animX = writeTo->animY = 0;
1614                 writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
1615                 writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
1616             }
1617         case Tabled:
1618         case Deformable:
1619             //Initial Rotation
1620             if (m_explicitDeformation){
1621                 if (!datum->deformationOwner)
1622                     datum->deformationOwner = this;
1623                 if (m_xVector){
1624                     const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1625                     if (datum->deformationOwner == this) {
1626                         datum->xx = ret.x();
1627                         datum->xy = ret.y();
1628                     } else {
1629                         getShadowDatum(datum)->xx = ret.x();
1630                         getShadowDatum(datum)->xy = ret.y();
1631                     }
1632                 }
1633                 if (m_yVector){
1634                     const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1635                     if (datum->deformationOwner == this) {
1636                         datum->yx = ret.x();
1637                         datum->yy = ret.y();
1638                     } else {
1639                         getShadowDatum(datum)->yx = ret.x();
1640                         getShadowDatum(datum)->yy = ret.y();
1641                     }
1642                 }
1643             }
1644
1645             if (m_explicitRotation){
1646                 if (!datum->rotationOwner)
1647                     datum->rotationOwner = this;
1648                 rotation =
1649                         (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1650                 rotationSpeed =
1651                         (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1652                 autoRotate = m_autoRotation?1.0:0.0;
1653                 if (datum->rotationOwner == this) {
1654                     datum->rotation = rotation;
1655                     datum->rotationSpeed = rotationSpeed;
1656                     datum->autoRotate = autoRotate;
1657                 } else {
1658                     getShadowDatum(datum)->rotation = rotation;
1659                     getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1660                     getShadowDatum(datum)->autoRotate = autoRotate;
1661                 }
1662             }
1663         case Colored:
1664             //Color initialization
1665             // Particle color
1666             if (m_explicitColor) {
1667                 if (!datum->colorOwner)
1668                     datum->colorOwner = this;
1669                 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1670                 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1671                 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1672                 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1673                 if (datum->colorOwner == this)
1674                     datum->color = color;
1675                 else
1676                     getShadowDatum(datum)->color = color;
1677             }
1678         default:
1679             break;
1680     }
1681 }
1682
1683 void QQuickImageParticle::commit(int gIdx, int pIdx)
1684 {
1685     if (m_pleaseReset)
1686         return;
1687     QSGGeometryNode *node = m_nodes[gIdx];
1688     if (!node)
1689         return;
1690     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1691     node->setFlag(QSGNode::OwnsGeometry, false);
1692     SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1693     DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1694     ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1695     SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1696     switch (perfLevel){//No automatic fall through intended on this one
1697     case Sprites:
1698         spriteVertices += pIdx*4;
1699         for (int i=0; i<4; i++){
1700             spriteVertices[i].x = datum->x  - m_systemOffset.x();
1701             spriteVertices[i].y = datum->y  - m_systemOffset.y();
1702             spriteVertices[i].t = datum->t;
1703             spriteVertices[i].lifeSpan = datum->lifeSpan;
1704             spriteVertices[i].size = datum->size;
1705             spriteVertices[i].endSize = datum->endSize;
1706             spriteVertices[i].vx = datum->vx;
1707             spriteVertices[i].vy = datum->vy;
1708             spriteVertices[i].ax = datum->ax;
1709             spriteVertices[i].ay = datum->ay;
1710             if (m_explicitDeformation && datum->deformationOwner != this) {
1711                 QQuickParticleData* shadow = getShadowDatum(datum);
1712                 spriteVertices[i].xx = shadow->xx;
1713                 spriteVertices[i].xy = shadow->xy;
1714                 spriteVertices[i].yx = shadow->yx;
1715                 spriteVertices[i].yy = shadow->yy;
1716             } else {
1717                 spriteVertices[i].xx = datum->xx;
1718                 spriteVertices[i].xy = datum->xy;
1719                 spriteVertices[i].yx = datum->yx;
1720                 spriteVertices[i].yy = datum->yy;
1721             }
1722             if (m_explicitRotation && datum->rotationOwner != this) {
1723                 QQuickParticleData* shadow = getShadowDatum(datum);
1724                 spriteVertices[i].rotation = shadow->rotation;
1725                 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1726                 spriteVertices[i].autoRotate = shadow->autoRotate;
1727             } else {
1728                 spriteVertices[i].rotation = datum->rotation;
1729                 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1730                 spriteVertices[i].autoRotate = datum->autoRotate;
1731             }
1732             //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand
1733             if (m_explicitColor && datum->colorOwner != this) {
1734                 QQuickParticleData* shadow = getShadowDatum(datum);
1735                 spriteVertices[i].color.r = shadow->color.r;
1736                 spriteVertices[i].color.g = shadow->color.g;
1737                 spriteVertices[i].color.b = shadow->color.b;
1738                 spriteVertices[i].color.a = shadow->color.a;
1739             } else {
1740                 spriteVertices[i].color.r = datum->color.r;
1741                 spriteVertices[i].color.g = datum->color.g;
1742                 spriteVertices[i].color.b = datum->color.b;
1743                 spriteVertices[i].color.a = datum->color.a;
1744             }
1745         }
1746         break;
1747     case Tabled: //Fall through until it has its own vertex class
1748     case Deformable:
1749         deformableVertices += pIdx*4;
1750         for (int i=0; i<4; i++){
1751             deformableVertices[i].x = datum->x  - m_systemOffset.x();
1752             deformableVertices[i].y = datum->y  - m_systemOffset.y();
1753             deformableVertices[i].t = datum->t;
1754             deformableVertices[i].lifeSpan = datum->lifeSpan;
1755             deformableVertices[i].size = datum->size;
1756             deformableVertices[i].endSize = datum->endSize;
1757             deformableVertices[i].vx = datum->vx;
1758             deformableVertices[i].vy = datum->vy;
1759             deformableVertices[i].ax = datum->ax;
1760             deformableVertices[i].ay = datum->ay;
1761             if (m_explicitDeformation && datum->deformationOwner != this) {
1762                 QQuickParticleData* shadow = getShadowDatum(datum);
1763                 deformableVertices[i].xx = shadow->xx;
1764                 deformableVertices[i].xy = shadow->xy;
1765                 deformableVertices[i].yx = shadow->yx;
1766                 deformableVertices[i].yy = shadow->yy;
1767             } else {
1768                 deformableVertices[i].xx = datum->xx;
1769                 deformableVertices[i].xy = datum->xy;
1770                 deformableVertices[i].yx = datum->yx;
1771                 deformableVertices[i].yy = datum->yy;
1772             }
1773             if (m_explicitRotation && datum->rotationOwner != this) {
1774                 QQuickParticleData* shadow = getShadowDatum(datum);
1775                 deformableVertices[i].rotation = shadow->rotation;
1776                 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1777                 deformableVertices[i].autoRotate = shadow->autoRotate;
1778             } else {
1779                 deformableVertices[i].rotation = datum->rotation;
1780                 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1781                 deformableVertices[i].autoRotate = datum->autoRotate;
1782             }
1783             if (m_explicitColor && datum->colorOwner != this) {
1784                 QQuickParticleData* shadow = getShadowDatum(datum);
1785                 deformableVertices[i].color.r = shadow->color.r;
1786                 deformableVertices[i].color.g = shadow->color.g;
1787                 deformableVertices[i].color.b = shadow->color.b;
1788                 deformableVertices[i].color.a = shadow->color.a;
1789             } else {
1790                 deformableVertices[i].color.r = datum->color.r;
1791                 deformableVertices[i].color.g = datum->color.g;
1792                 deformableVertices[i].color.b = datum->color.b;
1793                 deformableVertices[i].color.a = datum->color.a;
1794             }
1795         }
1796         break;
1797     case Colored:
1798         coloredVertices += pIdx*1;
1799         for (int i=0; i<1; i++){
1800             coloredVertices[i].x = datum->x  - m_systemOffset.x();
1801             coloredVertices[i].y = datum->y  - m_systemOffset.y();
1802             coloredVertices[i].t = datum->t;
1803             coloredVertices[i].lifeSpan = datum->lifeSpan;
1804             coloredVertices[i].size = datum->size;
1805             coloredVertices[i].endSize = datum->endSize;
1806             coloredVertices[i].vx = datum->vx;
1807             coloredVertices[i].vy = datum->vy;
1808             coloredVertices[i].ax = datum->ax;
1809             coloredVertices[i].ay = datum->ay;
1810             if (m_explicitColor && datum->colorOwner != this) {
1811                 QQuickParticleData* shadow = getShadowDatum(datum);
1812                 coloredVertices[i].color.r = shadow->color.r;
1813                 coloredVertices[i].color.g = shadow->color.g;
1814                 coloredVertices[i].color.b = shadow->color.b;
1815                 coloredVertices[i].color.a = shadow->color.a;
1816             } else {
1817                 coloredVertices[i].color.r = datum->color.r;
1818                 coloredVertices[i].color.g = datum->color.g;
1819                 coloredVertices[i].color.b = datum->color.b;
1820                 coloredVertices[i].color.a = datum->color.a;
1821             }
1822         }
1823         break;
1824     case Simple:
1825         simpleVertices += pIdx*1;
1826         for (int i=0; i<1; i++){
1827             simpleVertices[i].x = datum->x - m_systemOffset.x();
1828             simpleVertices[i].y = datum->y - m_systemOffset.y();
1829             simpleVertices[i].t = datum->t;
1830             simpleVertices[i].lifeSpan = datum->lifeSpan;
1831             simpleVertices[i].size = datum->size;
1832             simpleVertices[i].endSize = datum->endSize;
1833             simpleVertices[i].vx = datum->vx;
1834             simpleVertices[i].vy = datum->vy;
1835             simpleVertices[i].ax = datum->ax;
1836             simpleVertices[i].ay = datum->ay;
1837         }
1838         break;
1839     default:
1840         break;
1841     }
1842
1843     node->setFlag(QSGNode::OwnsGeometry, true);
1844 }
1845
1846
1847
1848 QT_END_NAMESPACE