aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/particles
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-06-24 16:37:03 +1000
committerAaron Kennedy <aaron.kennedy@nokia.com>2011-06-24 16:37:03 +1000
commit2a18f33552d20b637989e876175c6bd03c69bc97 (patch)
tree1bfe921c52dcebeaadf79511168db7d8164ee062 /src/declarative/particles
parent09b01b54f23fb10fd6b63398edf813a2bbd04cff (diff)
parenta9853d2ffe177bf98eb7610b58bb1bbb44743510 (diff)
Merge branch 'qtquick2' of scm.dev.nokia.troll.no:qt/qtdeclarative-staging
Conflicts: src/declarative/items/qsgtextnode.cpp
Diffstat (limited to 'src/declarative/particles')
-rw-r--r--src/declarative/particles/defaultshaders/ctfragment.shader11
-rw-r--r--src/declarative/particles/defaultshaders/ctvertex.shader38
-rw-r--r--src/declarative/particles/defaultshaders/defaultFadeInOut.pngbin0 -> 286 bytes
-rw-r--r--src/declarative/particles/defaultshaders/deformablefragment.shader8
-rw-r--r--src/declarative/particles/defaultshaders/deformablevertex.shader57
-rw-r--r--src/declarative/particles/defaultshaders/identitytable.pngbin0 -> 90 bytes
-rw-r--r--src/declarative/particles/defaultshaders/simplefragment.shader8
-rw-r--r--src/declarative/particles/defaultshaders/simplevertex.shader36
-rw-r--r--src/declarative/particles/defaultshaders/spritefragment.shader10
-rw-r--r--src/declarative/particles/defaultshaders/spriteimagefragment.shader9
-rw-r--r--src/declarative/particles/defaultshaders/spriteimagevertex.shader52
-rw-r--r--src/declarative/particles/defaultshaders/spritevertex.shader77
-rw-r--r--src/declarative/particles/defaultshaders/superfragment.shader11
-rw-r--r--src/declarative/particles/defaultshaders/supervertex.shader57
-rw-r--r--src/declarative/particles/defaultshaders/trailsfragment.shader8
-rw-r--r--src/declarative/particles/defaultshaders/trailsvertex.shader37
-rw-r--r--src/declarative/particles/defaultshaders/ultrafragment.shader16
-rw-r--r--src/declarative/particles/defaultshaders/ultravertex.shader94
-rw-r--r--src/declarative/particles/particles.pri60
-rw-r--r--src/declarative/particles/particles.qrc22
-rw-r--r--src/declarative/particles/qsgangleddirection.cpp66
-rw-r--r--src/declarative/particles/qsgangleddirection_p.h133
-rw-r--r--src/declarative/particles/qsgcustomparticle.cpp518
-rw-r--r--src/declarative/particles/qsgcustomparticle_p.h118
-rw-r--r--src/declarative/particles/qsgellipseextruder.cpp64
-rw-r--r--src/declarative/particles/qsgellipseextruder_p.h86
-rw-r--r--src/declarative/particles/qsgemitter.cpp199
-rw-r--r--src/declarative/particles/qsgemitter_p.h104
-rw-r--r--src/declarative/particles/qsgfollowemitter.cpp194
-rw-r--r--src/declarative/particles/qsgfollowemitter_p.h168
-rw-r--r--src/declarative/particles/qsgfriction.cpp59
-rw-r--r--src/declarative/particles/qsgfriction_p.h86
-rw-r--r--src/declarative/particles/qsggravity.cpp77
-rw-r--r--src/declarative/particles/qsggravity_p.h106
-rw-r--r--src/declarative/particles/qsgimageparticle.cpp934
-rw-r--r--src/declarative/particles/qsgimageparticle_p.h344
-rw-r--r--src/declarative/particles/qsgitemparticle.cpp212
-rw-r--r--src/declarative/particles/qsgitemparticle_p.h138
-rw-r--r--src/declarative/particles/qsgkill.cpp59
-rw-r--r--src/declarative/particles/qsgkill_p.h68
-rw-r--r--src/declarative/particles/qsglineextruder.cpp66
-rw-r--r--src/declarative/particles/qsglineextruder_p.h77
-rw-r--r--src/declarative/particles/qsgmaskextruder.cpp98
-rw-r--r--src/declarative/particles/qsgmaskextruder_p.h97
-rw-r--r--src/declarative/particles/qsgmodelparticle.cpp275
-rw-r--r--src/declarative/particles/qsgmodelparticle_p.h139
-rw-r--r--src/declarative/particles/qsgparticleaffector.cpp123
-rw-r--r--src/declarative/particles/qsgparticleaffector_p.h192
-rw-r--r--src/declarative/particles/qsgparticleemitter.cpp157
-rw-r--r--src/declarative/particles/qsgparticleemitter_p.h305
-rw-r--r--src/declarative/particles/qsgparticleextruder.cpp78
-rw-r--r--src/declarative/particles/qsgparticleextruder_p.h90
-rw-r--r--src/declarative/particles/qsgparticlepainter.cpp188
-rw-r--r--src/declarative/particles/qsgparticlepainter_p.h134
-rw-r--r--src/declarative/particles/qsgparticlesmodule.cpp111
-rw-r--r--src/declarative/particles/qsgparticlesmodule_p.h63
-rw-r--r--src/declarative/particles/qsgparticlesystem.cpp447
-rw-r--r--src/declarative/particles/qsgparticlesystem_p.h254
-rw-r--r--src/declarative/particles/qsgpointattractor.cpp88
-rw-r--r--src/declarative/particles/qsgpointattractor_p.h168
-rw-r--r--src/declarative/particles/qsgpointdirection.cpp62
-rw-r--r--src/declarative/particles/qsgpointdirection_p.h135
-rw-r--r--src/declarative/particles/qsgspritegoal.cpp100
-rw-r--r--src/declarative/particles/qsgspritegoal_p.h104
-rw-r--r--src/declarative/particles/qsgstochasticdirection.cpp56
-rw-r--r--src/declarative/particles/qsgstochasticdirection_p.h72
-rw-r--r--src/declarative/particles/qsgtargeteddirection.cpp93
-rw-r--r--src/declarative/particles/qsgtargeteddirection_p.h190
-rw-r--r--src/declarative/particles/qsgturbulence.cpp163
-rw-r--r--src/declarative/particles/qsgturbulence_p.h125
-rw-r--r--src/declarative/particles/qsgwander.cpp144
-rw-r--r--src/declarative/particles/qsgwander_p.h161
72 files changed, 8899 insertions, 0 deletions
diff --git a/src/declarative/particles/defaultshaders/ctfragment.shader b/src/declarative/particles/defaultshaders/ctfragment.shader
new file mode 100644
index 0000000000..a17f5841ca
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/ctfragment.shader
@@ -0,0 +1,11 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor * texture2D(colortable, vec2(tt, 0.5)) *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/declarative/particles/defaultshaders/ctvertex.shader b/src/declarative/particles/defaultshaders/ctvertex.shader
new file mode 100644
index 0000000000..b20676cc49
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/ctvertex.shader
@@ -0,0 +1,38 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute lowp vec4 vColor;
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform sampler2D sizetable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos = vPos
+ - currentSize / 2. + currentSize * vTex // adjust size
+ + vVec.xy * t * vData.y // apply speed vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/declarative/particles/defaultshaders/defaultFadeInOut.png b/src/declarative/particles/defaultshaders/defaultFadeInOut.png
new file mode 100644
index 0000000000..89c04eaefe
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/defaultFadeInOut.png
Binary files differ
diff --git a/src/declarative/particles/defaultshaders/deformablefragment.shader b/src/declarative/particles/defaultshaders/deformablefragment.shader
new file mode 100644
index 0000000000..494053e319
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/deformablefragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex)) * fFade;
+}
diff --git a/src/declarative/particles/defaultshaders/deformablevertex.shader b/src/declarative/particles/defaultshaders/deformablevertex.shader
new file mode 100644
index 0000000000..01570950b1
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/deformablevertex.shader
@@ -0,0 +1,57 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t);
+
+ highp vec2 pos;
+ if (t < 0. || t > 1.){
+ currentSize = 0.;
+ pos = vPos;
+ }else{
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+ }
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fFade = fadeIn * fadeOut * opacity;
+}
diff --git a/src/declarative/particles/defaultshaders/identitytable.png b/src/declarative/particles/defaultshaders/identitytable.png
new file mode 100644
index 0000000000..2cada1bfad
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/identitytable.png
Binary files differ
diff --git a/src/declarative/particles/defaultshaders/simplefragment.shader b/src/declarative/particles/defaultshaders/simplefragment.shader
new file mode 100644
index 0000000000..494053e319
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/simplefragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex)) * fFade;
+}
diff --git a/src/declarative/particles/defaultshaders/simplevertex.shader b/src/declarative/particles/defaultshaders/simplevertex.shader
new file mode 100644
index 0000000000..f185ef0700
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/simplevertex.shader
@@ -0,0 +1,36 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t);
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos = vPos
+ - currentSize / 2. + currentSize * vTex // adjust size
+ + vVec.xy * t * vData.y // apply speed vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fFade = fadeIn * fadeOut * opacity;
+}
diff --git a/src/declarative/particles/defaultshaders/spritefragment.shader b/src/declarative/particles/defaultshaders/spritefragment.shader
new file mode 100644
index 0000000000..4d89d69c6a
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/spritefragment.shader
@@ -0,0 +1,10 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress) * fColor.w;
+}
diff --git a/src/declarative/particles/defaultshaders/spriteimagefragment.shader b/src/declarative/particles/defaultshaders/spriteimagefragment.shader
new file mode 100644
index 0000000000..ecd62cf390
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/spriteimagefragment.shader
@@ -0,0 +1,9 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress);
+}
diff --git a/src/declarative/particles/defaultshaders/spriteimagevertex.shader b/src/declarative/particles/defaultshaders/spriteimagevertex.shader
new file mode 100644
index 0000000000..27de2ada6a
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/spriteimagevertex.shader
@@ -0,0 +1,52 @@
+attribute highp vec2 vTex;
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+uniform highp float width;
+uniform highp float height;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+
+
+void main() {
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+
+ gl_Position = matrix * vec4(width * vTex.x, height * vTex.y, 0, 1);
+}
diff --git a/src/declarative/particles/defaultshaders/spritevertex.shader b/src/declarative/particles/defaultshaders/spritevertex.shader
new file mode 100644
index 0000000000..78b8e36b3b
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/spritevertex.shader
@@ -0,0 +1,77 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+void main() {
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex = vTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ //### Should the next anim be precalculated to allow for interpolation there?
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+ //Applying Size here seems to screw with RockingAffector?
+ highp float currentSize = mix(size, endSize, t * t);
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ //If affector is mananging pos, they don't set speed?
+ highp vec2 pos = vPos
+ - currentSize / 2. + currentSize * vTex // adjust size
+ + vVec.xy * t * vData.y // apply speed vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ // calculate opacity
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ lowp vec4 white = vec4(1.);
+ fColor = white * fadeIn * fadeOut * opacity;
+}
diff --git a/src/declarative/particles/defaultshaders/superfragment.shader b/src/declarative/particles/defaultshaders/superfragment.shader
new file mode 100644
index 0000000000..a17f5841ca
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/superfragment.shader
@@ -0,0 +1,11 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor * texture2D(colortable, vec2(tt, 0.5)) *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/declarative/particles/defaultshaders/supervertex.shader b/src/declarative/particles/defaultshaders/supervertex.shader
new file mode 100644
index 0000000000..432a23ce05
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/supervertex.shader
@@ -0,0 +1,57 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute lowp vec4 vColor;
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform sampler2D sizetable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos;
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/declarative/particles/defaultshaders/trailsfragment.shader b/src/declarative/particles/defaultshaders/trailsfragment.shader
new file mode 100644
index 0000000000..d3db87fa30
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/trailsfragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor;
+}
diff --git a/src/declarative/particles/defaultshaders/trailsvertex.shader b/src/declarative/particles/defaultshaders/trailsvertex.shader
new file mode 100644
index 0000000000..7bc1d66b71
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/trailsvertex.shader
@@ -0,0 +1,37 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute lowp vec4 vColor;
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+
+void main() {
+ fTex = vTex;
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ highp float currentSize = mix(size, endSize, t * t);
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos = vPos
+ - currentSize / 2. + currentSize * vTex // adjust size
+ + vVec.xy * t * vData.y // apply speed vector..
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.);
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fColor = vColor * fadeIn * fadeOut * opacity;
+}
diff --git a/src/declarative/particles/defaultshaders/ultrafragment.shader b/src/declarative/particles/defaultshaders/ultrafragment.shader
new file mode 100644
index 0000000000..0627d0f1e8
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/ultrafragment.shader
@@ -0,0 +1,16 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress)
+ * fColor
+ * texture2D(colortable, vec2(tt, 0.5))
+ *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/declarative/particles/defaultshaders/ultravertex.shader b/src/declarative/particles/defaultshaders/ultravertex.shader
new file mode 100644
index 0000000000..65a1a3077a
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/ultravertex.shader
@@ -0,0 +1,94 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute lowp vec4 vColor;
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+uniform sampler2D sizetable;
+
+varying lowp float tt;
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+
+void main() {
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex = vTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ //### Should the next anim be precalculated to allow for interpolation there?
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+ highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos;
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/declarative/particles/particles.pri b/src/declarative/particles/particles.pri
new file mode 100644
index 0000000000..04200a380e
--- /dev/null
+++ b/src/declarative/particles/particles.pri
@@ -0,0 +1,60 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qsgangleddirection_p.h \
+ $$PWD/qsgcustomparticle_p.h \
+ $$PWD/qsgellipseextruder_p.h \
+ $$PWD/qsgemitter_p.h \
+ $$PWD/qsgfollowemitter_p.h \
+ $$PWD/qsgfriction_p.h \
+ $$PWD/qsggravity_p.h \
+ $$PWD/qsgimageparticle_p.h \
+ $$PWD/qsgitemparticle_p.h \
+ $$PWD/qsgkill_p.h \
+ $$PWD/qsglineextruder_p.h \
+ $$PWD/qsgmaskextruder_p.h \
+ $$PWD/qsgmodelparticle_p.h \
+ $$PWD/qsgparticleaffector_p.h \
+ $$PWD/qsgparticleemitter_p.h \
+ $$PWD/qsgparticleextruder_p.h \
+ $$PWD/qsgparticlepainter_p.h \
+ $$PWD/qsgparticlesmodule_p.h \
+ $$PWD/qsgparticlesystem_p.h \
+ $$PWD/qsgpointattractor_p.h \
+ $$PWD/qsgpointdirection_p.h \
+ $$PWD/qsgspritegoal_p.h \
+ $$PWD/qsgstochasticdirection_p.h \
+ $$PWD/qsgtargeteddirection_p.h \
+ $$PWD/qsgturbulence_p.h \
+ $$PWD/qsgwander_p.h
+
+SOURCES += \
+ $$PWD/qsgangleddirection.cpp \
+ $$PWD/qsgcustomparticle.cpp \
+ $$PWD/qsgellipseextruder.cpp \
+ $$PWD/qsgemitter.cpp \
+ $$PWD/qsgfollowemitter.cpp \
+ $$PWD/qsgfriction.cpp \
+ $$PWD/qsggravity.cpp \
+ $$PWD/qsgimageparticle.cpp \
+ $$PWD/qsgitemparticle.cpp \
+ $$PWD/qsgkill.cpp \
+ $$PWD/qsglineextruder.cpp \
+ $$PWD/qsgmaskextruder.cpp \
+ $$PWD/qsgmodelparticle.cpp \
+ $$PWD/qsgparticleaffector.cpp \
+ $$PWD/qsgparticleemitter.cpp \
+ $$PWD/qsgparticleextruder.cpp \
+ $$PWD/qsgparticlepainter.cpp \
+ $$PWD/qsgparticlesmodule.cpp \
+ $$PWD/qsgparticlesystem.cpp \
+ $$PWD/qsgpointattractor.cpp \
+ $$PWD/qsgpointdirection.cpp \
+ $$PWD/qsgspritegoal.cpp \
+ $$PWD/qsgstochasticdirection.cpp \
+ $$PWD/qsgtargeteddirection.cpp \
+ $$PWD/qsgturbulence.cpp \
+ $$PWD/qsgwander.cpp
+
+RESOURCES += \
+ $$PWD/particles.qrc
diff --git a/src/declarative/particles/particles.qrc b/src/declarative/particles/particles.qrc
new file mode 100644
index 0000000000..85931ec9ce
--- /dev/null
+++ b/src/declarative/particles/particles.qrc
@@ -0,0 +1,22 @@
+<RCC>
+ <qresource prefix="/">
+ <file>defaultshaders/spritefragment.shader</file>
+ <file>defaultshaders/spritevertex.shader</file>
+ <file>defaultshaders/ctfragment.shader</file>
+ <file>defaultshaders/ctvertex.shader</file>
+ <file>defaultshaders/trailsfragment.shader</file>
+ <file>defaultshaders/trailsvertex.shader</file>
+ <file>defaultshaders/spriteimagefragment.shader</file>
+ <file>defaultshaders/spriteimagevertex.shader</file>
+ <file>defaultshaders/identitytable.png</file>
+ <file>defaultshaders/defaultFadeInOut.png</file>
+ <file>defaultshaders/deformablefragment.shader</file>
+ <file>defaultshaders/deformablevertex.shader</file>
+ <file>defaultshaders/ultravertex.shader</file>
+ <file>defaultshaders/ultrafragment.shader</file>
+ <file>defaultshaders/supervertex.shader</file>
+ <file>defaultshaders/superfragment.shader</file>
+ <file>defaultshaders/simplevertex.shader</file>
+ <file>defaultshaders/simplefragment.shader</file>
+ </qresource>
+</RCC>
diff --git a/src/declarative/particles/qsgangleddirection.cpp b/src/declarative/particles/qsgangleddirection.cpp
new file mode 100644
index 0000000000..5c32b53e3e
--- /dev/null
+++ b/src/declarative/particles/qsgangleddirection.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgangleddirection_p.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+const qreal CONV = 0.017453292519943295;
+QSGAngledDirection::QSGAngledDirection(QObject *parent) :
+ QSGStochasticDirection(parent)
+ , m_angle(0)
+ , m_magnitude(0)
+ , m_angleVariation(0)
+ , m_magnitudeVariation(0)
+{
+
+}
+
+const QPointF &QSGAngledDirection::sample(const QPointF &from)
+{
+ //TODO: Faster
+ qreal theta = m_angle*CONV - m_angleVariation*CONV + rand()/float(RAND_MAX) * m_angleVariation*CONV * 2;
+ qreal mag = m_magnitude- m_magnitudeVariation + rand()/float(RAND_MAX) * m_magnitudeVariation * 2;
+ m_ret.setX(mag * cos(theta));
+ m_ret.setY(mag * sin(theta));
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgangleddirection_p.h b/src/declarative/particles/qsgangleddirection_p.h
new file mode 100644
index 0000000000..76262453a9
--- /dev/null
+++ b/src/declarative/particles/qsgangleddirection_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGANGLEDDIRECTION_H
+#define QSGANGLEDDIRECTION_H
+#include "qsgstochasticdirection_p.h"
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGAngledDirection : public QSGStochasticDirection
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged)
+ Q_PROPERTY(qreal angleVariation READ angleVariation WRITE setAngleVariation NOTIFY angleVariationChanged)
+ Q_PROPERTY(qreal magnitudeVariation READ magnitudeVariation WRITE setMagnitudeVariation NOTIFY magnitudeVariationChanged)
+public:
+ explicit QSGAngledDirection(QObject *parent = 0);
+ const QPointF &sample(const QPointF &from);
+ qreal angle() const
+ {
+ return m_angle;
+ }
+
+ qreal magnitude() const
+ {
+ return m_magnitude;
+ }
+
+ qreal angleVariation() const
+ {
+ return m_angleVariation;
+ }
+
+ qreal magnitudeVariation() const
+ {
+ return m_magnitudeVariation;
+ }
+
+signals:
+
+ void angleChanged(qreal arg);
+
+ void magnitudeChanged(qreal arg);
+
+ void angleVariationChanged(qreal arg);
+
+ void magnitudeVariationChanged(qreal arg);
+
+public slots:
+void setAngle(qreal arg)
+{
+ if (m_angle != arg) {
+ m_angle = arg;
+ emit angleChanged(arg);
+ }
+}
+
+void setMagnitude(qreal arg)
+{
+ if (m_magnitude != arg) {
+ m_magnitude = arg;
+ emit magnitudeChanged(arg);
+ }
+}
+
+void setAngleVariation(qreal arg)
+{
+ if (m_angleVariation != arg) {
+ m_angleVariation = arg;
+ emit angleVariationChanged(arg);
+ }
+}
+
+void setMagnitudeVariation(qreal arg)
+{
+ if (m_magnitudeVariation != arg) {
+ m_magnitudeVariation = arg;
+ emit magnitudeVariationChanged(arg);
+ }
+}
+
+private:
+qreal m_angle;
+qreal m_magnitude;
+qreal m_angleVariation;
+qreal m_magnitudeVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // QSGANGLEDDIRECTION_H
diff --git a/src/declarative/particles/qsgcustomparticle.cpp b/src/declarative/particles/qsgcustomparticle.cpp
new file mode 100644
index 0000000000..46f160ddf4
--- /dev/null
+++ b/src/declarative/particles/qsgcustomparticle.cpp
@@ -0,0 +1,518 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgcustomparticle_p.h"
+#include <private/qsgshadereffectmesh_p.h>
+#include <cstdlib>
+
+QT_BEGIN_NAMESPACE
+
+//TODO: Can we make the code such that you don't have to copy the whole vertex shader just to add one little calculation?
+//Includes comments because the code isn't self explanatory
+static const char qt_particles_default_vertex_code[] =
+ "attribute highp vec2 vPos; \n"
+ "attribute highp vec2 vTex; \n"
+ "attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize \n"
+ "attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration \n"
+ "uniform highp mat4 qt_ModelViewProjectionMatrix; \n"
+ "uniform highp float timestamp; \n"
+ "varying highp vec2 fTex; \n"
+ "void main() { \n"
+ " fTex = vTex; \n"
+ " highp float size = vData.z; \n"
+ " highp float endSize = vData.w; \n"
+ " highp float t = (timestamp - vData.x) / vData.y; \n"
+ " highp float currentSize = mix(size, endSize, t * t); \n"
+ " if (t < 0. || t > 1.) \n"
+ " currentSize = 0.; \n"
+ " highp vec2 pos = vPos \n"
+ " - currentSize / 2. + currentSize * vTex // adjust size \n"
+ " + vVec.xy * t * vData.y // apply speed vector.. \n"
+ " + 0.5 * vVec.zw * pow(t * vData.y, 2.); \n"
+ " gl_Position = qt_ModelViewProjectionMatrix * vec4(pos.x, pos.y, 0, 1); \n"
+ "}";
+
+static const char qt_particles_default_fragment_code[] =//TODO: Default frag requires source?
+ "uniform sampler2D source; \n"
+ "varying highp vec2 fTex; \n"
+ "uniform lowp float qt_Opacity; \n"
+ "void main() { \n"
+ " gl_FragColor = texture2D(source, fTex) * qt_Opacity; \n"
+ "}";
+
+static const char qt_position_attribute_name[] = "qt_Vertex";
+static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
+
+static QSGGeometry::Attribute PlainParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 1, GL_FLOAT } // r
+};
+
+static QSGGeometry::AttributeSet PlainParticle_AttributeSet =
+{
+ 5, // Attribute Count
+ (2 + 2 + 4 + 4 + 1) * sizeof(float),
+ PlainParticle_Attributes
+};
+
+struct PlainVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ float r;
+};
+
+struct PlainVertices {
+ PlainVertex v1;
+ PlainVertex v2;
+ PlainVertex v3;
+ PlainVertex v4;
+};
+
+QSGCustomParticle::QSGCustomParticle(QSGItem* parent)
+ : QSGParticlePainter(parent)
+ , m_pleaseReset(true)
+ , m_dirtyData(true)
+{
+ setFlag(QSGItem::ItemHasContents);
+}
+
+void QSGCustomParticle::componentComplete()
+{
+ reset();
+ QSGParticlePainter::componentComplete();
+}
+
+
+//Trying to keep the shader conventions the same as in qsgshadereffectitem
+/*!
+ \qmlproperty string CustomParticle::fragmentShader
+
+ This property holds the fragment shader's GLSL source code.
+ The default shader passes the texture coordinate along to the fragment
+ shader as "varying highp vec2 qt_TexCoord0".
+*/
+
+void QSGCustomParticle::setFragmentShader(const QByteArray &code)
+{
+ if (m_source.fragmentCode.constData() == code.constData())
+ return;
+ m_source.fragmentCode = code;
+ if (isComponentComplete()) {
+ reset();
+ }
+ emit fragmentShaderChanged();
+}
+
+/*!
+ \qmlproperty string CustomParticle::vertexShader
+
+ This property holds the vertex shader's GLSL source code.
+ The default shader expects the texture coordinate to be passed from the
+ vertex shader as "varying highp vec2 qt_TexCoord0", and it samples from a
+ sampler2D named "source".
+*/
+
+void QSGCustomParticle::setVertexShader(const QByteArray &code)
+{
+ if (m_source.vertexCode.constData() == code.constData())
+ return;
+ m_source.vertexCode = code;
+ if (isComponentComplete()) {
+ reset();
+ }
+ emit vertexShaderChanged();
+}
+
+void QSGCustomParticle::reset()
+{
+ disconnectPropertySignals();
+
+ m_source.attributeNames.clear();
+ m_source.uniformNames.clear();
+ m_source.respectsOpacity = false;
+ m_source.respectsMatrix = false;
+ m_source.className = metaObject()->className();
+
+ for (int i = 0; i < m_sources.size(); ++i) {
+ const SourceData &source = m_sources.at(i);
+ delete source.mapper;
+ if (source.item && source.item->parentItem() == this)
+ source.item->setParentItem(0);
+ }
+ m_sources.clear();
+
+ QSGParticlePainter::reset();
+ m_pleaseReset = true;
+}
+
+
+void QSGCustomParticle::changeSource(int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+ QVariant v = property(m_sources.at(index).name.constData());
+ setSource(v, index);
+}
+
+void QSGCustomParticle::updateData()
+{
+ m_dirtyData = true;
+ update();
+}
+
+void QSGCustomParticle::setSource(const QVariant &var, int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+
+ SourceData &source = m_sources[index];
+
+ source.item = 0;
+ if (var.isNull()) {
+ return;
+ } else if (!qVariantCanConvert<QObject *>(var)) {
+ qWarning("Could not assign source of type '%s' to property '%s'.", var.typeName(), source.name.constData());
+ return;
+ }
+
+ QObject *obj = qVariantValue<QObject *>(var);
+
+ QSGTextureProvider *int3rface = QSGTextureProvider::from(obj);
+ if (!int3rface) {
+ qWarning("Could not assign property '%s', did not implement QSGTextureProvider.", source.name.constData());
+ }
+
+ source.item = qobject_cast<QSGItem *>(obj);
+
+ // TODO: Copy better solution in QSGShaderEffectItem when they find it.
+ // 'source.item' needs a canvas to get a scenegraph node.
+ // The easiest way to make sure it gets a canvas is to
+ // make it a part of the same item tree as 'this'.
+ if (source.item && source.item->parentItem() == 0) {
+ source.item->setParentItem(this);
+ source.item->setVisible(false);
+ }
+}
+
+void QSGCustomParticle::disconnectPropertySignals()
+{
+ disconnect(this, 0, this, SLOT(updateData()));
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ disconnect(this, 0, source.mapper, 0);
+ disconnect(source.mapper, 0, this, 0);
+ }
+}
+
+void QSGCustomParticle::connectPropertySignals()
+{
+ QSet<QByteArray>::const_iterator it;
+ for (it = m_source.uniformNames.begin(); it != m_source.uniformNames.end(); ++it) {
+ int pi = metaObject()->indexOfProperty(it->constData());
+ if (pi >= 0) {
+ QMetaProperty mp = metaObject()->property(pi);
+ if (!mp.hasNotifySignal())
+ qWarning("QSGShaderEffectItem: property '%s' does not have notification method!", it->constData());
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().signature());
+ connect(this, signalName, this, SLOT(updateData()));
+ } else {
+ qWarning("QSGShaderEffectItem: '%s' does not have a matching property!", it->constData());
+ }
+ }
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ int pi = metaObject()->indexOfProperty(source.name.constData());
+ if (pi >= 0) {
+ QMetaProperty mp = metaObject()->property(pi);
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().signature());
+ connect(this, signalName, source.mapper, SLOT(map()));
+ source.mapper->setMapping(this, i);
+ connect(source.mapper, SIGNAL(mapped(int)), this, SLOT(changeSource(int)));
+ } else {
+ qWarning("QSGShaderEffectItem: '%s' does not have a matching source!", source.name.constData());
+ }
+ }
+}
+
+void QSGCustomParticle::updateProperties()
+{
+ QByteArray vertexCode = m_source.vertexCode;
+ QByteArray fragmentCode = m_source.fragmentCode;
+ if (vertexCode.isEmpty())
+ vertexCode = qt_particles_default_vertex_code;
+ if (fragmentCode.isEmpty())
+ fragmentCode = qt_particles_default_fragment_code;
+
+ m_source.attributeNames.clear();
+ m_source.attributeNames << "vPos" << "vTex" << "vData" << "vVec" << "r";
+
+ lookThroughShaderCode(vertexCode);
+ lookThroughShaderCode(fragmentCode);
+
+ if (!m_source.attributeNames.contains(qt_position_attribute_name))
+ qWarning("QSGShaderEffectItem: Missing reference to \'%s\'.", qt_position_attribute_name);
+ if (!m_source.attributeNames.contains(qt_texcoord_attribute_name))
+ qWarning("QSGShaderEffectItem: Missing reference to \'%s\'.", qt_texcoord_attribute_name);
+ if (!m_source.respectsMatrix)
+ qWarning("QSGShaderEffectItem: Missing reference to \'qt_ModelViewProjectionMatrix\'.");
+ if (!m_source.respectsOpacity)
+ qWarning("QSGShaderEffectItem: Missing reference to \'qt_Opacity\'.");
+
+ for (int i = 0; i < m_sources.size(); ++i) {
+ QVariant v = property(m_sources.at(i).name);
+ setSource(v, i);
+ }
+
+ connectPropertySignals();
+}
+
+void QSGCustomParticle::lookThroughShaderCode(const QByteArray &code)
+{
+ // Regexp for matching attributes and uniforms.
+ // In human readable form: attribute|uniform [lowp|mediump|highp] <type> <name>
+ static QRegExp re(QLatin1String("\\b(attribute|uniform)\\b\\s*\\b(?:lowp|mediump|highp)?\\b\\s*\\b(\\w+)\\b\\s*\\b(\\w+)"));
+ Q_ASSERT(re.isValid());
+
+ int pos = -1;
+
+ QString wideCode = QString::fromLatin1(code.constData(), code.size());
+
+ while ((pos = re.indexIn(wideCode, pos + 1)) != -1) {
+ QByteArray decl = re.cap(1).toLatin1(); // uniform or attribute
+ QByteArray type = re.cap(2).toLatin1(); // type
+ QByteArray name = re.cap(3).toLatin1(); // variable name
+
+ if (decl == "attribute") {
+ if(!m_source.attributeNames.contains(name))//TODO: Can they add custom attributes?
+ qWarning() << "Custom Particle: Unknown attribute " << name;
+ } else {
+ Q_ASSERT(decl == "uniform");//TODO: Shouldn't assert
+
+ if (name == "qt_ModelViewProjectionMatrix") {
+ m_source.respectsMatrix = true;
+ } else if (name == "qt_Opacity") {
+ m_source.respectsOpacity = true;
+ } else if (name == "timestamp") {
+ //TODO: Copy the whole thing just because I have one more uniform?
+ } else {
+ m_source.uniformNames.insert(name);
+ if (type == "sampler2D") {
+ SourceData d;
+ d.mapper = new QSignalMapper;
+ d.name = name;
+ d.item = 0;
+ m_sources.append(d);
+ }
+ }
+ }
+ }
+}
+
+QSGNode *QSGCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ //delete m_material;//Shader effect item doesn't regen material?
+
+ m_node = 0;
+ m_pleaseReset = false;
+ m_dirtyData = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ if(oldNode)
+ Q_ASSERT(oldNode == m_node);
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial); //done in buildData?
+ }
+
+ return m_node;
+}
+
+void QSGCustomParticle::prepareNextFrame(){
+ if(!m_node)
+ m_node = buildCustomNode();
+ if(!m_node)
+ return;
+
+ m_lastTime = m_system->systemSync(this) / 1000.;
+ if(m_dirtyData || true)//Currently this is how we update timestamp... potentially over expensive.
+ buildData();
+}
+
+QSGShaderEffectNode* QSGCustomParticle::buildCustomNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("CustomParticle: Too many particles... \n");//####Why is this here?
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("CustomParticle: Too few particles... \n");
+ return 0;
+ }
+
+ //Create Particle Geometry
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+ QSGGeometry *g = new QSGGeometry(PlainParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+ PlainVertex *vertices = (PlainVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+ reload(p);
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+ vertices += 4;
+ }
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ updateProperties();
+ QSGShaderEffectNode* node = new QSGShaderEffectNode();
+
+
+ node->setGeometry(g);
+ node->setMaterial(&m_material);
+
+ QSGShaderEffectProgram s = m_source;
+ if (s.fragmentCode.isEmpty())
+ s.fragmentCode = qt_particles_default_fragment_code;
+ if (s.vertexCode.isEmpty())
+ s.vertexCode = qt_particles_default_vertex_code;
+ m_material.setProgramSource(s);
+ return node;
+}
+
+static const QByteArray timestampName("timestamp");
+
+void QSGCustomParticle::buildData()
+{
+ if(!m_node)//Operates on m_node
+ return;
+ QVector<QPair<QByteArray, QVariant> > values;
+ QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
+ const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = m_material.textureProviders();
+
+ for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
+ it != m_source.uniformNames.end(); ++it) {
+ values.append(qMakePair(*it, property(*it)));
+ }
+ for (int i = 0; i < oldTextures.size(); ++i) {
+ QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
+ if (oldSource && oldSource->textureChangedSignal())
+ disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), m_node, SLOT(markDirtyTexture()));
+ }
+ for (int i = 0; i < m_sources.size(); ++i) {
+ const SourceData &source = m_sources.at(i);
+ textures.append(qMakePair(source.name, source.item));
+ QSGTextureProvider *t = QSGTextureProvider::from(source.item);
+ if (t && t->textureChangedSignal())
+ connect(source.item, t->textureChangedSignal(), m_node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+ }
+ values.append(qMakePair(timestampName, QVariant(m_lastTime)));
+ m_material.setUniforms(values);
+ m_material.setTextureProviders(textures);
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyData = false;
+}
+
+void QSGCustomParticle::initialize(int idx)
+{
+ m_data[idx]->r = rand()/(qreal)RAND_MAX;
+}
+
+void QSGCustomParticle::reload(int idx)
+{
+ if (m_node == 0)
+ return;
+
+ PlainVertices *particles = (PlainVertices *) m_node->geometry()->vertexData();
+ PlainVertex *vertices = (PlainVertex *)&particles[idx];
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = m_data[idx]->x - m_systemOffset.x();
+ vertices[i].y = m_data[idx]->y - m_systemOffset.y();
+ vertices[i].t = m_data[idx]->t;
+ vertices[i].lifeSpan = m_data[idx]->lifeSpan;
+ vertices[i].size = m_data[idx]->size;
+ vertices[i].endSize = m_data[idx]->endSize;
+ vertices[i].sx = m_data[idx]->sx;
+ vertices[i].sy = m_data[idx]->sy;
+ vertices[i].ax = m_data[idx]->ax;
+ vertices[i].ay = m_data[idx]->ay;
+ vertices[i].r = m_data[idx]->r;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgcustomparticle_p.h b/src/declarative/particles/qsgcustomparticle_p.h
new file mode 100644
index 0000000000..50ff37a2a0
--- /dev/null
+++ b/src/declarative/particles/qsgcustomparticle_p.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CUSTOM_PARTICLE_H
+#define CUSTOM_PARTICLE_H
+#include "qsgparticlepainter_p.h"
+#include <QtDeclarative/private/qsgshadereffectnode_p.h>
+#include <QSignalMapper>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGNode;
+struct PlainVertices;
+//Genealogy: Hybrid of UltraParticle and ShaderEffectItem
+class QSGCustomParticle : public QSGParticlePainter
+{
+ Q_OBJECT
+ Q_PROPERTY(QByteArray fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged)
+ Q_PROPERTY(QByteArray vertexShader READ vertexShader WRITE setVertexShader NOTIFY vertexShaderChanged)
+
+public:
+ explicit QSGCustomParticle(QSGItem* parent=0);
+
+ QByteArray fragmentShader() const { return m_source.fragmentCode; }
+ void setFragmentShader(const QByteArray &code);
+
+ QByteArray vertexShader() const { return m_source.vertexCode; }
+ void setVertexShader(const QByteArray &code);
+public Q_SLOTS:
+ void updateData();
+ void changeSource(int);
+Q_SIGNALS:
+ void fragmentShaderChanged();
+ void vertexShaderChanged();
+protected:
+ virtual void initialize(int idx);
+ virtual void reload(int idx);
+
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void prepareNextFrame();
+ void setSource(const QVariant &var, int index);
+ void disconnectPropertySignals();
+ void connectPropertySignals();
+ void reset();
+ void resize(int oldCount, int newCount);
+ void updateProperties();
+ void lookThroughShaderCode(const QByteArray &code);
+ virtual void componentComplete();
+ QSGShaderEffectNode *buildCustomNode();
+ void performPendingResize();
+
+private:
+ void buildData();
+
+
+ bool m_pleaseReset;
+ bool m_dirtyData;
+ QSGShaderEffectProgram m_source;
+ struct SourceData
+ {
+ QSignalMapper *mapper;
+ QPointer<QSGItem> item;
+ QByteArray name;
+ };
+ QVector<SourceData> m_sources;
+ QSGShaderEffectMaterial m_material;
+ QSGShaderEffectNode* m_node;
+ qreal m_lastTime;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //HEADER_GUARD
diff --git a/src/declarative/particles/qsgellipseextruder.cpp b/src/declarative/particles/qsgellipseextruder.cpp
new file mode 100644
index 0000000000..76925895b9
--- /dev/null
+++ b/src/declarative/particles/qsgellipseextruder.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgellipseextruder_p.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+QSGEllipseExtruder::QSGEllipseExtruder(QObject *parent) :
+ QSGParticleExtruder(parent)
+ , m_fill(true)
+{
+}
+
+QPointF QSGEllipseExtruder::extrude(const QRectF & r)
+{
+ qreal theta = ((qreal)rand()/RAND_MAX) * 6.2831853071795862;
+ qreal mag = m_fill ? ((qreal)rand()/RAND_MAX) : 1;
+ return QPointF(r.x() + r.width()/2 + mag * (r.width()/2) * cos(theta),
+ r.y() + r.height()/2 + mag * (r.height()/2) * sin(theta));
+}
+
+bool QSGEllipseExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ return bounds.contains(point);//TODO: Ellipse
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgellipseextruder_p.h b/src/declarative/particles/qsgellipseextruder_p.h
new file mode 100644
index 0000000000..9f770a7ee6
--- /dev/null
+++ b/src/declarative/particles/qsgellipseextruder_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ELLIPSEEXTRUDER_H
+#define ELLIPSEEXTRUDER_H
+#include "qsgparticleextruder_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGEllipseExtruder : public QSGParticleExtruder
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Use base class? If it's still box
+public:
+ explicit QSGEllipseExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);
+
+ bool fill() const
+ {
+ return m_fill;
+ }
+
+signals:
+
+ void fillChanged(bool arg);
+
+public slots:
+
+ void setFill(bool arg)
+ {
+ if (m_fill != arg) {
+ m_fill = arg;
+ emit fillChanged(arg);
+ }
+ }
+private:
+ bool m_fill;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ELLIPSEEXTRUDER_H
diff --git a/src/declarative/particles/qsgemitter.cpp b/src/declarative/particles/qsgemitter.cpp
new file mode 100644
index 0000000000..c3ec3ffc9e
--- /dev/null
+++ b/src/declarative/particles/qsgemitter.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgemitter_p.h"
+#include "qsgparticlesystem_p.h"
+#include "qsgparticlepainter_p.h"//TODO: What was this for again?
+QT_BEGIN_NAMESPACE
+
+QSGBasicEmitter::QSGBasicEmitter(QSGItem* parent)
+ : QSGParticleEmitter(parent)
+ , m_speed_from_movement(0)
+ , m_particle_count(0)
+ , m_reset_last(true)
+ , m_last_timestamp(0)
+ , m_last_emission(0)
+{
+// setFlag(ItemHasContents);
+}
+
+void QSGBasicEmitter::setSpeedFromMovement(qreal t)
+{
+ if (t == m_speed_from_movement)
+ return;
+ m_speed_from_movement = t;
+ emit speedFromMovementChanged();
+}
+
+void QSGBasicEmitter::reset()
+{
+ m_reset_last = true;
+}
+
+void QSGBasicEmitter::emitWindow(int timeStamp)
+{
+ if (m_system == 0)
+ return;
+ if((!m_emitting || !m_particlesPerSecond)&& !m_burstLeft && m_burstQueue.isEmpty()){
+ m_reset_last = true;
+ return;
+ }
+
+ if (m_reset_last) {
+ m_last_emitter = m_last_last_emitter = QPointF(x(), y());
+ m_last_timestamp = timeStamp/1000.;
+ m_last_emission = m_last_timestamp;
+ m_reset_last = false;
+ }
+
+ if(m_burstLeft){
+ m_burstLeft -= timeStamp - m_last_timestamp * 1000.;
+ if(m_burstLeft < 0){
+ if(!m_emitting)
+ timeStamp += m_burstLeft;
+ m_burstLeft = 0;
+ }
+ }
+
+ qreal time = timeStamp / 1000.;
+
+ qreal particleRatio = 1. / m_particlesPerSecond;
+ qreal pt = m_last_emission;
+
+ qreal opt = pt; // original particle time
+ qreal dt = time - m_last_timestamp; // timestamp delta...
+ if(!dt)
+ dt = 0.000001;
+
+ // emitter difference since last...
+ qreal dex = (x() - m_last_emitter.x());
+ qreal dey = (y() - m_last_emitter.y());
+
+ qreal ax = (m_last_last_emitter.x() + m_last_emitter.x()) / 2;
+ qreal bx = m_last_emitter.x();
+ qreal cx = (x() + m_last_emitter.x()) / 2;
+ qreal ay = (m_last_last_emitter.y() + m_last_emitter.y()) / 2;
+ qreal by = m_last_emitter.y();
+ qreal cy = (y() + m_last_emitter.y()) / 2;
+
+ qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize;
+ qreal emitter_x_offset = m_last_emitter.x() - x();
+ qreal emitter_y_offset = m_last_emitter.y() - y();
+ if(!m_burstQueue.isEmpty() && !m_burstLeft && !m_emitting)//'outside time' emissions only
+ pt = time;
+ while (pt < time || !m_burstQueue.isEmpty()) {
+ //int pos = m_last_particle % m_particle_count;
+ QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle]);
+ if(datum){//actually emit(otherwise we've been asked to skip this one)
+ datum->e = this;//###useful?
+ qreal t = 1 - (pt - opt) / dt;
+ qreal vx =
+ - 2 * ax * (1 - t)
+ + 2 * bx * (1 - 2 * t)
+ + 2 * cx * t;
+ qreal vy =
+ - 2 * ay * (1 - t)
+ + 2 * by * (1 - 2 * t)
+ + 2 * cy * t;
+
+
+ // Particle timestamp
+ datum->t = pt;
+ datum->lifeSpan = //TODO:Promote to base class?
+ (m_particleDuration
+ + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation))
+ / 1000.0;
+
+ // Particle position
+ QRectF boundsRect;
+ if(!m_burstQueue.isEmpty()){
+ boundsRect = QRectF(m_burstQueue.first().second.x() - x(), m_burstQueue.first().second.y() - y(),
+ width(), height());
+ } else {
+ boundsRect = QRectF(emitter_x_offset + dex * (pt - opt) / dt, emitter_y_offset + dey * (pt - opt) / dt
+ , width(), height());
+ }
+ QPointF newPos = effectiveExtruder()->extrude(boundsRect);
+ datum->x = newPos.x();
+ datum->y = newPos.y();
+
+ // Particle speed
+ const QPointF &speed = m_speed->sample(newPos);
+ datum->sx = speed.x()
+ + m_speed_from_movement * vx;
+ datum->sy = speed.y()
+ + m_speed_from_movement * vy;
+
+ // Particle acceleration
+ const QPointF &accel = m_acceleration->sample(newPos);
+ datum->ax = accel.x();
+ datum->ay = accel.y();
+
+ // Particle size
+ float sizeVariation = -m_particleSizeVariation
+ + rand() / float(RAND_MAX) * m_particleSizeVariation * 2;
+
+ float size = qMax((qreal)0.0 , m_particleSize + sizeVariation);
+ float endSize = qMax((qreal)0.0 , sizeAtEnd + sizeVariation);
+
+ datum->size = size;// * float(m_emitting);
+ datum->endSize = endSize;// * float(m_emitting);
+
+ m_system->emitParticle(datum);
+ }
+ if(m_burstQueue.isEmpty()){
+ pt += particleRatio;
+ }else{
+ m_burstQueue.first().first--;
+ if(m_burstQueue.first().first <= 0)
+ m_burstQueue.pop_front();
+ }
+ }
+ m_last_emission = pt;
+
+ m_last_last_last_emitter = m_last_last_emitter;
+ m_last_last_emitter = m_last_emitter;
+ m_last_emitter = QPointF(x(), y());
+ m_last_timestamp = time;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgemitter_p.h b/src/declarative/particles/qsgemitter_p.h
new file mode 100644
index 0000000000..3988c71cdf
--- /dev/null
+++ b/src/declarative/particles/qsgemitter_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TRAILSEMITTER_H
+#define TRAILSEMITTER_H
+
+#include <QtCore>
+#include <QtGui>
+
+#include "qsgparticleemitter_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGGeometryNode;
+
+class QSGBasicEmitter : public QSGParticleEmitter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal speedFromMovement READ speedFromMovement WRITE setSpeedFromMovement NOTIFY speedFromMovementChanged)
+
+public:
+ explicit QSGBasicEmitter(QSGItem* parent=0);
+ virtual ~QSGBasicEmitter(){}
+ virtual void emitWindow(int timeStamp);
+
+
+ qreal speedFromMovement() const { return m_speed_from_movement; }
+ void setSpeedFromMovement(qreal s);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+signals:
+
+ void speedFromMovementChanged();
+
+public slots:
+public:
+ virtual void reset();
+protected:
+
+private:
+
+ qreal m_speed_from_movement;
+
+ // derived values...
+ int m_particle_count;
+ bool m_reset_last;
+ qreal m_last_timestamp;
+ qreal m_last_emission;
+
+ QPointF m_last_emitter;
+ QPointF m_last_last_emitter;
+ QPointF m_last_last_last_emitter;
+
+ qreal m_render_opacity;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TRAILSEMITTER_H
diff --git a/src/declarative/particles/qsgfollowemitter.cpp b/src/declarative/particles/qsgfollowemitter.cpp
new file mode 100644
index 0000000000..ba31e8f834
--- /dev/null
+++ b/src/declarative/particles/qsgfollowemitter.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgfollowemitter_p.h"
+#include "qsgparticlepainter_p.h"//TODO: What was this for again?
+#include <cmath>
+QT_BEGIN_NAMESPACE
+
+QSGFollowEmitter::QSGFollowEmitter(QSGItem *parent) :
+ QSGParticleEmitter(parent)
+ , m_particlesPerParticlePerSecond(0)
+ , m_lastTimeStamp(0)
+ , m_emitterXVariation(0)
+ , m_emitterYVariation(0)
+ , m_followCount(0)
+ , m_emissionExtruder(0)
+ , m_defaultEmissionExtruder(new QSGParticleExtruder(this))
+{
+ //TODO: If followed increased their size
+ connect(this, SIGNAL(followChanged(QString)),
+ this, SLOT(recalcParticlesPerSecond()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SLOT(recalcParticlesPerSecond()));
+ connect(this, SIGNAL(particlesPerParticlePerSecondChanged(int)),
+ this, SLOT(recalcParticlesPerSecond()));
+}
+
+void QSGFollowEmitter::recalcParticlesPerSecond(){
+ if(!m_system)
+ return;
+ m_followCount = m_system->m_groupData[m_system->m_groupIds[m_follow]]->size;
+ if(!m_followCount){
+ setParticlesPerSecond(1);//XXX: Fix this horrendous hack, needed so they aren't turned off from start (causes crashes - test that when gone you don't crash with 0 PPPS)
+ }else{
+ setParticlesPerSecond(m_particlesPerParticlePerSecond * m_followCount);
+ m_lastEmission.resize(m_followCount);
+ m_lastEmission.fill(0);
+ }
+}
+
+void QSGFollowEmitter::reset()
+{
+ m_followCount = 0;
+}
+
+void QSGFollowEmitter::emitWindow(int timeStamp)
+{
+ if (m_system == 0)
+ return;
+ if(!m_emitting && !m_burstLeft && m_burstQueue.isEmpty())
+ return;
+ if(m_followCount != m_system->m_groupData[m_system->m_groupIds[m_follow]]->size){
+ qreal oldPPS = m_particlesPerSecond;
+ recalcParticlesPerSecond();
+ if(m_particlesPerSecond != oldPPS)
+ return;//system may need to update
+ }
+
+ if(m_burstLeft){
+ m_burstLeft -= timeStamp - m_lastTimeStamp * 1000.;
+ if(m_burstLeft < 0){
+ timeStamp += m_burstLeft;
+ m_burstLeft = 0;
+ }
+ }
+
+ qreal time = timeStamp / 1000.;
+ qreal particleRatio = 1. / m_particlesPerParticlePerSecond;
+ qreal pt;
+
+ //Have to map it into this system, because particlesystem automaps it back
+ QPointF offset = m_system->mapFromItem(this, QPointF(0, 0));
+ qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize;
+
+ int gId = m_system->m_groupIds[m_follow];
+ int gId2 = m_system->m_groupIds[m_particle];
+ foreach(QSGParticleData *d, m_system->m_groupData[gId]->data){
+ if(!d || !d->stillAlive())
+ continue;
+ pt = m_lastEmission[d->index];
+ if(pt < d->t)
+ pt = d->t;
+
+ if(!effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){
+ m_lastEmission[d->index] = time;//jump over this time period without emitting, because it's outside
+ continue;
+ }
+ while(pt < time || !m_burstQueue.isEmpty()){
+ QSGParticleData* datum = m_system->newDatum(gId2);
+ if(datum){//else, skip this emission
+ datum->e = this;//###useful?
+
+ // Particle timestamp
+ datum->t = pt;
+ datum->lifeSpan =
+ (m_particleDuration
+ + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation))
+ / 1000.0;
+
+ // Particle position
+ // Note that burst location doesn't get used for follow emitter
+ qreal followT = pt - d->t;
+ qreal followT2 = followT * followT * 0.5;
+ qreal sizeOffset = d->size/2;//TODO: Current size? As an option
+ //TODO: Set variations
+ //Subtract offset, because PS expects this in emitter coordinates
+ QRectF boundsRect(d->x - offset.x() + d->sx * followT + d->ax * followT2 - m_emitterXVariation/2,
+ d->y - offset.y() + d->sy * followT + d->ay * followT2 - m_emitterYVariation/2,
+ m_emitterXVariation,
+ m_emitterYVariation);
+ // QRectF boundsRect(d->x + d->sx * followT + d->ax * followT2 + offset.x() - sizeOffset,
+ // d->y + d->sy * followT + d->ay * followT2 + offset.y() - sizeOffset,
+ // sizeOffset*2,
+ // sizeOffset*2);
+
+ QSGParticleExtruder* effectiveEmissionExtruder = m_emissionExtruder ? m_emissionExtruder : m_defaultEmissionExtruder;
+ const QPointF &newPos = effectiveEmissionExtruder->extrude(boundsRect);
+ datum->x = newPos.x();
+ datum->y = newPos.y();
+
+ // Particle speed
+ const QPointF &speed = m_speed->sample(newPos);
+ datum->sx = speed.x();
+ datum->sy = speed.y();
+
+ // Particle acceleration
+ const QPointF &accel = m_acceleration->sample(newPos);
+ datum->ax = accel.x();
+ datum->ay = accel.y();
+
+ // Particle size
+ float sizeVariation = -m_particleSizeVariation
+ + rand() / float(RAND_MAX) * m_particleSizeVariation * 2;
+
+ float size = qMax((qreal)0.0, m_particleSize + sizeVariation);
+ float endSize = qMax((qreal)0.0, sizeAtEnd + sizeVariation);
+
+ datum->size = size * float(m_emitting);
+ datum->endSize = endSize * float(m_emitting);
+
+ m_system->emitParticle(datum);
+ }
+ if(!m_burstQueue.isEmpty()){
+ m_burstQueue.first().first--;
+ if(m_burstQueue.first().first <= 0)
+ m_burstQueue.pop_front();
+ }else{
+ pt += particleRatio;
+ }
+ }
+ m_lastEmission[d->index] = pt;
+ }
+
+ m_lastTimeStamp = time;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgfollowemitter_p.h b/src/declarative/particles/qsgfollowemitter_p.h
new file mode 100644
index 0000000000..bf5d2fe8ef
--- /dev/null
+++ b/src/declarative/particles/qsgfollowemitter_p.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FOLLOWEMITTER_H
+#define FOLLOWEMITTER_H
+#include "qsgparticleemitter_p.h"
+#include "qsgparticleaffector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGFollowEmitter : public QSGParticleEmitter
+{
+ Q_OBJECT
+ Q_PROPERTY(QString follow READ follow WRITE setFollow NOTIFY followChanged)
+ //### Remove, and just document that particles per second is per particle? But has count issues
+ Q_PROPERTY(int emitRatePerParticle READ particlesPerParticlePerSecond WRITE setParticlesPerParticlePerSecond NOTIFY particlesPerParticlePerSecondChanged)
+
+ //TODO: Document that FollowEmitter's box is where it follows. It emits in a rect centered on the followed particle
+ //TODO: A set of properties that can involve the particle size of the followed
+ Q_PROPERTY(QSGParticleExtruder* emitShape READ emissonShape WRITE setEmissionShape NOTIFY emissionShapeChanged)
+ Q_PROPERTY(qreal emitHeight READ emitterYVariation WRITE setEmitterYVariation NOTIFY emitterYVariationChanged)
+ Q_PROPERTY(qreal emitWidth READ emitterXVariation WRITE setEmitterXVariation NOTIFY emitterXVariationChanged)
+
+public:
+ explicit QSGFollowEmitter(QSGItem *parent = 0);
+ virtual void emitWindow(int timeStamp);
+ virtual void reset();
+
+ int particlesPerParticlePerSecond() const
+ {
+ return m_particlesPerParticlePerSecond;
+ }
+
+ qreal emitterXVariation() const
+ {
+ return m_emitterXVariation;
+ }
+
+ qreal emitterYVariation() const
+ {
+ return m_emitterYVariation;
+ }
+
+ QString follow() const
+ {
+ return m_follow;
+ }
+
+ QSGParticleExtruder* emissonShape() const
+ {
+ return m_emissionExtruder;
+ }
+
+signals:
+
+ void particlesPerParticlePerSecondChanged(int arg);
+
+ void emitterXVariationChanged(qreal arg);
+
+ void emitterYVariationChanged(qreal arg);
+
+ void followChanged(QString arg);
+
+ void emissionShapeChanged(QSGParticleExtruder* arg);
+
+public slots:
+
+ void setParticlesPerParticlePerSecond(int arg)
+ {
+ if (m_particlesPerParticlePerSecond != arg) {
+ m_particlesPerParticlePerSecond = arg;
+ emit particlesPerParticlePerSecondChanged(arg);
+ }
+ }
+ void setEmitterXVariation(qreal arg)
+ {
+ if (m_emitterXVariation != arg) {
+ m_emitterXVariation = arg;
+ emit emitterXVariationChanged(arg);
+ }
+ }
+
+ void setEmitterYVariation(qreal arg)
+ {
+ if (m_emitterYVariation != arg) {
+ m_emitterYVariation = arg;
+ emit emitterYVariationChanged(arg);
+ }
+ }
+
+ void setFollow(QString arg)
+ {
+ if (m_follow != arg) {
+ m_follow = arg;
+ emit followChanged(arg);
+ }
+ }
+
+ void setEmissionShape(QSGParticleExtruder* arg)
+ {
+ if (m_emissionExtruder != arg) {
+ m_emissionExtruder = arg;
+ emit emissionShapeChanged(arg);
+ }
+ }
+
+private slots:
+ void recalcParticlesPerSecond();
+
+private:
+ QSet<QSGParticleData*> m_pending;
+ QVector<qreal> m_lastEmission;
+ int m_particlesPerParticlePerSecond;
+ qreal m_lastTimeStamp;
+ qreal m_emitterXVariation;
+ qreal m_emitterYVariation;
+ QString m_follow;
+ int m_followCount;
+ QSGParticleExtruder* m_emissionExtruder;
+ QSGParticleExtruder* m_defaultEmissionExtruder;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // FOLLOWEMITTER_H
diff --git a/src/declarative/particles/qsgfriction.cpp b/src/declarative/particles/qsgfriction.cpp
new file mode 100644
index 0000000000..828d20556d
--- /dev/null
+++ b/src/declarative/particles/qsgfriction.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgfriction_p.h"
+QT_BEGIN_NAMESPACE
+QSGFrictionAffector::QSGFrictionAffector(QSGItem *parent) :
+ QSGParticleAffector(parent), m_factor(0.0)
+{
+}
+
+bool QSGFrictionAffector::affectParticle(QSGParticleData *d, qreal dt)
+{
+ if(!m_factor)
+ return false;
+ qreal curSX = d->curSX();
+ qreal curSY = d->curSY();
+ d->setInstantaneousSX(curSX + (curSX * m_factor * -1 * dt));
+ d->setInstantaneousSY(curSY + (curSY * m_factor * -1 * dt));
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgfriction_p.h b/src/declarative/particles/qsgfriction_p.h
new file mode 100644
index 0000000000..6b5a86f3f2
--- /dev/null
+++ b/src/declarative/particles/qsgfriction_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FRICTIONAFFECTOR_H
+#define FRICTIONAFFECTOR_H
+#include "qsgparticleaffector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGFrictionAffector : public QSGParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal factor READ factor WRITE setFactor NOTIFY factorChanged)
+public:
+ explicit QSGFrictionAffector(QSGItem *parent = 0);
+
+ qreal factor() const
+ {
+ return m_factor;
+ }
+protected:
+ virtual bool affectParticle(QSGParticleData *d, qreal dt);
+signals:
+
+ void factorChanged(qreal arg);
+
+public slots:
+
+void setFactor(qreal arg)
+{
+ if (m_factor != arg) {
+ m_factor = arg;
+ emit factorChanged(arg);
+ }
+}
+
+private:
+qreal m_factor;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // FRICTIONAFFECTOR_H
diff --git a/src/declarative/particles/qsggravity.cpp b/src/declarative/particles/qsggravity.cpp
new file mode 100644
index 0000000000..b1cf3e9481
--- /dev/null
+++ b/src/declarative/particles/qsggravity.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsggravity_p.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+const qreal CONV = 0.017453292520444443;
+QSGGravityAffector::QSGGravityAffector(QSGItem *parent) :
+ QSGParticleAffector(parent), m_acceleration(-10), m_angle(90), m_xAcc(0), m_yAcc(0)
+{
+ connect(this, SIGNAL(accelerationChanged(qreal)),
+ this, SLOT(recalc()));
+ connect(this, SIGNAL(angleChanged(qreal)),
+ this, SLOT(recalc()));
+ recalc();
+}
+
+void QSGGravityAffector::recalc()
+{
+ qreal theta = m_angle * CONV;
+ m_xAcc = m_acceleration * cos(theta);
+ m_yAcc = m_acceleration * sin(theta);
+}
+
+bool QSGGravityAffector::affectParticle(QSGParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ bool changed = false;
+ if(d->ax != m_xAcc){
+ d->setInstantaneousAX(m_xAcc);
+ changed = true;
+ }
+ if(d->ay != m_yAcc){
+ d->setInstantaneousAY(m_yAcc);
+ changed = true;
+ }
+ return changed;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsggravity_p.h b/src/declarative/particles/qsggravity_p.h
new file mode 100644
index 0000000000..57b2511911
--- /dev/null
+++ b/src/declarative/particles/qsggravity_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GRAVITYAFFECTOR_H
+#define GRAVITYAFFECTOR_H
+#include "qsgparticleaffector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGGravityAffector : public QSGParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+public:
+ explicit QSGGravityAffector(QSGItem *parent = 0);
+ qreal acceleration() const
+ {
+ return m_acceleration;
+ }
+
+ qreal angle() const
+ {
+ return m_angle;
+ }
+protected:
+ virtual bool affectParticle(QSGParticleData *d, qreal dt);
+signals:
+
+ void accelerationChanged(qreal arg);
+
+ void angleChanged(qreal arg);
+
+public slots:
+void setAcceleration(qreal arg)
+{
+ if (m_acceleration != arg) {
+ m_acceleration = arg;
+ emit accelerationChanged(arg);
+ }
+}
+
+void setAngle(qreal arg)
+{
+ if (m_angle != arg) {
+ m_angle = arg;
+ emit angleChanged(arg);
+ }
+}
+
+private slots:
+ void recalc();
+private:
+ qreal m_acceleration;
+ qreal m_angle;
+
+ qreal m_xAcc;
+ qreal m_yAcc;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // GRAVITYAFFECTOR_H
diff --git a/src/declarative/particles/qsgimageparticle.cpp b/src/declarative/particles/qsgimageparticle.cpp
new file mode 100644
index 0000000000..836236c13e
--- /dev/null
+++ b/src/declarative/particles/qsgimageparticle.cpp
@@ -0,0 +1,934 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "qsgimageparticle_p.h"
+#include "qsgparticleemitter_p.h"
+#include "qsgsprite_p.h"
+#include "qsgspriteengine_p.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+const float CONV = 0.017453292519943295;
+class UltraMaterial : public QSGMaterial
+{
+public:
+ UltraMaterial(bool withSprites=false)
+ : timestamp(0)
+ , framecount(1)
+ , animcount(1)
+ , usesSprites(withSprites)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~UltraMaterial()
+ {
+ delete texture;
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const UltraMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+
+ qreal timestamp;
+ int framecount;
+ int animcount;
+ bool usesSprites;
+};
+class UltraMaterialData : public QSGMaterialShader
+{
+public:
+ UltraMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":defaultshaders/ultravertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":defaultshaders/ultrafragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE1);
+ m->colortable->bind();
+ program()->setUniformValue(m_colortable_id, 1);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE2);
+ m->sizetable->bind();
+ program()->setUniformValue(m_sizetable_id, 2);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE3);
+ m->opacitytable->bind();
+ program()->setUniformValue(m_opacitytable_id, 3);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);//Investigate why this screws up Text{} if placed before 1
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+ program()->setUniformValue(m_framecount_id, (float) m->framecount);
+ program()->setUniformValue(m_animcount_id, (float) m->animcount);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_colortable_id = program()->uniformLocation("colortable");
+ m_sizetable_id = program()->uniformLocation("sizetable");
+ m_opacitytable_id = program()->uniformLocation("opacitytable");
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ m_framecount_id = program()->uniformLocation("framecount");
+ m_animcount_id = program()->uniformLocation("animcount");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vColor",
+ "vDeformVec",
+ "vRotation",
+ "vAnimData",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_colortable_id;
+ int m_sizetable_id;
+ int m_opacitytable_id;
+ int m_framecount_id;
+ int m_animcount_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float UltraMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *UltraMaterial::createShader() const
+{
+ if(usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
+ return new UltraMaterialData;
+ else
+ return new UltraMaterialData;
+}
+
+
+class SimpleMaterial : public UltraMaterial
+{
+ virtual QSGMaterialShader *createShader() const;
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+};
+
+class SimpleMaterialData : public QSGMaterialShader
+{
+public:
+ SimpleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":defaultshaders/simplevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":defaultshaders/simplefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SimpleMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SimpleMaterial::createShader() const {
+ return new SimpleMaterialData;
+}
+
+QSGImageParticle::QSGImageParticle(QSGItem* parent)
+ : QSGParticlePainter(parent)
+ , m_do_reset(false)
+ , m_color_variation(0.0)
+ , m_node(0)
+ , m_material(0)
+ , m_alphaVariation(0.0)
+ , m_alpha(1.0)
+ , m_redVariation(0.0)
+ , m_greenVariation(0.0)
+ , m_blueVariation(0.0)
+ , m_rotation(0)
+ , m_autoRotation(false)
+ , m_xVector(0)
+ , m_yVector(0)
+ , m_rotationVariation(0)
+ , m_rotationSpeed(0)
+ , m_rotationSpeedVariation(0)
+ , m_spriteEngine(0)
+ , m_bloat(false)
+ , perfLevel(Unknown)
+ , m_lastLevel(Unknown)
+{
+ setFlag(ItemHasContents);
+}
+
+QDeclarativeListProperty<QSGSprite> QSGImageParticle::sprites()
+{
+ return QDeclarativeListProperty<QSGSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
+
+void QSGImageParticle::setImage(const QUrl &image)
+{
+ if (image == m_image_name)
+ return;
+ m_image_name = image;
+ emit imageChanged();
+ reset();
+}
+
+
+void QSGImageParticle::setColortable(const QUrl &table)
+{
+ if (table == m_colortable_name)
+ return;
+ m_colortable_name = table;
+ emit colortableChanged();
+ reset();
+}
+
+void QSGImageParticle::setSizetable(const QUrl &table)
+{
+ if (table == m_sizetable_name)
+ return;
+ m_sizetable_name = table;
+ emit sizetableChanged();
+ reset();
+}
+
+void QSGImageParticle::setOpacitytable(const QUrl &table)
+{
+ if (table == m_opacitytable_name)
+ return;
+ m_opacitytable_name = table;
+ emit opacitytableChanged();
+ reset();
+}
+
+void QSGImageParticle::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ emit colorChanged();
+ if(perfLevel < Colored)
+ reset();
+}
+
+void QSGImageParticle::setColorVariation(qreal var)
+{
+ if (var == m_color_variation)
+ return;
+ m_color_variation = var;
+ emit colorVariationChanged();
+ if(perfLevel < Colored)
+ reset();
+}
+
+void QSGImageParticle::setAlphaVariation(qreal arg)
+{
+ if (m_alphaVariation != arg) {
+ m_alphaVariation = arg;
+ emit alphaVariationChanged(arg);
+ }
+ if(perfLevel < Colored)
+ reset();
+}
+
+void QSGImageParticle::setAlpha(qreal arg)
+{
+ if (m_alpha != arg) {
+ m_alpha = arg;
+ emit alphaChanged(arg);
+ }
+ if(perfLevel < Colored)
+ reset();
+}
+
+void QSGImageParticle::setRedVariation(qreal arg)
+{
+ if (m_redVariation != arg) {
+ m_redVariation = arg;
+ emit redVariationChanged(arg);
+ }
+ if(perfLevel < Colored)
+ reset();
+}
+
+void QSGImageParticle::setGreenVariation(qreal arg)
+{
+ if (m_greenVariation != arg) {
+ m_greenVariation = arg;
+ emit greenVariationChanged(arg);
+ }
+ if(perfLevel < Colored)
+ reset();
+}
+
+void QSGImageParticle::setBlueVariation(qreal arg)
+{
+ if (m_blueVariation != arg) {
+ m_blueVariation = arg;
+ emit blueVariationChanged(arg);
+ }
+ if(perfLevel < Colored)
+ reset();
+}
+
+void QSGImageParticle::setRotation(qreal arg)
+{
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void QSGImageParticle::setRotationVariation(qreal arg)
+{
+ if (m_rotationVariation != arg) {
+ m_rotationVariation = arg;
+ emit rotationVariationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void QSGImageParticle::setRotationSpeed(qreal arg)
+{
+ if (m_rotationSpeed != arg) {
+ m_rotationSpeed = arg;
+ emit rotationSpeedChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void QSGImageParticle::setRotationSpeedVariation(qreal arg)
+{
+ if (m_rotationSpeedVariation != arg) {
+ m_rotationSpeedVariation = arg;
+ emit rotationSpeedVariationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void QSGImageParticle::setAutoRotation(bool arg)
+{
+ if (m_autoRotation != arg) {
+ m_autoRotation = arg;
+ emit autoRotationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void QSGImageParticle::setXVector(QSGStochasticDirection* arg)
+{
+ if (m_xVector != arg) {
+ m_xVector = arg;
+ emit xVectorChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void QSGImageParticle::setYVector(QSGStochasticDirection* arg)
+{
+ if (m_yVector != arg) {
+ m_yVector = arg;
+ emit yVectorChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void QSGImageParticle::setBloat(bool arg)
+{
+ if (m_bloat != arg) {
+ m_bloat = arg;
+ emit bloatChanged(arg);
+ }
+ if(perfLevel < 9999)
+ reset();
+}
+
+void QSGImageParticle::reset()
+{
+ QSGParticlePainter::reset();
+ m_pleaseReset = true;
+}
+
+void QSGImageParticle::createEngine()
+{
+ if(m_spriteEngine)
+ delete m_spriteEngine;
+ if(m_sprites.count())
+ m_spriteEngine = new QSGSpriteEngine(m_sprites, this);
+ else
+ m_spriteEngine = 0;
+ reset();
+}
+
+static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT } // Vectors
+};
+
+static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
+{
+ 4, // Attribute Count
+ (2 + 2 + 4 + 4 ) * sizeof(float),
+ SimpleParticle_Attributes
+};
+
+static QSGGeometry::Attribute UltraParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_UNSIGNED_BYTE }, // Colors
+ { 5, 4, GL_FLOAT }, // DeformationVectors
+ { 6, 3, GL_FLOAT }, // Rotation
+ { 7, 4, GL_FLOAT } // Anim Data
+};
+
+static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
+{
+ 8, // Attribute Count
+ (2 + 2 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
+ UltraParticle_Attributes
+};
+
+QSGGeometryNode* QSGImageParticle::buildSimpleParticleNode()
+{
+ perfLevel = Simple;//TODO: Intermediate levels
+ QImage image = QImage(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+ qDebug() << "Simple Case";
+
+ QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SimpleVertex *vertices = (SimpleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p){
+ for(int i=0; i<4; i++){
+ vertices[i].x = m_data[p]->x;
+ vertices[i].y = m_data[p]->y;
+ vertices[i].t = m_data[p]->t;
+ vertices[i].size = m_data[p]->size;
+ vertices[i].endSize = m_data[p]->endSize;
+ vertices[i].sx = m_data[p]->sx;
+ vertices[i].sy = m_data[p]->sy;
+ vertices[i].ax = m_data[p]->ax;
+ vertices[i].ay = m_data[p]->ay;
+ }
+ //reload(p);
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_material = new SimpleMaterial();
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+ m_material->framecount = 1;
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+ return m_node;
+}
+
+QSGGeometryNode* QSGImageParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("UltraParticle: Too many particles... \n");//### Why is this here?
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ qDebug() << "UltraParticle: Too few particles... \n";//XXX: Is now a vaild intermediate state...
+ return 0;
+ }
+
+ if(!m_sprites.count() && !m_bloat
+ && m_colortable_name.isEmpty()
+ && m_sizetable_name.isEmpty()
+ && m_opacitytable_name.isEmpty()
+ && !m_autoRotation
+ && !m_rotation && !m_rotationVariation
+ && !m_rotationSpeed && !m_rotationSpeedVariation
+ && !m_alphaVariation && m_alpha == 1.0
+ && !m_redVariation && !m_blueVariation && !m_greenVariation
+ && !m_color.isValid()
+ )
+ return buildSimpleParticleNode();
+ perfLevel = Sprites;//TODO: intermediate levels
+ if(!m_color.isValid())//But we're in colored level (or higher)
+ m_color = QColor(Qt::white);
+ qDebug() << "Complex Case";
+
+ QImage image;
+ if(m_sprites.count()){
+ if (!m_spriteEngine) {
+ qWarning() << "UltraParticle: No sprite engine...";
+ return 0;
+ }
+ image = m_spriteEngine->assembledImage();
+ if(image.isNull())//Warning is printed in engine
+ return 0;
+ }else{
+ image = QImage(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+
+ UltraVertex *vertices = (UltraVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+ reload(p);//reload gets geometry from node
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ qFree(m_lastData);
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ m_material = new UltraMaterial();
+ if(colortable.isNull())
+ colortable = QImage(":defaultshaders/identitytable.png");
+ if(sizetable.isNull())
+ sizetable = QImage(":defaultshaders/identitytable.png");
+ if(opacitytable.isNull())
+ opacitytable = QImage(":defaultshaders/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_material->framecount = 1;
+ if(m_spriteEngine){
+ m_material->framecount = m_spriteEngine->maxFrames();
+ m_spriteEngine->setCount(m_count);
+ }
+
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *QSGImageParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node){
+ if(perfLevel == 1){
+ m_lastCount = m_node->geometry()->vertexCount() / 4;
+ m_lastData = qMalloc(m_lastCount*sizeof(SimpleVertices));
+ memcpy(m_lastData, m_node->geometry()->vertexData(), m_lastCount * sizeof(SimpleVertices));//TODO: Multiple levels
+ }
+ m_lastLevel = perfLevel;
+ delete m_node;
+ }
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void QSGImageParticle::prepareNextFrame()
+{
+ if (m_node == 0){//TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ qDebug() << "Feature level: " << perfLevel;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+
+ //Advance State
+ if(m_spriteEngine){//perfLevel == Sprites?
+ m_material->animcount = m_spriteEngine->spriteCount();
+ UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
+ m_spriteEngine->updateSprites(timeStamp);
+ for(int i=0; i<m_count; i++){
+ UltraVertices &p = particles[i];
+ int curIdx = m_spriteEngine->spriteState(i);
+ if(curIdx != p.v1.animIdx){
+ p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
+ p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
+ }
+ }
+ }else{
+ m_material->animcount = 1;
+ }
+}
+
+void QSGImageParticle::reloadColor(const Color4ub &c, QSGParticleData* d)
+{
+ d->color = c;
+ //TODO: get index for reload - or make function take an index
+}
+
+void QSGImageParticle::initialize(int idx)
+{
+ Color4ub color;
+ qreal redVariation = m_color_variation + m_redVariation;
+ qreal greenVariation = m_color_variation + m_greenVariation;
+ qreal blueVariation = m_color_variation + m_blueVariation;
+ switch(perfLevel){//Fall-through is intended on all of them
+ case Sprites:
+ // Initial Sprite State
+ m_data[idx]->animT = m_data[idx]->t;
+ m_data[idx]->animIdx = 0;
+ if(m_spriteEngine){
+ m_spriteEngine->startSprite(idx);
+ m_data[idx]->frameCount = m_spriteEngine->spriteFrames(idx);
+ m_data[idx]->frameDuration = m_spriteEngine->spriteDuration(idx);
+ }else{
+ m_data[idx]->frameCount = 1;
+ m_data[idx]->frameDuration = 9999;
+ }
+ case Tabled:
+ case Deformable:
+ //Initial Rotation
+ if(m_xVector){
+ const QPointF &ret = m_xVector->sample(QPointF(m_data[idx]->x, m_data[idx]->y));
+ m_data[idx]->xx = ret.x();
+ m_data[idx]->xy = ret.y();
+ }
+ if(m_yVector){
+ const QPointF &ret = m_yVector->sample(QPointF(m_data[idx]->x, m_data[idx]->y));
+ m_data[idx]->yx = ret.x();
+ m_data[idx]->yy = ret.y();
+ }
+ m_data[idx]->rotation =
+ (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
+ m_data[idx]->rotationSpeed =
+ (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
+ m_data[idx]->autoRotate = m_autoRotation?1.0:0.0;
+ case Colored:
+ //Color initialization
+ // Particle color
+ color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
+ color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
+ color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
+ color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
+ m_data[idx]->color = color;
+ default:
+ break;
+ }
+}
+
+void QSGImageParticle::reload(int idx)
+{
+ if(!m_node)
+ return;
+
+ m_node->setFlag(QSGNode::OwnsGeometry, false);
+ UltraVertex *ultraVertices = (UltraVertex *) m_node->geometry()->vertexData();
+ SimpleVertex *simpleVertices = (SimpleVertex *) m_node->geometry()->vertexData();
+ switch(perfLevel){
+ case Sprites:
+ ultraVertices += idx*4;
+ for(int i=0; i<4; i++){
+ ultraVertices[i].x = m_data[idx]->x - m_systemOffset.x();
+ ultraVertices[i].y = m_data[idx]->y - m_systemOffset.y();
+ ultraVertices[i].t = m_data[idx]->t;
+ ultraVertices[i].lifeSpan = m_data[idx]->lifeSpan;
+ ultraVertices[i].size = m_data[idx]->size;
+ ultraVertices[i].endSize = m_data[idx]->endSize;
+ ultraVertices[i].sx = m_data[idx]->sx;
+ ultraVertices[i].sy = m_data[idx]->sy;
+ ultraVertices[i].ax = m_data[idx]->ax;
+ ultraVertices[i].ay = m_data[idx]->ay;
+ ultraVertices[i].xx = m_data[idx]->xx;
+ ultraVertices[i].xy = m_data[idx]->xy;
+ ultraVertices[i].yx = m_data[idx]->yx;
+ ultraVertices[i].yy = m_data[idx]->yy;
+ ultraVertices[i].rotation = m_data[idx]->rotation;
+ ultraVertices[i].rotationSpeed = m_data[idx]->rotationSpeed;
+ ultraVertices[i].autoRotate = m_data[idx]->autoRotate;
+ ultraVertices[i].animIdx = m_data[idx]->animIdx;
+ ultraVertices[i].frameDuration = m_data[idx]->frameDuration;
+ ultraVertices[i].frameCount = m_data[idx]->frameCount;
+ ultraVertices[i].animT = m_data[idx]->animT;
+ ultraVertices[i].color.r = m_data[idx]->color.r;
+ ultraVertices[i].color.g = m_data[idx]->color.g;
+ ultraVertices[i].color.b = m_data[idx]->color.b;
+ ultraVertices[i].color.a = m_data[idx]->color.a;
+ }
+ break;
+ case Tabled://TODO: Us
+ case Deformable:
+ case Colored:
+ case Simple:
+ simpleVertices += idx*4;
+ for(int i=0; i<4; i++){
+ simpleVertices[i].x = m_data[idx]->x - m_systemOffset.x();
+ simpleVertices[i].y = m_data[idx]->y - m_systemOffset.y();
+ simpleVertices[i].t = m_data[idx]->t;
+ simpleVertices[i].lifeSpan = m_data[idx]->lifeSpan;
+ simpleVertices[i].size = m_data[idx]->size;
+ simpleVertices[i].endSize = m_data[idx]->endSize;
+ simpleVertices[i].sx = m_data[idx]->sx;
+ simpleVertices[i].sy = m_data[idx]->sy;
+ simpleVertices[i].ax = m_data[idx]->ax;
+ simpleVertices[i].ay = m_data[idx]->ay;
+ }
+ break;
+ default:
+ break;
+ }
+
+ m_node->setFlag(QSGNode::OwnsGeometry, true);
+}
+
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgimageparticle_p.h b/src/declarative/particles/qsgimageparticle_p.h
new file mode 100644
index 0000000000..dc79c5910e
--- /dev/null
+++ b/src/declarative/particles/qsgimageparticle_p.h
@@ -0,0 +1,344 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ULTRAPARTICLE_H
+#define ULTRAPARTICLE_H
+#include "qsgparticlepainter_p.h"
+#include "qsgstochasticdirection_p.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class UltraMaterial;
+class QSGGeometryNode;
+
+class QSGSprite;
+class QSGSpriteEngine;
+
+struct SimpleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+};
+
+struct SimpleVertices {
+ SimpleVertex v1;
+ SimpleVertex v2;
+ SimpleVertex v3;
+ SimpleVertex v4;
+};
+
+struct UltraVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ Color4ub color;
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ float rotation;
+ float rotationSpeed;
+ float autoRotate;//Assume that GPUs prefer floats to bools
+ float animIdx;
+ float frameDuration;
+ float frameCount;
+ float animT;
+};
+
+struct UltraVertices {
+ UltraVertex v1;
+ UltraVertex v2;
+ UltraVertex v3;
+ UltraVertex v4;
+};
+
+struct IntermediateVertices {
+ UltraVertex* v1;
+ UltraVertex* v2;
+ UltraVertex* v3;
+ UltraVertex* v4;
+};
+
+class QSGImageParticle : public QSGParticlePainter
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ image WRITE setImage NOTIFY imageChanged)
+ Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ //###Now just colorize - add a flag for 'solid' color particles(where the img is just a mask?)?
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ //Stacks (added) with individual colorVariations
+ Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
+ Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
+ Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
+ Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
+ //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
+ Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
+ Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
+ //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
+ //to 180 will lead to facing away from the direction of motion
+ Q_PROPERTY(bool autoRotation READ autoRotation WRITE setAutoRotation NOTIFY autoRotationChanged)
+
+ //###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
+ //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
+ Q_PROPERTY(QSGStochasticDirection* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
+ //yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
+ Q_PROPERTY(QSGStochasticDirection* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
+ Q_PROPERTY(QDeclarativeListProperty<QSGSprite> sprites READ sprites)
+ Q_PROPERTY(bool bloat READ bloat WRITE setBloat NOTIFY bloatChanged)//Just a debugging property to bypass optimizations
+public:
+ explicit QSGImageParticle(QSGItem *parent = 0);
+ virtual ~QSGImageParticle(){}
+
+
+ QDeclarativeListProperty<QSGSprite> sprites();
+ QSGSpriteEngine* spriteEngine() {return m_spriteEngine;}
+
+ enum PerformanceLevel{//TODO: Expose?
+ Unknown = 0,
+ Simple,
+ Colored,
+ Deformable,
+ Tabled,
+ Sprites
+ };
+
+ QUrl image() const { return m_image_name; }
+ void setImage(const QUrl &image);
+
+ QUrl colortable() const { return m_colortable_name; }
+ void setColortable(const QUrl &table);
+
+ QUrl sizetable() const { return m_sizetable_name; }
+ void setSizetable (const QUrl &table);
+
+ QUrl opacitytable() const { return m_opacitytable_name; }
+ void setOpacitytable(const QUrl &table);
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+
+ qreal colorVariation() const { return m_color_variation; }
+ void setColorVariation(qreal var);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ qreal alphaVariation() const { return m_alphaVariation; }
+
+ qreal alpha() const { return m_alpha; }
+
+ qreal redVariation() const { return m_redVariation; }
+
+ qreal greenVariation() const { return m_greenVariation; }
+
+ qreal blueVariation() const { return m_blueVariation; }
+
+ qreal rotation() const { return m_rotation; }
+
+ qreal rotationVariation() const { return m_rotationVariation; }
+
+ qreal rotationSpeed() const { return m_rotationSpeed; }
+
+ qreal rotationSpeedVariation() const { return m_rotationSpeedVariation; }
+
+ bool autoRotation() const { return m_autoRotation; }
+
+ QSGStochasticDirection* xVector() const { return m_xVector; }
+
+ QSGStochasticDirection* yVector() const { return m_yVector; }
+
+ bool bloat() const { return m_bloat; }
+
+signals:
+
+ void imageChanged();
+ void colortableChanged();
+ void sizetableChanged();
+ void opacitytableChanged();
+
+ void colorChanged();
+ void colorVariationChanged();
+
+ void particleDurationChanged();
+ void alphaVariationChanged(qreal arg);
+
+ void alphaChanged(qreal arg);
+
+ void redVariationChanged(qreal arg);
+
+ void greenVariationChanged(qreal arg);
+
+ void blueVariationChanged(qreal arg);
+
+ void rotationChanged(qreal arg);
+
+ void rotationVariationChanged(qreal arg);
+
+ void rotationSpeedChanged(qreal arg);
+
+ void rotationSpeedVariationChanged(qreal arg);
+
+ void autoRotationChanged(bool arg);
+
+ void xVectorChanged(QSGStochasticDirection* arg);
+
+ void yVectorChanged(QSGStochasticDirection* arg);
+
+ void bloatChanged(bool arg);
+
+public slots:
+ void reloadColor(const Color4ub &c, QSGParticleData* d);
+ void setAlphaVariation(qreal arg);
+
+ void setAlpha(qreal arg);
+
+ void setRedVariation(qreal arg);
+
+ void setGreenVariation(qreal arg);
+
+ void setBlueVariation(qreal arg);
+
+ void setRotation(qreal arg);
+
+ void setRotationVariation(qreal arg);
+
+ void setRotationSpeed(qreal arg);
+
+ void setRotationSpeedVariation(qreal arg);
+
+ void setAutoRotation(bool arg);
+
+ void setXVector(QSGStochasticDirection* arg);
+
+ void setYVector(QSGStochasticDirection* arg);
+
+ void setBloat(bool arg);
+
+protected:
+ void reset();
+ virtual void initialize(int idx);
+ virtual void reload(int idx);
+
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+ QSGGeometryNode* buildSimpleParticleNode();
+
+private slots:
+ void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
+
+private:
+ bool m_do_reset;
+
+ QUrl m_image_name;
+ QUrl m_colortable_name;
+ QUrl m_sizetable_name;
+ QUrl m_opacitytable_name;
+
+
+ QColor m_color;
+ qreal m_color_variation;
+ qreal m_particleDuration;
+
+ QSGGeometryNode *m_node;
+ UltraMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ qreal m_alphaVariation;
+ qreal m_alpha;
+ qreal m_redVariation;
+ qreal m_greenVariation;
+ qreal m_blueVariation;
+ qreal m_rotation;
+ qreal m_rotationVariation;
+ qreal m_rotationSpeed;
+ qreal m_rotationSpeedVariation;
+ bool m_autoRotation;
+ QSGStochasticDirection* m_xVector;
+ QSGStochasticDirection* m_yVector;
+
+ QList<QSGSprite*> m_sprites;
+ QSGSpriteEngine* m_spriteEngine;
+
+ bool m_bloat;
+ PerformanceLevel perfLevel;
+
+ PerformanceLevel m_lastLevel;
+ void* m_lastData;
+ int m_lastCount;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ULTRAPARTICLE_H
diff --git a/src/declarative/particles/qsgitemparticle.cpp b/src/declarative/particles/qsgitemparticle.cpp
new file mode 100644
index 0000000000..5e324cd43d
--- /dev/null
+++ b/src/declarative/particles/qsgitemparticle.cpp
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgitemparticle_p.h"
+#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
+#include <qsgnode.h>
+#include <QTimer>
+#include <QDeclarativeComponent>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QSGItemParticle::QSGItemParticle(QSGItem *parent) :
+ QSGParticlePainter(parent), m_fade(true), m_delegate(0)
+{
+ setFlag(QSGItem::ItemHasContents);
+ QTimer* manageDelegates = new QTimer(this);//TODO: don't leak
+ connect(manageDelegates, SIGNAL(timeout()),
+ this, SLOT(tick()));
+ manageDelegates->setInterval(16);
+ manageDelegates->setSingleShot(false);
+ manageDelegates->start();
+}
+
+
+void QSGItemParticle::freeze(QSGItem* item)
+{
+ m_stasis << item;
+}
+
+
+void QSGItemParticle::unfreeze(QSGItem* item)
+{
+ m_stasis.remove(item);
+}
+
+void QSGItemParticle::take(QSGItem *item, bool prioritize)
+{
+ if(prioritize)
+ m_pendingItems.push_front(item);
+ else
+ m_pendingItems.push_back(item);
+}
+
+void QSGItemParticle::give(QSGItem *item)
+{
+ //TODO: This
+}
+
+void QSGItemParticle::initialize(int idx)
+{
+ m_loadables << idx;//defer to other thread
+}
+
+void QSGItemParticle::reload(int idx)
+{
+}
+
+void QSGItemParticle::tick()
+{
+ foreach(QSGItem* item, m_deletables){
+ if(m_fade)
+ item->setOpacity(0.);
+ QSGItemParticleAttached* mpa;
+ if((mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(item))))
+ mpa->detach();//reparent as well?
+ //TODO: Delete iff we created it
+ m_activeCount--;
+ }
+ m_deletables.clear();
+
+ foreach(int pos, m_loadables){
+ if(m_stasis.contains(m_data[pos]->delegate))
+ qWarning() << "Current model particles prefers overwrite:false";
+ //remove old item from the particle that is dying to make room for this one
+ if(m_data[pos]->delegate){
+ m_deletables << m_data[pos]->delegate;
+ m_activeCount--;
+ }
+ m_data[pos]->delegate = 0;
+ if(!m_pendingItems.isEmpty()){
+ m_data[pos]->delegate = m_pendingItems.front();
+ m_pendingItems.pop_front();
+ }else if(m_delegate){
+ m_data[pos]->delegate = qobject_cast<QSGItem*>(m_delegate->create(qmlContext(this)));
+ }
+ if(m_data[pos]->delegate && m_data[pos]){//###Data can be zero if creating an item leads to a reset - this screws things up.
+ m_data[pos]->delegate->setX(m_data[pos]->curX() - m_data[pos]->delegate->width()/2);//TODO: adjust for system?
+ m_data[pos]->delegate->setY(m_data[pos]->curY() - m_data[pos]->delegate->height()/2);
+ QSGItemParticleAttached* mpa = qobject_cast<QSGItemParticleAttached*>(qmlAttachedPropertiesObject<QSGItemParticle>(m_data[pos]->delegate));
+ if(mpa){
+ mpa->m_mp = this;
+ mpa->attach();
+ }
+ m_data[pos]->delegate->setParentItem(this);
+ if(m_fade)
+ m_data[pos]->delegate->setOpacity(0.);
+ m_activeCount++;
+ }
+ }
+ m_loadables.clear();
+}
+
+void QSGItemParticle::reset()
+{
+ QSGParticlePainter::reset();
+ //TODO: Cleanup items?
+ m_loadables.clear();
+ //deletables?
+}
+
+
+QSGNode* QSGItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
+{
+ //Dummy update just to get painting tick
+ if(m_pleaseReset){
+ m_pleaseReset = false;
+ reset();
+ }
+ prepareNextFrame();
+
+ update();//Get called again
+ if(n)
+ n->markDirty(QSGNode::DirtyMaterial);
+ return QSGItem::updatePaintNode(n,d);
+}
+
+void QSGItemParticle::prepareNextFrame()
+{
+ qint64 timeStamp = m_system->systemSync(this);
+ qreal curT = timeStamp/1000.0;
+ qreal dt = curT - m_lastT;
+ m_lastT = curT;
+ if(!m_activeCount)
+ return;
+
+ //TODO: Size, better fade?
+ for(int i=0; i<count(); i++){
+ QSGParticleData* data = m_data[i];
+ QSGItem* item = data->delegate;
+ if(!item)
+ continue;
+ qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan;
+ if(m_stasis.contains(item)) {
+ m_data[i]->t += dt;//Stasis effect
+ continue;
+ }
+ if(t >= 1.0){//Usually happens from load
+ m_deletables << item;
+ m_data[i]->delegate = 0;
+ m_activeCount--;
+ }else{//Fade
+ if(m_fade){
+ qreal o = 1.;
+ if(t<0.2)
+ o = t*5;
+ if(t>0.8)
+ o = (1-t)*5;
+ item->setOpacity(o);
+ }else{
+ item->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on
+ }
+ }
+ item->setX(data->curX() - item->width()/2 - m_systemOffset.x());
+ item->setY(data->curY() - item->height()/2 - m_systemOffset.y());
+ }
+}
+
+QSGItemParticleAttached *QSGItemParticle::qmlAttachedProperties(QObject *object)
+{
+ return new QSGItemParticleAttached(object);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgitemparticle_p.h b/src/declarative/particles/qsgitemparticle_p.h
new file mode 100644
index 0000000000..24bbcf97d8
--- /dev/null
+++ b/src/declarative/particles/qsgitemparticle_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ITEMPARTICLE_H
+#define ITEMPARTICLE_H
+#include "qsgparticlepainter_p.h"
+#include <QPointer>
+#include <QSet>
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGVisualDataModel;
+class QSGItemParticleAttached;
+
+class QSGItemParticle : public QSGParticlePainter
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fade READ fade WRITE setFade NOTIFY fadeChanged)
+ Q_PROPERTY(QDeclarativeComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+public:
+ explicit QSGItemParticle(QSGItem *parent = 0);
+
+ bool fade() const { return m_fade; }
+
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+ static QSGItemParticleAttached *qmlAttachedProperties(QObject *object);
+ QDeclarativeComponent* delegate() const
+ {
+ return m_delegate;
+ }
+
+signals:
+ void fadeChanged();
+
+ void delegateChanged(QDeclarativeComponent* arg);
+
+public slots:
+ //TODO: Add a follow mode, where moving the delegate causes the logical particle to go with it?
+ void freeze(QSGItem* item);
+ void unfreeze(QSGItem* item);
+ void take(QSGItem* item,bool prioritize=false);//take by modelparticle
+ void give(QSGItem* item);//give from modelparticle
+
+ void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();}
+ void setDelegate(QDeclarativeComponent* arg)
+ {
+ if (m_delegate != arg) {
+ m_delegate = arg;
+ emit delegateChanged(arg);
+ }
+ }
+
+protected:
+ virtual void reset();
+ virtual void reload(int idx);
+ virtual void initialize(int idx);
+ void prepareNextFrame();
+private slots:
+ void tick();
+private:
+ QList<QSGItem* > m_deletables;
+ QList< int > m_loadables;
+ bool m_fade;
+
+ QList<QSGItem*> m_pendingItems;
+ QList<int> m_available;
+ QSet<QSGItem*> m_stasis;
+ qreal m_lastT;
+ int m_activeCount;
+ QDeclarativeComponent* m_delegate;
+};
+
+class QSGItemParticleAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QSGItemParticle* particle READ particle CONSTANT);
+public:
+ QSGItemParticleAttached(QObject* parent)
+ : QObject(parent), m_mp(0)
+ {;}
+ QSGItemParticle* particle() {return m_mp;}
+ void detach(){emit detached();}
+ void attach(){emit attached();}
+private:
+ QSGItemParticle* m_mp;
+ friend class QSGItemParticle;
+Q_SIGNALS:
+ void detached();
+ void attached();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QSGItemParticle, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+#endif // ITEMPARTICLE_H
diff --git a/src/declarative/particles/qsgkill.cpp b/src/declarative/particles/qsgkill.cpp
new file mode 100644
index 0000000000..eb3a55d402
--- /dev/null
+++ b/src/declarative/particles/qsgkill.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgkill_p.h"
+#include "qsgparticleemitter_p.h"
+QT_BEGIN_NAMESPACE
+QSGKillAffector::QSGKillAffector(QSGItem *parent) :
+ QSGParticleAffector(parent)
+{
+}
+
+
+bool QSGKillAffector::affectParticle(QSGParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ if(d->stillAlive()){
+ d->t -= d->lifeSpan + 1;
+ return true;
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgkill_p.h b/src/declarative/particles/qsgkill_p.h
new file mode 100644
index 0000000000..1b24b2fb40
--- /dev/null
+++ b/src/declarative/particles/qsgkill_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef KILLAFFECTOR_H
+#define KILLAFFECTOR_H
+#include "qsgparticleaffector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGKillAffector : public QSGParticleAffector
+{
+ Q_OBJECT
+public:
+ explicit QSGKillAffector(QSGItem *parent = 0);
+protected:
+ virtual bool affectParticle(QSGParticleData *d, qreal dt);
+signals:
+
+public slots:
+
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // KILLAFFECTOR_H
diff --git a/src/declarative/particles/qsglineextruder.cpp b/src/declarative/particles/qsglineextruder.cpp
new file mode 100644
index 0000000000..f32b01402a
--- /dev/null
+++ b/src/declarative/particles/qsglineextruder.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qsglineextruder_p.h"
+#include <cmath>
+
+QSGLineExtruder::QSGLineExtruder(QObject *parent) :
+ QSGParticleExtruder(parent), m_mirrored(false)
+{
+}
+
+QPointF QSGLineExtruder::extrude(const QRectF &r)
+{
+ qreal x,y;
+ if(!r.height()){
+ x = r.width() * ((qreal)rand())/RAND_MAX;
+ y = 0;
+ }else{
+ y = r.height() * ((qreal)rand())/RAND_MAX;
+ if(!r.width()){
+ x = 0;
+ }else{
+ x = r.width()/r.height() * y;
+ if(m_mirrored)
+ x = r.width() - x;
+ }
+ }
+ return QPointF(x,y);
+}
diff --git a/src/declarative/particles/qsglineextruder_p.h b/src/declarative/particles/qsglineextruder_p.h
new file mode 100644
index 0000000000..f356ca332a
--- /dev/null
+++ b/src/declarative/particles/qsglineextruder_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINEEXTRUDER_H
+#define LINEEXTRUDER_H
+#include "qsgparticleextruder_p.h"
+
+class QSGLineExtruder : public QSGParticleExtruder
+{
+ Q_OBJECT
+ //Default is topleft to bottom right. Flipped makes it topright to bottom left
+ Q_PROPERTY(bool mirrored READ mirrored WRITE setmirrored NOTIFY mirroredChanged)
+
+public:
+ explicit QSGLineExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ bool mirrored() const
+ {
+ return m_mirrored;
+ }
+
+signals:
+
+ void mirroredChanged(bool arg);
+
+public slots:
+
+ void setmirrored(bool arg)
+ {
+ if (m_mirrored != arg) {
+ m_mirrored = arg;
+ emit mirroredChanged(arg);
+ }
+ }
+private:
+ bool m_mirrored;
+};
+
+#endif // LINEEXTRUDER_H
diff --git a/src/declarative/particles/qsgmaskextruder.cpp b/src/declarative/particles/qsgmaskextruder.cpp
new file mode 100644
index 0000000000..d9a463910d
--- /dev/null
+++ b/src/declarative/particles/qsgmaskextruder.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmaskextruder_p.h"
+#include <QImage>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+QSGMaskExtruder::QSGMaskExtruder(QObject *parent) :
+ QSGParticleExtruder(parent)
+ , m_lastWidth(-1)
+ , m_lastHeight(-1)
+{
+}
+
+QPointF QSGMaskExtruder::extrude(const QRectF &r)
+{
+ ensureInitialized(r);
+ if(!m_mask.count() || m_img.isNull())
+ return r.topLeft();
+ const QPointF p = m_mask[rand() % m_mask.count()];
+ //### Should random sub-pixel positioning be added?
+ return p + r.topLeft();
+}
+
+bool QSGMaskExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ ensureInitialized(bounds);//###Current usage patterns WILL lead to different bounds/r calls. Separate list?
+ if(m_img.isNull())
+ return false;
+ QPoint p = point.toPoint() - bounds.topLeft().toPoint();
+ return m_img.rect().contains(p) && (bool)m_img.pixelIndex(p);
+}
+
+void QSGMaskExtruder::ensureInitialized(const QRectF &r)
+{
+ if(m_lastWidth == r.width() && m_lastHeight == r.height())
+ return;//Same as before
+ m_lastWidth = r.width();
+ m_lastHeight = r.height();
+
+ m_img = QImage();
+ m_mask.clear();
+ if(m_source.isEmpty())
+ return;
+ m_img = QImage(m_source.toLocalFile());
+ if(m_img.isNull()){
+ qWarning() << "MaskShape: Cannot load" << qPrintable(m_source.toLocalFile());
+ return;
+ }
+ m_img = m_img.createAlphaMask();
+ m_img = m_img.convertToFormat(QImage::Format_Mono);//Else LSB, but I think that's easier
+ m_img = m_img.scaled(r.size().toSize());//TODO: Do they need aspect ratio stuff? Or tiling?
+ for(int i=0; i<r.width(); i++){
+ for(int j=0; j<r.height(); j++){
+ if(m_img.pixelIndex(i,j))//Direct bit manipulation is presumably more efficient
+ m_mask << QPointF(i,j);
+ }
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgmaskextruder_p.h b/src/declarative/particles/qsgmaskextruder_p.h
new file mode 100644
index 0000000000..b564efa6dc
--- /dev/null
+++ b/src/declarative/particles/qsgmaskextruder_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MASKEXTRUDER_H
+#define MASKEXTRUDER_H
+#include "qsgparticleextruder_p.h"
+#include <QUrl>
+#include <QImage>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaskExtruder : public QSGParticleExtruder
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+public:
+ explicit QSGMaskExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);
+
+ QUrl source() const
+ {
+ return m_source;
+ }
+
+signals:
+
+ void sourceChanged(QUrl arg);
+
+public slots:
+
+ void setSource(QUrl arg)
+ {
+ if (m_source != arg) {
+ m_source = arg;
+ m_lastHeight = -1;//Trigger reset
+ m_lastWidth = -1;
+ emit sourceChanged(arg);
+ }
+ }
+private:
+ QUrl m_source;
+
+ void ensureInitialized(const QRectF &r);
+ int m_lastWidth;
+ int m_lastHeight;
+ QImage m_img;
+ QList<QPointF> m_mask;//TODO: More memory efficient datastructures
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // MASKEXTRUDER_H
diff --git a/src/declarative/particles/qsgmodelparticle.cpp b/src/declarative/particles/qsgmodelparticle.cpp
new file mode 100644
index 0000000000..47b8844ad5
--- /dev/null
+++ b/src/declarative/particles/qsgmodelparticle.cpp
@@ -0,0 +1,275 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmodelparticle_p.h"
+#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
+#include <qsgnode.h>
+#include <QTimer>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QSGModelParticle::QSGModelParticle(QSGItem *parent) :
+ QSGParticlePainter(parent), m_ownModel(false), m_comp(0), m_model(0), m_fade(true), m_modelCount(0)
+{
+ setFlag(QSGItem::ItemHasContents);
+ QTimer* manageDelegates = new QTimer(this);//TODO: don't leak
+ connect(manageDelegates, SIGNAL(timeout()),
+ this, SLOT(processPending()));
+ manageDelegates->setInterval(16);
+ manageDelegates->setSingleShot(false);
+ manageDelegates->start();
+}
+
+QVariant QSGModelParticle::model() const
+{
+ return m_dataSource;
+}
+
+void QSGModelParticle::setModel(const QVariant &arg)
+{
+ if(arg == m_dataSource)
+ return;
+ m_dataSource = arg;
+ if(qobject_cast<QSGVisualDataModel*>(arg.value<QObject*>())) {
+ if(m_ownModel && m_model)
+ delete m_model;
+ m_model = qobject_cast<QSGVisualDataModel*>(arg.value<QObject*>());
+ m_ownModel = false;
+ }else{
+ if(!m_model || !m_ownModel)
+ m_model = new QSGVisualDataModel(qmlContext(this));
+ m_model->setModel(m_dataSource);
+ m_ownModel = true;
+ }
+ if(m_comp)
+ m_model->setDelegate(m_comp);
+ emit modelChanged();
+ emit modelCountChanged();
+ connect(m_model, SIGNAL(countChanged()),
+ this, SIGNAL(modelCountChanged()));
+ connect(m_model, SIGNAL(countChanged()),
+ this, SLOT(updateCount()));
+ updateCount();
+}
+
+void QSGModelParticle::updateCount()
+{
+ int newCount = 0;
+ if(m_model)
+ newCount = m_model->count();
+ if(newCount < 0)
+ return;//WTF?
+ if(m_modelCount == 0 || newCount == 0){
+ m_available.clear();
+ for(int i=0; i<newCount; i++)
+ m_available << i;
+ }else if(newCount < m_modelCount){
+ for(int i=newCount; i<m_modelCount; i++) //existing ones must leave normally, but aren't readded
+ m_available.removeAll(i);
+ }else if(newCount > m_modelCount){
+ for(int i=m_modelCount; i<newCount; i++)
+ m_available << i;
+ }
+ m_modelCount = newCount;
+}
+
+QDeclarativeComponent *QSGModelParticle::delegate() const
+{
+ if(m_model)
+ return m_model->delegate();
+ return 0;
+}
+
+void QSGModelParticle::setDelegate(QDeclarativeComponent *comp)
+{
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(m_model))
+ if (comp == dataModel->delegate())
+ return;
+ m_comp = comp;
+ if(m_model)
+ m_model->setDelegate(comp);
+ emit delegateChanged();
+}
+
+int QSGModelParticle::modelCount() const
+{
+ if(m_model)
+ const_cast<QSGModelParticle*>(this)->updateCount();//TODO: Investigate why this doesn't get called properly
+ return m_modelCount;
+}
+
+
+void QSGModelParticle::freeze(QSGItem* item)
+{
+ m_stasis << item;
+}
+
+
+void QSGModelParticle::unfreeze(QSGItem* item)
+{
+ m_stasis.remove(item);
+}
+
+void QSGModelParticle::initialize(int idx)
+{
+ if(!m_model || !m_model->count())
+ return;
+ if(m_available.isEmpty())
+ return;
+ m_requests << idx;
+ m_activeCount++;
+}
+
+void QSGModelParticle::processPending()
+{//can't create/delete arbitrary items in the render thread
+ foreach(QSGItem* item, m_deletables){
+ item->setOpacity(0.);
+ m_model->release(item);
+ }
+ m_deletables.clear();
+
+ foreach(int pos, m_requests){
+ if(m_data[pos]->delegate){
+ if(m_stasis.contains(m_data[pos]->delegate))
+ qWarning() << "Current model particles prefers overwrite:false";
+ //remove old item from the particle that is dying to make room for this one
+ m_deletables << m_data[pos]->delegate;
+ m_available << m_data[pos]->modelIndex;
+ m_data[pos]->modelIndex = -1;
+ m_data[pos]->delegate = 0;
+ m_data[pos] = 0;
+ m_activeCount--;
+ }
+
+ if(!m_available.isEmpty()){
+ m_data[pos]->delegate = m_model->item(m_available.first());
+ m_data[pos]->modelIndex = m_available.first();
+ m_available.pop_front();
+ QSGModelParticleAttached* mpa = qobject_cast<QSGModelParticleAttached*>(qmlAttachedPropertiesObject<QSGModelParticle>(m_data[pos]->delegate));
+ if(mpa){
+ mpa->m_mp = this;
+ mpa->attach();
+ }
+ m_data[pos]->delegate->setParentItem(this);
+ }
+ }
+ m_requests.clear();
+}
+
+void QSGModelParticle::reload(int idx)
+{
+ //No-op unless we start copying the data.
+}
+
+void QSGModelParticle::reset()
+{
+ QSGParticlePainter::reset();
+ //TODO: Cleanup items?
+ //m_available.clear();//Should this be reset too?
+ //m_pendingItems.clear();//TODO: Should this be done? If so, Emit signal?
+}
+
+
+QSGNode* QSGModelParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
+{
+ //Dummy update just to get painting tick
+ if(m_pleaseReset){
+ m_pleaseReset = false;
+ reset();
+ }
+ prepareNextFrame();
+
+ update();//Get called again
+ if(n)
+ n->markDirty(QSGNode::DirtyMaterial);
+ return QSGItem::updatePaintNode(n,d);
+}
+
+void QSGModelParticle::prepareNextFrame()
+{
+ qint64 timeStamp = m_system->systemSync(this);
+ qreal curT = timeStamp/1000.0;
+ qreal dt = curT - m_lastT;
+ m_lastT = curT;
+ if(!m_activeCount)
+ return;
+
+ //TODO: Size, better fade?
+ for(int i=0; i<count(); i++){
+ QSGParticleData* data = m_data[i];
+ if(!data->delegate)
+ continue;
+ qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan;
+ if(m_stasis.contains(m_data[i]->delegate)) {
+ m_data[i]->t += dt;//Stasis effect
+ continue;
+ }
+ if(t >= 1.0){//Usually happens from load
+ m_available << m_data[i]->modelIndex;
+ m_deletables << m_data[i]->delegate;
+ m_data[i]->modelIndex = -1;
+ m_data[i]->delegate = 0;
+ m_data[i] = 0;
+ m_activeCount--;
+ }else{//Fade
+ if(m_fade){
+ qreal o = 1.;
+ if(t<0.2)
+ o = t*5;
+ if(t>0.8)
+ o = (1-t)*5;
+ m_data[i]->delegate->setOpacity(o);
+ }else{
+ m_data[i]->delegate->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on
+ }
+ }
+ m_data[i]->delegate->setX(data->curX() - m_data[i]->delegate->width()/2 - m_systemOffset.x());
+ m_data[i]->delegate->setY(data->curY() - m_data[i]->delegate->height()/2 - m_systemOffset.y());
+ }
+}
+
+QSGModelParticleAttached *QSGModelParticle::qmlAttachedProperties(QObject *object)
+{
+ return new QSGModelParticleAttached(object);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgmodelparticle_p.h b/src/declarative/particles/qsgmodelparticle_p.h
new file mode 100644
index 0000000000..31e4025bb4
--- /dev/null
+++ b/src/declarative/particles/qsgmodelparticle_p.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DATAPARTICLE_H
+#define DATAPARTICLE_H
+#include "qsgparticlepainter_p.h"
+#include <QPointer>
+#include <QSet>
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGVisualDataModel;
+class QSGModelParticleAttached;
+
+class QSGModelParticle : public QSGParticlePainter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int modelCount READ modelCount NOTIFY modelCountChanged)
+ Q_PROPERTY(bool fade READ fade WRITE setFade NOTIFY fadeChanged)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+public:
+ explicit QSGModelParticle(QSGItem *parent = 0);
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int modelCount() const;
+
+ bool fade() const { return m_fade; }
+
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+
+ static QSGModelParticleAttached *qmlAttachedProperties(QObject *object);
+signals:
+ void modelChanged();
+ void delegateChanged();
+ void modelCountChanged();
+ void fadeChanged();
+
+public slots:
+ void freeze(QSGItem* item);
+ void unfreeze(QSGItem* item);
+
+ void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();}
+protected:
+ virtual void reset();
+ virtual void reload(int idx);
+ virtual void initialize(int idx);
+ void prepareNextFrame();
+private slots:
+ void updateCount();
+ void processPending();
+private:
+ bool m_ownModel;
+ QDeclarativeComponent* m_comp;
+ QSGVisualDataModel *m_model;
+ QVariant m_dataSource;
+ QList<QSGItem*> m_deletables;
+ QList< int > m_requests;
+ bool m_fade;
+
+ QList<QSGItem*> m_pendingItems;
+ QList<int> m_available;
+ QSet<QSGItem*> m_stasis;
+ qreal m_lastT;
+ int m_activeCount;
+ int m_modelCount;
+};
+
+class QSGModelParticleAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QSGModelParticle* particle READ particle CONSTANT);
+public:
+ QSGModelParticleAttached(QObject* parent)
+ : QObject(parent), m_mp(0)
+ {;}
+ QSGModelParticle* particle() {return m_mp;}
+ void detach(){emit detached();}
+ void attach(){emit attached();}
+private:
+ QSGModelParticle* m_mp;
+ friend class QSGModelParticle;
+Q_SIGNALS:
+ void detached();
+ void attached();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QSGModelParticle, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+#endif // DATAPARTICLE_H
diff --git a/src/declarative/particles/qsgparticleaffector.cpp b/src/declarative/particles/qsgparticleaffector.cpp
new file mode 100644
index 0000000000..5b0936cc40
--- /dev/null
+++ b/src/declarative/particles/qsgparticleaffector.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgparticleaffector_p.h"
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+QSGParticleAffector::QSGParticleAffector(QSGItem *parent) :
+ QSGItem(parent), m_needsReset(false), m_system(0), m_active(true)
+ , m_updateIntSet(false), m_shape(new QSGParticleExtruder(this)), m_signal(false)
+{
+ connect(this, SIGNAL(systemChanged(QSGParticleSystem*)),
+ this, SLOT(updateOffsets()));
+ connect(this, SIGNAL(xChanged()),
+ this, SLOT(updateOffsets()));
+ connect(this, SIGNAL(yChanged()),
+ this, SLOT(updateOffsets()));//TODO: in componentComplete and all relevant signals
+}
+
+void QSGParticleAffector::componentComplete()
+{
+ if(!m_system && qobject_cast<QSGParticleSystem*>(parentItem()))
+ setSystem(qobject_cast<QSGParticleSystem*>(parentItem()));
+ if(!m_system)
+ qWarning() << "Affector created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+
+void QSGParticleAffector::affectSystem(qreal dt)
+{
+ if(!m_active)
+ return;
+ if(!m_system){
+ qDebug() << "No system" << this;
+ return;
+ }
+ //If not reimplemented, calls affect particle per particle
+ //But only on particles in targeted system/area
+ if(m_updateIntSet){
+ m_groups.clear();
+ foreach(const QString &p, m_particles)
+ m_groups << m_system->m_groupIds[p];//###Can this occur before group ids are properly assigned?
+ m_updateIntSet = false;
+ }
+ foreach(QSGParticleGroupData* gd, m_system->m_groupData){
+ foreach(QSGParticleData* d, gd->data){
+ if(!d || (m_onceOff && m_onceOffed.contains(qMakePair(d->group, d->index))))
+ continue;
+ if(m_groups.isEmpty() || m_groups.contains(d->group)){
+ //Need to have previous location for affected. if signal || shape might be faster?
+ QPointF curPos = QPointF(d->curX(), d->curY());
+ if(width() == 0 || height() == 0
+ || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()),curPos)){
+ if(affectParticle(d, dt)){
+ m_system->m_needsReset << d;
+ if(m_onceOff)
+ m_onceOffed << qMakePair(d->group, d->index);
+ if(m_signal)
+ emit affected(curPos.x(), curPos.y());
+ }
+ }
+ }
+ }
+ }
+}
+
+bool QSGParticleAffector::affectParticle(QSGParticleData *d, qreal dt)
+{
+ Q_UNUSED(d);
+ Q_UNUSED(dt);
+ return false;
+}
+
+void QSGParticleAffector::reset(QSGParticleData* pd)
+{//TODO: This, among other ones, should be restructured so they don't all need to remember to call the superclass
+ if(m_onceOff)
+ m_onceOffed.remove(qMakePair(pd->group, pd->index));
+}
+
+void QSGParticleAffector::updateOffsets()
+{
+ if(m_system)
+ m_offset = m_system->mapFromItem(this, QPointF(0, 0));
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgparticleaffector_p.h b/src/declarative/particles/qsgparticleaffector_p.h
new file mode 100644
index 0000000000..7418760941
--- /dev/null
+++ b/src/declarative/particles/qsgparticleaffector_p.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEAFFECTOR_H
+#define PARTICLEAFFECTOR_H
+
+#include <QObject>
+#include "qsgparticlesystem_p.h"
+#include "qsgparticleextruder_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParticleAffector : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged)
+ Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
+ Q_PROPERTY(bool onceOff READ onceOff WRITE setOnceOff NOTIFY onceOffChanged)
+ Q_PROPERTY(QSGParticleExtruder* shape READ shape WRITE setShape NOTIFY shapeChanged)
+ Q_PROPERTY(bool signal READ signal WRITE setSignal NOTIFY signalChanged)
+
+public:
+ explicit QSGParticleAffector(QSGItem *parent = 0);
+ virtual void affectSystem(qreal dt);
+ virtual void reset(QSGParticleData*);//As some store their own data per particle?
+ QSGParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+ QStringList particles() const
+ {
+ return m_particles;
+ }
+
+ bool active() const
+ {
+ return m_active;
+ }
+
+ bool onceOff() const
+ {
+ return m_onceOff;
+ }
+
+ QSGParticleExtruder* shape() const
+ {
+ return m_shape;
+ }
+
+ bool signal() const
+ {
+ return m_signal;
+ }
+
+signals:
+
+ void systemChanged(QSGParticleSystem* arg);
+
+ void particlesChanged(QStringList arg);
+
+ void activeChanged(bool arg);
+
+ void onceOffChanged(bool arg);
+
+ void shapeChanged(QSGParticleExtruder* arg);
+
+ void affected(qreal x, qreal y);
+ void signalChanged(bool arg);
+
+public slots:
+void setSystem(QSGParticleSystem* arg)
+{
+ if (m_system != arg) {
+ m_system = arg;
+ m_system->registerParticleAffector(this);
+ emit systemChanged(arg);
+ }
+}
+
+void setParticles(QStringList arg)
+{
+ if (m_particles != arg) {
+ m_particles = arg;
+ m_updateIntSet = true;
+ emit particlesChanged(arg);
+ }
+}
+
+void setActive(bool arg)
+{
+ if (m_active != arg) {
+ m_active = arg;
+ emit activeChanged(arg);
+ }
+}
+
+void setOnceOff(bool arg)
+{
+ if (m_onceOff != arg) {
+ m_onceOff = arg;
+ emit onceOffChanged(arg);
+ }
+}
+
+void setShape(QSGParticleExtruder* arg)
+{
+ if (m_shape != arg) {
+ m_shape = arg;
+ emit shapeChanged(arg);
+ }
+}
+
+void setSignal(bool arg)
+{
+ if (m_signal != arg) {
+ m_signal = arg;
+ emit signalChanged(arg);
+ }
+}
+
+protected:
+ friend class QSGParticleSystem;
+ virtual bool affectParticle(QSGParticleData *d, qreal dt);
+ bool m_needsReset;//### What is this really saving?
+ QSGParticleSystem* m_system;
+ QStringList m_particles;
+ bool activeGroup(int g) {return m_groups.isEmpty() || m_groups.contains(g);}
+ bool m_active;
+ virtual void componentComplete();
+ QPointF m_offset;
+private:
+ QSet<int> m_groups;
+ QSet<QPair<int, int> > m_onceOffed;
+ bool m_updateIntSet;
+
+ bool m_onceOff;
+
+ QSGParticleExtruder* m_shape;
+
+ bool m_signal;
+
+private slots:
+ void updateOffsets();
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // PARTICLEAFFECTOR_H
diff --git a/src/declarative/particles/qsgparticleemitter.cpp b/src/declarative/particles/qsgparticleemitter.cpp
new file mode 100644
index 0000000000..143338f798
--- /dev/null
+++ b/src/declarative/particles/qsgparticleemitter.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgparticleemitter_p.h"
+QT_BEGIN_NAMESPACE
+QSGParticleEmitter::QSGParticleEmitter(QSGItem *parent) :
+ QSGItem(parent)
+ , m_particlesPerSecond(10)
+ , m_particleDuration(1000)
+ , m_particleDurationVariation(0)
+ , m_emitting(true)
+ , m_system(0)
+ , m_extruder(0)
+ , m_defaultExtruder(0)
+ , m_speed(&m_nullVector)
+ , m_acceleration(&m_nullVector)
+ , m_particleSize(16)
+ , m_particleEndSize(-1)
+ , m_particleSizeVariation(0)
+ , m_maxParticleCount(-1)
+ , m_burstLeft(0)
+
+{
+ //TODO: Reset speed/acc back to null vector? Or allow null pointer?
+ connect(this, SIGNAL(maxParticleCountChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+}
+
+QSGParticleEmitter::~QSGParticleEmitter()
+{
+ if(m_defaultExtruder)
+ delete m_defaultExtruder;
+}
+
+void QSGParticleEmitter::componentComplete()
+{
+ if(!m_system && qobject_cast<QSGParticleSystem*>(parentItem()))
+ setSystem(qobject_cast<QSGParticleSystem*>(parentItem()));
+ if(!m_system)
+ qWarning() << "Emitter created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+void QSGParticleEmitter::emitWindow(int timeStamp)
+{
+ Q_UNUSED(timeStamp);
+}
+
+
+void QSGParticleEmitter::setEmitting(bool arg)
+{
+ if (m_emitting != arg) {
+ m_emitting = arg;
+ emit emittingChanged(arg);
+ }
+}
+
+
+QSGParticleExtruder* QSGParticleEmitter::effectiveExtruder()
+{
+ if(m_extruder)
+ return m_extruder;
+ if(!m_defaultExtruder)
+ m_defaultExtruder = new QSGParticleExtruder;
+ return m_defaultExtruder;
+}
+
+void QSGParticleEmitter::pulse(qreal seconds)
+{
+ if(!particleCount())
+ qWarning() << "pulse called on an emitter with a particle count of zero";
+ if(!m_emitting)
+ m_burstLeft = seconds*1000.0;//TODO: Change name to match
+}
+
+void QSGParticleEmitter::burst(int num)
+{
+ if(!particleCount())
+ qWarning() << "burst called on an emitter with a particle count of zero";
+ m_burstQueue << qMakePair(num, QPointF(x(), y()));
+}
+
+void QSGParticleEmitter::burst(int num, qreal x, qreal y)
+{
+ if(!particleCount())
+ qWarning() << "burst called on an emitter with a particle count of zero";
+ m_burstQueue << qMakePair(num, QPointF(x, y));
+}
+
+void QSGParticleEmitter::setMaxParticleCount(int arg)
+{
+ if (m_maxParticleCount != arg) {
+ if(arg < 0 && m_maxParticleCount >= 0){
+ connect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ }else if(arg >= 0 && m_maxParticleCount < 0){
+ disconnect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ disconnect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ }
+ m_maxParticleCount = arg;
+ emit maxParticleCountChanged(arg);
+ }
+}
+
+int QSGParticleEmitter::particleCount() const
+{
+ if(m_maxParticleCount >= 0)
+ return m_maxParticleCount;
+ return m_particlesPerSecond*((m_particleDuration+m_particleDurationVariation)/1000.0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgparticleemitter_p.h b/src/declarative/particles/qsgparticleemitter_p.h
new file mode 100644
index 0000000000..65aca0c83e
--- /dev/null
+++ b/src/declarative/particles/qsgparticleemitter_p.h
@@ -0,0 +1,305 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEEMITTER_H
+#define PARTICLEEMITTER_H
+
+#include <QSGItem>
+#include <QDebug>
+#include "qsgparticlesystem_p.h"
+#include "qsgparticleextruder_p.h"
+#include "qsgstochasticdirection_p.h"
+
+#include <QList>
+#include <QPair>
+#include <QPointF>
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParticleEmitter : public QSGItem
+{
+ Q_OBJECT
+ //###currently goes in emitters OR sets system. Pick one?
+ Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QString particle READ particle WRITE setParticle NOTIFY particleChanged)
+ Q_PROPERTY(QSGParticleExtruder* shape READ extruder WRITE setExtruder NOTIFY extruderChanged)
+ Q_PROPERTY(bool emitting READ emitting WRITE setEmitting NOTIFY emittingChanged)
+
+ Q_PROPERTY(qreal emitRate READ particlesPerSecond WRITE setParticlesPerSecond NOTIFY particlesPerSecondChanged)
+ Q_PROPERTY(int lifeSpan READ particleDuration WRITE setParticleDuration NOTIFY particleDurationChanged)
+ Q_PROPERTY(int lifeSpanVariation READ particleDurationVariation WRITE setParticleDurationVariation NOTIFY particleDurationVariationChanged)
+ Q_PROPERTY(int emitCap READ maxParticleCount WRITE setMaxParticleCount NOTIFY maxParticleCountChanged)
+
+ Q_PROPERTY(qreal size READ particleSize WRITE setParticleSize NOTIFY particleSizeChanged)
+ Q_PROPERTY(qreal endSize READ particleEndSize WRITE setParticleEndSize NOTIFY particleEndSizeChanged)
+ Q_PROPERTY(qreal sizeVariation READ particleSizeVariation WRITE setParticleSizeVariation NOTIFY particleSizeVariationChanged)
+
+ Q_PROPERTY(QSGStochasticDirection *speed READ speed WRITE setSpeed NOTIFY speedChanged)
+ Q_PROPERTY(QSGStochasticDirection *acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
+public:
+ explicit QSGParticleEmitter(QSGItem *parent = 0);
+ virtual ~QSGParticleEmitter();
+ virtual void emitWindow(int timeStamp);
+
+ bool emitting() const
+ {
+ return m_emitting;
+ }
+
+ qreal particlesPerSecond() const
+ {
+ return m_particlesPerSecond;
+ }
+
+ int particleDuration() const
+ {
+ return m_particleDuration;
+ }
+
+ QSGParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+ QString particle() const
+ {
+ return m_particle;
+ }
+
+ int particleDurationVariation() const
+ {
+ return m_particleDurationVariation;
+ }
+
+ virtual void componentComplete();
+signals:
+ void particlesPerSecondChanged(qreal);
+ void particleDurationChanged(int);
+ void emittingChanged(bool);
+
+ void systemChanged(QSGParticleSystem* arg);
+
+ void particleChanged(QString arg);
+
+ void particleDurationVariationChanged(int arg);
+
+ void extruderChanged(QSGParticleExtruder* arg);
+
+ void particleSizeChanged(qreal arg);
+
+ void particleEndSizeChanged(qreal arg);
+
+ void particleSizeVariationChanged(qreal arg);
+
+ void speedChanged(QSGStochasticDirection * arg);
+
+ void accelerationChanged(QSGStochasticDirection * arg);
+
+ void maxParticleCountChanged(int arg);
+ void particleCountChanged();
+
+public slots:
+ void pulse(qreal seconds);
+ void burst(int num);
+ void burst(int num, qreal x, qreal y);
+
+ void setEmitting(bool arg);
+
+ void setParticlesPerSecond(qreal arg)
+ {
+ if (m_particlesPerSecond != arg) {
+ m_particlesPerSecond = arg;
+ emit particlesPerSecondChanged(arg);
+ }
+ }
+
+ void setParticleDuration(int arg)
+ {
+ if (m_particleDuration != arg) {
+ m_particleDuration = arg;
+ emit particleDurationChanged(arg);
+ }
+ }
+
+ void setSystem(QSGParticleSystem* arg)
+ {
+ if (m_system != arg) {
+ m_system = arg;
+ m_system->registerParticleEmitter(this);
+ emit systemChanged(arg);
+ }
+ }
+
+ void setParticle(QString arg)
+ {
+ if (m_particle != arg) {
+ m_particle = arg;
+ emit particleChanged(arg);
+ }
+ }
+
+ void setParticleDurationVariation(int arg)
+ {
+ if (m_particleDurationVariation != arg) {
+ m_particleDurationVariation = arg;
+ emit particleDurationVariationChanged(arg);
+ }
+ }
+ void setExtruder(QSGParticleExtruder* arg)
+ {
+ if (m_extruder != arg) {
+ m_extruder = arg;
+ emit extruderChanged(arg);
+ }
+ }
+
+ void setParticleSize(qreal arg)
+ {
+ if (m_particleSize != arg) {
+ m_particleSize = arg;
+ emit particleSizeChanged(arg);
+ }
+ }
+
+ void setParticleEndSize(qreal arg)
+ {
+ if (m_particleEndSize != arg) {
+ m_particleEndSize = arg;
+ emit particleEndSizeChanged(arg);
+ }
+ }
+
+ void setParticleSizeVariation(qreal arg)
+ {
+ if (m_particleSizeVariation != arg) {
+ m_particleSizeVariation = arg;
+ emit particleSizeVariationChanged(arg);
+ }
+ }
+
+ void setSpeed(QSGStochasticDirection * arg)
+ {
+ if (m_speed != arg) {
+ m_speed = arg;
+ emit speedChanged(arg);
+ }
+ }
+
+ void setAcceleration(QSGStochasticDirection * arg)
+ {
+ if (m_acceleration != arg) {
+ m_acceleration = arg;
+ emit accelerationChanged(arg);
+ }
+ }
+
+ void setMaxParticleCount(int arg);
+
+public:
+ int particleCount() const;
+
+ virtual void reset(){;}
+ QSGParticleExtruder* extruder() const
+ {
+ return m_extruder;
+ }
+
+ qreal particleSize() const
+ {
+ return m_particleSize;
+ }
+
+ qreal particleEndSize() const
+ {
+ return m_particleEndSize;
+ }
+
+ qreal particleSizeVariation() const
+ {
+ return m_particleSizeVariation;
+ }
+
+ QSGStochasticDirection * speed() const
+ {
+ return m_speed;
+ }
+
+ QSGStochasticDirection * acceleration() const
+ {
+ return m_acceleration;
+ }
+
+ int maxParticleCount() const
+ {
+ return m_maxParticleCount;
+ }
+
+protected:
+ qreal m_particlesPerSecond;
+ int m_particleDuration;
+ int m_particleDurationVariation;
+ bool m_emitting;
+ QSGParticleSystem* m_system;
+ QString m_particle;
+ QSGParticleExtruder* m_extruder;
+ QSGParticleExtruder* m_defaultExtruder;
+ QSGParticleExtruder* effectiveExtruder();
+ QSGStochasticDirection * m_speed;
+ QSGStochasticDirection * m_acceleration;
+ qreal m_particleSize;
+ qreal m_particleEndSize;
+ qreal m_particleSizeVariation;
+
+ int m_burstLeft;//TODO: Rename to pulse
+ QList<QPair<int, QPointF > > m_burstQueue;
+ int m_maxParticleCount;
+private:
+ QSGStochasticDirection m_nullVector;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLEEMITTER_H
diff --git a/src/declarative/particles/qsgparticleextruder.cpp b/src/declarative/particles/qsgparticleextruder.cpp
new file mode 100644
index 0000000000..91b968c8af
--- /dev/null
+++ b/src/declarative/particles/qsgparticleextruder.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgparticleextruder_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGParticleExtruder::QSGParticleExtruder(QObject *parent) :
+ QObject(parent), m_fill(true)
+{
+}
+
+QPointF QSGParticleExtruder::extrude(const QRectF &rect)
+{
+ if(m_fill)
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ int side = rand() % 4;
+ switch(side){//TODO: Doesn't this overlap the corners?
+ case 0:
+ return QPointF(rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ case 1:
+ return QPointF(rect.width() + rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ case 2:
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ rect.y());
+ default:
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ rect.height() + rect.y());
+ }
+}
+
+bool QSGParticleExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ return bounds.contains(point);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgparticleextruder_p.h b/src/declarative/particles/qsgparticleextruder_p.h
new file mode 100644
index 0000000000..41e27eb2fa
--- /dev/null
+++ b/src/declarative/particles/qsgparticleextruder_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEEXTRUDER_H
+#define PARTICLEEXTRUDER_H
+
+#include <QObject>
+#include <QRectF>
+#include <QPointF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParticleExtruder : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Should this be base class, or a BoxExtruder?
+
+public:
+ explicit QSGParticleExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);//###Needed for follow emitter, but does it belong? Only marginally conceptually valid, and that's from user's perspective
+ bool fill() const
+ {
+ return m_fill;
+ }
+
+signals:
+
+ void fillChanged(bool arg);
+
+public slots:
+
+ void setFill(bool arg)
+ {
+ if (m_fill != arg) {
+ m_fill = arg;
+ emit fillChanged(arg);
+ }
+ }
+protected:
+ bool m_fill;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLEEXTRUDER_H
diff --git a/src/declarative/particles/qsgparticlepainter.cpp b/src/declarative/particles/qsgparticlepainter.cpp
new file mode 100644
index 0000000000..cf1d3c2894
--- /dev/null
+++ b/src/declarative/particles/qsgparticlepainter.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgparticlepainter_p.h"
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+QSGParticlePainter::QSGParticlePainter(QSGItem *parent) :
+ QSGItem(parent),
+ m_system(0), m_count(0), m_lastStart(0), m_sentinel(new QSGParticleData)
+{
+ connect(this, SIGNAL(xChanged()),
+ this, SLOT(calcSystemOffset()));
+ connect(this, SIGNAL(yChanged()),
+ this, SLOT(calcSystemOffset()));
+}
+
+void QSGParticlePainter::componentComplete()
+{
+ if(!m_system && qobject_cast<QSGParticleSystem*>(parentItem()))
+ setSystem(qobject_cast<QSGParticleSystem*>(parentItem()));
+ if(!m_system)
+ qWarning() << "ParticlePainter created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+
+
+void QSGParticlePainter::setSystem(QSGParticleSystem *arg)
+{
+ if (m_system != arg) {
+ m_system = arg;
+ if(m_system){
+ m_system->registerParticlePainter(this);
+ connect(m_system, SIGNAL(xChanged()),
+ this, SLOT(calcSystemOffset()));
+ connect(m_system, SIGNAL(yChanged()),
+ this, SLOT(calcSystemOffset()));
+ calcSystemOffset();
+ }
+ emit systemChanged(arg);
+ }
+}
+
+void QSGParticlePainter::load(QSGParticleData* d)
+{
+ int idx = particleTypeIndex(d);
+ m_data[idx] = d;
+ initialize(idx);
+ reload(idx);
+}
+
+void QSGParticlePainter::reload(QSGParticleData* d)
+{
+ reload(particleTypeIndex(d));
+}
+
+void QSGParticlePainter::reset()
+{
+ //Have to every time because what it's emitting may have changed and that affects particleTypeIndex
+ if(m_system && !m_inResize)
+ resize(0,1);//###Fix this by making resize take sensible arguments
+ //###This also means double resets. Make reset not virtual?
+}
+
+void QSGParticlePainter::resize(int oldSize, int newSize)
+{
+ if(newSize == oldSize)//TODO: What if particles switched so indices change but total count is the same?
+ return;
+
+ QHash<int, QPair<int, int> > oldStarts(m_particleStarts);
+ //Update particle starts datastore
+ m_particleStarts.clear();
+ m_lastStart = 0;
+ QList<int> particleList;
+ if(m_particles.isEmpty())
+ particleList << 0;
+ foreach(const QString &s, m_particles)
+ particleList << m_system->m_groupIds[s];
+ foreach(int gIdx, particleList){
+ QSGParticleGroupData *gd = m_system->m_groupData[gIdx];
+ m_particleStarts.insert(gIdx, qMakePair<int, int>(gd->size, m_lastStart));
+ m_lastStart += gd->size;
+ }
+
+ //Shuffle stuff around
+ //TODO: In place shuffling because it's faster
+ QVector<QSGParticleData*> oldData(m_data);
+ QVector<QObject*> oldAttached(m_attachedData);
+ m_data.clear();
+ m_data.resize(m_count);
+ m_attachedData.resize(m_count);
+ foreach(int gIdx, particleList){
+ QSGParticleGroupData *gd = m_system->m_groupData[gIdx];
+ for(int i=0; i<gd->data.size(); i++){//TODO: When group didn't exist before
+ int newIdx = m_particleStarts[gIdx].second + i;
+ int oldIdx = oldStarts[gIdx].second + i;
+ if(i >= oldStarts[gIdx].first || oldData.size() <= oldIdx){
+ m_data[newIdx] = m_sentinel;
+ }else{
+ m_data[newIdx] = oldData[oldIdx];
+ m_attachedData[newIdx] = oldAttached[oldIdx];
+ }
+ }
+ }
+ m_inResize = true;
+ reset();
+ m_inResize = false;
+}
+
+
+void QSGParticlePainter::setCount(int c)
+{
+ Q_ASSERT(c >= 0); //XXX
+ if(c == m_count)
+ return;
+ int lastCount = m_count;
+ m_count = c;
+ resize(lastCount, m_count);
+ emit countChanged();
+}
+
+int QSGParticlePainter::count()
+{
+ return m_count;
+}
+
+int QSGParticlePainter::particleTypeIndex(QSGParticleData* d)
+{
+ Q_ASSERT(d && m_particleStarts.contains(d->group));//XXX
+ int ret = m_particleStarts[d->group].second + d->index;
+ Q_ASSERT(ret >=0 && ret < m_count);//XXX:shouldn't assert, but bugs here were hard to find in the past
+ return ret;
+}
+
+
+void QSGParticlePainter::calcSystemOffset()
+{
+ if(!m_system)
+ return;
+ QPointF lastOffset = m_systemOffset;
+ m_systemOffset = -1 * this->mapFromItem(m_system, QPointF());
+ if(lastOffset != m_systemOffset){
+ //Reload all particles//TODO: Necessary?
+ foreach(const QString &g, m_particles){
+ int gId = m_system->m_groupIds[g];
+ foreach(QSGParticleData* d, m_system->m_groupData[gId]->data)
+ reload(d);
+ }
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgparticlepainter_p.h b/src/declarative/particles/qsgparticlepainter_p.h
new file mode 100644
index 0000000000..e506018f53
--- /dev/null
+++ b/src/declarative/particles/qsgparticlepainter_p.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLE_H
+#define PARTICLE_H
+
+#include <QObject>
+#include <QDebug>
+#include "qsgparticlesystem_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGParticlePainter : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged)
+
+public:
+ explicit QSGParticlePainter(QSGItem *parent = 0);
+ //Data Interface to system
+ void load(QSGParticleData*);
+ void reload(QSGParticleData*);
+ void setCount(int c);
+ int count();
+ QSGParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+
+ QStringList particles() const
+ {
+ return m_particles;
+ }
+
+signals:
+ void countChanged();
+ void systemChanged(QSGParticleSystem* arg);
+
+ void particlesChanged(QStringList arg);
+
+public slots:
+void setSystem(QSGParticleSystem* arg);
+
+void setParticles(QStringList arg)
+{
+ if (m_particles != arg) {
+ m_particles = arg;
+ emit particlesChanged(arg);
+ }
+}
+private slots:
+ void calcSystemOffset();
+
+protected:
+ /* Reset resets all your internal data structures. But anything attached to a particle should
+ be in attached data. So reset + reloads should have no visible effect.
+ ###Hunt down all cases where we do a complete reset for convenience and be more targeted
+ */
+ virtual void reset();
+
+ virtual void componentComplete();
+ //Data interface to painters
+ QVector<QSGParticleData*> m_data; //Actually stored in arbitrary order,
+ QVector<QObject*> m_attachedData; //This data will be moved along with m_data in resizes (but you own it)
+ virtual void initialize(int){}
+ virtual void reload(int){}//If you need to do something on size changed, check m_data size in this? Or we reset you every time?
+
+ QSGParticleSystem* m_system;
+ friend class QSGParticleSystem;
+ int m_count;
+ bool m_pleaseReset;
+ QStringList m_particles;
+ QPointF m_systemOffset;
+
+
+private:
+ int m_lastStart;
+ QHash<int, QPair<int, int> > m_particleStarts;
+ int particleTypeIndex(QSGParticleData* d);//Now private
+ void resize(int, int);
+
+ QSGParticleData* m_sentinel;
+ //QVector<QSGParticleData*> m_shadowData;//For when we implement overwrite: false
+ bool m_inResize;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // PARTICLE_H
diff --git a/src/declarative/particles/qsgparticlesmodule.cpp b/src/declarative/particles/qsgparticlesmodule.cpp
new file mode 100644
index 0000000000..a7a9a9253f
--- /dev/null
+++ b/src/declarative/particles/qsgparticlesmodule.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgangleddirection_p.h"
+#include "qsgcustomparticle_p.h"
+#include "qsgellipseextruder_p.h"
+#include "qsgemitter_p.h"
+#include "qsgfollowemitter_p.h"
+#include "qsgfriction_p.h"
+#include "qsggravity_p.h"
+#include "qsgimageparticle_p.h"
+#include "qsgitemparticle_p.h"
+#include "qsgkill_p.h"
+#include "qsglineextruder_p.h"
+#include "qsgmaskextruder_p.h"
+#include "qsgmodelparticle_p.h"
+#include "qsgparticleaffector_p.h"
+#include "qsgparticleemitter_p.h"
+#include "qsgparticleextruder_p.h"
+#include "qsgparticlepainter_p.h"
+#include "qsgparticlesmodule_p.h"
+#include "qsgparticlesystem_p.h"
+#include "qsgpointattractor_p.h"
+#include "qsgpointdirection_p.h"
+#include "qsgspritegoal_p.h"
+#include "qsgstochasticdirection_p.h"
+#include "qsgtargeteddirection_p.h"
+#include "qsgturbulence_p.h"
+#include "qsgwander_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QSGParticlesModule::defineModule()
+{
+ const char* uri = "QtQuick.Particles";
+ //Debugging only exposition
+ qmlRegisterType<QSGParticlePainter>(uri, 2, 0, "ParticlePainter");
+ qmlRegisterType<QSGParticleEmitter>(uri, 2, 0, "ParticleEmitter");
+ qmlRegisterType<QSGParticleExtruder>(uri, 2, 0, "ParticleExtruder");
+ qmlRegisterType<QSGStochasticDirection>(uri, 2, 0, "NullVector");
+ //Probably should be nocreate types
+
+ qmlRegisterType<QSGParticleSystem>(uri, 2, 0, "ParticleSystem");
+
+ qmlRegisterType<QSGImageParticle>(uri, 2, 0, "ImageParticle");
+ qmlRegisterType<QSGCustomParticle>(uri, 2, 0, "CustomParticle");
+ qmlRegisterType<QSGItemParticle>(uri, 2, 0, "ItemParticle");
+ qmlRegisterType<QSGModelParticle>(uri, 2, 0, "ModelParticle");
+
+ qmlRegisterType<QSGBasicEmitter>(uri, 2, 0, "Emitter");
+ qmlRegisterType<QSGFollowEmitter>(uri, 2, 0, "FollowEmitter");
+
+ qmlRegisterType<QSGEllipseExtruder>(uri, 2, 0, "EllipseShape");
+ qmlRegisterType<QSGLineExtruder>(uri, 2, 0, "LineShape");
+ qmlRegisterType<QSGMaskExtruder>(uri, 2, 0, "MaskShape");
+
+ qmlRegisterType<QSGPointDirection>(uri, 2, 0, "PointDirection");
+ qmlRegisterType<QSGAngledDirection>(uri, 2, 0, "AngledDirection");
+ qmlRegisterType<QSGTargetedDirection>(uri, 2, 0, "TargetedDirection");
+
+ qmlRegisterType<QSGParticleAffector>(uri, 2, 0, "ParticleAffector");//if it has a triggered signal, it's useful
+ qmlRegisterType<QSGWanderAffector>(uri, 2, 0, "Wander");
+ qmlRegisterType<QSGFrictionAffector>(uri, 2, 0, "Friction");
+ qmlRegisterType<QSGPointAttractorAffector>(uri, 2, 0, "PointAttractor");
+ qmlRegisterType<QSGGravityAffector>(uri, 2, 0, "Gravity");
+ qmlRegisterType<QSGKillAffector>(uri, 2, 0, "Kill");
+ qmlRegisterType<QSGSpriteGoalAffector>(uri, 2, 0, "SpriteGoal");
+ qmlRegisterType<QSGTurbulenceAffector>(uri, 2, 0 , "Turbulence");
+}
+
+QT_END_NAMESPACE
+
+//Q_EXPORT_PLUGIN2(Particles, QT_PREPEND_NAMESPACE(ParticlesModule))
diff --git a/src/declarative/particles/qsgparticlesmodule_p.h b/src/declarative/particles/qsgparticlesmodule_p.h
new file mode 100644
index 0000000000..1afe0654f6
--- /dev/null
+++ b/src/declarative/particles/qsgparticlesmodule_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPARTICLESMODULE_H
+#define QSGPARTICLESMODULE_H
+
+#include <qdeclarative.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGParticlesModule
+{
+public:
+ static void defineModule();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGPARTICLESMODULE_H
diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp
new file mode 100644
index 0000000000..2dc21299cf
--- /dev/null
+++ b/src/declarative/particles/qsgparticlesystem.cpp
@@ -0,0 +1,447 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgparticlesystem_p.h"
+#include <qsgnode.h>
+#include "qsgparticleemitter_p.h"
+#include "qsgparticleaffector_p.h"
+#include "qsgparticlepainter_p.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QSGParticleData::QSGParticleData()
+ : group(0)
+ , e(0)
+ , index(0)
+{
+ x = 0;
+ y = 0;
+ t = -1;
+ size = 0;
+ endSize = 0;
+ sx = 0;
+ sy = 0;
+ ax = 0;
+ ay = 0;
+ xx = 1;
+ xy = 0;
+ yx = 0;
+ yy = 1;
+ rotation = 0;
+ rotationSpeed = 0;
+ autoRotate = 0;
+ animIdx = -1;
+ frameDuration = 1;
+ frameCount = 0;
+ animT = -1;
+ color.r = 255;
+ color.g = 255;
+ color.b = 255;
+ color.a = 255;
+ r = 0;
+ delegate = 0;
+ modelIndex = -1;
+}
+
+QSGParticleSystem::QSGParticleSystem(QSGItem *parent) :
+ QSGItem(parent), m_particle_count(0), m_running(true)
+ , m_startTime(0), m_overwrite(false)
+ , m_componentComplete(false)
+{
+ QSGParticleGroupData* gd = new QSGParticleGroupData;//Default group
+ m_groupData.insert(0,gd);
+ m_groupIds.insert("",0);
+ m_nextGroupId = 1;
+
+ connect(&m_painterMapper, SIGNAL(mapped(QObject*)),
+ this, SLOT(loadPainter(QObject*)));
+}
+
+void QSGParticleSystem::registerParticlePainter(QSGParticlePainter* p)
+{
+ //TODO: a way to Unregister emitters, painters and affectors
+ m_particlePainters << QPointer<QSGParticlePainter>(p);//###Set or uniqueness checking?
+ connect(p, SIGNAL(particlesChanged(QStringList)),
+ &m_painterMapper, SLOT(map()));
+ loadPainter(p);
+ p->update();//###Initial update here?
+}
+
+void QSGParticleSystem::registerParticleEmitter(QSGParticleEmitter* e)
+{
+ m_emitters << QPointer<QSGParticleEmitter>(e);//###How to get them out?
+ connect(e, SIGNAL(particleCountChanged()),
+ this, SLOT(emittersChanged()));
+ connect(e, SIGNAL(particleChanged(QString)),
+ this, SLOT(emittersChanged()));
+ emittersChanged();
+ e->reset();//Start, so that starttime factors appropriately
+}
+
+void QSGParticleSystem::registerParticleAffector(QSGParticleAffector* a)
+{
+ m_affectors << QPointer<QSGParticleAffector>(a);
+}
+
+void QSGParticleSystem::loadPainter(QObject *p)
+{
+ if(!m_componentComplete)
+ return;
+
+ QSGParticlePainter* painter = qobject_cast<QSGParticlePainter*>(p);
+ Q_ASSERT(painter);//XXX
+ foreach(QSGParticleGroupData* sg, m_groupData)
+ sg->painters.remove(painter);
+ int particleCount = 0;
+ if(painter->particles().isEmpty()){//Uses default particle
+ particleCount += m_groupData[0]->size;
+ m_groupData[0]->painters << painter;
+ }else{
+ foreach(const QString &group, painter->particles()){
+ particleCount += m_groupData[m_groupIds[group]]->size;
+ m_groupData[m_groupIds[group]]->painters << painter;
+ }
+ }
+ painter->setCount(particleCount);
+ painter->update();//###Initial update here?
+ return;
+}
+
+void QSGParticleSystem::emittersChanged()
+{
+ if(!m_componentComplete)
+ return;
+
+ m_emitters.removeAll(0);
+
+ //Recalculate all counts, as emitter 'particle' may have changed as well
+ //### Worth tracking previous 'particle' per emitter to do partial recalculations?
+ m_particle_count = 0;
+
+ int previousGroups = m_nextGroupId;
+ QVector<int> previousSizes;
+ previousSizes.resize(previousGroups);
+ for(int i=0; i<previousGroups; i++)
+ previousSizes[i] = m_groupData[i]->size;
+ for(int i=0; i<previousGroups; i++)
+ m_groupData[i]->size = 0;
+
+ foreach(QSGParticleEmitter* e, m_emitters){//Populate groups and set sizes.
+ if(!m_groupIds.contains(e->particle())
+ || (!e->particle().isEmpty() && !m_groupIds[e->particle()])){//or it was accidentally inserted by a failed lookup earlier
+ QSGParticleGroupData* gd = new QSGParticleGroupData;
+ int id = m_nextGroupId++;
+ m_groupIds.insert(e->particle(), id);
+ m_groupData.insert(id, gd);
+ }
+ m_groupData[m_groupIds[e->particle()]]->size += e->particleCount();
+ m_particle_count += e->particleCount();
+ //###: Cull emptied groups?
+ }
+
+ foreach(QSGParticleGroupData* gd, m_groupData){//resize groups and update painters
+ int id = m_groupData.key(gd);
+
+ //TODO: Shrink back down! (but it has the problem of trying to remove the dead particles while maintaining integrity)
+ gd->size = qMax(gd->size, id < previousGroups?previousSizes[id]:0);
+
+ gd->data.resize(gd->size);
+ if(id < previousGroups){
+ for(int i=previousSizes[id]; i<gd->size; i++)
+ gd->data[i] = 0;
+ /*TODO:Consider salvaging partial updates, but have to batch changes to a single painter
+ int delta = 0;
+ delta = gd->size - previousSizes[id];
+ foreach(QSGParticlePainter* painter, gd->painters){
+ if(!painter->count() && delta){
+ painter->reset();
+ painter->update();
+ }
+ qDebug() << "Phi" << painter << painter->count() << delta;
+ painter->setCount(painter->count() + delta);
+ }
+ */
+ }
+ }
+ foreach(QSGParticlePainter *p, m_particlePainters)
+ loadPainter(p);
+
+ if(m_particle_count > 16000)//###Investigate if these limits are worth warning about?
+ qWarning() << "Particle system arbitarily believes it has a vast number of particles (>16000). Expect poor performance";
+}
+
+void QSGParticleSystem::setRunning(bool arg)
+{
+ if (m_running != arg) {
+ m_running = arg;
+ emit runningChanged(arg);
+ reset();
+ }
+}
+
+void QSGParticleSystem::componentComplete()
+{
+ QSGItem::componentComplete();
+ m_componentComplete = true;
+ //if(!m_emitters.isEmpty() && !m_particlePainters.isEmpty())
+ reset();
+}
+
+void QSGParticleSystem::reset()//TODO: Needed?
+{
+ if(!m_componentComplete)
+ return;
+
+ //Clear guarded pointers which have been deleted
+ int cleared = 0;
+ cleared += m_emitters.removeAll(0);
+ cleared += m_particlePainters.removeAll(0);
+ cleared += m_affectors.removeAll(0);
+ //qDebug() << "Reset" << m_emitters.count() << m_particles.count() << "Cleared" << cleared;
+
+ emittersChanged();
+
+ //TODO: Reset data
+// foreach(QSGParticlePainter* p, m_particlePainters)
+// p->reset();
+// foreach(QSGParticleEmitter* e, m_emitters)
+// e->reset();
+ //### Do affectors need reset too?
+
+ if(!m_running)
+ return;
+
+ foreach(QSGParticlePainter *p, m_particlePainters){
+ loadPainter(p);
+ p->reset();
+ }
+
+ m_timestamp.start();//TODO: Better placement
+ m_initialized = true;
+}
+
+QSGParticleData* QSGParticleSystem::newDatum(int groupId)
+{
+
+ Q_ASSERT(groupId < m_groupData.count());//XXX shouldn't really be an assert
+ Q_ASSERT(m_groupData[groupId]->size);
+
+ if( m_groupData[groupId]->nextIdx >= m_groupData[groupId]->size)
+ m_groupData[groupId]->nextIdx = 0;
+ int nextIdx = m_groupData[groupId]->nextIdx++;
+
+ Q_ASSERT(nextIdx < m_groupData[groupId]->size);
+ QSGParticleData* ret;
+ if(m_groupData[groupId]->data[nextIdx]){//Recycle, it's faster.
+ ret = m_groupData[groupId]->data[nextIdx];
+ if(!m_overwrite && ret->stillAlive()){
+ return 0;//Artificial longevity (or too fast emission) means this guy hasn't died. To maintain count, don't emit a new one
+ }//###Reset?
+ }else{
+ ret = new QSGParticleData;
+ m_groupData[groupId]->data[nextIdx] = ret;
+ }
+
+ ret->system = this;
+ ret->index = nextIdx;
+ ret->group = groupId;
+ return ret;
+}
+
+void QSGParticleSystem::emitParticle(QSGParticleData* pd)
+{// called from prepareNextFrame()->emitWindow - enforce?
+ //Account for relative emitter position
+ QPointF offset = this->mapFromItem(pd->e, QPointF(0, 0));
+ if(!offset.isNull()){
+ pd->x += offset.x();
+ pd->y += offset.y();
+ }
+
+ foreach(QSGParticleAffector *a, m_affectors)
+ if(a && a->m_needsReset)
+ a->reset(pd);
+ foreach(QSGParticlePainter* p, m_groupData[pd->group]->painters)
+ if(p)
+ p->load(pd);
+}
+
+
+
+qint64 QSGParticleSystem::systemSync(QSGParticlePainter* p)
+{
+ if (!m_running)
+ return 0;
+ if (!m_initialized)
+ return 0;//error in initialization
+
+ if(m_syncList.isEmpty() || m_syncList.contains(p)){//Need to advance the simulation
+ m_syncList.clear();
+
+ //### Elapsed time never shrinks - may cause problems if left emitting for weeks at a time.
+ qreal dt = m_timeInt / 1000.;
+ m_timeInt = m_timestamp.elapsed() + m_startTime;
+ qreal time = m_timeInt / 1000.;
+ dt = time - dt;
+ m_needsReset.clear();
+ foreach(QSGParticleEmitter* emitter, m_emitters)
+ if(emitter)
+ emitter->emitWindow(m_timeInt);
+ foreach(QSGParticleAffector* a, m_affectors)
+ if(a)
+ a->affectSystem(dt);
+ foreach(QSGParticleData* d, m_needsReset)
+ foreach(QSGParticlePainter* p, m_groupData[d->group]->painters)
+ if(p && d)
+ p->reload(d);
+ }
+ m_syncList << p;
+ return m_timeInt;
+}
+
+//sets the x accleration without affecting the instantaneous x velocity or position
+void QSGParticleData::setInstantaneousAX(qreal ax)
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ qreal sx = (this->sx + t*this->ax) - t*ax;
+ qreal ex = this->x + this->sx * t + 0.5 * this->ax * t * t;
+ qreal x = ex - t*sx - 0.5 * t*t*ax;
+
+ this->ax = ax;
+ this->sx = sx;
+ this->x = x;
+}
+
+//sets the x velocity without affecting the instantaneous x postion
+void QSGParticleData::setInstantaneousSX(qreal vx)
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ qreal sx = vx - t*this->ax;
+ qreal ex = this->x + this->sx * t + 0.5 * this->ax * t * t;
+ qreal x = ex - t*sx - 0.5 * t*t*this->ax;
+
+ this->sx = sx;
+ this->x = x;
+}
+
+//sets the instantaneous x postion
+void QSGParticleData::setInstantaneousX(qreal x)
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ this->x = x - t*this->sx - 0.5 * t*t*this->ax;
+}
+
+//sets the y accleration without affecting the instantaneous y velocity or position
+void QSGParticleData::setInstantaneousAY(qreal ay)
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ qreal sy = (this->sy + t*this->ay) - t*ay;
+ qreal ey = this->y + this->sy * t + 0.5 * this->ay * t * t;
+ qreal y = ey - t*sy - 0.5 * t*t*ay;
+
+ this->ay = ay;
+ this->sy = sy;
+ this->y = y;
+}
+
+//sets the y velocity without affecting the instantaneous y position
+void QSGParticleData::setInstantaneousSY(qreal vy)
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ //qDebug() << t << (system->m_timeInt/1000.0) << this->x << this->sx << this->ax << this->x + this->sx * t + 0.5 * this->ax * t * t;
+ qreal sy = vy - t*this->ay;
+ qreal ey = this->y + this->sy * t + 0.5 * this->ay * t * t;
+ qreal y = ey - t*sy - 0.5 * t*t*this->ay;
+
+ this->sy = sy;
+ this->y = y;
+}
+
+//sets the instantaneous Y position
+void QSGParticleData::setInstantaneousY(qreal y)
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ this->y = y - t*this->sy - 0.5 * t*t*this->ay;
+}
+
+qreal QSGParticleData::curX() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ return this->x + this->sx * t + 0.5 * this->ax * t * t;
+}
+
+qreal QSGParticleData::curSX() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ return this->sx + t*this->ax;
+}
+
+qreal QSGParticleData::curY() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ return y + sy * t + 0.5 * ay * t * t;
+}
+
+qreal QSGParticleData::curSY() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - this->t;
+ return sy + t*ay;
+}
+
+void QSGParticleData::debugDump()
+{
+ qDebug() << "Particle" << group
+ << "Pos: " << x << "," << y
+ << "Vel: " << sx << "," << sy
+ << "Acc: " << ax << "," << ay
+ << "Size: " << size << "," << endSize
+ << "Time: " << t << "," <<lifeSpan;
+}
+
+bool QSGParticleData::stillAlive()
+{
+ if(!system)
+ return false;
+ return (t + lifeSpan) > (system->m_timeInt/1000.0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h
new file mode 100644
index 0000000000..45b4e164f1
--- /dev/null
+++ b/src/declarative/particles/qsgparticlesystem_p.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLESYSTEM_H
+#define PARTICLESYSTEM_H
+
+#include <QSGItem>
+#include <QElapsedTimer>
+#include <QVector>
+#include <QHash>
+#include <QPointer>
+#include <QSignalMapper>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGParticleAffector;
+class QSGParticleEmitter;
+class QSGParticlePainter;
+class QSGParticleData;
+
+
+class QSGParticleGroupData{
+public:
+ QSGParticleGroupData():size(0),nextIdx(0)
+ {}
+ int size;
+ int nextIdx;
+ QSet<QSGParticlePainter*> painters;
+ QVector<QSGParticleData*> data;
+};
+
+class QSGParticleSystem : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
+ Q_PROPERTY(bool overwrite READ overwrite WRITE setOverwrite NOTIFY overwriteChanged)//XXX: Should just be an implementation detail, but I can't decide which way
+ /* The problem is that it ought to be false (usually) for stasis effects like model particles,
+ but it ought to be true (usually) for burst effects where you want it to burst, and forget the old stuff
+ Ideally burst never overflows? But that leads to crappy behaviour from crappy users...
+ */
+
+public:
+ explicit QSGParticleSystem(QSGItem *parent = 0);
+
+bool isRunning() const
+{
+ return m_running;
+}
+
+int startTime() const
+{
+ return m_startTime;
+}
+
+int count(){ return m_particle_count; }
+
+signals:
+
+void systemInitialized();
+void runningChanged(bool arg);
+
+void startTimeChanged(int arg);
+
+
+void overwriteChanged(bool arg);
+
+public slots:
+void reset();
+void setRunning(bool arg);
+
+
+void setStartTime(int arg)
+{
+ m_startTime = arg;
+}
+
+void setOverwrite(bool arg)
+{
+ if (m_overwrite != arg) {
+ m_overwrite = arg;
+emit overwriteChanged(arg);
+}
+}
+
+void fastForward(int ms)
+{
+ m_startTime += ms;
+}
+
+protected:
+ void componentComplete();
+
+private slots:
+ void emittersChanged();
+ void loadPainter(QObject* p);
+public://but only really for related class usage. Perhaps we should all be friends?
+ void emitParticle(QSGParticleData* p);
+ QSGParticleData* newDatum(int groupId);
+ qint64 systemSync(QSGParticlePainter* p);
+ QElapsedTimer m_timestamp;
+ QSet<QSGParticleData*> m_needsReset;
+ QHash<QString, int> m_groupIds;
+ QHash<int, QSGParticleGroupData*> m_groupData;
+ qint64 m_timeInt;
+ bool m_initialized;
+
+ void registerParticlePainter(QSGParticlePainter* p);
+ void registerParticleEmitter(QSGParticleEmitter* e);
+ void registerParticleAffector(QSGParticleAffector* a);
+ bool overwrite() const
+ {
+ return m_overwrite;
+ }
+
+ int m_particle_count;
+private:
+ void initializeSystem();
+ bool m_running;
+ QList<QPointer<QSGParticleEmitter> > m_emitters;
+ QList<QPointer<QSGParticleAffector> > m_affectors;
+ QList<QPointer<QSGParticlePainter> > m_particlePainters;
+ QList<QPointer<QSGParticlePainter> > m_syncList;
+ qint64 m_startTime;
+ int m_nextGroupId;
+ bool m_overwrite;
+ bool m_componentComplete;
+
+ QSignalMapper m_painterMapper;
+ QSignalMapper m_emitterMapper;
+};
+
+struct Color4ub {
+ uchar r;
+ uchar g;
+ uchar b;
+ uchar a;
+};
+
+class QSGParticleData{
+public:
+ //TODO: QObject like memory management (without the cost, just attached to system)
+ QSGParticleData();
+
+ //Convenience functions for working backwards, because parameters are from the start of particle life
+ //If setting multiple parameters at once, doing the conversion yourself will be faster.
+
+ //sets the x accleration without affecting the instantaneous x velocity or position
+ void setInstantaneousAX(qreal ax);
+ //sets the x velocity without affecting the instantaneous x postion
+ void setInstantaneousSX(qreal vx);
+ //sets the instantaneous x postion
+ void setInstantaneousX(qreal x);
+ //sets the y accleration without affecting the instantaneous y velocity or position
+ void setInstantaneousAY(qreal ay);
+ //sets the y velocity without affecting the instantaneous y postion
+ void setInstantaneousSY(qreal vy);
+ //sets the instantaneous Y postion
+ void setInstantaneousY(qreal y);
+
+ //TODO: Slight caching?
+ qreal curX() const;
+ qreal curSX() const;
+ qreal curY() const;
+ qreal curSY() const;
+
+ int group;
+ QSGParticleEmitter* e;//### Needed?
+ QSGParticleSystem* system;
+ int index;
+
+ //General Position Stuff
+ float x;
+ float y;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+
+ //Other stuff, now universally shared
+ Color4ub color;
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ float rotation;
+ float rotationSpeed;
+ float autoRotate;//Assume that GPUs prefer floats to bools
+ float animIdx;
+ float frameDuration;
+ float frameCount;
+ float animT;
+ float r;
+ QSGItem* delegate;
+ int modelIndex;
+
+ void debugDump();
+ bool stillAlive();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLESYSTEM_H
+
+
diff --git a/src/declarative/particles/qsgpointattractor.cpp b/src/declarative/particles/qsgpointattractor.cpp
new file mode 100644
index 0000000000..6f57ecaa36
--- /dev/null
+++ b/src/declarative/particles/qsgpointattractor.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpointattractor_p.h"
+#include <cmath>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+QSGPointAttractorAffector::QSGPointAttractorAffector(QSGItem *parent) :
+ QSGParticleAffector(parent), m_strength(0.0), m_x(0), m_y(0)
+ , m_physics(Velocity), m_proportionalToDistance(Linear)
+{
+}
+
+bool QSGPointAttractorAffector::affectParticle(QSGParticleData *d, qreal dt)
+{
+ if(m_strength == 0.0)
+ return false;
+ qreal dx = m_y - d->curX();
+ qreal dy = m_x - d->curY();
+ qreal r = sqrt((dx*dx) + (dy*dy));
+ qreal theta = atan2(dy,dx);
+ qreal ds = 0;
+ switch(m_proportionalToDistance){
+ case Quadratic:
+ ds = (m_strength / qMax<qreal>(1.,r*r)) * dt;
+ break;
+ case Linear://also default
+ default:
+ ds = (m_strength / qMax<qreal>(1.,r)) * dt;
+ }
+ dx = ds * cos(theta);
+ dy = ds * sin(theta);
+ switch(m_physics){
+ case Position:
+ d->x = (d->x + dx);
+ d->y = (d->y + dy);
+ break;
+ case Acceleration:
+ d->setInstantaneousAX(d->ax + dx);
+ d->setInstantaneousAY(d->ay + dy);
+ break;
+ case Velocity: //also default
+ default:
+ d->setInstantaneousSX(d->sx + dx);
+ d->setInstantaneousSY(d->sy + dy);
+ }
+
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgpointattractor_p.h b/src/declarative/particles/qsgpointattractor_p.h
new file mode 100644
index 0000000000..3ca29dfa96
--- /dev/null
+++ b/src/declarative/particles/qsgpointattractor_p.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ATTRACTORAFFECTOR_H
+#define ATTRACTORAFFECTOR_H
+#include "qsgparticleaffector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGPointAttractorAffector : public QSGParticleAffector
+{
+ Q_OBJECT
+ //Like Gravitational singularity, but linear to distance instead of quadratic
+ //And affects ds/dt, not da/dt
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(PhysicsAffects physics READ physics WRITE setPhysics NOTIFY physicsChanged)
+ Q_PROPERTY(Proportion proportionalToDistance READ proportionalToDistance WRITE setProportionalToDistance NOTIFY proportionalToDistanceChanged)
+ Q_ENUMS(PhysicsAffects)
+ Q_ENUMS(Proportion)
+
+public:
+ enum Proportion{
+ Linear,
+ Quadratic
+ };
+
+ enum PhysicsAffects {
+ Position,
+ Velocity,
+ Acceleration
+ };
+
+ explicit QSGPointAttractorAffector(QSGItem *parent = 0);
+
+ qreal strength() const
+ {
+ return m_strength;
+ }
+
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+ PhysicsAffects physics() const
+ {
+ return m_physics;
+ }
+
+ Proportion proportionalToDistance() const
+ {
+ return m_proportionalToDistance;
+ }
+
+signals:
+
+ void strengthChanged(qreal arg);
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+ void physicsChanged(PhysicsAffects arg);
+
+ void proportionalToDistanceChanged(Proportion arg);
+
+public slots:
+void setStrength(qreal arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setX(qreal arg)
+{
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+}
+
+void setY(qreal arg)
+{
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+}
+void setPhysics(PhysicsAffects arg)
+{
+ if (m_physics != arg) {
+ m_physics = arg;
+ emit physicsChanged(arg);
+ }
+}
+
+void setProportionalToDistance(Proportion arg)
+{
+ if (m_proportionalToDistance != arg) {
+ m_proportionalToDistance = arg;
+ emit proportionalToDistanceChanged(arg);
+ }
+}
+
+protected:
+ virtual bool affectParticle(QSGParticleData *d, qreal dt);
+private:
+qreal m_strength;
+qreal m_x;
+qreal m_y;
+PhysicsAffects m_physics;
+Proportion m_proportionalToDistance;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ATTRACTORAFFECTOR_H
diff --git a/src/declarative/particles/qsgpointdirection.cpp b/src/declarative/particles/qsgpointdirection.cpp
new file mode 100644
index 0000000000..c3c4f1c5de
--- /dev/null
+++ b/src/declarative/particles/qsgpointdirection.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpointdirection_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGPointDirection::QSGPointDirection(QObject *parent) :
+ QSGStochasticDirection(parent)
+ , m_x(0)
+ , m_y(0)
+ , m_xVariation(0)
+ , m_yVariation(0)
+{
+}
+
+const QPointF &QSGPointDirection::sample(const QPointF &)
+{
+ m_ret.setX(m_x - m_xVariation + rand() / float(RAND_MAX) * m_xVariation * 2);
+ m_ret.setY(m_y - m_yVariation + rand() / float(RAND_MAX) * m_yVariation * 2);
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgpointdirection_p.h b/src/declarative/particles/qsgpointdirection_p.h
new file mode 100644
index 0000000000..5e5b052744
--- /dev/null
+++ b/src/declarative/particles/qsgpointdirection_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef POINTVECTOR_H
+#define POINTVECTOR_H
+#include "qsgstochasticdirection_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGPointDirection : public QSGStochasticDirection
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(qreal xVariation READ xVariation WRITE setXVariation NOTIFY xVariationChanged)
+ Q_PROPERTY(qreal yVariation READ yVariation WRITE setYVariation NOTIFY yVariationChanged)
+public:
+ explicit QSGPointDirection(QObject *parent = 0);
+ virtual const QPointF &sample(const QPointF &from);
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+ qreal xVariation() const
+ {
+ return m_xVariation;
+ }
+
+ qreal yVariation() const
+ {
+ return m_yVariation;
+ }
+
+signals:
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+ void xVariationChanged(qreal arg);
+
+ void yVariationChanged(qreal arg);
+
+public slots:
+ void setX(qreal arg)
+ {
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+ }
+
+ void setY(qreal arg)
+ {
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+ }
+
+ void setXVariation(qreal arg)
+ {
+ if (m_xVariation != arg) {
+ m_xVariation = arg;
+ emit xVariationChanged(arg);
+ }
+ }
+
+ void setYVariation(qreal arg)
+ {
+ if (m_yVariation != arg) {
+ m_yVariation = arg;
+ emit yVariationChanged(arg);
+ }
+ }
+
+private:
+
+ qreal m_x;
+ qreal m_y;
+ qreal m_xVariation;
+ qreal m_yVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // POINTVECTOR_H
diff --git a/src/declarative/particles/qsgspritegoal.cpp b/src/declarative/particles/qsgspritegoal.cpp
new file mode 100644
index 0000000000..c97bfd1f26
--- /dev/null
+++ b/src/declarative/particles/qsgspritegoal.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgspritegoal_p.h"
+#include "private/qsgspriteengine_p.h"
+#include "private/qsgsprite_p.h"
+#include "qsgimageparticle_p.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QSGSpriteGoalAffector::QSGSpriteGoalAffector(QSGItem *parent) :
+ QSGParticleAffector(parent), m_goalIdx(-1), m_jump(false)
+{
+}
+
+void QSGSpriteGoalAffector::updateStateIndex(QSGSpriteEngine* e)
+{
+ m_lastEngine = e;
+ for(int i=0; i<e->stateCount(); i++){
+ if(e->state(i)->name() == m_goalState){
+ m_goalIdx = i;
+ return;
+ }
+ }
+ m_goalIdx = -1;//Can't find it
+}
+
+void QSGSpriteGoalAffector::setGoalState(QString arg)
+{
+ if (m_goalState != arg) {
+ m_goalState = arg;
+ emit goalStateChanged(arg);
+ if(m_goalState.isEmpty())
+ m_goalIdx = -1;
+ else
+ m_goalIdx = -2;
+ }
+}
+
+bool QSGSpriteGoalAffector::affectParticle(QSGParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ //TODO: Affect all engines
+ QSGSpriteEngine *engine = 0;
+ foreach(QSGParticlePainter *p, m_system->m_groupData[d->group]->painters)
+ if(qobject_cast<QSGImageParticle*>(p))
+ engine = qobject_cast<QSGImageParticle*>(p)->spriteEngine();
+ if(!engine)
+ return false;
+
+ if(m_goalIdx == -2 || engine != m_lastEngine)
+ updateStateIndex(engine);
+ if(engine->spriteState(d->index) != m_goalIdx){
+ engine->setGoal(m_goalIdx, d->index, m_jump);
+ emit affected(QPointF(d->curX(), d->curY()));//###Expensive if unconnected? Move to Affector?
+ return true; //Doesn't affect particle data, but necessary for onceOff
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgspritegoal_p.h b/src/declarative/particles/qsgspritegoal_p.h
new file mode 100644
index 0000000000..28fb2939e6
--- /dev/null
+++ b/src/declarative/particles/qsgspritegoal_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEGOALAFFECTOR_H
+#define SPRITEGOALAFFECTOR_H
+#include "qsgparticleaffector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGSpriteEngine;
+
+class QSGSpriteGoalAffector : public QSGParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged)
+ Q_PROPERTY(bool jump READ jump WRITE setJump NOTIFY jumpChanged)
+public:
+ explicit QSGSpriteGoalAffector(QSGItem *parent = 0);
+
+ QString goalState() const
+ {
+ return m_goalState;
+ }
+
+ bool jump() const
+ {
+ return m_jump;
+ }
+protected:
+ virtual bool affectParticle(QSGParticleData *d, qreal dt);
+signals:
+
+ void goalStateChanged(QString arg);
+
+ void jumpChanged(bool arg);
+
+ void affected(const QPointF &pos);
+public slots:
+
+void setGoalState(QString arg);
+
+void setJump(bool arg)
+{
+ if (m_jump != arg) {
+ m_jump = arg;
+ emit jumpChanged(arg);
+ }
+}
+
+private:
+ void updateStateIndex(QSGSpriteEngine* e);
+ QString m_goalState;
+ int m_goalIdx;
+ QSGSpriteEngine* m_lastEngine;
+ bool m_jump;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEGOALAFFECTOR_H
diff --git a/src/declarative/particles/qsgstochasticdirection.cpp b/src/declarative/particles/qsgstochasticdirection.cpp
new file mode 100644
index 0000000000..3673b9c7a7
--- /dev/null
+++ b/src/declarative/particles/qsgstochasticdirection.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgstochasticdirection_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGStochasticDirection::QSGStochasticDirection(QObject *parent) :
+ QObject(parent)
+{
+}
+
+const QPointF &QSGStochasticDirection::sample(const QPointF &from)
+{
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgstochasticdirection_p.h b/src/declarative/particles/qsgstochasticdirection_p.h
new file mode 100644
index 0000000000..da3a4302b1
--- /dev/null
+++ b/src/declarative/particles/qsgstochasticdirection_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VARYINGVECTOR_H
+#define VARYINGVECTOR_H
+
+#include <QObject>
+#include <QPointF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGStochasticDirection : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QSGStochasticDirection(QObject *parent = 0);
+
+ virtual const QPointF &sample(const QPointF &from);
+signals:
+
+public slots:
+
+protected:
+ QPointF m_ret;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // VARYINGVECTOR_H
diff --git a/src/declarative/particles/qsgtargeteddirection.cpp b/src/declarative/particles/qsgtargeteddirection.cpp
new file mode 100644
index 0000000000..9f1a868512
--- /dev/null
+++ b/src/declarative/particles/qsgtargeteddirection.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtargeteddirection_p.h"
+#include "qsgparticleemitter_p.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+QSGTargetedDirection::QSGTargetedDirection(QObject *parent) :
+ QSGStochasticDirection(parent)
+ , m_targetX(0)
+ , m_targetY(0)
+ , m_targetVariation(0)
+ , m_proportionalMagnitude(false)
+ , m_magnitude(0)
+ , m_magnitudeVariation(0)
+ , m_targetItem(0)
+{
+}
+
+const QPointF &QSGTargetedDirection::sample(const QPointF &from)
+{
+ //###This approach loses interpolating the last position of the target (like we could with the emitter) is it worthwhile?
+ qreal targetX;
+ qreal targetY;
+ if(m_targetItem){
+ QSGParticleEmitter* parentEmitter = qobject_cast<QSGParticleEmitter*>(parent());
+ targetX = m_targetItem->width()/2;
+ targetY = m_targetItem->height()/2;
+ if(!parentEmitter){
+ qWarning() << "Directed vector is not a child of the emitter. Mapping of target item coordinates may fail.";
+ targetX += m_targetItem->x();
+ targetY += m_targetItem->y();
+ }else{
+ m_ret = parentEmitter->mapFromItem(m_targetItem, QPointF(targetX, targetY));
+ targetX = m_ret.x();
+ targetY = m_ret.y();
+ }
+ }else{
+ targetX = m_targetX;
+ targetY = m_targetY;
+ }
+ targetX += 0 - from.x() - m_targetVariation + rand()/(float)RAND_MAX * m_targetVariation*2;
+ targetY += 0 - from.y() - m_targetVariation + rand()/(float)RAND_MAX * m_targetVariation*2;
+ qreal theta = atan2(targetY, targetX);
+ qreal mag = m_magnitude + rand()/(float)RAND_MAX * m_magnitudeVariation * 2 - m_magnitudeVariation;
+ if(m_proportionalMagnitude)
+ mag *= sqrt(targetX * targetX + targetY * targetY);
+ m_ret.setX(mag * cos(theta));
+ m_ret.setY(mag * sin(theta));
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgtargeteddirection_p.h b/src/declarative/particles/qsgtargeteddirection_p.h
new file mode 100644
index 0000000000..4010505858
--- /dev/null
+++ b/src/declarative/particles/qsgtargeteddirection_p.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTEDVECTOR_H
+#define DIRECTEDVECTOR_H
+#include "qsgstochasticdirection_p.h"
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class QSGTargetedDirection : public QSGStochasticDirection
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal targetX READ targetX WRITE setTargetX NOTIFY targetXChanged)
+ Q_PROPERTY(qreal targetY READ targetY WRITE setTargetY NOTIFY targetYChanged)
+ //If targetItem is set, X/Y are ignored. Aims at middle of item, use variation for variation
+ Q_PROPERTY(QSGItem* targetItem READ targetItem WRITE setTargetItem NOTIFY targetItemChanged)
+
+ Q_PROPERTY(qreal targetVariation READ targetVariation WRITE setTargetVariation NOTIFY targetVariationChanged)
+
+ Q_PROPERTY(bool proportionalMagnitude READ proportionalMagnitude WRITE setProportionalMagnitude NOTIFY proprotionalMagnitudeChanged)
+ Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged)
+ Q_PROPERTY(qreal magnitudeVariation READ magnitudeVariation WRITE setMagnitudeVariation NOTIFY magnitudeVariationChanged)
+
+public:
+ explicit QSGTargetedDirection(QObject *parent = 0);
+ virtual const QPointF &sample(const QPointF &from);
+
+ qreal targetX() const
+ {
+ return m_targetX;
+ }
+
+ qreal targetY() const
+ {
+ return m_targetY;
+ }
+
+ qreal targetVariation() const
+ {
+ return m_targetVariation;
+ }
+
+ qreal magnitude() const
+ {
+ return m_magnitude;
+ }
+
+ bool proportionalMagnitude() const
+ {
+ return m_proportionalMagnitude;
+ }
+
+ qreal magnitudeVariation() const
+ {
+ return m_magnitudeVariation;
+ }
+
+ QSGItem* targetItem() const
+ {
+ return m_targetItem;
+ }
+
+signals:
+
+ void targetXChanged(qreal arg);
+
+ void targetYChanged(qreal arg);
+
+ void targetVariationChanged(qreal arg);
+
+ void magnitudeChanged(qreal arg);
+
+ void proprotionalMagnitudeChanged(bool arg);
+
+ void magnitudeVariationChanged(qreal arg);
+
+ void targetItemChanged(QSGItem* arg);
+
+public slots:
+ void setTargetX(qreal arg)
+ {
+ if (m_targetX != arg) {
+ m_targetX = arg;
+ emit targetXChanged(arg);
+ }
+ }
+
+ void setTargetY(qreal arg)
+ {
+ if (m_targetY != arg) {
+ m_targetY = arg;
+ emit targetYChanged(arg);
+ }
+ }
+
+ void setTargetVariation(qreal arg)
+ {
+ if (m_targetVariation != arg) {
+ m_targetVariation = arg;
+ emit targetVariationChanged(arg);
+ }
+ }
+
+ void setMagnitude(qreal arg)
+ {
+ if (m_magnitude != arg) {
+ m_magnitude = arg;
+ emit magnitudeChanged(arg);
+ }
+ }
+
+ void setProportionalMagnitude(bool arg)
+ {
+ if (m_proportionalMagnitude != arg) {
+ m_proportionalMagnitude = arg;
+ emit proprotionalMagnitudeChanged(arg);
+ }
+ }
+
+ void setMagnitudeVariation(qreal arg)
+ {
+ if (m_magnitudeVariation != arg) {
+ m_magnitudeVariation = arg;
+ emit magnitudeVariationChanged(arg);
+ }
+ }
+
+ void setTargetItem(QSGItem* arg)
+ {
+ if (m_targetItem != arg) {
+ m_targetItem = arg;
+ emit targetItemChanged(arg);
+ }
+ }
+
+private:
+ qreal m_targetX;
+ qreal m_targetY;
+ qreal m_targetVariation;
+ bool m_proportionalMagnitude;
+ qreal m_magnitude;
+ qreal m_magnitudeVariation;
+ QSGItem *m_targetItem;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // DIRECTEDVECTOR_H
diff --git a/src/declarative/particles/qsgturbulence.cpp b/src/declarative/particles/qsgturbulence.cpp
new file mode 100644
index 0000000000..bb46b99f0d
--- /dev/null
+++ b/src/declarative/particles/qsgturbulence.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgturbulence_p.h"
+#include "qsgparticlepainter_p.h"//TODO: Why was this needed again?
+#include <cmath>
+#include <cstdlib>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+
+QSGTurbulenceAffector::QSGTurbulenceAffector(QSGItem *parent) :
+ QSGParticleAffector(parent),
+ m_strength(10), m_lastT(0), m_frequency(64), m_gridSize(10), m_field(0), m_inited(false)
+{
+ //TODO: Update grid on size change
+}
+
+QSGTurbulenceAffector::~QSGTurbulenceAffector()
+{
+ if (m_field) {
+ for(int i=0; i<m_gridSize; i++)
+ free(m_field[i]);
+ free(m_field);
+ }
+}
+
+static qreal magnitude(qreal x, qreal y)
+{
+ return sqrt(x*x + y*y);
+}
+
+void QSGTurbulenceAffector::setSize(int arg)
+{
+ if (m_gridSize != arg) {
+ if(m_field){ //deallocate and then reallocate grid
+ for(int i=0; i<m_gridSize; i++)
+ free(m_field[i]);
+ free(m_field);
+ m_system = 0;
+ }
+ m_gridSize = arg;
+ emit sizeChanged(arg);
+ }
+}
+
+void QSGTurbulenceAffector::ensureInit()
+{
+ if(m_inited)
+ return;
+ m_inited = true;
+ m_field = (QPointF**)malloc(m_gridSize * sizeof(QPointF*));
+ for(int i=0; i<m_gridSize; i++)
+ m_field[i] = (QPointF*)malloc(m_gridSize * sizeof(QPointF));
+ for(int i=0; i<m_gridSize; i++)
+ for(int j=0; j<m_gridSize; j++)
+ m_field[i][j] = QPointF();
+ m_spacing = QPointF(width()/m_gridSize, height()/m_gridSize);
+ m_magSum = magnitude(m_spacing.x(), m_spacing.y())*2;
+}
+
+void QSGTurbulenceAffector::mapUpdate()
+{
+ QPoint pos(rand() % m_gridSize, rand() % m_gridSize);
+ QPointF vector(m_strength - (((qreal)rand() / RAND_MAX) * m_strength*2),
+ m_strength - (((qreal)rand() / RAND_MAX) * m_strength*2));
+ for(int i = 0; i < m_gridSize; i++){
+ for(int j = 0; j < m_gridSize; j++){
+ qreal dist = magnitude(i-pos.x(), j-pos.y());
+ m_field[i][j] += vector/(dist + 1);
+ if(magnitude(m_field[i][j].x(), m_field[i][j].y()) > m_strength){
+ //Speed limit
+ qreal theta = atan2(m_field[i][j].y(), m_field[i][j].x());
+ m_field[i][j].setX(m_strength * cos(theta));
+ m_field[i][j].setY(m_strength * sin(theta));
+ }
+ }
+ }
+}
+
+
+void QSGTurbulenceAffector::affectSystem(qreal dt)
+{
+ if(!m_system || !m_active)
+ return;
+ ensureInit();
+ qreal period = 1.0/m_frequency;
+ qreal time = m_system->m_timeInt / 1000.0;
+ while( m_lastT < time ){
+ mapUpdate();
+ m_lastT += period;
+ }
+
+ foreach(QSGParticleGroupData *gd, m_system->m_groupData){
+ if(!activeGroup(m_system->m_groupData.key(gd)))//TODO: Surely this can be done better
+ return;
+ foreach(QSGParticleData *d, gd->data){
+ if(!d || !activeGroup(d->group))
+ return;
+ qreal fx = 0.0;
+ qreal fy = 0.0;
+ QPointF pos = QPointF(d->curX() - x(), d->curY() - y());//TODO: Offset
+ QPointF nodePos = QPointF(pos.x() / m_spacing.x(), pos.y() / m_spacing.y());
+ QSet<QPair<int, int> > nodes;
+ nodes << qMakePair((int)ceil(nodePos.x()), (int)ceil(nodePos.y()));
+ nodes << qMakePair((int)ceil(nodePos.x()), (int)floor(nodePos.y()));
+ nodes << qMakePair((int)floor(nodePos.x()), (int)ceil(nodePos.y()));
+ nodes << qMakePair((int)floor(nodePos.x()), (int)floor(nodePos.y()));
+ typedef QPair<int, int> intPair;
+ foreach(const intPair &p, nodes){
+ if(!QRect(0,0,m_gridSize-1,m_gridSize-1).contains(QPoint(p.first, p.second)))
+ continue;
+ qreal dist = magnitude(pos.x() - p.first*m_spacing.x(), pos.y() - p.second*m_spacing.y());//TODO: Mathematically valid
+ fx += m_field[p.first][p.second].x() * ((m_magSum - dist)/m_magSum);//Proportionally weight nodes
+ fy += m_field[p.first][p.second].y() * ((m_magSum - dist)/m_magSum);
+ }
+ if(fx || fy){
+ d->setInstantaneousSX(d->curSX()+ fx * dt);
+ d->setInstantaneousSY(d->curSY()+ fy * dt);
+ m_system->m_needsReset << d;
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgturbulence_p.h b/src/declarative/particles/qsgturbulence_p.h
new file mode 100644
index 0000000000..29483fbc70
--- /dev/null
+++ b/src/declarative/particles/qsgturbulence_p.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TURBULENCEAFFECTOR_H
+#define TURBULENCEAFFECTOR_H
+#include "qsgparticleaffector_p.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class QSGParticlePainter;
+
+class QSGTurbulenceAffector : public QSGParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(int strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(int frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged)
+ Q_PROPERTY(int gridSize READ size WRITE setSize NOTIFY sizeChanged)
+public:
+ explicit QSGTurbulenceAffector(QSGItem *parent = 0);
+ ~QSGTurbulenceAffector();
+ virtual void affectSystem(qreal dt);
+
+ int strength() const
+ {
+ return m_strength;
+ }
+
+ int frequency() const
+ {
+ return m_frequency;
+ }
+
+ int size() const
+ {
+ return m_gridSize;
+ }
+
+signals:
+
+ void strengthChanged(int arg);
+
+ void frequencyChanged(int arg);
+
+ void sizeChanged(int arg);
+
+public slots:
+
+void setStrength(int arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setFrequency(int arg)
+{
+ if (m_frequency != arg) {
+ m_frequency = arg;
+ emit frequencyChanged(arg);
+ }
+}
+
+void setSize(int arg);
+
+private:
+ void ensureInit();
+ void mapUpdate();
+ int m_strength;
+ qreal m_lastT;
+ int m_frequency;
+ int m_gridSize;
+ QPointF** m_field;
+ QPointF m_spacing;
+ qreal m_magSum;
+ bool m_inited;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TURBULENCEAFFECTOR_H
diff --git a/src/declarative/particles/qsgwander.cpp b/src/declarative/particles/qsgwander.cpp
new file mode 100644
index 0000000000..26bea4ee04
--- /dev/null
+++ b/src/declarative/particles/qsgwander.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgwander_p.h"
+#include "qsgparticlesystem_p.h"//for ParticlesVertices
+QT_BEGIN_NAMESPACE
+
+QSGWanderAffector::QSGWanderAffector(QSGItem *parent) :
+ QSGParticleAffector(parent), m_xVariance(0), m_yVariance(0), m_pace(0)
+ , m_physics(Velocity)
+{
+ m_needsReset = true;
+}
+
+QSGWanderAffector::~QSGWanderAffector()
+{
+ for(QHash<int, WanderData*>::const_iterator iter=m_wanderData.constBegin();
+ iter != m_wanderData.constEnd(); iter++)
+ delete (*iter);
+}
+
+WanderData* QSGWanderAffector::getData(int idx)
+{
+ if(m_wanderData.contains(idx))
+ return m_wanderData[idx];
+ WanderData* d = new WanderData;
+ d->x_vel = 0;
+ d->y_vel = 0;
+ d->x_peak = m_xVariance;
+ d->y_peak = m_yVariance;
+ d->x_var = m_pace * qreal(qrand()) / RAND_MAX;
+ d->y_var = m_pace * qreal(qrand()) / RAND_MAX;
+
+ m_wanderData.insert(idx, d);
+ return d;
+}
+
+void QSGWanderAffector::reset(int systemIdx)
+{
+ if(m_wanderData.contains(systemIdx))
+ delete m_wanderData[systemIdx];
+ m_wanderData.remove(systemIdx);
+}
+
+bool QSGWanderAffector::affectParticle(QSGParticleData* data, qreal dt)
+{
+ /*TODO: Add a mode which does basically this - picking a direction, going in it (random speed) and then going back
+ WanderData* d = getData(data->systemIndex);
+ if (m_xVariance != 0.) {
+ if ((d->x_vel > d->x_peak && d->x_var > 0.0) || (d->x_vel < -d->x_peak && d->x_var < 0.0)) {
+ d->x_var = -d->x_var;
+ d->x_peak = m_xVariance + m_xVariance * qreal(qrand()) / RAND_MAX;
+ }
+ d->x_vel += d->x_var * dt;
+ }
+ qreal dx = dt * d->x_vel;
+
+ if (m_yVariance != 0.) {
+ if ((d->y_vel > d->y_peak && d->y_var > 0.0) || (d->y_vel < -d->y_peak && d->y_var < 0.0)) {
+ d->y_var = -d->y_var;
+ d->y_peak = m_yVariance + m_yVariance * qreal(qrand()) / RAND_MAX;
+ }
+ d->y_vel += d->y_var * dt;
+ }
+ qreal dy = dt * d->x_vel;
+
+ //### Should we be amending vel instead?
+ ParticleVertex* p = &(data->pv);
+ p->x += dx;
+
+ p->y += dy;
+ return true;
+ */
+ qreal dx = dt * m_pace * (2 * qreal(qrand())/RAND_MAX - 1);
+ qreal dy = dt * m_pace * (2 * qreal(qrand())/RAND_MAX - 1);
+ qreal newX, newY;
+ switch(m_physics){
+ case Position:
+ newX = data->curX() + dx;
+ if(m_xVariance > qAbs(newX) )
+ data->x += dx;
+ newY = data->curY() + dy;
+ if(m_yVariance > qAbs(newY) )
+ data->y += dy;
+ break;
+ default:
+ case Velocity:
+ newX = data->curSX() + dx;
+ if(m_xVariance > qAbs(newX) )
+ data->setInstantaneousSX(newX);
+ newY = data->curSY() + dy;
+ if(m_yVariance > qAbs(newY) )
+ data->setInstantaneousSY(newY);
+ break;
+ case Acceleration:
+ newX = data->ax + dx;
+ if(m_xVariance > qAbs(newX) )
+ data->setInstantaneousAX(newX);
+ newY = data->ay + dy;
+ if(m_yVariance > qAbs(newY) )
+ data->setInstantaneousAY(newY);
+ break;
+ }
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/particles/qsgwander_p.h b/src/declarative/particles/qsgwander_p.h
new file mode 100644
index 0000000000..783efc8636
--- /dev/null
+++ b/src/declarative/particles/qsgwander_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Declarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WANDERAFFECTOR_H
+#define WANDERAFFECTOR_H
+#include <QHash>
+#include "qsgparticleaffector_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+struct WanderData{
+ qreal x_vel;
+ qreal y_vel;
+ qreal x_peak;
+ qreal x_var;
+ qreal y_peak;
+ qreal y_var;
+};
+
+class QSGWanderAffector : public QSGParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal pace READ pace WRITE setPace NOTIFY paceChanged)
+ Q_PROPERTY(qreal xVariance READ xVariance WRITE setXVariance NOTIFY xVarianceChanged)
+ Q_PROPERTY(qreal yVariance READ yVariance WRITE setYVariance NOTIFY yVarianceChanged)
+ Q_PROPERTY(PhysicsAffects physics READ physics WRITE setPhysics NOTIFY physicsChanged)
+ Q_ENUMS(PhysicsAffects)
+
+public:
+ enum PhysicsAffects {
+ Position,
+ Velocity,
+ Acceleration
+ };
+
+ explicit QSGWanderAffector(QSGItem *parent = 0);
+ ~QSGWanderAffector();
+ virtual void reset(int systemIdx);
+
+ qreal xVariance() const
+ {
+ return m_xVariance;
+ }
+
+ qreal yVariance() const
+ {
+ return m_yVariance;
+ }
+
+ qreal pace() const
+ {
+ return m_pace;
+ }
+
+ PhysicsAffects physics() const
+ {
+ return m_physics;
+ }
+
+protected:
+ virtual bool affectParticle(QSGParticleData *d, qreal dt);
+signals:
+
+ void xVarianceChanged(qreal arg);
+
+ void yVarianceChanged(qreal arg);
+
+ void paceChanged(qreal arg);
+
+
+ void physicsChanged(PhysicsAffects arg);
+
+public slots:
+void setXVariance(qreal arg)
+{
+ if (m_xVariance != arg) {
+ m_xVariance = arg;
+ emit xVarianceChanged(arg);
+ }
+}
+
+void setYVariance(qreal arg)
+{
+ if (m_yVariance != arg) {
+ m_yVariance = arg;
+ emit yVarianceChanged(arg);
+ }
+}
+
+void setPace(qreal arg)
+{
+ if (m_pace != arg) {
+ m_pace = arg;
+ emit paceChanged(arg);
+ }
+}
+
+
+void setPhysics(PhysicsAffects arg)
+{
+ if (m_physics != arg) {
+ m_physics = arg;
+ emit physicsChanged(arg);
+ }
+}
+
+private:
+ WanderData* getData(int idx);
+ QHash<int, WanderData*> m_wanderData;
+ qreal m_xVariance;
+ qreal m_yVariance;
+ qreal m_pace;
+ PhysicsAffects m_physics;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // WANDERAFFECTOR_H