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