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 ** 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.
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.
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.
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.
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 <QOpenGLFunctions>
53 #include <qsgengine.h>
54 #include <private/qsgtexture_p.h>
57 //###Switch to define later, for now user-friendly (no compilation) debugging is worth it
58 DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG)
60 #ifndef QT_OPENGL_ES_2
61 #define SHADER_DEFINES "#version 120\n"
63 #define SHADER_DEFINES ""
66 //TODO: Make it larger on desktop? Requires fixing up shader code with the same define
67 #define UNIFORM_ARRAY_SIZE 64
69 const qreal CONV = 0.017453292519943295;
70 class ImageMaterialData
74 : texture(0), colorTable(0)
83 QSGTexture *colorTable;
84 float sizeTable[UNIFORM_ARRAY_SIZE];
85 float opacityTable[UNIFORM_ARRAY_SIZE];
92 //TODO: Move shaders inline once they've stablilized
93 class TabledMaterialData : public ImageMaterialData {};
94 class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
96 QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
101 QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
102 vf.open(QFile::ReadOnly);
103 m_vertex_code = QByteArray(SHADER_DEFINES)
104 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
107 QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
108 ff.open(QFile::ReadOnly);
109 m_fragment_code = QByteArray(SHADER_DEFINES)
110 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
113 Q_ASSERT(!m_vertex_code.isNull());
114 Q_ASSERT(!m_fragment_code.isNull());
117 const char *vertexShader() const { return m_vertex_code.constData(); }
118 const char *fragmentShader() const { return m_fragment_code.constData(); }
120 QList<QByteArray> attributes() const {
121 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
122 << "vColor" << "vDeformVec" << "vRotation";
126 QSGSimpleMaterialShader<TabledMaterialData>::initialize();
128 program()->setUniformValue("texture", 0);
129 program()->setUniformValue("colortable", 1);
130 glFuncs = QOpenGLContext::currentContext()->functions();
131 m_timestamp_id = program()->uniformLocation("timestamp");
132 m_entry_id = program()->uniformLocation("entry");
133 m_sizetable_id = program()->uniformLocation("sizetable");
134 m_opacitytable_id = program()->uniformLocation("opacitytable");
137 void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
138 glFuncs->glActiveTexture(GL_TEXTURE1);
139 d->colorTable->bind();
141 glFuncs->glActiveTexture(GL_TEXTURE0);
144 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
145 program()->setUniformValue(m_entry_id, (float) d->entry);
146 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1);
147 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
153 int m_opacitytable_id;
154 QByteArray m_vertex_code;
155 QByteArray m_fragment_code;
156 QOpenGLFunctions* glFuncs;
159 class DeformableMaterialData : public ImageMaterialData {};
160 class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData>
162 QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData)
167 QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
168 vf.open(QFile::ReadOnly);
169 m_vertex_code = QByteArray(SHADER_DEFINES)
170 + QByteArray("#define DEFORM\n#define COLOR\n")
173 QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
174 ff.open(QFile::ReadOnly);
175 m_fragment_code = QByteArray(SHADER_DEFINES)
176 + QByteArray("#define DEFORM\n#define COLOR\n")
179 Q_ASSERT(!m_vertex_code.isNull());
180 Q_ASSERT(!m_fragment_code.isNull());
183 const char *vertexShader() const { return m_vertex_code.constData(); }
184 const char *fragmentShader() const { return m_fragment_code.constData(); }
186 QList<QByteArray> attributes() const {
187 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
188 << "vColor" << "vDeformVec" << "vRotation";
192 QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
194 program()->setUniformValue("texture", 0);
195 glFuncs = QOpenGLContext::currentContext()->functions();
196 m_timestamp_id = program()->uniformLocation("timestamp");
197 m_entry_id = program()->uniformLocation("entry");
200 void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) {
201 glFuncs->glActiveTexture(GL_TEXTURE0);
204 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
205 program()->setUniformValue(m_entry_id, (float) d->entry);
210 QByteArray m_vertex_code;
211 QByteArray m_fragment_code;
212 QOpenGLFunctions* glFuncs;
215 class SpriteMaterialData : public ImageMaterialData {};
216 class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
218 QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData)
223 QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
224 vf.open(QFile::ReadOnly);
225 m_vertex_code = QByteArray(SHADER_DEFINES)
226 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
229 QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
230 ff.open(QFile::ReadOnly);
231 m_fragment_code = QByteArray(SHADER_DEFINES)
232 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
235 Q_ASSERT(!m_vertex_code.isNull());
236 Q_ASSERT(!m_fragment_code.isNull());
239 const char *vertexShader() const { return m_vertex_code.constData(); }
240 const char *fragmentShader() const { return m_fragment_code.constData(); }
242 QList<QByteArray> attributes() const {
243 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
244 << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
248 QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
250 program()->setUniformValue("texture", 0);
251 program()->setUniformValue("colortable", 1);
252 glFuncs = QOpenGLContext::currentContext()->functions();
253 m_timestamp_id = program()->uniformLocation("timestamp");
254 m_animsize_id = program()->uniformLocation("animSheetSize");
255 m_entry_id = program()->uniformLocation("entry");
256 m_sizetable_id = program()->uniformLocation("sizetable");
257 m_opacitytable_id = program()->uniformLocation("opacitytable");
260 void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) {
261 glFuncs->glActiveTexture(GL_TEXTURE1);
262 d->colorTable->bind();
264 // make sure we end by setting GL_TEXTURE0 as active texture
265 glFuncs->glActiveTexture(GL_TEXTURE0);
268 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
269 program()->setUniformValue(m_animsize_id, d->animSheetSize);
270 program()->setUniformValue(m_entry_id, (float) d->entry);
271 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, 64, 1);
272 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
279 int m_opacitytable_id;
280 QByteArray m_vertex_code;
281 QByteArray m_fragment_code;
282 QOpenGLFunctions* glFuncs;
285 class ColoredMaterialData : public ImageMaterialData {};
286 class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
288 QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData)
293 QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
294 vf.open(QFile::ReadOnly);
295 m_vertex_code = QByteArray(SHADER_DEFINES)
296 + QByteArray("#define COLOR\n")
299 QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
300 ff.open(QFile::ReadOnly);
301 m_fragment_code = QByteArray(SHADER_DEFINES)
302 + QByteArray("#define COLOR\n")
305 Q_ASSERT(!m_vertex_code.isNull());
306 Q_ASSERT(!m_fragment_code.isNull());
309 const char *vertexShader() const { return m_vertex_code.constData(); }
310 const char *fragmentShader() const { return m_fragment_code.constData(); }
313 QSGSimpleMaterialShader<ColoredMaterialData>::activate();
314 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
315 glEnable(GL_POINT_SPRITE);
316 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
321 QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
322 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
323 glDisable(GL_POINT_SPRITE);
324 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
328 QList<QByteArray> attributes() const {
329 return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
333 QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
335 program()->setUniformValue("texture", 0);
336 glFuncs = QOpenGLContext::currentContext()->functions();
337 m_timestamp_id = program()->uniformLocation("timestamp");
338 m_entry_id = program()->uniformLocation("entry");
341 void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) {
342 glFuncs->glActiveTexture(GL_TEXTURE0);
345 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
346 program()->setUniformValue(m_entry_id, (float) d->entry);
351 QByteArray m_vertex_code;
352 QByteArray m_fragment_code;
353 QOpenGLFunctions* glFuncs;
356 class SimpleMaterialData : public ImageMaterialData {};
357 class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
359 QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData)
364 QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
365 vf.open(QFile::ReadOnly);
366 m_vertex_code = QByteArray(SHADER_DEFINES)
369 QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
370 ff.open(QFile::ReadOnly);
371 m_fragment_code = QByteArray(SHADER_DEFINES)
374 Q_ASSERT(!m_vertex_code.isNull());
375 Q_ASSERT(!m_fragment_code.isNull());
378 const char *vertexShader() const { return m_vertex_code.constData(); }
379 const char *fragmentShader() const { return m_fragment_code.constData(); }
382 QSGSimpleMaterialShader<SimpleMaterialData>::activate();
383 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
384 glEnable(GL_POINT_SPRITE);
385 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
390 QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
391 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
392 glDisable(GL_POINT_SPRITE);
393 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
397 QList<QByteArray> attributes() const {
398 return QList<QByteArray>() << "vPos" << "vData" << "vVec";
402 QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
404 program()->setUniformValue("texture", 0);
405 glFuncs = QOpenGLContext::currentContext()->functions();
406 m_timestamp_id = program()->uniformLocation("timestamp");
407 m_entry_id = program()->uniformLocation("entry");
410 void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) {
411 glFuncs->glActiveTexture(GL_TEXTURE0);
414 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
415 program()->setUniformValue(m_entry_id, (float) d->entry);
420 QByteArray m_vertex_code;
421 QByteArray m_fragment_code;
422 QOpenGLFunctions* glFuncs;
425 void fillUniformArrayFromImage(float* array, const QImage& img, int size)
428 for (int i=0; i<size; i++)
432 QImage scaled = img.scaled(size,1);
433 for (int i=0; i<size; i++)
434 array[i] = qAlpha(scaled.pixel(i,0))/255.0;
438 \qmlclass ImageParticle QSGImageParticle
439 \inqmlmodule QtQuick.Particles 2
440 \inherits ParticlePainter
441 \brief The ImageParticle element visualizes logical particles using an image
443 This element renders a logical particle as an image. The image can be
448 \o a sprite-based animation
451 ImageParticles implictly share data on particles if multiple ImageParticles are painting
452 the same logical particle group. This is broken down along the four capabilities listed
453 above. So if one ImageParticle defines data for rendering the particles in one of those
454 capabilities, and the other does not, then both will draw the particles the same in that
455 aspect automatically. This is primarily useful when there is some random variation on
456 the particle which is supposed to stay with it when switching painters. If both ImageParticles
457 define how they should appear for that aspect, they diverge and each appears as it is defined.
459 This sharing of data happens behind the scenes based off of whether properties were implicitly or explicitly
460 set. One drawback of the current implementation is that it is only possible to reset the capabilities as a whole.
461 So if you explicity set an attribute affecting color, such as redVariation, and then reset it (by setting redVariation
462 to undefined), all color data will be reset and it will begin to have an implicit value of any shared color from
463 other ImageParticles.
466 \qmlproperty url QtQuick.Particles2::ImageParticle::source
468 The source image to be used.
470 If the image is a sprite animation, use the sprite property instead.
473 \qmlproperty list<Sprite> QtQuick.Particles2::ImageParticle::sprites
475 The sprite or sprites used to draw this particle.
478 \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable
480 An image whose color will be used as a 1D texture to determine color over life. E.g. when
481 the particle is halfway through its lifetime, it will have the color specified halfway
484 This color is blended with the color property and the color of the source image.
487 \qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
489 An image whose opacity will be used as a 1D texture to determine size over life.
491 This property is expected to be removed shortly, in favor of custom easing curves to determine size over life.
494 \qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
496 An image whose opacity will be used as a 1D texture to determine size over life.
498 This property is expected to be removed shortly, in favor of custom easing curves to determine opacity over life.
501 \qmlproperty color QtQuick.Particles2::ImageParticle::color
503 If a color is specified, the provided image will be colorized with it.
505 Default is white (no change).
508 \qmlproperty real QtQuick.Particles2::ImageParticle::colorVariation
510 This number represents the color variation applied to individual particles.
511 Setting colorVariation is the same as setting redVariation, greenVariation,
512 and blueVariation to the same number.
514 Each channel can vary between particle by up to colorVariation from its usual color.
516 Color is measured, per channel, from 0.0 to 1.0.
521 \qmlproperty real QtQuick.Particles2::ImageParticle::redVariation
522 The variation in the red color channel between particles.
524 Color is measured, per channel, from 0.0 to 1.0.
529 \qmlproperty real QtQuick.Particles2::ImageParticle::greenVariation
530 The variation in the green color channel between particles.
532 Color is measured, per channel, from 0.0 to 1.0.
537 \qmlproperty real QtQuick.Particles2::ImageParticle::blueVariation
538 The variation in the blue color channel between particles.
540 Color is measured, per channel, from 0.0 to 1.0.
545 \qmlproperty real QtQuick.Particles2::ImageParticle::alpha
546 An alpha to be applied to the image. This value is multiplied by the value in
547 the image, and the value in the color property.
549 Particles have additive blending, so lower alpha on single particles leads
550 to stronger effects when multiple particles overlap.
552 Alpha is measured from 0.0 to 1.0.
557 \qmlproperty real QtQuick.Particles2::ImageParticle::alphaVariation
558 The variation in the alpha channel between particles.
560 Alpha is measured from 0.0 to 1.0.
565 \qmlproperty real QtQuick.Particles2::ImageParticle::rotation
567 If set the image will be rotated by this many degrees before it is drawn.
569 The particle coordinates are not transformed.
572 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationVariation
574 If set the rotation of individual particles will vary by up to this much
579 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeed
581 If set particles will rotate at this speed in degrees/second.
584 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeedVariation
586 If set the rotationSpeed of individual particles will vary by up to this much
591 \qmlproperty bool QtQuick.Particles2::ImageParticle::autoRotation
593 If set to true then a rotation will be applied on top of the particles rotation, so
594 that it faces the direction of travel. So to face away from the direction of travel,
595 set autoRotation to true and rotation to 180.
600 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::xVector
602 Allows you to deform the particle image when drawn. The rectangular image will
603 be deformed so that the horizontal sides are in the shape of this vector instead
607 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::yVector
609 Allows you to deform the particle image when drawn. The rectangular image will
610 be deformed so that the vertical sides are in the shape of this vector instead
614 \qmlproperty EntryEffect QtQuick.Particles2::ImageParticle::entryEffect
616 This property provides basic and cheap entrance and exit effects for the particles.
617 For fine-grained control, see sizeTable and opacityTable.
619 Acceptable values are
621 \o None: Particles just appear and disappear.
622 \o Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
623 \o Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end.
626 Default value is Fade.
629 \qmlproperty bool QtQuick.Particles2::ImageParticle::spritesInterpolate
631 If set to true, sprite particles will interpolate between sprite frames each rendered frame, making
632 the sprites look smoother.
638 QSGImageParticle::QSGImageParticle(QSGItem* parent)
639 : QSGParticlePainter(parent)
640 , m_color_variation(0.0)
643 , m_alphaVariation(0.0)
645 , m_redVariation(0.0)
646 , m_greenVariation(0.0)
647 , m_blueVariation(0.0)
649 , m_rotationVariation(0)
651 , m_rotationSpeedVariation(0)
652 , m_autoRotation(false)
656 , m_spritesInterpolate(true)
657 , m_explicitColor(false)
658 , m_explicitRotation(false)
659 , m_explicitDeformation(false)
660 , m_explicitAnimation(false)
663 , m_lastLevel(Unknown)
665 , m_entryEffect(Fade)
667 setFlag(ItemHasContents);
668 m_debugMode = qmlParticlesDebug();
671 QSGImageParticle::~QSGImageParticle()
675 QDeclarativeListProperty<QSGSprite> QSGImageParticle::sprites()
677 return QDeclarativeListProperty<QSGSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
680 void QSGImageParticle::setImage(const QUrl &image)
682 if (image == m_image_name)
684 m_image_name = image;
690 void QSGImageParticle::setColortable(const QUrl &table)
692 if (table == m_colortable_name)
694 m_colortable_name = table;
695 emit colortableChanged();
699 void QSGImageParticle::setSizetable(const QUrl &table)
701 if (table == m_sizetable_name)
703 m_sizetable_name = table;
704 emit sizetableChanged();
708 void QSGImageParticle::setOpacitytable(const QUrl &table)
710 if (table == m_opacitytable_name)
712 m_opacitytable_name = table;
713 emit opacitytableChanged();
717 void QSGImageParticle::setColor(const QColor &color)
719 if (color == m_color)
723 m_explicitColor = true;
724 if (perfLevel < Colored)
728 void QSGImageParticle::setColorVariation(qreal var)
730 if (var == m_color_variation)
732 m_color_variation = var;
733 emit colorVariationChanged();
734 m_explicitColor = true;
735 if (perfLevel < Colored)
739 void QSGImageParticle::setAlphaVariation(qreal arg)
741 if (m_alphaVariation != arg) {
742 m_alphaVariation = arg;
743 emit alphaVariationChanged(arg);
745 m_explicitColor = true;
746 if (perfLevel < Colored)
750 void QSGImageParticle::setAlpha(qreal arg)
752 if (m_alpha != arg) {
754 emit alphaChanged(arg);
756 m_explicitColor = true;
757 if (perfLevel < Colored)
761 void QSGImageParticle::setRedVariation(qreal arg)
763 if (m_redVariation != arg) {
764 m_redVariation = arg;
765 emit redVariationChanged(arg);
767 m_explicitColor = true;
768 if (perfLevel < Colored)
772 void QSGImageParticle::setGreenVariation(qreal arg)
774 if (m_greenVariation != arg) {
775 m_greenVariation = arg;
776 emit greenVariationChanged(arg);
778 m_explicitColor = true;
779 if (perfLevel < Colored)
783 void QSGImageParticle::setBlueVariation(qreal arg)
785 if (m_blueVariation != arg) {
786 m_blueVariation = arg;
787 emit blueVariationChanged(arg);
789 m_explicitColor = true;
790 if (perfLevel < Colored)
794 void QSGImageParticle::setRotation(qreal arg)
796 if (m_rotation != arg) {
798 emit rotationChanged(arg);
800 m_explicitRotation = true;
801 if (perfLevel < Deformable)
805 void QSGImageParticle::setRotationVariation(qreal arg)
807 if (m_rotationVariation != arg) {
808 m_rotationVariation = arg;
809 emit rotationVariationChanged(arg);
811 m_explicitRotation = true;
812 if (perfLevel < Deformable)
816 void QSGImageParticle::setRotationSpeed(qreal arg)
818 if (m_rotationSpeed != arg) {
819 m_rotationSpeed = arg;
820 emit rotationSpeedChanged(arg);
822 m_explicitRotation = true;
823 if (perfLevel < Deformable)
827 void QSGImageParticle::setRotationSpeedVariation(qreal arg)
829 if (m_rotationSpeedVariation != arg) {
830 m_rotationSpeedVariation = arg;
831 emit rotationSpeedVariationChanged(arg);
833 m_explicitRotation = true;
834 if (perfLevel < Deformable)
838 void QSGImageParticle::setAutoRotation(bool arg)
840 if (m_autoRotation != arg) {
841 m_autoRotation = arg;
842 emit autoRotationChanged(arg);
844 m_explicitRotation = true;
845 if (perfLevel < Deformable)
849 void QSGImageParticle::setXVector(QSGDirection* arg)
851 if (m_xVector != arg) {
853 emit xVectorChanged(arg);
855 m_explicitDeformation = true;
856 if (perfLevel < Deformable)
860 void QSGImageParticle::setYVector(QSGDirection* arg)
862 if (m_yVector != arg) {
864 emit yVectorChanged(arg);
866 m_explicitDeformation = true;
867 if (perfLevel < Deformable)
871 void QSGImageParticle::setSpritesInterpolate(bool arg)
873 if (m_spritesInterpolate != arg) {
874 m_spritesInterpolate = arg;
875 emit spritesInterpolateChanged(arg);
879 void QSGImageParticle::setBloat(bool arg)
881 if (m_bloat != arg) {
883 emit bloatChanged(arg);
885 if (perfLevel < 9999)
889 void QSGImageParticle::setEntryEffect(EntryEffect arg)
891 if (m_entryEffect != arg) {
894 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
895 emit entryEffectChanged(arg);
899 void QSGImageParticle::resetColor()
901 m_explicitColor = false;
902 foreach (const QString &str, m_groups)
903 foreach (QSGParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
904 if (d->colorOwner == this)
907 m_color_variation = 0.0f;
908 m_redVariation = 0.0f;
909 m_blueVariation = 0.0f;
910 m_greenVariation = 0.0f;
912 m_alphaVariation = 0.0f;
915 void QSGImageParticle::resetRotation()
917 m_explicitRotation = false;
918 foreach (const QString &str, m_groups)
919 foreach (QSGParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
920 if (d->rotationOwner == this)
921 d->rotationOwner = 0;
923 m_rotationVariation = 0;
925 m_rotationSpeedVariation = 0;
926 m_autoRotation = false;
929 void QSGImageParticle::resetDeformation()
931 m_explicitDeformation = false;
932 foreach (const QString &str, m_groups)
933 foreach (QSGParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
934 if (d->deformationOwner == this)
935 d->deformationOwner = 0;
944 void QSGImageParticle::reset()
946 QSGParticlePainter::reset();
947 m_pleaseReset = true;
951 void QSGImageParticle::createEngine()
954 delete m_spriteEngine;
955 if (m_sprites.count())
956 m_spriteEngine = new QSGSpriteEngine(m_sprites, this);
959 m_explicitAnimation = true;
963 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
964 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
965 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
966 QSGGeometry::Attribute::create(2, 4, GL_FLOAT) // Vectors
969 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
971 3, // Attribute Count
972 ( 2 + 4 + 4 ) * sizeof(float),
973 SimpleParticle_Attributes
976 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
977 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
978 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
979 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
980 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
983 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
985 4, // Attribute Count
986 ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
987 ColoredParticle_Attributes
990 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
991 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
992 QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // TexCoord
993 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Data
994 QSGGeometry::Attribute::create(3, 4, GL_FLOAT), // Vectors
995 QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE), // Colors
996 QSGGeometry::Attribute::create(5, 4, GL_FLOAT), // DeformationVectors
997 QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Rotation
1000 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1002 7, // Attribute Count
1003 (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1004 DeformableParticle_Attributes
1007 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1008 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1009 QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // TexCoord
1010 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Data
1011 QSGGeometry::Attribute::create(3, 4, GL_FLOAT), // Vectors
1012 QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE), // Colors
1013 QSGGeometry::Attribute::create(5, 4, GL_FLOAT), // DeformationVectors
1014 QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Rotation
1015 QSGGeometry::Attribute::create(7, 4, GL_FLOAT), // Anim Data
1016 QSGGeometry::Attribute::create(8, 4, GL_FLOAT) // Anim Pos
1019 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1021 9, // Attribute Count
1022 (2 + 2 + 4 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1023 SpriteParticle_Attributes
1026 void QSGImageParticle::clearShadows()
1028 m_shadowInit = false;
1029 foreach (const QVector<QSGParticleData*> data, m_shadowData)
1031 m_shadowData.clear();
1034 //Only call if you need to, may initialize the whole array first time
1035 QSGParticleData* QSGImageParticle::getShadowDatum(QSGParticleData* datum)
1037 QSGParticleGroupData* gd = m_system->groupData[datum->group];
1038 if (!m_shadowData.contains(datum->group)) {
1039 QVector<QSGParticleData*> data;
1040 for (int i=0; i<gd->size(); i++){
1041 QSGParticleData* datum = new QSGParticleData(m_system);
1042 *datum = *(gd->data[i]);
1045 m_shadowData.insert(datum->group, data);
1047 //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1049 return m_shadowData[datum->group][datum->index];
1052 QSGGeometryNode* QSGImageParticle::buildParticleNodes()
1054 #ifdef QT_OPENGL_ES_2
1055 if (m_count * 4 > 0xffff) {
1056 printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1064 if (m_sprites.count() || m_bloat) {
1065 perfLevel = Sprites;
1066 } else if (!m_colortable_name.isEmpty() || !m_sizetable_name.isEmpty()
1067 || !m_opacitytable_name.isEmpty()) {
1069 } else if (m_autoRotation || m_rotation || m_rotationVariation
1070 || m_rotationSpeed || m_rotationSpeedVariation
1071 || m_xVector || m_yVector) {
1072 perfLevel = Deformable;
1073 } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1074 || m_redVariation || m_blueVariation || m_greenVariation) {
1075 perfLevel = Colored;
1080 foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1081 int gIdx = m_system->groupIds[str];
1082 foreach (QSGParticlePainter* p, m_system->groupData[gIdx]->painters){
1083 QSGImageParticle* other = qobject_cast<QSGImageParticle*>(p);
1085 if (other->perfLevel > perfLevel) {
1086 if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1087 if (perfLevel < Deformable)
1088 perfLevel = Deformable;
1090 perfLevel = other->perfLevel;
1092 } else if (other->perfLevel < perfLevel) {
1099 if (perfLevel >= Colored && !m_color.isValid())
1100 m_color = QColor(Qt::white);//Hidden default, but different from unset
1103 if (perfLevel >= Sprites){
1104 if (!m_spriteEngine) {
1105 qWarning() << "ImageParticle: No sprite engine...";
1108 image = m_spriteEngine->assembledImage();
1109 if (image.isNull())//Warning is printed in engine
1112 image = QImage(m_image_name.toLocalFile());
1113 if (image.isNull()) {
1114 printf("ImageParticle: loading image failed '%s'\n", qPrintable(m_image_name.toLocalFile()));
1126 QImage opacitytable;
1127 switch (perfLevel) {//Fallthrough intended
1129 m_material = SpriteMaterial::createMaterial();
1130 getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1131 m_spriteEngine->setCount(m_count);
1134 m_material = TabledMaterial::createMaterial();
1135 colortable = QImage(m_colortable_name.toLocalFile());
1136 sizetable = QImage(m_sizetable_name.toLocalFile());
1137 opacitytable = QImage(m_opacitytable_name.toLocalFile());
1138 if (colortable.isNull())
1139 colortable = QImage(QStringLiteral(":defaultshaders/identitytable.png"));
1140 Q_ASSERT(!colortable.isNull());
1141 getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1142 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1143 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1146 m_material = DeformableMaterial::createMaterial();
1149 m_material = ColoredMaterial::createMaterial();
1150 default://Also Simple
1152 m_material = SimpleMaterial::createMaterial();
1153 getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1154 getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1155 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1156 m_material->setFlag(QSGMaterial::Blending);
1159 foreach (const QString &str, m_groups){
1160 int gIdx = m_system->groupIds[str];
1161 int count = m_system->groupData[gIdx]->size();
1162 QSGGeometryNode* node = new QSGGeometryNode();
1163 node->setMaterial(m_material);
1164 node->markDirty(QSGNode::DirtyMaterial);
1166 m_nodes.insert(gIdx, node);
1167 m_idxStarts.insert(gIdx, m_lastIdxStart);
1168 m_lastIdxStart += count;
1170 //Create Particle Geometry
1171 int vCount = count * 4;
1172 int iCount = count * 6;
1175 if (perfLevel == Sprites)
1176 g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1177 else if (perfLevel == Tabled)
1178 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1179 else if (perfLevel == Deformable)
1180 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1181 else if (perfLevel == Colored)
1182 g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1184 g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1186 node->setGeometry(g);
1187 if (perfLevel <= Colored){
1188 g->setDrawingMode(GL_POINTS);
1190 GLfloat pointSizeRange[2];
1191 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1192 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1195 g->setDrawingMode(GL_TRIANGLES);
1197 for (int p=0; p < count; ++p)
1198 commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1200 if (perfLevel == Sprites)
1201 initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1202 else if (perfLevel == Tabled)
1203 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1204 else if (perfLevel == Deformable)
1205 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1207 if (perfLevel > Colored){
1208 quint16 *indices = g->indexDataAsUShort();
1209 for (int i=0; i < count; ++i) {
1223 foreach (QSGGeometryNode* node, m_nodes){
1224 if (node == *(m_nodes.begin()))
1225 node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1227 (*(m_nodes.begin()))->appendChildNode(node);
1230 return *(m_nodes.begin());
1233 QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1236 m_lastLevel = perfLevel;
1238 delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1242 m_idxStarts.clear();
1247 m_pleaseReset = false;
1250 if (m_system && m_system->isRunning() && !m_system->isPaused()){
1254 foreach (QSGGeometryNode* node, m_nodes)
1255 node->markDirty(QSGNode::DirtyGeometry);
1262 void QSGImageParticle::prepareNextFrame()
1264 if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1265 m_rootNode = buildParticleNodes();
1266 if (m_rootNode == 0)
1269 qDebug() << "QSGImageParticle Feature level: " << perfLevel;
1270 qDebug() << "QSGImageParticle Nodes: ";
1272 foreach(int i, m_nodes.keys()){
1273 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1274 count += m_system->groupData[i]->size();
1276 qDebug() << "Total count: " << count;
1279 qint64 timeStamp = m_system->systemSync(this);
1281 qreal time = timeStamp / 1000.;
1283 switch (perfLevel){//Fall-through intended
1286 m_spriteEngine->updateSprites(timeStamp);
1287 foreach (const QString &str, m_groups){
1288 int gIdx = m_system->groupIds[str];
1289 int count = m_system->groupData[gIdx]->size();
1291 Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData();
1292 for (int i=0; i < count; i++){
1293 int spriteIdx = m_idxStarts[gIdx] + i;
1294 Vertices<SpriteVertex> &p = particles[i];
1295 int curY = m_spriteEngine->spriteY(spriteIdx);//Y is fixed per sprite row, used to distinguish rows here
1296 if (curY != p.v1.animY){
1297 p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1298 p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1299 p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1300 p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx);
1301 p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx);
1302 p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1303 p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1311 default: //Also Simple
1312 getState<ImageMaterialData>(m_material)->timestamp = time;
1316 foreach (QSGGeometryNode* node, m_nodes)
1317 node->markDirty(QSGNode::DirtyMaterial);
1320 void QSGImageParticle::reloadColor(const Color4ub &c, QSGParticleData* d)
1323 //TODO: get index for reload - or make function take an index
1326 void QSGImageParticle::initialize(int gIdx, int pIdx)
1329 QSGParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1330 qreal redVariation = m_color_variation + m_redVariation;
1331 qreal greenVariation = m_color_variation + m_greenVariation;
1332 qreal blueVariation = m_color_variation + m_blueVariation;
1333 int spriteIdx = m_idxStarts[gIdx] + datum->index;
1335 float rotationSpeed;
1337 switch (perfLevel){//Fall-through is intended on all of them
1339 // Initial Sprite State
1340 if (m_explicitAnimation){
1341 if (!datum->animationOwner)
1342 datum->animationOwner = this;
1343 QSGParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1344 writeTo->animT = writeTo->t;
1345 //writeTo->animInterpolate = m_spritesInterpolate;
1346 if (m_spriteEngine){
1347 m_spriteEngine->start(spriteIdx);
1348 writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1349 writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1350 writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1351 writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1352 writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1353 writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1355 writeTo->frameCount = 1;
1356 writeTo->frameDuration = 9999;
1357 writeTo->animX = writeTo->animY = writeTo->animWidth = writeTo->animHeight = 0;
1363 if (m_explicitDeformation){
1364 if (!datum->deformationOwner)
1365 datum->deformationOwner = this;
1367 const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1368 if (datum->deformationOwner == this) {
1369 datum->xx = ret.x();
1370 datum->xy = ret.y();
1372 getShadowDatum(datum)->xx = ret.x();
1373 getShadowDatum(datum)->xy = ret.y();
1377 const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1378 if (datum->deformationOwner == this) {
1379 datum->yx = ret.x();
1380 datum->yy = ret.y();
1382 getShadowDatum(datum)->yx = ret.x();
1383 getShadowDatum(datum)->yy = ret.y();
1388 if (m_explicitRotation){
1389 if (!datum->rotationOwner)
1390 datum->rotationOwner = this;
1392 (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1394 (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1395 autoRotate = m_autoRotation?1.0:0.0;
1396 if (datum->rotationOwner == this) {
1397 datum->rotation = rotation;
1398 datum->rotationSpeed = rotationSpeed;
1399 datum->autoRotate = autoRotate;
1401 getShadowDatum(datum)->rotation = rotation;
1402 getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1403 getShadowDatum(datum)->autoRotate = autoRotate;
1407 //Color initialization
1409 if (m_explicitColor) {
1410 if (!datum->colorOwner)
1411 datum->colorOwner = this;
1412 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1413 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1414 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1415 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1416 if (datum->colorOwner == this)
1417 datum->color = color;
1419 getShadowDatum(datum)->color = color;
1426 void QSGImageParticle::commit(int gIdx, int pIdx)
1430 QSGGeometryNode *node = m_nodes[gIdx];
1433 QSGParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1434 node->setFlag(QSGNode::OwnsGeometry, false);
1435 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1436 DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1437 ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1438 SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1439 switch (perfLevel){//No automatic fall through intended on this one
1441 spriteVertices += pIdx*4;
1442 for (int i=0; i<4; i++){
1443 spriteVertices[i].x = datum->x - m_systemOffset.x();
1444 spriteVertices[i].y = datum->y - m_systemOffset.y();
1445 spriteVertices[i].t = datum->t;
1446 spriteVertices[i].lifeSpan = datum->lifeSpan;
1447 spriteVertices[i].size = datum->size;
1448 spriteVertices[i].endSize = datum->endSize;
1449 spriteVertices[i].vx = datum->vx;
1450 spriteVertices[i].vy = datum->vy;
1451 spriteVertices[i].ax = datum->ax;
1452 spriteVertices[i].ay = datum->ay;
1453 if (m_explicitDeformation && datum->deformationOwner != this) {
1454 QSGParticleData* shadow = getShadowDatum(datum);
1455 spriteVertices[i].xx = shadow->xx;
1456 spriteVertices[i].xy = shadow->xy;
1457 spriteVertices[i].yx = shadow->yx;
1458 spriteVertices[i].yy = shadow->yy;
1460 spriteVertices[i].xx = datum->xx;
1461 spriteVertices[i].xy = datum->xy;
1462 spriteVertices[i].yx = datum->yx;
1463 spriteVertices[i].yy = datum->yy;
1465 if (m_explicitRotation && datum->rotationOwner != this) {
1466 QSGParticleData* shadow = getShadowDatum(datum);
1467 spriteVertices[i].rotation = shadow->rotation;
1468 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1469 spriteVertices[i].autoRotate = shadow->autoRotate;
1471 spriteVertices[i].rotation = datum->rotation;
1472 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1473 spriteVertices[i].autoRotate = datum->autoRotate;
1475 spriteVertices[i].animInterpolate = m_spritesInterpolate ? 1.0 : 0.0;//### Shadow? In particleData? Or uniform?
1476 if (m_explicitAnimation && datum->animationOwner != this) {
1477 QSGParticleData* shadow = getShadowDatum(datum);
1478 spriteVertices[i].frameDuration = shadow->frameDuration;
1479 spriteVertices[i].frameCount = shadow->frameCount;
1480 spriteVertices[i].animT = shadow->animT;
1481 spriteVertices[i].animX = shadow->animX;
1482 spriteVertices[i].animY = shadow->animY;
1483 spriteVertices[i].animWidth = shadow->animWidth;
1484 spriteVertices[i].animHeight = shadow->animHeight;
1486 spriteVertices[i].frameDuration = datum->frameDuration;
1487 spriteVertices[i].frameCount = datum->frameCount;
1488 spriteVertices[i].animT = datum->animT;
1489 spriteVertices[i].animX = datum->animX;
1490 spriteVertices[i].animY = datum->animY;
1491 spriteVertices[i].animWidth = datum->animWidth;
1492 spriteVertices[i].animHeight = datum->animHeight;
1494 if (m_explicitColor && datum->colorOwner != this) {
1495 QSGParticleData* shadow = getShadowDatum(datum);
1496 spriteVertices[i].color.r = shadow->color.r;
1497 spriteVertices[i].color.g = shadow->color.g;
1498 spriteVertices[i].color.b = shadow->color.b;
1499 spriteVertices[i].color.a = shadow->color.a;
1501 spriteVertices[i].color.r = datum->color.r;
1502 spriteVertices[i].color.g = datum->color.g;
1503 spriteVertices[i].color.b = datum->color.b;
1504 spriteVertices[i].color.a = datum->color.a;
1508 case Tabled: //Fall through until it has its own vertex class
1510 deformableVertices += pIdx*4;
1511 for (int i=0; i<4; i++){
1512 deformableVertices[i].x = datum->x - m_systemOffset.x();
1513 deformableVertices[i].y = datum->y - m_systemOffset.y();
1514 deformableVertices[i].t = datum->t;
1515 deformableVertices[i].lifeSpan = datum->lifeSpan;
1516 deformableVertices[i].size = datum->size;
1517 deformableVertices[i].endSize = datum->endSize;
1518 deformableVertices[i].vx = datum->vx;
1519 deformableVertices[i].vy = datum->vy;
1520 deformableVertices[i].ax = datum->ax;
1521 deformableVertices[i].ay = datum->ay;
1522 if (m_explicitDeformation && datum->deformationOwner != this) {
1523 QSGParticleData* shadow = getShadowDatum(datum);
1524 deformableVertices[i].xx = shadow->xx;
1525 deformableVertices[i].xy = shadow->xy;
1526 deformableVertices[i].yx = shadow->yx;
1527 deformableVertices[i].yy = shadow->yy;
1529 deformableVertices[i].xx = datum->xx;
1530 deformableVertices[i].xy = datum->xy;
1531 deformableVertices[i].yx = datum->yx;
1532 deformableVertices[i].yy = datum->yy;
1534 if (m_explicitRotation && datum->rotationOwner != this) {
1535 QSGParticleData* shadow = getShadowDatum(datum);
1536 deformableVertices[i].rotation = shadow->rotation;
1537 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1538 deformableVertices[i].autoRotate = shadow->autoRotate;
1540 deformableVertices[i].rotation = datum->rotation;
1541 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1542 deformableVertices[i].autoRotate = datum->autoRotate;
1544 if (m_explicitColor && datum->colorOwner != this) {
1545 QSGParticleData* shadow = getShadowDatum(datum);
1546 deformableVertices[i].color.r = shadow->color.r;
1547 deformableVertices[i].color.g = shadow->color.g;
1548 deformableVertices[i].color.b = shadow->color.b;
1549 deformableVertices[i].color.a = shadow->color.a;
1551 deformableVertices[i].color.r = datum->color.r;
1552 deformableVertices[i].color.g = datum->color.g;
1553 deformableVertices[i].color.b = datum->color.b;
1554 deformableVertices[i].color.a = datum->color.a;
1559 coloredVertices += pIdx*1;
1560 for (int i=0; i<1; i++){
1561 coloredVertices[i].x = datum->x - m_systemOffset.x();
1562 coloredVertices[i].y = datum->y - m_systemOffset.y();
1563 coloredVertices[i].t = datum->t;
1564 coloredVertices[i].lifeSpan = datum->lifeSpan;
1565 coloredVertices[i].size = datum->size;
1566 coloredVertices[i].endSize = datum->endSize;
1567 coloredVertices[i].vx = datum->vx;
1568 coloredVertices[i].vy = datum->vy;
1569 coloredVertices[i].ax = datum->ax;
1570 coloredVertices[i].ay = datum->ay;
1571 if (m_explicitColor && datum->colorOwner != this) {
1572 QSGParticleData* shadow = getShadowDatum(datum);
1573 coloredVertices[i].color.r = shadow->color.r;
1574 coloredVertices[i].color.g = shadow->color.g;
1575 coloredVertices[i].color.b = shadow->color.b;
1576 coloredVertices[i].color.a = shadow->color.a;
1578 coloredVertices[i].color.r = datum->color.r;
1579 coloredVertices[i].color.g = datum->color.g;
1580 coloredVertices[i].color.b = datum->color.b;
1581 coloredVertices[i].color.a = datum->color.a;
1586 simpleVertices += pIdx*1;
1587 for (int i=0; i<1; i++){
1588 simpleVertices[i].x = datum->x - m_systemOffset.x();
1589 simpleVertices[i].y = datum->y - m_systemOffset.y();
1590 simpleVertices[i].t = datum->t;
1591 simpleVertices[i].lifeSpan = datum->lifeSpan;
1592 simpleVertices[i].size = datum->size;
1593 simpleVertices[i].endSize = datum->endSize;
1594 simpleVertices[i].vx = datum->vx;
1595 simpleVertices[i].vy = datum->vy;
1596 simpleVertices[i].ax = datum->ax;
1597 simpleVertices[i].ay = datum->ay;
1604 node->setFlag(QSGNode::OwnsGeometry, true);