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 "#if defined(DEFORM)\n"
72 "attribute highp vec4 vPosTex;\n"
74 "attribute highp vec2 vPos;\n"
76 "attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize\n"
77 "attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration\n"
78 "uniform highp float entry;\n"
79 "#if defined(COLOR)\n"
80 "attribute highp vec4 vColor;\n"
82 "#if defined(DEFORM)\n"
83 "attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector\n"
84 "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate\n"
86 "#if defined(SPRITE)\n"
87 "attribute highp vec4 vAnimData;// interpolate(bool), duration, frameCount (this anim), timestamp (this anim)\n"
88 "attribute highp vec4 vAnimPos;//sheet x,y, width/height of this anim\n"
89 "uniform highp vec2 animSheetSize; //width/height of whole sheet\n"
92 "uniform highp mat4 qt_Matrix;\n"
93 "uniform highp float timestamp;\n"
94 "#if defined(TABLE)\n"
95 "varying lowp vec2 tt;//y is progress if Sprite mode\n"
96 "uniform highp float sizetable[64];\n"
97 "uniform highp float opacitytable[64];\n"
99 "#if defined(SPRITE)\n"
100 "varying highp vec4 fTexS;\n"
101 "#elif defined(DEFORM)\n"
102 "varying highp vec2 fTex;\n"
104 "#if defined(COLOR)\n"
105 "varying lowp vec4 fColor;\n"
107 "varying lowp float fFade;\n"
113 " highp float t = (timestamp - vData.x) / vData.y;\n"
114 " if (t < 0. || t > 1.) {\n"
115 "#if defined(DEFORM)\n"
116 " gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
118 " gl_PointSize = 0.;\n"
121 "#if defined(SPRITE)\n"
122 " //Calculate frame location in texture\n"
123 " highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);\n"
124 " tt.y = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;\n"
126 " frameIndex = floor(frameIndex);\n"
127 " fTexS.xy = vec2(((frameIndex + vPosTex.z) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vPosTex.w * vAnimPos.w) / animSheetSize.y));\n"
129 " //Next frame is also passed, for interpolation\n"
130 " //### Should the next anim be precalculated to allow for interpolation there?\n"
131 " if (vAnimData.x == 1.0 && frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop\n"
132 " frameIndex = mod(frameIndex+1., vAnimData.z);\n"
133 " fTexS.zw = vec2(((frameIndex + vPosTex.z) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vPosTex.w * vAnimPos.w) / animSheetSize.y));\n"
134 "#elif defined(DEFORM)\n"
135 " fTex = vPosTex.zw;\n"
137 " highp float currentSize = mix(vData.z, vData.w, t * t);\n"
138 " lowp float fade = 1.;\n"
139 " highp float fadeIn = min(t * 10., 1.);\n"
140 " highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);\n"
142 "#if defined(TABLE)\n"
143 " currentSize = currentSize * sizetable[int(floor(t*64.))];\n"
144 " fade = fade * opacitytable[int(floor(t*64.))];\n"
147 " if (entry == 1.)\n"
148 " fade = fade * fadeIn * fadeOut;\n"
149 " else if (entry == 2.)\n"
150 " currentSize = currentSize * fadeIn * fadeOut;\n"
152 " if (currentSize <= 0.) {\n"
153 "#if defined(DEFORM)\n"
154 " gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
156 " gl_PointSize = 0.;\n"
159 " if (currentSize < 3.)//Sizes too small look jittery as they move\n"
160 " currentSize = 3.;\n"
163 "#if defined(DEFORM)\n"
164 " highp float rotation = vRotation.x + vRotation.y * t * vData.y;\n"
165 " if (vRotation.z == 1.0){\n"
166 " highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;\n"
167 " rotation += atan(curVel.y, curVel.x);\n"
169 " highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));\n"
170 " highp vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);\n"
171 " highp vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;\n"
172 " rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));\n"
173 " /* The readable version:\n"
174 " highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);\n"
175 " highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);\n"
176 " highp vec2 xRotatedDeform;\n"
177 " xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;\n"
178 " xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;\n"
179 " highp vec2 yRotatedDeform;\n"
180 " yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;\n"
181 " yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;\n"
183 " pos = vPosTex.xy\n"
184 " + rotatedDeform.xy\n"
185 " + rotatedDeform.zw\n"
186 " + vVec.xy * t * vData.y // apply speed\n"
187 " + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration\n"
190 " + vVec.xy * t * vData.y // apply speed vector..\n"
191 " + 0.5 * vVec.zw * pow(t * vData.y, 2.);\n"
192 " gl_PointSize = currentSize;\n"
194 " gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);\n"
196 "#if defined(COLOR)\n"
197 " fColor = vColor * fade;\n"
201 "#if defined(TABLE)\n"
208 static const char fragmentShaderCode[] =
209 "uniform sampler2D texture;\n"
210 "uniform lowp float qt_Opacity;\n"
212 "#if defined(SPRITE)\n"
213 "varying highp vec4 fTexS;\n"
214 "#elif defined(DEFORM)\n"
215 "varying highp vec2 fTex;\n"
217 "#if defined(COLOR)\n"
218 "varying lowp vec4 fColor;\n"
220 "varying lowp float fFade;\n"
222 "#if defined(TABLE)\n"
223 "varying lowp vec2 tt;\n"
224 "uniform sampler2D colortable;\n"
228 "#if defined(SPRITE)\n"
229 " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), tt.y)\n"
231 " * texture2D(colortable, tt)\n"
233 "#elif defined(TABLE)\n"
234 " gl_FragColor = texture2D(texture, fTex)\n"
236 " * texture2D(colortable, tt)\n"
238 "#elif defined(DEFORM)\n"
239 " gl_FragColor = (texture2D(texture, fTex)) * fColor * qt_Opacity;\n"
240 "#elif defined(COLOR)\n"
241 " gl_FragColor = (texture2D(texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
243 " gl_FragColor = texture2D(texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
247 const qreal CONV = 0.017453292519943295;
248 class ImageMaterialData
252 : texture(0), colorTable(0)
255 ~ImageMaterialData(){
261 QSGTexture *colorTable;
262 float sizeTable[UNIFORM_ARRAY_SIZE];
263 float opacityTable[UNIFORM_ARRAY_SIZE];
267 QSizeF animSheetSize;
270 class TabledMaterialData : public ImageMaterialData {};
271 class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
273 QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
278 m_vertex_code = QByteArray(SHADER_DEFINES)
279 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
282 m_fragment_code = QByteArray(SHADER_DEFINES)
283 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
284 + fragmentShaderCode;
286 Q_ASSERT(!m_vertex_code.isNull());
287 Q_ASSERT(!m_fragment_code.isNull());
290 const char *vertexShader() const { return m_vertex_code.constData(); }
291 const char *fragmentShader() const { return m_fragment_code.constData(); }
293 QList<QByteArray> attributes() const {
294 return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
295 << "vColor" << "vDeformVec" << "vRotation";
299 QSGSimpleMaterialShader<TabledMaterialData>::initialize();
301 program()->setUniformValue("texture", 0);
302 program()->setUniformValue("colortable", 1);
303 glFuncs = QOpenGLContext::currentContext()->functions();
304 m_timestamp_id = program()->uniformLocation("timestamp");
305 m_entry_id = program()->uniformLocation("entry");
306 m_sizetable_id = program()->uniformLocation("sizetable");
307 m_opacitytable_id = program()->uniformLocation("opacitytable");
310 void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
311 glFuncs->glActiveTexture(GL_TEXTURE1);
312 d->colorTable->bind();
314 glFuncs->glActiveTexture(GL_TEXTURE0);
317 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
318 program()->setUniformValue(m_entry_id, (float) d->entry);
319 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1);
320 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
326 int m_opacitytable_id;
327 QByteArray m_vertex_code;
328 QByteArray m_fragment_code;
329 QOpenGLFunctions* glFuncs;
332 class DeformableMaterialData : public ImageMaterialData {};
333 class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData>
335 QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData)
340 m_vertex_code = QByteArray(SHADER_DEFINES)
341 + QByteArray("#define DEFORM\n#define COLOR\n")
344 m_fragment_code = QByteArray(SHADER_DEFINES)
345 + QByteArray("#define DEFORM\n#define COLOR\n")
346 + fragmentShaderCode;
348 Q_ASSERT(!m_vertex_code.isNull());
349 Q_ASSERT(!m_fragment_code.isNull());
352 const char *vertexShader() const { return m_vertex_code.constData(); }
353 const char *fragmentShader() const { return m_fragment_code.constData(); }
355 QList<QByteArray> attributes() const {
356 return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
357 << "vColor" << "vDeformVec" << "vRotation";
361 QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
363 program()->setUniformValue("texture", 0);
364 glFuncs = QOpenGLContext::currentContext()->functions();
365 m_timestamp_id = program()->uniformLocation("timestamp");
366 m_entry_id = program()->uniformLocation("entry");
369 void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) {
370 glFuncs->glActiveTexture(GL_TEXTURE0);
373 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
374 program()->setUniformValue(m_entry_id, (float) d->entry);
379 QByteArray m_vertex_code;
380 QByteArray m_fragment_code;
381 QOpenGLFunctions* glFuncs;
384 class SpriteMaterialData : public ImageMaterialData {};
385 class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
387 QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData)
392 m_vertex_code = QByteArray(SHADER_DEFINES)
393 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
396 m_fragment_code = QByteArray(SHADER_DEFINES)
397 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
398 + fragmentShaderCode;
400 Q_ASSERT(!m_vertex_code.isNull());
401 Q_ASSERT(!m_fragment_code.isNull());
404 const char *vertexShader() const { return m_vertex_code.constData(); }
405 const char *fragmentShader() const { return m_fragment_code.constData(); }
407 QList<QByteArray> attributes() const {
408 return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
409 << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
413 QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
415 program()->setUniformValue("texture", 0);
416 program()->setUniformValue("colortable", 1);
417 glFuncs = QOpenGLContext::currentContext()->functions();
418 m_timestamp_id = program()->uniformLocation("timestamp");
419 m_animsize_id = program()->uniformLocation("animSheetSize");
420 m_entry_id = program()->uniformLocation("entry");
421 m_sizetable_id = program()->uniformLocation("sizetable");
422 m_opacitytable_id = program()->uniformLocation("opacitytable");
425 void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) {
426 glFuncs->glActiveTexture(GL_TEXTURE1);
427 d->colorTable->bind();
429 // make sure we end by setting GL_TEXTURE0 as active texture
430 glFuncs->glActiveTexture(GL_TEXTURE0);
433 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
434 program()->setUniformValue(m_animsize_id, d->animSheetSize);
435 program()->setUniformValue(m_entry_id, (float) d->entry);
436 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, 64, 1);
437 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
444 int m_opacitytable_id;
445 QByteArray m_vertex_code;
446 QByteArray m_fragment_code;
447 QOpenGLFunctions* glFuncs;
450 class ColoredMaterialData : public ImageMaterialData {};
451 class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
453 QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData)
458 m_vertex_code = QByteArray(SHADER_DEFINES)
459 + QByteArray("#define COLOR\n")
462 m_fragment_code = QByteArray(SHADER_DEFINES)
463 + QByteArray("#define COLOR\n")
464 + fragmentShaderCode;
466 Q_ASSERT(!m_vertex_code.isNull());
467 Q_ASSERT(!m_fragment_code.isNull());
470 const char *vertexShader() const { return m_vertex_code.constData(); }
471 const char *fragmentShader() const { return m_fragment_code.constData(); }
474 QSGSimpleMaterialShader<ColoredMaterialData>::activate();
475 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
476 glEnable(GL_POINT_SPRITE);
477 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
482 QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
483 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
484 glDisable(GL_POINT_SPRITE);
485 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
489 QList<QByteArray> attributes() const {
490 return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
494 QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
496 program()->setUniformValue("texture", 0);
497 glFuncs = QOpenGLContext::currentContext()->functions();
498 m_timestamp_id = program()->uniformLocation("timestamp");
499 m_entry_id = program()->uniformLocation("entry");
502 void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) {
503 glFuncs->glActiveTexture(GL_TEXTURE0);
506 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
507 program()->setUniformValue(m_entry_id, (float) d->entry);
512 QByteArray m_vertex_code;
513 QByteArray m_fragment_code;
514 QOpenGLFunctions* glFuncs;
517 class SimpleMaterialData : public ImageMaterialData {};
518 class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
520 QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData)
525 m_vertex_code = QByteArray(SHADER_DEFINES)
528 m_fragment_code = QByteArray(SHADER_DEFINES)
529 + fragmentShaderCode;
531 Q_ASSERT(!m_vertex_code.isNull());
532 Q_ASSERT(!m_fragment_code.isNull());
535 const char *vertexShader() const { return m_vertex_code.constData(); }
536 const char *fragmentShader() const { return m_fragment_code.constData(); }
539 QSGSimpleMaterialShader<SimpleMaterialData>::activate();
540 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
541 glEnable(GL_POINT_SPRITE);
542 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
547 QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
548 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
549 glDisable(GL_POINT_SPRITE);
550 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
554 QList<QByteArray> attributes() const {
555 return QList<QByteArray>() << "vPos" << "vData" << "vVec";
559 QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
561 program()->setUniformValue("texture", 0);
562 glFuncs = QOpenGLContext::currentContext()->functions();
563 m_timestamp_id = program()->uniformLocation("timestamp");
564 m_entry_id = program()->uniformLocation("entry");
567 void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) {
568 glFuncs->glActiveTexture(GL_TEXTURE0);
571 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
572 program()->setUniformValue(m_entry_id, (float) d->entry);
577 QByteArray m_vertex_code;
578 QByteArray m_fragment_code;
579 QOpenGLFunctions* glFuncs;
582 void fillUniformArrayFromImage(float* array, const QImage& img, int size)
585 for (int i=0; i<size; i++)
589 QImage scaled = img.scaled(size,1);
590 for (int i=0; i<size; i++)
591 array[i] = qAlpha(scaled.pixel(i,0))/255.0;
595 \qmlclass ImageParticle QQuickImageParticle
596 \inqmlmodule QtQuick.Particles 2
597 \inherits ParticlePainter
598 \brief The ImageParticle element visualizes logical particles using an image
600 This element renders a logical particle as an image. The image can be
605 \o a sprite-based animation
608 ImageParticles implictly share data on particles if multiple ImageParticles are painting
609 the same logical particle group. This is broken down along the four capabilities listed
610 above. So if one ImageParticle defines data for rendering the particles in one of those
611 capabilities, and the other does not, then both will draw the particles the same in that
612 aspect automatically. This is primarily useful when there is some random variation on
613 the particle which is supposed to stay with it when switching painters. If both ImageParticles
614 define how they should appear for that aspect, they diverge and each appears as it is defined.
616 This sharing of data happens behind the scenes based off of whether properties were implicitly or explicitly
617 set. One drawback of the current implementation is that it is only possible to reset the capabilities as a whole.
618 So if you explicity set an attribute affecting color, such as redVariation, and then reset it (by setting redVariation
619 to undefined), all color data will be reset and it will begin to have an implicit value of any shared color from
620 other ImageParticles.
623 \qmlproperty url QtQuick.Particles2::ImageParticle::source
625 The source image to be used.
627 If the image is a sprite animation, use the sprite property instead.
630 \qmlproperty list<Sprite> QtQuick.Particles2::ImageParticle::sprites
632 The sprite or sprites used to draw this particle.
634 Note that the sprite image will be scaled to a square based on the size of
635 the particle being rendered.
638 \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable
640 An image whose color will be used as a 1D texture to determine color over life. E.g. when
641 the particle is halfway through its lifetime, it will have the color specified halfway
644 This color is blended with the color property and the color of the source image.
647 \qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
649 An image whose opacity will be used as a 1D texture to determine size over life.
651 This property is expected to be removed shortly, in favor of custom easing curves to determine size over life.
654 \qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
656 An image whose opacity will be used as a 1D texture to determine size over life.
658 This property is expected to be removed shortly, in favor of custom easing curves to determine opacity over life.
661 \qmlproperty color QtQuick.Particles2::ImageParticle::color
663 If a color is specified, the provided image will be colorized with it.
665 Default is white (no change).
668 \qmlproperty real QtQuick.Particles2::ImageParticle::colorVariation
670 This number represents the color variation applied to individual particles.
671 Setting colorVariation is the same as setting redVariation, greenVariation,
672 and blueVariation to the same number.
674 Each channel can vary between particle by up to colorVariation from its usual color.
676 Color is measured, per channel, from 0.0 to 1.0.
681 \qmlproperty real QtQuick.Particles2::ImageParticle::redVariation
682 The variation in the red color channel between particles.
684 Color is measured, per channel, from 0.0 to 1.0.
689 \qmlproperty real QtQuick.Particles2::ImageParticle::greenVariation
690 The variation in the green color channel between particles.
692 Color is measured, per channel, from 0.0 to 1.0.
697 \qmlproperty real QtQuick.Particles2::ImageParticle::blueVariation
698 The variation in the blue color channel between particles.
700 Color is measured, per channel, from 0.0 to 1.0.
705 \qmlproperty real QtQuick.Particles2::ImageParticle::alpha
706 An alpha to be applied to the image. This value is multiplied by the value in
707 the image, and the value in the color property.
709 Particles have additive blending, so lower alpha on single particles leads
710 to stronger effects when multiple particles overlap.
712 Alpha is measured from 0.0 to 1.0.
717 \qmlproperty real QtQuick.Particles2::ImageParticle::alphaVariation
718 The variation in the alpha channel between particles.
720 Alpha is measured from 0.0 to 1.0.
725 \qmlproperty real QtQuick.Particles2::ImageParticle::rotation
727 If set the image will be rotated by this many degrees before it is drawn.
729 The particle coordinates are not transformed.
732 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationVariation
734 If set the rotation of individual particles will vary by up to this much
739 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeed
741 If set particles will rotate at this speed in degrees/second.
744 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeedVariation
746 If set the rotationSpeed of individual particles will vary by up to this much
751 \qmlproperty bool QtQuick.Particles2::ImageParticle::autoRotation
753 If set to true then a rotation will be applied on top of the particles rotation, so
754 that it faces the direction of travel. So to face away from the direction of travel,
755 set autoRotation to true and rotation to 180.
760 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::xVector
762 Allows you to deform the particle image when drawn. The rectangular image will
763 be deformed so that the horizontal sides are in the shape of this vector instead
767 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::yVector
769 Allows you to deform the particle image when drawn. The rectangular image will
770 be deformed so that the vertical sides are in the shape of this vector instead
774 \qmlproperty EntryEffect QtQuick.Particles2::ImageParticle::entryEffect
776 This property provides basic and cheap entrance and exit effects for the particles.
777 For fine-grained control, see sizeTable and opacityTable.
779 Acceptable values are
781 \o None: Particles just appear and disappear.
782 \o Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
783 \o Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end.
786 Default value is Fade.
789 \qmlproperty bool QtQuick.Particles2::ImageParticle::spritesInterpolate
791 If set to true, sprite particles will interpolate between sprite frames each rendered frame, making
792 the sprites look smoother.
798 QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
799 : QQuickParticlePainter(parent)
800 , m_color_variation(0.0)
803 , m_alphaVariation(0.0)
805 , m_redVariation(0.0)
806 , m_greenVariation(0.0)
807 , m_blueVariation(0.0)
809 , m_rotationVariation(0)
811 , m_rotationSpeedVariation(0)
812 , m_autoRotation(false)
816 , m_spritesInterpolate(true)
817 , m_explicitColor(false)
818 , m_explicitRotation(false)
819 , m_explicitDeformation(false)
820 , m_explicitAnimation(false)
821 , m_bypassOptimizations(false)
823 , m_lastLevel(Unknown)
825 , m_entryEffect(Fade)
827 setFlag(ItemHasContents);
828 m_debugMode = qmlParticlesDebug();
831 QQuickImageParticle::~QQuickImageParticle()
835 QDeclarativeListProperty<QQuickSprite> QQuickImageParticle::sprites()
837 return QDeclarativeListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
840 void QQuickImageParticle::setImage(const QUrl &image)
842 if (image == m_image_name)
844 m_image_name = image;
850 void QQuickImageParticle::setColortable(const QUrl &table)
852 if (table == m_colortable_name)
854 m_colortable_name = table;
855 emit colortableChanged();
859 void QQuickImageParticle::setSizetable(const QUrl &table)
861 if (table == m_sizetable_name)
863 m_sizetable_name = table;
864 emit sizetableChanged();
868 void QQuickImageParticle::setOpacitytable(const QUrl &table)
870 if (table == m_opacitytable_name)
872 m_opacitytable_name = table;
873 emit opacitytableChanged();
877 void QQuickImageParticle::setColor(const QColor &color)
879 if (color == m_color)
883 m_explicitColor = true;
884 if (perfLevel < Colored)
888 void QQuickImageParticle::setColorVariation(qreal var)
890 if (var == m_color_variation)
892 m_color_variation = var;
893 emit colorVariationChanged();
894 m_explicitColor = true;
895 if (perfLevel < Colored)
899 void QQuickImageParticle::setAlphaVariation(qreal arg)
901 if (m_alphaVariation != arg) {
902 m_alphaVariation = arg;
903 emit alphaVariationChanged(arg);
905 m_explicitColor = true;
906 if (perfLevel < Colored)
910 void QQuickImageParticle::setAlpha(qreal arg)
912 if (m_alpha != arg) {
914 emit alphaChanged(arg);
916 m_explicitColor = true;
917 if (perfLevel < Colored)
921 void QQuickImageParticle::setRedVariation(qreal arg)
923 if (m_redVariation != arg) {
924 m_redVariation = arg;
925 emit redVariationChanged(arg);
927 m_explicitColor = true;
928 if (perfLevel < Colored)
932 void QQuickImageParticle::setGreenVariation(qreal arg)
934 if (m_greenVariation != arg) {
935 m_greenVariation = arg;
936 emit greenVariationChanged(arg);
938 m_explicitColor = true;
939 if (perfLevel < Colored)
943 void QQuickImageParticle::setBlueVariation(qreal arg)
945 if (m_blueVariation != arg) {
946 m_blueVariation = arg;
947 emit blueVariationChanged(arg);
949 m_explicitColor = true;
950 if (perfLevel < Colored)
954 void QQuickImageParticle::setRotation(qreal arg)
956 if (m_rotation != arg) {
958 emit rotationChanged(arg);
960 m_explicitRotation = true;
961 if (perfLevel < Deformable)
965 void QQuickImageParticle::setRotationVariation(qreal arg)
967 if (m_rotationVariation != arg) {
968 m_rotationVariation = arg;
969 emit rotationVariationChanged(arg);
971 m_explicitRotation = true;
972 if (perfLevel < Deformable)
976 void QQuickImageParticle::setRotationSpeed(qreal arg)
978 if (m_rotationSpeed != arg) {
979 m_rotationSpeed = arg;
980 emit rotationSpeedChanged(arg);
982 m_explicitRotation = true;
983 if (perfLevel < Deformable)
987 void QQuickImageParticle::setRotationSpeedVariation(qreal arg)
989 if (m_rotationSpeedVariation != arg) {
990 m_rotationSpeedVariation = arg;
991 emit rotationSpeedVariationChanged(arg);
993 m_explicitRotation = true;
994 if (perfLevel < Deformable)
998 void QQuickImageParticle::setAutoRotation(bool arg)
1000 if (m_autoRotation != arg) {
1001 m_autoRotation = arg;
1002 emit autoRotationChanged(arg);
1004 m_explicitRotation = true;
1005 if (perfLevel < Deformable)
1009 void QQuickImageParticle::setXVector(QQuickDirection* arg)
1011 if (m_xVector != arg) {
1013 emit xVectorChanged(arg);
1015 m_explicitDeformation = true;
1016 if (perfLevel < Deformable)
1020 void QQuickImageParticle::setYVector(QQuickDirection* arg)
1022 if (m_yVector != arg) {
1024 emit yVectorChanged(arg);
1026 m_explicitDeformation = true;
1027 if (perfLevel < Deformable)
1031 void QQuickImageParticle::setSpritesInterpolate(bool arg)
1033 if (m_spritesInterpolate != arg) {
1034 m_spritesInterpolate = arg;
1035 emit spritesInterpolateChanged(arg);
1039 void QQuickImageParticle::setBypassOptimizations(bool arg)
1041 if (m_bypassOptimizations != arg) {
1042 m_bypassOptimizations = arg;
1043 emit bypassOptimizationsChanged(arg);
1045 if (perfLevel < 9999)
1049 void QQuickImageParticle::setEntryEffect(EntryEffect arg)
1051 if (m_entryEffect != arg) {
1052 m_entryEffect = arg;
1054 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1055 emit entryEffectChanged(arg);
1059 void QQuickImageParticle::resetColor()
1061 m_explicitColor = false;
1062 foreach (const QString &str, m_groups)
1063 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1064 if (d->colorOwner == this)
1067 m_color_variation = 0.0f;
1068 m_redVariation = 0.0f;
1069 m_blueVariation = 0.0f;
1070 m_greenVariation = 0.0f;
1072 m_alphaVariation = 0.0f;
1075 void QQuickImageParticle::resetRotation()
1077 m_explicitRotation = false;
1078 foreach (const QString &str, m_groups)
1079 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1080 if (d->rotationOwner == this)
1081 d->rotationOwner = 0;
1083 m_rotationVariation = 0;
1084 m_rotationSpeed = 0;
1085 m_rotationSpeedVariation = 0;
1086 m_autoRotation = false;
1089 void QQuickImageParticle::resetDeformation()
1091 m_explicitDeformation = false;
1092 foreach (const QString &str, m_groups)
1093 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1094 if (d->deformationOwner == this)
1095 d->deformationOwner = 0;
1104 void QQuickImageParticle::reset()
1106 QQuickParticlePainter::reset();
1107 m_pleaseReset = true;
1111 void QQuickImageParticle::createEngine()
1114 delete m_spriteEngine;
1115 if (m_sprites.count()) {
1116 m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1117 connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1118 this, SLOT(spriteAdvance(int)));
1119 m_explicitAnimation = true;
1122 m_explicitAnimation = false;
1127 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
1128 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1129 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1130 QSGGeometry::Attribute::create(2, 4, GL_FLOAT) // Vectors
1133 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
1135 3, // Attribute Count
1136 ( 2 + 4 + 4 ) * sizeof(float),
1137 SimpleParticle_Attributes
1140 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
1141 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1142 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1143 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1144 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1147 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
1149 4, // Attribute Count
1150 ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1151 ColoredParticle_Attributes
1154 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
1155 QSGGeometry::Attribute::create(0, 4, GL_FLOAT), // Position & TexCoord
1156 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1157 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1158 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1159 QSGGeometry::Attribute::create(4, 4, GL_FLOAT), // DeformationVectors
1160 QSGGeometry::Attribute::create(5, 3, GL_FLOAT), // Rotation
1163 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1165 6, // Attribute Count
1166 (4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1167 DeformableParticle_Attributes
1170 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1171 QSGGeometry::Attribute::create(0, 4, GL_FLOAT), // Position & TexCoord
1172 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1173 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1174 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1175 QSGGeometry::Attribute::create(4, 4, GL_FLOAT), // DeformationVectors
1176 QSGGeometry::Attribute::create(5, 3, GL_FLOAT), // Rotation
1177 QSGGeometry::Attribute::create(6, 4, GL_FLOAT), // Anim Data
1178 QSGGeometry::Attribute::create(7, 4, GL_FLOAT) // Anim Pos
1181 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1183 8, // Attribute Count
1184 (4 + 4 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1185 SpriteParticle_Attributes
1188 void QQuickImageParticle::clearShadows()
1190 foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1192 m_shadowData.clear();
1195 //Only call if you need to, may initialize the whole array first time
1196 QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1198 QQuickParticleGroupData* gd = m_system->groupData[datum->group];
1199 if (!m_shadowData.contains(datum->group)) {
1200 QVector<QQuickParticleData*> data;
1201 for (int i=0; i<gd->size(); i++){
1202 QQuickParticleData* datum = new QQuickParticleData(m_system);
1203 *datum = *(gd->data[i]);
1206 m_shadowData.insert(datum->group, data);
1208 //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1210 return m_shadowData[datum->group][datum->index];
1213 QSGGeometryNode* QQuickImageParticle::buildParticleNodes()
1215 #ifdef QT_OPENGL_ES_2
1216 if (m_count * 4 > 0xffff) {
1217 printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1225 if (m_sprites.count() || m_bypassOptimizations) {
1226 perfLevel = Sprites;
1227 } else if (!m_colortable_name.isEmpty() || !m_sizetable_name.isEmpty()
1228 || !m_opacitytable_name.isEmpty()) {
1230 } else if (m_autoRotation || m_rotation || m_rotationVariation
1231 || m_rotationSpeed || m_rotationSpeedVariation
1232 || m_xVector || m_yVector) {
1233 perfLevel = Deformable;
1234 } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1235 || m_redVariation || m_blueVariation || m_greenVariation) {
1236 perfLevel = Colored;
1241 foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1242 int gIdx = m_system->groupIds[str];
1243 foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){
1244 QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1246 if (other->perfLevel > perfLevel) {
1247 if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1248 if (perfLevel < Deformable)
1249 perfLevel = Deformable;
1251 perfLevel = other->perfLevel;
1253 } else if (other->perfLevel < perfLevel) {
1260 if (perfLevel >= Colored && !m_color.isValid())
1261 m_color = QColor(Qt::white);//Hidden default, but different from unset
1264 if (perfLevel >= Sprites){
1265 if (!m_spriteEngine) {
1266 qWarning() << "ImageParticle: No sprite engine...";
1267 //Sprite performance mode with static image is supported, but not advised
1268 //Note that in this case it always uses shadow data
1270 image = m_spriteEngine->assembledImage();
1271 if (image.isNull())//Warning is printed in engine
1276 if ( image.isNull() ) {
1277 image = QImage(m_image_name.toLocalFile());
1278 if (image.isNull()) {
1279 printf("ImageParticle: loading image failed '%s'\n", qPrintable(m_image_name.toLocalFile()));
1291 QImage opacitytable;
1292 switch (perfLevel) {//Fallthrough intended
1294 m_material = SpriteMaterial::createMaterial();
1295 getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1297 m_spriteEngine->setCount(m_count);
1300 m_material = TabledMaterial::createMaterial();
1301 colortable = QImage(m_colortable_name.toLocalFile());
1302 sizetable = QImage(m_sizetable_name.toLocalFile());
1303 opacitytable = QImage(m_opacitytable_name.toLocalFile());
1304 if (colortable.isNull()){
1305 colortable = QImage(1,1,QImage::Format_ARGB32);
1306 colortable.fill(Qt::white);
1308 Q_ASSERT(!colortable.isNull());
1309 getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1310 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1311 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1314 m_material = DeformableMaterial::createMaterial();
1317 m_material = ColoredMaterial::createMaterial();
1318 default://Also Simple
1320 m_material = SimpleMaterial::createMaterial();
1321 getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1322 getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1323 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1324 m_material->setFlag(QSGMaterial::Blending);
1328 foreach (const QString &str, m_groups){
1329 int gIdx = m_system->groupIds[str];
1330 int count = m_system->groupData[gIdx]->size();
1331 QSGGeometryNode* node = new QSGGeometryNode();
1332 node->setMaterial(m_material);
1333 node->markDirty(QSGNode::DirtyMaterial);
1335 m_nodes.insert(gIdx, node);
1336 m_idxStarts.insert(gIdx, m_lastIdxStart);
1337 m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx));
1338 m_lastIdxStart += count;
1340 //Create Particle Geometry
1341 int vCount = count * 4;
1342 int iCount = count * 6;
1345 if (perfLevel == Sprites)
1346 g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1347 else if (perfLevel == Tabled)
1348 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1349 else if (perfLevel == Deformable)
1350 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1351 else if (perfLevel == Colored)
1352 g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1354 g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1356 node->setGeometry(g);
1357 if (perfLevel <= Colored){
1358 g->setDrawingMode(GL_POINTS);
1360 GLfloat pointSizeRange[2];
1361 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1362 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1365 g->setDrawingMode(GL_TRIANGLES);
1367 for (int p=0; p < count; ++p)
1368 commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1370 if (perfLevel == Sprites)
1371 initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1372 else if (perfLevel == Tabled)
1373 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1374 else if (perfLevel == Deformable)
1375 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1377 if (perfLevel > Colored){
1378 quint16 *indices = g->indexDataAsUShort();
1379 for (int i=0; i < count; ++i) {
1393 foreach (QSGGeometryNode* node, m_nodes){
1394 if (node == *(m_nodes.begin()))
1395 node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1397 (*(m_nodes.begin()))->appendChildNode(node);
1400 return *(m_nodes.begin());
1403 QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1406 m_lastLevel = perfLevel;
1408 delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1412 m_idxStarts.clear();
1413 m_startsIdx.clear();
1418 m_pleaseReset = false;
1421 if (m_system && m_system->isRunning() && !m_system->isPaused()){
1425 foreach (QSGGeometryNode* node, m_nodes)
1426 node->markDirty(QSGNode::DirtyGeometry);
1433 void QQuickImageParticle::prepareNextFrame()
1435 if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1436 m_rootNode = buildParticleNodes();
1438 qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1439 qDebug() << "QQuickImageParticle Nodes: ";
1441 foreach (int i, m_nodes.keys()) {
1442 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1443 count += m_system->groupData[i]->size();
1445 qDebug() << "Total count: " << count;
1447 if (m_rootNode == 0)
1450 qint64 timeStamp = m_system->systemSync(this);
1452 qreal time = timeStamp / 1000.;
1454 switch (perfLevel){//Fall-through intended
1458 m_spriteEngine->updateSprites(timeStamp);
1463 default: //Also Simple
1464 getState<ImageMaterialData>(m_material)->timestamp = time;
1467 foreach (QSGGeometryNode* node, m_nodes)
1468 node->markDirty(QSGNode::DirtyMaterial);
1471 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1473 if (!m_startsIdx.count())//Probably overly defensive
1478 for (i = 0; i<m_startsIdx.count(); i++) {
1479 if (spriteIdx < m_startsIdx[i].first) {
1480 gIdx = m_startsIdx[i-1].second;
1485 gIdx = m_startsIdx[i-1].second;
1486 int pIdx = spriteIdx - m_startsIdx[i-1].first;
1488 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1489 QQuickParticleData* d = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1491 d->animIdx = m_spriteEngine->spriteState(spriteIdx);
1492 Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData();
1493 Vertices<SpriteVertex> &p = particles[pIdx];
1494 d->animT = p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1495 d->frameCount = p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1496 d->frameDuration = p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1497 d->animX = p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx);
1498 d->animY = p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx);
1499 d->animWidth = p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1500 d->animHeight = p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1503 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1506 //TODO: get index for reload - or make function take an index
1509 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1512 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1513 qreal redVariation = m_color_variation + m_redVariation;
1514 qreal greenVariation = m_color_variation + m_greenVariation;
1515 qreal blueVariation = m_color_variation + m_blueVariation;
1517 if (m_spriteEngine) {
1518 spriteIdx = m_idxStarts[gIdx] + datum->index;
1519 if (spriteIdx >= m_spriteEngine->count())
1520 m_spriteEngine->setCount(spriteIdx+1);
1524 float rotationSpeed;
1526 switch (perfLevel){//Fall-through is intended on all of them
1528 // Initial Sprite State
1529 if (m_explicitAnimation && m_spriteEngine){
1530 if (!datum->animationOwner)
1531 datum->animationOwner = this;
1532 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1533 writeTo->animT = writeTo->t;
1534 //writeTo->animInterpolate = m_spritesInterpolate;
1535 if (m_spriteEngine){
1536 m_spriteEngine->start(spriteIdx);
1537 writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1538 writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1539 writeTo->animIdx = 0;//Always starts at 0
1540 writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1541 writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1542 writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1543 writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1546 QQuickParticleData* writeTo = getShadowDatum(datum);
1547 writeTo->animT = datum->t;
1548 writeTo->frameCount = 1;
1549 writeTo->frameDuration = 60000000.0;
1550 writeTo->animIdx = 0;
1552 writeTo->animX = writeTo->animY = 0;
1553 writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
1554 writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
1559 if (m_explicitDeformation){
1560 if (!datum->deformationOwner)
1561 datum->deformationOwner = this;
1563 const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1564 if (datum->deformationOwner == this) {
1565 datum->xx = ret.x();
1566 datum->xy = ret.y();
1568 getShadowDatum(datum)->xx = ret.x();
1569 getShadowDatum(datum)->xy = ret.y();
1573 const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1574 if (datum->deformationOwner == this) {
1575 datum->yx = ret.x();
1576 datum->yy = ret.y();
1578 getShadowDatum(datum)->yx = ret.x();
1579 getShadowDatum(datum)->yy = ret.y();
1584 if (m_explicitRotation){
1585 if (!datum->rotationOwner)
1586 datum->rotationOwner = this;
1588 (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1590 (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1591 autoRotate = m_autoRotation?1.0:0.0;
1592 if (datum->rotationOwner == this) {
1593 datum->rotation = rotation;
1594 datum->rotationSpeed = rotationSpeed;
1595 datum->autoRotate = autoRotate;
1597 getShadowDatum(datum)->rotation = rotation;
1598 getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1599 getShadowDatum(datum)->autoRotate = autoRotate;
1603 //Color initialization
1605 if (m_explicitColor) {
1606 if (!datum->colorOwner)
1607 datum->colorOwner = this;
1608 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1609 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1610 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1611 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1612 if (datum->colorOwner == this)
1613 datum->color = color;
1615 getShadowDatum(datum)->color = color;
1622 void QQuickImageParticle::commit(int gIdx, int pIdx)
1626 QSGGeometryNode *node = m_nodes[gIdx];
1629 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1630 node->setFlag(QSGNode::OwnsGeometry, false);
1631 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1632 DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1633 ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1634 SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1635 switch (perfLevel){//No automatic fall through intended on this one
1637 spriteVertices += pIdx*4;
1638 for (int i=0; i<4; i++){
1639 spriteVertices[i].x = datum->x - m_systemOffset.x();
1640 spriteVertices[i].y = datum->y - m_systemOffset.y();
1641 spriteVertices[i].t = datum->t;
1642 spriteVertices[i].lifeSpan = datum->lifeSpan;
1643 spriteVertices[i].size = datum->size;
1644 spriteVertices[i].endSize = datum->endSize;
1645 spriteVertices[i].vx = datum->vx;
1646 spriteVertices[i].vy = datum->vy;
1647 spriteVertices[i].ax = datum->ax;
1648 spriteVertices[i].ay = datum->ay;
1649 if (m_explicitDeformation && datum->deformationOwner != this) {
1650 QQuickParticleData* shadow = getShadowDatum(datum);
1651 spriteVertices[i].xx = shadow->xx;
1652 spriteVertices[i].xy = shadow->xy;
1653 spriteVertices[i].yx = shadow->yx;
1654 spriteVertices[i].yy = shadow->yy;
1656 spriteVertices[i].xx = datum->xx;
1657 spriteVertices[i].xy = datum->xy;
1658 spriteVertices[i].yx = datum->yx;
1659 spriteVertices[i].yy = datum->yy;
1661 if (m_explicitRotation && datum->rotationOwner != this) {
1662 QQuickParticleData* shadow = getShadowDatum(datum);
1663 spriteVertices[i].rotation = shadow->rotation;
1664 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1665 spriteVertices[i].autoRotate = shadow->autoRotate;
1667 spriteVertices[i].rotation = datum->rotation;
1668 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1669 spriteVertices[i].autoRotate = datum->autoRotate;
1671 spriteVertices[i].animInterpolate = m_spriteEngine ? (m_spritesInterpolate ? 1.0 : 0.0) : 0.0;//### Shadow? In particleData? Or uniform?
1672 if (!m_spriteEngine || (m_explicitAnimation && datum->animationOwner != this)) {
1673 QQuickParticleData* shadow = getShadowDatum(datum);
1674 spriteVertices[i].frameDuration = shadow->frameDuration;
1675 spriteVertices[i].frameCount = shadow->frameCount;
1676 spriteVertices[i].animT = shadow->animT;
1677 spriteVertices[i].animX = shadow->animX;
1678 spriteVertices[i].animY = shadow->animY;
1679 spriteVertices[i].animWidth = shadow->animWidth;
1680 spriteVertices[i].animHeight = shadow->animHeight;
1682 spriteVertices[i].frameDuration = datum->frameDuration;
1683 spriteVertices[i].frameCount = datum->frameCount;
1684 spriteVertices[i].animT = datum->animT;
1685 spriteVertices[i].animX = datum->animX;
1686 spriteVertices[i].animY = datum->animY;
1687 spriteVertices[i].animWidth = datum->animWidth;
1688 spriteVertices[i].animHeight = datum->animHeight;
1690 if (m_explicitColor && datum->colorOwner != this) {
1691 QQuickParticleData* shadow = getShadowDatum(datum);
1692 spriteVertices[i].color.r = shadow->color.r;
1693 spriteVertices[i].color.g = shadow->color.g;
1694 spriteVertices[i].color.b = shadow->color.b;
1695 spriteVertices[i].color.a = shadow->color.a;
1697 spriteVertices[i].color.r = datum->color.r;
1698 spriteVertices[i].color.g = datum->color.g;
1699 spriteVertices[i].color.b = datum->color.b;
1700 spriteVertices[i].color.a = datum->color.a;
1704 case Tabled: //Fall through until it has its own vertex class
1706 deformableVertices += pIdx*4;
1707 for (int i=0; i<4; i++){
1708 deformableVertices[i].x = datum->x - m_systemOffset.x();
1709 deformableVertices[i].y = datum->y - m_systemOffset.y();
1710 deformableVertices[i].t = datum->t;
1711 deformableVertices[i].lifeSpan = datum->lifeSpan;
1712 deformableVertices[i].size = datum->size;
1713 deformableVertices[i].endSize = datum->endSize;
1714 deformableVertices[i].vx = datum->vx;
1715 deformableVertices[i].vy = datum->vy;
1716 deformableVertices[i].ax = datum->ax;
1717 deformableVertices[i].ay = datum->ay;
1718 if (m_explicitDeformation && datum->deformationOwner != this) {
1719 QQuickParticleData* shadow = getShadowDatum(datum);
1720 deformableVertices[i].xx = shadow->xx;
1721 deformableVertices[i].xy = shadow->xy;
1722 deformableVertices[i].yx = shadow->yx;
1723 deformableVertices[i].yy = shadow->yy;
1725 deformableVertices[i].xx = datum->xx;
1726 deformableVertices[i].xy = datum->xy;
1727 deformableVertices[i].yx = datum->yx;
1728 deformableVertices[i].yy = datum->yy;
1730 if (m_explicitRotation && datum->rotationOwner != this) {
1731 QQuickParticleData* shadow = getShadowDatum(datum);
1732 deformableVertices[i].rotation = shadow->rotation;
1733 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1734 deformableVertices[i].autoRotate = shadow->autoRotate;
1736 deformableVertices[i].rotation = datum->rotation;
1737 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1738 deformableVertices[i].autoRotate = datum->autoRotate;
1740 if (m_explicitColor && datum->colorOwner != this) {
1741 QQuickParticleData* shadow = getShadowDatum(datum);
1742 deformableVertices[i].color.r = shadow->color.r;
1743 deformableVertices[i].color.g = shadow->color.g;
1744 deformableVertices[i].color.b = shadow->color.b;
1745 deformableVertices[i].color.a = shadow->color.a;
1747 deformableVertices[i].color.r = datum->color.r;
1748 deformableVertices[i].color.g = datum->color.g;
1749 deformableVertices[i].color.b = datum->color.b;
1750 deformableVertices[i].color.a = datum->color.a;
1755 coloredVertices += pIdx*1;
1756 for (int i=0; i<1; i++){
1757 coloredVertices[i].x = datum->x - m_systemOffset.x();
1758 coloredVertices[i].y = datum->y - m_systemOffset.y();
1759 coloredVertices[i].t = datum->t;
1760 coloredVertices[i].lifeSpan = datum->lifeSpan;
1761 coloredVertices[i].size = datum->size;
1762 coloredVertices[i].endSize = datum->endSize;
1763 coloredVertices[i].vx = datum->vx;
1764 coloredVertices[i].vy = datum->vy;
1765 coloredVertices[i].ax = datum->ax;
1766 coloredVertices[i].ay = datum->ay;
1767 if (m_explicitColor && datum->colorOwner != this) {
1768 QQuickParticleData* shadow = getShadowDatum(datum);
1769 coloredVertices[i].color.r = shadow->color.r;
1770 coloredVertices[i].color.g = shadow->color.g;
1771 coloredVertices[i].color.b = shadow->color.b;
1772 coloredVertices[i].color.a = shadow->color.a;
1774 coloredVertices[i].color.r = datum->color.r;
1775 coloredVertices[i].color.g = datum->color.g;
1776 coloredVertices[i].color.b = datum->color.b;
1777 coloredVertices[i].color.a = datum->color.a;
1782 simpleVertices += pIdx*1;
1783 for (int i=0; i<1; i++){
1784 simpleVertices[i].x = datum->x - m_systemOffset.x();
1785 simpleVertices[i].y = datum->y - m_systemOffset.y();
1786 simpleVertices[i].t = datum->t;
1787 simpleVertices[i].lifeSpan = datum->lifeSpan;
1788 simpleVertices[i].size = datum->size;
1789 simpleVertices[i].endSize = datum->endSize;
1790 simpleVertices[i].vx = datum->vx;
1791 simpleVertices[i].vy = datum->vy;
1792 simpleVertices[i].ax = datum->ax;
1793 simpleVertices[i].ay = datum->ay;
1800 node->setFlag(QSGNode::OwnsGeometry, true);