1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Declarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <private/qsgcontext_p.h>
43 #include <private/qsgadaptationlayer_p.h>
45 #include <qsgtexturematerial.h>
46 #include <qsgtexture.h>
48 #include "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 <qsgengine.h>
54 #include <private/qsgtexture_p.h>
57 //###Switch to define later, for now user-friendly (no compilation) debugging is worth it
58 DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG)
60 #ifndef QT_OPENGL_ES_2
61 #define SHADER_DEFINES "#version 120\n"
63 #define SHADER_DEFINES ""
66 //TODO: Make it larger on desktop? Requires fixing up shader code with the same define
67 #define UNIFORM_ARRAY_SIZE 64
69 static const char vertexShaderCode[] =
70 "attribute highp vec2 vPos;\n"
71 "attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize\n"
72 "attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration\n"
73 "uniform highp float entry;\n"
75 "attribute lowp vec4 vColor;\n"
78 "attribute highp vec2 vTex;\n"
79 "attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector\n"
80 "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate\n"
83 "attribute highp vec4 vAnimData;// interpolate(bool), duration, frameCount (this anim), timestamp (this anim)\n"
84 "attribute highp vec4 vAnimPos;//sheet x,y, width/height of this anim\n"
85 "uniform highp vec2 animSheetSize; //width/height of whole sheet\n"
88 "uniform highp mat4 qt_Matrix;\n"
89 "uniform highp float timestamp;\n"
91 "varying lowp vec2 tt;//y is progress if Sprite mode\n"
92 "uniform highp float sizetable[64];\n"
93 "uniform highp float opacitytable[64];\n"
96 "varying highp vec4 fTexS;\n"
99 "varying highp vec2 fTex;\n"
103 "varying lowp vec4 fColor;\n"
105 "varying lowp float fFade;\n"
111 " highp float t = (timestamp - vData.x) / vData.y;\n"
112 " if (t < 0. || t > 1.){\n"
113 "#ifdef DEFORM //Not point sprites\n"
114 " gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0., 1.);\n"
116 " gl_PointSize = 0.;\n"
121 " //Calculate frame location in texture\n"
122 " highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);\n"
123 " tt.y = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;\n"
125 " frameIndex = floor(frameIndex);\n"
126 " fTexS.xy = vec2(((frameIndex + vTex.x) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vTex.y * vAnimPos.w) / animSheetSize.y));\n"
128 " //Next frame is also passed, for interpolation\n"
129 " //### Should the next anim be precalculated to allow for interpolation there?\n"
130 " if (vAnimData.x == 1.0 && frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop\n"
131 " frameIndex = mod(frameIndex+1., vAnimData.z);\n"
132 " fTexS.zw = vec2(((frameIndex + vTex.x) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vTex.y * vAnimPos.w) / animSheetSize.y));\n"
138 " highp float currentSize = mix(vData.z, vData.w, t * t);\n"
139 " lowp float fade = 1.;\n"
140 " highp float fadeIn = min(t * 10., 1.);\n"
141 " highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);\n"
144 " currentSize = currentSize * sizetable[int(floor(t*64.))];\n"
145 " fade = fade * opacitytable[int(floor(t*64.))];\n"
148 " if (entry == 1.)\n"
149 " fade = fade * fadeIn * fadeOut;\n"
150 " else if (entry == 2.)\n"
151 " currentSize = currentSize * fadeIn * fadeOut;\n"
153 " if (currentSize <= 0.){\n"
154 "#ifdef DEFORM //Not point sprites\n"
155 " gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0., 1.);\n"
157 " gl_PointSize = 0.;\n"
161 " if (currentSize < 3.)//Sizes too small look jittery as they move\n"
162 " currentSize = 3.;\n"
166 " highp float rotation = vRotation.x + vRotation.y * t * vData.y;\n"
167 " if (vRotation.z == 1.0){\n"
168 " highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;\n"
169 " rotation += atan(curVel.y, curVel.x);\n"
171 " highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));\n"
172 " highp vec4 deform = vDeformVec * currentSize * (vTex.xxyy - 0.5);\n"
173 " highp vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;\n"
174 " rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));\n"
175 " /* The readable version:\n"
176 " highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);\n"
177 " highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);\n"
178 " highp vec2 xRotatedDeform;\n"
179 " xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;\n"
180 " xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;\n"
181 " highp vec2 yRotatedDeform;\n"
182 " yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;\n"
183 " yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;\n"
186 " + rotatedDeform.xy\n"
187 " + rotatedDeform.zw\n"
188 " + vVec.xy * t * vData.y // apply speed\n"
189 " + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration\n"
192 " + vVec.xy * t * vData.y // apply speed vector..\n"
193 " + 0.5 * vVec.zw * pow(t * vData.y, 2.);\n"
194 " gl_PointSize = currentSize;\n"
196 " gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);\n"
199 " fColor = vColor * fade;\n"
208 static const char fragmentShaderCode[] =
209 "uniform sampler2D texture;\n"
210 "uniform lowp float qt_Opacity;\n"
213 "varying highp vec4 fTexS;\n"
215 "#ifdef DEFORM //First non-pointsprite\n"
216 "varying highp vec2 fTex;\n"
220 "varying lowp vec4 fColor;\n"
222 "varying lowp float fFade;\n"
225 "varying lowp vec2 tt;\n"
226 "uniform sampler2D colortable;\n"
231 " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), tt.y)\n"
233 " * texture2D(colortable, tt)\n"
237 " gl_FragColor = texture2D(texture, fTex)\n"
239 " * texture2D(colortable, tt)\n"
243 " gl_FragColor = (texture2D(texture, fTex)) * fColor * qt_Opacity;\n"
246 " gl_FragColor = (texture2D(texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
248 " gl_FragColor = texture2D(texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
255 const qreal CONV = 0.017453292519943295;
256 class ImageMaterialData
260 : texture(0), colorTable(0)
263 ~ImageMaterialData(){
269 QSGTexture *colorTable;
270 float sizeTable[UNIFORM_ARRAY_SIZE];
271 float opacityTable[UNIFORM_ARRAY_SIZE];
275 QSizeF animSheetSize;
278 class TabledMaterialData : public ImageMaterialData {};
279 class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
281 QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
286 m_vertex_code = QByteArray(SHADER_DEFINES)
287 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
290 m_fragment_code = QByteArray(SHADER_DEFINES)
291 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
292 + fragmentShaderCode;
294 Q_ASSERT(!m_vertex_code.isNull());
295 Q_ASSERT(!m_fragment_code.isNull());
298 const char *vertexShader() const { return m_vertex_code.constData(); }
299 const char *fragmentShader() const { return m_fragment_code.constData(); }
301 QList<QByteArray> attributes() const {
302 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
303 << "vColor" << "vDeformVec" << "vRotation";
307 QSGSimpleMaterialShader<TabledMaterialData>::initialize();
309 program()->setUniformValue("texture", 0);
310 program()->setUniformValue("colortable", 1);
311 glFuncs = QOpenGLContext::currentContext()->functions();
312 m_timestamp_id = program()->uniformLocation("timestamp");
313 m_entry_id = program()->uniformLocation("entry");
314 m_sizetable_id = program()->uniformLocation("sizetable");
315 m_opacitytable_id = program()->uniformLocation("opacitytable");
318 void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
319 glFuncs->glActiveTexture(GL_TEXTURE1);
320 d->colorTable->bind();
322 glFuncs->glActiveTexture(GL_TEXTURE0);
325 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
326 program()->setUniformValue(m_entry_id, (float) d->entry);
327 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1);
328 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
334 int m_opacitytable_id;
335 QByteArray m_vertex_code;
336 QByteArray m_fragment_code;
337 QOpenGLFunctions* glFuncs;
340 class DeformableMaterialData : public ImageMaterialData {};
341 class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData>
343 QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData)
348 m_vertex_code = QByteArray(SHADER_DEFINES)
349 + QByteArray("#define DEFORM\n#define COLOR\n")
352 m_fragment_code = QByteArray(SHADER_DEFINES)
353 + QByteArray("#define DEFORM\n#define COLOR\n")
354 + fragmentShaderCode;
356 Q_ASSERT(!m_vertex_code.isNull());
357 Q_ASSERT(!m_fragment_code.isNull());
360 const char *vertexShader() const { return m_vertex_code.constData(); }
361 const char *fragmentShader() const { return m_fragment_code.constData(); }
363 QList<QByteArray> attributes() const {
364 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
365 << "vColor" << "vDeformVec" << "vRotation";
369 QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
371 program()->setUniformValue("texture", 0);
372 glFuncs = QOpenGLContext::currentContext()->functions();
373 m_timestamp_id = program()->uniformLocation("timestamp");
374 m_entry_id = program()->uniformLocation("entry");
377 void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) {
378 glFuncs->glActiveTexture(GL_TEXTURE0);
381 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
382 program()->setUniformValue(m_entry_id, (float) d->entry);
387 QByteArray m_vertex_code;
388 QByteArray m_fragment_code;
389 QOpenGLFunctions* glFuncs;
392 class SpriteMaterialData : public ImageMaterialData {};
393 class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
395 QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData)
400 m_vertex_code = QByteArray(SHADER_DEFINES)
401 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
404 m_fragment_code = QByteArray(SHADER_DEFINES)
405 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
406 + fragmentShaderCode;
408 Q_ASSERT(!m_vertex_code.isNull());
409 Q_ASSERT(!m_fragment_code.isNull());
412 const char *vertexShader() const { return m_vertex_code.constData(); }
413 const char *fragmentShader() const { return m_fragment_code.constData(); }
415 QList<QByteArray> attributes() const {
416 return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
417 << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
421 QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
423 program()->setUniformValue("texture", 0);
424 program()->setUniformValue("colortable", 1);
425 glFuncs = QOpenGLContext::currentContext()->functions();
426 m_timestamp_id = program()->uniformLocation("timestamp");
427 m_animsize_id = program()->uniformLocation("animSheetSize");
428 m_entry_id = program()->uniformLocation("entry");
429 m_sizetable_id = program()->uniformLocation("sizetable");
430 m_opacitytable_id = program()->uniformLocation("opacitytable");
433 void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) {
434 glFuncs->glActiveTexture(GL_TEXTURE1);
435 d->colorTable->bind();
437 // make sure we end by setting GL_TEXTURE0 as active texture
438 glFuncs->glActiveTexture(GL_TEXTURE0);
441 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
442 program()->setUniformValue(m_animsize_id, d->animSheetSize);
443 program()->setUniformValue(m_entry_id, (float) d->entry);
444 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, 64, 1);
445 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
452 int m_opacitytable_id;
453 QByteArray m_vertex_code;
454 QByteArray m_fragment_code;
455 QOpenGLFunctions* glFuncs;
458 class ColoredMaterialData : public ImageMaterialData {};
459 class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
461 QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData)
466 m_vertex_code = QByteArray(SHADER_DEFINES)
467 + QByteArray("#define COLOR\n")
470 m_fragment_code = QByteArray(SHADER_DEFINES)
471 + QByteArray("#define COLOR\n")
472 + fragmentShaderCode;
474 Q_ASSERT(!m_vertex_code.isNull());
475 Q_ASSERT(!m_fragment_code.isNull());
478 const char *vertexShader() const { return m_vertex_code.constData(); }
479 const char *fragmentShader() const { return m_fragment_code.constData(); }
482 QSGSimpleMaterialShader<ColoredMaterialData>::activate();
483 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
484 glEnable(GL_POINT_SPRITE);
485 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
490 QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
491 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
492 glDisable(GL_POINT_SPRITE);
493 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
497 QList<QByteArray> attributes() const {
498 return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
502 QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
504 program()->setUniformValue("texture", 0);
505 glFuncs = QOpenGLContext::currentContext()->functions();
506 m_timestamp_id = program()->uniformLocation("timestamp");
507 m_entry_id = program()->uniformLocation("entry");
510 void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) {
511 glFuncs->glActiveTexture(GL_TEXTURE0);
514 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
515 program()->setUniformValue(m_entry_id, (float) d->entry);
520 QByteArray m_vertex_code;
521 QByteArray m_fragment_code;
522 QOpenGLFunctions* glFuncs;
525 class SimpleMaterialData : public ImageMaterialData {};
526 class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
528 QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData)
533 m_vertex_code = QByteArray(SHADER_DEFINES)
536 m_fragment_code = QByteArray(SHADER_DEFINES)
537 + fragmentShaderCode;
539 Q_ASSERT(!m_vertex_code.isNull());
540 Q_ASSERT(!m_fragment_code.isNull());
543 const char *vertexShader() const { return m_vertex_code.constData(); }
544 const char *fragmentShader() const { return m_fragment_code.constData(); }
547 QSGSimpleMaterialShader<SimpleMaterialData>::activate();
548 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
549 glEnable(GL_POINT_SPRITE);
550 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
555 QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
556 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
557 glDisable(GL_POINT_SPRITE);
558 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
562 QList<QByteArray> attributes() const {
563 return QList<QByteArray>() << "vPos" << "vData" << "vVec";
567 QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
569 program()->setUniformValue("texture", 0);
570 glFuncs = QOpenGLContext::currentContext()->functions();
571 m_timestamp_id = program()->uniformLocation("timestamp");
572 m_entry_id = program()->uniformLocation("entry");
575 void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) {
576 glFuncs->glActiveTexture(GL_TEXTURE0);
579 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
580 program()->setUniformValue(m_entry_id, (float) d->entry);
585 QByteArray m_vertex_code;
586 QByteArray m_fragment_code;
587 QOpenGLFunctions* glFuncs;
590 void fillUniformArrayFromImage(float* array, const QImage& img, int size)
593 for (int i=0; i<size; i++)
597 QImage scaled = img.scaled(size,1);
598 for (int i=0; i<size; i++)
599 array[i] = qAlpha(scaled.pixel(i,0))/255.0;
603 \qmlclass ImageParticle QQuickImageParticle
604 \inqmlmodule QtQuick.Particles 2
605 \inherits ParticlePainter
606 \brief The ImageParticle element visualizes logical particles using an image
608 This element renders a logical particle as an image. The image can be
613 \o a sprite-based animation
616 ImageParticles implictly share data on particles if multiple ImageParticles are painting
617 the same logical particle group. This is broken down along the four capabilities listed
618 above. So if one ImageParticle defines data for rendering the particles in one of those
619 capabilities, and the other does not, then both will draw the particles the same in that
620 aspect automatically. This is primarily useful when there is some random variation on
621 the particle which is supposed to stay with it when switching painters. If both ImageParticles
622 define how they should appear for that aspect, they diverge and each appears as it is defined.
624 This sharing of data happens behind the scenes based off of whether properties were implicitly or explicitly
625 set. One drawback of the current implementation is that it is only possible to reset the capabilities as a whole.
626 So if you explicity set an attribute affecting color, such as redVariation, and then reset it (by setting redVariation
627 to undefined), all color data will be reset and it will begin to have an implicit value of any shared color from
628 other ImageParticles.
631 \qmlproperty url QtQuick.Particles2::ImageParticle::source
633 The source image to be used.
635 If the image is a sprite animation, use the sprite property instead.
638 \qmlproperty list<Sprite> QtQuick.Particles2::ImageParticle::sprites
640 The sprite or sprites used to draw this particle.
642 Note that the sprite image will be scaled to a square based on the size of
643 the particle being rendered.
646 \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable
648 An image whose color will be used as a 1D texture to determine color over life. E.g. when
649 the particle is halfway through its lifetime, it will have the color specified halfway
652 This color is blended with the color property and the color of the source image.
655 \qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
657 An image whose opacity will be used as a 1D texture to determine size over life.
659 This property is expected to be removed shortly, in favor of custom easing curves to determine size over life.
662 \qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
664 An image whose opacity will be used as a 1D texture to determine size over life.
666 This property is expected to be removed shortly, in favor of custom easing curves to determine opacity over life.
669 \qmlproperty color QtQuick.Particles2::ImageParticle::color
671 If a color is specified, the provided image will be colorized with it.
673 Default is white (no change).
676 \qmlproperty real QtQuick.Particles2::ImageParticle::colorVariation
678 This number represents the color variation applied to individual particles.
679 Setting colorVariation is the same as setting redVariation, greenVariation,
680 and blueVariation to the same number.
682 Each channel can vary between particle by up to colorVariation from its usual color.
684 Color is measured, per channel, from 0.0 to 1.0.
689 \qmlproperty real QtQuick.Particles2::ImageParticle::redVariation
690 The variation in the red color channel between particles.
692 Color is measured, per channel, from 0.0 to 1.0.
697 \qmlproperty real QtQuick.Particles2::ImageParticle::greenVariation
698 The variation in the green color channel between particles.
700 Color is measured, per channel, from 0.0 to 1.0.
705 \qmlproperty real QtQuick.Particles2::ImageParticle::blueVariation
706 The variation in the blue color channel between particles.
708 Color is measured, per channel, from 0.0 to 1.0.
713 \qmlproperty real QtQuick.Particles2::ImageParticle::alpha
714 An alpha to be applied to the image. This value is multiplied by the value in
715 the image, and the value in the color property.
717 Particles have additive blending, so lower alpha on single particles leads
718 to stronger effects when multiple particles overlap.
720 Alpha is measured from 0.0 to 1.0.
725 \qmlproperty real QtQuick.Particles2::ImageParticle::alphaVariation
726 The variation in the alpha channel between particles.
728 Alpha is measured from 0.0 to 1.0.
733 \qmlproperty real QtQuick.Particles2::ImageParticle::rotation
735 If set the image will be rotated by this many degrees before it is drawn.
737 The particle coordinates are not transformed.
740 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationVariation
742 If set the rotation of individual particles will vary by up to this much
747 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeed
749 If set particles will rotate at this speed in degrees/second.
752 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeedVariation
754 If set the rotationSpeed of individual particles will vary by up to this much
759 \qmlproperty bool QtQuick.Particles2::ImageParticle::autoRotation
761 If set to true then a rotation will be applied on top of the particles rotation, so
762 that it faces the direction of travel. So to face away from the direction of travel,
763 set autoRotation to true and rotation to 180.
768 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::xVector
770 Allows you to deform the particle image when drawn. The rectangular image will
771 be deformed so that the horizontal sides are in the shape of this vector instead
775 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::yVector
777 Allows you to deform the particle image when drawn. The rectangular image will
778 be deformed so that the vertical sides are in the shape of this vector instead
782 \qmlproperty EntryEffect QtQuick.Particles2::ImageParticle::entryEffect
784 This property provides basic and cheap entrance and exit effects for the particles.
785 For fine-grained control, see sizeTable and opacityTable.
787 Acceptable values are
789 \o None: Particles just appear and disappear.
790 \o Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
791 \o Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end.
794 Default value is Fade.
797 \qmlproperty bool QtQuick.Particles2::ImageParticle::spritesInterpolate
799 If set to true, sprite particles will interpolate between sprite frames each rendered frame, making
800 the sprites look smoother.
806 QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
807 : QQuickParticlePainter(parent)
808 , m_color_variation(0.0)
811 , m_alphaVariation(0.0)
813 , m_redVariation(0.0)
814 , m_greenVariation(0.0)
815 , m_blueVariation(0.0)
817 , m_rotationVariation(0)
819 , m_rotationSpeedVariation(0)
820 , m_autoRotation(false)
824 , m_spritesInterpolate(true)
825 , m_explicitColor(false)
826 , m_explicitRotation(false)
827 , m_explicitDeformation(false)
828 , m_explicitAnimation(false)
831 , m_lastLevel(Unknown)
833 , m_entryEffect(Fade)
835 setFlag(ItemHasContents);
836 m_debugMode = qmlParticlesDebug();
839 QQuickImageParticle::~QQuickImageParticle()
843 QDeclarativeListProperty<QQuickSprite> QQuickImageParticle::sprites()
845 return QDeclarativeListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
848 void QQuickImageParticle::setImage(const QUrl &image)
850 if (image == m_image_name)
852 m_image_name = image;
858 void QQuickImageParticle::setColortable(const QUrl &table)
860 if (table == m_colortable_name)
862 m_colortable_name = table;
863 emit colortableChanged();
867 void QQuickImageParticle::setSizetable(const QUrl &table)
869 if (table == m_sizetable_name)
871 m_sizetable_name = table;
872 emit sizetableChanged();
876 void QQuickImageParticle::setOpacitytable(const QUrl &table)
878 if (table == m_opacitytable_name)
880 m_opacitytable_name = table;
881 emit opacitytableChanged();
885 void QQuickImageParticle::setColor(const QColor &color)
887 if (color == m_color)
891 m_explicitColor = true;
892 if (perfLevel < Colored)
896 void QQuickImageParticle::setColorVariation(qreal var)
898 if (var == m_color_variation)
900 m_color_variation = var;
901 emit colorVariationChanged();
902 m_explicitColor = true;
903 if (perfLevel < Colored)
907 void QQuickImageParticle::setAlphaVariation(qreal arg)
909 if (m_alphaVariation != arg) {
910 m_alphaVariation = arg;
911 emit alphaVariationChanged(arg);
913 m_explicitColor = true;
914 if (perfLevel < Colored)
918 void QQuickImageParticle::setAlpha(qreal arg)
920 if (m_alpha != arg) {
922 emit alphaChanged(arg);
924 m_explicitColor = true;
925 if (perfLevel < Colored)
929 void QQuickImageParticle::setRedVariation(qreal arg)
931 if (m_redVariation != arg) {
932 m_redVariation = arg;
933 emit redVariationChanged(arg);
935 m_explicitColor = true;
936 if (perfLevel < Colored)
940 void QQuickImageParticle::setGreenVariation(qreal arg)
942 if (m_greenVariation != arg) {
943 m_greenVariation = arg;
944 emit greenVariationChanged(arg);
946 m_explicitColor = true;
947 if (perfLevel < Colored)
951 void QQuickImageParticle::setBlueVariation(qreal arg)
953 if (m_blueVariation != arg) {
954 m_blueVariation = arg;
955 emit blueVariationChanged(arg);
957 m_explicitColor = true;
958 if (perfLevel < Colored)
962 void QQuickImageParticle::setRotation(qreal arg)
964 if (m_rotation != arg) {
966 emit rotationChanged(arg);
968 m_explicitRotation = true;
969 if (perfLevel < Deformable)
973 void QQuickImageParticle::setRotationVariation(qreal arg)
975 if (m_rotationVariation != arg) {
976 m_rotationVariation = arg;
977 emit rotationVariationChanged(arg);
979 m_explicitRotation = true;
980 if (perfLevel < Deformable)
984 void QQuickImageParticle::setRotationSpeed(qreal arg)
986 if (m_rotationSpeed != arg) {
987 m_rotationSpeed = arg;
988 emit rotationSpeedChanged(arg);
990 m_explicitRotation = true;
991 if (perfLevel < Deformable)
995 void QQuickImageParticle::setRotationSpeedVariation(qreal arg)
997 if (m_rotationSpeedVariation != arg) {
998 m_rotationSpeedVariation = arg;
999 emit rotationSpeedVariationChanged(arg);
1001 m_explicitRotation = true;
1002 if (perfLevel < Deformable)
1006 void QQuickImageParticle::setAutoRotation(bool arg)
1008 if (m_autoRotation != arg) {
1009 m_autoRotation = arg;
1010 emit autoRotationChanged(arg);
1012 m_explicitRotation = true;
1013 if (perfLevel < Deformable)
1017 void QQuickImageParticle::setXVector(QQuickDirection* arg)
1019 if (m_xVector != arg) {
1021 emit xVectorChanged(arg);
1023 m_explicitDeformation = true;
1024 if (perfLevel < Deformable)
1028 void QQuickImageParticle::setYVector(QQuickDirection* arg)
1030 if (m_yVector != arg) {
1032 emit yVectorChanged(arg);
1034 m_explicitDeformation = true;
1035 if (perfLevel < Deformable)
1039 void QQuickImageParticle::setSpritesInterpolate(bool arg)
1041 if (m_spritesInterpolate != arg) {
1042 m_spritesInterpolate = arg;
1043 emit spritesInterpolateChanged(arg);
1047 void QQuickImageParticle::setBloat(bool arg)
1049 if (m_bloat != arg) {
1051 emit bloatChanged(arg);
1053 if (perfLevel < 9999)
1057 void QQuickImageParticle::setEntryEffect(EntryEffect arg)
1059 if (m_entryEffect != arg) {
1060 m_entryEffect = arg;
1062 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1063 emit entryEffectChanged(arg);
1067 void QQuickImageParticle::resetColor()
1069 m_explicitColor = false;
1070 foreach (const QString &str, m_groups)
1071 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1072 if (d->colorOwner == this)
1075 m_color_variation = 0.0f;
1076 m_redVariation = 0.0f;
1077 m_blueVariation = 0.0f;
1078 m_greenVariation = 0.0f;
1080 m_alphaVariation = 0.0f;
1083 void QQuickImageParticle::resetRotation()
1085 m_explicitRotation = false;
1086 foreach (const QString &str, m_groups)
1087 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1088 if (d->rotationOwner == this)
1089 d->rotationOwner = 0;
1091 m_rotationVariation = 0;
1092 m_rotationSpeed = 0;
1093 m_rotationSpeedVariation = 0;
1094 m_autoRotation = false;
1097 void QQuickImageParticle::resetDeformation()
1099 m_explicitDeformation = false;
1100 foreach (const QString &str, m_groups)
1101 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1102 if (d->deformationOwner == this)
1103 d->deformationOwner = 0;
1112 void QQuickImageParticle::reset()
1114 QQuickParticlePainter::reset();
1115 m_pleaseReset = true;
1119 void QQuickImageParticle::createEngine()
1122 delete m_spriteEngine;
1123 if (m_sprites.count()) {
1124 m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1125 connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1126 this, SLOT(spriteAdvance(int)));
1127 m_explicitAnimation = true;
1130 m_explicitAnimation = false;
1135 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
1136 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1137 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1138 QSGGeometry::Attribute::create(2, 4, GL_FLOAT) // Vectors
1141 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
1143 3, // Attribute Count
1144 ( 2 + 4 + 4 ) * sizeof(float),
1145 SimpleParticle_Attributes
1148 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
1149 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1150 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1151 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1152 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1155 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
1157 4, // Attribute Count
1158 ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1159 ColoredParticle_Attributes
1162 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
1163 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1164 QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // TexCoord
1165 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Data
1166 QSGGeometry::Attribute::create(3, 4, GL_FLOAT), // Vectors
1167 QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE), // Colors
1168 QSGGeometry::Attribute::create(5, 4, GL_FLOAT), // DeformationVectors
1169 QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Rotation
1172 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1174 7, // Attribute Count
1175 (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1176 DeformableParticle_Attributes
1179 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1180 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1181 QSGGeometry::Attribute::create(1, 2, GL_FLOAT), // TexCoord
1182 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Data
1183 QSGGeometry::Attribute::create(3, 4, GL_FLOAT), // Vectors
1184 QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE), // Colors
1185 QSGGeometry::Attribute::create(5, 4, GL_FLOAT), // DeformationVectors
1186 QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Rotation
1187 QSGGeometry::Attribute::create(7, 4, GL_FLOAT), // Anim Data
1188 QSGGeometry::Attribute::create(8, 4, GL_FLOAT) // Anim Pos
1191 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1193 9, // Attribute Count
1194 (2 + 2 + 4 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1195 SpriteParticle_Attributes
1198 void QQuickImageParticle::clearShadows()
1200 m_shadowInit = false;
1201 foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1203 m_shadowData.clear();
1206 //Only call if you need to, may initialize the whole array first time
1207 QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1209 QQuickParticleGroupData* gd = m_system->groupData[datum->group];
1210 if (!m_shadowData.contains(datum->group)) {
1211 QVector<QQuickParticleData*> data;
1212 for (int i=0; i<gd->size(); i++){
1213 QQuickParticleData* datum = new QQuickParticleData(m_system);
1214 *datum = *(gd->data[i]);
1217 m_shadowData.insert(datum->group, data);
1219 //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1221 return m_shadowData[datum->group][datum->index];
1224 QSGGeometryNode* QQuickImageParticle::buildParticleNodes()
1226 #ifdef QT_OPENGL_ES_2
1227 if (m_count * 4 > 0xffff) {
1228 printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1236 if (m_sprites.count() || m_bloat) {
1237 perfLevel = Sprites;
1238 } else if (!m_colortable_name.isEmpty() || !m_sizetable_name.isEmpty()
1239 || !m_opacitytable_name.isEmpty()) {
1241 } else if (m_autoRotation || m_rotation || m_rotationVariation
1242 || m_rotationSpeed || m_rotationSpeedVariation
1243 || m_xVector || m_yVector) {
1244 perfLevel = Deformable;
1245 } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1246 || m_redVariation || m_blueVariation || m_greenVariation) {
1247 perfLevel = Colored;
1252 foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1253 int gIdx = m_system->groupIds[str];
1254 foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){
1255 QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1257 if (other->perfLevel > perfLevel) {
1258 if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1259 if (perfLevel < Deformable)
1260 perfLevel = Deformable;
1262 perfLevel = other->perfLevel;
1264 } else if (other->perfLevel < perfLevel) {
1271 if (perfLevel >= Colored && !m_color.isValid())
1272 m_color = QColor(Qt::white);//Hidden default, but different from unset
1275 if (perfLevel >= Sprites){
1276 if (!m_spriteEngine) {
1277 qWarning() << "ImageParticle: No sprite engine...";
1280 image = m_spriteEngine->assembledImage();
1281 if (image.isNull())//Warning is printed in engine
1284 image = QImage(m_image_name.toLocalFile());
1285 if (image.isNull()) {
1286 printf("ImageParticle: loading image failed '%s'\n", qPrintable(m_image_name.toLocalFile()));
1298 QImage opacitytable;
1299 switch (perfLevel) {//Fallthrough intended
1301 m_material = SpriteMaterial::createMaterial();
1302 getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1303 m_spriteEngine->setCount(m_count);
1306 m_material = TabledMaterial::createMaterial();
1307 colortable = QImage(m_colortable_name.toLocalFile());
1308 sizetable = QImage(m_sizetable_name.toLocalFile());
1309 opacitytable = QImage(m_opacitytable_name.toLocalFile());
1310 if (colortable.isNull()){
1311 colortable = QImage(1,1,QImage::Format_ARGB32);
1312 colortable.fill(Qt::white);
1314 Q_ASSERT(!colortable.isNull());
1315 getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1316 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1317 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1320 m_material = DeformableMaterial::createMaterial();
1323 m_material = ColoredMaterial::createMaterial();
1324 default://Also Simple
1326 m_material = SimpleMaterial::createMaterial();
1327 getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1328 getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1329 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1330 m_material->setFlag(QSGMaterial::Blending);
1333 foreach (const QString &str, m_groups){
1334 int gIdx = m_system->groupIds[str];
1335 int count = m_system->groupData[gIdx]->size();
1336 QSGGeometryNode* node = new QSGGeometryNode();
1337 node->setMaterial(m_material);
1338 node->markDirty(QSGNode::DirtyMaterial);
1340 m_nodes.insert(gIdx, node);
1341 m_idxStarts.insert(gIdx, m_lastIdxStart);
1342 m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx));
1343 m_lastIdxStart += count;
1345 //Create Particle Geometry
1346 int vCount = count * 4;
1347 int iCount = count * 6;
1350 if (perfLevel == Sprites)
1351 g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1352 else if (perfLevel == Tabled)
1353 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1354 else if (perfLevel == Deformable)
1355 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1356 else if (perfLevel == Colored)
1357 g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1359 g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1361 node->setGeometry(g);
1362 if (perfLevel <= Colored){
1363 g->setDrawingMode(GL_POINTS);
1365 GLfloat pointSizeRange[2];
1366 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1367 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1370 g->setDrawingMode(GL_TRIANGLES);
1372 for (int p=0; p < count; ++p)
1373 commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1375 if (perfLevel == Sprites)
1376 initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1377 else if (perfLevel == Tabled)
1378 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1379 else if (perfLevel == Deformable)
1380 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1382 if (perfLevel > Colored){
1383 quint16 *indices = g->indexDataAsUShort();
1384 for (int i=0; i < count; ++i) {
1398 foreach (QSGGeometryNode* node, m_nodes){
1399 if (node == *(m_nodes.begin()))
1400 node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1402 (*(m_nodes.begin()))->appendChildNode(node);
1405 return *(m_nodes.begin());
1408 QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1411 m_lastLevel = perfLevel;
1413 delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1417 m_idxStarts.clear();
1418 m_startsIdx.clear();
1423 m_pleaseReset = false;
1426 if (m_system && m_system->isRunning() && !m_system->isPaused()){
1430 foreach (QSGGeometryNode* node, m_nodes)
1431 node->markDirty(QSGNode::DirtyGeometry);
1438 void QQuickImageParticle::prepareNextFrame()
1440 if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1441 m_rootNode = buildParticleNodes();
1442 if (m_rootNode == 0)
1445 qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1446 qDebug() << "QQuickImageParticle Nodes: ";
1448 foreach(int i, m_nodes.keys()){
1449 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1450 count += m_system->groupData[i]->size();
1452 qDebug() << "Total count: " << count;
1455 qint64 timeStamp = m_system->systemSync(this);
1457 qreal time = timeStamp / 1000.;
1459 switch (perfLevel){//Fall-through intended
1462 m_spriteEngine->updateSprites(timeStamp);
1467 default: //Also Simple
1468 getState<ImageMaterialData>(m_material)->timestamp = time;
1472 foreach (QSGGeometryNode* node, m_nodes)
1473 node->markDirty(QSGNode::DirtyMaterial);
1476 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1478 if (!m_startsIdx.count())//Probably overly defensive
1483 for (i = 0; i<m_startsIdx.count(); i++) {
1484 if (spriteIdx < m_startsIdx[i].first) {
1485 gIdx = m_startsIdx[i-1].second;
1490 gIdx = m_startsIdx[i-1].second;
1491 int pIdx = spriteIdx - m_startsIdx[i-1].first;
1493 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1494 QQuickParticleData* d = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1496 d->animIdx = m_spriteEngine->spriteState(spriteIdx);
1497 Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData();
1498 Vertices<SpriteVertex> &p = particles[pIdx];
1499 d->animT = p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1500 d->frameCount = p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1501 d->frameDuration = p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1502 d->animX = p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx);
1503 d->animY = p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx);
1504 d->animWidth = p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1505 d->animHeight = p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1508 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1511 //TODO: get index for reload - or make function take an index
1514 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1517 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1518 qreal redVariation = m_color_variation + m_redVariation;
1519 qreal greenVariation = m_color_variation + m_greenVariation;
1520 qreal blueVariation = m_color_variation + m_blueVariation;
1522 if (m_spriteEngine) {
1523 spriteIdx = m_idxStarts[gIdx] + datum->index;
1524 if (spriteIdx >= m_spriteEngine->count())
1525 m_spriteEngine->setCount(spriteIdx+1);
1529 float rotationSpeed;
1531 switch (perfLevel){//Fall-through is intended on all of them
1533 // Initial Sprite State
1534 if (m_explicitAnimation){
1535 if (!datum->animationOwner)
1536 datum->animationOwner = this;
1537 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1538 writeTo->animT = writeTo->t;
1539 //writeTo->animInterpolate = m_spritesInterpolate;
1540 if (m_spriteEngine){
1541 m_spriteEngine->start(spriteIdx);
1542 writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1543 writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1544 writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1545 writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1546 writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1547 writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1549 writeTo->frameCount = 1;
1550 writeTo->frameDuration = 9999;
1551 writeTo->animX = writeTo->animY = 0;
1552 writeTo->animWidth = writeTo->animHeight = 1;
1558 if (m_explicitDeformation){
1559 if (!datum->deformationOwner)
1560 datum->deformationOwner = this;
1562 const QPointF &ret = m_xVector->sample(QPointF(datum->x, datum->y));
1563 if (datum->deformationOwner == this) {
1564 datum->xx = ret.x();
1565 datum->xy = ret.y();
1567 getShadowDatum(datum)->xx = ret.x();
1568 getShadowDatum(datum)->xy = ret.y();
1572 const QPointF &ret = m_yVector->sample(QPointF(datum->x, datum->y));
1573 if (datum->deformationOwner == this) {
1574 datum->yx = ret.x();
1575 datum->yy = ret.y();
1577 getShadowDatum(datum)->yx = ret.x();
1578 getShadowDatum(datum)->yy = ret.y();
1583 if (m_explicitRotation){
1584 if (!datum->rotationOwner)
1585 datum->rotationOwner = this;
1587 (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
1589 (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
1590 autoRotate = m_autoRotation?1.0:0.0;
1591 if (datum->rotationOwner == this) {
1592 datum->rotation = rotation;
1593 datum->rotationSpeed = rotationSpeed;
1594 datum->autoRotate = autoRotate;
1596 getShadowDatum(datum)->rotation = rotation;
1597 getShadowDatum(datum)->rotationSpeed = rotationSpeed;
1598 getShadowDatum(datum)->autoRotate = autoRotate;
1602 //Color initialization
1604 if (m_explicitColor) {
1605 if (!datum->colorOwner)
1606 datum->colorOwner = this;
1607 color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
1608 color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
1609 color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
1610 color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
1611 if (datum->colorOwner == this)
1612 datum->color = color;
1614 getShadowDatum(datum)->color = color;
1621 void QQuickImageParticle::commit(int gIdx, int pIdx)
1625 QSGGeometryNode *node = m_nodes[gIdx];
1628 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1629 node->setFlag(QSGNode::OwnsGeometry, false);
1630 SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData();
1631 DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData();
1632 ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData();
1633 SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData();
1634 switch (perfLevel){//No automatic fall through intended on this one
1636 spriteVertices += pIdx*4;
1637 for (int i=0; i<4; i++){
1638 spriteVertices[i].x = datum->x - m_systemOffset.x();
1639 spriteVertices[i].y = datum->y - m_systemOffset.y();
1640 spriteVertices[i].t = datum->t;
1641 spriteVertices[i].lifeSpan = datum->lifeSpan;
1642 spriteVertices[i].size = datum->size;
1643 spriteVertices[i].endSize = datum->endSize;
1644 spriteVertices[i].vx = datum->vx;
1645 spriteVertices[i].vy = datum->vy;
1646 spriteVertices[i].ax = datum->ax;
1647 spriteVertices[i].ay = datum->ay;
1648 if (m_explicitDeformation && datum->deformationOwner != this) {
1649 QQuickParticleData* shadow = getShadowDatum(datum);
1650 spriteVertices[i].xx = shadow->xx;
1651 spriteVertices[i].xy = shadow->xy;
1652 spriteVertices[i].yx = shadow->yx;
1653 spriteVertices[i].yy = shadow->yy;
1655 spriteVertices[i].xx = datum->xx;
1656 spriteVertices[i].xy = datum->xy;
1657 spriteVertices[i].yx = datum->yx;
1658 spriteVertices[i].yy = datum->yy;
1660 if (m_explicitRotation && datum->rotationOwner != this) {
1661 QQuickParticleData* shadow = getShadowDatum(datum);
1662 spriteVertices[i].rotation = shadow->rotation;
1663 spriteVertices[i].rotationSpeed = shadow->rotationSpeed;
1664 spriteVertices[i].autoRotate = shadow->autoRotate;
1666 spriteVertices[i].rotation = datum->rotation;
1667 spriteVertices[i].rotationSpeed = datum->rotationSpeed;
1668 spriteVertices[i].autoRotate = datum->autoRotate;
1670 spriteVertices[i].animInterpolate = m_spritesInterpolate ? 1.0 : 0.0;//### Shadow? In particleData? Or uniform?
1671 if (m_explicitAnimation && datum->animationOwner != this) {
1672 QQuickParticleData* shadow = getShadowDatum(datum);
1673 spriteVertices[i].frameDuration = shadow->frameDuration;
1674 spriteVertices[i].frameCount = shadow->frameCount;
1675 spriteVertices[i].animT = shadow->animT;
1676 spriteVertices[i].animX = shadow->animX;
1677 spriteVertices[i].animY = shadow->animY;
1678 spriteVertices[i].animWidth = shadow->animWidth;
1679 spriteVertices[i].animHeight = shadow->animHeight;
1681 spriteVertices[i].frameDuration = datum->frameDuration;
1682 spriteVertices[i].frameCount = datum->frameCount;
1683 spriteVertices[i].animT = datum->animT;
1684 spriteVertices[i].animX = datum->animX;
1685 spriteVertices[i].animY = datum->animY;
1686 spriteVertices[i].animWidth = datum->animWidth;
1687 spriteVertices[i].animHeight = datum->animHeight;
1689 if (m_explicitColor && datum->colorOwner != this) {
1690 QQuickParticleData* shadow = getShadowDatum(datum);
1691 spriteVertices[i].color.r = shadow->color.r;
1692 spriteVertices[i].color.g = shadow->color.g;
1693 spriteVertices[i].color.b = shadow->color.b;
1694 spriteVertices[i].color.a = shadow->color.a;
1696 spriteVertices[i].color.r = datum->color.r;
1697 spriteVertices[i].color.g = datum->color.g;
1698 spriteVertices[i].color.b = datum->color.b;
1699 spriteVertices[i].color.a = datum->color.a;
1703 case Tabled: //Fall through until it has its own vertex class
1705 deformableVertices += pIdx*4;
1706 for (int i=0; i<4; i++){
1707 deformableVertices[i].x = datum->x - m_systemOffset.x();
1708 deformableVertices[i].y = datum->y - m_systemOffset.y();
1709 deformableVertices[i].t = datum->t;
1710 deformableVertices[i].lifeSpan = datum->lifeSpan;
1711 deformableVertices[i].size = datum->size;
1712 deformableVertices[i].endSize = datum->endSize;
1713 deformableVertices[i].vx = datum->vx;
1714 deformableVertices[i].vy = datum->vy;
1715 deformableVertices[i].ax = datum->ax;
1716 deformableVertices[i].ay = datum->ay;
1717 if (m_explicitDeformation && datum->deformationOwner != this) {
1718 QQuickParticleData* shadow = getShadowDatum(datum);
1719 deformableVertices[i].xx = shadow->xx;
1720 deformableVertices[i].xy = shadow->xy;
1721 deformableVertices[i].yx = shadow->yx;
1722 deformableVertices[i].yy = shadow->yy;
1724 deformableVertices[i].xx = datum->xx;
1725 deformableVertices[i].xy = datum->xy;
1726 deformableVertices[i].yx = datum->yx;
1727 deformableVertices[i].yy = datum->yy;
1729 if (m_explicitRotation && datum->rotationOwner != this) {
1730 QQuickParticleData* shadow = getShadowDatum(datum);
1731 deformableVertices[i].rotation = shadow->rotation;
1732 deformableVertices[i].rotationSpeed = shadow->rotationSpeed;
1733 deformableVertices[i].autoRotate = shadow->autoRotate;
1735 deformableVertices[i].rotation = datum->rotation;
1736 deformableVertices[i].rotationSpeed = datum->rotationSpeed;
1737 deformableVertices[i].autoRotate = datum->autoRotate;
1739 if (m_explicitColor && datum->colorOwner != this) {
1740 QQuickParticleData* shadow = getShadowDatum(datum);
1741 deformableVertices[i].color.r = shadow->color.r;
1742 deformableVertices[i].color.g = shadow->color.g;
1743 deformableVertices[i].color.b = shadow->color.b;
1744 deformableVertices[i].color.a = shadow->color.a;
1746 deformableVertices[i].color.r = datum->color.r;
1747 deformableVertices[i].color.g = datum->color.g;
1748 deformableVertices[i].color.b = datum->color.b;
1749 deformableVertices[i].color.a = datum->color.a;
1754 coloredVertices += pIdx*1;
1755 for (int i=0; i<1; i++){
1756 coloredVertices[i].x = datum->x - m_systemOffset.x();
1757 coloredVertices[i].y = datum->y - m_systemOffset.y();
1758 coloredVertices[i].t = datum->t;
1759 coloredVertices[i].lifeSpan = datum->lifeSpan;
1760 coloredVertices[i].size = datum->size;
1761 coloredVertices[i].endSize = datum->endSize;
1762 coloredVertices[i].vx = datum->vx;
1763 coloredVertices[i].vy = datum->vy;
1764 coloredVertices[i].ax = datum->ax;
1765 coloredVertices[i].ay = datum->ay;
1766 if (m_explicitColor && datum->colorOwner != this) {
1767 QQuickParticleData* shadow = getShadowDatum(datum);
1768 coloredVertices[i].color.r = shadow->color.r;
1769 coloredVertices[i].color.g = shadow->color.g;
1770 coloredVertices[i].color.b = shadow->color.b;
1771 coloredVertices[i].color.a = shadow->color.a;
1773 coloredVertices[i].color.r = datum->color.r;
1774 coloredVertices[i].color.g = datum->color.g;
1775 coloredVertices[i].color.b = datum->color.b;
1776 coloredVertices[i].color.a = datum->color.a;
1781 simpleVertices += pIdx*1;
1782 for (int i=0; i<1; i++){
1783 simpleVertices[i].x = datum->x - m_systemOffset.x();
1784 simpleVertices[i].y = datum->y - m_systemOffset.y();
1785 simpleVertices[i].t = datum->t;
1786 simpleVertices[i].lifeSpan = datum->lifeSpan;
1787 simpleVertices[i].size = datum->size;
1788 simpleVertices[i].endSize = datum->endSize;
1789 simpleVertices[i].vx = datum->vx;
1790 simpleVertices[i].vy = datum->vy;
1791 simpleVertices[i].ax = datum->ax;
1792 simpleVertices[i].ay = datum->ay;
1799 node->setFlag(QSGNode::OwnsGeometry, true);