Merge branch 'qtquick2' of scm.dev.nokia.troll.no:qt/qtdeclarative-staging into qtquick2
[profile/ivi/qtdeclarative.git] / src / declarative / particles / qsgimageparticle.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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <private/qsgcontext_p.h>
43 #include <private/qsgadaptationlayer_p.h>
44 #include <qsgnode.h>
45 #include <qsgtexturematerial.h>
46 #include <qsgtexture.h>
47 #include <QFile>
48 #include "qsgimageparticle_p.h"
49 #include "qsgparticleemitter_p.h"
50 #include "qsgsprite_p.h"
51 #include "qsgspriteengine_p.h"
52 #include <QGLFunctions>
53 #include <qsgengine.h>
54
55 QT_BEGIN_NAMESPACE
56
57 const float CONV = 0.017453292519943295;
58 class UltraMaterial : public QSGMaterial
59 {
60 public:
61     UltraMaterial(bool withSprites=false)
62         : timestamp(0)
63         , framecount(1)
64         , animcount(1)
65         , usesSprites(withSprites)
66     {
67         setFlag(Blending, true);
68     }
69
70     ~UltraMaterial()
71     {
72         delete texture;
73         delete colortable;
74         delete sizetable;
75         delete opacitytable;
76     }
77
78     virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
79     virtual QSGMaterialShader *createShader() const;
80     virtual int compare(const QSGMaterial *other) const
81     {
82         return this - static_cast<const UltraMaterial *>(other);
83     }
84
85     QSGTexture *texture;
86     QSGTexture *colortable;
87     QSGTexture *sizetable;
88     QSGTexture *opacitytable;
89
90     qreal timestamp;
91     int framecount;
92     int animcount;
93     bool usesSprites;
94 };
95 class UltraMaterialData : public QSGMaterialShader
96 {
97 public:
98     UltraMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
99     {
100         QFile vf(vertexFile ? vertexFile : ":defaultshaders/ultravertex.shader");
101         vf.open(QFile::ReadOnly);
102         m_vertex_code = vf.readAll();
103
104         QFile ff(fragmentFile ? fragmentFile : ":defaultshaders/ultrafragment.shader");
105         ff.open(QFile::ReadOnly);
106         m_fragment_code = ff.readAll();
107
108         Q_ASSERT(!m_vertex_code.isNull());
109         Q_ASSERT(!m_fragment_code.isNull());
110     }
111
112     void deactivate() {
113         QSGMaterialShader::deactivate();
114
115         for (int i=0; i<8; ++i) {
116             program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
117         }
118     }
119
120     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
121     {
122         UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
123         state.context()->functions()->glActiveTexture(GL_TEXTURE1);
124         m->colortable->bind();
125         program()->setUniformValue(m_colortable_id, 1);
126
127         state.context()->functions()->glActiveTexture(GL_TEXTURE2);
128         m->sizetable->bind();
129         program()->setUniformValue(m_sizetable_id, 2);
130
131         state.context()->functions()->glActiveTexture(GL_TEXTURE3);
132         m->opacitytable->bind();
133         program()->setUniformValue(m_opacitytable_id, 3);
134
135         state.context()->functions()->glActiveTexture(GL_TEXTURE0);//Investigate why this screws up Text{} if placed before 1
136         m->texture->bind();
137
138         program()->setUniformValue(m_opacity_id, state.opacity());
139         program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
140         program()->setUniformValue(m_framecount_id, (float) m->framecount);
141         program()->setUniformValue(m_animcount_id, (float) m->animcount);
142
143         if (state.isMatrixDirty())
144             program()->setUniformValue(m_matrix_id, state.combinedMatrix());
145     }
146
147     virtual void initialize() {
148         m_colortable_id = program()->uniformLocation("colortable");
149         m_sizetable_id = program()->uniformLocation("sizetable");
150         m_opacitytable_id = program()->uniformLocation("opacitytable");
151         m_matrix_id = program()->uniformLocation("matrix");
152         m_opacity_id = program()->uniformLocation("opacity");
153         m_timestamp_id = program()->uniformLocation("timestamp");
154         m_framecount_id = program()->uniformLocation("framecount");
155         m_animcount_id = program()->uniformLocation("animcount");
156     }
157
158     virtual const char *vertexShader() const { return m_vertex_code.constData(); }
159     virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
160
161     virtual char const *const *attributeNames() const {
162         static const char *attr[] = {
163             "vPos",
164             "vTex",
165             "vData",
166             "vVec",
167             "vColor",
168             "vDeformVec",
169             "vRotation",
170             "vAnimData",
171             0
172         };
173         return attr;
174     }
175
176     virtual bool isColorTable() const { return false; }
177
178     int m_matrix_id;
179     int m_opacity_id;
180     int m_timestamp_id;
181     int m_colortable_id;
182     int m_sizetable_id;
183     int m_opacitytable_id;
184     int m_framecount_id;
185     int m_animcount_id;
186
187     QByteArray m_vertex_code;
188     QByteArray m_fragment_code;
189
190     static float chunkOfBytes[1024];
191 };
192 float UltraMaterialData::chunkOfBytes[1024];
193
194 QSGMaterialShader *UltraMaterial::createShader() const
195 {
196     if(usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
197         return new UltraMaterialData;
198     else
199         return new UltraMaterialData;
200 }
201
202
203 class SimpleMaterial : public UltraMaterial
204 {
205     virtual QSGMaterialShader *createShader() const;
206     virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
207 };
208
209 class SimpleMaterialData : public QSGMaterialShader
210 {
211 public:
212     SimpleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
213     {
214         QFile vf(vertexFile ? vertexFile : ":defaultshaders/simplevertex.shader");
215         vf.open(QFile::ReadOnly);
216         m_vertex_code = vf.readAll();
217
218         QFile ff(fragmentFile ? fragmentFile : ":defaultshaders/simplefragment.shader");
219         ff.open(QFile::ReadOnly);
220         m_fragment_code = ff.readAll();
221
222         Q_ASSERT(!m_vertex_code.isNull());
223         Q_ASSERT(!m_fragment_code.isNull());
224     }
225
226     void deactivate() {
227         QSGMaterialShader::deactivate();
228
229         for (int i=0; i<8; ++i) {
230             program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
231         }
232     }
233
234     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
235     {
236         UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
237         state.context()->functions()->glActiveTexture(GL_TEXTURE0);
238         m->texture->bind();
239
240         program()->setUniformValue(m_opacity_id, state.opacity());
241         program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
242
243         if (state.isMatrixDirty())
244             program()->setUniformValue(m_matrix_id, state.combinedMatrix());
245     }
246
247     virtual void initialize() {
248         m_matrix_id = program()->uniformLocation("matrix");
249         m_opacity_id = program()->uniformLocation("opacity");
250         m_timestamp_id = program()->uniformLocation("timestamp");
251     }
252
253     virtual const char *vertexShader() const { return m_vertex_code.constData(); }
254     virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
255
256     virtual char const *const *attributeNames() const {
257         static const char *attr[] = {
258             "vPos",
259             "vTex",
260             "vData",
261             "vVec",
262             0
263         };
264         return attr;
265     }
266
267     virtual bool isColorTable() const { return false; }
268
269     int m_matrix_id;
270     int m_opacity_id;
271     int m_timestamp_id;
272
273     QByteArray m_vertex_code;
274     QByteArray m_fragment_code;
275
276     static float chunkOfBytes[1024];
277 };
278 float SimpleMaterialData::chunkOfBytes[1024];
279
280 QSGMaterialShader *SimpleMaterial::createShader() const {
281     return new SimpleMaterialData;
282 }
283
284 QSGImageParticle::QSGImageParticle(QSGItem* parent)
285     : QSGParticlePainter(parent)
286     , m_do_reset(false)
287     , m_color_variation(0.0)
288     , m_node(0)
289     , m_material(0)
290     , m_alphaVariation(0.0)
291     , m_alpha(1.0)
292     , m_redVariation(0.0)
293     , m_greenVariation(0.0)
294     , m_blueVariation(0.0)
295     , m_rotation(0)
296     , m_autoRotation(false)
297     , m_xVector(0)
298     , m_yVector(0)
299     , m_rotationVariation(0)
300     , m_rotationSpeed(0)
301     , m_rotationSpeedVariation(0)
302     , m_spriteEngine(0)
303     , m_bloat(false)
304     , perfLevel(Unknown)
305     , m_lastLevel(Unknown)
306 {
307     setFlag(ItemHasContents);
308 }
309
310 QDeclarativeListProperty<QSGSprite> QSGImageParticle::sprites()
311 {
312     return QDeclarativeListProperty<QSGSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
313 }
314
315 void QSGImageParticle::setImage(const QUrl &image)
316 {
317     if (image == m_image_name)
318         return;
319     m_image_name = image;
320     emit imageChanged();
321     reset();
322 }
323
324
325 void QSGImageParticle::setColortable(const QUrl &table)
326 {
327     if (table == m_colortable_name)
328         return;
329     m_colortable_name = table;
330     emit colortableChanged();
331     reset();
332 }
333
334 void QSGImageParticle::setSizetable(const QUrl &table)
335 {
336     if (table == m_sizetable_name)
337         return;
338     m_sizetable_name = table;
339     emit sizetableChanged();
340     reset();
341 }
342
343 void QSGImageParticle::setOpacitytable(const QUrl &table)
344 {
345     if (table == m_opacitytable_name)
346         return;
347     m_opacitytable_name = table;
348     emit opacitytableChanged();
349     reset();
350 }
351
352 void QSGImageParticle::setColor(const QColor &color)
353 {
354     if (color == m_color)
355         return;
356     m_color = color;
357     emit colorChanged();
358     if(perfLevel < Colored)
359         reset();
360 }
361
362 void QSGImageParticle::setColorVariation(qreal var)
363 {
364     if (var == m_color_variation)
365         return;
366     m_color_variation = var;
367     emit colorVariationChanged();
368     if(perfLevel < Colored)
369         reset();
370 }
371
372 void QSGImageParticle::setAlphaVariation(qreal arg)
373 {
374     if (m_alphaVariation != arg) {
375         m_alphaVariation = arg;
376         emit alphaVariationChanged(arg);
377     }
378     if(perfLevel < Colored)
379         reset();
380 }
381
382 void QSGImageParticle::setAlpha(qreal arg)
383 {
384     if (m_alpha != arg) {
385         m_alpha = arg;
386         emit alphaChanged(arg);
387     }
388     if(perfLevel < Colored)
389         reset();
390 }
391
392 void QSGImageParticle::setRedVariation(qreal arg)
393 {
394     if (m_redVariation != arg) {
395         m_redVariation = arg;
396         emit redVariationChanged(arg);
397     }
398     if(perfLevel < Colored)
399         reset();
400 }
401
402 void QSGImageParticle::setGreenVariation(qreal arg)
403 {
404     if (m_greenVariation != arg) {
405         m_greenVariation = arg;
406         emit greenVariationChanged(arg);
407     }
408     if(perfLevel < Colored)
409         reset();
410 }
411
412 void QSGImageParticle::setBlueVariation(qreal arg)
413 {
414     if (m_blueVariation != arg) {
415         m_blueVariation = arg;
416         emit blueVariationChanged(arg);
417     }
418     if(perfLevel < Colored)
419         reset();
420 }
421
422 void QSGImageParticle::setRotation(qreal arg)
423 {
424     if (m_rotation != arg) {
425         m_rotation = arg;
426         emit rotationChanged(arg);
427     }
428     if(perfLevel < Deformable)
429         reset();
430 }
431
432 void QSGImageParticle::setRotationVariation(qreal arg)
433 {
434     if (m_rotationVariation != arg) {
435         m_rotationVariation = arg;
436         emit rotationVariationChanged(arg);
437     }
438     if(perfLevel < Deformable)
439         reset();
440 }
441
442 void QSGImageParticle::setRotationSpeed(qreal arg)
443 {
444     if (m_rotationSpeed != arg) {
445         m_rotationSpeed = arg;
446         emit rotationSpeedChanged(arg);
447     }
448     if(perfLevel < Deformable)
449         reset();
450 }
451
452 void QSGImageParticle::setRotationSpeedVariation(qreal arg)
453 {
454     if (m_rotationSpeedVariation != arg) {
455         m_rotationSpeedVariation = arg;
456         emit rotationSpeedVariationChanged(arg);
457     }
458     if(perfLevel < Deformable)
459         reset();
460 }
461
462 void QSGImageParticle::setAutoRotation(bool arg)
463 {
464     if (m_autoRotation != arg) {
465         m_autoRotation = arg;
466         emit autoRotationChanged(arg);
467     }
468     if(perfLevel < Deformable)
469         reset();
470 }
471
472 void QSGImageParticle::setXVector(QSGStochasticDirection* arg)
473 {
474     if (m_xVector != arg) {
475         m_xVector = arg;
476         emit xVectorChanged(arg);
477     }
478     if(perfLevel < Deformable)
479         reset();
480 }
481
482 void QSGImageParticle::setYVector(QSGStochasticDirection* arg)
483 {
484     if (m_yVector != arg) {
485         m_yVector = arg;
486         emit yVectorChanged(arg);
487     }
488     if(perfLevel < Deformable)
489         reset();
490 }
491
492 void QSGImageParticle::setBloat(bool arg)
493 {
494     if (m_bloat != arg) {
495         m_bloat = arg;
496         emit bloatChanged(arg);
497     }
498     if(perfLevel < 9999)
499         reset();
500 }
501
502 void QSGImageParticle::reset()
503 {
504     QSGParticlePainter::reset();
505      m_pleaseReset = true;
506 }
507
508 void QSGImageParticle::createEngine()
509 {
510     if(m_spriteEngine)
511         delete m_spriteEngine;
512     if(m_sprites.count())
513         m_spriteEngine = new QSGSpriteEngine(m_sprites, this);
514     else
515         m_spriteEngine = 0;
516     reset();
517 }
518
519 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
520     { 0, 2, GL_FLOAT },             // Position
521     { 1, 2, GL_FLOAT },             // TexCoord
522     { 2, 4, GL_FLOAT },             // Data
523     { 3, 4, GL_FLOAT }             // Vectors
524 };
525
526 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
527 {
528     4, // Attribute Count
529     (2 + 2 + 4 + 4 ) * sizeof(float),
530     SimpleParticle_Attributes
531 };
532
533 static QSGGeometry::Attribute UltraParticle_Attributes[] = {
534     { 0, 2, GL_FLOAT },             // Position
535     { 1, 2, GL_FLOAT },             // TexCoord
536     { 2, 4, GL_FLOAT },             // Data
537     { 3, 4, GL_FLOAT },             // Vectors
538     { 4, 4, GL_UNSIGNED_BYTE },     // Colors
539     { 5, 4, GL_FLOAT },             // DeformationVectors
540     { 6, 3, GL_FLOAT },             // Rotation
541     { 7, 4, GL_FLOAT }              // Anim Data
542 };
543
544 static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
545 {
546     8, // Attribute Count
547     (2 + 2 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
548     UltraParticle_Attributes
549 };
550
551 QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode()
552 {
553     perfLevel = Simple;//TODO: Intermediate levels
554     QImage image = QImage(m_image_name.toLocalFile());
555     if (image.isNull()) {
556         printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
557         return 0;
558     }
559     int vCount = m_count * 4;
560     int iCount = m_count * 6;
561     qDebug() << "Simple Case";
562
563     QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
564     g->setDrawingMode(GL_TRIANGLES);
565
566     SimpleVertex *vertices = (SimpleVertex *) g->vertexData();
567     for (int p=0; p<m_count; ++p){
568         for(int i=0; i<4; i++){
569             vertices[i].x = m_data[p]->x;
570             vertices[i].y = m_data[p]->y;
571             vertices[i].t = m_data[p]->t;
572             vertices[i].size = m_data[p]->size;
573             vertices[i].endSize = m_data[p]->endSize;
574             vertices[i].sx = m_data[p]->sx;
575             vertices[i].sy = m_data[p]->sy;
576             vertices[i].ax = m_data[p]->ax;
577             vertices[i].ay = m_data[p]->ay;
578         }
579         //reload(p);
580         vertices[0].tx = 0;
581         vertices[0].ty = 0;
582
583         vertices[1].tx = 1;
584         vertices[1].ty = 0;
585
586         vertices[2].tx = 0;
587         vertices[2].ty = 1;
588
589         vertices[3].tx = 1;
590         vertices[3].ty = 1;
591
592         vertices += 4;
593     }
594
595     quint16 *indices = g->indexDataAsUShort();
596     for (int i=0; i<m_count; ++i) {
597         int o = i * 4;
598         indices[0] = o;
599         indices[1] = o + 1;
600         indices[2] = o + 2;
601         indices[3] = o + 1;
602         indices[4] = o + 3;
603         indices[5] = o + 2;
604         indices += 6;
605     }
606
607     m_node = new QSGGeometryNode();
608     m_node->setGeometry(g);
609
610     if (m_material) {
611         delete m_material;
612         m_material = 0;
613     }
614
615     m_material = new SimpleMaterial();
616     m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
617     m_material->texture->setFiltering(QSGTexture::Linear);
618     m_material->framecount = 1;
619     m_node->setMaterial(m_material);
620
621     m_last_particle = 0;
622     return m_node;
623 }
624
625 QSGGeometryNode* QSGImageParticle::buildParticleNode()
626 {
627     if (m_count * 4 > 0xffff) {
628         printf("UltraParticle: Too many particles... \n");//### Why is this here?
629         return 0;
630     }
631
632     if(m_count <= 0) {
633         qDebug() << "UltraParticle: Too few particles... \n";//XXX: Is now a vaild intermediate state...
634         return 0;
635     }
636
637     if(!m_sprites.count() && !m_bloat
638             && m_colortable_name.isEmpty()
639             && m_sizetable_name.isEmpty()
640             && m_opacitytable_name.isEmpty()
641             && !m_autoRotation
642             && !m_rotation && !m_rotationVariation
643             && !m_rotationSpeed && !m_rotationSpeedVariation
644             && !m_alphaVariation && m_alpha == 1.0
645             && !m_redVariation && !m_blueVariation && !m_greenVariation
646             && !m_color.isValid()
647             )
648         return buildSimpleParticleNode();
649     perfLevel = Sprites;//TODO: intermediate levels
650     if(!m_color.isValid())//But we're in colored level (or higher)
651         m_color = QColor(Qt::white);
652     qDebug() << "Complex Case";
653
654     QImage image;
655     if(m_sprites.count()){
656         if (!m_spriteEngine) {
657             qWarning() << "UltraParticle: No sprite engine...";
658             return 0;
659         }
660         image = m_spriteEngine->assembledImage();
661         if(image.isNull())//Warning is printed in engine
662             return 0;
663     }else{
664         image = QImage(m_image_name.toLocalFile());
665         if (image.isNull()) {
666             printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
667             return 0;
668         }
669     }
670
671     int vCount = m_count * 4;
672     int iCount = m_count * 6;
673
674     QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
675     g->setDrawingMode(GL_TRIANGLES);
676     m_node = new QSGGeometryNode();
677     m_node->setGeometry(g);
678
679     UltraVertex *vertices = (UltraVertex *) g->vertexData();
680     for (int p=0; p<m_count; ++p) {
681         reload(p);//reload gets geometry from node
682
683         vertices[0].tx = 0;
684         vertices[0].ty = 0;
685
686         vertices[1].tx = 1;
687         vertices[1].ty = 0;
688
689         vertices[2].tx = 0;
690         vertices[2].ty = 1;
691
692         vertices[3].tx = 1;
693         vertices[3].ty = 1;
694
695         vertices += 4;
696     }
697
698     quint16 *indices = g->indexDataAsUShort();
699     for (int i=0; i<m_count; ++i) {
700         int o = i * 4;
701         indices[0] = o;
702         indices[1] = o + 1;
703         indices[2] = o + 2;
704         indices[3] = o + 1;
705         indices[4] = o + 3;
706         indices[5] = o + 2;
707         indices += 6;
708     }
709
710     qFree(m_lastData);
711     if (m_material) {
712         delete m_material;
713         m_material = 0;
714     }
715
716     QImage colortable(m_colortable_name.toLocalFile());
717     QImage sizetable(m_sizetable_name.toLocalFile());
718     QImage opacitytable(m_opacitytable_name.toLocalFile());
719     m_material = new UltraMaterial();
720     if(colortable.isNull())
721         colortable = QImage(":defaultshaders/identitytable.png");
722     if(sizetable.isNull())
723         sizetable = QImage(":defaultshaders/identitytable.png");
724     if(opacitytable.isNull())
725         opacitytable = QImage(":defaultshaders/defaultFadeInOut.png");
726     Q_ASSERT(!colortable.isNull());
727     Q_ASSERT(!sizetable.isNull());
728     Q_ASSERT(!opacitytable.isNull());
729     m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
730     m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
731     m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
732
733     m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
734     m_material->texture->setFiltering(QSGTexture::Linear);
735
736     m_material->framecount = 1;
737     if(m_spriteEngine){
738         m_material->framecount = m_spriteEngine->maxFrames();
739         m_spriteEngine->setCount(m_count);
740     }
741
742     m_node->setMaterial(m_material);
743
744     m_last_particle = 0;
745
746     return m_node;
747 }
748
749 QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
750 {
751     if(m_pleaseReset){
752         if(m_node){
753             if(perfLevel == 1){
754                 m_lastCount = m_node->geometry()->vertexCount() / 4;
755                 m_lastData = qMalloc(m_lastCount*sizeof(SimpleVertices));
756                 memcpy(m_lastData, m_node->geometry()->vertexData(), m_lastCount * sizeof(SimpleVertices));//TODO: Multiple levels
757             }
758             m_lastLevel = perfLevel;
759             delete m_node;
760         }
761         if(m_material)
762             delete m_material;
763
764         m_node = 0;
765         m_material = 0;
766         m_pleaseReset = false;
767     }
768
769     if(m_system && m_system->isRunning())
770         prepareNextFrame();
771     if (m_node){
772         update();
773         m_node->markDirty(QSGNode::DirtyMaterial);
774     }
775
776     return m_node;
777 }
778
779 void QSGImageParticle::prepareNextFrame()
780 {
781     if (m_node == 0){//TODO: Staggered loading (as emitted)
782         m_node = buildParticleNode();
783         if(m_node == 0)
784             return;
785         qDebug() << "Feature level: " << perfLevel;
786     }
787     qint64 timeStamp = m_system->systemSync(this);
788
789     qreal time = timeStamp / 1000.;
790     m_material->timestamp = time;
791
792     //Advance State
793     if(m_spriteEngine){//perfLevel == Sprites?
794         m_material->animcount = m_spriteEngine->spriteCount();
795         UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
796         m_spriteEngine->updateSprites(timeStamp);
797         for(int i=0; i<m_count; i++){
798             UltraVertices &p = particles[i];
799             int curIdx = m_spriteEngine->spriteState(i);
800             if(curIdx != p.v1.animIdx){
801                 p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
802                 p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
803                 p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
804                 p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
805             }
806         }
807     }else{
808         m_material->animcount = 1;
809     }
810 }
811
812 void QSGImageParticle::reloadColor(const Color4ub &c, QSGParticleData* d)
813 {
814     d->color = c;
815     //TODO: get index for reload - or make function take an index
816 }
817
818 void QSGImageParticle::initialize(int idx)
819 {
820     Color4ub color;
821     qreal redVariation = m_color_variation + m_redVariation;
822     qreal greenVariation = m_color_variation + m_greenVariation;
823     qreal blueVariation = m_color_variation + m_blueVariation;
824     switch(perfLevel){//Fall-through is intended on all of them
825         case Sprites:
826             // Initial Sprite State
827             m_data[idx]->animT = m_data[idx]->t;
828             m_data[idx]->animIdx = 0;
829             if(m_spriteEngine){
830                 m_spriteEngine->startSprite(idx);
831                 m_data[idx]->frameCount = m_spriteEngine->spriteFrames(idx);
832                 m_data[idx]->frameDuration = m_spriteEngine->spriteDuration(idx);
833             }else{
834                 m_data[idx]->frameCount = 1;
835                 m_data[idx]->frameDuration = 9999;
836             }
837         case Tabled:
838         case Deformable:
839             //Initial Rotation
840             if(m_xVector){
841                 const QPointF &ret = m_xVector->sample(QPointF(m_data[idx]->x, m_data[idx]->y));
842                 m_data[idx]->xx = ret.x();
843                 m_data[idx]->xy = ret.y();
844             }
845             if(m_yVector){
846                 const QPointF &ret = m_yVector->sample(QPointF(m_data[idx]->x, m_data[idx]->y));
847                 m_data[idx]->yx = ret.x();
848                 m_data[idx]->yy = ret.y();
849             }
850             m_data[idx]->rotation =
851                     (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
852             m_data[idx]->rotationSpeed =
853                     (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
854             m_data[idx]->autoRotate = m_autoRotation?1.0:0.0;
855         case Colored:
856             //Color initialization
857             // Particle color
858             color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
859             color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
860             color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
861             color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
862             m_data[idx]->color = color;
863         default:
864             break;
865     }
866 }
867
868 void QSGImageParticle::reload(int idx)
869 {
870     if(!m_node)
871         return;
872
873     m_node->setFlag(QSGNode::OwnsGeometry, false);
874     UltraVertex *ultraVertices = (UltraVertex *) m_node->geometry()->vertexData();
875     SimpleVertex *simpleVertices = (SimpleVertex *) m_node->geometry()->vertexData();
876     switch(perfLevel){
877     case Sprites:
878         ultraVertices += idx*4;
879         for(int i=0; i<4; i++){
880             ultraVertices[i].x = m_data[idx]->x  - m_systemOffset.x();
881             ultraVertices[i].y = m_data[idx]->y  - m_systemOffset.y();
882             ultraVertices[i].t = m_data[idx]->t;
883             ultraVertices[i].lifeSpan = m_data[idx]->lifeSpan;
884             ultraVertices[i].size = m_data[idx]->size;
885             ultraVertices[i].endSize = m_data[idx]->endSize;
886             ultraVertices[i].sx = m_data[idx]->sx;
887             ultraVertices[i].sy = m_data[idx]->sy;
888             ultraVertices[i].ax = m_data[idx]->ax;
889             ultraVertices[i].ay = m_data[idx]->ay;
890             ultraVertices[i].xx = m_data[idx]->xx;
891             ultraVertices[i].xy = m_data[idx]->xy;
892             ultraVertices[i].yx = m_data[idx]->yx;
893             ultraVertices[i].yy = m_data[idx]->yy;
894             ultraVertices[i].rotation = m_data[idx]->rotation;
895             ultraVertices[i].rotationSpeed = m_data[idx]->rotationSpeed;
896             ultraVertices[i].autoRotate = m_data[idx]->autoRotate;
897             ultraVertices[i].animIdx = m_data[idx]->animIdx;
898             ultraVertices[i].frameDuration = m_data[idx]->frameDuration;
899             ultraVertices[i].frameCount = m_data[idx]->frameCount;
900             ultraVertices[i].animT = m_data[idx]->animT;
901             ultraVertices[i].color.r = m_data[idx]->color.r;
902             ultraVertices[i].color.g = m_data[idx]->color.g;
903             ultraVertices[i].color.b = m_data[idx]->color.b;
904             ultraVertices[i].color.a = m_data[idx]->color.a;
905         }
906         break;
907     case Tabled://TODO: Us
908     case Deformable:
909     case Colored:
910     case Simple:
911         simpleVertices += idx*4;
912         for(int i=0; i<4; i++){
913             simpleVertices[i].x = m_data[idx]->x - m_systemOffset.x();
914             simpleVertices[i].y = m_data[idx]->y - m_systemOffset.y();
915             simpleVertices[i].t = m_data[idx]->t;
916             simpleVertices[i].lifeSpan = m_data[idx]->lifeSpan;
917             simpleVertices[i].size = m_data[idx]->size;
918             simpleVertices[i].endSize = m_data[idx]->endSize;
919             simpleVertices[i].sx = m_data[idx]->sx;
920             simpleVertices[i].sy = m_data[idx]->sy;
921             simpleVertices[i].ax = m_data[idx]->ax;
922             simpleVertices[i].ay = m_data[idx]->ay;
923         }
924         break;
925     default:
926         break;
927     }
928
929     m_node->setFlag(QSGNode::OwnsGeometry, true);
930 }
931
932
933
934 QT_END_NAMESPACE