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