Per-frame Sprites patch one
[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             double frameAt;
1478             qreal progress;
1479             if (datum->frameDuration > 0) {
1480                 qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0);
1481                 frame = qBound(0.0, frame, (qreal)datum->frameCount - 1.0);//Stop at count-1 frames until we have between anim interpolation
1482                 progress = modf(frame,&frameAt);
1483             } else {
1484                 datum->frameAt++;
1485                 if (datum->frameAt >= datum->frameCount){
1486                     datum->frameAt = 0;
1487                     for (int i = 0; i<m_startsIdx.count(); i++) {
1488                         if (m_startsIdx[i].second == gIdx){
1489                             m_spriteEngine->advance(m_startsIdx[i].first + datum->index);
1490                             break;
1491                         }
1492                     }
1493                 }
1494                 frameAt = datum->frameAt;
1495                 progress = 0;
1496             }
1497             QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize;
1498             qreal y = datum->animY / sheetSize.height();
1499             qreal w = datum->animWidth / sheetSize.width();
1500             qreal h = datum->animHeight / sheetSize.height();
1501             qreal x1 = datum->animX / sheetSize.width();
1502             x1 += frameAt * w;
1503             qreal x2 = x1;
1504             if (frameAt < (datum->frameCount-1))
1505                 x2 += w;
1506
1507             node->setFlag(QSGNode::OwnsGeometry, false);
1508             SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1509             spriteVertices += datum->index*4;
1510             for (int i=0; i<4; i++) {
1511                 spriteVertices[i].animX1 = x1;
1512                 spriteVertices[i].animY1 = y;
1513                 spriteVertices[i].animX2 = x2;
1514                 spriteVertices[i].animY2 = y;
1515                 spriteVertices[i].animW = w;
1516                 spriteVertices[i].animH = h;
1517                 spriteVertices[i].animProgress = progress;
1518             }
1519             node->setFlag(QSGNode::OwnsGeometry, true);
1520         }
1521     }
1522 }
1523
1524 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1525 {
1526     if (!m_startsIdx.count())//Probably overly defensive
1527         return;
1528
1529     int gIdx = -1;
1530     int i;
1531     for (i = 0; i<m_startsIdx.count(); i++) {
1532         if (spriteIdx < m_startsIdx[i].first) {
1533             gIdx = m_startsIdx[i-1].second;
1534             break;
1535         }
1536     }
1537     if (gIdx == -1)
1538         gIdx = m_startsIdx[i-1].second;
1539     int pIdx = spriteIdx - m_startsIdx[i-1].first;
1540
1541     QQuickParticleData* mainDatum = m_system->groupData[gIdx]->data[pIdx];
1542     QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1543
1544     datum->animIdx = m_spriteEngine->spriteState(spriteIdx);
1545     datum->animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1546     datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1547     datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1548     datum->animX = m_spriteEngine->spriteX(spriteIdx);
1549     datum->animY = m_spriteEngine->spriteY(spriteIdx);
1550     datum->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1551     datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1552 }
1553
1554 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1555 {
1556     d->color = c;
1557     //TODO: get index for reload - or make function take an index
1558 }
1559
1560 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1561 {
1562     Color4ub color;
1563     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1564     qreal redVariation = m_color_variation + m_redVariation;
1565     qreal greenVariation = m_color_variation + m_greenVariation;
1566     qreal blueVariation = m_color_variation + m_blueVariation;
1567     int spriteIdx = 0;
1568     if (m_spriteEngine) {
1569         spriteIdx = m_idxStarts[gIdx] + datum->index;
1570         if (spriteIdx >= m_spriteEngine->count())
1571             m_spriteEngine->setCount(spriteIdx+1);
1572     }
1573
1574     float rotation;
1575     float rotationSpeed;
1576     float autoRotate;
1577     switch (perfLevel){//Fall-through is intended on all of them
1578         case Sprites:
1579             // Initial Sprite State
1580             if (m_explicitAnimation && m_spriteEngine){
1581                 if (!datum->animationOwner)
1582                     datum->animationOwner = this;
1583                 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1584                 writeTo->animT = writeTo->t;
1585                 //writeTo->animInterpolate = m_spritesInterpolate;
1586                 if (m_spriteEngine){
1587                     m_spriteEngine->start(spriteIdx);
1588                     writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1589                     writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1590                     writeTo->animIdx = 0;//Always starts at 0
1591                     writeTo->frameAt = -1;
1592                     writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1593                     writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1594                     writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1595                     writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1596                 }
1597             } else {
1598                 QQuickParticleData* writeTo = getShadowDatum(datum);
1599                 writeTo->animT = datum->t;
1600                 writeTo->frameCount = 1;
1601                 writeTo->frameDuration = 60000000.0;
1602                 writeTo->frameAt = -1;
1603                 writeTo->animIdx = 0;
1604                 writeTo->animT = 0;
1605                 writeTo->animX = writeTo->animY = 0;
1606                 writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
1607                 writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
1608             }
1609         case Tabled:
1610         case Deformable:
1611             //Initial Rotation
1612             if (m_explicitDeformation){
1613                 if (!datum->deformationOwner)
1614                     datum->deformationOwner = this;
1615                 if (m_xVector){
1616                     const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1617                     if (datum->deformationOwner == this) {
1618                         datum->xx = ret.x();
1619                         datum->xy = ret.y();
1620                     } else {
1621                         getShadowDatum(datum)->xx = ret.x();
1622                         getShadowDatum(datum)->xy = ret.y();
1623                     }
1624                 }
1625                 if (m_yVector){
1626                     const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1627                     if (datum->deformationOwner == this) {
1628                         datum->yx = ret.x();
1629                         datum->yy = ret.y();
1630                     } else {
1631                         getShadowDatum(datum)->yx = ret.x();
1632                         getShadowDatum(datum)->yy = ret.y();
1633                     }
1634                 }
1635             }
1636
1637             if (m_explicitRotation){
1638                 if (!datum->rotationOwner)
1639                     datum->rotationOwner = this;
1640                 rotation =
1641                         (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1642                 rotationSpeed =
1643                         (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1644                 autoRotate = m_autoRotation?1.0:0.0;
1645                 if (datum->rotationOwner == this) {
1646                     datum->rotation = rotation;
1647                     datum->rotationSpeed = rotationSpeed;
1648                     datum->autoRotate = autoRotate;
1649                 } else {
1650                     getShadowDatum(datum)->rotation = rotation;
1651                     getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1652                     getShadowDatum(datum)->autoRotate = autoRotate;
1653                 }
1654             }
1655         case Colored:
1656             //Color initialization
1657             // Particle color
1658             if (m_explicitColor) {
1659                 if (!datum->colorOwner)
1660                     datum->colorOwner = this;
1661                 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1662                 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1663                 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1664                 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1665                 if (datum->colorOwner == this)
1666                     datum->color = color;
1667                 else
1668                     getShadowDatum(datum)->color = color;
1669             }
1670         default:
1671             break;
1672     }
1673 }
1674
1675 void QQuickImageParticle::commit(int gIdx, int pIdx)
1676 {
1677     if (m_pleaseReset)
1678         return;
1679     QSGGeometryNode *node = m_nodes[gIdx];
1680     if (!node)
1681         return;
1682     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1683     node->setFlag(QSGNode::OwnsGeometry, false);
1684     SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1685     DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1686     ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1687     SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1688     switch (perfLevel){//No automatic fall through intended on this one
1689     case Sprites:
1690         spriteVertices += pIdx*4;
1691         for (int i=0; i<4; i++){
1692             spriteVertices[i].x = datum->x  - m_systemOffset.x();
1693             spriteVertices[i].y = datum->y  - m_systemOffset.y();
1694             spriteVertices[i].t = datum->t;
1695             spriteVertices[i].lifeSpan = datum->lifeSpan;
1696             spriteVertices[i].size = datum->size;
1697             spriteVertices[i].endSize = datum->endSize;
1698             spriteVertices[i].vx = datum->vx;
1699             spriteVertices[i].vy = datum->vy;
1700             spriteVertices[i].ax = datum->ax;
1701             spriteVertices[i].ay = datum->ay;
1702             if (m_explicitDeformation && datum->deformationOwner != this) {
1703                 QQuickParticleData* shadow = getShadowDatum(datum);
1704                 spriteVertices[i].xx = shadow->xx;
1705                 spriteVertices[i].xy = shadow->xy;
1706                 spriteVertices[i].yx = shadow->yx;
1707                 spriteVertices[i].yy = shadow->yy;
1708             } else {
1709                 spriteVertices[i].xx = datum->xx;
1710                 spriteVertices[i].xy = datum->xy;
1711                 spriteVertices[i].yx = datum->yx;
1712                 spriteVertices[i].yy = datum->yy;
1713             }
1714             if (m_explicitRotation && datum->rotationOwner != this) {
1715                 QQuickParticleData* shadow = getShadowDatum(datum);
1716                 spriteVertices[i].rotation = shadow->rotation;
1717                 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1718                 spriteVertices[i].autoRotate = shadow->autoRotate;
1719             } else {
1720                 spriteVertices[i].rotation = datum->rotation;
1721                 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1722                 spriteVertices[i].autoRotate = datum->autoRotate;
1723             }
1724             //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand
1725             if (m_explicitColor && datum->colorOwner != this) {
1726                 QQuickParticleData* shadow = getShadowDatum(datum);
1727                 spriteVertices[i].color.r = shadow->color.r;
1728                 spriteVertices[i].color.g = shadow->color.g;
1729                 spriteVertices[i].color.b = shadow->color.b;
1730                 spriteVertices[i].color.a = shadow->color.a;
1731             } else {
1732                 spriteVertices[i].color.r = datum->color.r;
1733                 spriteVertices[i].color.g = datum->color.g;
1734                 spriteVertices[i].color.b = datum->color.b;
1735                 spriteVertices[i].color.a = datum->color.a;
1736             }
1737         }
1738         break;
1739     case Tabled: //Fall through until it has its own vertex class
1740     case Deformable:
1741         deformableVertices += pIdx*4;
1742         for (int i=0; i<4; i++){
1743             deformableVertices[i].x = datum->x  - m_systemOffset.x();
1744             deformableVertices[i].y = datum->y  - m_systemOffset.y();
1745             deformableVertices[i].t = datum->t;
1746             deformableVertices[i].lifeSpan = datum->lifeSpan;
1747             deformableVertices[i].size = datum->size;
1748             deformableVertices[i].endSize = datum->endSize;
1749             deformableVertices[i].vx = datum->vx;
1750             deformableVertices[i].vy = datum->vy;
1751             deformableVertices[i].ax = datum->ax;
1752             deformableVertices[i].ay = datum->ay;
1753             if (m_explicitDeformation && datum->deformationOwner != this) {
1754                 QQuickParticleData* shadow = getShadowDatum(datum);
1755                 deformableVertices[i].xx = shadow->xx;
1756                 deformableVertices[i].xy = shadow->xy;
1757                 deformableVertices[i].yx = shadow->yx;
1758                 deformableVertices[i].yy = shadow->yy;
1759             } else {
1760                 deformableVertices[i].xx = datum->xx;
1761                 deformableVertices[i].xy = datum->xy;
1762                 deformableVertices[i].yx = datum->yx;
1763                 deformableVertices[i].yy = datum->yy;
1764             }
1765             if (m_explicitRotation && datum->rotationOwner != this) {
1766                 QQuickParticleData* shadow = getShadowDatum(datum);
1767                 deformableVertices[i].rotation = shadow->rotation;
1768                 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1769                 deformableVertices[i].autoRotate = shadow->autoRotate;
1770             } else {
1771                 deformableVertices[i].rotation = datum->rotation;
1772                 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1773                 deformableVertices[i].autoRotate = datum->autoRotate;
1774             }
1775             if (m_explicitColor && datum->colorOwner != this) {
1776                 QQuickParticleData* shadow = getShadowDatum(datum);
1777                 deformableVertices[i].color.r = shadow->color.r;
1778                 deformableVertices[i].color.g = shadow->color.g;
1779                 deformableVertices[i].color.b = shadow->color.b;
1780                 deformableVertices[i].color.a = shadow->color.a;
1781             } else {
1782                 deformableVertices[i].color.r = datum->color.r;
1783                 deformableVertices[i].color.g = datum->color.g;
1784                 deformableVertices[i].color.b = datum->color.b;
1785                 deformableVertices[i].color.a = datum->color.a;
1786             }
1787         }
1788         break;
1789     case Colored:
1790         coloredVertices += pIdx*1;
1791         for (int i=0; i<1; i++){
1792             coloredVertices[i].x = datum->x  - m_systemOffset.x();
1793             coloredVertices[i].y = datum->y  - m_systemOffset.y();
1794             coloredVertices[i].t = datum->t;
1795             coloredVertices[i].lifeSpan = datum->lifeSpan;
1796             coloredVertices[i].size = datum->size;
1797             coloredVertices[i].endSize = datum->endSize;
1798             coloredVertices[i].vx = datum->vx;
1799             coloredVertices[i].vy = datum->vy;
1800             coloredVertices[i].ax = datum->ax;
1801             coloredVertices[i].ay = datum->ay;
1802             if (m_explicitColor && datum->colorOwner != this) {
1803                 QQuickParticleData* shadow = getShadowDatum(datum);
1804                 coloredVertices[i].color.r = shadow->color.r;
1805                 coloredVertices[i].color.g = shadow->color.g;
1806                 coloredVertices[i].color.b = shadow->color.b;
1807                 coloredVertices[i].color.a = shadow->color.a;
1808             } else {
1809                 coloredVertices[i].color.r = datum->color.r;
1810                 coloredVertices[i].color.g = datum->color.g;
1811                 coloredVertices[i].color.b = datum->color.b;
1812                 coloredVertices[i].color.a = datum->color.a;
1813             }
1814         }
1815         break;
1816     case Simple:
1817         simpleVertices += pIdx*1;
1818         for (int i=0; i<1; i++){
1819             simpleVertices[i].x = datum->x - m_systemOffset.x();
1820             simpleVertices[i].y = datum->y - m_systemOffset.y();
1821             simpleVertices[i].t = datum->t;
1822             simpleVertices[i].lifeSpan = datum->lifeSpan;
1823             simpleVertices[i].size = datum->size;
1824             simpleVertices[i].endSize = datum->endSize;
1825             simpleVertices[i].vx = datum->vx;
1826             simpleVertices[i].vy = datum->vy;
1827             simpleVertices[i].ax = datum->ax;
1828             simpleVertices[i].ay = datum->ay;
1829         }
1830         break;
1831     default:
1832         break;
1833     }
1834
1835     node->setFlag(QSGNode::OwnsGeometry, true);
1836 }
1837
1838
1839
1840 QT_END_NAMESPACE