From 29993ff8e91715bdfbaf964c91e07a112f6d2a24 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 13 Sep 2011 09:39:11 +1000 Subject: [PATCH] Refactor SpriteEngine out of StochasticEngine Also add ParticleGroups which use only StochasticStates Simplistic change for now, just to focus the API for the particle system. ParticleGroup elements replace the particleStates property on the system, and the term "group" is now used more consistently. Change-Id: I6456f9c521b8166ccd94ea953275557bcfbf6423 Reviewed-on: http://codereview.qt-project.org/4699 Reviewed-by: Alan Alpert --- .../animation/basics/color-animation.qml | 4 +- examples/declarative/flickr/flickr.qml | 6 +- .../minehunt/MinehuntCore/Explosion.qml | 4 +- .../particles/allsmiles/smilefactory.qml | 10 +- .../particles/allsmiles/spriteparticles.qml | 8 +- .../declarative/particles/asteroid/asteroid.qml | 14 +- .../declarative/particles/asteroid/blackhole.qml | 16 +- .../declarative/particles/trails/combustion.qml | 116 ++++++------ .../declarative/particles/trails/fireballs.qml | 16 +- .../declarative/particles/trails/fireworks.qml | 62 +++--- examples/declarative/particles/trails/portal.qml | 6 +- .../declarative/particles/trails/turbulence.qml | 10 +- .../plasmapatrol/content/BlasterHardpoint.qml | 4 +- .../plasmapatrol/content/CannonHardpoint.qml | 4 +- .../declarative/plasmapatrol/content/Cruiser.qml | 6 +- .../declarative/plasmapatrol/content/Frigate.qml | 4 +- .../plasmapatrol/content/LaserHardpoint.qml | 4 +- .../plasmapatrol/content/PlasmaPatrolParticles.qml | 24 ++-- .../declarative/plasmapatrol/content/Sloop.qml | 2 +- examples/declarative/plasmapatrol/plasmapatrol.qml | 2 +- .../samegame/SamegameCore/BoomBlock.qml | 2 +- .../declarative/samegame/SamegameCore/GameArea.qml | 6 +- examples/declarative/snake/content/Cookie.qml | 4 +- examples/declarative/snake/content/Link.qml | 4 +- .../declarative/toys/dynamicscene/dynamicscene.qml | 4 +- src/declarative/items/qsgsprite.cpp | 27 +--- src/declarative/items/qsgsprite_p.h | 114 +----------- src/declarative/items/qsgspriteengine.cpp | 112 +++++++----- src/declarative/items/qsgspriteengine_p.h | 204 +++++++++++++++++--- src/declarative/items/qsgspriteimage.cpp | 2 +- src/declarative/particles/particles.pri | 6 +- src/declarative/particles/qsgcustomparticle.cpp | 2 +- src/declarative/particles/qsgimageparticle.cpp | 6 +- src/declarative/particles/qsgimageparticle_p.h | 4 +- src/declarative/particles/qsgitemparticle.cpp | 2 +- src/declarative/particles/qsgparticleaffector.cpp | 18 +- src/declarative/particles/qsgparticleaffector_p.h | 20 +- src/declarative/particles/qsgparticleemitter.cpp | 6 +- src/declarative/particles/qsgparticleemitter_p.h | 18 +- src/declarative/particles/qsgparticlegroup.cpp | 142 ++++++++++++++ src/declarative/particles/qsgparticlegroup_p.h | 107 ++++++++++ src/declarative/particles/qsgparticlepainter.cpp | 6 +- src/declarative/particles/qsgparticlepainter_p.h | 18 +- src/declarative/particles/qsgparticlesmodule.cpp | 2 + src/declarative/particles/qsgparticlesystem.cpp | 117 ++++++----- src/declarative/particles/qsgparticlesystem_p.h | 13 +- src/declarative/particles/qsgspritegoal.cpp | 12 +- src/declarative/particles/qsgspritegoal_p.h | 6 +- src/declarative/particles/qsgtrailemitter.cpp | 2 +- src/declarative/particles/qsgtrailemitter_p.h | 2 +- 50 files changed, 803 insertions(+), 507 deletions(-) create mode 100644 src/declarative/particles/qsgparticlegroup.cpp create mode 100644 src/declarative/particles/qsgparticlegroup_p.h diff --git a/examples/declarative/animation/basics/color-animation.qml b/examples/declarative/animation/basics/color-animation.qml index a83dbab..9e0f29c 100644 --- a/examples/declarative/animation/basics/color-animation.qml +++ b/examples/declarative/animation/basics/color-animation.qml @@ -86,7 +86,7 @@ Item { width: parent.width; height: parent.height/2 ImageParticle { source: "images/star.png" - particles: ["star"] + groups: ["star"] color: "#00333333" SequentialAnimation on opacity { loops: Animation.Infinite @@ -95,7 +95,7 @@ Item { } } Emitter { - particle: "star" + group: "star" anchors.fill: parent emitRate: parent.width / 50 lifeSpan: 5000 diff --git a/examples/declarative/flickr/flickr.qml b/examples/declarative/flickr/flickr.qml index 14e4fca..4397d0a 100644 --- a/examples/declarative/flickr/flickr.qml +++ b/examples/declarative/flickr/flickr.qml @@ -56,7 +56,7 @@ Item { id: bgParticles anchors.fill: parent ImageParticle { - particles: ["trail"] + groups: ["trail"] source: "content/images/particle.png" color: "#1A1A6F" alpha: 0.1 @@ -64,7 +64,7 @@ Item { blueVariation: 0.8 } Emitter { - particle: "drops" + group: "drops" width: parent.width emitRate: 0.5 lifeSpan: 20000 @@ -75,7 +75,7 @@ Item { } TrailEmitter { follow: "drops" - particle: "trail" + group: "trail" emitRatePerParticle: 18 size: 32 endSize: 0 diff --git a/examples/declarative/minehunt/MinehuntCore/Explosion.qml b/examples/declarative/minehunt/MinehuntCore/Explosion.qml index 225c19d..af98ad1 100644 --- a/examples/declarative/minehunt/MinehuntCore/Explosion.qml +++ b/examples/declarative/minehunt/MinehuntCore/Explosion.qml @@ -48,14 +48,14 @@ Item { width: 40 height: 40 ImageParticle { - particles: ["star"] + groups: ["star"] source: "file:MinehuntCore/pics/star.png" // TODO: Use qrc path once QTBUG-21129 is fixed } Emitter { id: particles emitting: false anchors.centerIn: parent - particle: "star" + group: "star" speed: AngledDirection { angleVariation: 360; magnitude: 150; magnitudeVariation: 50 } emitRate: 200 z: 100 diff --git a/examples/declarative/particles/allsmiles/smilefactory.qml b/examples/declarative/particles/allsmiles/smilefactory.qml index fe65149..4b01862 100644 --- a/examples/declarative/particles/allsmiles/smilefactory.qml +++ b/examples/declarative/particles/allsmiles/smilefactory.qml @@ -48,7 +48,7 @@ Rectangle{ ParticleSystem{id:sys} ImageParticle{ system: sys - particles: ["goingLeft", "goingRight"] + groups: ["goingLeft", "goingRight"] source: "content/singlesmile.png" rotation: 90 rotationSpeed: 90 @@ -56,7 +56,7 @@ Rectangle{ } ImageParticle{ system: sys - particles: ["goingDown"] + groups: ["goingDown"] source: "content/squarefacespriteXX.png" yVector: PointDirection{ y: 0.5; yVariation: 0.25; xVariation: 0.25; } rotation: 180 @@ -85,7 +85,7 @@ Rectangle{ y: 120 system: sys enabled: false - particle: "goingRight" + group: "goingRight" speed: PointDirection{ x: 100 } lifeSpan: 4000 emitRate: 2 @@ -97,7 +97,7 @@ Rectangle{ y: 240 system: sys enabled: false - particle: "goingLeft" + group: "goingLeft" speed: PointDirection{ x: -100 } lifeSpan: 4000 emitRate: 2 @@ -109,7 +109,7 @@ Rectangle{ y: 360 system: sys enabled: false - particle: "goingDown" + group: "goingDown" speed: PointDirection{ x: 100 } lifeSpan: 4000 emitRate: 2 diff --git a/examples/declarative/particles/allsmiles/spriteparticles.qml b/examples/declarative/particles/allsmiles/spriteparticles.qml index 705016e..0586dfd 100644 --- a/examples/declarative/particles/allsmiles/spriteparticles.qml +++ b/examples/declarative/particles/allsmiles/spriteparticles.qml @@ -47,7 +47,7 @@ Rectangle{ height: 400 ImageParticle{ id: test - particles: ["Test"] + groups: ["Test"] source: "content/particle.png" system: sys z: 2 @@ -57,7 +57,7 @@ Rectangle{ } ImageParticle{ id: single - particles: ["Face"] + groups: ["Face"] system: sys z: 2 anchors.fill: parent @@ -73,7 +73,7 @@ Rectangle{ } Emitter{ system: sys - particle: "Test" + group: "Test" anchors.fill: parent id: particles2 emitRate: 6000 @@ -83,7 +83,7 @@ Rectangle{ } Emitter{ system: sys - particle: "Face" + group: "Face" anchors.fill: parent id: particles emitRate: 60 diff --git a/examples/declarative/particles/asteroid/asteroid.qml b/examples/declarative/particles/asteroid/asteroid.qml index ea2fabd..6d55699 100644 --- a/examples/declarative/particles/asteroid/asteroid.qml +++ b/examples/declarative/particles/asteroid/asteroid.qml @@ -67,7 +67,7 @@ Item { } ImageParticle { system: sys - particles: ["starfield"] + groups: ["starfield"] source: "content/star.png" colorVariation: 0.3 color: "white" @@ -75,7 +75,7 @@ Item { Emitter { id: starField system: sys - particle: "starfield" + group: "starfield" emitRate: 80 lifeSpan: 2500 @@ -91,7 +91,7 @@ Item { } Emitter{ system: sys - particle: "meteor" + group: "meteor" emitRate: 12 lifeSpan: 5000 acceleration: PointDirection{ xVariation: 80; yVariation: 80; } @@ -101,7 +101,7 @@ Item { } ImageParticle{ system: sys - particles: ["meteor"] + groups: ["meteor"] sprites:[Sprite{ id: spinState name: "spinning" @@ -126,7 +126,7 @@ Item { ] } SpriteGoal{ - particles: ["meteor"] + groups: ["meteor"] system: sys goalState: "explode" jump: true @@ -170,7 +170,7 @@ Item { ImageParticle{ z:0 system: sys - particles: ["exhaust"] + groups: ["exhaust"] source: "content/particle4.png" color: "orange" @@ -193,7 +193,7 @@ Item { Emitter{ id: trailsNormal2 system: sys - particle: "exhaust" + group: "exhaust" emitRate: 300 lifeSpan: 500 diff --git a/examples/declarative/particles/asteroid/blackhole.qml b/examples/declarative/particles/asteroid/blackhole.qml index 7e8a7a9..00fca7e 100644 --- a/examples/declarative/particles/asteroid/blackhole.qml +++ b/examples/declarative/particles/asteroid/blackhole.qml @@ -66,7 +66,7 @@ Rectangle{ } Emitter{ - particle: "stars" + group: "stars" system: particles emitRate: 40 lifeSpan: 4000 @@ -77,7 +77,7 @@ Rectangle{ height: parent.height } Emitter{ - particle: "roids" + group: "roids" system: particles emitRate: 10 lifeSpan: 4000 @@ -93,7 +93,7 @@ Rectangle{ } ImageParticle{ id: stars - particles: ["stars"] + groups: ["stars"] system: particles source: "content/star.png" color: "white" @@ -102,7 +102,7 @@ Rectangle{ } ImageParticle{ id: roids - particles: ["roids"] + groups: ["roids"] system: particles sprites: Sprite{ id: spinState @@ -115,7 +115,7 @@ Rectangle{ } ImageParticle{ id: shot - particles: ["shot"] + groups: ["shot"] system: particles source: "content/star.png" @@ -124,7 +124,7 @@ Rectangle{ } ImageParticle{ id: engine - particles: ["engine"] + groups: ["engine"] system: particles source: "content/particle4.png" @@ -170,7 +170,7 @@ Rectangle{ drag.target: ship } Emitter{ - particle: "engine" + group: "engine" system: particles emitRate: 200 lifeSpan: 1000 @@ -182,7 +182,7 @@ Rectangle{ width: 20 } Emitter{ - particle: "shot" + group: "shot" system: particles emitRate: 32 lifeSpan: 2000 diff --git a/examples/declarative/particles/trails/combustion.qml b/examples/declarative/particles/trails/combustion.qml index e4a21e9..238dbe8 100644 --- a/examples/declarative/particles/trails/combustion.qml +++ b/examples/declarative/particles/trails/combustion.qml @@ -57,71 +57,67 @@ Rectangle { ParticleSystem{ id: particles anchors.fill: parent + ParticleGroup{ + name: "unlit" + duration: 1000 + to: {"lighting":1, "unlit":99} + ImageParticle{ + source: "content/particleA.png" + colorVariation: 0.1 + color: "#2060160f" + } + SpriteGoal{ + whenCollidingWith: ["lit"] + goalState: "lighting" + jump: true + systemStates: true + } + } + ParticleGroup{ + name: "lighting" + duration: 100 + to: {"lit":1} + } + ParticleGroup{ + name: "lit" + duration: 10000 + onEntered: score++; + TrailEmitter{ + id: fireballFlame + group: "flame" + emitRatePerParticle: 48 + lifeSpan: 200 + emitWidth: 8 + emitHeight: 8 - particleStates:[ - Sprite{ - name: "unlit" - duration: 1000 - to: {"lighting":1, "unlit":99} - ImageParticle{ - source: "content/particleA.png" - colorVariation: 0.1 - color: "#2060160f" - } - SpriteGoal{ - whenCollidingWith: ["lit"] - goalState: "lighting" - jump: true - systemStates: true - } - }, - Sprite{ - name: "lighting" - duration: 100 - to: {"lit":1} - }, - Sprite{ - name: "lit" - duration: 10000 - onEntered: score++; - TrailEmitter{ - id: fireballFlame - particle: "flame" - - emitRatePerParticle: 48 - lifeSpan: 200 - emitWidth: 8 - emitHeight: 8 - - size: 24 - sizeVariation: 8 - endSize: 4 - } + size: 24 + sizeVariation: 8 + endSize: 4 + } - TrailEmitter{ - id: fireballSmoke - particle: "smoke" + TrailEmitter{ + id: fireballSmoke + group: "smoke" - emitRatePerParticle: 120 - lifeSpan: 2000 - emitWidth: 16 - emitHeight: 16 + emitRatePerParticle: 120 + lifeSpan: 2000 + emitWidth: 16 + emitHeight: 16 - speed: PointDirection{yVariation: 16; xVariation: 16} - acceleration: PointDirection{y: -16} + speed: PointDirection{yVariation: 16; xVariation: 16} + acceleration: PointDirection{y: -16} - size: 24 - sizeVariation: 8 - endSize: 8 - } + size: 24 + sizeVariation: 8 + endSize: 8 } - ] + } ImageParticle{ id: smoke anchors.fill: parent - particles: ["smoke"] + groups: ["smoke"] source: "content/particle.png" colorVariation: 0 color: "#00111111" @@ -129,7 +125,7 @@ Rectangle { ImageParticle{ id: pilot anchors.fill: parent - particles: ["pilot"] + groups: ["pilot"] source: "content/particle.png" redVariation: 0.01 blueVariation: 0.4 @@ -138,7 +134,7 @@ Rectangle { ImageParticle{ id: flame anchors.fill: parent - particles: ["flame", "lit", "lighting"] + groups: ["flame", "lit", "lighting"] source: "content/particleA.png" colorVariation: 0.1 color: "#00ff400f" @@ -152,14 +148,14 @@ Rectangle { sizeVariation: 4 speed: PointDirection{x:120; xVariation: 80; yVariation: 50} acceleration: PointDirection{y:120} - particle: "unlit" + group: "unlit" } Emitter{ id: flamer x: 100 y: 300 - particle: "pilot" + group: "pilot" emitRate: 80 lifeSpan: 600 size: 24 @@ -167,7 +163,7 @@ Rectangle { endSize: 0 speed: PointDirection{ y:-100; yVariation: 4; xVariation: 4 } SpriteGoal{ - particles: ["unlit"] + groups: ["unlit"] goalState: "lit" jump: true systemStates: true @@ -181,7 +177,7 @@ Rectangle { } //Click to enflame SpriteGoal{//TODO: Aux emiiters in the state definition (which allows the occasional ball to spontaneously combust) - particles: ["unlit"] + groups: ["unlit"] goalState: "lighting" jump: true systemStates: true diff --git a/examples/declarative/particles/trails/fireballs.qml b/examples/declarative/particles/trails/fireballs.qml index 97a0c0a..c7c0420 100644 --- a/examples/declarative/particles/trails/fireballs.qml +++ b/examples/declarative/particles/trails/fireballs.qml @@ -55,7 +55,7 @@ Rectangle { ImageParticle{ id: fireball anchors.fill: parent - particles: ["E"] + groups: ["E"] system: particles source: "content/particleA.png" colorVariation: 0.2 @@ -66,7 +66,7 @@ Rectangle { id: smoke system: particles anchors.fill: parent - particles: ["A", "B"] + groups: ["A", "B"] source: "content/particle.png" colorVariation: 0 color: "#00111111" @@ -75,7 +75,7 @@ Rectangle { id: flame anchors.fill: parent system: particles - particles: ["C", "D"] + groups: ["C", "D"] source: "content/particle.png" colorVariation: 0.1 color: "#00ff400f" @@ -83,7 +83,7 @@ Rectangle { Emitter{ id: fire system: particles - particle: "C" + group: "C" y: parent.height width: parent.width @@ -100,7 +100,7 @@ Rectangle { } TrailEmitter{ id: fireSmoke - particle: "B" + group: "B" system: particles follow: "C" width: root.width @@ -120,7 +120,7 @@ Rectangle { id: fireballFlame anchors.fill: parent system: particles - particle: "D" + group: "D" follow: "E" emitRatePerParticle: 120 @@ -137,7 +137,7 @@ Rectangle { id: fireballSmoke anchors.fill: parent system: particles - particle: "A" + group: "A" follow: "E" emitRatePerParticle: 128 @@ -155,7 +155,7 @@ Rectangle { Emitter{ id: balls system: particles - particle: "E" + group: "E" y: parent.height width: parent.width diff --git a/examples/declarative/particles/trails/fireworks.qml b/examples/declarative/particles/trails/fireworks.qml index 437d9ee..6b370b3 100644 --- a/examples/declarative/particles/trails/fireworks.qml +++ b/examples/declarative/particles/trails/fireworks.qml @@ -48,36 +48,34 @@ Rectangle{ ParticleSystem{ anchors.fill: parent id: syssy - particleStates:[ - Sprite{ - name: "fire" - duration: 2000 - durationVariation: 2000 - to: {"splode":1} - }, - Sprite{ - name: "splode" - duration: 400 - to: {"dead":1} - TrailEmitter{ - particle: "works" - emitRatePerParticle: 100 - lifeSpan: 1000 - maximumEmitted: 1200 - size: 8 - speed: AngleDirection{angle: 270; angleVariation: 45; magnitude: 20; magnitudeVariation: 20;} - acceleration: PointDirection{y:100; yVariation: 20} - } - }, - Sprite{ - name: "dead" - duration: 1000 - Affector{ - once: true - onAffected: worksEmitter.burst(400,x,y) - } + ParticleGroup{ + name: "fire" + duration: 2000 + durationVariation: 2000 + to: {"splode":1} + } + ParticleGroup{ + name: "splode" + duration: 400 + to: {"dead":1} + TrailEmitter{ + group: "works" + emitRatePerParticle: 100 + lifeSpan: 1000 + maximumEmitted: 1200 + size: 8 + speed: AngleDirection{angle: 270; angleVariation: 45; magnitude: 20; magnitudeVariation: 20;} + acceleration: PointDirection{y:100; yVariation: 20} + } + } + ParticleGroup{ + name: "dead" + duration: 1000 + Affector{ + once: true + onAffected: worksEmitter.burst(400,x,y) } - ] + } Timer{ interval: 6000 running: true @@ -87,7 +85,7 @@ Rectangle{ } Emitter{ id: startingEmitter - particle: "fire" + group: "fire" width: parent.width y: parent.height enabled: false @@ -98,7 +96,7 @@ Rectangle{ } Emitter{ id: worksEmitter - particle: "works" + group: "works" enabled: false emitRate: 100 lifeSpan: 1600 @@ -111,7 +109,7 @@ Rectangle{ acceleration: PointDirection{y:100; yVariation: 20} } ImageParticle{ - particles: ["works", "fire", "splode"] + groups: ["works", "fire", "splode"] source: "content/particle.png" entryEffect: ImageParticle.Scale } diff --git a/examples/declarative/particles/trails/portal.qml b/examples/declarative/particles/trails/portal.qml index 85efd9a..adf620f 100644 --- a/examples/declarative/particles/trails/portal.qml +++ b/examples/declarative/particles/trails/portal.qml @@ -54,7 +54,7 @@ Rectangle{ id: particles } ImageParticle{ - particles: ["center","edge"] + groups: ["center","edge"] anchors.fill: parent system: particles source: "content/particle.png" @@ -63,7 +63,7 @@ Rectangle{ } Emitter{ anchors.fill: parent - particle: "center" + group: "center" system: particles emitRate: 200 lifeSpan: 2000 @@ -80,7 +80,7 @@ Rectangle{ } Emitter{ anchors.fill: parent - particle: "edge" + group: "edge" startTime: 2000 system: particles emitRate: 4000 diff --git a/examples/declarative/particles/trails/turbulence.qml b/examples/declarative/particles/trails/turbulence.qml index 104bb10..13eae16 100644 --- a/examples/declarative/particles/trails/turbulence.qml +++ b/examples/declarative/particles/trails/turbulence.qml @@ -71,14 +71,14 @@ Rectangle{ strength: 32 } ImageParticle{ - particles: ["smoke"] + groups: ["smoke"] system: ps source: "content/particle.png" color: "#11111111" colorVariation: 0 } ImageParticle{ - particles: ["flame"] + groups: ["flame"] system: ps source: "content/particle.png" color: "#11ff400f" @@ -87,7 +87,7 @@ Rectangle{ Emitter{ anchors.centerIn: parent system: ps - particle: "flame" + group: "flame" emitRate: 120 lifeSpan: 1200 @@ -102,7 +102,7 @@ Rectangle{ width: root.width height: root.height/2 - 20 system: ps - particle: "smoke" + group: "smoke" follow: "flame" emitRatePerParticle: 1 @@ -119,7 +119,7 @@ Rectangle{ width: root.width height: root.height/2 - 40 system: ps - particle: "smoke" + group: "smoke" follow: "flame" emitRatePerParticle: 4 diff --git a/examples/declarative/plasmapatrol/content/BlasterHardpoint.qml b/examples/declarative/plasmapatrol/content/BlasterHardpoint.qml index 384275f..3e751f4 100644 --- a/examples/declarative/plasmapatrol/content/BlasterHardpoint.qml +++ b/examples/declarative/plasmapatrol/content/BlasterHardpoint.qml @@ -55,7 +55,7 @@ Item { height: 24 Emitter{ id: visualization - particle: "blaster" + group: "blaster" system: container.system enabled: show anchors.fill: parent @@ -114,7 +114,7 @@ Item { } Emitter{ id: emitter - particle: "blaster" + group: "blaster" enabled: false system: container.system anchors.centerIn: parent diff --git a/examples/declarative/plasmapatrol/content/CannonHardpoint.qml b/examples/declarative/plasmapatrol/content/CannonHardpoint.qml index b2c7aca..dc15f0c 100644 --- a/examples/declarative/plasmapatrol/content/CannonHardpoint.qml +++ b/examples/declarative/plasmapatrol/content/CannonHardpoint.qml @@ -51,7 +51,7 @@ Item { height: 24 Emitter{ id: visualization - particle: "cannon" + group: "cannon" enabled: container.show system: container.system anchors.centerIn: parent @@ -80,7 +80,7 @@ Item { } Emitter{ id: emitter - particle: "cannon" + group: "cannon" enabled: false system: container.system anchors.centerIn: parent diff --git a/examples/declarative/plasmapatrol/content/Cruiser.qml b/examples/declarative/plasmapatrol/content/Cruiser.qml index b0d2002..a4983fc 100644 --- a/examples/declarative/plasmapatrol/content/Cruiser.qml +++ b/examples/declarative/plasmapatrol/content/Cruiser.qml @@ -58,7 +58,7 @@ Item { //TODO: Cooler would be an 'orbiting' affector //TODO: On the subject, opacity and size should be grouped type 'overLife' if we can cram that in the particles system: container.system - particle: container.shipParticle + group: container.shipParticle anchors.centerIn: parent width: 64 height: 64 @@ -76,7 +76,7 @@ Item { } Emitter{ system: container.system - particle: "cruiserArmor" + group: "cruiserArmor" anchors.fill: parent shape: EllipseShape{ fill: false } enabled: hp>0 @@ -92,7 +92,7 @@ Item { system: container.system enabled: container.hp <=0 anchors.fill: parent - particles: ["cruiserArmor"] + groups: ["cruiserArmor"] goalState: "death" // jump: true once: true diff --git a/examples/declarative/plasmapatrol/content/Frigate.qml b/examples/declarative/plasmapatrol/content/Frigate.qml index 8d493b8..f26e7e8 100644 --- a/examples/declarative/plasmapatrol/content/Frigate.qml +++ b/examples/declarative/plasmapatrol/content/Frigate.qml @@ -56,7 +56,7 @@ Item { height: 128 Emitter{ system: container.system - particle: "frigateShield" + group: "frigateShield" anchors.centerIn: parent size: 92 emitRate: 1 @@ -65,7 +65,7 @@ Item { } Emitter{ system: container.system - particle: container.shipParticle + group: container.shipParticle anchors.centerIn: parent width: 64 height: 16 diff --git a/examples/declarative/plasmapatrol/content/LaserHardpoint.qml b/examples/declarative/plasmapatrol/content/LaserHardpoint.qml index 45712bf..56fd91b 100644 --- a/examples/declarative/plasmapatrol/content/LaserHardpoint.qml +++ b/examples/declarative/plasmapatrol/content/LaserHardpoint.qml @@ -51,7 +51,7 @@ Item { height: 24 Emitter{ id: visualization - particle: "laser" + group: "laser" system: container.system anchors.fill: parent enabled: container.show @@ -86,7 +86,7 @@ Item { } Emitter{ id: emitter - particle: "laser" + group: "laser" enabled: false system: container.system x: Math.min(container.width/2, target.x); diff --git a/examples/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml b/examples/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml index 792ba7a..7a8c3e6 100644 --- a/examples/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml +++ b/examples/declarative/plasmapatrol/content/PlasmaPatrolParticles.qml @@ -45,7 +45,7 @@ Item{ property ParticleSystem sys ImageParticle{ system: sys - particles: ["default"] + groups: ["default"] source: "pics/blur-circle3.png" color: "#003A3A3A" colorVariation: 0.1 @@ -53,7 +53,7 @@ Item{ } ImageParticle{ system: sys - particles: ["redTeam"] + groups: ["redTeam"] source: "pics/blur-circle3.png" color: "#0028060A" colorVariation: 0.1 @@ -61,7 +61,7 @@ Item{ } ImageParticle{ system: sys - particles: ["greenTeam"] + groups: ["greenTeam"] source: "pics/blur-circle3.png" color: "#0006280A" colorVariation: 0.1 @@ -69,7 +69,7 @@ Item{ } ImageParticle{ system: sys - particles: ["blaster"] + groups: ["blaster"] source: "pics/star2.png" //color: "#0F282406" color: "#0F484416" @@ -78,7 +78,7 @@ Item{ } ImageParticle{ system: sys - particles: ["laser"] + groups: ["laser"] source: "pics/star3.png" //color: "#00123F68" color: "#00428FF8" @@ -87,7 +87,7 @@ Item{ } ImageParticle{ system: sys - particles: ["cannon"] + groups: ["cannon"] source: "pics/particle.png" color: "#80FFAAFF" colorVariation: 0.1 @@ -95,7 +95,7 @@ Item{ } ImageParticle{ system: sys - particles: ["cannonCore"] + groups: ["cannonCore"] source: "pics/particle.png" color: "#00666666" colorVariation: 0.8 @@ -103,7 +103,7 @@ Item{ } ImageParticle{ system: sys - particles: ["cannonWake"] + groups: ["cannonWake"] source: "pics/star.png" color: "#00CCCCCC" colorVariation: 0.2 @@ -111,7 +111,7 @@ Item{ } ImageParticle{ system: sys - particles: ["frigateShield"] + groups: ["frigateShield"] source: "pics/blur-circle2.png" color: "#00000000" colorVariation: 0.05 @@ -121,7 +121,7 @@ Item{ } ImageParticle{ system: sys - particles: ["cruiserArmor"] + groups: ["cruiserArmor"] z: 1 sprites:[Sprite{ id: spinState @@ -146,7 +146,7 @@ Item{ } TrailEmitter{ system: sys - particle: "cannonWake" + group: "cannonWake" follow: "cannon" emitRatePerParticle: 64 lifeSpan: 600 @@ -160,7 +160,7 @@ Item{ } TrailEmitter{ system: sys - particle: "cannonCore" + group: "cannonCore" follow: "cannon" emitRatePerParticle: 256 lifeSpan: 128 diff --git a/examples/declarative/plasmapatrol/content/Sloop.qml b/examples/declarative/plasmapatrol/content/Sloop.qml index 82e57f5..59678a7 100644 --- a/examples/declarative/plasmapatrol/content/Sloop.qml +++ b/examples/declarative/plasmapatrol/content/Sloop.qml @@ -60,7 +60,7 @@ Item { //TODO: Cooler would be an 'orbiting' affector //TODO: On the subject, opacity and size should be grouped type 'overLife' if we can cram that in the particles system: container.system - particle: container.shipParticle + group: container.shipParticle shape: EllipseShape{} emitRate: hp > 0 ? hp + 20 : 0 diff --git a/examples/declarative/plasmapatrol/plasmapatrol.qml b/examples/declarative/plasmapatrol/plasmapatrol.qml index 4ea464b..2fa9f44 100644 --- a/examples/declarative/plasmapatrol/plasmapatrol.qml +++ b/examples/declarative/plasmapatrol/plasmapatrol.qml @@ -97,7 +97,7 @@ Rectangle { anchors.fill: parent system: particles enabled: true - particle: "default" + group: "default" emitRate: 1200 lifeSpan: 1200 shape: MaskShape{source:"content/pics/TitleText.png"} diff --git a/examples/declarative/samegame/SamegameCore/BoomBlock.qml b/examples/declarative/samegame/SamegameCore/BoomBlock.qml index 1c84fa8..df3e9bd 100644 --- a/examples/declarative/samegame/SamegameCore/BoomBlock.qml +++ b/examples/declarative/samegame/SamegameCore/BoomBlock.qml @@ -75,7 +75,7 @@ Item { Emitter { id: particles system: particleSystem - particle: { + group: { if(type == 0){ "red"; } else if (type == 1) { diff --git a/examples/declarative/samegame/SamegameCore/GameArea.qml b/examples/declarative/samegame/SamegameCore/GameArea.qml index 967e299..9a8f68a 100644 --- a/examples/declarative/samegame/SamegameCore/GameArea.qml +++ b/examples/declarative/samegame/SamegameCore/GameArea.qml @@ -65,21 +65,21 @@ Item { id: particleSystem; z:2 ImageParticle { - particles: ["red"] + groups: ["red"] color: Qt.darker("red");//Actually want desaturated... source: "pics/particle.png" colorVariation: 0.4 alpha: 0.1 } ImageParticle { - particles: ["green"] + groups: ["green"] color: Qt.darker("green");//Actually want desaturated... source: "pics/particle.png" colorVariation: 0.4 alpha: 0.1 } ImageParticle { - particles: ["blue"] + groups: ["blue"] color: Qt.darker("blue");//Actually want desaturated... source: "pics/particle.png" colorVariation: 0.4 diff --git a/examples/declarative/snake/content/Cookie.qml b/examples/declarative/snake/content/Cookie.qml index e3b3bbf..d9fedd9 100644 --- a/examples/declarative/snake/content/Cookie.qml +++ b/examples/declarative/snake/content/Cookie.qml @@ -71,13 +71,13 @@ Item { ParticleSystem { width:1; height:1; anchors.centerIn: parent; ImageParticle { - particles: ["star"] + groups: ["star"] source: "pics/yellowStar.png" } Emitter { id: particles anchors.fill: parent - particle: "star" + group: "star" emitRate: 50 emitting: false lifeSpan: 700 diff --git a/examples/declarative/snake/content/Link.qml b/examples/declarative/snake/content/Link.qml index 82e0359..31ad622 100644 --- a/examples/declarative/snake/content/Link.qml +++ b/examples/declarative/snake/content/Link.qml @@ -96,13 +96,13 @@ Item { id:link ParticleSystem { width:1; height:1; anchors.centerIn: parent; ImageParticle { - particles: ["star"] + groups: ["star"] source: type == 1 ? "pics/blueStar.png" : "pics/redStar.png" } Emitter { id: particles anchors.fill: parent - particle: "star" + group: "star" emitRate: 50 emitting: false lifeSpan: 700 diff --git a/examples/declarative/toys/dynamicscene/dynamicscene.qml b/examples/declarative/toys/dynamicscene/dynamicscene.qml index 5670aac..179d633 100644 --- a/examples/declarative/toys/dynamicscene/dynamicscene.qml +++ b/examples/declarative/toys/dynamicscene/dynamicscene.qml @@ -104,7 +104,7 @@ Item { ImageParticle { id: stars source: "content/images/star.png" - particles: ["stars"] + groups: ["stars"] opacity: .5 } @@ -113,7 +113,7 @@ Item { anchors.fill: parent emitRate: parent.width / 50 lifeSpan: 5000 - particle: "stars" + group: "stars" } } diff --git a/src/declarative/items/qsgsprite.cpp b/src/declarative/items/qsgsprite.cpp index 806f7a9..63d1951 100644 --- a/src/declarative/items/qsgsprite.cpp +++ b/src/declarative/items/qsgsprite.cpp @@ -40,42 +40,17 @@ ****************************************************************************/ #include "qsgsprite_p.h" -//TODO: Split out particle system dependency -#include "qsgparticlesystem_p.h" #include QT_BEGIN_NAMESPACE QSGSprite::QSGSprite(QObject *parent) : - QObject(parent) + QSGStochasticState(parent) , m_generatedCount(0) , m_framesPerRow(0) - , m_frames(1) , m_frameHeight(0) , m_frameWidth(0) - , m_duration(1000) { } -void redirectError(QDeclarativeListProperty *prop, QObject *value) -{ - qWarning() << "Could not add " << value << " to state" << prop->object << "as it is not associated with a particle system."; -} - -QDeclarativeListProperty QSGSprite::particleChildren() -{ - QSGParticleSystem* system = qobject_cast(parent()); - if (system) - return QDeclarativeListProperty(this, 0, &QSGParticleSystem::stateRedirect); - else - return QDeclarativeListProperty(this, 0, &redirectError); -} - -int QSGSprite::variedDuration() const -{ - return m_duration - + (m_durationVariance * ((qreal)qrand()/RAND_MAX) * 2) - - m_durationVariance; -} - QT_END_NAMESPACE diff --git a/src/declarative/items/qsgsprite_p.h b/src/declarative/items/qsgsprite_p.h index c18e9b4..ed7c6c4 100644 --- a/src/declarative/items/qsgsprite_p.h +++ b/src/declarative/items/qsgsprite_p.h @@ -46,6 +46,7 @@ #include #include #include +#include "qsgspriteengine_p.h" QT_BEGIN_HEADER @@ -54,38 +55,23 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QSGSprite : public QObject +class QSGSprite : public QSGStochasticState { Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged) - //If frame height or width is not specified, it is assumed to be a single long row of frames. + //If frame height or width is not specified, it is assumed to be a single long row of square frames. //Otherwise, it can be multiple contiguous rows, when one row runs out the next will be used. Q_PROPERTY(int frameHeight READ frameHeight WRITE setFrameHeight NOTIFY frameHeightChanged) Q_PROPERTY(int frameWidth READ frameWidth WRITE setFrameWidth NOTIFY frameWidthChanged) - Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged) - Q_PROPERTY(int durationVariation READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged) - Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged) - Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged) - Q_PROPERTY(QDeclarativeListProperty particleChildren READ particleChildren DESIGNABLE false)//### Hidden property for in-state system definitions - ought not to be used in actual "Sprite" states - Q_CLASSINFO("DefaultProperty", "particleChildren") public: explicit QSGSprite(QObject *parent = 0); - QDeclarativeListProperty particleChildren(); - QUrl source() const { return m_source; } - int frames() const - { - return m_frames; - } - int frameHeight() const { return m_frameHeight; @@ -96,55 +82,15 @@ public: return m_frameWidth; } - int duration() const - { - return m_duration; - } - - QString name() const - { - return m_name; - } - - QVariantMap to() const - { - return m_to; - } - - qreal speedModifer() const - { - return m_speedModifier; - } - - int durationVariance() const - { - return m_durationVariance; - } - - int variedDuration() const; signals: void sourceChanged(QUrl arg); - void framesChanged(int arg); - void frameHeightChanged(int arg); void frameWidthChanged(int arg); - void durationChanged(int arg); - - void nameChanged(QString arg); - - void toChanged(QVariantMap arg); - - void speedModifierChanged(qreal arg); - - void durationVarianceChanged(int arg); - - void entered();//### Just playing around - don't expect full state API - public slots: void setSource(QUrl arg) @@ -155,14 +101,6 @@ public slots: } } - void setFrames(int arg) - { - if (m_frames != arg) { - m_frames = arg; - emit framesChanged(arg); - } - } - void setFrameHeight(int arg) { if (m_frameHeight != arg) { @@ -179,60 +117,16 @@ public slots: } } - void setDuration(int arg) - { - if (m_duration != arg) { - m_duration = arg; - emit durationChanged(arg); - } - } - - void setName(QString arg) - { - if (m_name != arg) { - m_name = arg; - emit nameChanged(arg); - } - } - - void setTo(QVariantMap arg) - { - if (m_to != arg) { - m_to = arg; - emit toChanged(arg); - } - } - - void setSpeedModifier(qreal arg) - { - if (m_speedModifier != arg) { - m_speedModifier = arg; - emit speedModifierChanged(arg); - } - } - - void setDurationVariance(int arg) - { - if (m_durationVariance != arg) { - m_durationVariance = arg; - emit durationVarianceChanged(arg); - } - } private: friend class QSGImageParticle; friend class QSGSpriteEngine; + friend class QSGStochasticEngine; int m_generatedCount; int m_framesPerRow; QUrl m_source; - int m_frames; int m_frameHeight; int m_frameWidth; - int m_duration; - QString m_name; - QVariantMap m_to; - qreal m_speedModifier; - int m_durationVariance; }; diff --git a/src/declarative/items/qsgspriteengine.cpp b/src/declarative/items/qsgspriteengine.cpp index 1915db6..0391ce1 100644 --- a/src/declarative/items/qsgspriteengine.cpp +++ b/src/declarative/items/qsgspriteengine.cpp @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE Also solve the state data initialization/transfer issue so as to not need to make friends */ -QSGSpriteEngine::QSGSpriteEngine(QObject *parent) : +QSGStochasticEngine::QSGStochasticEngine(QObject *parent) : QObject(parent), m_timeOffset(0) { //Default size 1 @@ -61,7 +61,7 @@ QSGSpriteEngine::QSGSpriteEngine(QObject *parent) : m_advanceTime.start(); } -QSGSpriteEngine::QSGSpriteEngine(QList states, QObject *parent) : +QSGStochasticEngine::QSGStochasticEngine(QList states, QObject *parent) : QObject(parent), m_states(states), m_timeOffset(0) { //Default size 1 @@ -69,10 +69,27 @@ QSGSpriteEngine::QSGSpriteEngine(QList states, QObject *parent) : m_advanceTime.start(); } +QSGStochasticEngine::~QSGStochasticEngine() +{ +} + +QSGSpriteEngine::QSGSpriteEngine(QObject *parent) + : QSGStochasticEngine(parent) +{ +} + +QSGSpriteEngine::QSGSpriteEngine(QList sprites, QObject *parent) + : QSGStochasticEngine(parent) +{ + foreach (QSGSprite* sprite, sprites) + m_states << (QSGStochasticState*)sprite; +} + QSGSpriteEngine::~QSGSpriteEngine() { } + int QSGSpriteEngine::maxFrames() { return m_maxFrames; @@ -87,46 +104,46 @@ TODO: Above idea needs to have the varying duration offset added to it */ int QSGSpriteEngine::spriteState(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) return state; - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; return state + extra; } int QSGSpriteEngine::spriteStart(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) return m_startTimes[sprite]; - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; return state + extra*rowDuration; } int QSGSpriteEngine::spriteFrames(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) - return m_states[state]->frames(); - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) + return m_sprites[state]->frames(); + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; - if (extra == m_states[state]->m_generatedCount - 1)//last state - return m_states[state]->frames() % m_states[state]->m_framesPerRow; + if (extra == m_sprites[state]->m_generatedCount - 1)//last state + return m_sprites[state]->frames() % m_sprites[state]->m_framesPerRow; else - return m_states[state]->m_framesPerRow; + return m_sprites[state]->m_framesPerRow; } int QSGSpriteEngine::spriteDuration(int sprite) { - int state = m_sprites[sprite]; - if (!m_states[state]->m_generatedCount) + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) return m_duration[sprite]; - int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; - if (extra == m_states[state]->m_generatedCount - 1)//last state - return (m_duration[sprite] * m_states[state]->frames()) % rowDuration; + if (extra == m_sprites[state]->m_generatedCount - 1)//last state + return (m_duration[sprite] * m_sprites[state]->frames()) % rowDuration; else return rowDuration; } @@ -136,21 +153,21 @@ int QSGSpriteEngine::spriteCount()//TODO: Actually image state count, need to re return m_imageStateCount; } -void QSGSpriteEngine::setGoal(int state, int sprite, bool jump) +void QSGStochasticEngine::setGoal(int state, int sprite, bool jump) { - if (sprite >= m_sprites.count() || state >= m_states.count()) + if (sprite >= m_things.count() || state >= m_states.count()) return; if (!jump){ m_goals[sprite] = state; return; } - if (m_sprites[sprite] == state) + if (m_things[sprite] == state) return;//Already there - m_sprites[sprite] = state; + m_things[sprite] = state; m_duration[sprite] = m_states[state]->variedDuration(); m_goals[sprite] = -1; - restartSprite(sprite); + restart(sprite); emit stateChanged(sprite); emit m_states[state]->entered(); return; @@ -165,8 +182,15 @@ QImage QSGSpriteEngine::assembledImage() int maxSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); + foreach (QSGStochasticState* s, m_states){ + QSGSprite* sprite = qobject_cast(s); + if (sprite) + m_sprites << sprite; + else + qDebug() << "Error: Non-sprite in QSGSpriteEngine"; + } - foreach (QSGSprite* state, m_states){ + foreach (QSGSprite* state, m_sprites){ if (state->frames() > m_maxFrames) m_maxFrames = state->frames(); @@ -224,7 +248,7 @@ QImage QSGSpriteEngine::assembledImage() image.fill(0); QPainter p(&image); int y = 0; - foreach (QSGSprite* state, m_states){ + foreach (QSGSprite* state, m_sprites){ QImage img(state->source().toLocalFile()); if (img.height() == frameHeight && img.width() < maxSize){//Simple case p.drawImage(0,y,img); @@ -271,51 +295,51 @@ QImage QSGSpriteEngine::assembledImage() return image; } -void QSGSpriteEngine::setCount(int c) +void QSGStochasticEngine::setCount(int c) { - m_sprites.resize(c); + m_things.resize(c); m_goals.resize(c); m_duration.resize(c); m_startTimes.resize(c); } -void QSGSpriteEngine::startSprite(int index, int state) +void QSGStochasticEngine::start(int index, int state) { - if (index >= m_sprites.count()) + if (index >= m_things.count()) return; - m_sprites[index] = state; + m_things[index] = state; m_duration[index] = m_states[state]->variedDuration(); m_goals[index] = -1; - restartSprite(index); + restart(index); } -void QSGSpriteEngine::stopSprite(int index) +void QSGStochasticEngine::stop(int index) { - if (index >= m_sprites.count()) + if (index >= m_things.count()) return; //Will never change until start is called again with a new state - this is not a 'pause' for (int i=0; iframes() + m_startTimes[index]; + int time = m_duration[index] * m_states[m_things[index]]->frames() + m_startTimes[index]; for (int i=0; i changedIndexes; while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){ foreach (int idx, m_stateUpdates.first().second){ - if (idx >= m_sprites.count()) + if (idx >= m_things.count()) continue;//TODO: Proper fix(because this does happen and I'm just ignoring it) - int stateIdx = m_sprites[idx]; + int stateIdx = m_things[idx]; int nextIdx = -1; int goalPath = goalSeek(stateIdx, idx); if (goalPath == -1){//Random @@ -347,7 +371,7 @@ uint QSGSpriteEngine::updateSprites(uint time)//### would returning a list of ch if (nextIdx == -1)//No to states means stay here nextIdx = stateIdx; - m_sprites[idx] = nextIdx; + m_things[idx] = nextIdx; m_duration[idx] = m_states[nextIdx]->variedDuration(); m_startTimes[idx] = time; if (nextIdx != stateIdx){ @@ -370,7 +394,7 @@ uint QSGSpriteEngine::updateSprites(uint time)//### would returning a list of ch return m_stateUpdates.first().first; } -int QSGSpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist) +int QSGStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist) { QString goalName; if (m_goals[spriteIdx] != -1) @@ -386,7 +410,7 @@ int QSGSpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist) return curIdx; if (dist < 0) dist = m_states.count(); - QSGSprite* curState = m_states[curIdx]; + QSGStochasticState* curState = m_states[curIdx]; for (QVariantMap::const_iterator iter = curState->m_to.constBegin(); iter!=curState->m_to.constEnd(); iter++){ if (iter.key() == goalName) @@ -445,7 +469,7 @@ int QSGSpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist) return -1; } -void QSGSpriteEngine::addToUpdateList(uint t, int idx) +void QSGStochasticEngine::addToUpdateList(uint t, int idx) { for (int i=0; i sprites READ sprites) + //TODO: Optimize single state case? Q_PROPERTY(QString globalGoal READ globalGoal WRITE setGlobalGoal NOTIFY globalGoalChanged) + Q_PROPERTY(QDeclarativeListProperty states READ states) public: - explicit QSGSpriteEngine(QObject *parent = 0); - QSGSpriteEngine(QList sprites, QObject *parent=0); - ~QSGSpriteEngine(); + explicit QSGStochasticEngine(QObject *parent = 0); + QSGStochasticEngine(QList states, QObject *parent=0); + ~QSGStochasticEngine(); - QDeclarativeListProperty sprites() + QDeclarativeListProperty states() { - return QDeclarativeListProperty(this, m_states); + return QDeclarativeListProperty(this, m_states); } + QString globalGoal() const { return m_globalGoal; } - int count() const {return m_sprites.count();} + int count() const {return m_things.count();} void setCount(int c); - int spriteState(int sprite=0);// {return m_sprites[sprite];} - int spriteStart(int sprite=0);// {return m_startTimes[sprite];} - int spriteFrames(int sprite=0); - int spriteDuration(int sprite=0); - int spriteCount();//Like state count, but for the image states - int maxFrames(); - void setGoal(int state, int sprite=0, bool jump=false); - QImage assembledImage(); - void startSprite(int index=0, int state=0); - void stopSprite(int index=0); + void setGoal(int state, int sprite=0, bool jump=false); + void start(int index=0, int state=0); + void stop(int index=0); + int curState(int index=0) {return m_things[index];} -private://Nothing outside should use this? - friend class QSGSpriteGoalAffector;//XXX: Fix interface + QSGStochasticState* state(int idx){return m_states[idx];} + int stateIndex(QSGStochasticState* s){return m_states.indexOf(s);} int stateCount() {return m_states.count();} - int stateIndex(QSGSprite* s){return m_states.indexOf(s);}//TODO: Does this need to be hidden? - QSGSprite* state(int idx){return m_states[idx];}//Used by spritegoal affector +private: signals: void globalGoalChanged(QString arg); @@ -116,14 +239,14 @@ public slots: uint updateSprites(uint time); -private: +protected: friend class QSGParticleSystem; - void restartSprite(int sprite); + void restart(int index); void addToUpdateList(uint t, int idx); - int goalSeek(int curState, int spriteIdx, int dist=-1); - QList m_states; + int goalSeek(int curState, int idx, int dist=-1); + QList m_states; //### Consider struct or class for the four data variables? - QVector m_sprites;//int is the index in m_states of the current state + QVector m_things;//int is the index in m_states of the current state QVector m_goals; QVector m_duration; QVector m_startTimes; @@ -136,6 +259,31 @@ private: int m_imageStateCount; }; +class QSGSpriteEngine : public QSGStochasticEngine +{ + Q_OBJECT + Q_PROPERTY(QDeclarativeListProperty sprites READ sprites) +public: + explicit QSGSpriteEngine(QObject *parent = 0); + QSGSpriteEngine(QList sprites, QObject *parent=0); + ~QSGSpriteEngine(); + QDeclarativeListProperty sprites() + { + return QDeclarativeListProperty(this, m_sprites); + } + + + int spriteState(int sprite=0); + int spriteStart(int sprite=0); + int spriteFrames(int sprite=0); + int spriteDuration(int sprite=0); + int spriteCount();//Like state count, but for the image states + int maxFrames(); + QImage assembledImage(); +private: + QList m_sprites; +}; + //Common use is to have your own list property which is transparently an engine inline void spriteAppend(QDeclarativeListProperty *p, QSGSprite* s) { diff --git a/src/declarative/items/qsgspriteimage.cpp b/src/declarative/items/qsgspriteimage.cpp index afa80e4..5557ea5 100644 --- a/src/declarative/items/qsgspriteimage.cpp +++ b/src/declarative/items/qsgspriteimage.cpp @@ -263,7 +263,7 @@ QSGGeometryNode* QSGSpriteImage::buildNode() g->setDrawingMode(GL_TRIANGLES); SpriteVertices *p = (SpriteVertices *) g->vertexData(); - m_spriteEngine->startSprite(0); + m_spriteEngine->start(0); p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = 0; p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = 0; p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames(); diff --git a/src/declarative/particles/particles.pri b/src/declarative/particles/particles.pri index 527bd9a..8676e52 100644 --- a/src/declarative/particles/particles.pri +++ b/src/declarative/particles/particles.pri @@ -29,7 +29,8 @@ HEADERS += \ $$PWD/qsgtargetaffector_p.h \ $$PWD/qsgcumulativedirection_p.h \ $$PWD/qsgv8particledata_p.h \ - $$PWD/qsgrectangleextruder_p.h + $$PWD/qsgrectangleextruder_p.h \ + $$PWD/qsgparticlegroup_p.h SOURCES += \ $$PWD/qsgangledirection.cpp \ @@ -60,7 +61,8 @@ SOURCES += \ $$PWD/qsgtargetaffector.cpp \ $$PWD/qsgcumulativedirection.cpp \ $$PWD/qsgv8particledata.cpp \ - $$PWD/qsgrectangleextruder.cpp + $$PWD/qsgrectangleextruder.cpp \ + $$PWD/qsgparticlegroup.cpp RESOURCES += \ $$PWD/particles.qrc diff --git a/src/declarative/particles/qsgcustomparticle.cpp b/src/declarative/particles/qsgcustomparticle.cpp index ab4cfa0..a1d65a5 100644 --- a/src/declarative/particles/qsgcustomparticle.cpp +++ b/src/declarative/particles/qsgcustomparticle.cpp @@ -465,7 +465,7 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNodes() s.vertexCode = qt_particles_default_vertex_code; s.vertexCode = qt_particles_template_vertex_code + s.vertexCode; m_material.setProgramSource(s); - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); //Create Particle Geometry diff --git a/src/declarative/particles/qsgimageparticle.cpp b/src/declarative/particles/qsgimageparticle.cpp index 581024d..b1aef78 100644 --- a/src/declarative/particles/qsgimageparticle.cpp +++ b/src/declarative/particles/qsgimageparticle.cpp @@ -1021,7 +1021,7 @@ QSGGeometryNode* QSGImageParticle::buildParticleNodes() m_material->setFlag(QSGMaterial::Blending); } - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); QSGGeometryNode* node = new QSGGeometryNode(); @@ -1151,7 +1151,7 @@ void QSGImageParticle::prepareNextFrame() //Advance State getState(m_material)->animcount = m_spriteEngine->spriteCount(); m_spriteEngine->updateSprites(timeStamp); - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); @@ -1199,7 +1199,7 @@ void QSGImageParticle::initialize(int gIdx, int pIdx) datum->animT = datum->t; datum->animIdx = 0; if (m_spriteEngine){ - m_spriteEngine->startSprite(spriteIdx); + m_spriteEngine->start(spriteIdx); datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx); datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx); }else{ diff --git a/src/declarative/particles/qsgimageparticle_p.h b/src/declarative/particles/qsgimageparticle_p.h index 01eacba..1f87b16 100644 --- a/src/declarative/particles/qsgimageparticle_p.h +++ b/src/declarative/particles/qsgimageparticle_p.h @@ -56,7 +56,7 @@ class ImageMaterialData; class QSGGeometryNode; class QSGSprite; -class QSGSpriteEngine; +class QSGStochasticEngine; struct SimpleVertex { float x; @@ -186,7 +186,7 @@ public: QDeclarativeListProperty sprites(); - QSGSpriteEngine* spriteEngine() {return m_spriteEngine;} + QSGStochasticEngine* spriteEngine() {return m_spriteEngine;} enum EntryEffect { None = 0, diff --git a/src/declarative/particles/qsgitemparticle.cpp b/src/declarative/particles/qsgitemparticle.cpp index c330880..2572d67 100644 --- a/src/declarative/particles/qsgitemparticle.cpp +++ b/src/declarative/particles/qsgitemparticle.cpp @@ -226,7 +226,7 @@ void QSGItemParticle::prepareNextFrame() return; //TODO: Size, better fade? - foreach (const QString &str, m_particles){ + foreach (const QString &str, m_groups){ int gIdx = m_system->m_groupIds[str]; int count = m_system->m_groupData[gIdx]->size(); diff --git a/src/declarative/particles/qsgparticleaffector.cpp b/src/declarative/particles/qsgparticleaffector.cpp index cff3c29..7cb4869 100644 --- a/src/declarative/particles/qsgparticleaffector.cpp +++ b/src/declarative/particles/qsgparticleaffector.cpp @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE If the Affector is a direct child of a ParticleSystem, it will automatically be associated with it. */ /*! - \qmlproperty list QtQuick.Particles2::Affector::particles + \qmlproperty list QtQuick.Particles2::Affector::groups Which logical particle groups will be affected. If empty, it will affect all particles. @@ -100,9 +100,9 @@ QT_BEGIN_NAMESPACE x,y are the coordinates of the affected particle, relative to the ParticleSystem. */ -//TODO: Document particle 'type' + /*! - \qmlsignal QtQuick.Particles2::Affector::affectParticle(particle, dt) + \qmlsignal QtQuick.Particles2::Affector::affectParticle(particle particle, real dt) This handler is called when particles are selected to be affected. @@ -113,7 +113,7 @@ QT_BEGIN_NAMESPACE high-volume particle systems. */ /*! - \qmlsignal QtQuick.Particles2::Affector::affected(x, y) + \qmlsignal QtQuick.Particles2::Affector::affected(real x, real y) This handler is called when a particle is selected to be affected. It will only be called if signal is set to true. @@ -142,12 +142,12 @@ void QSGParticleAffector::componentComplete() bool QSGParticleAffector::activeGroup(int g) { 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_groupIds.clear(); + foreach (const QString &p, m_groups) + m_groupIds << m_system->m_groupIds[p];//###Can this occur before group ids are properly assigned? m_updateIntSet = false; } - return m_groups.isEmpty() || m_groups.contains(g); + return m_groupIds.isEmpty() || m_groupIds.contains(g); } void QSGParticleAffector::affectSystem(qreal dt) @@ -195,7 +195,7 @@ bool QSGParticleAffector::affectParticle(QSGParticleData *, qreal ) 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) - if (m_groups.isEmpty() || m_groups.contains(pd->group)) + if (m_groups.isEmpty() || m_groupIds.contains(pd->group)) m_onceOffed.remove(qMakePair(pd->group, pd->index)); } diff --git a/src/declarative/particles/qsgparticleaffector_p.h b/src/declarative/particles/qsgparticleaffector_p.h index 5700969..0dadeff 100644 --- a/src/declarative/particles/qsgparticleaffector_p.h +++ b/src/declarative/particles/qsgparticleaffector_p.h @@ -56,7 +56,7 @@ 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(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged) Q_PROPERTY(QStringList whenCollidingWith READ whenCollidingWith WRITE setWhenCollidingWith NOTIFY whenCollidingWithChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(bool once READ onceOff WRITE setOnceOff NOTIFY onceChanged) @@ -71,9 +71,9 @@ public: return m_system; } - QStringList particles() const + QStringList groups() const { - return m_particles; + return m_groups; } bool enabled() const @@ -100,7 +100,7 @@ signals: void systemChanged(QSGParticleSystem* arg); - void particlesChanged(QStringList arg); + void groupsChanged(QStringList arg); void enabledChanged(bool arg); @@ -122,12 +122,12 @@ void setSystem(QSGParticleSystem* arg) } } -void setParticles(QStringList arg) +void setGroups(QStringList arg) { - if (m_particles != arg) { - m_particles = arg; + if (m_groups != arg) { + m_groups = arg; m_updateIntSet = true; - emit particlesChanged(arg); + emit groupsChanged(arg); } } @@ -169,14 +169,14 @@ protected: virtual bool affectParticle(QSGParticleData *d, qreal dt); bool m_needsReset;//### What is this really saving? QSGParticleSystem* m_system; - QStringList m_particles; + QStringList m_groups; bool activeGroup(int g); bool m_enabled; virtual void componentComplete(); QPointF m_offset; bool isAffectedConnected(); private: - QSet m_groups; + QSet m_groupIds; QSet > m_onceOffed; bool m_updateIntSet; diff --git a/src/declarative/particles/qsgparticleemitter.cpp b/src/declarative/particles/qsgparticleemitter.cpp index 13ab3e6..fdba3de 100644 --- a/src/declarative/particles/qsgparticleemitter.cpp +++ b/src/declarative/particles/qsgparticleemitter.cpp @@ -68,9 +68,9 @@ QT_BEGIN_NAMESPACE This can be omitted if the Emitter is a direct child of the ParticleSystem */ /*! - \qmlproperty string QtQuick.Particles2::Emitter::particle + \qmlproperty string QtQuick.Particles2::Emitter::group - This is the type of logical particle which it will emit. + This is the logical particle group which it will emit into. Default value is "" (empty string). */ @@ -396,7 +396,7 @@ void QSGParticleEmitter::emitWindow(int timeStamp) pt = time; while ((pt < time && m_emitCap) || !m_burstQueue.isEmpty()) { //int pos = m_last_particle % m_particle_count; - QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle], !m_overwrite); + QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_group], !m_overwrite); if (datum){//actually emit(otherwise we've been asked to skip this one) datum->e = this;//###useful? qreal t = 1 - (pt - opt) / dt; diff --git a/src/declarative/particles/qsgparticleemitter_p.h b/src/declarative/particles/qsgparticleemitter_p.h index 8ed7ee7..8bd205b 100644 --- a/src/declarative/particles/qsgparticleemitter_p.h +++ b/src/declarative/particles/qsgparticleemitter_p.h @@ -61,7 +61,7 @@ class QSGParticleEmitter : public QSGItem { Q_OBJECT Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) - Q_PROPERTY(QString particle READ particle WRITE setParticle NOTIFY particleChanged) + Q_PROPERTY(QString group READ group WRITE setGroup NOTIFY groupChanged) Q_PROPERTY(QSGParticleExtruder* shape READ extruder WRITE setExtruder NOTIFY extruderChanged) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged) @@ -109,9 +109,9 @@ public: return m_system; } - QString particle() const + QString group() const { - return m_particle; + return m_group; } int particleDurationVariation() const @@ -130,7 +130,7 @@ signals: void systemChanged(QSGParticleSystem* arg); - void particleChanged(QString arg); + void groupChanged(QString arg); void particleDurationVariationChanged(int arg); @@ -185,11 +185,11 @@ public slots: } } - void setParticle(QString arg) + void setGroup(QString arg) { - if (m_particle != arg) { - m_particle = arg; - emit particleChanged(arg); + if (m_group != arg) { + m_group = arg; + emit groupChanged(arg); } } @@ -308,7 +308,7 @@ protected: int m_particleDurationVariation; bool m_enabled; QSGParticleSystem* m_system; - QString m_particle; + QString m_group; QSGParticleExtruder* m_extruder; QSGParticleExtruder* m_defaultExtruder; QSGParticleExtruder* effectiveExtruder(); diff --git a/src/declarative/particles/qsgparticlegroup.cpp b/src/declarative/particles/qsgparticlegroup.cpp new file mode 100644 index 0000000..28eb4d2 --- /dev/null +++ b/src/declarative/particles/qsgparticlegroup.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgparticlegroup_p.h" + +/*! + \qmlclass ParticleGroup QSGParticleGroup + \inqmlmodule QtQuick.Particles 2 + \brief ParticleGroup elements allow you to set attributes on a logical particle group. + + This element allows you to set timed transitions on particle groups. + + You can also use this element to group particle system elements related to the logical + particle group. Emitters, Affectors and Painters set as direct children of a ParticleGroup + will automatically apply to that logical particle group. TrailEmitters will automatically follow + the group. + + If a ParticleGroup element is not defined for a group, the group will function normally as if + none of the transition properties were set. +*/ +/*! + \qmlproperty ParticleSystem QtQuick.Particles2::ParticleGroup::system + This is the system which will contain the group. + + If the ParticleGroup is a direct child of a ParticleSystem, it will automatically be associated with it. +*/ +/*! + \qmlproperty string QtQuick.Particles2::ParticleGroup::name + This is the name of the particle group, and how it is generally referred to by other elements. + + If elements refer to a name which does not have an explicit ParticleGroup created, it will + work normally (with no transitions specified for the group). If you do not need to assign + duration based transitions to a group, you do not need to create a ParticleGroup with that name (although you may). +*/ +/*! + \qmlproperty int QtQuick.Particles2::ParticleGroup::duration + The time in milliseconds before the group will attempt to transition. + +*/ +/*! + \qmlproperty ParticleSystem QtQuick.Particles2::ParticleGroup::durationVariation + The maximum number of milliseconds that the duration of the transition cycle varies per particle in the group. + + Default value is zero. +*/ +/*! + \qmlproperty ParticleSystem QtQuick.Particles2::ParticleGroup::to + The weighted list of transitions valid for this group. + + If the chosen transition stays in this group, another duration (+/- up to durationVariation) + milliseconds will occur before another transition is attempted. +*/ + +QSGParticleGroup::QSGParticleGroup(QObject* parent) + : QSGStochasticState(parent) +{ + +} + +void delayedRedirect(QDeclarativeListProperty *prop, QObject *value) +{ + QSGParticleGroup* pg = qobject_cast(prop->object); + if (pg) + pg->delayRedirect(value); +} + +QDeclarativeListProperty QSGParticleGroup::particleChildren() +{ + QSGParticleSystem* system = qobject_cast(parent()); + if (system) + return QDeclarativeListProperty(this, 0, &QSGParticleSystem::statePropertyRedirect); + else + return QDeclarativeListProperty(this, 0, &delayedRedirect); +} + +void QSGParticleGroup::setSystem(QSGParticleSystem* arg) +{ + if (m_system != arg) { + m_system = arg; + m_system->registerParticleGroup(this); + performDelayedRedirects(); + emit systemChanged(arg); + } +} + +void QSGParticleGroup::delayRedirect(QObject *obj) +{ + m_delayedRedirects << obj; +} + +void QSGParticleGroup::performDelayedRedirects() +{ + if (!m_system) + return; + foreach (QObject* obj, m_delayedRedirects) + m_system->stateRedirect(this, m_system, obj); + + m_delayedRedirects.clear(); +} + +void QSGParticleGroup::componentComplete(){ + if (!m_system && qobject_cast(parent())) + setSystem(qobject_cast(parent())); +} diff --git a/src/declarative/particles/qsgparticlegroup_p.h b/src/declarative/particles/qsgparticlegroup_p.h new file mode 100644 index 0000000..346b4ab --- /dev/null +++ b/src/declarative/particles/qsgparticlegroup_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QSGPARTICLEGROUP +#define QSGPARTICLEGROUP +#include "qsgspriteengine_p.h" +#include "qsgparticlesystem_p.h" +#include "qdeclarativeparserstatus.h" + +class QSGParticleGroup : public QSGStochasticState, public QDeclarativeParserStatus +{ + Q_OBJECT + //### Would setting limits per group be useful? Or clutter the API? + //Q_PROPERTY(int maximumAlive READ maximumAlive WRITE setMaximumAlive NOTIFY maximumAliveChanged) + + Q_PROPERTY(QSGParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) + + //Intercept children requests and assign to the group & system + Q_PROPERTY(QDeclarativeListProperty particleChildren READ particleChildren DESIGNABLE false)//### Hidden property for in-state system definitions - ought not to be used in actual "Sprite" states + Q_CLASSINFO("DefaultProperty", "particleChildren") + +public: + explicit QSGParticleGroup(QObject* parent = 0); + + QDeclarativeListProperty particleChildren(); + + int maximumAlive() const + { + return m_maximumAlive; + } + + QSGParticleSystem* system() const + { + return m_system; + } + +public slots: + + void setMaximumAlive(int arg) + { + if (m_maximumAlive != arg) { + m_maximumAlive = arg; + emit maximumAliveChanged(arg); + } + } + + void setSystem(QSGParticleSystem* arg); + + void delayRedirect(QObject* obj); + +signals: + + void maximumAliveChanged(int arg); + + void systemChanged(QSGParticleSystem* arg); + +protected: + virtual void componentComplete(); + virtual void classBegin(){;} + +private: + + void performDelayedRedirects(); + + int m_maximumAlive; + QSGParticleSystem* m_system; + QList m_delayedRedirects; +}; + +#endif diff --git a/src/declarative/particles/qsgparticlepainter.cpp b/src/declarative/particles/qsgparticlepainter.cpp index f4639c2..670c1f2 100644 --- a/src/declarative/particles/qsgparticlepainter.cpp +++ b/src/declarative/particles/qsgparticlepainter.cpp @@ -58,10 +58,10 @@ QT_BEGIN_NAMESPACE If the ParticlePainter is a direct child of a ParticleSystem, it will automatically be associated with it. */ /*! - \qmlproperty list QtQuick.Particles2::ParticlePainter::particles + \qmlproperty list QtQuick.Particles2::ParticlePainter::groups Which logical particle groups will be painted. - If empty, it will paint the default particle (""). + If empty, it will paint the default particle group (""). */ QSGParticlePainter::QSGParticlePainter(QSGItem *parent) : QSGItem(parent), @@ -144,7 +144,7 @@ void QSGParticlePainter::calcSystemOffset(bool resetPending) m_systemOffset = -1 * this->mapFromItem(m_system, QPointF(0.0, 0.0)); if (lastOffset != m_systemOffset && !resetPending){ //Reload all particles//TODO: Necessary? - foreach (const QString &g, m_particles){ + foreach (const QString &g, m_groups){ int gId = m_system->m_groupIds[g]; foreach (QSGParticleData* d, m_system->m_groupData[gId]->data) reload(d); diff --git a/src/declarative/particles/qsgparticlepainter_p.h b/src/declarative/particles/qsgparticlepainter_p.h index 08ae3ae..d469947 100644 --- a/src/declarative/particles/qsgparticlepainter_p.h +++ b/src/declarative/particles/qsgparticlepainter_p.h @@ -58,7 +58,7 @@ 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) + Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged) public: explicit QSGParticlePainter(QSGItem *parent = 0); @@ -74,25 +74,25 @@ public: } - QStringList particles() const + QStringList groups() const { - return m_particles; + return m_groups; } signals: void countChanged(); void systemChanged(QSGParticleSystem* arg); - void particlesChanged(QStringList arg); + void groupsChanged(QStringList arg); public slots: void setSystem(QSGParticleSystem* arg); -void setParticles(QStringList arg) +void setGroups(QStringList arg) { - if (m_particles != arg) { - m_particles = arg; - emit particlesChanged(arg); + if (m_groups != arg) { + m_groups = arg; + emit groupsChanged(arg); } } @@ -121,7 +121,7 @@ protected: friend class QSGParticleSystem; int m_count; bool m_pleaseReset; - QStringList m_particles; + QStringList m_groups; QPointF m_systemOffset; private: diff --git a/src/declarative/particles/qsgparticlesmodule.cpp b/src/declarative/particles/qsgparticlesmodule.cpp index 9fa0eba..f880842 100644 --- a/src/declarative/particles/qsgparticlesmodule.cpp +++ b/src/declarative/particles/qsgparticlesmodule.cpp @@ -67,6 +67,7 @@ #include "qsgcumulativedirection_p.h" #include "qsgcustomaffector_p.h" #include "qsgrectangleextruder_p.h" +#include "qsgparticlegroup_p.h" QT_BEGIN_NAMESPACE @@ -75,6 +76,7 @@ void QSGParticlesModule::defineModule() const char* uri = "QtQuick.Particles"; qmlRegisterType(uri, 2, 0, "ParticleSystem"); + qmlRegisterType(uri, 2, 0, "ParticleGroup"); qmlRegisterType(uri, 2, 0, "ImageParticle"); qmlRegisterType(uri, 2, 0, "CustomParticle"); diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index 085e6af..bc27073 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -47,6 +47,7 @@ #include "qsgspriteengine_p.h" #include "qsgsprite_p.h" #include "qsgv8particledata_p.h" +#include "qsgparticlegroup_p.h" #include "qsgtrailemitter_p.h"//###For auto-follow on states, perhaps should be in emitter? #include @@ -549,8 +550,8 @@ void QSGParticleData::debugDump() { qDebug() << "Particle" << systemIndex << group << "/" << index << stillAlive() << "Pos: " << x << "," << y - //<< "Vel: " << vx << "," << sy - //<< "Acc: " << ax << "," << ay + << "Vel: " << vx << "," << vy + << "Acc: " << ax << "," << ay << "Size: " << size << "," << endSize << "Time: " << t << "," <m_timeInt / 1000.0) ; } @@ -559,7 +560,6 @@ bool QSGParticleData::stillAlive() { if (!system) return false; - //fprintf(stderr, "%.9lf %.9lf\n",((qreal)system->m_timeInt/1000.0), (t+lifeSpan)); return (t + lifeSpan - EPSILON) > ((qreal)system->m_timeInt/1000.0); } @@ -601,7 +601,7 @@ void QSGParticleData::extendLife(float time) QSGParticleSystem::QSGParticleSystem(QSGItem *parent) : QSGItem(parent), m_particle_count(0), m_running(true), m_paused(false) - , m_nextIndex(0), m_componentComplete(false), m_spriteEngine(0) + , m_nextIndex(0), m_componentComplete(false), m_stateEngine(0) { connect(&m_painterMapper, SIGNAL(mapped(QObject*)), this, SLOT(loadPainter(QObject*))); @@ -630,16 +630,11 @@ void QSGParticleSystem::initGroups() m_nextGroupId = 1; } - QDeclarativeListProperty QSGParticleSystem::particleStates() -{ - return QDeclarativeListProperty(this, &m_states, spriteAppend, spriteCount, spriteAt, spriteClear); -} - void QSGParticleSystem::registerParticlePainter(QSGParticlePainter* p) { //TODO: a way to Unregister emitters, painters and affectors m_painters << QPointer(p);//###Set or uniqueness checking? - connect(p, SIGNAL(particlesChanged(QStringList)), + connect(p, SIGNAL(groupsChanged(QStringList)), &m_painterMapper, SLOT(map())); loadPainter(p); } @@ -649,7 +644,7 @@ void QSGParticleSystem::registerParticleEmitter(QSGParticleEmitter* e) m_emitters << QPointer(e);//###How to get them out? connect(e, SIGNAL(particleCountChanged()), this, SLOT(emittersChanged())); - connect(e, SIGNAL(particleChanged(QString)), + connect(e, SIGNAL(groupChanged(QString)), this, SLOT(emittersChanged())); emittersChanged(); e->reset();//Start, so that starttime factors appropriately @@ -660,6 +655,12 @@ void QSGParticleSystem::registerParticleAffector(QSGParticleAffector* a) m_affectors << QPointer(a); } +void QSGParticleSystem::registerParticleGroup(QSGParticleGroup* g) +{ + m_groups << QPointer(g); + createEngine(); +} + void QSGParticleSystem::setRunning(bool arg) { if (m_running != arg) { @@ -685,40 +686,45 @@ void QSGParticleSystem::setPaused(bool arg){ } } -void QSGParticleSystem::stateRedirect(QDeclarativeListProperty *prop, QObject *value) +void QSGParticleSystem::statePropertyRedirect(QDeclarativeListProperty *prop, QObject *value) { //Hooks up automatic state-associated stuff QSGParticleSystem* sys = qobject_cast(prop->object->parent()); - QSGSprite* sprite = qobject_cast(prop->object); - if (!sprite || !sys) + QSGParticleGroup* group = qobject_cast(prop->object); + if (!group || !sys || !value) return; + stateRedirect(group, sys, value); +} + +void QSGParticleSystem::stateRedirect(QSGParticleGroup* group, QSGParticleSystem* sys, QObject *value) +{ QStringList list; - list << sprite->name(); + list << group->name(); QSGParticleAffector* a = qobject_cast(value); if (a){ a->setParentItem(sys); - a->setParticles(list); + a->setGroups(list); a->setSystem(sys); return; } QSGTrailEmitter* fe = qobject_cast(value); if (fe){ fe->setParentItem(sys); - fe->setFollow(sprite->name()); + fe->setFollow(group->name()); fe->setSystem(sys); return; } QSGParticleEmitter* e = qobject_cast(value); if (e){ e->setParentItem(sys); - e->setParticle(sprite->name()); + e->setGroup(group->name()); e->setSystem(sys); return; } QSGParticlePainter* p = qobject_cast(value); if (p){ p->setParentItem(sys); - p->setParticles(list); + p->setGroups(list); p->setSystem(sys); return; } @@ -785,14 +791,14 @@ void QSGParticleSystem::loadPainter(QObject *p) foreach (QSGParticleGroupData* sg, m_groupData) sg->painters.remove(painter); int particleCount = 0; - if (painter->particles().isEmpty()){//Uses default particle + if (painter->groups().isEmpty()){//Uses default particle QStringList def; def << ""; - painter->setParticles(def); + painter->setGroups(def); particleCount += m_groupData[0]->size(); m_groupData[0]->painters << painter; }else{ - foreach (const QString &group, painter->particles()){ + foreach (const QString &group, painter->groups()){ if (group != QLatin1String("") && !m_groupIds[group]){//new group int id = m_nextGroupId++; QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); @@ -824,16 +830,16 @@ void QSGParticleSystem::emittersChanged() } 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 + if (!m_groupIds.contains(e->group()) + || (!e->group().isEmpty() && !m_groupIds[e->group()])){//or it was accidentally inserted by a failed lookup earlier int id = m_nextGroupId++; QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); - m_groupIds.insert(e->particle(), id); + m_groupIds.insert(e->group(), id); m_groupData.insert(id, gd); previousSizes << 0; newSizes << 0; } - newSizes[m_groupIds[e->particle()]] += e->particleCount(); + newSizes[m_groupIds[e->group()]] += e->particleCount(); //###: Cull emptied groups? } @@ -850,7 +856,7 @@ void QSGParticleSystem::emittersChanged() foreach (QSGParticlePainter *p, m_painters) loadPainter(p); - if (!m_states.isEmpty()) + if (!m_groups.isEmpty()) createEngine(); if (m_debugMode) @@ -861,58 +867,63 @@ void QSGParticleSystem::createEngine() { if (!m_componentComplete) return; + if (m_stateEngine && m_debugMode) + qDebug() << "Resetting Existing Sprite Engine..."; //### Solve the losses if size/states go down - foreach (QSGSprite* sprite, m_states){ + foreach (QSGParticleGroup* group, m_groups){ bool exists = false; foreach (const QString &name, m_groupIds.keys()) - if (sprite->name() == name) + if (group->name() == name) exists = true; if (!exists){ int id = m_nextGroupId++; QSGParticleGroupData* gd = new QSGParticleGroupData(id, this); - m_groupIds.insert(sprite->name(), id); + m_groupIds.insert(group->name(), id); m_groupData.insert(id, gd); } } - if (m_states.count()){ - //Reorder Sprite List so as to have the same order as groups - QList newList; + if (m_groups.count()){ + //Reorder groups List so as to have the same order as groupData + QList newList; for (int i=0; iname(); - foreach (QSGSprite* existing, m_states){ + foreach (QSGParticleGroup* existing, m_groups){ if (existing->name() == name){ newList << existing; exists = true; } } if (!exists){ - newList << new QSGSprite(this); + newList << new QSGParticleGroup(this); newList.back()->setName(name); } } - m_states = newList; + m_groups = newList; + QList states; + foreach (QSGParticleGroup* g, m_groups) + states << (QSGStochasticState*)g; - if (!m_spriteEngine) - m_spriteEngine = new QSGSpriteEngine(this); - m_spriteEngine->setCount(m_particle_count); - m_spriteEngine->m_states = m_states; + if (!m_stateEngine) + m_stateEngine = new QSGStochasticEngine(this); + m_stateEngine->setCount(m_particle_count); + m_stateEngine->m_states = states; - connect(m_spriteEngine, SIGNAL(stateChanged(int)), + connect(m_stateEngine, SIGNAL(stateChanged(int)), this, SLOT(particleStateChange(int))); }else{ - if (m_spriteEngine) - delete m_spriteEngine; - m_spriteEngine = 0; + if (m_stateEngine) + delete m_stateEngine; + m_stateEngine = 0; } } void QSGParticleSystem::particleStateChange(int idx) { - moveGroups(m_bySysIdx[idx], m_spriteEngine->spriteState(idx)); + moveGroups(m_bySysIdx[idx], m_stateEngine->curState(idx)); } void QSGParticleSystem::moveGroups(QSGParticleData *d, int newGIdx) @@ -934,8 +945,8 @@ int QSGParticleSystem::nextSystemIndex() } if (m_nextIndex >= m_bySysIdx.size()){ m_bySysIdx.resize(m_bySysIdx.size() < 10 ? 10 : m_bySysIdx.size()*1.1);//###+1,10%,+10? Choose something non-arbitrarily - if (m_spriteEngine) - m_spriteEngine->setCount(m_bySysIdx.size()); + if (m_stateEngine) + m_stateEngine->setCount(m_bySysIdx.size()); } return m_nextIndex++; @@ -954,8 +965,8 @@ QSGParticleData* QSGParticleSystem::newDatum(int groupId, bool respectLimits, in ret->systemIndex = nextSystemIndex(); }else{ if (ret->systemIndex != -1){ - if (m_spriteEngine) - m_spriteEngine->stopSprite(ret->systemIndex); + if (m_stateEngine) + m_stateEngine->stop(ret->systemIndex); m_reusableIndexes << ret->systemIndex; m_bySysIdx[ret->systemIndex] = 0; } @@ -963,8 +974,8 @@ QSGParticleData* QSGParticleSystem::newDatum(int groupId, bool respectLimits, in } m_bySysIdx[ret->systemIndex] = ret; - if (m_spriteEngine) - m_spriteEngine->startSprite(ret->systemIndex, ret->group); + if (m_stateEngine) + m_stateEngine->start(ret->systemIndex, ret->group); m_empty = false; return ret; @@ -1011,8 +1022,8 @@ void QSGParticleSystem::updateCurrentTime( int currentTime ) foreach (QSGParticleGroupData* gd, m_groupData)//Recycle all groups and see if they're out of live particles m_empty = gd->recycle() && m_empty; - if (m_spriteEngine) - m_spriteEngine->updateSprites(m_timeInt); + if (m_stateEngine) + m_stateEngine->updateSprites(m_timeInt); foreach (QSGParticleEmitter* emitter, m_emitters) if (emitter) diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h index 25a0c87..f531e7f 100644 --- a/src/declarative/particles/qsgparticlesystem_p.h +++ b/src/declarative/particles/qsgparticlesystem_p.h @@ -65,9 +65,10 @@ class QSGParticleEmitter; class QSGParticlePainter; class QSGParticleData; class QSGParticleSystemAnimation; -class QSGSpriteEngine; +class QSGStochasticEngine; class QSGSprite; class QSGV8ParticleData; +class QSGParticleGroup; struct QSGParticleDataHeapNode{ int time;//in ms @@ -223,12 +224,10 @@ class QSGParticleSystem : public QSGItem Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) Q_PROPERTY(bool paused READ isPaused WRITE setPaused NOTIFY pausedChanged) Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged) - Q_PROPERTY(QDeclarativeListProperty particleStates READ particleStates) public: explicit QSGParticleSystem(QSGItem *parent = 0); ~QSGParticleSystem(); - QDeclarativeListProperty particleStates(); //TODO: Hook up running and temporal manipulators to the animation bool isRunning() const @@ -286,7 +285,7 @@ public://###but only really for related class usage. Perhaps we should all be fr QVector m_bySysIdx; //Another reference to the data (data owned by group), but by sysIdx QHash m_groupIds; QHash m_groupData; - QSGSpriteEngine* m_spriteEngine; + QSGStochasticEngine* m_stateEngine; int m_timeInt; bool m_initialized; @@ -294,9 +293,11 @@ public://###but only really for related class usage. Perhaps we should all be fr void registerParticlePainter(QSGParticlePainter* p); void registerParticleEmitter(QSGParticleEmitter* e); void registerParticleAffector(QSGParticleAffector* a); + void registerParticleGroup(QSGParticleGroup* g); int m_particle_count; - static void stateRedirect(QDeclarativeListProperty *prop, QObject *value);//From QSGSprite + static void statePropertyRedirect(QDeclarativeListProperty *prop, QObject *value); + static void stateRedirect(QSGParticleGroup* group, QSGParticleSystem* sys, QObject *value); bool isPaused() const { return m_paused; @@ -315,11 +316,11 @@ private: QList > m_affectors; QList > m_painters; QList > m_syncList; + QList m_groups; int m_nextGroupId; int m_nextIndex; QSet m_reusableIndexes; bool m_componentComplete; - QList m_states; QSignalMapper m_painterMapper; QSignalMapper m_emitterMapper; diff --git a/src/declarative/particles/qsgspritegoal.cpp b/src/declarative/particles/qsgspritegoal.cpp index 1837167..ec2be02 100644 --- a/src/declarative/particles/qsgspritegoal.cpp +++ b/src/declarative/particles/qsgspritegoal.cpp @@ -64,16 +64,12 @@ QT_BEGIN_NAMESPACE \qmlproperty bool QtQuick.Particles2::SpriteGoal::systemStates */ - Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged) - Q_PROPERTY(bool jump READ jump WRITE setJump NOTIFY jumpChanged) - Q_PROPERTY(bool systemStates READ systemStates WRITE setSystemStates NOTIFY systemStatesChanged) - QSGSpriteGoalAffector::QSGSpriteGoalAffector(QSGItem *parent) : QSGParticleAffector(parent), m_goalIdx(-1), m_jump(false), m_systemStates(false), m_lastEngine(0), m_notUsingEngine(false) { } -void QSGSpriteGoalAffector::updateStateIndex(QSGSpriteEngine* e) +void QSGSpriteGoalAffector::updateStateIndex(QSGStochasticEngine* e) { if (m_systemStates){ m_goalIdx = m_system->m_groupIds[m_goalState]; @@ -104,14 +100,14 @@ void QSGSpriteGoalAffector::setGoalState(QString arg) bool QSGSpriteGoalAffector::affectParticle(QSGParticleData *d, qreal dt) { Q_UNUSED(dt); - QSGSpriteEngine *engine = 0; + QSGStochasticEngine *engine = 0; if (!m_systemStates){ //TODO: Affect all engines foreach (QSGParticlePainter *p, m_system->m_groupData[d->group]->painters) if (qobject_cast(p)) engine = qobject_cast(p)->spriteEngine(); }else{ - engine = m_system->m_spriteEngine; + engine = m_system->m_stateEngine; if (!engine) m_notUsingEngine = true; } @@ -126,7 +122,7 @@ bool QSGSpriteGoalAffector::affectParticle(QSGParticleData *d, qreal dt) if (m_notUsingEngine){//systemStates && no stochastic states defined. So cut out the engine //TODO: It's possible to move to a group that is intermediate and not used by painters or emitters - but right now that will redirect to the default group m_system->moveGroups(d, m_goalIdx); - }else if (engine->spriteState(index) != m_goalIdx){ + }else if (engine->curState(index) != m_goalIdx){ engine->setGoal(m_goalIdx, 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 diff --git a/src/declarative/particles/qsgspritegoal_p.h b/src/declarative/particles/qsgspritegoal_p.h index 7c799b1..043970b 100644 --- a/src/declarative/particles/qsgspritegoal_p.h +++ b/src/declarative/particles/qsgspritegoal_p.h @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QSGSpriteEngine; +class QSGStochasticEngine; class QSGSpriteGoalAffector : public QSGParticleAffector { @@ -106,10 +106,10 @@ void setSystemStates(bool arg) } private: - void updateStateIndex(QSGSpriteEngine* e); + void updateStateIndex(QSGStochasticEngine* e); QString m_goalState; int m_goalIdx; - QSGSpriteEngine* m_lastEngine; + QSGStochasticEngine* m_lastEngine; bool m_jump; bool m_systemStates; diff --git a/src/declarative/particles/qsgtrailemitter.cpp b/src/declarative/particles/qsgtrailemitter.cpp index 427b587..5a19ac5 100644 --- a/src/declarative/particles/qsgtrailemitter.cpp +++ b/src/declarative/particles/qsgtrailemitter.cpp @@ -166,7 +166,7 @@ void QSGTrailEmitter::emitWindow(int timeStamp) 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]; + int gId2 = m_system->m_groupIds[m_group]; foreach (QSGParticleData *d, m_system->m_groupData[gId]->data){ if (!d || !d->stillAlive()){ m_lastEmission[d->index] = time; //Should only start emitting when it returns to life diff --git a/src/declarative/particles/qsgtrailemitter_p.h b/src/declarative/particles/qsgtrailemitter_p.h index 5ab6f24..009ccd5 100644 --- a/src/declarative/particles/qsgtrailemitter_p.h +++ b/src/declarative/particles/qsgtrailemitter_p.h @@ -94,7 +94,7 @@ public: } signals: - void emitFollowParticle(QDeclarativeV8Handle particle, QDeclarativeV8Handle followed); + void emitFollowParticle(QDeclarativeV8Handle group, QDeclarativeV8Handle followed); void particlesPerParticlePerSecondChanged(int arg); -- 1.7.2.5