Add BurstEmitter, and a simple render path for UltraParticles
[profile/ivi/qtdeclarative.git] / src / imports / particles / ultraparticle.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 "ultraparticle.h"
49 #include "particleemitter.h"
50 #include "spritestate.h"
51 #include "spriteengine.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 : ":resources/ultravertex.shader");
101         vf.open(QFile::ReadOnly);
102         m_vertex_code = vf.readAll();
103
104         QFile ff(fragmentFile ? fragmentFile : ":resources/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 };
207
208 class SimpleMaterialData : public QSGMaterialShader
209 {
210 public:
211     SimpleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
212     {
213         QFile vf(vertexFile ? vertexFile : ":resources/simplevertex.shader");
214         vf.open(QFile::ReadOnly);
215         m_vertex_code = vf.readAll();
216
217         QFile ff(fragmentFile ? fragmentFile : ":resources/simplefragment.shader");
218         ff.open(QFile::ReadOnly);
219         m_fragment_code = ff.readAll();
220
221         Q_ASSERT(!m_vertex_code.isNull());
222         Q_ASSERT(!m_fragment_code.isNull());
223     }
224
225     void deactivate() {
226         QSGMaterialShader::deactivate();
227
228         for (int i=0; i<8; ++i) {
229             program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
230         }
231     }
232
233     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
234     {
235         UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
236         state.context()->functions()->glActiveTexture(GL_TEXTURE0);
237         m->texture->bind();
238
239         program()->setUniformValue(m_opacity_id, state.opacity());
240         program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
241
242         if (state.isMatrixDirty())
243             program()->setUniformValue(m_matrix_id, state.combinedMatrix());
244     }
245
246     virtual void initialize() {
247         m_matrix_id = program()->uniformLocation("matrix");
248         m_opacity_id = program()->uniformLocation("opacity");
249         m_timestamp_id = program()->uniformLocation("timestamp");
250     }
251
252     virtual const char *vertexShader() const { return m_vertex_code.constData(); }
253     virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
254
255     virtual char const *const *attributeNames() const {
256         static const char *attr[] = {
257             "vPos",
258             "vTex",
259             "vData",
260             "vVec",
261             0
262         };
263         return attr;
264     }
265
266     virtual bool isColorTable() const { return false; }
267
268     int m_matrix_id;
269     int m_opacity_id;
270     int m_timestamp_id;
271
272     QByteArray m_vertex_code;
273     QByteArray m_fragment_code;
274
275     static float chunkOfBytes[1024];
276 };
277 float SimpleMaterialData::chunkOfBytes[1024];
278
279 QSGMaterialShader *SimpleMaterial::createShader() const {
280     return new SimpleMaterialData;
281 }
282
283 UltraParticle::UltraParticle(QSGItem* parent)
284     : ParticleType(parent)
285     , m_do_reset(false)
286     , m_color_variation(0.0)
287     , m_node(0)
288     , m_material(0)
289     , m_alphaVariation(0.0)
290     , m_alpha(1.0)
291     , m_redVariation(0.0)
292     , m_greenVariation(0.0)
293     , m_blueVariation(0.0)
294     , m_rotation(0)
295     , m_autoRotation(false)
296     , m_xVector(0)
297     , m_yVector(0)
298     , m_rotationVariation(0)
299     , m_rotationSpeed(0)
300     , m_rotationSpeedVariation(0)
301     , m_spriteEngine(0)
302     , m_bloat(false)
303     , perfLevel(Unknown)
304 {
305     setFlag(ItemHasContents);
306 }
307
308 QDeclarativeListProperty<SpriteState> UltraParticle::sprites()
309 {
310     return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
311 }
312
313 void UltraParticle::setImage(const QUrl &image)
314 {
315     if (image == m_image_name)
316         return;
317     m_image_name = image;
318     emit imageChanged();
319     reset();
320 }
321
322
323 void UltraParticle::setColortable(const QUrl &table)
324 {
325     if (table == m_colortable_name)
326         return;
327     m_colortable_name = table;
328     emit colortableChanged();
329     reset();
330 }
331
332 void UltraParticle::setSizetable(const QUrl &table)
333 {
334     if (table == m_sizetable_name)
335         return;
336     m_sizetable_name = table;
337     emit sizetableChanged();
338     reset();
339 }
340
341 void UltraParticle::setOpacitytable(const QUrl &table)
342 {
343     if (table == m_opacitytable_name)
344         return;
345     m_opacitytable_name = table;
346     emit opacitytableChanged();
347     reset();
348 }
349
350 void UltraParticle::setColor(const QColor &color)
351 {
352     if (color == m_color)
353         return;
354     m_color = color;
355     emit colorChanged();
356 }
357
358 void UltraParticle::setColorVariation(qreal var)
359 {
360     if (var == m_color_variation)
361         return;
362     m_color_variation = var;
363     emit colorVariationChanged();
364 }
365
366 void UltraParticle::setCount(int c)
367 {
368     ParticleType::setCount(c);
369     m_pleaseReset = true;
370 }
371
372 void UltraParticle::reset()
373 {
374     ParticleType::reset();
375      m_pleaseReset = true;
376 }
377
378 void UltraParticle::createEngine()
379 {
380     if(m_spriteEngine)
381         delete m_spriteEngine;
382     if(m_sprites.count())
383         m_spriteEngine = new SpriteEngine(m_sprites, this);
384     else
385         m_spriteEngine = 0;
386     reset();
387 }
388
389 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
390     { 0, 2, GL_FLOAT },             // Position
391     { 1, 2, GL_FLOAT },             // TexCoord
392     { 2, 4, GL_FLOAT },             // Data
393     { 3, 4, GL_FLOAT }             // Vectors
394 };
395
396 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
397 {
398     4, // Attribute Count
399     (2 + 2 + 4 + 4 ) * sizeof(float),
400     SimpleParticle_Attributes
401 };
402
403 static QSGGeometry::Attribute UltraParticle_Attributes[] = {
404     { 0, 2, GL_FLOAT },             // Position
405     { 1, 2, GL_FLOAT },             // TexCoord
406     { 2, 4, GL_FLOAT },             // Data
407     { 3, 4, GL_FLOAT },             // Vectors
408     { 4, 4, GL_UNSIGNED_BYTE },     // Colors
409     { 5, 4, GL_FLOAT },             // DeformationVectors
410     { 6, 3, GL_FLOAT },             // Rotation
411     { 7, 4, GL_FLOAT }              // Anim Data
412 };
413
414 static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
415 {
416     8, // Attribute Count
417     (2 + 2 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
418     UltraParticle_Attributes
419 };
420
421 QSGGeometryNode* UltraParticle::buildSimpleParticleNode()
422 {
423     perfLevel = Simple;//TODO: Intermediate levels
424     QImage image = QImage(m_image_name.toLocalFile());
425     if (image.isNull()) {
426         printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
427         return 0;
428     }
429     int vCount = m_count * 4;
430     int iCount = m_count * 6;
431     qDebug() << "Simple Case";
432
433     QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
434     g->setDrawingMode(GL_TRIANGLES);
435
436     SimpleVertex *vertices = (SimpleVertex *) g->vertexData();
437     for (int p=0; p<m_count; ++p) {
438         for (int i=0; i<4; ++i) {
439             vertices[i].x = 0;
440             vertices[i].y = 0;
441             vertices[i].t = -1;
442             vertices[i].lifeSpan = 0;
443             vertices[i].size = 0;
444             vertices[i].endSize = 0;
445             vertices[i].sx = 0;
446             vertices[i].sy = 0;
447             vertices[i].ax = 0;
448             vertices[i].ay = 0;
449         }
450
451         vertices[0].tx = 0;
452         vertices[0].ty = 0;
453
454         vertices[1].tx = 1;
455         vertices[1].ty = 0;
456
457         vertices[2].tx = 0;
458         vertices[2].ty = 1;
459
460         vertices[3].tx = 1;
461         vertices[3].ty = 1;
462
463         vertices += 4;
464     }
465
466     quint16 *indices = g->indexDataAsUShort();
467     for (int i=0; i<m_count; ++i) {
468         int o = i * 4;
469         indices[0] = o;
470         indices[1] = o + 1;
471         indices[2] = o + 2;
472         indices[3] = o + 1;
473         indices[4] = o + 3;
474         indices[5] = o + 2;
475         indices += 6;
476     }
477
478     if (m_material) {
479         delete m_material;
480         m_material = 0;
481     }
482
483     m_material = new SimpleMaterial();
484     m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
485     m_material->texture->setFiltering(QSGTexture::Linear);
486     m_material->framecount = 1;
487     m_node = new QSGGeometryNode();
488     m_node->setGeometry(g);
489     m_node->setMaterial(m_material);
490
491     m_last_particle = 0;
492
493     return m_node;
494 }
495
496 QSGGeometryNode* UltraParticle::buildParticleNode()
497 {
498     if (m_count * 4 > 0xffff) {
499         printf("UltraParticle: Too many particles... \n");//####Why is this here?
500         return 0;
501     }
502
503     if(m_count <= 0) {
504         printf("UltraParticle: Too few particles... \n");
505         return 0;
506     }
507
508     qDebug() << m_colortable_name.isEmpty() << !m_color.isValid();
509     if(!m_sprites.count() && !m_bloat
510             && m_colortable_name.isEmpty()
511             && m_sizetable_name.isEmpty()
512             && m_opacitytable_name.isEmpty()
513             && !m_rotation && !m_rotationVariation
514             && !m_rotationSpeed && !m_rotationSpeedVariation
515             && !m_alphaVariation && m_alpha == 1.0
516             && !m_redVariation && !m_blueVariation && !m_greenVariation
517             && !m_color.isValid()
518             )
519         return buildSimpleParticleNode();
520     perfLevel = Sprites;//TODO: intermediate levels
521     qDebug() << "Complex Case";
522
523     QImage image;
524     if(m_sprites.count()){
525         if (!m_spriteEngine) {
526             qWarning() << "UltraParticle: No sprite engine...";
527             return 0;
528         }
529         image = m_spriteEngine->assembledImage();
530         if(image.isNull())//Warning is printed in engine
531             return 0;
532     }else{
533         image = QImage(m_image_name.toLocalFile());
534         if (image.isNull()) {
535             printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
536             return 0;
537         }
538     }
539
540     int vCount = m_count * 4;
541     int iCount = m_count * 6;
542
543     QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
544     g->setDrawingMode(GL_TRIANGLES);
545
546     UltraVertex *vertices = (UltraVertex *) g->vertexData();
547     for (int p=0; p<m_count; ++p) {
548
549         for (int i=0; i<4; ++i) {
550             vertices[i].x = 0;
551             vertices[i].y = 0;
552             vertices[i].t = -1;
553             vertices[i].lifeSpan = 0;
554             vertices[i].size = 0;
555             vertices[i].endSize = 0;
556             vertices[i].sx = 0;
557             vertices[i].sy = 0;
558             vertices[i].ax = 0;
559             vertices[i].ay = 0;
560             vertices[i].xx = 1;
561             vertices[i].xy = 0;
562             vertices[i].yx = 0;
563             vertices[i].yy = 1;
564             vertices[i].rotation = 0;
565             vertices[i].rotationSpeed = 0;
566             vertices[i].autoRotate = 0;
567             vertices[i].animIdx = 0;
568             vertices[i].frameDuration = 1;
569             vertices[i].frameCount = 1;
570             vertices[i].animT = -1;
571         }
572
573         vertices[0].tx = 0;
574         vertices[0].ty = 0;
575
576         vertices[1].tx = 1;
577         vertices[1].ty = 0;
578
579         vertices[2].tx = 0;
580         vertices[2].ty = 1;
581
582         vertices[3].tx = 1;
583         vertices[3].ty = 1;
584
585         vertices += 4;
586     }
587
588     quint16 *indices = g->indexDataAsUShort();
589     for (int i=0; i<m_count; ++i) {
590         int o = i * 4;
591         indices[0] = o;
592         indices[1] = o + 1;
593         indices[2] = o + 2;
594         indices[3] = o + 1;
595         indices[4] = o + 3;
596         indices[5] = o + 2;
597         indices += 6;
598     }
599
600     if (m_material) {
601         delete m_material;
602         m_material = 0;
603     }
604
605     QImage colortable(m_colortable_name.toLocalFile());
606     QImage sizetable(m_sizetable_name.toLocalFile());
607     QImage opacitytable(m_opacitytable_name.toLocalFile());
608     m_material = new UltraMaterial();
609     if(colortable.isNull())
610         colortable = QImage(":resources/identitytable.png");
611     if(sizetable.isNull())
612         sizetable = QImage(":resources/identitytable.png");
613     if(opacitytable.isNull())
614         opacitytable = QImage(":resources/defaultFadeInOut.png");
615     Q_ASSERT(!colortable.isNull());
616     Q_ASSERT(!sizetable.isNull());
617     Q_ASSERT(!opacitytable.isNull());
618     m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
619     m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
620     m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
621
622     m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
623     m_material->texture->setFiltering(QSGTexture::Linear);
624
625     m_material->framecount = 1;
626     if(m_spriteEngine){
627         m_material->framecount = m_spriteEngine->maxFrames();
628         m_spriteEngine->setCount(m_count);
629     }
630
631     m_node = new QSGGeometryNode();
632     m_node->setGeometry(g);
633     m_node->setMaterial(m_material);
634
635     m_last_particle = 0;
636
637     return m_node;
638 }
639
640 QSGNode *UltraParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
641 {
642     if(m_pleaseReset){
643         if(m_node)
644             delete m_node;
645         if(m_material)
646             delete m_material;
647
648         m_node = 0;
649         m_material = 0;
650         m_pleaseReset = false;
651     }
652
653     if(m_system && m_system->isRunning())
654         prepareNextFrame();
655     if (m_node){
656         update();
657         m_node->markDirty(QSGNode::DirtyMaterial);
658     }
659
660     return m_node;
661 }
662
663 void UltraParticle::prepareNextFrame()
664 {
665     if (m_node == 0){    //TODO: Staggered loading (as emitted)
666         m_node = buildParticleNode();
667         if(m_node == 0)
668             return;
669         qDebug() << "Feature level: " << perfLevel;
670     }
671     qint64 timeStamp = m_system->systemSync(this);
672
673     qreal time = timeStamp / 1000.;
674     m_material->timestamp = time;
675
676     //Advance State
677     if(m_spriteEngine){//perfLevel == Sprites?
678         m_material->animcount = m_spriteEngine->stateCount();
679         UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
680         m_spriteEngine->updateSprites(timeStamp);
681         for(int i=0; i<m_count; i++){
682             UltraVertices &p = particles[i];
683             int curIdx = m_spriteEngine->spriteState(i);
684             if(curIdx != p.v1.animIdx){
685                 p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
686                 p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
687                 p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->state(curIdx)->frames();
688                 p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
689             }
690         }
691     }else{
692         m_material->animcount = 1;
693     }
694 }
695
696 template <typename VT>
697 IntermediateVertices* transplant(IntermediateVertices* iv, VT &v)
698 {//Deliberate typemangling cast
699     iv->v1 = (UltraVertex*)&(v.v1);
700     iv->v2 = (UltraVertex*)&(v.v2);
701     iv->v3 = (UltraVertex*)&(v.v3);
702     iv->v4 = (UltraVertex*)&(v.v4);
703     return iv;
704 }
705
706 IntermediateVertices* UltraParticle::fetchIntermediateVertices(int pos)
707 {
708     //Note that this class ruins typesafety for you. Maybe even thread safety.
709     //TODO: Something better, possibly with templates or inheritance
710     static IntermediateVertices iv;
711     SimpleVertices *sv;
712     UltraVertices *uv;
713     switch(perfLevel){
714         case Simple:
715             sv = (SimpleVertices *) m_node->geometry()->vertexData();
716             return transplant(&iv, sv[pos]);
717         case Coloured:
718         case Deformable:
719         case Tabled:
720         case Sprites:
721         default:
722             uv = (UltraVertices *) m_node->geometry()->vertexData();
723             return transplant(&iv,uv[pos]);
724     }
725 }
726
727 void UltraParticle::reloadColor(const Color4ub &c, ParticleData* d)
728 {
729     UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
730     int pos = particleTypeIndex(d);
731     UltraVertices &p = particles[pos];
732     p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
733 }
734
735 /*Repalced by superclass templated function
736 void UltraParticle::vertexCopy(UltraVertex &b,const ParticleVertex& a)
737 {
738     b.x = a.x - m_systemOffset.x();
739     b.y = a.y - m_systemOffset.y();
740     b.t = a.t;
741     b.lifeSpan = a.lifeSpan;
742     b.size = a.size;
743     b.endSize = a.endSize;
744     b.sx = a.sx;
745     b.sy = a.sy;
746     b.ax = a.ax;
747     b.ay = a.ay;
748 }
749 */
750
751
752 void UltraParticle::reload(ParticleData *d)
753 {
754     if (m_node == 0)
755         return;
756
757     int pos = particleTypeIndex(d);
758     IntermediateVertices* p = fetchIntermediateVertices(pos);
759
760     //Perhaps we could be more efficient?
761     vertexCopy(*p->v1, d->pv);
762     vertexCopy(*p->v2, d->pv);
763     vertexCopy(*p->v3, d->pv);
764     vertexCopy(*p->v4, d->pv);
765 }
766
767 void UltraParticle::load(ParticleData *d)
768 {
769     if (m_node == 0)
770         return;
771
772     int pos = particleTypeIndex(d);
773     IntermediateVertices* p = fetchIntermediateVertices(pos);//Remember this removes typesafety!
774     Color4ub color;
775     qreal redVariation = m_color_variation + m_redVariation;
776     qreal greenVariation = m_color_variation + m_greenVariation;
777     qreal blueVariation = m_color_variation + m_blueVariation;
778     switch(perfLevel){//Fall-through is intended on all of them
779         case Sprites:
780             // Initial Sprite State
781             p->v1->animT = p->v2->animT = p->v3->animT = p->v4->animT = p->v1->t;
782             p->v1->animIdx = p->v2->animIdx = p->v3->animIdx = p->v4->animIdx = 0;
783             if(m_spriteEngine){
784                 SpriteState* state = m_spriteEngine->state(0);
785                 p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = state->frames();
786                 p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = state->duration();
787                 m_spriteEngine->startSprite(pos);
788             }else{
789                 p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = 1;
790                 p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = 9999;
791             }
792         case Tabled:
793         case Deformable:
794             //Initial Rotation
795             if(m_xVector){
796                 const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
797                 p->v1->xx = p->v2->xx = p->v3->xx = p->v4->xx = ret.x();
798                 p->v1->xy = p->v2->xy = p->v3->xy = p->v4->xy = ret.y();
799             }
800             if(m_yVector){
801                 const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
802                 p->v1->yx = p->v2->yx = p->v3->yx = p->v4->yx = ret.x();
803                 p->v1->yy = p->v2->yy = p->v3->yy = p->v4->yy = ret.y();
804             }
805             p->v1->rotation = p->v2->rotation = p->v3->rotation = p->v4->rotation =
806                     (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
807             p->v1->rotationSpeed = p->v2->rotationSpeed = p->v3->rotationSpeed = p->v4->rotationSpeed =
808                     (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
809             p->v1->autoRotate = p->v2->autoRotate = p->v3->autoRotate = p->v4->autoRotate = m_autoRotation?1.0:0.0;
810         case Coloured:
811             //Color initialization
812             // Particle color
813             color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
814             color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
815             color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
816             color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
817             p->v1->color = p->v2->color = p->v3->color = p->v4->color = color;
818         default:
819             break;
820     }
821
822     vertexCopy(*p->v1, d->pv);
823     vertexCopy(*p->v2, d->pv);
824     vertexCopy(*p->v3, d->pv);
825     vertexCopy(*p->v4, d->pv);
826 }
827
828 QT_END_NAMESPACE