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 <QtQuick/private/qsgcontext_p.h>
43 #include <private/qsgadaptationlayer_p.h>
44 #include <QtQuick/qsgnode.h>
45 #include <QtQuick/qsgtexturematerial.h>
46 #include <QtQuick/qsgtexture.h>
48 #include "qquickimageparticle_p.h"
49 #include "qquickparticleemitter_p.h"
50 #include <private/qquicksprite_p.h>
51 #include <private/qquickspriteengine_p.h>
52 #include <QOpenGLFunctions>
53 #include <QtQuick/qsgengine.h>
54 #include <QtQuick/private/qsgtexture_p.h>
55 #include <private/qdeclarativeglobal_p.h>
58 //###Switch to define later, for now user-friendly (no compilation) debugging is worth it
59 DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG)
61 #ifndef QT_OPENGL_ES_2
62 #define SHADER_DEFINES "#version 120\n"
64 #define SHADER_DEFINES ""
67 //TODO: Make it larger on desktop? Requires fixing up shader code with the same define
68 #define UNIFORM_ARRAY_SIZE 64
70 static const char vertexShaderCode[] =
71 "attribute highp vec2 vPos;\n"
72 "attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize\n"
73 "attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration\n"
74 "uniform highp float entry;\n"
75 "#if defined(COLOR)\n"
76 "attribute lowp vec4 vColor;\n"
78 "#if defined(DEFORM)\n"
79 "attribute highp vec2 vTex;\n"
80 "attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector\n"
81 "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate\n"
83 "#if defined(SPRITE)\n"
84 "attribute highp vec4 vAnimData;// interpolate(bool), duration, frameCount (this anim), timestamp (this anim)\n"
85 "attribute highp vec4 vAnimPos;//sheet x,y, width/height of this anim\n"
86 "uniform highp vec2 animSheetSize; //width/height of whole sheet\n"
89 "uniform highp mat4 qt_Matrix;\n"
90 "uniform highp float timestamp;\n"
91 "#if defined(TABLE)\n"
92 "varying lowp vec2 tt;//y is progress if Sprite mode\n"
93 "uniform highp float sizetable[64];\n"
94 "uniform highp float opacitytable[64];\n"
96 "#if defined(SPRITE)\n"
97 "varying highp vec4 fTexS;\n"
98 "#elif defined(DEFORM)\n"
99 "varying highp vec2 fTex;\n"
101 "#if defined(COLOR)\n"
102 "varying lowp vec4 fColor;\n"
104 "varying lowp float fFade;\n"
110 " highp float t = (timestamp - vData.x) / vData.y;\n"
111 " if (t < 0. || t > 1.) {\n"
112 "#if defined(DEFORM)\n"
113 " gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0., 1.);\n"
115 " gl_PointSize = 0.;\n"
118 "#if defined(SPRITE)\n"
119 " //Calculate frame location in texture\n"
120 " highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);\n"
121 " tt.y = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;\n"
123 " frameIndex = floor(frameIndex);\n"
124 " fTexS.xy = vec2(((frameIndex + vTex.x) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vTex.y * vAnimPos.w) / animSheetSize.y));\n"
126 " //Next frame is also passed, for interpolation\n"
127 " //### Should the next anim be precalculated to allow for interpolation there?\n"
128 " if (vAnimData.x == 1.0 && frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop\n"
129 " frameIndex = mod(frameIndex+1., vAnimData.z);\n"
130 " fTexS.zw = vec2(((frameIndex + vTex.x) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vTex.y * vAnimPos.w) / animSheetSize.y));\n"
131 "#elif defined(DEFORM)\n"
134 " highp float currentSize = mix(vData.z, vData.w, t * t);\n"
135 " lowp float fade = 1.;\n"
136 " highp float fadeIn = min(t * 10., 1.);\n"
137 " highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);\n"
139 "#if defined(TABLE)\n"
140 " currentSize = currentSize * sizetable[int(floor(t*64.))];\n"
141 " fade = fade * opacitytable[int(floor(t*64.))];\n"
144 " if (entry == 1.)\n"
145 " fade = fade * fadeIn * fadeOut;\n"
146 " else if (entry == 2.)\n"
147 " currentSize = currentSize * fadeIn * fadeOut;\n"
149 " if (currentSize <= 0.) {\n"
150 "#if defined(DEFORM)\n"
151 " gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0., 1.);\n"
153 " gl_PointSize = 0.;\n"
156 " if (currentSize < 3.)//Sizes too small look jittery as they move\n"
157 " currentSize = 3.;\n"
160 "#if defined(DEFORM)\n"
161 " highp float rotation = vRotation.x + vRotation.y * t * vData.y;\n"
162 " if (vRotation.z == 1.0){\n"
163 " highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;\n"
164 " rotation += atan(curVel.y, curVel.x);\n"
166 " highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));\n"
167 " highp vec4 deform = vDeformVec * currentSize * (vTex.xxyy - 0.5);\n"
168 " highp vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;\n"
169 " rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));\n"
170 " /* The readable version:\n"
171 " highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);\n"
172 " highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);\n"
173 " highp vec2 xRotatedDeform;\n"
174 " xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;\n"
175 " xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;\n"
176 " highp vec2 yRotatedDeform;\n"
177 " yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;\n"
178 " yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;\n"
181 " + rotatedDeform.xy\n"
182 " + rotatedDeform.zw\n"
183 " + vVec.xy * t * vData.y // apply speed\n"
184 " + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration\n"
187 " + vVec.xy * t * vData.y // apply speed vector..\n"
188 " + 0.5 * vVec.zw * pow(t * vData.y, 2.);\n"
189 " gl_PointSize = currentSize;\n"
191 " gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);\n"
193 "#if defined(COLOR)\n"
194 " fColor = vColor * fade;\n"
198 "#if defined(TABLE)\n"
205 static const char fragmentShaderCode[] =
206 "uniform sampler2D texture;\n"
207 "uniform lowp float qt_Opacity;\n"
209 "#if defined(SPRITE)\n"
210 "varying highp vec4 fTexS;\n"
211 "#elif defined(DEFORM)\n"
212 "varying highp vec2 fTex;\n"
214 "#if defined(COLOR)\n"
215 "varying lowp vec4 fColor;\n"
217 "varying lowp float fFade;\n"
219 "#if defined(TABLE)\n"
220 "varying lowp vec2 tt;\n"
221 "uniform sampler2D colortable;\n"
225 "#if defined(SPRITE)\n"
226 " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), tt.y)\n"
228 " * texture2D(colortable, tt)\n"
230 "#elif defined(TABLE)\n"
231 " gl_FragColor = texture2D(texture, fTex)\n"
233 " * texture2D(colortable, tt)\n"
235 "#elif defined(DEFORM)\n"
236 " gl_FragColor = (texture2D(texture, fTex)) * fColor * qt_Opacity;\n"
237 "#elif defined(COLOR)\n"
238 " gl_FragColor = (texture2D(texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
240 " gl_FragColor = texture2D(texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
244 const qreal CONV = 0.017453292519943295;
245 class ImageMaterialData
249 : texture(0), colorTable(0)
252 ~ImageMaterialData(){
258 QSGTexture *colorTable;
259 float sizeTable[UNIFORM_ARRAY_SIZE];
260 float opacityTable[UNIFORM_ARRAY_SIZE];
264 QSizeF animSheetSize;
267 class TabledMaterialData : public ImageMaterialData {};
268 class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
270 QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
275 m_vertex_code = QByteArray(SHADER_DEFINES)
276 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
279 m_fragment_code = QByteArray(SHADER_DEFINES)
280 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
281 + fragmentShaderCode;
283 Q_ASSERT(!m_vertex_code.isNull());
284 Q_ASSERT(!m_fragment_code.isNull());
287 const char *vertexShader() const { return m_vertex_code.constData(); }
288 const char *fragmentShader() const { return m_fragment_code.constData(); }
290 QList<QByteArray> attributes() const {
291 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
292 << "vColor" << "vDeformVec" << "vRotation";
296 QSGSimpleMaterialShader<TabledMaterialData>::initialize();
298 program()->setUniformValue("texture", 0);
299 program()->setUniformValue("colortable", 1);
300 glFuncs = QOpenGLContext::currentContext()->functions();
301 m_timestamp_id = program()->uniformLocation("timestamp");
302 m_entry_id = program()->uniformLocation("entry");
303 m_sizetable_id = program()->uniformLocation("sizetable");
304 m_opacitytable_id = program()->uniformLocation("opacitytable");
307 void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
308 glFuncs->glActiveTexture(GL_TEXTURE1);
309 d->colorTable->bind();
311 glFuncs->glActiveTexture(GL_TEXTURE0);
314 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
315 program()->setUniformValue(m_entry_id, (float) d->entry);
316 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1);
317 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
323 int m_opacitytable_id;
324 QByteArray m_vertex_code;
325 QByteArray m_fragment_code;
326 QOpenGLFunctions* glFuncs;
329 class DeformableMaterialData : public ImageMaterialData {};
330 class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData>
332 QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData)
337 m_vertex_code = QByteArray(SHADER_DEFINES)
338 + QByteArray("#define DEFORM\n#define COLOR\n")
341 m_fragment_code = QByteArray(SHADER_DEFINES)
342 + QByteArray("#define DEFORM\n#define COLOR\n")
343 + fragmentShaderCode;
345 Q_ASSERT(!m_vertex_code.isNull());
346 Q_ASSERT(!m_fragment_code.isNull());
349 const char *vertexShader() const { return m_vertex_code.constData(); }
350 const char *fragmentShader() const { return m_fragment_code.constData(); }
352 QList<QByteArray> attributes() const {
353 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
354 << "vColor" << "vDeformVec" << "vRotation";
358 QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
360 program()->setUniformValue("texture", 0);
361 glFuncs = QOpenGLContext::currentContext()->functions();
362 m_timestamp_id = program()->uniformLocation("timestamp");
363 m_entry_id = program()->uniformLocation("entry");
366 void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) {
367 glFuncs->glActiveTexture(GL_TEXTURE0);
370 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
371 program()->setUniformValue(m_entry_id, (float) d->entry);
376 QByteArray m_vertex_code;
377 QByteArray m_fragment_code;
378 QOpenGLFunctions* glFuncs;
381 class SpriteMaterialData : public ImageMaterialData {};
382 class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
384 QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData)
389 m_vertex_code = QByteArray(SHADER_DEFINES)
390 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
393 m_fragment_code = QByteArray(SHADER_DEFINES)
394 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
395 + fragmentShaderCode;
397 Q_ASSERT(!m_vertex_code.isNull());
398 Q_ASSERT(!m_fragment_code.isNull());
401 const char *vertexShader() const { return m_vertex_code.constData(); }
402 const char *fragmentShader() const { return m_fragment_code.constData(); }
404 QList<QByteArray> attributes() const {
405 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
406 << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
410 QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
412 program()->setUniformValue("texture", 0);
413 program()->setUniformValue("colortable", 1);
414 glFuncs = QOpenGLContext::currentContext()->functions();
415 m_timestamp_id = program()->uniformLocation("timestamp");
416 m_animsize_id = program()->uniformLocation("animSheetSize");
417 m_entry_id = program()->uniformLocation("entry");
418 m_sizetable_id = program()->uniformLocation("sizetable");
419 m_opacitytable_id = program()->uniformLocation("opacitytable");
422 void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) {
423 glFuncs->glActiveTexture(GL_TEXTURE1);
424 d->colorTable->bind();
426 // make sure we end by setting GL_TEXTURE0 as active texture
427 glFuncs->glActiveTexture(GL_TEXTURE0);
430 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
431 program()->setUniformValue(m_animsize_id, d->animSheetSize);
432 program()->setUniformValue(m_entry_id, (float) d->entry);
433 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, 64, 1);
434 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
441 int m_opacitytable_id;
442 QByteArray m_vertex_code;
443 QByteArray m_fragment_code;
444 QOpenGLFunctions* glFuncs;
447 class ColoredMaterialData : public ImageMaterialData {};
448 class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
450 QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData)
455 m_vertex_code = QByteArray(SHADER_DEFINES)
456 + QByteArray("#define COLOR\n")
459 m_fragment_code = QByteArray(SHADER_DEFINES)
460 + QByteArray("#define COLOR\n")
461 + fragmentShaderCode;
463 Q_ASSERT(!m_vertex_code.isNull());
464 Q_ASSERT(!m_fragment_code.isNull());
467 const char *vertexShader() const { return m_vertex_code.constData(); }
468 const char *fragmentShader() const { return m_fragment_code.constData(); }
471 QSGSimpleMaterialShader<ColoredMaterialData>::activate();
472 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
473 glEnable(GL_POINT_SPRITE);
474 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
479 QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
480 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
481 glDisable(GL_POINT_SPRITE);
482 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
486 QList<QByteArray> attributes() const {
487 return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
491 QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
493 program()->setUniformValue("texture", 0);
494 glFuncs = QOpenGLContext::currentContext()->functions();
495 m_timestamp_id = program()->uniformLocation("timestamp");
496 m_entry_id = program()->uniformLocation("entry");
499 void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) {
500 glFuncs->glActiveTexture(GL_TEXTURE0);
503 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
504 program()->setUniformValue(m_entry_id, (float) d->entry);
509 QByteArray m_vertex_code;
510 QByteArray m_fragment_code;
511 QOpenGLFunctions* glFuncs;
514 class SimpleMaterialData : public ImageMaterialData {};
515 class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
517 QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData)
522 m_vertex_code = QByteArray(SHADER_DEFINES)
525 m_fragment_code = QByteArray(SHADER_DEFINES)
526 + fragmentShaderCode;
528 Q_ASSERT(!m_vertex_code.isNull());
529 Q_ASSERT(!m_fragment_code.isNull());
532 const char *vertexShader() const { return m_vertex_code.constData(); }
533 const char *fragmentShader() const { return m_fragment_code.constData(); }
536 QSGSimpleMaterialShader<SimpleMaterialData>::activate();
537 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
538 glEnable(GL_POINT_SPRITE);
539 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
544 QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
545 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
546 glDisable(GL_POINT_SPRITE);
547 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
551 QList<QByteArray> attributes() const {
552 return QList<QByteArray>() << "vPos" << "vData" << "vVec";
556 QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
558 program()->setUniformValue("texture", 0);
559 glFuncs = QOpenGLContext::currentContext()->functions();
560 m_timestamp_id = program()->uniformLocation("timestamp");
561 m_entry_id = program()->uniformLocation("entry");
564 void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) {
565 glFuncs->glActiveTexture(GL_TEXTURE0);
568 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
569 program()->setUniformValue(m_entry_id, (float) d->entry);
574 QByteArray m_vertex_code;
575 QByteArray m_fragment_code;
576 QOpenGLFunctions* glFuncs;
579 void fillUniformArrayFromImage(float* array, const QImage& img, int size)
582 for (int i=0; i<size; i++)
586 QImage scaled = img.scaled(size,1);
587 for (int i=0; i<size; i++)
588 array[i] = qAlpha(scaled.pixel(i,0))/255.0;
592 \qmlclass ImageParticle QQuickImageParticle
593 \inqmlmodule QtQuick.Particles 2
594 \inherits ParticlePainter
595 \brief The ImageParticle element visualizes logical particles using an image
597 This element renders a logical particle as an image. The image can be
602 \o a sprite-based animation
605 ImageParticles implictly share data on particles if multiple ImageParticles are painting
606 the same logical particle group. This is broken down along the four capabilities listed
607 above. So if one ImageParticle defines data for rendering the particles in one of those
608 capabilities, and the other does not, then both will draw the particles the same in that
609 aspect automatically. This is primarily useful when there is some random variation on
610 the particle which is supposed to stay with it when switching painters. If both ImageParticles
611 define how they should appear for that aspect, they diverge and each appears as it is defined.
613 This sharing of data happens behind the scenes based off of whether properties were implicitly or explicitly
614 set. One drawback of the current implementation is that it is only possible to reset the capabilities as a whole.
615 So if you explicity set an attribute affecting color, such as redVariation, and then reset it (by setting redVariation
616 to undefined), all color data will be reset and it will begin to have an implicit value of any shared color from
617 other ImageParticles.
620 \qmlproperty url QtQuick.Particles2::ImageParticle::source
622 The source image to be used.
624 If the image is a sprite animation, use the sprite property instead.
627 \qmlproperty list<Sprite> QtQuick.Particles2::ImageParticle::sprites
629 The sprite or sprites used to draw this particle.
631 Note that the sprite image will be scaled to a square based on the size of
632 the particle being rendered.
635 \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable
637 An image whose color will be used as a 1D texture to determine color over life. E.g. when
638 the particle is halfway through its lifetime, it will have the color specified halfway
641 This color is blended with the color property and the color of the source image.
644 \qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
646 An image whose opacity will be used as a 1D texture to determine size over life.
648 This property is expected to be removed shortly, in favor of custom easing curves to determine size over life.
651 \qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
653 An image whose opacity will be used as a 1D texture to determine size over life.
655 This property is expected to be removed shortly, in favor of custom easing curves to determine opacity over life.
658 \qmlproperty color QtQuick.Particles2::ImageParticle::color
660 If a color is specified, the provided image will be colorized with it.
662 Default is white (no change).
665 \qmlproperty real QtQuick.Particles2::ImageParticle::colorVariation
667 This number represents the color variation applied to individual particles.
668 Setting colorVariation is the same as setting redVariation, greenVariation,
669 and blueVariation to the same number.
671 Each channel can vary between particle by up to colorVariation from its usual color.
673 Color is measured, per channel, from 0.0 to 1.0.
678 \qmlproperty real QtQuick.Particles2::ImageParticle::redVariation
679 The variation in the red color channel between particles.
681 Color is measured, per channel, from 0.0 to 1.0.
686 \qmlproperty real QtQuick.Particles2::ImageParticle::greenVariation
687 The variation in the green color channel between particles.
689 Color is measured, per channel, from 0.0 to 1.0.
694 \qmlproperty real QtQuick.Particles2::ImageParticle::blueVariation
695 The variation in the blue color channel between particles.
697 Color is measured, per channel, from 0.0 to 1.0.
702 \qmlproperty real QtQuick.Particles2::ImageParticle::alpha
703 An alpha to be applied to the image. This value is multiplied by the value in
704 the image, and the value in the color property.
706 Particles have additive blending, so lower alpha on single particles leads
707 to stronger effects when multiple particles overlap.
709 Alpha is measured from 0.0 to 1.0.
714 \qmlproperty real QtQuick.Particles2::ImageParticle::alphaVariation
715 The variation in the alpha channel between particles.
717 Alpha is measured from 0.0 to 1.0.
722 \qmlproperty real QtQuick.Particles2::ImageParticle::rotation
724 If set the image will be rotated by this many degrees before it is drawn.
726 The particle coordinates are not transformed.
729 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationVariation
731 If set the rotation of individual particles will vary by up to this much
736 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeed
738 If set particles will rotate at this speed in degrees/second.
741 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeedVariation
743 If set the rotationSpeed of individual particles will vary by up to this much
748 \qmlproperty bool QtQuick.Particles2::ImageParticle::autoRotation
750 If set to true then a rotation will be applied on top of the particles rotation, so
751 that it faces the direction of travel. So to face away from the direction of travel,
752 set autoRotation to true and rotation to 180.
757 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::xVector
759 Allows you to deform the particle image when drawn. The rectangular image will
760 be deformed so that the horizontal sides are in the shape of this vector instead
764 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::yVector
766 Allows you to deform the particle image when drawn. The rectangular image will
767 be deformed so that the vertical sides are in the shape of this vector instead
771 \qmlproperty EntryEffect QtQuick.Particles2::ImageParticle::entryEffect
773 This property provides basic and cheap entrance and exit effects for the particles.
774 For fine-grained control, see sizeTable and opacityTable.
776 Acceptable values are
778 \o None: Particles just appear and disappear.
779 \o Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
780 \o Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end.
783 Default value is Fade.
786 \qmlproperty bool QtQuick.Particles2::ImageParticle::spritesInterpolate
788 If set to true, sprite particles will interpolate between sprite frames each rendered frame, making
789 the sprites look smoother.
795 QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
796 : QQuickParticlePainter(parent)
797 , m_color_variation(0.0)
800 , m_alphaVariation(0.0)
802 , m_redVariation(0.0)
803 , m_greenVariation(0.0)
804 , m_blueVariation(0.0)
806 , m_rotationVariation(0)
808 , m_rotationSpeedVariation(0)
809 , m_autoRotation(false)
813 , m_spritesInterpolate(true)
814 , m_explicitColor(false)
815 , m_explicitRotation(false)
816 , m_explicitDeformation(false)
817 , m_explicitAnimation(false)
820 , m_lastLevel(Unknown)
822 , m_entryEffect(Fade)
824 setFlag(ItemHasContents);
825 m_debugMode = qmlParticlesDebug();
828 QQuickImageParticle::~QQuickImageParticle()
832 QDeclarativeListProperty<QQuickSprite> QQuickImageParticle::sprites()
834 return QDeclarativeListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
837 void QQuickImageParticle::setImage(const QUrl &image)
839 if (image == m_image_name)
841 m_image_name = image;
847 void QQuickImageParticle::setColortable(const QUrl &table)
849 if (table == m_colortable_name)
851 m_colortable_name = table;
852 emit colortableChanged();
856 void QQuickImageParticle::setSizetable(const QUrl &table)
858 if (table == m_sizetable_name)
860 m_sizetable_name = table;
861 emit sizetableChanged();
865 void QQuickImageParticle::setOpacitytable(const QUrl &table)
867 if (table == m_opacitytable_name)
869 m_opacitytable_name = table;
870 emit opacitytableChanged();
874 void QQuickImageParticle::setColor(const QColor &color)
876 if (color == m_color)
880 m_explicitColor = true;
881 if (perfLevel < Colored)
885 void QQuickImageParticle::setColorVariation(qreal var)
887 if (var == m_color_variation)
889 m_color_variation = var;
890 emit colorVariationChanged();
891 m_explicitColor = true;
892 if (perfLevel < Colored)
896 void QQuickImageParticle::setAlphaVariation(qreal arg)
898 if (m_alphaVariation != arg) {
899 m_alphaVariation = arg;
900 emit alphaVariationChanged(arg);
902 m_explicitColor = true;
903 if (perfLevel < Colored)
907 void QQuickImageParticle::setAlpha(qreal arg)
909 if (m_alpha != arg) {
911 emit alphaChanged(arg);
913 m_explicitColor = true;
914 if (perfLevel < Colored)
918 void QQuickImageParticle::setRedVariation(qreal arg)
920 if (m_redVariation != arg) {
921 m_redVariation = arg;
922 emit redVariationChanged(arg);
924 m_explicitColor = true;
925 if (perfLevel < Colored)
929 void QQuickImageParticle::setGreenVariation(qreal arg)
931 if (m_greenVariation != arg) {
932 m_greenVariation = arg;
933 emit greenVariationChanged(arg);
935 m_explicitColor = true;
936 if (perfLevel < Colored)
940 void QQuickImageParticle::setBlueVariation(qreal arg)
942 if (m_blueVariation != arg) {
943 m_blueVariation = arg;
944 emit blueVariationChanged(arg);
946 m_explicitColor = true;
947 if (perfLevel < Colored)
951 void QQuickImageParticle::setRotation(qreal arg)
953 if (m_rotation != arg) {
955 emit rotationChanged(arg);
957 m_explicitRotation = true;
958 if (perfLevel < Deformable)
962 void QQuickImageParticle::setRotationVariation(qreal arg)
964 if (m_rotationVariation != arg) {
965 m_rotationVariation = arg;
966 emit rotationVariationChanged(arg);
968 m_explicitRotation = true;
969 if (perfLevel < Deformable)
973 void QQuickImageParticle::setRotationSpeed(qreal arg)
975 if (m_rotationSpeed != arg) {
976 m_rotationSpeed = arg;
977 emit rotationSpeedChanged(arg);
979 m_explicitRotation = true;
980 if (perfLevel < Deformable)
984 void QQuickImageParticle::setRotationSpeedVariation(qreal arg)
986 if (m_rotationSpeedVariation != arg) {
987 m_rotationSpeedVariation = arg;
988 emit rotationSpeedVariationChanged(arg);
990 m_explicitRotation = true;
991 if (perfLevel < Deformable)
995 void QQuickImageParticle::setAutoRotation(bool arg)
997 if (m_autoRotation != arg) {
998 m_autoRotation = arg;
999 emit autoRotationChanged(arg);
1001 m_explicitRotation = true;
1002 if (perfLevel < Deformable)
1006 void QQuickImageParticle::setXVector(QQuickDirection* arg)
1008 if (m_xVector != arg) {
1010 emit xVectorChanged(arg);
1012 m_explicitDeformation = true;
1013 if (perfLevel < Deformable)
1017 void QQuickImageParticle::setYVector(QQuickDirection* arg)
1019 if (m_yVector != arg) {
1021 emit yVectorChanged(arg);
1023 m_explicitDeformation = true;
1024 if (perfLevel < Deformable)
1028 void QQuickImageParticle::setSpritesInterpolate(bool arg)
1030 if (m_spritesInterpolate != arg) {
1031 m_spritesInterpolate = arg;
1032 emit spritesInterpolateChanged(arg);
1036 void QQuickImageParticle::setBloat(bool arg)
1038 if (m_bloat != arg) {
1040 emit bloatChanged(arg);
1042 if (perfLevel < 9999)
1046 void QQuickImageParticle::setEntryEffect(EntryEffect arg)
1048 if (m_entryEffect != arg) {
1049 m_entryEffect = arg;
1051 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1052 emit entryEffectChanged(arg);
1056 void QQuickImageParticle::resetColor()
1058 m_explicitColor = false;
1059 foreach (const QString &str, m_groups)
1060 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1061 if (d->colorOwner == this)
1064 m_color_variation = 0.0f;
1065 m_redVariation = 0.0f;
1066 m_blueVariation = 0.0f;
1067 m_greenVariation = 0.0f;
1069 m_alphaVariation = 0.0f;
1072 void QQuickImageParticle::resetRotation()
1074 m_explicitRotation = false;
1075 foreach (const QString &str, m_groups)
1076 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1077 if (d->rotationOwner == this)
1078 d->rotationOwner = 0;
1080 m_rotationVariation = 0;
1081 m_rotationSpeed = 0;
1082 m_rotationSpeedVariation = 0;
1083 m_autoRotation = false;
1086 void QQuickImageParticle::resetDeformation()
1088 m_explicitDeformation = false;
1089 foreach (const QString &str, m_groups)
1090 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1091 if (d->deformationOwner == this)
1092 d->deformationOwner = 0;
1101 void QQuickImageParticle::reset()
1103 QQuickParticlePainter::reset();
1104 m_pleaseReset = true;
1108 void QQuickImageParticle::createEngine()
1111 delete m_spriteEngine;
1112 if (m_sprites.count()) {
1113 m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1114 connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1115 this, SLOT(spriteAdvance(int)));
1116 m_explicitAnimation = true;
1119 m_explicitAnimation = false;
1124 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
1125 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1126 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1127 QSGGeometry::Attribute::create(2, 4, GL_FLOAT) // Vectors
1130 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
1132 3, // Attribute Count
1133 ( 2 + 4 + 4 ) * sizeof(float),
1134 SimpleParticle_Attributes
1137 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
1138 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1139 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1140 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1141 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1144 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
1146 4, // Attribute Count
1147 ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1148 ColoredParticle_Attributes
1151 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
1152 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1153 QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // TexCoord
1154 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Data
1155 QSGGeometry::Attribute::create(3, 4, GL_FLOAT), // Vectors
1156 QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE), // Colors
1157 QSGGeometry::Attribute::create(5, 4, GL_FLOAT), // DeformationVectors
1158 QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Rotation
1161 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1163 7, // Attribute Count
1164 (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1165 DeformableParticle_Attributes
1168 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1169 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1170 QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // TexCoord
1171 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Data
1172 QSGGeometry::Attribute::create(3, 4, GL_FLOAT), // Vectors
1173 QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE), // Colors
1174 QSGGeometry::Attribute::create(5, 4, GL_FLOAT), // DeformationVectors
1175 QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Rotation
1176 QSGGeometry::Attribute::create(7, 4, GL_FLOAT), // Anim Data
1177 QSGGeometry::Attribute::create(8, 4, GL_FLOAT) // Anim Pos
1180 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1182 9, // Attribute Count
1183 (2 + 2 + 4 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1184 SpriteParticle_Attributes
1187 void QQuickImageParticle::clearShadows()
1189 foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1191 m_shadowData.clear();
1194 //Only call if you need to, may initialize the whole array first time
1195 QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1197 QQuickParticleGroupData* gd = m_system->groupData[datum->group];
1198 if (!m_shadowData.contains(datum->group)) {
1199 QVector<QQuickParticleData*> data;
1200 for (int i=0; i<gd->size(); i++){
1201 QQuickParticleData* datum = new QQuickParticleData(m_system);
1202 *datum = *(gd->data[i]);
1205 m_shadowData.insert(datum->group, data);
1207 //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1209 return m_shadowData[datum->group][datum->index];
1212 QSGGeometryNode* QQuickImageParticle::buildParticleNodes()
1214 #ifdef QT_OPENGL_ES_2
1215 if (m_count * 4 > 0xffff) {
1216 printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1224 if (m_sprites.count() || m_bloat) {
1225 perfLevel = Sprites;
1226 } else if (!m_colortable_name.isEmpty() || !m_sizetable_name.isEmpty()
1227 || !m_opacitytable_name.isEmpty()) {
1229 } else if (m_autoRotation || m_rotation || m_rotationVariation
1230 || m_rotationSpeed || m_rotationSpeedVariation
1231 || m_xVector || m_yVector) {
1232 perfLevel = Deformable;
1233 } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1234 || m_redVariation || m_blueVariation || m_greenVariation) {
1235 perfLevel = Colored;
1240 foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1241 int gIdx = m_system->groupIds[str];
1242 foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){
1243 QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1245 if (other->perfLevel > perfLevel) {
1246 if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1247 if (perfLevel < Deformable)
1248 perfLevel = Deformable;
1250 perfLevel = other->perfLevel;
1252 } else if (other->perfLevel < perfLevel) {
1259 if (perfLevel >= Colored && !m_color.isValid())
1260 m_color = QColor(Qt::white);//Hidden default, but different from unset
1263 if (perfLevel >= Sprites){
1264 if (!m_spriteEngine) {
1265 qWarning() << "ImageParticle: No sprite engine...";
1268 image = m_spriteEngine->assembledImage();
1269 if (image.isNull())//Warning is printed in engine
1272 image = QImage(m_image_name.toLocalFile());
1273 if (image.isNull()) {
1274 printf("ImageParticle: loading image failed '%s'\n", qPrintable(m_image_name.toLocalFile()));
1286 QImage opacitytable;
1287 switch (perfLevel) {//Fallthrough intended
1289 m_material = SpriteMaterial::createMaterial();
1290 getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1291 m_spriteEngine->setCount(m_count);
1294 m_material = TabledMaterial::createMaterial();
1295 colortable = QImage(m_colortable_name.toLocalFile());
1296 sizetable = QImage(m_sizetable_name.toLocalFile());
1297 opacitytable = QImage(m_opacitytable_name.toLocalFile());
1298 if (colortable.isNull()){
1299 colortable = QImage(1,1,QImage::Format_ARGB32);
1300 colortable.fill(Qt::white);
1302 Q_ASSERT(!colortable.isNull());
1303 getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1304 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1305 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1308 m_material = DeformableMaterial::createMaterial();
1311 m_material = ColoredMaterial::createMaterial();
1312 default://Also Simple
1314 m_material = SimpleMaterial::createMaterial();
1315 getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1316 getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1317 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1318 m_material->setFlag(QSGMaterial::Blending);
1321 foreach (const QString &str, m_groups){
1322 int gIdx = m_system->groupIds[str];
1323 int count = m_system->groupData[gIdx]->size();
1324 QSGGeometryNode* node = new QSGGeometryNode();
1325 node->setMaterial(m_material);
1326 node->markDirty(QSGNode::DirtyMaterial);
1328 m_nodes.insert(gIdx, node);
1329 m_idxStarts.insert(gIdx, m_lastIdxStart);
1330 m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx));
1331 m_lastIdxStart += count;
1333 //Create Particle Geometry
1334 int vCount = count * 4;
1335 int iCount = count * 6;
1338 if (perfLevel == Sprites)
1339 g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1340 else if (perfLevel == Tabled)
1341 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1342 else if (perfLevel == Deformable)
1343 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1344 else if (perfLevel == Colored)
1345 g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1347 g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1349 node->setGeometry(g);
1350 if (perfLevel <= Colored){
1351 g->setDrawingMode(GL_POINTS);
1353 GLfloat pointSizeRange[2];
1354 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1355 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1358 g->setDrawingMode(GL_TRIANGLES);
1360 for (int p=0; p < count; ++p)
1361 commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1363 if (perfLevel == Sprites)
1364 initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1365 else if (perfLevel == Tabled)
1366 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1367 else if (perfLevel == Deformable)
1368 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1370 if (perfLevel > Colored){
1371 quint16 *indices = g->indexDataAsUShort();
1372 for (int i=0; i < count; ++i) {
1386 foreach (QSGGeometryNode* node, m_nodes){
1387 if (node == *(m_nodes.begin()))
1388 node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1390 (*(m_nodes.begin()))->appendChildNode(node);
1393 return *(m_nodes.begin());
1396 QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1399 m_lastLevel = perfLevel;
1401 delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1405 m_idxStarts.clear();
1406 m_startsIdx.clear();
1411 m_pleaseReset = false;
1414 if (m_system && m_system->isRunning() && !m_system->isPaused()){
1418 foreach (QSGGeometryNode* node, m_nodes)
1419 node->markDirty(QSGNode::DirtyGeometry);
1426 void QQuickImageParticle::prepareNextFrame()
1428 if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1429 m_rootNode = buildParticleNodes();
1430 if (m_rootNode == 0)
1433 qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1434 qDebug() << "QQuickImageParticle Nodes: ";
1436 foreach (int i, m_nodes.keys()) {
1437 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1438 count += m_system->groupData[i]->size();
1440 qDebug() << "Total count: " << count;
1443 qint64 timeStamp = m_system->systemSync(this);
1445 qreal time = timeStamp / 1000.;
1447 switch (perfLevel){//Fall-through intended
1450 m_spriteEngine->updateSprites(timeStamp);
1455 default: //Also Simple
1456 getState<ImageMaterialData>(m_material)->timestamp = time;
1460 foreach (QSGGeometryNode* node, m_nodes)
1461 node->markDirty(QSGNode::DirtyMaterial);
1464 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1466 if (!m_startsIdx.count())//Probably overly defensive
1471 for (i = 0; i<m_startsIdx.count(); i++) {
1472 if (spriteIdx < m_startsIdx[i].first) {
1473 gIdx = m_startsIdx[i-1].second;
1478 gIdx = m_startsIdx[i-1].second;
1479 int pIdx = spriteIdx - m_startsIdx[i-1].first;
1481 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1482 QQuickParticleData* d = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1484 d->animIdx = m_spriteEngine->spriteState(spriteIdx);
1485 Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData();
1486 Vertices<SpriteVertex> &p = particles[pIdx];
1487 d->animT = p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1488 d->frameCount = p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1489 d->frameDuration = p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1490 d->animX = p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx);
1491 d->animY = p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx);
1492 d->animWidth = p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1493 d->animHeight = p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1496 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1499 //TODO: get index for reload - or make function take an index
1502 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1505 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1506 qreal redVariation = m_color_variation + m_redVariation;
1507 qreal greenVariation = m_color_variation + m_greenVariation;
1508 qreal blueVariation = m_color_variation + m_blueVariation;
1510 if (m_spriteEngine) {
1511 spriteIdx = m_idxStarts[gIdx] + datum->index;
1512 if (spriteIdx >= m_spriteEngine->count())
1513 m_spriteEngine->setCount(spriteIdx+1);
1517 float rotationSpeed;
1519 switch (perfLevel){//Fall-through is intended on all of them
1521 // Initial Sprite State
1522 if (m_explicitAnimation){
1523 if (!datum->animationOwner)
1524 datum->animationOwner = this;
1525 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1526 writeTo->animT = writeTo->t;
1527 //writeTo->animInterpolate = m_spritesInterpolate;
1528 if (m_spriteEngine){
1529 m_spriteEngine->start(spriteIdx);
1530 writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1531 writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1532 writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1533 writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1534 writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1535 writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1537 writeTo->frameCount = 1;
1538 writeTo->frameDuration = 9999;
1539 writeTo->animX = writeTo->animY = 0;
1540 writeTo->animWidth = writeTo->animHeight = 1;
1546 if (m_explicitDeformation){
1547 if (!datum->deformationOwner)
1548 datum->deformationOwner = this;
1550 const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1551 if (datum->deformationOwner == this) {
1552 datum->xx = ret.x();
1553 datum->xy = ret.y();
1555 getShadowDatum(datum)->xx = ret.x();
1556 getShadowDatum(datum)->xy = ret.y();
1560 const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1561 if (datum->deformationOwner == this) {
1562 datum->yx = ret.x();
1563 datum->yy = ret.y();
1565 getShadowDatum(datum)->yx = ret.x();
1566 getShadowDatum(datum)->yy = ret.y();
1571 if (m_explicitRotation){
1572 if (!datum->rotationOwner)
1573 datum->rotationOwner = this;
1575 (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1577 (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1578 autoRotate = m_autoRotation?1.0:0.0;
1579 if (datum->rotationOwner == this) {
1580 datum->rotation = rotation;
1581 datum->rotationSpeed = rotationSpeed;
1582 datum->autoRotate = autoRotate;
1584 getShadowDatum(datum)->rotation = rotation;
1585 getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1586 getShadowDatum(datum)->autoRotate = autoRotate;
1590 //Color initialization
1592 if (m_explicitColor) {
1593 if (!datum->colorOwner)
1594 datum->colorOwner = this;
1595 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1596 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1597 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1598 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1599 if (datum->colorOwner == this)
1600 datum->color = color;
1602 getShadowDatum(datum)->color = color;
1609 void QQuickImageParticle::commit(int gIdx, int pIdx)
1613 QSGGeometryNode *node = m_nodes[gIdx];
1616 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1617 node->setFlag(QSGNode::OwnsGeometry, false);
1618 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1619 DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1620 ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1621 SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1622 switch (perfLevel){//No automatic fall through intended on this one
1624 spriteVertices += pIdx*4;
1625 for (int i=0; i<4; i++){
1626 spriteVertices[i].x = datum->x - m_systemOffset.x();
1627 spriteVertices[i].y = datum->y - m_systemOffset.y();
1628 spriteVertices[i].t = datum->t;
1629 spriteVertices[i].lifeSpan = datum->lifeSpan;
1630 spriteVertices[i].size = datum->size;
1631 spriteVertices[i].endSize = datum->endSize;
1632 spriteVertices[i].vx = datum->vx;
1633 spriteVertices[i].vy = datum->vy;
1634 spriteVertices[i].ax = datum->ax;
1635 spriteVertices[i].ay = datum->ay;
1636 if (m_explicitDeformation && datum->deformationOwner != this) {
1637 QQuickParticleData* shadow = getShadowDatum(datum);
1638 spriteVertices[i].xx = shadow->xx;
1639 spriteVertices[i].xy = shadow->xy;
1640 spriteVertices[i].yx = shadow->yx;
1641 spriteVertices[i].yy = shadow->yy;
1643 spriteVertices[i].xx = datum->xx;
1644 spriteVertices[i].xy = datum->xy;
1645 spriteVertices[i].yx = datum->yx;
1646 spriteVertices[i].yy = datum->yy;
1648 if (m_explicitRotation && datum->rotationOwner != this) {
1649 QQuickParticleData* shadow = getShadowDatum(datum);
1650 spriteVertices[i].rotation = shadow->rotation;
1651 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1652 spriteVertices[i].autoRotate = shadow->autoRotate;
1654 spriteVertices[i].rotation = datum->rotation;
1655 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1656 spriteVertices[i].autoRotate = datum->autoRotate;
1658 spriteVertices[i].animInterpolate = m_spritesInterpolate ? 1.0 : 0.0;//### Shadow? In particleData? Or uniform?
1659 if (m_explicitAnimation && datum->animationOwner != this) {
1660 QQuickParticleData* shadow = getShadowDatum(datum);
1661 spriteVertices[i].frameDuration = shadow->frameDuration;
1662 spriteVertices[i].frameCount = shadow->frameCount;
1663 spriteVertices[i].animT = shadow->animT;
1664 spriteVertices[i].animX = shadow->animX;
1665 spriteVertices[i].animY = shadow->animY;
1666 spriteVertices[i].animWidth = shadow->animWidth;
1667 spriteVertices[i].animHeight = shadow->animHeight;
1669 spriteVertices[i].frameDuration = datum->frameDuration;
1670 spriteVertices[i].frameCount = datum->frameCount;
1671 spriteVertices[i].animT = datum->animT;
1672 spriteVertices[i].animX = datum->animX;
1673 spriteVertices[i].animY = datum->animY;
1674 spriteVertices[i].animWidth = datum->animWidth;
1675 spriteVertices[i].animHeight = datum->animHeight;
1677 if (m_explicitColor && datum->colorOwner != this) {
1678 QQuickParticleData* shadow = getShadowDatum(datum);
1679 spriteVertices[i].color.r = shadow->color.r;
1680 spriteVertices[i].color.g = shadow->color.g;
1681 spriteVertices[i].color.b = shadow->color.b;
1682 spriteVertices[i].color.a = shadow->color.a;
1684 spriteVertices[i].color.r = datum->color.r;
1685 spriteVertices[i].color.g = datum->color.g;
1686 spriteVertices[i].color.b = datum->color.b;
1687 spriteVertices[i].color.a = datum->color.a;
1691 case Tabled: //Fall through until it has its own vertex class
1693 deformableVertices += pIdx*4;
1694 for (int i=0; i<4; i++){
1695 deformableVertices[i].x = datum->x - m_systemOffset.x();
1696 deformableVertices[i].y = datum->y - m_systemOffset.y();
1697 deformableVertices[i].t = datum->t;
1698 deformableVertices[i].lifeSpan = datum->lifeSpan;
1699 deformableVertices[i].size = datum->size;
1700 deformableVertices[i].endSize = datum->endSize;
1701 deformableVertices[i].vx = datum->vx;
1702 deformableVertices[i].vy = datum->vy;
1703 deformableVertices[i].ax = datum->ax;
1704 deformableVertices[i].ay = datum->ay;
1705 if (m_explicitDeformation && datum->deformationOwner != this) {
1706 QQuickParticleData* shadow = getShadowDatum(datum);
1707 deformableVertices[i].xx = shadow->xx;
1708 deformableVertices[i].xy = shadow->xy;
1709 deformableVertices[i].yx = shadow->yx;
1710 deformableVertices[i].yy = shadow->yy;
1712 deformableVertices[i].xx = datum->xx;
1713 deformableVertices[i].xy = datum->xy;
1714 deformableVertices[i].yx = datum->yx;
1715 deformableVertices[i].yy = datum->yy;
1717 if (m_explicitRotation && datum->rotationOwner != this) {
1718 QQuickParticleData* shadow = getShadowDatum(datum);
1719 deformableVertices[i].rotation = shadow->rotation;
1720 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1721 deformableVertices[i].autoRotate = shadow->autoRotate;
1723 deformableVertices[i].rotation = datum->rotation;
1724 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1725 deformableVertices[i].autoRotate = datum->autoRotate;
1727 if (m_explicitColor && datum->colorOwner != this) {
1728 QQuickParticleData* shadow = getShadowDatum(datum);
1729 deformableVertices[i].color.r = shadow->color.r;
1730 deformableVertices[i].color.g = shadow->color.g;
1731 deformableVertices[i].color.b = shadow->color.b;
1732 deformableVertices[i].color.a = shadow->color.a;
1734 deformableVertices[i].color.r = datum->color.r;
1735 deformableVertices[i].color.g = datum->color.g;
1736 deformableVertices[i].color.b = datum->color.b;
1737 deformableVertices[i].color.a = datum->color.a;
1742 coloredVertices += pIdx*1;
1743 for (int i=0; i<1; i++){
1744 coloredVertices[i].x = datum->x - m_systemOffset.x();
1745 coloredVertices[i].y = datum->y - m_systemOffset.y();
1746 coloredVertices[i].t = datum->t;
1747 coloredVertices[i].lifeSpan = datum->lifeSpan;
1748 coloredVertices[i].size = datum->size;
1749 coloredVertices[i].endSize = datum->endSize;
1750 coloredVertices[i].vx = datum->vx;
1751 coloredVertices[i].vy = datum->vy;
1752 coloredVertices[i].ax = datum->ax;
1753 coloredVertices[i].ay = datum->ay;
1754 if (m_explicitColor && datum->colorOwner != this) {
1755 QQuickParticleData* shadow = getShadowDatum(datum);
1756 coloredVertices[i].color.r = shadow->color.r;
1757 coloredVertices[i].color.g = shadow->color.g;
1758 coloredVertices[i].color.b = shadow->color.b;
1759 coloredVertices[i].color.a = shadow->color.a;
1761 coloredVertices[i].color.r = datum->color.r;
1762 coloredVertices[i].color.g = datum->color.g;
1763 coloredVertices[i].color.b = datum->color.b;
1764 coloredVertices[i].color.a = datum->color.a;
1769 simpleVertices += pIdx*1;
1770 for (int i=0; i<1; i++){
1771 simpleVertices[i].x = datum->x - m_systemOffset.x();
1772 simpleVertices[i].y = datum->y - m_systemOffset.y();
1773 simpleVertices[i].t = datum->t;
1774 simpleVertices[i].lifeSpan = datum->lifeSpan;
1775 simpleVertices[i].size = datum->size;
1776 simpleVertices[i].endSize = datum->endSize;
1777 simpleVertices[i].vx = datum->vx;
1778 simpleVertices[i].vy = datum->vy;
1779 simpleVertices[i].ax = datum->ax;
1780 simpleVertices[i].ay = datum->ay;
1787 node->setFlag(QSGNode::OwnsGeometry, true);