More documentation about importing LocalStorage module from Javascript
[profile/ivi/qtdeclarative.git] / src / quick / 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 Declarative 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/qsgengine.h>
55 #include <QtQuick/private/qsgtexture_p.h>
56 #include <private/qdeclarativeglobal_p.h>
57 #include <QtDeclarative/qdeclarativeinfo.h>
58 #include <cmath>
59
60 QT_BEGIN_NAMESPACE
61
62 #ifndef QT_OPENGL_ES_2
63 #define SHADER_DEFINES "#version 120\n"
64 #else
65 #define SHADER_DEFINES ""
66 #endif
67
68 //TODO: Make it larger on desktop? Requires fixing up shader code with the same define
69 #define UNIFORM_ARRAY_SIZE 64
70
71 static const char vertexShaderCode[] =
72     "#if defined(DEFORM)\n"
73     "attribute highp vec4 vPosTex;\n"
74     "#else\n"
75     "attribute highp vec2 vPos;\n"
76     "#endif\n"
77     "attribute highp vec4 vData; //  x = time,  y = lifeSpan, z = size,  w = endSize\n"
78     "attribute highp vec4 vVec; // x,y = constant speed,  z,w = acceleration\n"
79     "uniform highp float entry;\n"
80     "#if defined(COLOR)\n"
81     "attribute highp vec4 vColor;\n"
82     "#endif\n"
83     "#if defined(DEFORM)\n"
84     "attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector\n"
85     "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate\n"
86     "#endif\n"
87     "#if defined(SPRITE)\n"
88     "attribute highp vec3 vAnimData;// w,h(premultiplied of anim), interpolation progress\n"
89     "attribute highp vec4 vAnimPos;//x,y, x,y (two frames for interpolation)\n"
90     "#endif\n"
91     "\n"
92     "uniform highp mat4 qt_Matrix;\n"
93     "uniform highp float timestamp;\n"
94     "#if defined(TABLE)\n"
95     "varying lowp vec2 tt;//y is progress if Sprite mode\n"
96     "uniform highp float sizetable[64];\n"
97     "uniform highp float opacitytable[64];\n"
98     "#endif\n"
99     "#if defined(SPRITE)\n"
100     "varying highp vec4 fTexS;\n"
101     "#elif defined(DEFORM)\n"
102     "varying highp vec2 fTex;\n"
103     "#endif\n"
104     "#if defined(COLOR)\n"
105     "varying lowp vec4 fColor;\n"
106     "#else\n"
107     "varying lowp float fFade;\n"
108     "#endif\n"
109     "\n"
110     "\n"
111     "void main() {\n"
112     "\n"
113     "    highp float t = (timestamp - vData.x) / vData.y;\n"
114     "    if (t < 0. || t > 1.) {\n"
115     "#if defined(DEFORM)\n"
116     "        gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
117     "#else\n"
118     "        gl_PointSize = 0.;\n"
119     "#endif\n"
120     "    } else {\n"
121     "#if defined(SPRITE)\n"
122     "        tt.y = vAnimData.z;\n"
123     "        //Calculate frame location in texture\n"
124     "        fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;\n"
125     "        //Next frame is also passed, for interpolation\n"
126     "        fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;\n"
127     "\n"
128     "#elif defined(DEFORM)\n"
129     "        fTex = vPosTex.zw;\n"
130     "#endif\n"
131     "        highp float currentSize = mix(vData.z, vData.w, t * t);\n"
132     "        lowp float fade = 1.;\n"
133     "        highp float fadeIn = min(t * 10., 1.);\n"
134     "        highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);\n"
135     "\n"
136     "#if defined(TABLE)\n"
137     "        currentSize = currentSize * sizetable[int(floor(t*64.))];\n"
138     "        fade = fade * opacitytable[int(floor(t*64.))];\n"
139     "#endif\n"
140     "\n"
141     "        if (entry == 1.)\n"
142     "            fade = fade * fadeIn * fadeOut;\n"
143     "        else if (entry == 2.)\n"
144     "            currentSize = currentSize * fadeIn * fadeOut;\n"
145     "\n"
146     "        if (currentSize <= 0.) {\n"
147     "#if defined(DEFORM)\n"
148     "            gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
149     "#else\n"
150     "            gl_PointSize = 0.;\n"
151     "#endif\n"
152     "        } else {\n"
153     "            if (currentSize < 3.)//Sizes too small look jittery as they move\n"
154     "                currentSize = 3.;\n"
155     "\n"
156     "            highp vec2 pos;\n"
157     "#if defined(DEFORM)\n"
158     "            highp float rotation = vRotation.x + vRotation.y * t * vData.y;\n"
159     "            if (vRotation.z == 1.0){\n"
160     "                highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;\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     \o colorized
595     \o rotated
596     \o deformed
597     \o 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     \o ImageParticle.None: Particles just appear and disappear.
774     \o ImageParticle.Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
775     \o 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 QDeclarativeListProperty<QQuickSprite> QQuickImageParticle::sprites()
838 {
839     return QDeclarativeListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
840 }
841
842 void QQuickImageParticle::setImage(const QUrl &image)
843 {
844     if (image.isEmpty()){
845         if (m_image) {
846             delete m_image;
847             emit imageChanged();
848         }
849         return;
850     }
851
852     if (!m_image)
853         m_image = new ImageData;
854     if (image == m_image->source)
855         return;
856     m_image->source = image;
857     emit imageChanged();
858     reset();
859 }
860
861
862 void QQuickImageParticle::setColortable(const QUrl &table)
863 {
864     if (table.isEmpty()){
865         if (m_colorTable) {
866             delete m_colorTable;
867             emit colortableChanged();
868         }
869         return;
870     }
871
872     if (!m_colorTable)
873         m_colorTable = new ImageData;
874     if (table == m_colorTable->source)
875         return;
876     m_colorTable->source = table;
877     emit colortableChanged();
878     reset();
879 }
880
881 void QQuickImageParticle::setSizetable(const QUrl &table)
882 {
883     if (table.isEmpty()){
884         if (m_sizeTable) {
885             delete m_sizeTable;
886             emit sizetableChanged();
887         }
888         return;
889     }
890
891     if (!m_sizeTable)
892         m_sizeTable = new ImageData;
893     if (table == m_sizeTable->source)
894         return;
895     m_sizeTable->source = table;
896     emit sizetableChanged();
897     reset();
898 }
899
900 void QQuickImageParticle::setOpacitytable(const QUrl &table)
901 {
902     if (table.isEmpty()){
903         if (m_opacityTable) {
904             delete m_opacityTable;
905             emit opacitytableChanged();
906         }
907         return;
908     }
909
910     if (!m_opacityTable)
911         m_opacityTable = new ImageData;
912     if (table == m_opacityTable->source)
913         return;
914     m_opacityTable->source = table;
915     emit opacitytableChanged();
916     reset();
917 }
918
919 void QQuickImageParticle::setColor(const QColor &color)
920 {
921     if (color == m_color)
922         return;
923     m_color = color;
924     emit colorChanged();
925     m_explicitColor = true;
926     if (perfLevel < Colored)
927         reset();
928 }
929
930 void QQuickImageParticle::setColorVariation(qreal var)
931 {
932     if (var == m_color_variation)
933         return;
934     m_color_variation = var;
935     emit colorVariationChanged();
936     m_explicitColor = true;
937     if (perfLevel < Colored)
938         reset();
939 }
940
941 void QQuickImageParticle::setAlphaVariation(qreal arg)
942 {
943     if (m_alphaVariation != arg) {
944         m_alphaVariation = arg;
945         emit alphaVariationChanged(arg);
946     }
947     m_explicitColor = true;
948     if (perfLevel < Colored)
949         reset();
950 }
951
952 void QQuickImageParticle::setAlpha(qreal arg)
953 {
954     if (m_alpha != arg) {
955         m_alpha = arg;
956         emit alphaChanged(arg);
957     }
958     m_explicitColor = true;
959     if (perfLevel < Colored)
960         reset();
961 }
962
963 void QQuickImageParticle::setRedVariation(qreal arg)
964 {
965     if (m_redVariation != arg) {
966         m_redVariation = arg;
967         emit redVariationChanged(arg);
968     }
969     m_explicitColor = true;
970     if (perfLevel < Colored)
971         reset();
972 }
973
974 void QQuickImageParticle::setGreenVariation(qreal arg)
975 {
976     if (m_greenVariation != arg) {
977         m_greenVariation = arg;
978         emit greenVariationChanged(arg);
979     }
980     m_explicitColor = true;
981     if (perfLevel < Colored)
982         reset();
983 }
984
985 void QQuickImageParticle::setBlueVariation(qreal arg)
986 {
987     if (m_blueVariation != arg) {
988         m_blueVariation = arg;
989         emit blueVariationChanged(arg);
990     }
991     m_explicitColor = true;
992     if (perfLevel < Colored)
993         reset();
994 }
995
996 void QQuickImageParticle::setRotation(qreal arg)
997 {
998     if (m_rotation != arg) {
999         m_rotation = arg;
1000         emit rotationChanged(arg);
1001     }
1002     m_explicitRotation = true;
1003     if (perfLevel < Deformable)
1004         reset();
1005 }
1006
1007 void QQuickImageParticle::setRotationVariation(qreal arg)
1008 {
1009     if (m_rotationVariation != arg) {
1010         m_rotationVariation = arg;
1011         emit rotationVariationChanged(arg);
1012     }
1013     m_explicitRotation = true;
1014     if (perfLevel < Deformable)
1015         reset();
1016 }
1017
1018 void QQuickImageParticle::setRotationSpeed(qreal arg)
1019 {
1020     if (m_rotationSpeed != arg) {
1021         m_rotationSpeed = arg;
1022         emit rotationSpeedChanged(arg);
1023     }
1024     m_explicitRotation = true;
1025     if (perfLevel < Deformable)
1026         reset();
1027 }
1028
1029 void QQuickImageParticle::setRotationSpeedVariation(qreal arg)
1030 {
1031     if (m_rotationSpeedVariation != arg) {
1032         m_rotationSpeedVariation = arg;
1033         emit rotationSpeedVariationChanged(arg);
1034     }
1035     m_explicitRotation = true;
1036     if (perfLevel < Deformable)
1037         reset();
1038 }
1039
1040 void QQuickImageParticle::setAutoRotation(bool arg)
1041 {
1042     if (m_autoRotation != arg) {
1043         m_autoRotation = arg;
1044         emit autoRotationChanged(arg);
1045     }
1046     m_explicitRotation = true;
1047     if (perfLevel < Deformable)
1048         reset();
1049 }
1050
1051 void QQuickImageParticle::setXVector(QQuickDirection* arg)
1052 {
1053     if (m_xVector != arg) {
1054         m_xVector = arg;
1055         emit xVectorChanged(arg);
1056     }
1057     m_explicitDeformation = true;
1058     if (perfLevel < Deformable)
1059         reset();
1060 }
1061
1062 void QQuickImageParticle::setYVector(QQuickDirection* arg)
1063 {
1064     if (m_yVector != arg) {
1065         m_yVector = arg;
1066         emit yVectorChanged(arg);
1067     }
1068     m_explicitDeformation = true;
1069     if (perfLevel < Deformable)
1070         reset();
1071 }
1072
1073 void QQuickImageParticle::setSpritesInterpolate(bool arg)
1074 {
1075     if (m_spritesInterpolate != arg) {
1076         m_spritesInterpolate = arg;
1077         emit spritesInterpolateChanged(arg);
1078     }
1079 }
1080
1081 void QQuickImageParticle::setBypassOptimizations(bool arg)
1082 {
1083     if (m_bypassOptimizations != arg) {
1084         m_bypassOptimizations = arg;
1085         emit bypassOptimizationsChanged(arg);
1086     }
1087     if (perfLevel < 9999)
1088         reset();
1089 }
1090
1091 void QQuickImageParticle::setEntryEffect(EntryEffect arg)
1092 {
1093     if (m_entryEffect != arg) {
1094         m_entryEffect = arg;
1095         if (m_material)
1096             getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1097         emit entryEffectChanged(arg);
1098     }
1099 }
1100
1101 void QQuickImageParticle::resetColor()
1102 {
1103     m_explicitColor = false;
1104     foreach (const QString &str, m_groups)
1105         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1106             if (d->colorOwner == this)
1107                 d->colorOwner = 0;
1108     m_color = QColor();
1109     m_color_variation = 0.0f;
1110     m_redVariation = 0.0f;
1111     m_blueVariation = 0.0f;
1112     m_greenVariation = 0.0f;
1113     m_alpha = 1.0f;
1114     m_alphaVariation = 0.0f;
1115 }
1116
1117 void QQuickImageParticle::resetRotation()
1118 {
1119     m_explicitRotation = false;
1120     foreach (const QString &str, m_groups)
1121         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1122             if (d->rotationOwner == this)
1123                 d->rotationOwner = 0;
1124     m_rotation = 0;
1125     m_rotationVariation = 0;
1126     m_rotationSpeed = 0;
1127     m_rotationSpeedVariation = 0;
1128     m_autoRotation = false;
1129 }
1130
1131 void QQuickImageParticle::resetDeformation()
1132 {
1133     m_explicitDeformation = false;
1134     foreach (const QString &str, m_groups)
1135         foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1136             if (d->deformationOwner == this)
1137                 d->deformationOwner = 0;
1138     if (m_xVector)
1139         delete m_xVector;
1140     if (m_yVector)
1141         delete m_yVector;
1142     m_xVector = 0;
1143     m_yVector = 0;
1144 }
1145
1146 void QQuickImageParticle::reset()
1147 {
1148     QQuickParticlePainter::reset();
1149     m_pleaseReset = true;
1150     update();
1151 }
1152
1153 void QQuickImageParticle::createEngine()
1154 {
1155     if (m_spriteEngine)
1156         delete m_spriteEngine;
1157     if (m_sprites.count()) {
1158         m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1159         connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1160                 this, SLOT(spriteAdvance(int)), Qt::DirectConnection);
1161         m_explicitAnimation = true;
1162     } else {
1163         m_spriteEngine = 0;
1164         m_explicitAnimation = false;
1165     }
1166     reset();
1167 }
1168
1169 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
1170     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
1171     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1172     QSGGeometry::Attribute::create(2, 4, GL_FLOAT)             // Vectors
1173 };
1174
1175 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
1176 {
1177     3, // Attribute Count
1178     ( 2 + 4 + 4 ) * sizeof(float),
1179     SimpleParticle_Attributes
1180 };
1181
1182 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
1183     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
1184     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1185     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1186     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1187 };
1188
1189 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
1190 {
1191     4, // Attribute Count
1192     ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1193     ColoredParticle_Attributes
1194 };
1195
1196 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
1197     QSGGeometry::Attribute::create(0, 4, GL_FLOAT),             // Position & TexCoord
1198     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1199     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1200     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1201     QSGGeometry::Attribute::create(4, 4, GL_FLOAT),             // DeformationVectors
1202     QSGGeometry::Attribute::create(5, 3, GL_FLOAT),             // Rotation
1203 };
1204
1205 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1206 {
1207     6, // Attribute Count
1208     (4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1209     DeformableParticle_Attributes
1210 };
1211
1212 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1213     QSGGeometry::Attribute::create(0, 4, GL_FLOAT),       // Position & TexCoord
1214     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
1215     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
1216     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
1217     QSGGeometry::Attribute::create(4, 4, GL_FLOAT),             // DeformationVectors
1218     QSGGeometry::Attribute::create(5, 3, GL_FLOAT),             // Rotation
1219     QSGGeometry::Attribute::create(6, 3, GL_FLOAT),             // Anim Data
1220     QSGGeometry::Attribute::create(7, 4, GL_FLOAT)              // Anim Pos
1221 };
1222
1223 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1224 {
1225     8, // Attribute Count
1226     (4 + 4 + 4 + 4 + 3 + 3 + 4) * sizeof(float) + 4 * sizeof(uchar),
1227     SpriteParticle_Attributes
1228 };
1229
1230 void QQuickImageParticle::clearShadows()
1231 {
1232     foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1233         qDeleteAll(data);
1234     m_shadowData.clear();
1235 }
1236
1237 //Only call if you need to, may initialize the whole array first time
1238 QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1239 {
1240     //Will return datum if the datum is a sentinel or uninitialized, to centralize that one check
1241     if (datum->systemIndex == -1)
1242         return datum;
1243     QQuickParticleGroupData* gd = m_system->groupData[datum->group];
1244     if (!m_shadowData.contains(datum->group)) {
1245         QVector<QQuickParticleData*> data;
1246         for (int i=0; i<gd->size(); i++){
1247             QQuickParticleData* datum = new QQuickParticleData(m_system);
1248             *datum = *(gd->data[i]);
1249             data << datum;
1250         }
1251         m_shadowData.insert(datum->group, data);
1252     }
1253     //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1254
1255     return m_shadowData[datum->group][datum->index];
1256 }
1257
1258 bool QQuickImageParticle::loadingSomething()
1259 {
1260     return (m_image && m_image->pix.isLoading())
1261         || (m_colorTable && m_colorTable->pix.isLoading())
1262         || (m_sizeTable && m_sizeTable->pix.isLoading())
1263         || (m_opacityTable && m_opacityTable->pix.isLoading())
1264         || (m_spriteEngine && m_spriteEngine->isLoading());
1265 }
1266
1267 void QQuickImageParticle::buildParticleNodes()//Starts async parts, like loading images.
1268 {
1269     if (m_rootNode || loadingSomething())
1270         return;
1271
1272     if (!m_buildingNodes) {
1273         if (m_image) {//ImageData created on setSource
1274             m_image->pix.clear(this);
1275             m_image->pix.load(qmlEngine(this), m_image->source);
1276         }
1277
1278         if (m_spriteEngine)
1279             m_spriteEngine->startAssemblingImage();
1280
1281         if (m_colorTable)
1282             m_colorTable->pix.load(qmlEngine(this), m_colorTable->source);
1283
1284         if (m_sizeTable)
1285             m_sizeTable->pix.load(qmlEngine(this), m_sizeTable->source);
1286
1287         if (m_opacityTable)
1288             m_opacityTable->pix.load(qmlEngine(this), m_opacityTable->source);
1289
1290         m_buildingNodes = true;
1291         if (loadingSomething())
1292             return;
1293     }
1294     finishBuildParticleNodes();
1295 }
1296
1297 void QQuickImageParticle::finishBuildParticleNodes()
1298 {
1299     m_buildingNodes = false;
1300 #ifdef QT_OPENGL_ES_2
1301     if (m_count * 4 > 0xffff) {
1302         printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1303         return;
1304     }
1305 #endif
1306
1307     if (count() <= 0)
1308         return;
1309
1310     m_debugMode = m_system->m_debugMode;
1311
1312     if (m_sprites.count() || m_bypassOptimizations) {
1313         perfLevel = Sprites;
1314     } else if (m_colorTable || m_sizeTable || m_opacityTable) {
1315         perfLevel = Tabled;
1316     } else if (m_autoRotation || m_rotation || m_rotationVariation
1317                || m_rotationSpeed || m_rotationSpeedVariation
1318                || m_xVector || m_yVector) {
1319         perfLevel = Deformable;
1320     } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1321                || m_redVariation || m_blueVariation || m_greenVariation) {
1322         perfLevel = Colored;
1323     } else {
1324         perfLevel = Simple;
1325     }
1326
1327     foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1328         int gIdx = m_system->groupIds[str];
1329         foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){
1330             QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1331             if (other){
1332                 if (other->perfLevel > perfLevel) {
1333                     if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1334                         if (perfLevel < Deformable)
1335                             perfLevel = Deformable;
1336                     } else {
1337                         perfLevel = other->perfLevel;
1338                     }
1339                 } else if (other->perfLevel < perfLevel) {
1340                     other->reset();
1341                 }
1342             }
1343         }
1344     }
1345 #ifdef Q_OS_WIN
1346     if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows.
1347         perfLevel = Deformable;
1348 #endif
1349
1350     if (perfLevel >= Colored  && !m_color.isValid())
1351         m_color = QColor(Qt::white);//Hidden default, but different from unset
1352
1353     clearShadows();
1354     if (m_material)
1355         m_material = 0;
1356
1357     //Setup material
1358     QImage colortable;
1359     QImage sizetable;
1360     QImage opacitytable;
1361     QImage image;
1362     bool imageLoaded = false;
1363     switch (perfLevel) {//Fallthrough intended
1364     case Sprites:
1365         if (!m_spriteEngine) {
1366             qWarning() << "ImageParticle: No sprite engine...";
1367             //Sprite performance mode with static image is supported, but not advised
1368             //Note that in this case it always uses shadow data
1369         } else {
1370             image = m_spriteEngine->assembledImage();
1371             if (image.isNull())//Warning is printed in engine
1372                 return;
1373             imageLoaded = true;
1374         }
1375         m_material = SpriteMaterial::createMaterial();
1376         if (imageLoaded)
1377             getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1378         getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1379         if (m_spriteEngine)
1380             m_spriteEngine->setCount(m_count);
1381     case Tabled:
1382         if (!m_material)
1383             m_material = TabledMaterial::createMaterial();
1384
1385         if (m_colorTable) {
1386             if (m_colorTable->pix.isReady())
1387                 colortable = m_colorTable->pix.image();
1388             else
1389                 qmlInfo(this) << "Error loading color table: " << m_colorTable->pix.error();
1390         }
1391
1392         if (m_sizeTable) {
1393             if (m_sizeTable->pix.isReady())
1394                 sizetable = m_sizeTable->pix.image();
1395             else
1396                 qmlInfo(this) << "Error loading size table: " << m_sizeTable->pix.error();
1397         }
1398
1399         if (m_opacityTable) {
1400             if (m_opacityTable->pix.isReady())
1401                 opacitytable = m_opacityTable->pix.image();
1402             else
1403                 qmlInfo(this) << "Error loading opacity table: " << m_opacityTable->pix.error();
1404         }
1405
1406         if (colortable.isNull()){//###Goes through image just for this
1407             colortable = QImage(1,1,QImage::Format_ARGB32);
1408             colortable.fill(Qt::white);
1409         }
1410         getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1411         fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1412         fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1413     case Deformable:
1414         if (!m_material)
1415             m_material = DeformableMaterial::createMaterial();
1416     case Colored:
1417         if (!m_material)
1418             m_material = ColoredMaterial::createMaterial();
1419     default://Also Simple
1420         if (!m_material)
1421             m_material = SimpleMaterial::createMaterial();
1422         if (!imageLoaded) {
1423             if (!m_image->pix.isReady()) {
1424                 qmlInfo(this) << m_image->pix.error();
1425                 delete m_material;
1426                 return;
1427             }
1428             //getState<ImageMaterialData>(m_material)->texture //TODO: Shouldn't this be better? But not crash?
1429             //    = QQuickItemPrivate::get(this)->sceneGraphContext()->textureForFactory(m_imagePix.textureFactory());
1430             getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(m_image->pix.image());
1431         }
1432         getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1433         getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1434         m_material->setFlag(QSGMaterial::Blending);
1435     }
1436
1437     m_nodes.clear();
1438     foreach (const QString &str, m_groups){
1439         int gIdx = m_system->groupIds[str];
1440         int count = m_system->groupData[gIdx]->size();
1441         QSGGeometryNode* node = new QSGGeometryNode();
1442         node->setMaterial(m_material);
1443         node->markDirty(QSGNode::DirtyMaterial);
1444
1445         m_nodes.insert(gIdx, node);
1446         m_idxStarts.insert(gIdx, m_lastIdxStart);
1447         m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx));
1448         m_lastIdxStart += count;
1449
1450         //Create Particle Geometry
1451         int vCount = count * 4;
1452         int iCount = count * 6;
1453
1454         QSGGeometry *g;
1455         if (perfLevel == Sprites)
1456             g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1457         else if (perfLevel == Tabled)
1458             g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1459         else if (perfLevel == Deformable)
1460             g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1461         else if (perfLevel == Colored)
1462             g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1463         else //Simple
1464             g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1465
1466         node->setGeometry(g);
1467         if (perfLevel <= Colored){
1468             g->setDrawingMode(GL_POINTS);
1469             if (m_debugMode){
1470                 GLfloat pointSizeRange[2];
1471                 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1472                 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1473             }
1474         }else
1475             g->setDrawingMode(GL_TRIANGLES);
1476
1477         for (int p=0; p < count; ++p)
1478             commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1479
1480         if (perfLevel == Sprites)
1481             initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1482         else if (perfLevel == Tabled)
1483             initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1484         else if (perfLevel == Deformable)
1485             initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1486
1487         if (perfLevel > Colored){
1488             quint16 *indices = g->indexDataAsUShort();
1489             for (int i=0; i < count; ++i) {
1490                 int o = i * 4;
1491                 indices[0] = o;
1492                 indices[1] = o + 1;
1493                 indices[2] = o + 2;
1494                 indices[3] = o + 1;
1495                 indices[4] = o + 3;
1496                 indices[5] = o + 2;
1497                 indices += 6;
1498             }
1499         }
1500     }
1501
1502     if (perfLevel == Sprites)
1503         spritesUpdate();//Gives all vertexes the initial sprite data, then maintained per frame
1504
1505     foreach (QSGGeometryNode* node, m_nodes){
1506         if (node == *(m_nodes.begin()))
1507             node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1508         else
1509             (*(m_nodes.begin()))->appendChildNode(node);
1510     }
1511
1512     m_rootNode = *(m_nodes.begin());
1513     update();
1514 }
1515
1516 QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1517 {
1518     if (m_pleaseReset){
1519         m_lastLevel = perfLevel;
1520
1521         delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1522         m_rootNode = 0;
1523         m_nodes.clear();
1524
1525         m_idxStarts.clear();
1526         m_startsIdx.clear();
1527         m_lastIdxStart = 0;
1528
1529         m_material = 0;
1530
1531         m_pleaseReset = false;
1532         m_buildingNodes = false;//Cancel a part-way build
1533     }
1534
1535     if (m_system && m_system->isRunning() && !m_system->isPaused()){
1536         prepareNextFrame();
1537         if (m_rootNode) {
1538             update();
1539             foreach (QSGGeometryNode* node, m_nodes)
1540                 node->markDirty(QSGNode::DirtyGeometry);
1541         } else if (m_buildingNodes) {
1542             update();//To call prepareNextFrame() again from the renderThread
1543         }
1544     }
1545
1546     return m_rootNode;
1547 }
1548
1549 void QQuickImageParticle::prepareNextFrame()
1550 {
1551     if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1552         buildParticleNodes();
1553         if (m_debugMode) {
1554             qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1555             qDebug() << "QQuickImageParticle Nodes: ";
1556             int count = 0;
1557             foreach (int i, m_nodes.keys()) {
1558                 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1559                 count += m_system->groupData[i]->size();
1560             }
1561             qDebug() << "Total count: " << count;
1562         }
1563         if (m_rootNode == 0)
1564             return;
1565     }
1566     qint64 timeStamp = m_system->systemSync(this);
1567
1568     qreal time = timeStamp / 1000.;
1569
1570     switch (perfLevel){//Fall-through intended
1571     case Sprites:
1572         //Advance State
1573         if (m_spriteEngine)
1574             m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed
1575         spritesUpdate(time);
1576     case Tabled:
1577     case Deformable:
1578     case Colored:
1579     case Simple:
1580     default: //Also Simple
1581         getState<ImageMaterialData>(m_material)->timestamp = time;
1582         break;
1583     }
1584     foreach (QSGGeometryNode* node, m_nodes)
1585         node->markDirty(QSGNode::DirtyMaterial);
1586 }
1587
1588 void QQuickImageParticle::spritesUpdate(qreal time)
1589 {
1590     // Sprite progression handled CPU side, so as to have per-frame control.
1591     foreach (const QString &str, m_groups) {
1592         int gIdx = m_system->groupIds[str];
1593         foreach (QQuickParticleData* mainDatum, m_system->groupData[gIdx]->data) {
1594             QSGGeometryNode *node = m_nodes[gIdx];
1595             if (!node)
1596                 continue;
1597             //TODO: Interpolate between two different animations if it's going to transition next frame
1598             //      This is particularly important for cut-up sprites.
1599             QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1600             int spriteIdx = 0;
1601             for (int i = 0; i<m_startsIdx.count(); i++) {
1602                 if (m_startsIdx[i].second == gIdx){
1603                     spriteIdx = m_startsIdx[i].first + datum->index;
1604                     break;
1605                 }
1606             }
1607
1608             double frameAt;
1609             qreal progress = 0;
1610
1611             if (datum->frameDuration > 0) {
1612                 qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0);
1613                 frame = qBound((qreal)0.0, frame, (qreal)((qreal)datum->frameCount - 1.0));//Stop at count-1 frames until we have between anim interpolation
1614                 if (m_spritesInterpolate)
1615                     progress = modf(frame,&frameAt);
1616                 else
1617                     modf(frame,&frameAt);
1618             } else {
1619                 datum->frameAt++;
1620                 if (datum->frameAt >= datum->frameCount){
1621                     datum->frameAt = 0;
1622                     m_spriteEngine->advance(spriteIdx);
1623                 }
1624                 frameAt = datum->frameAt;
1625             }
1626             if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too?
1627                 frameAt = (datum->frameCount - 1) - frameAt;
1628             QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize;
1629             qreal y = datum->animY / sheetSize.height();
1630             qreal w = datum->animWidth / sheetSize.width();
1631             qreal h = datum->animHeight / sheetSize.height();
1632             qreal x1 = datum->animX / sheetSize.width();
1633             x1 += frameAt * w;
1634             qreal x2 = x1;
1635             if (frameAt < (datum->frameCount-1))
1636                 x2 += w;
1637
1638             node->setFlag(QSGNode::OwnsGeometry, false);
1639             SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1640             spriteVertices += datum->index*4;
1641             for (int i=0; i<4; i++) {
1642                 spriteVertices[i].animX1 = x1;
1643                 spriteVertices[i].animY1 = y;
1644                 spriteVertices[i].animX2 = x2;
1645                 spriteVertices[i].animY2 = y;
1646                 spriteVertices[i].animW = w;
1647                 spriteVertices[i].animH = h;
1648                 spriteVertices[i].animProgress = progress;
1649             }
1650             node->setFlag(QSGNode::OwnsGeometry, true);
1651         }
1652     }
1653 }
1654
1655 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1656 {
1657     if (!m_startsIdx.count())//Probably overly defensive
1658         return;
1659
1660     int gIdx = -1;
1661     int i;
1662     for (i = 0; i<m_startsIdx.count(); i++) {
1663         if (spriteIdx < m_startsIdx[i].first) {
1664             gIdx = m_startsIdx[i-1].second;
1665             break;
1666         }
1667     }
1668     if (gIdx == -1)
1669         gIdx = m_startsIdx[i-1].second;
1670     int pIdx = spriteIdx - m_startsIdx[i-1].first;
1671
1672     QQuickParticleData* mainDatum = m_system->groupData[gIdx]->data[pIdx];
1673     QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
1674
1675     datum->animIdx = m_spriteEngine->spriteState(spriteIdx);
1676     datum->animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1677     datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1678     datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / datum->frameCount;
1679     datum->animX = m_spriteEngine->spriteX(spriteIdx);
1680     datum->animY = m_spriteEngine->spriteY(spriteIdx);
1681     datum->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1682     datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1683 }
1684
1685 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1686 {
1687     d->color = c;
1688     //TODO: get index for reload - or make function take an index
1689 }
1690
1691 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1692 {
1693     Color4ub color;
1694     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1695     qreal redVariation = m_color_variation + m_redVariation;
1696     qreal greenVariation = m_color_variation + m_greenVariation;
1697     qreal blueVariation = m_color_variation + m_blueVariation;
1698     int spriteIdx = 0;
1699     if (m_spriteEngine) {
1700         spriteIdx = m_idxStarts[gIdx] + datum->index;
1701         if (spriteIdx >= m_spriteEngine->count())
1702             m_spriteEngine->setCount(spriteIdx+1);
1703     }
1704
1705     float rotation;
1706     float rotationSpeed;
1707     float autoRotate;
1708     switch (perfLevel){//Fall-through is intended on all of them
1709         case Sprites:
1710             // Initial Sprite State
1711             if (m_explicitAnimation && m_spriteEngine){
1712                 if (!datum->animationOwner)
1713                     datum->animationOwner = this;
1714                 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1715                 writeTo->animT = writeTo->t;
1716                 //writeTo->animInterpolate = m_spritesInterpolate;
1717                 if (m_spriteEngine){
1718                     m_spriteEngine->start(spriteIdx);
1719                     writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1720                     writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / writeTo->frameCount;
1721                     writeTo->animIdx = 0;//Always starts at 0
1722                     writeTo->frameAt = -1;
1723                     writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1724                     writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1725                     writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1726                     writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1727                 }
1728             } else {
1729                 QQuickParticleData* writeTo = getShadowDatum(datum);
1730                 writeTo->animT = datum->t;
1731                 writeTo->frameCount = 1;
1732                 writeTo->frameDuration = 60000000.0;
1733                 writeTo->frameAt = -1;
1734                 writeTo->animIdx = 0;
1735                 writeTo->animT = 0;
1736                 writeTo->animX = writeTo->animY = 0;
1737                 writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
1738                 writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
1739             }
1740         case Tabled:
1741         case Deformable:
1742             //Initial Rotation
1743             if (m_explicitDeformation){
1744                 if (!datum->deformationOwner)
1745                     datum->deformationOwner = this;
1746                 if (m_xVector){
1747                     const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1748                     if (datum->deformationOwner == this) {
1749                         datum->xx = ret.x();
1750                         datum->xy = ret.y();
1751                     } else {
1752                         getShadowDatum(datum)->xx = ret.x();
1753                         getShadowDatum(datum)->xy = ret.y();
1754                     }
1755                 }
1756                 if (m_yVector){
1757                     const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1758                     if (datum->deformationOwner == this) {
1759                         datum->yx = ret.x();
1760                         datum->yy = ret.y();
1761                     } else {
1762                         getShadowDatum(datum)->yx = ret.x();
1763                         getShadowDatum(datum)->yy = ret.y();
1764                     }
1765                 }
1766             }
1767
1768             if (m_explicitRotation){
1769                 if (!datum->rotationOwner)
1770                     datum->rotationOwner = this;
1771                 rotation =
1772                         (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1773                 rotationSpeed =
1774                         (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1775                 autoRotate = m_autoRotation?1.0:0.0;
1776                 if (datum->rotationOwner == this) {
1777                     datum->rotation = rotation;
1778                     datum->rotationSpeed = rotationSpeed;
1779                     datum->autoRotate = autoRotate;
1780                 } else {
1781                     getShadowDatum(datum)->rotation = rotation;
1782                     getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1783                     getShadowDatum(datum)->autoRotate = autoRotate;
1784                 }
1785             }
1786         case Colored:
1787             //Color initialization
1788             // Particle color
1789             if (m_explicitColor) {
1790                 if (!datum->colorOwner)
1791                     datum->colorOwner = this;
1792                 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1793                 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1794                 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1795                 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1796                 if (datum->colorOwner == this)
1797                     datum->color = color;
1798                 else
1799                     getShadowDatum(datum)->color = color;
1800             }
1801         default:
1802             break;
1803     }
1804 }
1805
1806 void QQuickImageParticle::commit(int gIdx, int pIdx)
1807 {
1808     if (m_pleaseReset)
1809         return;
1810     QSGGeometryNode *node = m_nodes[gIdx];
1811     if (!node)
1812         return;
1813     QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1814     node->setFlag(QSGNode::OwnsGeometry, false);
1815     SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1816     DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1817     ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1818     SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1819     switch (perfLevel){//No automatic fall through intended on this one
1820     case Sprites:
1821         spriteVertices += pIdx*4;
1822         for (int i=0; i<4; i++){
1823             spriteVertices[i].x = datum->x  - m_systemOffset.x();
1824             spriteVertices[i].y = datum->y  - m_systemOffset.y();
1825             spriteVertices[i].t = datum->t;
1826             spriteVertices[i].lifeSpan = datum->lifeSpan;
1827             spriteVertices[i].size = datum->size;
1828             spriteVertices[i].endSize = datum->endSize;
1829             spriteVertices[i].vx = datum->vx;
1830             spriteVertices[i].vy = datum->vy;
1831             spriteVertices[i].ax = datum->ax;
1832             spriteVertices[i].ay = datum->ay;
1833             if (m_explicitDeformation && datum->deformationOwner != this) {
1834                 QQuickParticleData* shadow = getShadowDatum(datum);
1835                 spriteVertices[i].xx = shadow->xx;
1836                 spriteVertices[i].xy = shadow->xy;
1837                 spriteVertices[i].yx = shadow->yx;
1838                 spriteVertices[i].yy = shadow->yy;
1839             } else {
1840                 spriteVertices[i].xx = datum->xx;
1841                 spriteVertices[i].xy = datum->xy;
1842                 spriteVertices[i].yx = datum->yx;
1843                 spriteVertices[i].yy = datum->yy;
1844             }
1845             if (m_explicitRotation && datum->rotationOwner != this) {
1846                 QQuickParticleData* shadow = getShadowDatum(datum);
1847                 spriteVertices[i].rotation = shadow->rotation;
1848                 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1849                 spriteVertices[i].autoRotate = shadow->autoRotate;
1850             } else {
1851                 spriteVertices[i].rotation = datum->rotation;
1852                 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1853                 spriteVertices[i].autoRotate = datum->autoRotate;
1854             }
1855             //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand
1856             if (m_explicitColor && datum->colorOwner != this) {
1857                 QQuickParticleData* shadow = getShadowDatum(datum);
1858                 spriteVertices[i].color.r = shadow->color.r;
1859                 spriteVertices[i].color.g = shadow->color.g;
1860                 spriteVertices[i].color.b = shadow->color.b;
1861                 spriteVertices[i].color.a = shadow->color.a;
1862             } else {
1863                 spriteVertices[i].color.r = datum->color.r;
1864                 spriteVertices[i].color.g = datum->color.g;
1865                 spriteVertices[i].color.b = datum->color.b;
1866                 spriteVertices[i].color.a = datum->color.a;
1867             }
1868         }
1869         break;
1870     case Tabled: //Fall through until it has its own vertex class
1871     case Deformable:
1872         deformableVertices += pIdx*4;
1873         for (int i=0; i<4; i++){
1874             deformableVertices[i].x = datum->x  - m_systemOffset.x();
1875             deformableVertices[i].y = datum->y  - m_systemOffset.y();
1876             deformableVertices[i].t = datum->t;
1877             deformableVertices[i].lifeSpan = datum->lifeSpan;
1878             deformableVertices[i].size = datum->size;
1879             deformableVertices[i].endSize = datum->endSize;
1880             deformableVertices[i].vx = datum->vx;
1881             deformableVertices[i].vy = datum->vy;
1882             deformableVertices[i].ax = datum->ax;
1883             deformableVertices[i].ay = datum->ay;
1884             if (m_explicitDeformation && datum->deformationOwner != this) {
1885                 QQuickParticleData* shadow = getShadowDatum(datum);
1886                 deformableVertices[i].xx = shadow->xx;
1887                 deformableVertices[i].xy = shadow->xy;
1888                 deformableVertices[i].yx = shadow->yx;
1889                 deformableVertices[i].yy = shadow->yy;
1890             } else {
1891                 deformableVertices[i].xx = datum->xx;
1892                 deformableVertices[i].xy = datum->xy;
1893                 deformableVertices[i].yx = datum->yx;
1894                 deformableVertices[i].yy = datum->yy;
1895             }
1896             if (m_explicitRotation && datum->rotationOwner != this) {
1897                 QQuickParticleData* shadow = getShadowDatum(datum);
1898                 deformableVertices[i].rotation = shadow->rotation;
1899                 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1900                 deformableVertices[i].autoRotate = shadow->autoRotate;
1901             } else {
1902                 deformableVertices[i].rotation = datum->rotation;
1903                 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1904                 deformableVertices[i].autoRotate = datum->autoRotate;
1905             }
1906             if (m_explicitColor && datum->colorOwner != this) {
1907                 QQuickParticleData* shadow = getShadowDatum(datum);
1908                 deformableVertices[i].color.r = shadow->color.r;
1909                 deformableVertices[i].color.g = shadow->color.g;
1910                 deformableVertices[i].color.b = shadow->color.b;
1911                 deformableVertices[i].color.a = shadow->color.a;
1912             } else {
1913                 deformableVertices[i].color.r = datum->color.r;
1914                 deformableVertices[i].color.g = datum->color.g;
1915                 deformableVertices[i].color.b = datum->color.b;
1916                 deformableVertices[i].color.a = datum->color.a;
1917             }
1918         }
1919         break;
1920     case Colored:
1921         coloredVertices += pIdx*1;
1922         for (int i=0; i<1; i++){
1923             coloredVertices[i].x = datum->x  - m_systemOffset.x();
1924             coloredVertices[i].y = datum->y  - m_systemOffset.y();
1925             coloredVertices[i].t = datum->t;
1926             coloredVertices[i].lifeSpan = datum->lifeSpan;
1927             coloredVertices[i].size = datum->size;
1928             coloredVertices[i].endSize = datum->endSize;
1929             coloredVertices[i].vx = datum->vx;
1930             coloredVertices[i].vy = datum->vy;
1931             coloredVertices[i].ax = datum->ax;
1932             coloredVertices[i].ay = datum->ay;
1933             if (m_explicitColor && datum->colorOwner != this) {
1934                 QQuickParticleData* shadow = getShadowDatum(datum);
1935                 coloredVertices[i].color.r = shadow->color.r;
1936                 coloredVertices[i].color.g = shadow->color.g;
1937                 coloredVertices[i].color.b = shadow->color.b;
1938                 coloredVertices[i].color.a = shadow->color.a;
1939             } else {
1940                 coloredVertices[i].color.r = datum->color.r;
1941                 coloredVertices[i].color.g = datum->color.g;
1942                 coloredVertices[i].color.b = datum->color.b;
1943                 coloredVertices[i].color.a = datum->color.a;
1944             }
1945         }
1946         break;
1947     case Simple:
1948         simpleVertices += pIdx*1;
1949         for (int i=0; i<1; i++){
1950             simpleVertices[i].x = datum->x - m_systemOffset.x();
1951             simpleVertices[i].y = datum->y - m_systemOffset.y();
1952             simpleVertices[i].t = datum->t;
1953             simpleVertices[i].lifeSpan = datum->lifeSpan;
1954             simpleVertices[i].size = datum->size;
1955             simpleVertices[i].endSize = datum->endSize;
1956             simpleVertices[i].vx = datum->vx;
1957             simpleVertices[i].vy = datum->vy;
1958             simpleVertices[i].ax = datum->ax;
1959             simpleVertices[i].ay = datum->ay;
1960         }
1961         break;
1962     default:
1963         break;
1964     }
1965
1966     node->setFlag(QSGNode::OwnsGeometry, true);
1967 }
1968
1969
1970
1971 QT_END_NAMESPACE