Remove QSGEngine
[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 The ImageParticle element visualizes logical particles using an image
591
592     This element renders a logical particle as an image. The image can be
593     \list
594     \li colorized
595     \li rotated
596     \li deformed
597     \li a sprite-based animation
598     \endlist
599
600     ImageParticles implictly share data on particles if multiple ImageParticles are painting
601     the same logical particle group. This is broken down along the four capabilities listed
602     above. So if one ImageParticle defines data for rendering the particles in one of those
603     capabilities, and the other does not, then both will draw the particles the same in that
604     aspect automatically. This is primarily useful when there is some random variation on
605     the particle which is supposed to stay with it when switching painters. If both ImageParticles
606     define how they should appear for that aspect, they diverge and each appears as it is defined.
607
608     This sharing of data happens behind the scenes based off of whether properties were implicitly or explicitly
609     set. One drawback of the current implementation is that it is only possible to reset the capabilities as a whole.
610     So if you explicity set an attribute affecting color, such as redVariation, and then reset it (by setting redVariation
611     to undefined), all color data will be reset and it will begin to have an implicit value of any shared color from
612     other ImageParticles.
613 */
614 /*!
615     \qmlproperty url QtQuick.Particles2::ImageParticle::source
616
617     The source image to be used.
618
619     If the image is a sprite animation, use the sprite property instead.
620 */
621 /*!
622     \qmlproperty list<Sprite> QtQuick.Particles2::ImageParticle::sprites
623
624     The sprite or sprites used to draw this particle.
625
626     Note that the sprite image will be scaled to a square based on the size of
627     the particle being rendered.
628 */
629 /*!
630     \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable
631
632     An image whose color will be used as a 1D texture to determine color over life. E.g. when
633     the particle is halfway through its lifetime, it will have the color specified halfway
634     across the image.
635
636     This color is blended with the color property and the color of the source image.
637 */
638 /*!
639     \qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
640
641     An image whose opacity will be used as a 1D texture to determine size over life.
642
643     This property is expected to be removed shortly, in favor of custom easing curves to determine size over life.
644 */
645 /*!
646     \qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
647
648     An image whose opacity will be used as a 1D texture to determine size over life.
649
650     This property is expected to be removed shortly, in favor of custom easing curves to determine opacity over life.
651 */
652 /*!
653     \qmlproperty color QtQuick.Particles2::ImageParticle::color
654
655     If a color is specified, the provided image will be colorized with it.
656
657     Default is white (no change).
658 */
659 /*!
660     \qmlproperty real QtQuick.Particles2::ImageParticle::colorVariation
661
662     This number represents the color variation applied to individual particles.
663     Setting colorVariation is the same as setting redVariation, greenVariation,
664     and blueVariation to the same number.
665
666     Each channel can vary between particle by up to colorVariation from its usual color.
667
668     Color is measured, per channel, from 0.0 to 1.0.
669
670     Default is 0.0
671 */
672 /*!
673     \qmlproperty real QtQuick.Particles2::ImageParticle::redVariation
674     The variation in the red color channel between particles.
675
676     Color is measured, per channel, from 0.0 to 1.0.
677
678     Default is 0.0
679 */
680 /*!
681     \qmlproperty real QtQuick.Particles2::ImageParticle::greenVariation
682     The variation in the green color channel between particles.
683
684     Color is measured, per channel, from 0.0 to 1.0.
685
686     Default is 0.0
687 */
688 /*!
689     \qmlproperty real QtQuick.Particles2::ImageParticle::blueVariation
690     The variation in the blue 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::alpha
698     An alpha to be applied to the image. This value is multiplied by the value in
699     the image, and the value in the color property.
700
701     Particles have additive blending, so lower alpha on single particles leads
702     to stronger effects when multiple particles overlap.
703
704     Alpha is measured from 0.0 to 1.0.
705
706     Default is 1.0
707 */
708 /*!
709     \qmlproperty real QtQuick.Particles2::ImageParticle::alphaVariation
710     The variation in the alpha channel between particles.
711
712     Alpha is measured from 0.0 to 1.0.
713
714     Default is 0.0
715 */
716 /*!
717     \qmlproperty real QtQuick.Particles2::ImageParticle::rotation
718
719     If set the image will be rotated by this many degrees before it is drawn.
720
721     The particle coordinates are not transformed.
722 */
723 /*!
724     \qmlproperty real QtQuick.Particles2::ImageParticle::rotationVariation
725
726     If set the rotation of individual particles will vary by up to this much
727     between particles.
728
729 */
730 /*!
731     \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeed
732
733     If set particles will rotate at this speed in degrees/second.
734 */
735 /*!
736     \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeedVariation
737
738     If set the rotationSpeed of individual particles will vary by up to this much
739     between particles.
740
741 */
742 /*!
743     \qmlproperty bool QtQuick.Particles2::ImageParticle::autoRotation
744
745     If set to true then a rotation will be applied on top of the particles rotation, so
746     that it faces the direction of travel. So to face away from the direction of travel,
747     set autoRotation to true and rotation to 180.
748
749     Default is false
750 */
751 /*!
752     \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::xVector
753
754     Allows you to deform the particle image when drawn. The rectangular image will
755     be deformed so that the horizontal sides are in the shape of this vector instead
756     of (1,0).
757 */
758 /*!
759     \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::yVector
760
761     Allows you to deform the particle image when drawn. The rectangular image will
762     be deformed so that the vertical sides are in the shape of this vector instead
763     of (0,1).
764 */
765 /*!
766     \qmlproperty EntryEffect QtQuick.Particles2::ImageParticle::entryEffect
767
768     This property provides basic and cheap entrance and exit effects for the particles.
769     For fine-grained control, see sizeTable and opacityTable.
770
771     Acceptable values are
772     \list
773     \li ImageParticle.None: Particles just appear and disappear.
774     \li ImageParticle.Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
775     \li ImageParticle.Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end.
776     \endlist
777
778     Default value is Fade.
779 */
780 /*!
781     \qmlproperty bool QtQuick.Particles2::ImageParticle::spritesInterpolate
782
783     If set to true, sprite particles will interpolate between sprite frames each rendered frame, making
784     the sprites look smoother.
785
786     Default is true.
787 */
788
789 /*!
790     \qmlproperty Status QtQuick.Particles2::ImageParticle::status
791
792     The status of loading the image.
793 */
794
795
796 QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
797     : QQuickParticlePainter(parent)
798     , m_image(0)
799     , m_colorTable(0)
800     , m_sizeTable(0)
801     , m_opacityTable(0)
802     , m_color_variation(0.0)
803     , m_rootNode(0)
804     , m_material(0)
805     , m_alphaVariation(0.0)
806     , m_alpha(1.0)
807     , m_redVariation(0.0)
808     , m_greenVariation(0.0)
809     , m_blueVariation(0.0)
810     , m_rotation(0)
811     , m_rotationVariation(0)
812     , m_rotationSpeed(0)
813     , m_rotationSpeedVariation(0)
814     , m_autoRotation(false)
815     , m_xVector(0)
816     , m_yVector(0)
817     , m_spriteEngine(0)
818     , m_spritesInterpolate(true)
819     , m_explicitColor(false)
820     , m_explicitRotation(false)
821     , m_explicitDeformation(false)
822     , m_explicitAnimation(false)
823     , m_bypassOptimizations(false)
824     , perfLevel(Unknown)
825     , m_lastLevel(Unknown)
826     , m_debugMode(false)
827     , m_entryEffect(Fade)
828     , m_buildingNodes(false)
829 {
830     setFlag(ItemHasContents);
831 }
832
833 QQuickImageParticle::~QQuickImageParticle()
834 {
835 }
836
837 QQmlListProperty<QQuickSprite> QQuickImageParticle::sprites()
838 {
839     return QQmlListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
840 }
841
842 void QQuickImageParticle::sceneGraphInvalidated()
843 {
844     m_nodes.clear();
845     m_rootNode = 0;
846     m_material = 0;
847 }
848
849 void QQuickImageParticle::setImage(const QUrl &image)
850 {
851     if (image.isEmpty()){
852         if (m_image) {
853             delete m_image;
854             emit imageChanged();
855         }
856         return;
857     }
858
859     if (!m_image)
860         m_image = new ImageData;
861     if (image == m_image->source)
862         return;
863     m_image->source = image;
864     emit imageChanged();
865     reset();
866 }
867
868
869 void QQuickImageParticle::setColortable(const QUrl &table)
870 {
871     if (table.isEmpty()){
872         if (m_colorTable) {
873             delete m_colorTable;
874             emit colortableChanged();
875         }
876         return;
877     }
878
879     if (!m_colorTable)
880         m_colorTable = new ImageData;
881     if (table == m_colorTable->source)
882         return;
883     m_colorTable->source = table;
884     emit colortableChanged();
885     reset();
886 }
887
888 void QQuickImageParticle::setSizetable(const QUrl &table)
889 {
890     if (table.isEmpty()){
891         if (m_sizeTable) {
892             delete m_sizeTable;
893             emit sizetableChanged();
894         }
895         return;
896     }
897
898     if (!m_sizeTable)
899         m_sizeTable = new ImageData;
900     if (table == m_sizeTable->source)
901         return;
902     m_sizeTable->source = table;
903     emit sizetableChanged();
904     reset();
905 }
906
907 void QQuickImageParticle::setOpacitytable(const QUrl &table)
908 {
909     if (table.isEmpty()){
910         if (m_opacityTable) {
911             delete m_opacityTable;
912             emit opacitytableChanged();
913         }
914         return;
915     }
916
917     if (!m_opacityTable)
918         m_opacityTable = new ImageData;
919     if (table == m_opacityTable->source)
920         return;
921     m_opacityTable->source = table;
922     emit opacitytableChanged();
923     reset();
924 }
925
926 void QQuickImageParticle::setColor(const QColor &color)
927 {
928     if (color == m_color)
929         return;
930     m_color = color;
931     emit colorChanged();
932     m_explicitColor = true;
933     if (perfLevel < Colored)
934         reset();
935 }
936
937 void QQuickImageParticle::setColorVariation(qreal var)
938 {
939     if (var == m_color_variation)
940         return;
941     m_color_variation = var;
942     emit colorVariationChanged();
943     m_explicitColor = true;
944     if (perfLevel < Colored)
945         reset();
946 }
947
948 void QQuickImageParticle::setAlphaVariation(qreal arg)
949 {
950     if (m_alphaVariation != arg) {
951         m_alphaVariation = arg;
952         emit alphaVariationChanged(arg);
953     }
954     m_explicitColor = true;
955     if (perfLevel < Colored)
956         reset();
957 }
958
959 void QQuickImageParticle::setAlpha(qreal arg)
960 {
961     if (m_alpha != arg) {
962         m_alpha = arg;
963         emit alphaChanged(arg);
964     }
965     m_explicitColor = true;
966     if (perfLevel < Colored)
967         reset();
968 }
969
970 void QQuickImageParticle::setRedVariation(qreal arg)
971 {
972     if (m_redVariation != arg) {
973         m_redVariation = arg;
974         emit redVariationChanged(arg);
975     }
976     m_explicitColor = true;
977     if (perfLevel < Colored)
978         reset();
979 }
980
981 void QQuickImageParticle::setGreenVariation(qreal arg)
982 {
983     if (m_greenVariation != arg) {
984         m_greenVariation = arg;
985         emit greenVariationChanged(arg);
986     }
987     m_explicitColor = true;
988     if (perfLevel < Colored)
989         reset();
990 }
991
992 void QQuickImageParticle::setBlueVariation(qreal arg)
993 {
994     if (m_blueVariation != arg) {
995         m_blueVariation = arg;
996         emit blueVariationChanged(arg);
997     }
998     m_explicitColor = true;
999     if (perfLevel < Colored)
1000         reset();
1001 }
1002
1003 void QQuickImageParticle::setRotation(qreal arg)
1004 {
1005     if (m_rotation != arg) {
1006         m_rotation = arg;
1007         emit rotationChanged(arg);
1008     }
1009     m_explicitRotation = true;
1010     if (perfLevel < Deformable)
1011         reset();
1012 }
1013
1014 void QQuickImageParticle::setRotationVariation(qreal arg)
1015 {
1016     if (m_rotationVariation != arg) {
1017         m_rotationVariation = arg;
1018         emit rotationVariationChanged(arg);
1019     }
1020     m_explicitRotation = true;
1021     if (perfLevel < Deformable)
1022         reset();
1023 }
1024
1025 void QQuickImageParticle::setRotationSpeed(qreal arg)
1026 {
1027     if (m_rotationSpeed != arg) {
1028         m_rotationSpeed = arg;
1029         emit rotationSpeedChanged(arg);
1030     }
1031     m_explicitRotation = true;
1032     if (perfLevel < Deformable)
1033         reset();
1034 }
1035
1036 void QQuickImageParticle::setRotationSpeedVariation(qreal arg)
1037 {
1038     if (m_rotationSpeedVariation != arg) {
1039         m_rotationSpeedVariation = arg;
1040         emit rotationSpeedVariationChanged(arg);
1041     }
1042     m_explicitRotation = true;
1043     if (perfLevel < Deformable)
1044         reset();
1045 }
1046
1047 void QQuickImageParticle::setAutoRotation(bool arg)
1048 {
1049     if (m_autoRotation != arg) {
1050         m_autoRotation = arg;
1051         emit autoRotationChanged(arg);
1052     }
1053     m_explicitRotation = true;
1054     if (perfLevel < Deformable)
1055         reset();
1056 }
1057
1058 void QQuickImageParticle::setXVector(QQuickDirection* arg)
1059 {
1060     if (m_xVector != arg) {
1061         m_xVector = arg;
1062         emit xVectorChanged(arg);
1063     }
1064     m_explicitDeformation = true;
1065     if (perfLevel < Deformable)
1066         reset();
1067 }
1068
1069 void QQuickImageParticle::setYVector(QQuickDirection* arg)
1070 {
1071     if (m_yVector != arg) {
1072         m_yVector = arg;
1073         emit yVectorChanged(arg);
1074     }
1075     m_explicitDeformation = true;
1076     if (perfLevel < Deformable)
1077         reset();
1078 }
1079
1080 void QQuickImageParticle::setSpritesInterpolate(bool arg)
1081 {
1082     if (m_spritesInterpolate != arg) {
1083         m_spritesInterpolate = arg;
1084         emit spritesInterpolateChanged(arg);
1085     }
1086 }
1087
1088 void QQuickImageParticle::setBypassOptimizations(bool arg)
1089 {
1090     if (m_bypassOptimizations != arg) {
1091         m_bypassOptimizations = arg;
1092         emit bypassOptimizationsChanged(arg);
1093     }
1094     if (perfLevel < 9999)
1095         reset();
1096 }
1097
1098 void QQuickImageParticle::setEntryEffect(EntryEffect arg)
1099 {
1100     if (m_entryEffect != arg) {
1101         m_entryEffect = arg;
1102         if (m_material)
1103             getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1104         emit entryEffectChanged(arg);
1105     }
1106 }
1107
1108 void QQuickImageParticle::resetColor()
1109 {
1110     m_explicitColor = false;
1111     foreach (const QString &str, m_groups)
1112         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1113             if (d->colorOwner == this)
1114                 d->colorOwner = 0;
1115     m_color = QColor();
1116     m_color_variation = 0.0f;
1117     m_redVariation = 0.0f;
1118     m_blueVariation = 0.0f;
1119     m_greenVariation = 0.0f;
1120     m_alpha = 1.0f;
1121     m_alphaVariation = 0.0f;
1122 }
1123
1124 void QQuickImageParticle::resetRotation()
1125 {
1126     m_explicitRotation = false;
1127     foreach (const QString &str, m_groups)
1128         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1129             if (d->rotationOwner == this)
1130                 d->rotationOwner = 0;
1131     m_rotation = 0;
1132     m_rotationVariation = 0;
1133     m_rotationSpeed = 0;
1134     m_rotationSpeedVariation = 0;
1135     m_autoRotation = false;
1136 }
1137
1138 void QQuickImageParticle::resetDeformation()
1139 {
1140     m_explicitDeformation = false;
1141     foreach (const QString &str, m_groups)
1142         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1143             if (d->deformationOwner == this)
1144                 d->deformationOwner = 0;
1145     if (m_xVector)
1146         delete m_xVector;
1147     if (m_yVector)
1148         delete m_yVector;
1149     m_xVector = 0;
1150     m_yVector = 0;
1151 }
1152
1153 void QQuickImageParticle::reset()
1154 {
1155     QQuickParticlePainter::reset();
1156     m_pleaseReset = true;
1157     update();
1158 }
1159
1160 void QQuickImageParticle::createEngine()
1161 {
1162     if (m_spriteEngine)
1163         delete m_spriteEngine;
1164     if (m_sprites.count()) {
1165         m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1166         connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1167                 this, SLOT(spriteAdvance(int)), Qt::DirectConnection);
1168         m_explicitAnimation = true;
1169     } else {
1170         m_spriteEngine = 0;
1171         m_explicitAnimation = false;
1172     }
1173     reset();
1174 }
1175
1176 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
1177     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
1178     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1179     QSGGeometry::Attribute::create(2, 4, GL_FLOAT)             // Vectors
1180 };
1181
1182 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
1183 {
1184     3, // Attribute Count
1185     ( 2 + 4 + 4 ) * sizeof(float),
1186     SimpleParticle_Attributes
1187 };
1188
1189 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
1190     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
1191     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1192     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1193     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1194 };
1195
1196 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
1197 {
1198     4, // Attribute Count
1199     ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1200     ColoredParticle_Attributes
1201 };
1202
1203 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
1204     QSGGeometry::Attribute::create(0, 4, GL_FLOAT),             // Position & TexCoord
1205     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1206     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1207     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1208     QSGGeometry::Attribute::create(4, 4, GL_FLOAT),             // DeformationVectors
1209     QSGGeometry::Attribute::create(5, 3, GL_FLOAT),             // Rotation
1210 };
1211
1212 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1213 {
1214     6, // Attribute Count
1215     (4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1216     DeformableParticle_Attributes
1217 };
1218
1219 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1220     QSGGeometry::Attribute::create(0, 4, GL_FLOAT),       // Position & TexCoord
1221     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1222     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1223     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1224     QSGGeometry::Attribute::create(4, 4, GL_FLOAT),             // DeformationVectors
1225     QSGGeometry::Attribute::create(5, 3, GL_FLOAT),             // Rotation
1226     QSGGeometry::Attribute::create(6, 3, GL_FLOAT),             // Anim Data
1227     QSGGeometry::Attribute::create(7, 4, GL_FLOAT)              // Anim Pos
1228 };
1229
1230 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1231 {
1232     8, // Attribute Count
1233     (4 + 4 + 4 + 4 + 3 + 3 + 4) * sizeof(float) + 4 * sizeof(uchar),
1234     SpriteParticle_Attributes
1235 };
1236
1237 void QQuickImageParticle::clearShadows()
1238 {
1239     foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1240         qDeleteAll(data);
1241     m_shadowData.clear();
1242 }
1243
1244 //Only call if you need to, may initialize the whole array first time
1245 QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1246 {
1247     //Will return datum if the datum is a sentinel or uninitialized, to centralize that one check
1248     if (datum->systemIndex == -1)
1249         return datum;
1250     QQuickParticleGroupData* gd = m_system->groupData[datum->group];
1251     if (!m_shadowData.contains(datum->group)) {
1252         QVector<QQuickParticleData*> data;
1253         for (int i=0; i<gd->size(); i++){
1254             QQuickParticleData* datum = new QQuickParticleData(m_system);
1255             *datum = *(gd->data[i]);
1256             data << datum;
1257         }
1258         m_shadowData.insert(datum->group, data);
1259     }
1260     //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1261
1262     return m_shadowData[datum->group][datum->index];
1263 }
1264
1265 bool QQuickImageParticle::loadingSomething()
1266 {
1267     return (m_image && m_image->pix.isLoading())
1268         || (m_colorTable && m_colorTable->pix.isLoading())
1269         || (m_sizeTable && m_sizeTable->pix.isLoading())
1270         || (m_opacityTable && m_opacityTable->pix.isLoading())
1271         || (m_spriteEngine && m_spriteEngine->isLoading());
1272 }
1273
1274 void QQuickImageParticle::buildParticleNodes()//Starts async parts, like loading images.
1275 {
1276     if (m_rootNode || loadingSomething())
1277         return;
1278
1279     if (!m_buildingNodes) {
1280         if (m_image) {//ImageData created on setSource
1281             m_image->pix.clear(this);
1282             m_image->pix.load(qmlEngine(this), m_image->source);
1283         }
1284
1285         if (m_spriteEngine)
1286             m_spriteEngine->startAssemblingImage();
1287
1288         if (m_colorTable)
1289             m_colorTable->pix.load(qmlEngine(this), m_colorTable->source);
1290
1291         if (m_sizeTable)
1292             m_sizeTable->pix.load(qmlEngine(this), m_sizeTable->source);
1293
1294         if (m_opacityTable)
1295             m_opacityTable->pix.load(qmlEngine(this), m_opacityTable->source);
1296
1297         m_buildingNodes = true;
1298         if (loadingSomething())
1299             return;
1300     }
1301     finishBuildParticleNodes();
1302 }
1303
1304 void QQuickImageParticle::finishBuildParticleNodes()
1305 {
1306     m_buildingNodes = false;
1307 #ifdef QT_OPENGL_ES_2
1308     if (m_count * 4 > 0xffff) {
1309         printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1310         return;
1311     }
1312 #endif
1313
1314     if (count() <= 0)
1315         return;
1316
1317     m_debugMode = m_system->m_debugMode;
1318
1319     if (m_sprites.count() || m_bypassOptimizations) {
1320         perfLevel = Sprites;
1321     } else if (m_colorTable || m_sizeTable || m_opacityTable) {
1322         perfLevel = Tabled;
1323     } else if (m_autoRotation || m_rotation || m_rotationVariation
1324                || m_rotationSpeed || m_rotationSpeedVariation
1325                || m_xVector || m_yVector) {
1326         perfLevel = Deformable;
1327     } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1328                || m_redVariation || m_blueVariation || m_greenVariation) {
1329         perfLevel = Colored;
1330     } else {
1331         perfLevel = Simple;
1332     }
1333
1334     foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1335         int gIdx = m_system->groupIds[str];
1336         foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){
1337             QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1338             if (other){
1339                 if (other->perfLevel > perfLevel) {
1340                     if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1341                         if (perfLevel < Deformable)
1342                             perfLevel = Deformable;
1343                     } else {
1344                         perfLevel = other->perfLevel;
1345                     }
1346                 } else if (other->perfLevel < perfLevel) {
1347                     other->reset();
1348                 }
1349             }
1350         }
1351     }
1352 #ifdef Q_OS_WIN
1353     if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows.
1354         perfLevel = Deformable;
1355 #endif
1356
1357     if (perfLevel >= Colored  && !m_color.isValid())
1358         m_color = QColor(Qt::white);//Hidden default, but different from unset
1359
1360     clearShadows();
1361     if (m_material)
1362         m_material = 0;
1363
1364     //Setup material
1365     QImage colortable;
1366     QImage sizetable;
1367     QImage opacitytable;
1368     QImage image;
1369     bool imageLoaded = false;
1370     switch (perfLevel) {//Fallthrough intended
1371     case Sprites:
1372         if (!m_spriteEngine) {
1373             qWarning() << "ImageParticle: No sprite engine...";
1374             //Sprite performance mode with static image is supported, but not advised
1375             //Note that in this case it always uses shadow data
1376         } else {
1377             image = m_spriteEngine->assembledImage();
1378             if (image.isNull())//Warning is printed in engine
1379                 return;
1380             imageLoaded = true;
1381         }
1382         m_material = SpriteMaterial::createMaterial();
1383         if (imageLoaded)
1384             getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1385         getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1386         if (m_spriteEngine)
1387             m_spriteEngine->setCount(m_count);
1388     case Tabled:
1389         if (!m_material)
1390             m_material = TabledMaterial::createMaterial();
1391
1392         if (m_colorTable) {
1393             if (m_colorTable->pix.isReady())
1394                 colortable = m_colorTable->pix.image();
1395             else
1396                 qmlInfo(this) << "Error loading color table: " << m_colorTable->pix.error();
1397         }
1398
1399         if (m_sizeTable) {
1400             if (m_sizeTable->pix.isReady())
1401                 sizetable = m_sizeTable->pix.image();
1402             else
1403                 qmlInfo(this) << "Error loading size table: " << m_sizeTable->pix.error();
1404         }
1405
1406         if (m_opacityTable) {
1407             if (m_opacityTable->pix.isReady())
1408                 opacitytable = m_opacityTable->pix.image();
1409             else
1410                 qmlInfo(this) << "Error loading opacity table: " << m_opacityTable->pix.error();
1411         }
1412
1413         if (colortable.isNull()){//###Goes through image just for this
1414             colortable = QImage(1,1,QImage::Format_ARGB32_Premultiplied);
1415             colortable.fill(Qt::white);
1416         }
1417         getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1418         fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1419         fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1420     case Deformable:
1421         if (!m_material)
1422             m_material = DeformableMaterial::createMaterial();
1423     case Colored:
1424         if (!m_material)
1425             m_material = ColoredMaterial::createMaterial();
1426     default://Also Simple
1427         if (!m_material)
1428             m_material = SimpleMaterial::createMaterial();
1429         if (!imageLoaded) {
1430             if (!m_image->pix.isReady()) {
1431                 qmlInfo(this) << m_image->pix.error();
1432                 delete m_material;
1433                 return;
1434             }
1435             //getState<ImageMaterialData>(m_material)->texture //TODO: Shouldn't this be better? But not crash?
1436             //    = QQuickItemPrivate::get(this)->sceneGraphContext()->textureForFactory(m_imagePix.textureFactory());
1437             getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(m_image->pix.image());
1438         }
1439         getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1440         getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1441         m_material->setFlag(QSGMaterial::Blending | QSGMaterial::RequiresFullMatrix);
1442     }
1443
1444     m_nodes.clear();
1445     foreach (const QString &str, m_groups){
1446         int gIdx = m_system->groupIds[str];
1447         int count = m_system->groupData[gIdx]->size();
1448         QSGGeometryNode* node = new QSGGeometryNode();
1449         node->setMaterial(m_material);
1450         node->markDirty(QSGNode::DirtyMaterial);
1451
1452         m_nodes.insert(gIdx, node);
1453         m_idxStarts.insert(gIdx, m_lastIdxStart);
1454         m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx));
1455         m_lastIdxStart += count;
1456
1457         //Create Particle Geometry
1458         int vCount = count * 4;
1459         int iCount = count * 6;
1460
1461         QSGGeometry *g;
1462         if (perfLevel == Sprites)
1463             g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1464         else if (perfLevel == Tabled)
1465             g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1466         else if (perfLevel == Deformable)
1467             g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1468         else if (perfLevel == Colored)
1469             g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1470         else //Simple
1471             g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1472
1473         node->setGeometry(g);
1474         if (perfLevel <= Colored){
1475             g->setDrawingMode(GL_POINTS);
1476             if (m_debugMode){
1477                 GLfloat pointSizeRange[2];
1478                 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1479                 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1480             }
1481         }else
1482             g->setDrawingMode(GL_TRIANGLES);
1483
1484         for (int p=0; p < count; ++p)
1485             commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1486
1487         if (perfLevel == Sprites)
1488             initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1489         else if (perfLevel == Tabled)
1490             initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1491         else if (perfLevel == Deformable)
1492             initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1493
1494         if (perfLevel > Colored){
1495             quint16 *indices = g->indexDataAsUShort();
1496             for (int i=0; i < count; ++i) {
1497                 int o = i * 4;
1498                 indices[0] = o;
1499                 indices[1] = o + 1;
1500                 indices[2] = o + 2;
1501                 indices[3] = o + 1;
1502                 indices[4] = o + 3;
1503                 indices[5] = o + 2;
1504                 indices += 6;
1505             }
1506         }
1507     }
1508
1509     if (perfLevel == Sprites)
1510         spritesUpdate();//Gives all vertexes the initial sprite data, then maintained per frame
1511
1512     foreach (QSGGeometryNode* node, m_nodes){
1513         if (node == *(m_nodes.begin()))
1514             node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1515         else
1516             (*(m_nodes.begin()))->appendChildNode(node);
1517     }
1518
1519     m_rootNode = *(m_nodes.begin());
1520     update();
1521 }
1522
1523 QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1524 {
1525     if (m_pleaseReset){
1526         m_lastLevel = perfLevel;
1527
1528         delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1529         m_rootNode = 0;
1530         m_nodes.clear();
1531
1532         m_idxStarts.clear();
1533         m_startsIdx.clear();
1534         m_lastIdxStart = 0;
1535
1536         m_material = 0;
1537
1538         m_pleaseReset = false;
1539         m_buildingNodes = false;//Cancel a part-way build
1540     }
1541
1542     if (m_system && m_system->isRunning() && !m_system->isPaused()){
1543         prepareNextFrame();
1544         if (m_rootNode) {
1545             update();
1546             foreach (QSGGeometryNode* node, m_nodes)
1547                 node->markDirty(QSGNode::DirtyGeometry);
1548         } else if (m_buildingNodes) {
1549             update();//To call prepareNextFrame() again from the renderThread
1550         }
1551     }
1552
1553     return m_rootNode;
1554 }
1555
1556 void QQuickImageParticle::prepareNextFrame()
1557 {
1558     if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1559         buildParticleNodes();
1560         if (m_debugMode) {
1561             qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1562             qDebug() << "QQuickImageParticle Nodes: ";
1563             int count = 0;
1564             foreach (int i, m_nodes.keys()) {
1565                 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1566                 count += m_system->groupData[i]->size();
1567             }
1568             qDebug() << "Total count: " << count;
1569         }
1570         if (m_rootNode == 0)
1571             return;
1572     }
1573     qint64 timeStamp = m_system->systemSync(this);
1574
1575     qreal time = timeStamp / 1000.;
1576
1577     switch (perfLevel){//Fall-through intended
1578     case Sprites:
1579         //Advance State
1580         if (m_spriteEngine)
1581             m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed
1582         spritesUpdate(time);
1583     case Tabled:
1584     case Deformable:
1585     case Colored:
1586     case Simple:
1587     default: //Also Simple
1588         getState<ImageMaterialData>(m_material)->timestamp = time;
1589         break;
1590     }
1591     foreach (QSGGeometryNode* node, m_nodes)
1592         node->markDirty(QSGNode::DirtyMaterial);
1593 }
1594
1595 void QQuickImageParticle::spritesUpdate(qreal time)
1596 {
1597     // Sprite progression handled CPU side, so as to have per-frame control.
1598     foreach (const QString &str, m_groups) {
1599         int gIdx = m_system->groupIds[str];
1600         foreach (QQuickParticleData* mainDatum, m_system->groupData[gIdx]->data) {
1601             QSGGeometryNode *node = m_nodes[gIdx];
1602             if (!node)
1603                 continue;
1604             //TODO: Interpolate between two different animations if it's going to transition next frame
1605             //      This is particularly important for cut-up sprites.
1606             QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1607             int spriteIdx = 0;
1608             for (int i = 0; i<m_startsIdx.count(); i++) {
1609                 if (m_startsIdx[i].second == gIdx){
1610                     spriteIdx = m_startsIdx[i].first + datum->index;
1611                     break;
1612                 }
1613             }
1614
1615             double frameAt;
1616             qreal progress = 0;
1617
1618             if (datum->frameDuration > 0) {
1619                 qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0);
1620                 frame = qBound((qreal)0.0, frame, (qreal)((qreal)datum->frameCount - 1.0));//Stop at count-1 frames until we have between anim interpolation
1621                 if (m_spritesInterpolate)
1622                     progress = modf(frame,&frameAt);
1623                 else
1624                     modf(frame,&frameAt);
1625             } else {
1626                 datum->frameAt++;
1627                 if (datum->frameAt >= datum->frameCount){
1628                     datum->frameAt = 0;
1629                     m_spriteEngine->advance(spriteIdx);
1630                 }
1631                 frameAt = datum->frameAt;
1632             }
1633             if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too?
1634                 frameAt = (datum->frameCount - 1) - frameAt;
1635             QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize;
1636             qreal y = datum->animY / sheetSize.height();
1637             qreal w = datum->animWidth / sheetSize.width();
1638             qreal h = datum->animHeight / sheetSize.height();
1639             qreal x1 = datum->animX / sheetSize.width();
1640             x1 += frameAt * w;
1641             qreal x2 = x1;
1642             if (frameAt < (datum->frameCount-1))
1643                 x2 += w;
1644
1645             node->setFlag(QSGNode::OwnsGeometry, false);
1646             SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1647             spriteVertices += datum->index*4;
1648             for (int i=0; i<4; i++) {
1649                 spriteVertices[i].animX1 = x1;
1650                 spriteVertices[i].animY1 = y;
1651                 spriteVertices[i].animX2 = x2;
1652                 spriteVertices[i].animY2 = y;
1653                 spriteVertices[i].animW = w;
1654                 spriteVertices[i].animH = h;
1655                 spriteVertices[i].animProgress = progress;
1656             }
1657             node->setFlag(QSGNode::OwnsGeometry, true);
1658         }
1659     }
1660 }
1661
1662 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1663 {
1664     if (!m_startsIdx.count())//Probably overly defensive
1665         return;
1666
1667     int gIdx = -1;
1668     int i;
1669     for (i = 0; i<m_startsIdx.count(); i++) {
1670         if (spriteIdx < m_startsIdx[i].first) {
1671             gIdx = m_startsIdx[i-1].second;
1672             break;
1673         }
1674     }
1675     if (gIdx == -1)
1676         gIdx = m_startsIdx[i-1].second;
1677     int pIdx = spriteIdx - m_startsIdx[i-1].first;
1678
1679     QQuickParticleData* mainDatum = m_system->groupData[gIdx]->data[pIdx];
1680     QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1681
1682     datum->animIdx = m_spriteEngine->spriteState(spriteIdx);
1683     datum->animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1684     datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1685     datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / datum->frameCount;
1686     datum->animX = m_spriteEngine->spriteX(spriteIdx);
1687     datum->animY = m_spriteEngine->spriteY(spriteIdx);
1688     datum->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1689     datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1690 }
1691
1692 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1693 {
1694     d->color = c;
1695     //TODO: get index for reload - or make function take an index
1696 }
1697
1698 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1699 {
1700     Color4ub color;
1701     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1702     qreal redVariation = m_color_variation + m_redVariation;
1703     qreal greenVariation = m_color_variation + m_greenVariation;
1704     qreal blueVariation = m_color_variation + m_blueVariation;
1705     int spriteIdx = 0;
1706     if (m_spriteEngine) {
1707         spriteIdx = m_idxStarts[gIdx] + datum->index;
1708         if (spriteIdx >= m_spriteEngine->count())
1709             m_spriteEngine->setCount(spriteIdx+1);
1710     }
1711
1712     float rotation;
1713     float rotationSpeed;
1714     float autoRotate;
1715     switch (perfLevel){//Fall-through is intended on all of them
1716         case Sprites:
1717             // Initial Sprite State
1718             if (m_explicitAnimation && m_spriteEngine){
1719                 if (!datum->animationOwner)
1720                     datum->animationOwner = this;
1721                 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1722                 writeTo->animT = writeTo->t;
1723                 //writeTo->animInterpolate = m_spritesInterpolate;
1724                 if (m_spriteEngine){
1725                     m_spriteEngine->start(spriteIdx);
1726                     writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1727                     writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / writeTo->frameCount;
1728                     writeTo->animIdx = 0;//Always starts at 0
1729                     writeTo->frameAt = -1;
1730                     writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1731                     writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1732                     writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1733                     writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1734                 }
1735             } else {
1736                 QQuickParticleData* writeTo = getShadowDatum(datum);
1737                 writeTo->animT = datum->t;
1738                 writeTo->frameCount = 1;
1739                 writeTo->frameDuration = 60000000.0;
1740                 writeTo->frameAt = -1;
1741                 writeTo->animIdx = 0;
1742                 writeTo->animT = 0;
1743                 writeTo->animX = writeTo->animY = 0;
1744                 writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
1745                 writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
1746             }
1747         case Tabled:
1748         case Deformable:
1749             //Initial Rotation
1750             if (m_explicitDeformation){
1751                 if (!datum->deformationOwner)
1752                     datum->deformationOwner = this;
1753                 if (m_xVector){
1754                     const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1755                     if (datum->deformationOwner == this) {
1756                         datum->xx = ret.x();
1757                         datum->xy = ret.y();
1758                     } else {
1759                         getShadowDatum(datum)->xx = ret.x();
1760                         getShadowDatum(datum)->xy = ret.y();
1761                     }
1762                 }
1763                 if (m_yVector){
1764                     const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1765                     if (datum->deformationOwner == this) {
1766                         datum->yx = ret.x();
1767                         datum->yy = ret.y();
1768                     } else {
1769                         getShadowDatum(datum)->yx = ret.x();
1770                         getShadowDatum(datum)->yy = ret.y();
1771                     }
1772                 }
1773             }
1774
1775             if (m_explicitRotation){
1776                 if (!datum->rotationOwner)
1777                     datum->rotationOwner = this;
1778                 rotation =
1779                         (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1780                 rotationSpeed =
1781                         (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1782                 autoRotate = m_autoRotation?1.0:0.0;
1783                 if (datum->rotationOwner == this) {
1784                     datum->rotation = rotation;
1785                     datum->rotationSpeed = rotationSpeed;
1786                     datum->autoRotate = autoRotate;
1787                 } else {
1788                     getShadowDatum(datum)->rotation = rotation;
1789                     getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1790                     getShadowDatum(datum)->autoRotate = autoRotate;
1791                 }
1792             }
1793         case Colored:
1794             //Color initialization
1795             // Particle color
1796             if (m_explicitColor) {
1797                 if (!datum->colorOwner)
1798                     datum->colorOwner = this;
1799                 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1800                 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1801                 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1802                 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1803                 if (datum->colorOwner == this)
1804                     datum->color = color;
1805                 else
1806                     getShadowDatum(datum)->color = color;
1807             }
1808         default:
1809             break;
1810     }
1811 }
1812
1813 void QQuickImageParticle::commit(int gIdx, int pIdx)
1814 {
1815     if (m_pleaseReset)
1816         return;
1817     QSGGeometryNode *node = m_nodes[gIdx];
1818     if (!node)
1819         return;
1820     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1821     node->setFlag(QSGNode::OwnsGeometry, false);
1822     SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1823     DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1824     ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1825     SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1826     switch (perfLevel){//No automatic fall through intended on this one
1827     case Sprites:
1828         spriteVertices += pIdx*4;
1829         for (int i=0; i<4; i++){
1830             spriteVertices[i].x = datum->x  - m_systemOffset.x();
1831             spriteVertices[i].y = datum->y  - m_systemOffset.y();
1832             spriteVertices[i].t = datum->t;
1833             spriteVertices[i].lifeSpan = datum->lifeSpan;
1834             spriteVertices[i].size = datum->size;
1835             spriteVertices[i].endSize = datum->endSize;
1836             spriteVertices[i].vx = datum->vx;
1837             spriteVertices[i].vy = datum->vy;
1838             spriteVertices[i].ax = datum->ax;
1839             spriteVertices[i].ay = datum->ay;
1840             if (m_explicitDeformation && datum->deformationOwner != this) {
1841                 QQuickParticleData* shadow = getShadowDatum(datum);
1842                 spriteVertices[i].xx = shadow->xx;
1843                 spriteVertices[i].xy = shadow->xy;
1844                 spriteVertices[i].yx = shadow->yx;
1845                 spriteVertices[i].yy = shadow->yy;
1846             } else {
1847                 spriteVertices[i].xx = datum->xx;
1848                 spriteVertices[i].xy = datum->xy;
1849                 spriteVertices[i].yx = datum->yx;
1850                 spriteVertices[i].yy = datum->yy;
1851             }
1852             if (m_explicitRotation && datum->rotationOwner != this) {
1853                 QQuickParticleData* shadow = getShadowDatum(datum);
1854                 spriteVertices[i].rotation = shadow->rotation;
1855                 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1856                 spriteVertices[i].autoRotate = shadow->autoRotate;
1857             } else {
1858                 spriteVertices[i].rotation = datum->rotation;
1859                 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1860                 spriteVertices[i].autoRotate = datum->autoRotate;
1861             }
1862             //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand
1863             if (m_explicitColor && datum->colorOwner != this) {
1864                 QQuickParticleData* shadow = getShadowDatum(datum);
1865                 spriteVertices[i].color.r = shadow->color.r;
1866                 spriteVertices[i].color.g = shadow->color.g;
1867                 spriteVertices[i].color.b = shadow->color.b;
1868                 spriteVertices[i].color.a = shadow->color.a;
1869             } else {
1870                 spriteVertices[i].color.r = datum->color.r;
1871                 spriteVertices[i].color.g = datum->color.g;
1872                 spriteVertices[i].color.b = datum->color.b;
1873                 spriteVertices[i].color.a = datum->color.a;
1874             }
1875         }
1876         break;
1877     case Tabled: //Fall through until it has its own vertex class
1878     case Deformable:
1879         deformableVertices += pIdx*4;
1880         for (int i=0; i<4; i++){
1881             deformableVertices[i].x = datum->x  - m_systemOffset.x();
1882             deformableVertices[i].y = datum->y  - m_systemOffset.y();
1883             deformableVertices[i].t = datum->t;
1884             deformableVertices[i].lifeSpan = datum->lifeSpan;
1885             deformableVertices[i].size = datum->size;
1886             deformableVertices[i].endSize = datum->endSize;
1887             deformableVertices[i].vx = datum->vx;
1888             deformableVertices[i].vy = datum->vy;
1889             deformableVertices[i].ax = datum->ax;
1890             deformableVertices[i].ay = datum->ay;
1891             if (m_explicitDeformation && datum->deformationOwner != this) {
1892                 QQuickParticleData* shadow = getShadowDatum(datum);
1893                 deformableVertices[i].xx = shadow->xx;
1894                 deformableVertices[i].xy = shadow->xy;
1895                 deformableVertices[i].yx = shadow->yx;
1896                 deformableVertices[i].yy = shadow->yy;
1897             } else {
1898                 deformableVertices[i].xx = datum->xx;
1899                 deformableVertices[i].xy = datum->xy;
1900                 deformableVertices[i].yx = datum->yx;
1901                 deformableVertices[i].yy = datum->yy;
1902             }
1903             if (m_explicitRotation && datum->rotationOwner != this) {
1904                 QQuickParticleData* shadow = getShadowDatum(datum);
1905                 deformableVertices[i].rotation = shadow->rotation;
1906                 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1907                 deformableVertices[i].autoRotate = shadow->autoRotate;
1908             } else {
1909                 deformableVertices[i].rotation = datum->rotation;
1910                 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1911                 deformableVertices[i].autoRotate = datum->autoRotate;
1912             }
1913             if (m_explicitColor && datum->colorOwner != this) {
1914                 QQuickParticleData* shadow = getShadowDatum(datum);
1915                 deformableVertices[i].color.r = shadow->color.r;
1916                 deformableVertices[i].color.g = shadow->color.g;
1917                 deformableVertices[i].color.b = shadow->color.b;
1918                 deformableVertices[i].color.a = shadow->color.a;
1919             } else {
1920                 deformableVertices[i].color.r = datum->color.r;
1921                 deformableVertices[i].color.g = datum->color.g;
1922                 deformableVertices[i].color.b = datum->color.b;
1923                 deformableVertices[i].color.a = datum->color.a;
1924             }
1925         }
1926         break;
1927     case Colored:
1928         coloredVertices += pIdx*1;
1929         for (int i=0; i<1; i++){
1930             coloredVertices[i].x = datum->x  - m_systemOffset.x();
1931             coloredVertices[i].y = datum->y  - m_systemOffset.y();
1932             coloredVertices[i].t = datum->t;
1933             coloredVertices[i].lifeSpan = datum->lifeSpan;
1934             coloredVertices[i].size = datum->size;
1935             coloredVertices[i].endSize = datum->endSize;
1936             coloredVertices[i].vx = datum->vx;
1937             coloredVertices[i].vy = datum->vy;
1938             coloredVertices[i].ax = datum->ax;
1939             coloredVertices[i].ay = datum->ay;
1940             if (m_explicitColor && datum->colorOwner != this) {
1941                 QQuickParticleData* shadow = getShadowDatum(datum);
1942                 coloredVertices[i].color.r = shadow->color.r;
1943                 coloredVertices[i].color.g = shadow->color.g;
1944                 coloredVertices[i].color.b = shadow->color.b;
1945                 coloredVertices[i].color.a = shadow->color.a;
1946             } else {
1947                 coloredVertices[i].color.r = datum->color.r;
1948                 coloredVertices[i].color.g = datum->color.g;
1949                 coloredVertices[i].color.b = datum->color.b;
1950                 coloredVertices[i].color.a = datum->color.a;
1951             }
1952         }
1953         break;
1954     case Simple:
1955         simpleVertices += pIdx*1;
1956         for (int i=0; i<1; i++){
1957             simpleVertices[i].x = datum->x - m_systemOffset.x();
1958             simpleVertices[i].y = datum->y - m_systemOffset.y();
1959             simpleVertices[i].t = datum->t;
1960             simpleVertices[i].lifeSpan = datum->lifeSpan;
1961             simpleVertices[i].size = datum->size;
1962             simpleVertices[i].endSize = datum->endSize;
1963             simpleVertices[i].vx = datum->vx;
1964             simpleVertices[i].vy = datum->vy;
1965             simpleVertices[i].ax = datum->ax;
1966             simpleVertices[i].ay = datum->ay;
1967         }
1968         break;
1969     default:
1970         break;
1971     }
1972
1973     node->setFlag(QSGNode::OwnsGeometry, true);
1974 }
1975
1976
1977
1978 QT_END_NAMESPACE