1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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>
59 #ifndef QT_OPENGL_ES_2
60 #define SHADER_DEFINES "#version 120\n"
62 #define SHADER_DEFINES ""
65 //TODO: Make it larger on desktop? Requires fixing up shader code with the same define
66 #define UNIFORM_ARRAY_SIZE 64
68 static const char vertexShaderCode[] =
69 "#if defined(DEFORM)\n"
70 "attribute highp vec4 vPosTex;\n"
72 "attribute highp vec2 vPos;\n"
74 "attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize\n"
75 "attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration\n"
76 "uniform highp float entry;\n"
77 "#if defined(COLOR)\n"
78 "attribute highp vec4 vColor;\n"
80 "#if defined(DEFORM)\n"
81 "attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector\n"
82 "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate\n"
84 "#if defined(SPRITE)\n"
85 "attribute highp vec4 vAnimData;// interpolate(bool), duration, frameCount (this anim), timestamp (this anim)\n"
86 "attribute highp vec4 vAnimPos;//sheet x,y, width/height of this anim\n"
87 "uniform highp vec2 animSheetSize; //width/height of whole sheet\n"
90 "uniform highp mat4 qt_Matrix;\n"
91 "uniform highp float timestamp;\n"
92 "#if defined(TABLE)\n"
93 "varying lowp vec2 tt;//y is progress if Sprite mode\n"
94 "uniform highp float sizetable[64];\n"
95 "uniform highp float opacitytable[64];\n"
97 "#if defined(SPRITE)\n"
98 "varying highp vec4 fTexS;\n"
99 "#elif defined(DEFORM)\n"
100 "varying highp vec2 fTex;\n"
102 "#if defined(COLOR)\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 "#if defined(DEFORM)\n"
114 " gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
116 " gl_PointSize = 0.;\n"
119 "#if defined(SPRITE)\n"
120 " //Calculate frame location in texture\n"
121 " highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);\n"
122 " tt.y = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;\n"
124 " frameIndex = floor(frameIndex);\n"
125 " fTexS.xy = vec2(((frameIndex + vPosTex.z) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vPosTex.w * vAnimPos.w) / animSheetSize.y));\n"
127 " //Next frame is also passed, for interpolation\n"
128 " //### Should the next anim be precalculated to allow for interpolation there?\n"
129 " if (vAnimData.x == 1.0 && frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop\n"
130 " frameIndex = mod(frameIndex+1., vAnimData.z);\n"
131 " fTexS.zw = vec2(((frameIndex + vPosTex.z) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vPosTex.w * vAnimPos.w) / animSheetSize.y));\n"
132 "#elif defined(DEFORM)\n"
133 " fTex = vPosTex.zw;\n"
135 " highp float currentSize = mix(vData.z, vData.w, t * t);\n"
136 " lowp float fade = 1.;\n"
137 " highp float fadeIn = min(t * 10., 1.);\n"
138 " highp float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.);\n"
140 "#if defined(TABLE)\n"
141 " currentSize = currentSize * sizetable[int(floor(t*64.))];\n"
142 " fade = fade * opacitytable[int(floor(t*64.))];\n"
145 " if (entry == 1.)\n"
146 " fade = fade * fadeIn * fadeOut;\n"
147 " else if (entry == 2.)\n"
148 " currentSize = currentSize * fadeIn * fadeOut;\n"
150 " if (currentSize <= 0.) {\n"
151 "#if defined(DEFORM)\n"
152 " gl_Position = qt_Matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.);\n"
154 " gl_PointSize = 0.;\n"
157 " if (currentSize < 3.)//Sizes too small look jittery as they move\n"
158 " currentSize = 3.;\n"
161 "#if defined(DEFORM)\n"
162 " highp float rotation = vRotation.x + vRotation.y * t * vData.y;\n"
163 " if (vRotation.z == 1.0){\n"
164 " highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;\n"
165 " rotation += atan(curVel.y, curVel.x);\n"
167 " highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));\n"
168 " highp vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5);\n"
169 " highp vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy;\n"
170 " rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.));\n"
171 " /* The readable version:\n"
172 " highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);\n"
173 " highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);\n"
174 " highp vec2 xRotatedDeform;\n"
175 " xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;\n"
176 " xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;\n"
177 " highp vec2 yRotatedDeform;\n"
178 " yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;\n"
179 " yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;\n"
181 " pos = vPosTex.xy\n"
182 " + rotatedDeform.xy\n"
183 " + rotatedDeform.zw\n"
184 " + vVec.xy * t * vData.y // apply speed\n"
185 " + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration\n"
188 " + vVec.xy * t * vData.y // apply speed vector..\n"
189 " + 0.5 * vVec.zw * pow(t * vData.y, 2.);\n"
190 " gl_PointSize = currentSize;\n"
192 " gl_Position = qt_Matrix * vec4(pos.x, pos.y, 0, 1);\n"
194 "#if defined(COLOR)\n"
195 " fColor = vColor * fade;\n"
199 "#if defined(TABLE)\n"
206 static const char fragmentShaderCode[] =
207 "uniform sampler2D texture;\n"
208 "uniform lowp float qt_Opacity;\n"
210 "#if defined(SPRITE)\n"
211 "varying highp vec4 fTexS;\n"
212 "#elif defined(DEFORM)\n"
213 "varying highp vec2 fTex;\n"
215 "#if defined(COLOR)\n"
216 "varying lowp vec4 fColor;\n"
218 "varying lowp float fFade;\n"
220 "#if defined(TABLE)\n"
221 "varying lowp vec2 tt;\n"
222 "uniform sampler2D colortable;\n"
226 "#if defined(SPRITE)\n"
227 " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), tt.y)\n"
229 " * texture2D(colortable, tt)\n"
231 "#elif defined(TABLE)\n"
232 " gl_FragColor = texture2D(texture, fTex)\n"
234 " * texture2D(colortable, tt)\n"
236 "#elif defined(DEFORM)\n"
237 " gl_FragColor = (texture2D(texture, fTex)) * fColor * qt_Opacity;\n"
238 "#elif defined(COLOR)\n"
239 " gl_FragColor = (texture2D(texture, gl_PointCoord)) * fColor * qt_Opacity;\n"
241 " gl_FragColor = texture2D(texture, gl_PointCoord) * (fFade * qt_Opacity);\n"
245 const qreal CONV = 0.017453292519943295;
246 class ImageMaterialData
250 : texture(0), colorTable(0)
253 ~ImageMaterialData(){
259 QSGTexture *colorTable;
260 float sizeTable[UNIFORM_ARRAY_SIZE];
261 float opacityTable[UNIFORM_ARRAY_SIZE];
265 QSizeF animSheetSize;
268 class TabledMaterialData : public ImageMaterialData {};
269 class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
271 QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
276 m_vertex_code = QByteArray(SHADER_DEFINES)
277 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
280 m_fragment_code = QByteArray(SHADER_DEFINES)
281 + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
282 + fragmentShaderCode;
284 Q_ASSERT(!m_vertex_code.isNull());
285 Q_ASSERT(!m_fragment_code.isNull());
288 const char *vertexShader() const { return m_vertex_code.constData(); }
289 const char *fragmentShader() const { return m_fragment_code.constData(); }
291 QList<QByteArray> attributes() const {
292 return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
293 << "vColor" << "vDeformVec" << "vRotation";
297 QSGSimpleMaterialShader<TabledMaterialData>::initialize();
299 program()->setUniformValue("texture", 0);
300 program()->setUniformValue("colortable", 1);
301 glFuncs = QOpenGLContext::currentContext()->functions();
302 m_timestamp_id = program()->uniformLocation("timestamp");
303 m_entry_id = program()->uniformLocation("entry");
304 m_sizetable_id = program()->uniformLocation("sizetable");
305 m_opacitytable_id = program()->uniformLocation("opacitytable");
308 void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
309 glFuncs->glActiveTexture(GL_TEXTURE1);
310 d->colorTable->bind();
312 glFuncs->glActiveTexture(GL_TEXTURE0);
315 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
316 program()->setUniformValue(m_entry_id, (float) d->entry);
317 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1);
318 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
324 int m_opacitytable_id;
325 QByteArray m_vertex_code;
326 QByteArray m_fragment_code;
327 QOpenGLFunctions* glFuncs;
330 class DeformableMaterialData : public ImageMaterialData {};
331 class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData>
333 QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData)
338 m_vertex_code = QByteArray(SHADER_DEFINES)
339 + QByteArray("#define DEFORM\n#define COLOR\n")
342 m_fragment_code = QByteArray(SHADER_DEFINES)
343 + QByteArray("#define DEFORM\n#define COLOR\n")
344 + fragmentShaderCode;
346 Q_ASSERT(!m_vertex_code.isNull());
347 Q_ASSERT(!m_fragment_code.isNull());
350 const char *vertexShader() const { return m_vertex_code.constData(); }
351 const char *fragmentShader() const { return m_fragment_code.constData(); }
353 QList<QByteArray> attributes() const {
354 return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
355 << "vColor" << "vDeformVec" << "vRotation";
359 QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
361 program()->setUniformValue("texture", 0);
362 glFuncs = QOpenGLContext::currentContext()->functions();
363 m_timestamp_id = program()->uniformLocation("timestamp");
364 m_entry_id = program()->uniformLocation("entry");
367 void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) {
368 glFuncs->glActiveTexture(GL_TEXTURE0);
371 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
372 program()->setUniformValue(m_entry_id, (float) d->entry);
377 QByteArray m_vertex_code;
378 QByteArray m_fragment_code;
379 QOpenGLFunctions* glFuncs;
382 class SpriteMaterialData : public ImageMaterialData {};
383 class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData>
385 QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData)
390 m_vertex_code = QByteArray(SHADER_DEFINES)
391 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
394 m_fragment_code = QByteArray(SHADER_DEFINES)
395 + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
396 + fragmentShaderCode;
398 Q_ASSERT(!m_vertex_code.isNull());
399 Q_ASSERT(!m_fragment_code.isNull());
402 const char *vertexShader() const { return m_vertex_code.constData(); }
403 const char *fragmentShader() const { return m_fragment_code.constData(); }
405 QList<QByteArray> attributes() const {
406 return QList<QByteArray>() << "vPosTex" << "vData" << "vVec"
407 << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos";
411 QSGSimpleMaterialShader<SpriteMaterialData>::initialize();
413 program()->setUniformValue("texture", 0);
414 program()->setUniformValue("colortable", 1);
415 glFuncs = QOpenGLContext::currentContext()->functions();
416 m_timestamp_id = program()->uniformLocation("timestamp");
417 m_animsize_id = program()->uniformLocation("animSheetSize");
418 m_entry_id = program()->uniformLocation("entry");
419 m_sizetable_id = program()->uniformLocation("sizetable");
420 m_opacitytable_id = program()->uniformLocation("opacitytable");
423 void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) {
424 glFuncs->glActiveTexture(GL_TEXTURE1);
425 d->colorTable->bind();
427 // make sure we end by setting GL_TEXTURE0 as active texture
428 glFuncs->glActiveTexture(GL_TEXTURE0);
431 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
432 program()->setUniformValue(m_animsize_id, d->animSheetSize);
433 program()->setUniformValue(m_entry_id, (float) d->entry);
434 program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, 64, 1);
435 program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1);
442 int m_opacitytable_id;
443 QByteArray m_vertex_code;
444 QByteArray m_fragment_code;
445 QOpenGLFunctions* glFuncs;
448 class ColoredMaterialData : public ImageMaterialData {};
449 class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData>
451 QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData)
456 m_vertex_code = QByteArray(SHADER_DEFINES)
457 + QByteArray("#define COLOR\n")
460 m_fragment_code = QByteArray(SHADER_DEFINES)
461 + QByteArray("#define COLOR\n")
462 + fragmentShaderCode;
464 Q_ASSERT(!m_vertex_code.isNull());
465 Q_ASSERT(!m_fragment_code.isNull());
468 const char *vertexShader() const { return m_vertex_code.constData(); }
469 const char *fragmentShader() const { return m_fragment_code.constData(); }
472 QSGSimpleMaterialShader<ColoredMaterialData>::activate();
473 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
474 glEnable(GL_POINT_SPRITE);
475 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
480 QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
481 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
482 glDisable(GL_POINT_SPRITE);
483 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
487 QList<QByteArray> attributes() const {
488 return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor";
492 QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
494 program()->setUniformValue("texture", 0);
495 glFuncs = QOpenGLContext::currentContext()->functions();
496 m_timestamp_id = program()->uniformLocation("timestamp");
497 m_entry_id = program()->uniformLocation("entry");
500 void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) {
501 glFuncs->glActiveTexture(GL_TEXTURE0);
504 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
505 program()->setUniformValue(m_entry_id, (float) d->entry);
510 QByteArray m_vertex_code;
511 QByteArray m_fragment_code;
512 QOpenGLFunctions* glFuncs;
515 class SimpleMaterialData : public ImageMaterialData {};
516 class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData>
518 QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData)
523 m_vertex_code = QByteArray(SHADER_DEFINES)
526 m_fragment_code = QByteArray(SHADER_DEFINES)
527 + fragmentShaderCode;
529 Q_ASSERT(!m_vertex_code.isNull());
530 Q_ASSERT(!m_fragment_code.isNull());
533 const char *vertexShader() const { return m_vertex_code.constData(); }
534 const char *fragmentShader() const { return m_fragment_code.constData(); }
537 QSGSimpleMaterialShader<SimpleMaterialData>::activate();
538 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
539 glEnable(GL_POINT_SPRITE);
540 glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
545 QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
546 #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
547 glDisable(GL_POINT_SPRITE);
548 glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
552 QList<QByteArray> attributes() const {
553 return QList<QByteArray>() << "vPos" << "vData" << "vVec";
557 QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
559 program()->setUniformValue("texture", 0);
560 glFuncs = QOpenGLContext::currentContext()->functions();
561 m_timestamp_id = program()->uniformLocation("timestamp");
562 m_entry_id = program()->uniformLocation("entry");
565 void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) {
566 glFuncs->glActiveTexture(GL_TEXTURE0);
569 program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
570 program()->setUniformValue(m_entry_id, (float) d->entry);
575 QByteArray m_vertex_code;
576 QByteArray m_fragment_code;
577 QOpenGLFunctions* glFuncs;
580 void fillUniformArrayFromImage(float* array, const QImage& img, int size)
583 for (int i=0; i<size; i++)
587 QImage scaled = img.scaled(size,1);
588 for (int i=0; i<size; i++)
589 array[i] = qAlpha(scaled.pixel(i,0))/255.0;
593 \qmlclass ImageParticle QQuickImageParticle
594 \inqmlmodule QtQuick.Particles 2
595 \inherits ParticlePainter
596 \brief The ImageParticle element visualizes logical particles using an image
598 This element renders a logical particle as an image. The image can be
603 \o a sprite-based animation
606 ImageParticles implictly share data on particles if multiple ImageParticles are painting
607 the same logical particle group. This is broken down along the four capabilities listed
608 above. So if one ImageParticle defines data for rendering the particles in one of those
609 capabilities, and the other does not, then both will draw the particles the same in that
610 aspect automatically. This is primarily useful when there is some random variation on
611 the particle which is supposed to stay with it when switching painters. If both ImageParticles
612 define how they should appear for that aspect, they diverge and each appears as it is defined.
614 This sharing of data happens behind the scenes based off of whether properties were implicitly or explicitly
615 set. One drawback of the current implementation is that it is only possible to reset the capabilities as a whole.
616 So if you explicity set an attribute affecting color, such as redVariation, and then reset it (by setting redVariation
617 to undefined), all color data will be reset and it will begin to have an implicit value of any shared color from
618 other ImageParticles.
621 \qmlproperty url QtQuick.Particles2::ImageParticle::source
623 The source image to be used.
625 If the image is a sprite animation, use the sprite property instead.
628 \qmlproperty list<Sprite> QtQuick.Particles2::ImageParticle::sprites
630 The sprite or sprites used to draw this particle.
632 Note that the sprite image will be scaled to a square based on the size of
633 the particle being rendered.
636 \qmlproperty url QtQuick.Particles2::ImageParticle::colorTable
638 An image whose color will be used as a 1D texture to determine color over life. E.g. when
639 the particle is halfway through its lifetime, it will have the color specified halfway
642 This color is blended with the color property and the color of the source image.
645 \qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
647 An image whose opacity will be used as a 1D texture to determine size over life.
649 This property is expected to be removed shortly, in favor of custom easing curves to determine size over life.
652 \qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
654 An image whose opacity will be used as a 1D texture to determine size over life.
656 This property is expected to be removed shortly, in favor of custom easing curves to determine opacity over life.
659 \qmlproperty color QtQuick.Particles2::ImageParticle::color
661 If a color is specified, the provided image will be colorized with it.
663 Default is white (no change).
666 \qmlproperty real QtQuick.Particles2::ImageParticle::colorVariation
668 This number represents the color variation applied to individual particles.
669 Setting colorVariation is the same as setting redVariation, greenVariation,
670 and blueVariation to the same number.
672 Each channel can vary between particle by up to colorVariation from its usual color.
674 Color is measured, per channel, from 0.0 to 1.0.
679 \qmlproperty real QtQuick.Particles2::ImageParticle::redVariation
680 The variation in the red color channel between particles.
682 Color is measured, per channel, from 0.0 to 1.0.
687 \qmlproperty real QtQuick.Particles2::ImageParticle::greenVariation
688 The variation in the green color channel between particles.
690 Color is measured, per channel, from 0.0 to 1.0.
695 \qmlproperty real QtQuick.Particles2::ImageParticle::blueVariation
696 The variation in the blue color channel between particles.
698 Color is measured, per channel, from 0.0 to 1.0.
703 \qmlproperty real QtQuick.Particles2::ImageParticle::alpha
704 An alpha to be applied to the image. This value is multiplied by the value in
705 the image, and the value in the color property.
707 Particles have additive blending, so lower alpha on single particles leads
708 to stronger effects when multiple particles overlap.
710 Alpha is measured from 0.0 to 1.0.
715 \qmlproperty real QtQuick.Particles2::ImageParticle::alphaVariation
716 The variation in the alpha channel between particles.
718 Alpha is measured from 0.0 to 1.0.
723 \qmlproperty real QtQuick.Particles2::ImageParticle::rotation
725 If set the image will be rotated by this many degrees before it is drawn.
727 The particle coordinates are not transformed.
730 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationVariation
732 If set the rotation of individual particles will vary by up to this much
737 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeed
739 If set particles will rotate at this speed in degrees/second.
742 \qmlproperty real QtQuick.Particles2::ImageParticle::rotationSpeedVariation
744 If set the rotationSpeed of individual particles will vary by up to this much
749 \qmlproperty bool QtQuick.Particles2::ImageParticle::autoRotation
751 If set to true then a rotation will be applied on top of the particles rotation, so
752 that it faces the direction of travel. So to face away from the direction of travel,
753 set autoRotation to true and rotation to 180.
758 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::xVector
760 Allows you to deform the particle image when drawn. The rectangular image will
761 be deformed so that the horizontal sides are in the shape of this vector instead
765 \qmlproperty StochasticDirection QtQuick.Particles2::ImageParticle::yVector
767 Allows you to deform the particle image when drawn. The rectangular image will
768 be deformed so that the vertical sides are in the shape of this vector instead
772 \qmlproperty EntryEffect QtQuick.Particles2::ImageParticle::entryEffect
774 This property provides basic and cheap entrance and exit effects for the particles.
775 For fine-grained control, see sizeTable and opacityTable.
777 Acceptable values are
779 \o None: Particles just appear and disappear.
780 \o Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end.
781 \o Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end.
784 Default value is Fade.
787 \qmlproperty bool QtQuick.Particles2::ImageParticle::spritesInterpolate
789 If set to true, sprite particles will interpolate between sprite frames each rendered frame, making
790 the sprites look smoother.
796 QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
797 : QQuickParticlePainter(parent)
798 , m_color_variation(0.0)
801 , m_alphaVariation(0.0)
803 , m_redVariation(0.0)
804 , m_greenVariation(0.0)
805 , m_blueVariation(0.0)
807 , m_rotationVariation(0)
809 , m_rotationSpeedVariation(0)
810 , m_autoRotation(false)
814 , m_spritesInterpolate(true)
815 , m_explicitColor(false)
816 , m_explicitRotation(false)
817 , m_explicitDeformation(false)
818 , m_explicitAnimation(false)
819 , m_bypassOptimizations(false)
821 , m_lastLevel(Unknown)
823 , m_entryEffect(Fade)
825 setFlag(ItemHasContents);
828 QQuickImageParticle::~QQuickImageParticle()
832 QDeclarativeListProperty<QQuickSprite> QQuickImageParticle::sprites()
834 return QDeclarativeListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
837 void QQuickImageParticle::setImage(const QUrl &image)
839 if (image == m_image_name)
841 m_image_name = image;
847 void QQuickImageParticle::setColortable(const QUrl &table)
849 if (table == m_colortable_name)
851 m_colortable_name = table;
852 emit colortableChanged();
856 void QQuickImageParticle::setSizetable(const QUrl &table)
858 if (table == m_sizetable_name)
860 m_sizetable_name = table;
861 emit sizetableChanged();
865 void QQuickImageParticle::setOpacitytable(const QUrl &table)
867 if (table == m_opacitytable_name)
869 m_opacitytable_name = table;
870 emit opacitytableChanged();
874 void QQuickImageParticle::setColor(const QColor &color)
876 if (color == m_color)
880 m_explicitColor = true;
881 if (perfLevel < Colored)
885 void QQuickImageParticle::setColorVariation(qreal var)
887 if (var == m_color_variation)
889 m_color_variation = var;
890 emit colorVariationChanged();
891 m_explicitColor = true;
892 if (perfLevel < Colored)
896 void QQuickImageParticle::setAlphaVariation(qreal arg)
898 if (m_alphaVariation != arg) {
899 m_alphaVariation = arg;
900 emit alphaVariationChanged(arg);
902 m_explicitColor = true;
903 if (perfLevel < Colored)
907 void QQuickImageParticle::setAlpha(qreal arg)
909 if (m_alpha != arg) {
911 emit alphaChanged(arg);
913 m_explicitColor = true;
914 if (perfLevel < Colored)
918 void QQuickImageParticle::setRedVariation(qreal arg)
920 if (m_redVariation != arg) {
921 m_redVariation = arg;
922 emit redVariationChanged(arg);
924 m_explicitColor = true;
925 if (perfLevel < Colored)
929 void QQuickImageParticle::setGreenVariation(qreal arg)
931 if (m_greenVariation != arg) {
932 m_greenVariation = arg;
933 emit greenVariationChanged(arg);
935 m_explicitColor = true;
936 if (perfLevel < Colored)
940 void QQuickImageParticle::setBlueVariation(qreal arg)
942 if (m_blueVariation != arg) {
943 m_blueVariation = arg;
944 emit blueVariationChanged(arg);
946 m_explicitColor = true;
947 if (perfLevel < Colored)
951 void QQuickImageParticle::setRotation(qreal arg)
953 if (m_rotation != arg) {
955 emit rotationChanged(arg);
957 m_explicitRotation = true;
958 if (perfLevel < Deformable)
962 void QQuickImageParticle::setRotationVariation(qreal arg)
964 if (m_rotationVariation != arg) {
965 m_rotationVariation = arg;
966 emit rotationVariationChanged(arg);
968 m_explicitRotation = true;
969 if (perfLevel < Deformable)
973 void QQuickImageParticle::setRotationSpeed(qreal arg)
975 if (m_rotationSpeed != arg) {
976 m_rotationSpeed = arg;
977 emit rotationSpeedChanged(arg);
979 m_explicitRotation = true;
980 if (perfLevel < Deformable)
984 void QQuickImageParticle::setRotationSpeedVariation(qreal arg)
986 if (m_rotationSpeedVariation != arg) {
987 m_rotationSpeedVariation = arg;
988 emit rotationSpeedVariationChanged(arg);
990 m_explicitRotation = true;
991 if (perfLevel < Deformable)
995 void QQuickImageParticle::setAutoRotation(bool arg)
997 if (m_autoRotation != arg) {
998 m_autoRotation = arg;
999 emit autoRotationChanged(arg);
1001 m_explicitRotation = true;
1002 if (perfLevel < Deformable)
1006 void QQuickImageParticle::setXVector(QQuickDirection* arg)
1008 if (m_xVector != arg) {
1010 emit xVectorChanged(arg);
1012 m_explicitDeformation = true;
1013 if (perfLevel < Deformable)
1017 void QQuickImageParticle::setYVector(QQuickDirection* arg)
1019 if (m_yVector != arg) {
1021 emit yVectorChanged(arg);
1023 m_explicitDeformation = true;
1024 if (perfLevel < Deformable)
1028 void QQuickImageParticle::setSpritesInterpolate(bool arg)
1030 if (m_spritesInterpolate != arg) {
1031 m_spritesInterpolate = arg;
1032 emit spritesInterpolateChanged(arg);
1036 void QQuickImageParticle::setBypassOptimizations(bool arg)
1038 if (m_bypassOptimizations != arg) {
1039 m_bypassOptimizations = arg;
1040 emit bypassOptimizationsChanged(arg);
1042 if (perfLevel < 9999)
1046 void QQuickImageParticle::setEntryEffect(EntryEffect arg)
1048 if (m_entryEffect != arg) {
1049 m_entryEffect = arg;
1051 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1052 emit entryEffectChanged(arg);
1056 void QQuickImageParticle::resetColor()
1058 m_explicitColor = false;
1059 foreach (const QString &str, m_groups)
1060 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1061 if (d->colorOwner == this)
1064 m_color_variation = 0.0f;
1065 m_redVariation = 0.0f;
1066 m_blueVariation = 0.0f;
1067 m_greenVariation = 0.0f;
1069 m_alphaVariation = 0.0f;
1072 void QQuickImageParticle::resetRotation()
1074 m_explicitRotation = false;
1075 foreach (const QString &str, m_groups)
1076 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1077 if (d->rotationOwner == this)
1078 d->rotationOwner = 0;
1080 m_rotationVariation = 0;
1081 m_rotationSpeed = 0;
1082 m_rotationSpeedVariation = 0;
1083 m_autoRotation = false;
1086 void QQuickImageParticle::resetDeformation()
1088 m_explicitDeformation = false;
1089 foreach (const QString &str, m_groups)
1090 foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data)
1091 if (d->deformationOwner == this)
1092 d->deformationOwner = 0;
1101 void QQuickImageParticle::reset()
1103 QQuickParticlePainter::reset();
1104 m_pleaseReset = true;
1108 void QQuickImageParticle::createEngine()
1111 delete m_spriteEngine;
1112 if (m_sprites.count()) {
1113 m_spriteEngine = new QQuickSpriteEngine(m_sprites, this);
1114 connect(m_spriteEngine, SIGNAL(stateChanged(int)),
1115 this, SLOT(spriteAdvance(int)), Qt::DirectConnection);
1116 m_explicitAnimation = true;
1119 m_explicitAnimation = false;
1124 static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
1125 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1126 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1127 QSGGeometry::Attribute::create(2, 4, GL_FLOAT) // Vectors
1130 static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
1132 3, // Attribute Count
1133 ( 2 + 4 + 4 ) * sizeof(float),
1134 SimpleParticle_Attributes
1137 static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
1138 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position
1139 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1140 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1141 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1144 static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
1146 4, // Attribute Count
1147 ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar),
1148 ColoredParticle_Attributes
1151 static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
1152 QSGGeometry::Attribute::create(0, 4, GL_FLOAT), // Position & TexCoord
1153 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1154 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1155 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1156 QSGGeometry::Attribute::create(4, 4, GL_FLOAT), // DeformationVectors
1157 QSGGeometry::Attribute::create(5, 3, GL_FLOAT), // Rotation
1160 static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
1162 6, // Attribute Count
1163 (4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1164 DeformableParticle_Attributes
1167 static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
1168 QSGGeometry::Attribute::create(0, 4, GL_FLOAT), // Position & TexCoord
1169 QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data
1170 QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors
1171 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors
1172 QSGGeometry::Attribute::create(4, 4, GL_FLOAT), // DeformationVectors
1173 QSGGeometry::Attribute::create(5, 3, GL_FLOAT), // Rotation
1174 QSGGeometry::Attribute::create(6, 4, GL_FLOAT), // Anim Data
1175 QSGGeometry::Attribute::create(7, 4, GL_FLOAT) // Anim Pos
1178 static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
1180 8, // Attribute Count
1181 (4 + 4 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
1182 SpriteParticle_Attributes
1185 void QQuickImageParticle::clearShadows()
1187 foreach (const QVector<QQuickParticleData*> data, m_shadowData)
1189 m_shadowData.clear();
1192 //Only call if you need to, may initialize the whole array first time
1193 QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datum)
1195 QQuickParticleGroupData* gd = m_system->groupData[datum->group];
1196 if (!m_shadowData.contains(datum->group)) {
1197 QVector<QQuickParticleData*> data;
1198 for (int i=0; i<gd->size(); i++){
1199 QQuickParticleData* datum = new QQuickParticleData(m_system);
1200 *datum = *(gd->data[i]);
1203 m_shadowData.insert(datum->group, data);
1205 //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request
1207 return m_shadowData[datum->group][datum->index];
1210 QSGGeometryNode* QQuickImageParticle::buildParticleNodes()
1212 #ifdef QT_OPENGL_ES_2
1213 if (m_count * 4 > 0xffff) {
1214 printf("ImageParticle: Too many particles - maximum 16,000 per ImageParticle.\n");//ES 2 vertex count limit is ushort
1222 m_debugMode = m_system->m_debugMode;
1224 if (m_sprites.count() || m_bypassOptimizations) {
1225 perfLevel = Sprites;
1226 } else if (!m_colortable_name.isEmpty() || !m_sizetable_name.isEmpty()
1227 || !m_opacitytable_name.isEmpty()) {
1229 } else if (m_autoRotation || m_rotation || m_rotationVariation
1230 || m_rotationSpeed || m_rotationSpeedVariation
1231 || m_xVector || m_yVector) {
1232 perfLevel = Deformable;
1233 } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation
1234 || m_redVariation || m_blueVariation || m_greenVariation) {
1235 perfLevel = Colored;
1240 foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders
1241 int gIdx = m_system->groupIds[str];
1242 foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){
1243 QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p);
1245 if (other->perfLevel > perfLevel) {
1246 if (other->perfLevel >= Tabled){//Deformable is the highest level needed for this, anything higher isn't shared (or requires your own sprite)
1247 if (perfLevel < Deformable)
1248 perfLevel = Deformable;
1250 perfLevel = other->perfLevel;
1252 } else if (other->perfLevel < perfLevel) {
1259 if (perfLevel >= Colored && !m_color.isValid())
1260 m_color = QColor(Qt::white);//Hidden default, but different from unset
1263 if (perfLevel >= Sprites){
1264 if (!m_spriteEngine) {
1265 qWarning() << "ImageParticle: No sprite engine...";
1266 //Sprite performance mode with static image is supported, but not advised
1267 //Note that in this case it always uses shadow data
1269 image = m_spriteEngine->assembledImage();
1270 if (image.isNull())//Warning is printed in engine
1275 if ( image.isNull() ) {
1276 image = QImage(m_image_name.toLocalFile());
1277 if (image.isNull()) {
1278 printf("ImageParticle: loading image failed '%s'\n", qPrintable(m_image_name.toLocalFile()));
1290 QImage opacitytable;
1291 switch (perfLevel) {//Fallthrough intended
1293 m_material = SpriteMaterial::createMaterial();
1294 getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size());
1296 m_spriteEngine->setCount(m_count);
1299 m_material = TabledMaterial::createMaterial();
1300 colortable = QImage(m_colortable_name.toLocalFile());
1301 sizetable = QImage(m_sizetable_name.toLocalFile());
1302 opacitytable = QImage(m_opacitytable_name.toLocalFile());
1303 if (colortable.isNull()){
1304 colortable = QImage(1,1,QImage::Format_ARGB32);
1305 colortable.fill(Qt::white);
1307 Q_ASSERT(!colortable.isNull());
1308 getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable);
1309 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
1310 fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE);
1313 m_material = DeformableMaterial::createMaterial();
1316 m_material = ColoredMaterial::createMaterial();
1317 default://Also Simple
1319 m_material = SimpleMaterial::createMaterial();
1320 getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image);
1321 getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear);
1322 getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect;
1323 m_material->setFlag(QSGMaterial::Blending);
1327 foreach (const QString &str, m_groups){
1328 int gIdx = m_system->groupIds[str];
1329 int count = m_system->groupData[gIdx]->size();
1330 QSGGeometryNode* node = new QSGGeometryNode();
1331 node->setMaterial(m_material);
1332 node->markDirty(QSGNode::DirtyMaterial);
1334 m_nodes.insert(gIdx, node);
1335 m_idxStarts.insert(gIdx, m_lastIdxStart);
1336 m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx));
1337 m_lastIdxStart += count;
1339 //Create Particle Geometry
1340 int vCount = count * 4;
1341 int iCount = count * 6;
1344 if (perfLevel == Sprites)
1345 g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
1346 else if (perfLevel == Tabled)
1347 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1348 else if (perfLevel == Deformable)
1349 g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
1350 else if (perfLevel == Colored)
1351 g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0);
1353 g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0);
1355 node->setGeometry(g);
1356 if (perfLevel <= Colored){
1357 g->setDrawingMode(GL_POINTS);
1359 GLfloat pointSizeRange[2];
1360 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange);
1361 qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1];
1364 g->setDrawingMode(GL_TRIANGLES);
1366 for (int p=0; p < count; ++p)
1367 commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch
1369 if (perfLevel == Sprites)
1370 initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount);
1371 else if (perfLevel == Tabled)
1372 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1373 else if (perfLevel == Deformable)
1374 initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount);
1376 if (perfLevel > Colored){
1377 quint16 *indices = g->indexDataAsUShort();
1378 for (int i=0; i < count; ++i) {
1392 foreach (QSGGeometryNode* node, m_nodes){
1393 if (node == *(m_nodes.begin()))
1394 node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes
1396 (*(m_nodes.begin()))->appendChildNode(node);
1399 return *(m_nodes.begin());
1402 QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
1405 m_lastLevel = perfLevel;
1407 delete m_rootNode;//Automatically deletes children, and SG manages material lifetime
1411 m_idxStarts.clear();
1412 m_startsIdx.clear();
1417 m_pleaseReset = false;
1420 if (m_system && m_system->isRunning() && !m_system->isPaused()){
1424 foreach (QSGGeometryNode* node, m_nodes)
1425 node->markDirty(QSGNode::DirtyGeometry);
1432 void QQuickImageParticle::prepareNextFrame()
1434 if (m_rootNode == 0){//TODO: Staggered loading (as emitted)
1435 m_rootNode = buildParticleNodes();
1437 qDebug() << "QQuickImageParticle Feature level: " << perfLevel;
1438 qDebug() << "QQuickImageParticle Nodes: ";
1440 foreach (int i, m_nodes.keys()) {
1441 qDebug() << "Group " << i << " (" << m_system->groupData[i]->size() << " particles)";
1442 count += m_system->groupData[i]->size();
1444 qDebug() << "Total count: " << count;
1446 if (m_rootNode == 0)
1449 qint64 timeStamp = m_system->systemSync(this);
1451 qreal time = timeStamp / 1000.;
1453 switch (perfLevel){//Fall-through intended
1457 m_spriteEngine->updateSprites(timeStamp);
1462 default: //Also Simple
1463 getState<ImageMaterialData>(m_material)->timestamp = time;
1466 foreach (QSGGeometryNode* node, m_nodes)
1467 node->markDirty(QSGNode::DirtyMaterial);
1470 void QQuickImageParticle::spriteAdvance(int spriteIdx)
1472 if (!m_startsIdx.count())//Probably overly defensive
1477 for (i = 0; i<m_startsIdx.count(); i++) {
1478 if (spriteIdx < m_startsIdx[i].first) {
1479 gIdx = m_startsIdx[i-1].second;
1484 gIdx = m_startsIdx[i-1].second;
1485 int pIdx = spriteIdx - m_startsIdx[i-1].first;
1487 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1488 QQuickParticleData* d = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1490 d->animIdx = m_spriteEngine->spriteState(spriteIdx);
1491 Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData();
1492 Vertices<SpriteVertex> &p = particles[pIdx];
1493 d->animT = p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0;
1494 d->frameCount = p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1495 d->frameDuration = p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1496 d->animX = p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx);
1497 d->animY = p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx);
1498 d->animWidth = p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1499 d->animHeight = p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1502 void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d)
1505 //TODO: get index for reload - or make function take an index
1508 void QQuickImageParticle::initialize(int gIdx, int pIdx)
1511 QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx];
1512 qreal redVariation = m_color_variation + m_redVariation;
1513 qreal greenVariation = m_color_variation + m_greenVariation;
1514 qreal blueVariation = m_color_variation + m_blueVariation;
1516 if (m_spriteEngine) {
1517 spriteIdx = m_idxStarts[gIdx] + datum->index;
1518 if (spriteIdx >= m_spriteEngine->count())
1519 m_spriteEngine->setCount(spriteIdx+1);
1523 float rotationSpeed;
1525 switch (perfLevel){//Fall-through is intended on all of them
1527 // Initial Sprite State
1528 if (m_explicitAnimation && m_spriteEngine){
1529 if (!datum->animationOwner)
1530 datum->animationOwner = this;
1531 QQuickParticleData* writeTo = (datum->animationOwner == this ? datum : getShadowDatum(datum));
1532 writeTo->animT = writeTo->t;
1533 //writeTo->animInterpolate = m_spritesInterpolate;
1534 if (m_spriteEngine){
1535 m_spriteEngine->start(spriteIdx);
1536 writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
1537 writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
1538 writeTo->animIdx = 0;//Always starts at 0
1539 writeTo->animX = m_spriteEngine->spriteX(spriteIdx);
1540 writeTo->animY = m_spriteEngine->spriteY(spriteIdx);
1541 writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx);
1542 writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx);
1545 QQuickParticleData* writeTo = getShadowDatum(datum);
1546 writeTo->animT = datum->t;
1547 writeTo->frameCount = 1;
1548 writeTo->frameDuration = 60000000.0;
1549 writeTo->animIdx = 0;
1551 writeTo->animX = writeTo->animY = 0;
1552 writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width();
1553 writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height();
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_spriteEngine ? (m_spritesInterpolate ? 1.0 : 0.0) : 0.0;//### Shadow? In particleData? Or uniform?
1671 if (!m_spriteEngine || (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);