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