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