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