1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Declarative module of the Qt Toolkit.
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
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include <private/qsgcontext_p.h>
43 #include <private/qsgadaptationlayer_p.h>
45 #include <qsgtexturematerial.h>
46 #include <qsgtexture.h>
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>
57 const float CONV = 0.017453292519943295;
58 class UltraMaterial : public QSGMaterial
61 UltraMaterial(bool withSprites=false)
65 , usesSprites(withSprites)
67 setFlag(Blending, true);
78 virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
79 virtual QSGMaterialShader *createShader() const;
80 virtual int compare(const QSGMaterial *other) const
82 return this - static_cast<const UltraMaterial *>(other);
86 QSGTexture *colortable;
87 QSGTexture *sizetable;
88 QSGTexture *opacitytable;
95 class UltraMaterialData : public QSGMaterialShader
98 UltraMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
100 QFile vf(vertexFile ? vertexFile : ":defaultshaders/ultravertex.shader");
101 vf.open(QFile::ReadOnly);
102 m_vertex_code = vf.readAll();
104 QFile ff(fragmentFile ? fragmentFile : ":defaultshaders/ultrafragment.shader");
105 ff.open(QFile::ReadOnly);
106 m_fragment_code = ff.readAll();
108 Q_ASSERT(!m_vertex_code.isNull());
109 Q_ASSERT(!m_fragment_code.isNull());
113 QSGMaterialShader::deactivate();
115 for (int i=0; i<8; ++i) {
116 program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
120 virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
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);
127 state.context()->functions()->glActiveTexture(GL_TEXTURE2);
128 m->sizetable->bind();
129 program()->setUniformValue(m_sizetable_id, 2);
131 state.context()->functions()->glActiveTexture(GL_TEXTURE3);
132 m->opacitytable->bind();
133 program()->setUniformValue(m_opacitytable_id, 3);
135 state.context()->functions()->glActiveTexture(GL_TEXTURE0);//Investigate why this screws up Text{} if placed before 1
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);
143 if (state.isMatrixDirty())
144 program()->setUniformValue(m_matrix_id, state.combinedMatrix());
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");
158 virtual const char *vertexShader() const { return m_vertex_code.constData(); }
159 virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
161 virtual char const *const *attributeNames() const {
162 static const char *attr[] = {
176 virtual bool isColorTable() const { return false; }
183 int m_opacitytable_id;
187 QByteArray m_vertex_code;
188 QByteArray m_fragment_code;
190 static float chunkOfBytes[1024];
192 float UltraMaterialData::chunkOfBytes[1024];
194 QSGMaterialShader *UltraMaterial::createShader() const
196 if(usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
197 return new UltraMaterialData;
199 return new UltraMaterialData;
203 class SimpleMaterial : public UltraMaterial
205 virtual QSGMaterialShader *createShader() const;
206 virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
209 class SimpleMaterialData : public QSGMaterialShader
212 SimpleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
214 QFile vf(vertexFile ? vertexFile : ":defaultshaders/simplevertex.shader");
215 vf.open(QFile::ReadOnly);
216 m_vertex_code = vf.readAll();
218 QFile ff(fragmentFile ? fragmentFile : ":defaultshaders/simplefragment.shader");
219 ff.open(QFile::ReadOnly);
220 m_fragment_code = ff.readAll();
222 Q_ASSERT(!m_vertex_code.isNull());
223 Q_ASSERT(!m_fragment_code.isNull());
227 QSGMaterialShader::deactivate();
229 for (int i=0; i<8; ++i) {
230 program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
234 virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
236 UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
237 state.context()->functions()->glActiveTexture(GL_TEXTURE0);
240 program()->setUniformValue(m_opacity_id, state.opacity());
241 program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
243 if (state.isMatrixDirty())
244 program()->setUniformValue(m_matrix_id, state.combinedMatrix());
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");
253 virtual const char *vertexShader() const { return m_vertex_code.constData(); }
254 virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
256 virtual char const *const *attributeNames() const {
257 static const char *attr[] = {
267 virtual bool isColorTable() const { return false; }
273 QByteArray m_vertex_code;
274 QByteArray m_fragment_code;
276 static float chunkOfBytes[1024];
278 float SimpleMaterialData::chunkOfBytes[1024];
280 QSGMaterialShader *SimpleMaterial::createShader() const {
281 return new SimpleMaterialData;
284 QSGImageParticle::QSGImageParticle(QSGItem* parent)
285 : QSGParticlePainter(parent)
287 , m_color_variation(0.0)
290 , m_alphaVariation(0.0)
292 , m_redVariation(0.0)
293 , m_greenVariation(0.0)
294 , m_blueVariation(0.0)
296 , m_autoRotation(false)
299 , m_rotationVariation(0)
301 , m_rotationSpeedVariation(0)
305 , m_lastLevel(Unknown)
307 setFlag(ItemHasContents);
308 //TODO: Clean up defaults here and in custom
309 m_defaultUltra = new UltraVertices;
310 m_defaultSimple = new SimpleVertices;
311 UltraVertex *vertices = (UltraVertex *) m_defaultUltra;
312 SimpleVertex *vertices2 = (SimpleVertex *) m_defaultSimple;
313 for (int i=0; i<4; ++i) {
314 vertices2[i].x = vertices[i].x = 0;
315 vertices2[i].y = vertices[i].y = 0;
316 vertices2[i].t = vertices[i].t = -1;
317 vertices2[i].lifeSpan = vertices[i].lifeSpan = 0;
318 vertices2[i].size = vertices[i].size = 0;
319 vertices2[i].endSize = vertices[i].endSize = 0;
320 vertices2[i].sx = vertices[i].sx = 0;
321 vertices2[i].sy = vertices[i].sy = 0;
322 vertices2[i].ax = vertices[i].ax = 0;
323 vertices2[i].ay = vertices[i].ay = 0;
328 vertices[i].rotation = 0;
329 vertices[i].rotationSpeed = 0;
330 vertices[i].autoRotate = 0;
331 vertices[i].animIdx = -1;
332 vertices[i].frameDuration = 1;
333 vertices[i].frameCount = 0;
334 vertices[i].animT = -1;
335 vertices[i].color.r = 255;
336 vertices[i].color.g = 255;
337 vertices[i].color.b = 255;
338 vertices[i].color.a = 255;
366 QDeclarativeListProperty<QSGSprite> QSGImageParticle::sprites()
368 return QDeclarativeListProperty<QSGSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
371 void QSGImageParticle::setImage(const QUrl &image)
373 if (image == m_image_name)
375 m_image_name = image;
381 void QSGImageParticle::setColortable(const QUrl &table)
383 if (table == m_colortable_name)
385 m_colortable_name = table;
386 emit colortableChanged();
390 void QSGImageParticle::setSizetable(const QUrl &table)
392 if (table == m_sizetable_name)
394 m_sizetable_name = table;
395 emit sizetableChanged();
399 void QSGImageParticle::setOpacitytable(const QUrl &table)
401 if (table == m_opacitytable_name)
403 m_opacitytable_name = table;
404 emit opacitytableChanged();
408 void QSGImageParticle::setColor(const QColor &color)
410 if (color == m_color)
414 if(perfLevel < Coloured)
418 void QSGImageParticle::setColorVariation(qreal var)
420 if (var == m_color_variation)
422 m_color_variation = var;
423 emit colorVariationChanged();
424 if(perfLevel < Coloured)
428 void QSGImageParticle::setAlphaVariation(qreal arg)
430 if (m_alphaVariation != arg) {
431 m_alphaVariation = arg;
432 emit alphaVariationChanged(arg);
434 if(perfLevel < Coloured)
438 void QSGImageParticle::setAlpha(qreal arg)
440 if (m_alpha != arg) {
442 emit alphaChanged(arg);
444 if(perfLevel < Coloured)
448 void QSGImageParticle::setRedVariation(qreal arg)
450 if (m_redVariation != arg) {
451 m_redVariation = arg;
452 emit redVariationChanged(arg);
454 if(perfLevel < Coloured)
458 void QSGImageParticle::setGreenVariation(qreal arg)
460 if (m_greenVariation != arg) {
461 m_greenVariation = arg;
462 emit greenVariationChanged(arg);
464 if(perfLevel < Coloured)
468 void QSGImageParticle::setBlueVariation(qreal arg)
470 if (m_blueVariation != arg) {
471 m_blueVariation = arg;
472 emit blueVariationChanged(arg);
474 if(perfLevel < Coloured)
478 void QSGImageParticle::setRotation(qreal arg)
480 if (m_rotation != arg) {
482 emit rotationChanged(arg);
484 if(perfLevel < Deformable)
488 void QSGImageParticle::setRotationVariation(qreal arg)
490 if (m_rotationVariation != arg) {
491 m_rotationVariation = arg;
492 emit rotationVariationChanged(arg);
494 if(perfLevel < Deformable)
498 void QSGImageParticle::setRotationSpeed(qreal arg)
500 if (m_rotationSpeed != arg) {
501 m_rotationSpeed = arg;
502 emit rotationSpeedChanged(arg);
504 if(perfLevel < Deformable)
508 void QSGImageParticle::setRotationSpeedVariation(qreal arg)
510 if (m_rotationSpeedVariation != arg) {
511 m_rotationSpeedVariation = arg;
512 emit rotationSpeedVariationChanged(arg);
514 if(perfLevel < Deformable)
518 void QSGImageParticle::setAutoRotation(bool arg)
520 if (m_autoRotation != arg) {
521 m_autoRotation = arg;
522 emit autoRotationChanged(arg);
524 if(perfLevel < Deformable)
528 void QSGImageParticle::setXVector(QSGStochasticDirection* arg)
530 if (m_xVector != arg) {
532 emit xVectorChanged(arg);
534 if(perfLevel < Deformable)
538 void QSGImageParticle::setYVector(QSGStochasticDirection* arg)
540 if (m_yVector != arg) {
542 emit yVectorChanged(arg);
544 if(perfLevel < Deformable)
548 void QSGImageParticle::setBloat(bool arg)
550 if (m_bloat != arg) {
552 emit bloatChanged(arg);
558 void QSGImageParticle::reset()
560 QSGParticlePainter::reset();
561 m_pleaseReset = true;
564 void QSGImageParticle::createEngine()
567 delete m_spriteEngine;
568 if(m_sprites.count())
569 m_spriteEngine = new QSGSpriteEngine(m_sprites, this);
575 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
576 { 0, 2, GL_FLOAT }, // Position
577 { 1, 2, GL_FLOAT }, // TexCoord
578 { 2, 4, GL_FLOAT }, // Data
579 { 3, 4, GL_FLOAT } // Vectors
582 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
584 4, // Attribute Count
585 (2 + 2 + 4 + 4 ) * sizeof(float),
586 SimpleParticle_Attributes
589 static QSGGeometry::Attribute UltraParticle_Attributes[] = {
590 { 0, 2, GL_FLOAT }, // Position
591 { 1, 2, GL_FLOAT }, // TexCoord
592 { 2, 4, GL_FLOAT }, // Data
593 { 3, 4, GL_FLOAT }, // Vectors
594 { 4, 4, GL_UNSIGNED_BYTE }, // Colors
595 { 5, 4, GL_FLOAT }, // DeformationVectors
596 { 6, 3, GL_FLOAT }, // Rotation
597 { 7, 4, GL_FLOAT } // Anim Data
600 static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
602 8, // Attribute Count
603 (2 + 2 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
604 UltraParticle_Attributes
607 QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode()
609 perfLevel = Simple;//TODO: Intermediate levels
610 QImage image = QImage(m_image_name.toLocalFile());
611 if (image.isNull()) {
612 printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
615 int vCount = m_count * 4;
616 int iCount = m_count * 6;
617 qDebug() << "Simple Case";
619 QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
620 g->setDrawingMode(GL_TRIANGLES);
622 SimpleVertices *vertices = (SimpleVertices *) g->vertexData();
623 for (int p=0; p<m_count; ++p)
624 memcpy(vertices++, m_defaultSimple, sizeof(SimpleVertices));
626 quint16 *indices = g->indexDataAsUShort();
627 for (int i=0; i<m_count; ++i) {
643 m_material = new SimpleMaterial();
644 m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
645 m_material->texture->setFiltering(QSGTexture::Linear);
646 m_material->framecount = 1;
647 m_node = new QSGGeometryNode();
648 m_node->setGeometry(g);
649 m_node->setMaterial(m_material);
656 QSGGeometryNode* QSGImageParticle::buildParticleNode()
658 if (m_count * 4 > 0xffff) {
659 printf("UltraParticle: Too many particles... \n");//####Why is this here?
664 printf("UltraParticle: Too few particles... \n");
668 m_resizePending = false;
669 if(!m_sprites.count() && !m_bloat
670 && m_colortable_name.isEmpty()
671 && m_sizetable_name.isEmpty()
672 && m_opacitytable_name.isEmpty()
674 && !m_rotation && !m_rotationVariation
675 && !m_rotationSpeed && !m_rotationSpeedVariation
676 && !m_alphaVariation && m_alpha == 1.0
677 && !m_redVariation && !m_blueVariation && !m_greenVariation
678 && !m_color.isValid()
680 return buildSimpleParticleNode();
681 perfLevel = Sprites;//TODO: intermediate levels
682 if(!m_color.isValid())//But we're in colored level (or higher)
683 m_color = QColor(Qt::white);
684 qDebug() << "Complex Case";
687 if(m_sprites.count()){
688 if (!m_spriteEngine) {
689 qWarning() << "UltraParticle: No sprite engine...";
692 image = m_spriteEngine->assembledImage();
693 if(image.isNull())//Warning is printed in engine
696 image = QImage(m_image_name.toLocalFile());
697 if (image.isNull()) {
698 printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
703 int vCount = m_count * 4;
704 int iCount = m_count * 6;
706 QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
707 g->setDrawingMode(GL_TRIANGLES);
709 UltraVertex *vertices = (UltraVertex *) g->vertexData();
710 SimpleVertex *oldSimple = (SimpleVertex *) m_lastData;//TODO: Other levels
712 qDebug() << "Theta" << m_lastLevel << oldSimple[0].x << oldSimple[0].y << oldSimple[0].t;
713 for (int p=0; p<m_count; ++p) {
714 memcpy(vertices, m_defaultUltra, sizeof(UltraVertices));
715 if (m_lastLevel == 1 && m_lastCount > p) {//Transplant/IntermediateVertices?
716 for (int i=0; i<4; ++i) {
717 vertices[i].x = oldSimple[i].x;
718 vertices[i].y = oldSimple[i].y;
719 vertices[i].t = oldSimple[i].t;
720 vertices[i].lifeSpan = oldSimple[i].lifeSpan;
721 vertices[i].size = oldSimple[i].size;
722 vertices[i].endSize = oldSimple[i].endSize;
723 vertices[i].sx = oldSimple[i].sx;
724 vertices[i].sy = oldSimple[i].sy;
725 vertices[i].ax = oldSimple[i].ax;
726 vertices[i].ay = oldSimple[i].ay;
728 vertices[i].frameDuration = oldSimple[i].lifeSpan;
729 vertices[i].frameCount = 1;
730 vertices[i].animT = oldSimple[i].t;
739 quint16 *indices = g->indexDataAsUShort();//TODO: Speed gains by copying this over if count unchanged?
740 for (int i=0; i<m_count; ++i) {
757 QImage colortable(m_colortable_name.toLocalFile());
758 QImage sizetable(m_sizetable_name.toLocalFile());
759 QImage opacitytable(m_opacitytable_name.toLocalFile());
760 m_material = new UltraMaterial();
761 if(colortable.isNull())
762 colortable = QImage(":defaultshaders/identitytable.png");
763 if(sizetable.isNull())
764 sizetable = QImage(":defaultshaders/identitytable.png");
765 if(opacitytable.isNull())
766 opacitytable = QImage(":defaultshaders/defaultFadeInOut.png");
767 Q_ASSERT(!colortable.isNull());
768 Q_ASSERT(!sizetable.isNull());
769 Q_ASSERT(!opacitytable.isNull());
770 m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
771 m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
772 m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
774 m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
775 m_material->texture->setFiltering(QSGTexture::Linear);
777 m_material->framecount = 1;
779 m_material->framecount = m_spriteEngine->maxFrames();
780 m_spriteEngine->setCount(m_count);
783 m_node = new QSGGeometryNode();
784 m_node->setGeometry(g);
785 m_node->setMaterial(m_material);
792 void QSGImageParticle::resize(int oldCount, int newCount)
794 //If perf level changes at the same time as a resize, we reset instead of doing pending resize
801 reset();//TODO: Handle sprite resizeing (have to shuffle the engine too...)
805 if(!m_resizePending){
806 m_resizePendingUltra.resize(oldCount);
807 UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
808 for(int i=0; i<oldCount; i++)
809 m_resizePendingUltra[i] = &particles[i];
811 groupShuffle(m_resizePendingUltra, m_defaultUltra);
814 if(!m_resizePending){
815 m_resizePendingSimple.resize(oldCount);
816 SimpleVertices *particles = (SimpleVertices *) m_node->geometry()->vertexData();
817 for(int i=0; i<oldCount; i++)
818 m_resizePendingSimple[i] = &particles[i];
820 groupShuffle(m_resizePendingSimple, m_defaultSimple);
823 m_resizePending = true;
826 void QSGImageParticle::performPendingResize()
828 m_resizePending = false;
831 UltraVertices tmp1[m_count];//###More vast memcpys that will decrease performance
832 SimpleVertices tmp2[m_count];//###More vast memcpys that will decrease performance
838 Q_ASSERT(m_resizePendingUltra.size() == m_count);//XXX
839 for(int i=0; i<m_count; i++){
840 Q_ASSERT(m_resizePendingUltra[i]);
841 tmp1[i] = *m_resizePendingUltra[i];
843 m_node->setFlag(QSGNode::OwnsGeometry, false);
844 m_node->geometry()->allocate(m_count*4, m_count*6);
845 memcpy(m_node->geometry()->vertexData(), tmp1, sizeof(UltraVertices) * m_count);
846 m_node->setFlag(QSGNode::OwnsGeometry, true);
849 Q_ASSERT(m_resizePendingSimple.size() == m_count);//XXX
850 for(int i=0; i<m_count; i++)
851 tmp2[i] = *m_resizePendingSimple[i];
852 m_node->setFlag(QSGNode::OwnsGeometry, false);
853 m_node->geometry()->allocate(m_count*4, m_count*6);
854 memcpy(m_node->geometry()->vertexData(), tmp2, sizeof(SimpleVertices) * m_count);
855 m_node->setFlag(QSGNode::OwnsGeometry, true);
858 quint16 *indices = m_node->geometry()->indexDataAsUShort();
859 for (int i=0; i<m_count; ++i) {
869 m_node->setFlag(QSGNode::OwnsGeometry, true);
872 QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
878 m_lastCount = m_node->geometry()->vertexCount() / 4;
879 m_lastData = qMalloc(m_lastCount*sizeof(SimpleVertices));
880 memcpy(m_lastData, m_node->geometry()->vertexData(), m_lastCount * sizeof(SimpleVertices));//TODO: Multiple levels
882 m_lastLevel = perfLevel;
890 m_pleaseReset = false;
893 performPendingResize();
895 if(m_system && m_system->isRunning())
899 m_node->markDirty(QSGNode::DirtyMaterial);
905 void QSGImageParticle::prepareNextFrame()
907 if (m_node == 0){ //TODO: Staggered loading (as emitted)
908 m_node = buildParticleNode();
911 qDebug() << "Feature level: " << perfLevel;
913 qint64 timeStamp = m_system->systemSync(this);
915 qreal time = timeStamp / 1000.;
916 m_material->timestamp = time;
919 if(m_spriteEngine){//perfLevel == Sprites?
920 m_material->animcount = m_spriteEngine->spriteCount();
921 UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
922 m_spriteEngine->updateSprites(timeStamp);
923 for(int i=0; i<m_count; i++){
924 UltraVertices &p = particles[i];
925 int curIdx = m_spriteEngine->spriteState(i);
926 if(curIdx != p.v1.animIdx){
927 p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
928 p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
929 p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
930 p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
934 m_material->animcount = 1;
938 template <typename VT>
939 IntermediateVertices* transplant(IntermediateVertices* iv, VT &v)
940 {//Deliberate typemangling cast
941 iv->v1 = (UltraVertex*)&(v.v1);
942 iv->v2 = (UltraVertex*)&(v.v2);
943 iv->v3 = (UltraVertex*)&(v.v3);
944 iv->v4 = (UltraVertex*)&(v.v4);
948 IntermediateVertices* QSGImageParticle::fetchIntermediateVertices(int pos)
950 //Note that this class ruins typesafety for you. Maybe even thread safety.
951 //TODO: Something better, possibly with templates or inheritance
952 static IntermediateVertices iv;
957 sv = (SimpleVertices *) m_node->geometry()->vertexData();
958 return transplant(&iv, sv[pos]);
964 uv = (UltraVertices *) m_node->geometry()->vertexData();
965 return transplant(&iv,uv[pos]);
969 void QSGImageParticle::reloadColor(const Color4ub &c, QSGParticleData* d)
971 UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
972 int pos = particleTypeIndex(d);
973 UltraVertices &p = particles[pos];
974 p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
977 void QSGImageParticle::reload(QSGParticleData *d)
982 int pos = particleTypeIndex(d);
983 IntermediateVertices* p = fetchIntermediateVertices(pos);
985 //Perhaps we could be more efficient?
986 vertexCopy(*p->v1, d->pv);
987 vertexCopy(*p->v2, d->pv);
988 vertexCopy(*p->v3, d->pv);
989 vertexCopy(*p->v4, d->pv);
992 void QSGImageParticle::load(QSGParticleData *d)
997 int pos = particleTypeIndex(d);
998 IntermediateVertices* p = fetchIntermediateVertices(pos);//Remember this removes typesafety!
1000 qreal redVariation = m_color_variation + m_redVariation;
1001 qreal greenVariation = m_color_variation + m_greenVariation;
1002 qreal blueVariation = m_color_variation + m_blueVariation;
1003 switch(perfLevel){//Fall-through is intended on all of them
1005 // Initial Sprite State
1006 p->v1->animT = p->v2->animT = p->v3->animT = p->v4->animT = p->v1->t;
1007 p->v1->animIdx = p->v2->animIdx = p->v3->animIdx = p->v4->animIdx = 0;
1009 m_spriteEngine->startSprite(pos);
1010 p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = m_spriteEngine->spriteFrames(pos);
1011 p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = m_spriteEngine->spriteDuration(pos);
1013 p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = 1;
1014 p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = 9999;
1020 const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
1021 p->v1->xx = p->v2->xx = p->v3->xx = p->v4->xx = ret.x();
1022 p->v1->xy = p->v2->xy = p->v3->xy = p->v4->xy = ret.y();
1025 const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
1026 p->v1->yx = p->v2->yx = p->v3->yx = p->v4->yx = ret.x();
1027 p->v1->yy = p->v2->yy = p->v3->yy = p->v4->yy = ret.y();
1029 p->v1->rotation = p->v2->rotation = p->v3->rotation = p->v4->rotation =
1030 (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1031 p->v1->rotationSpeed = p->v2->rotationSpeed = p->v3->rotationSpeed = p->v4->rotationSpeed =
1032 (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1033 p->v1->autoRotate = p->v2->autoRotate = p->v3->autoRotate = p->v4->autoRotate = m_autoRotation?1.0:0.0;
1035 //Color initialization
1037 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1038 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1039 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1040 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1041 p->v1->color = p->v2->color = p->v3->color = p->v4->color = color;
1046 vertexCopy(*p->v1, d->pv);
1047 vertexCopy(*p->v2, d->pv);
1048 vertexCopy(*p->v3, d->pv);
1049 vertexCopy(*p->v4, d->pv);
1053 void QSGImageParticle::verticesUpgrade(void *prev, void *next)
1055 PerformanceLevel copyLevel = qMin(perfLevel, m_lastLevel);
1056 switch(perfLevel){//Intentional fall-through
1058 if(copyLevel >= Sprites)