1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 // ideas taken from:
 28 //   . The ocean spray in your face [Jeff Lander]
 29 //      http://www.double.co.nz/dust/col0798.pdf
 30 //   . Building an Advanced Particle System [John van der Burg]
 31 //      http://www.gamasutra.com/features/20000623/vanderburg_01.htm
 32 //   . LOVE game engine
 33 //      http://love2d.org/
 34 //
 35 //
 36 // Radius mode support, from 71 squared
 37 //      http://particledesigner.71squared.com/
 38 //
 39 // IMPORTANT: Particle Designer is supported by cocos2d, but
 40 // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d,
 41 //  cocos2d uses a another approach, but the results are almost identical.
 42 //
 43 
 44 
 45 // tCCPositionType
 46 // possible types of particle positions
 47 
 48 
 49 /**
 50  * Structure that contains the values of each particle
 51  * @Class
 52  * @Construct
 53  * @param {cc.Point} [pos=cc.p(0,0)] Position of particle
 54  * @param {cc.Point} [startPos=cc.p(0,0)]
 55  * @param {cc.Color} [color= cc.color(0, 0, 0, 255)]
 56  * @param {cc.Color} [deltaColor=cc.color(0, 0, 0, 255)]
 57  * @param {cc.Size} [size=0]
 58  * @param {cc.Size} [deltaSize=0]
 59  * @param {Number} [rotation=0]
 60  * @param {Number} [deltaRotation=0]
 61  * @param {Number} [timeToLive=0]
 62  * @param {Number} [atlasIndex=0]
 63  * @param {cc.Particle.ModeA} [modeA=]
 64  * @param {cc.Particle.ModeA} [modeB=]
 65  */
 66 cc.Particle = function (pos, startPos, color, deltaColor, size, deltaSize, rotation, deltaRotation, timeToLive, atlasIndex, modeA, modeB) {
 67     this.pos = pos ? pos : cc.p(0,0);
 68     this.startPos = startPos ? startPos : cc.p(0,0);
 69     this.color = color ? color : {r:0, g: 0, b:0, a:255};
 70     this.deltaColor = deltaColor ? deltaColor : {r:0, g: 0, b:0, a:255} ;
 71     this.size = size || 0;
 72     this.deltaSize = deltaSize || 0;
 73     this.rotation = rotation || 0;
 74     this.deltaRotation = deltaRotation || 0;
 75     this.timeToLive = timeToLive || 0;
 76     this.atlasIndex = atlasIndex || 0;
 77     this.modeA = modeA ? modeA : new cc.Particle.ModeA();
 78     this.modeB = modeB ? modeB : new cc.Particle.ModeB();
 79     this.isChangeColor = false;
 80     this.drawPos = cc.p(0, 0);
 81 };
 82 
 83 /**
 84  * Mode A: gravity, direction, radial accel, tangential accel
 85  * @Class
 86  * @Construct
 87  * @param {cc.Point} dir direction of particle
 88  * @param {Number} radialAccel
 89  * @param {Number} tangentialAccel
 90  */
 91 cc.Particle.ModeA = function (dir, radialAccel, tangentialAccel) {
 92     this.dir = dir ? dir : cc.p(0,0);
 93     this.radialAccel = radialAccel || 0;
 94     this.tangentialAccel = tangentialAccel || 0;
 95 };
 96 
 97 /**
 98  * Mode B: radius mode
 99  * @Class
100  * @Construct
101  * @param {Number} angle
102  * @param {Number} degreesPerSecond
103  * @param {Number} radius
104  * @param {Number} deltaRadius
105  */
106 cc.Particle.ModeB = function (angle, degreesPerSecond, radius, deltaRadius) {
107     this.angle = angle || 0;
108     this.degreesPerSecond = degreesPerSecond || 0;
109     this.radius = radius || 0;
110     this.deltaRadius = deltaRadius || 0;
111 };
112 
113 /**
114   * Array of Point instances used to optimize particle updates
115   */
116 cc.Particle.TemporaryPoints = [
117     cc.p(),
118     cc.p(),
119     cc.p(),
120     cc.p()
121 ];
122 
123 /**
124  * <p>
125  *     Particle System base class. <br/>
126  *     Attributes of a Particle System:<br/>
127  *     - emission rate of the particles<br/>
128  *     - Gravity Mode (Mode A): <br/>
129  *     - gravity <br/>
130  *     - direction <br/>
131  *     - speed +-  variance <br/>
132  *     - tangential acceleration +- variance<br/>
133  *     - radial acceleration +- variance<br/>
134  *     - Radius Mode (Mode B):      <br/>
135  *     - startRadius +- variance    <br/>
136  *     - endRadius +- variance      <br/>
137  *     - rotate +- variance         <br/>
138  *     - Properties common to all modes: <br/>
139  *     - life +- life variance      <br/>
140  *     - start spin +- variance     <br/>
141  *     - end spin +- variance       <br/>
142  *     - start size +- variance     <br/>
143  *     - end size +- variance       <br/>
144  *     - start color +- variance    <br/>
145  *     - end color +- variance      <br/>
146  *     - life +- variance           <br/>
147  *     - blending function          <br/>
148  *     - texture                    <br/>
149  *                                  <br/>
150  *     cocos2d also supports particles generated by Particle Designer (http://particledesigner.71squared.com/).<br/>
151  *     'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d,  <br/>
152  *     cocos2d uses a another approach, but the results are almost identical.<br/>
153  *     cocos2d supports all the variables used by Particle Designer plus a bit more:  <br/>
154  *     - spinning particles (supported when using ParticleSystem)       <br/>
155  *     - tangential acceleration (Gravity mode)                               <br/>
156  *     - radial acceleration (Gravity mode)                                   <br/>
157  *     - radius direction (Radius mode) (Particle Designer supports outwards to inwards direction only) <br/>
158  *     It is possible to customize any of the above mentioned properties in runtime. Example:   <br/>
159  * </p>
160  * @class
161  * @extends cc.Node
162  *
163  * @property {Boolean}              opacityModifyRGB    - Indicate whether the alpha value modify color.
164  * @property {cc.SpriteBatchNode}   batchNode           - Weak reference to the sprite batch node.
165  * @property {Boolean}              active              - <@readonly> Indicate whether the particle system is activated.
166  * @property {Number}               shapeType           - ShapeType of ParticleSystem : cc.ParticleSystem.BALL_SHAPE | cc.ParticleSystem.STAR_SHAPE.
167  * @property {Number}               atlasIndex          - Index of system in batch node array.
168  * @property {Number}               particleCount       - Current quantity of particles that are being simulated.
169  * @property {Number}               duration            - How many seconds the emitter wil run. -1 means 'forever'
170  * @property {cc.Point}             sourcePos           - Source position of the emitter.
171  * @property {cc.Point}             posVar              - Variation of source position.
172  * @property {Number}               life                - Life of each particle setter.
173  * @property {Number}               lifeVar             - Variation of life.
174  * @property {Number}               angle               - Angle of each particle setter.
175  * @property {Number}               angleVar            - Variation of angle of each particle setter.
176  * @property {Number}               startSize           - Start size in pixels of each particle.
177  * @property {Number}               startSizeVar        - Variation of start size in pixels.
178  * @property {Number}               endSize             - End size in pixels of each particle.
179  * @property {Number}               endSizeVar          - Variation of end size in pixels.
180  * @property {Number}               startSpin           - Start angle of each particle.
181  * @property {Number}               startSpinVar        - Variation of start angle.
182  * @property {Number}               endSpin             - End angle of each particle.
183  * @property {Number}               endSpinVar          - Variation of end angle.
184  * @property {cc.Point}             gravity             - Gravity of the emitter.
185  * @property {cc.Point}             speed               - Speed of the emitter.
186  * @property {cc.Point}             speedVar            - Variation of the speed.
187  * @property {Number}               tangentialAccel     - Tangential acceleration of each particle. Only available in 'Gravity' mode.
188  * @property {Number}               tangentialAccelVar  - Variation of the tangential acceleration.
189  * @property {Number}               tangentialAccel     - Radial acceleration of each particle. Only available in 'Gravity' mode.
190  * @property {Number}               tangentialAccelVar  - Variation of the radial acceleration.
191  * @property {Boolean}              rotationIsDir       - Indicate whether the rotation of each particle equals to its direction. Only available in 'Gravity' mode.
192  * @property {Number}               startRadius         - Starting radius of the particles. Only available in 'Radius' mode.
193  * @property {Number}               startRadiusVar      - Variation of the starting radius.
194  * @property {Number}               endRadius           - Ending radius of the particles. Only available in 'Radius' mode.
195  * @property {Number}               endRadiusVar        - Variation of the ending radius.
196  * @property {Number}               rotatePerS          - Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode.
197  * @property {Number}               rotatePerSVar       - Variation of the degress to rotate a particle around the source pos per second.
198  * @property {cc.Color}             startColor          - Start color of each particle.
199  * @property {cc.Color}             startColorVar       - Variation of the start color.
200  * @property {cc.Color}             endColor            - Ending color of each particle.
201  * @property {cc.Color}             endColorVar         - Variation of the end color.
202  * @property {Number}               emissionRate        - Emission rate of the particles.
203  * @property {Number}               emitterMode         - Emitter modes: CCParticleSystem.MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration; CCParticleSystem.MODE_RADIUS: uses radius movement + rotation.
204  * @property {Number}               positionType        - Particles movement type: cc.ParticleSystem.TYPE_FREE | cc.ParticleSystem.TYPE_GROUPED.
205  * @property {Number}               totalParticles      - Maximum particles of the system.
206  * @property {Boolean}              autoRemoveOnFinish  - Indicate whether the node will be auto-removed when it has no particles left.
207  * @property {cc.Texture2D|HTMLImageElement|HTMLCanvasElement}         texture             - Texture of Particle System.
208  *
209  * @example
210  *  emitter.radialAccel = 15;
211  *  emitter.startSpin = 0;
212  */
213 cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{
214     _className:"ParticleSystem",
215     //***********variables*************
216     _plistFile: "",
217     //! time elapsed since the start of the system (in seconds)
218     _elapsed: 0,
219     _dontTint: false,
220 
221     // Different modes
222     //! Mode A:Gravity + Tangential Accel + Radial Accel
223     modeA: null,
224     //! Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode)
225     modeB: null,
226 
227     //private POINTZERO for ParticleSystem
228     _pointZeroForParticle: cc.p(0, 0),
229 
230     //! Array of particles
231     _particles: null,
232 
233     // color modulate
234     //  BOOL colorModulate;
235 
236     //! How many particles can be emitted per second
237     _emitCounter: 0,
238     //!  particle idx
239     _particleIdx: 0,
240 
241     _batchNode: null,
242     atlasIndex: 0,
243 
244     //true if scaled or rotated
245     _transformSystemDirty: false,
246     _allocatedParticles: 0,
247 
248     _isActive: false,
249     particleCount: 0,
250     duration: 0,
251     _sourcePosition: null,
252     _posVar: null,
253     life: 0,
254     lifeVar: 0,
255     angle: 0,
256     angleVar: 0,
257     startSize: 0,
258     startSizeVar: 0,
259     endSize: 0,
260     endSizeVar: 0,
261     _startColor: null,
262     _startColorVar: null,
263     _endColor: null,
264     _endColorVar: null,
265     startSpin: 0,
266     startSpinVar: 0,
267     endSpin: 0,
268     endSpinVar: 0,
269     emissionRate: 0,
270     _totalParticles: 0,
271     _texture: null,
272     _blendFunc: null,
273     _opacityModifyRGB: false,
274     positionType: null,
275     autoRemoveOnFinish: false,
276     emitterMode: 0,
277 
278     _textureLoaded: null,
279 
280     /**
281      * <p> return the string found by key in dict. <br/>
282      *    This plist files can be create manually or with Particle Designer:<br/>
283      *    http://particledesigner.71squared.com/<br/>
284      * </p>
285      * Constructor of cc.ParticleSystem
286      * @param {String|Number} plistFile
287      */
288     ctor:function (plistFile) {
289         cc.Node.prototype.ctor.call(this);
290         this.emitterMode = cc.ParticleSystem.MODE_GRAVITY;
291         this.modeA = new cc.ParticleSystem.ModeA();
292         this.modeB = new cc.ParticleSystem.ModeB();
293         this._blendFunc = {src:cc.BLEND_SRC, dst:cc.BLEND_DST};
294 
295         this._particles = [];
296         this._sourcePosition = cc.p(0, 0);
297         this._posVar = cc.p(0, 0);
298 
299         this._startColor = cc.color(255, 255, 255, 255);
300         this._startColorVar = cc.color(255, 255, 255, 255);
301         this._endColor = cc.color(255, 255, 255, 255);
302         this._endColorVar = cc.color(255, 255, 255, 255);
303 
304         this._plistFile = "";
305         this._elapsed = 0;
306         this._dontTint = false;
307         this._pointZeroForParticle = cc.p(0, 0);
308         this._emitCounter = 0;
309         this._particleIdx = 0;
310         this._batchNode = null;
311         this.atlasIndex = 0;
312 
313         this._transformSystemDirty = false;
314         this._allocatedParticles = 0;
315         this._isActive = false;
316         this.particleCount = 0;
317         this.duration = 0;
318         this.life = 0;
319         this.lifeVar = 0;
320         this.angle = 0;
321         this.angleVar = 0;
322         this.startSize = 0;
323         this.startSizeVar = 0;
324         this.endSize = 0;
325         this.endSizeVar = 0;
326 
327         this.startSpin = 0;
328         this.startSpinVar = 0;
329         this.endSpin = 0;
330         this.endSpinVar = 0;
331         this.emissionRate = 0;
332         this._totalParticles = 0;
333         this._texture = null;
334         this._opacityModifyRGB = false;
335         this.positionType = cc.ParticleSystem.TYPE_FREE;
336         this.autoRemoveOnFinish = false;
337 
338         this._textureLoaded = true;
339 
340         if (!plistFile || cc.isNumber(plistFile)) {
341             var ton = plistFile || 100;
342             this.setDrawMode(cc.ParticleSystem.TEXTURE_MODE);
343             this.initWithTotalParticles(ton);
344         } else if (cc.isString(plistFile)) {
345             this.initWithFile(plistFile);
346         } else if (cc.isObject(plistFile)) {
347             this.initWithDictionary(plistFile, "");
348         }
349     },
350 
351     _createRenderCmd: function(){
352         if(cc._renderType === cc.game.RENDER_TYPE_CANVAS)
353             return new cc.ParticleSystem.CanvasRenderCmd(this);
354         else
355             return new cc.ParticleSystem.WebGLRenderCmd(this);
356     },
357 
358     /**
359      * This is a hack function for performance, it's only available on Canvas mode. <br/>
360      * It's very expensive to change color on Canvas mode, so if set it to true, particle system will ignore the changing color operation.
361      * @param {boolean} ignore
362      */
363     ignoreColor: function(ignore){
364        this._dontTint = ignore;
365     },
366 
367     /**
368      * <p> initializes the texture with a rectangle measured Points<br/>
369      * pointRect should be in Texture coordinates, not pixel coordinates
370      * </p>
371      * @param {cc.Rect} pointRect
372      */
373     initTexCoordsWithRect:function (pointRect) {
374         this._renderCmd.initTexCoordsWithRect(pointRect);
375     },
376 
377     /**
378      * return weak reference to the cc.SpriteBatchNode that renders the cc.Sprite
379      * @return {cc.ParticleBatchNode}
380      */
381     getBatchNode:function () {
382         return this._batchNode;
383     },
384 
385     /**
386      *  set weak reference to the cc.SpriteBatchNode that renders the cc.Sprite
387      * @param {cc.ParticleBatchNode} batchNode
388      */
389     setBatchNode:function (batchNode) {
390         this._renderCmd.setBatchNode(batchNode);
391     },
392 
393     /**
394      * return index of system in batch node array
395      * @return {Number}
396      */
397     getAtlasIndex:function () {
398         return this.atlasIndex;
399     },
400 
401     /**
402      * set index of system in batch node array
403      * @param {Number} atlasIndex
404      */
405     setAtlasIndex:function (atlasIndex) {
406         this.atlasIndex = atlasIndex;
407     },
408 
409     /**
410      * Return DrawMode of ParticleSystem   (Canvas Mode only)
411      * @return {Number}
412      */
413     getDrawMode:function () {
414         return this._renderCmd.getDrawMode();
415     },
416 
417     /**
418      * DrawMode of ParticleSystem setter   (Canvas Mode only)
419      * @param {Number} drawMode
420      */
421     setDrawMode:function (drawMode) {
422         this._renderCmd.setDrawMode(drawMode);
423     },
424 
425     /**
426      * Return ShapeType of ParticleSystem  (Canvas Mode only)
427      * @return {Number}
428      */
429     getShapeType:function () {
430         return this._renderCmd.getShapeType();
431     },
432 
433     /**
434      * ShapeType of ParticleSystem setter  (Canvas Mode only)
435      * @param {Number} shapeType
436      */
437     setShapeType:function (shapeType) {
438         this._renderCmd.setShapeType(shapeType);
439     },
440 
441     /**
442      * Return ParticleSystem is active
443      * @return {Boolean}
444      */
445     isActive:function () {
446         return this._isActive;
447     },
448 
449     /**
450      * Quantity of particles that are being simulated at the moment
451      * @return {Number}
452      */
453     getParticleCount:function () {
454         return this.particleCount;
455     },
456 
457     /**
458      * Quantity of particles setter
459      * @param {Number} particleCount
460      */
461     setParticleCount:function (particleCount) {
462         this.particleCount = particleCount;
463     },
464 
465     /**
466      * How many seconds the emitter wil run. -1 means 'forever'
467      * @return {Number}
468      */
469     getDuration:function () {
470         return this.duration;
471     },
472 
473     /**
474      * set run seconds of the emitter
475      * @param {Number} duration
476      */
477     setDuration:function (duration) {
478         this.duration = duration;
479     },
480 
481     /**
482      * Return sourcePosition of the emitter
483      * @return {cc.Point | Object}
484      */
485     getSourcePosition:function () {
486         return {x: this._sourcePosition.x, y: this._sourcePosition.y};
487     },
488 
489     /**
490      * sourcePosition of the emitter setter
491      * @param sourcePosition
492      */
493     setSourcePosition:function (sourcePosition) {
494         this._sourcePosition = sourcePosition;
495     },
496 
497     /**
498      * Return Position variance of the emitter
499      * @return {cc.Point | Object}
500      */
501     getPosVar:function () {
502         return {x: this._posVar.x, y: this._posVar.y};
503     },
504 
505     /**
506      * Position variance of the emitter setter
507      * @param {cc.Point} posVar
508      */
509     setPosVar:function (posVar) {
510         this._posVar = posVar;
511     },
512 
513     /**
514      * Return life of each particle
515      * @return {Number}
516      */
517     getLife:function () {
518         return this.life;
519     },
520 
521     /**
522      * life of each particle setter
523      * @param {Number} life
524      */
525     setLife:function (life) {
526         this.life = life;
527     },
528 
529     /**
530      * Return life variance of each particle
531      * @return {Number}
532      */
533     getLifeVar:function () {
534         return this.lifeVar;
535     },
536 
537     /**
538      * life variance of each particle setter
539      * @param {Number} lifeVar
540      */
541     setLifeVar:function (lifeVar) {
542         this.lifeVar = lifeVar;
543     },
544 
545     /**
546      * Return angle of each particle
547      * @return {Number}
548      */
549     getAngle:function () {
550         return this.angle;
551     },
552 
553     /**
554      * angle of each particle setter
555      * @param {Number} angle
556      */
557     setAngle:function (angle) {
558         this.angle = angle;
559     },
560 
561     /**
562      * Return angle variance of each particle
563      * @return {Number}
564      */
565     getAngleVar:function () {
566         return this.angleVar;
567     },
568 
569     /**
570      * angle variance of each particle setter
571      * @param angleVar
572      */
573     setAngleVar:function (angleVar) {
574         this.angleVar = angleVar;
575     },
576 
577     // mode A
578     /**
579      * Return Gravity of emitter
580      * @return {cc.Point}
581      */
582     getGravity:function () {
583         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
584             cc.log("cc.ParticleBatchNode.getGravity() : Particle Mode should be Gravity");
585         var locGravity = this.modeA.gravity;
586         return cc.p(locGravity.x, locGravity.y);
587     },
588 
589     /**
590      * Gravity of emitter setter
591      * @param {cc.Point} gravity
592      */
593     setGravity:function (gravity) {
594         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
595             cc.log("cc.ParticleBatchNode.setGravity() : Particle Mode should be Gravity");
596         this.modeA.gravity = gravity;
597     },
598 
599     /**
600      * Return Speed of each particle
601      * @return {Number}
602      */
603     getSpeed:function () {
604         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
605             cc.log("cc.ParticleBatchNode.getSpeed() : Particle Mode should be Gravity");
606         return this.modeA.speed;
607     },
608 
609     /**
610      * Speed of each particle setter
611      * @param {Number} speed
612      */
613     setSpeed:function (speed) {
614         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
615             cc.log("cc.ParticleBatchNode.setSpeed() : Particle Mode should be Gravity");
616         this.modeA.speed = speed;
617     },
618 
619     /**
620      * return speed variance of each particle. Only available in 'Gravity' mode.
621      * @return {Number}
622      */
623     getSpeedVar:function () {
624         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
625             cc.log("cc.ParticleBatchNode.getSpeedVar() : Particle Mode should be Gravity");
626         return this.modeA.speedVar;
627     },
628 
629     /**
630      * speed variance of each particle setter. Only available in 'Gravity' mode.
631      * @param {Number} speedVar
632      */
633     setSpeedVar:function (speedVar) {
634         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
635             cc.log("cc.ParticleBatchNode.setSpeedVar() : Particle Mode should be Gravity");
636         this.modeA.speedVar = speedVar;
637     },
638 
639     /**
640      * Return tangential acceleration of each particle. Only available in 'Gravity' mode.
641      * @return {Number}
642      */
643     getTangentialAccel:function () {
644         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
645             cc.log("cc.ParticleBatchNode.getTangentialAccel() : Particle Mode should be Gravity");
646         return this.modeA.tangentialAccel;
647     },
648 
649     /**
650      * Tangential acceleration of each particle setter. Only available in 'Gravity' mode.
651      * @param {Number} tangentialAccel
652      */
653     setTangentialAccel:function (tangentialAccel) {
654         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
655             cc.log("cc.ParticleBatchNode.setTangentialAccel() : Particle Mode should be Gravity");
656         this.modeA.tangentialAccel = tangentialAccel;
657     },
658 
659     /**
660      * Return tangential acceleration variance of each particle. Only available in 'Gravity' mode.
661      * @return {Number}
662      */
663     getTangentialAccelVar:function () {
664         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
665             cc.log("cc.ParticleBatchNode.getTangentialAccelVar() : Particle Mode should be Gravity");
666         return this.modeA.tangentialAccelVar;
667     },
668 
669     /**
670      * tangential acceleration variance of each particle setter. Only available in 'Gravity' mode.
671      * @param {Number} tangentialAccelVar
672      */
673     setTangentialAccelVar:function (tangentialAccelVar) {
674         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
675             cc.log("cc.ParticleBatchNode.setTangentialAccelVar() : Particle Mode should be Gravity");
676         this.modeA.tangentialAccelVar = tangentialAccelVar;
677     },
678 
679     /**
680      * Return radial acceleration of each particle. Only available in 'Gravity' mode.
681      * @return {Number}
682      */
683     getRadialAccel:function () {
684         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
685             cc.log("cc.ParticleBatchNode.getRadialAccel() : Particle Mode should be Gravity");
686         return this.modeA.radialAccel;
687     },
688 
689     /**
690      * radial acceleration of each particle setter. Only available in 'Gravity' mode.
691      * @param {Number} radialAccel
692      */
693     setRadialAccel:function (radialAccel) {
694         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
695             cc.log("cc.ParticleBatchNode.setRadialAccel() : Particle Mode should be Gravity");
696         this.modeA.radialAccel = radialAccel;
697     },
698 
699     /**
700      * Return radial acceleration variance of each particle. Only available in 'Gravity' mode.
701      * @return {Number}
702      */
703     getRadialAccelVar:function () {
704         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
705             cc.log("cc.ParticleBatchNode.getRadialAccelVar() : Particle Mode should be Gravity");
706         return this.modeA.radialAccelVar;
707     },
708 
709     /**
710      * radial acceleration variance of each particle setter. Only available in 'Gravity' mode.
711      * @param {Number} radialAccelVar
712      */
713     setRadialAccelVar:function (radialAccelVar) {
714         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
715             cc.log("cc.ParticleBatchNode.setRadialAccelVar() : Particle Mode should be Gravity");
716         this.modeA.radialAccelVar = radialAccelVar;
717     },
718 
719     /**
720      * get the rotation of each particle to its direction Only available in 'Gravity' mode.
721      * @returns {boolean}
722      */
723     getRotationIsDir: function(){
724         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
725             cc.log("cc.ParticleBatchNode.getRotationIsDir() : Particle Mode should be Gravity");
726         return this.modeA.rotationIsDir;
727     },
728 
729     /**
730      * set the rotation of each particle to its direction Only available in 'Gravity' mode.
731      * @param {boolean} t
732      */
733     setRotationIsDir: function(t){
734         if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY)
735             cc.log("cc.ParticleBatchNode.setRotationIsDir() : Particle Mode should be Gravity");
736         this.modeA.rotationIsDir = t;
737     },
738 
739     // mode B
740     /**
741      * Return starting radius of the particles. Only available in 'Radius' mode.
742      * @return {Number}
743      */
744     getStartRadius:function () {
745         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
746             cc.log("cc.ParticleBatchNode.getStartRadius() : Particle Mode should be Radius");
747         return this.modeB.startRadius;
748     },
749 
750     /**
751      * starting radius of the particles setter. Only available in 'Radius' mode.
752      * @param {Number} startRadius
753      */
754     setStartRadius:function (startRadius) {
755         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
756             cc.log("cc.ParticleBatchNode.setStartRadius() : Particle Mode should be Radius");
757         this.modeB.startRadius = startRadius;
758     },
759 
760     /**
761      * Return starting radius variance of the particles. Only available in 'Radius' mode.
762      * @return {Number}
763      */
764     getStartRadiusVar:function () {
765         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
766             cc.log("cc.ParticleBatchNode.getStartRadiusVar() : Particle Mode should be Radius");
767         return this.modeB.startRadiusVar;
768     },
769 
770     /**
771      * starting radius variance of the particles setter. Only available in 'Radius' mode.
772      * @param {Number} startRadiusVar
773      */
774     setStartRadiusVar:function (startRadiusVar) {
775         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
776             cc.log("cc.ParticleBatchNode.setStartRadiusVar() : Particle Mode should be Radius");
777         this.modeB.startRadiusVar = startRadiusVar;
778     },
779 
780     /**
781      * Return ending radius of the particles. Only available in 'Radius' mode.
782      * @return {Number}
783      */
784     getEndRadius:function () {
785         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
786             cc.log("cc.ParticleBatchNode.getEndRadius() : Particle Mode should be Radius");
787         return this.modeB.endRadius;
788     },
789 
790     /**
791      * ending radius of the particles setter. Only available in 'Radius' mode.
792      * @param {Number} endRadius
793      */
794     setEndRadius:function (endRadius) {
795         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
796             cc.log("cc.ParticleBatchNode.setEndRadius() : Particle Mode should be Radius");
797         this.modeB.endRadius = endRadius;
798     },
799 
800     /**
801      * Return ending radius variance of the particles. Only available in 'Radius' mode.
802      * @return {Number}
803      */
804     getEndRadiusVar:function () {
805         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
806             cc.log("cc.ParticleBatchNode.getEndRadiusVar() : Particle Mode should be Radius");
807         return this.modeB.endRadiusVar;
808     },
809 
810     /**
811      * ending radius variance of the particles setter. Only available in 'Radius' mode.
812      * @param endRadiusVar
813      */
814     setEndRadiusVar:function (endRadiusVar) {
815         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
816             cc.log("cc.ParticleBatchNode.setEndRadiusVar() : Particle Mode should be Radius");
817         this.modeB.endRadiusVar = endRadiusVar;
818     },
819 
820     /**
821      * get Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode.
822      * @return {Number}
823      */
824     getRotatePerSecond:function () {
825         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
826             cc.log("cc.ParticleBatchNode.getRotatePerSecond() : Particle Mode should be Radius");
827         return this.modeB.rotatePerSecond;
828     },
829 
830     /**
831      * set Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode.
832      * @param {Number} degrees
833      */
834     setRotatePerSecond:function (degrees) {
835         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
836             cc.log("cc.ParticleBatchNode.setRotatePerSecond() : Particle Mode should be Radius");
837         this.modeB.rotatePerSecond = degrees;
838     },
839 
840     /**
841      * Return Variance in degrees for rotatePerSecond. Only available in 'Radius' mode.
842      * @return {Number}
843      */
844     getRotatePerSecondVar:function () {
845         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
846             cc.log("cc.ParticleBatchNode.getRotatePerSecondVar() : Particle Mode should be Radius");
847         return this.modeB.rotatePerSecondVar;
848     },
849 
850     /**
851      * Variance in degrees for rotatePerSecond setter. Only available in 'Radius' mode.
852      * @param degrees
853      */
854     setRotatePerSecondVar:function (degrees) {
855         if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS)
856             cc.log("cc.ParticleBatchNode.setRotatePerSecondVar() : Particle Mode should be Radius");
857         this.modeB.rotatePerSecondVar = degrees;
858     },
859     //////////////////////////////////////////////////////////////////////////
860 
861     //don't use a transform matrix, this is faster
862     setScale:function (scale, scaleY) {
863         this._transformSystemDirty = true;
864         cc.Node.prototype.setScale.call(this, scale, scaleY);
865     },
866 
867     setRotation:function (newRotation) {
868         this._transformSystemDirty = true;
869         cc.Node.prototype.setRotation.call(this, newRotation);
870     },
871 
872     setScaleX:function (newScaleX) {
873         this._transformSystemDirty = true;
874         cc.Node.prototype.setScaleX.call(this, newScaleX);
875     },
876 
877     setScaleY:function (newScaleY) {
878         this._transformSystemDirty = true;
879         cc.Node.prototype.setScaleY.call(this, newScaleY);
880     },
881 
882     /**
883      * get start size in pixels of each particle
884      * @return {Number}
885      */
886     getStartSize:function () {
887         return this.startSize;
888     },
889 
890     /**
891      * set start size in pixels of each particle
892      * @param {Number} startSize
893      */
894     setStartSize:function (startSize) {
895         this.startSize = startSize;
896     },
897 
898     /**
899      * get size variance in pixels of each particle
900      * @return {Number}
901      */
902     getStartSizeVar:function () {
903         return this.startSizeVar;
904     },
905 
906     /**
907      * set size variance in pixels of each particle
908      * @param {Number} startSizeVar
909      */
910     setStartSizeVar:function (startSizeVar) {
911         this.startSizeVar = startSizeVar;
912     },
913 
914     /**
915      * get end size in pixels of each particle
916      * @return {Number}
917      */
918     getEndSize:function () {
919         return this.endSize;
920     },
921 
922     /**
923      * set end size in pixels of each particle
924      * @param endSize
925      */
926     setEndSize:function (endSize) {
927         this.endSize = endSize;
928     },
929 
930     /**
931      * get end size variance in pixels of each particle
932      * @return {Number}
933      */
934     getEndSizeVar:function () {
935         return this.endSizeVar;
936     },
937 
938     /**
939      * set end size variance in pixels of each particle
940      * @param {Number} endSizeVar
941      */
942     setEndSizeVar:function (endSizeVar) {
943         this.endSizeVar = endSizeVar;
944     },
945 
946     /**
947      * set start color of each particle
948      * @return {cc.Color}
949      */
950     getStartColor:function () {
951         return cc.color(this._startColor.r, this._startColor.g, this._startColor.b, this._startColor.a);
952     },
953 
954     /**
955      * get start color of each particle
956      * @param {cc.Color} startColor
957      */
958     setStartColor:function (startColor) {
959         this._startColor = cc.color(startColor);
960     },
961 
962     /**
963      * get start color variance of each particle
964      * @return {cc.Color}
965      */
966     getStartColorVar:function () {
967         return cc.color(this._startColorVar.r, this._startColorVar.g, this._startColorVar.b, this._startColorVar.a);
968     },
969 
970     /**
971      * set start color variance of each particle
972      * @param {cc.Color} startColorVar
973      */
974     setStartColorVar:function (startColorVar) {
975         this._startColorVar = cc.color(startColorVar);
976     },
977 
978     /**
979      * get end color and end color variation of each particle
980      * @return {cc.Color}
981      */
982     getEndColor:function () {
983         return cc.color(this._endColor.r, this._endColor.g, this._endColor.b, this._endColor.a);
984     },
985 
986     /**
987      * set end color and end color variation of each particle
988      * @param {cc.Color} endColor
989      */
990     setEndColor:function (endColor) {
991         this._endColor = cc.color(endColor);
992     },
993 
994     /**
995      * get end color variance of each particle
996      * @return {cc.Color}
997      */
998     getEndColorVar:function () {
999         return cc.color(this._endColorVar.r, this._endColorVar.g, this._endColorVar.b, this._endColorVar.a);
1000     },
1001 
1002     /**
1003      * set end color variance of each particle
1004      * @param {cc.Color} endColorVar
1005      */
1006     setEndColorVar:function (endColorVar) {
1007         this._endColorVar = cc.color(endColorVar);
1008     },
1009 
1010     /**
1011      * get initial angle of each particle
1012      * @return {Number}
1013      */
1014     getStartSpin:function () {
1015         return this.startSpin;
1016     },
1017 
1018     /**
1019      * set initial angle of each particle
1020      * @param {Number} startSpin
1021      */
1022     setStartSpin:function (startSpin) {
1023         this.startSpin = startSpin;
1024     },
1025 
1026     /**
1027      * get initial angle variance of each particle
1028      * @return {Number}
1029      */
1030     getStartSpinVar:function () {
1031         return this.startSpinVar;
1032     },
1033 
1034     /**
1035      * set initial angle variance of each particle
1036      * @param {Number} startSpinVar
1037      */
1038     setStartSpinVar:function (startSpinVar) {
1039         this.startSpinVar = startSpinVar;
1040     },
1041 
1042     /**
1043      * get end angle of each particle
1044      * @return {Number}
1045      */
1046     getEndSpin:function () {
1047         return this.endSpin;
1048     },
1049 
1050     /**
1051      * set end angle of each particle
1052      * @param {Number} endSpin
1053      */
1054     setEndSpin:function (endSpin) {
1055         this.endSpin = endSpin;
1056     },
1057 
1058     /**
1059      * get end angle variance of each particle
1060      * @return {Number}
1061      */
1062     getEndSpinVar:function () {
1063         return this.endSpinVar;
1064     },
1065 
1066     /**
1067      * set end angle variance of each particle
1068      * @param {Number} endSpinVar
1069      */
1070     setEndSpinVar:function (endSpinVar) {
1071         this.endSpinVar = endSpinVar;
1072     },
1073 
1074     /**
1075      * get emission rate of the particles
1076      * @return {Number}
1077      */
1078     getEmissionRate:function () {
1079         return this.emissionRate;
1080     },
1081 
1082     /**
1083      * set emission rate of the particles
1084      * @param {Number} emissionRate
1085      */
1086     setEmissionRate:function (emissionRate) {
1087         this.emissionRate = emissionRate;
1088     },
1089 
1090     /**
1091      * get maximum particles of the system
1092      * @return {Number}
1093      */
1094     getTotalParticles:function () {
1095         return this._totalParticles;
1096     },
1097 
1098     /**
1099      * set maximum particles of the system
1100      * @param {Number} tp totalParticles
1101      */
1102     setTotalParticles:function (tp) {
1103         this._renderCmd.setTotalParticles(tp);
1104     },
1105 
1106     /**
1107      * get Texture of Particle System
1108      * @return {cc.Texture2D}
1109      */
1110     getTexture:function () {
1111         return this._texture;
1112     },
1113 
1114     /**
1115      * set Texture of Particle System
1116      * @param {cc.Texture2D } texture
1117      */
1118     setTexture:function (texture) {
1119         if(!texture)
1120             return;
1121 
1122         if(texture.isLoaded()){
1123             this.setTextureWithRect(texture, cc.rect(0, 0, texture.width, texture.height));
1124         } else {
1125             this._textureLoaded = false;
1126             texture.addEventListener("load", function(sender){
1127                 this._textureLoaded = true;
1128                 this.setTextureWithRect(sender, cc.rect(0, 0, sender.width, sender.height));
1129             }, this);
1130         }
1131     },
1132 
1133     /** conforms to CocosNodeTexture protocol */
1134     /**
1135      * get BlendFunc of Particle System
1136      * @return {cc.BlendFunc}
1137      */
1138     getBlendFunc:function () {
1139         return this._blendFunc;
1140     },
1141 
1142     /**
1143      * set BlendFunc of Particle System
1144      * @param {Number} src
1145      * @param {Number} dst
1146      */
1147     setBlendFunc:function (src, dst) {
1148         if (dst === undefined) {
1149             if (this._blendFunc !== src) {
1150                 this._blendFunc = src;
1151                 this._updateBlendFunc();
1152             }
1153         } else {
1154             if (this._blendFunc.src !== src || this._blendFunc.dst !== dst) {
1155                 this._blendFunc = {src:src, dst:dst};
1156                 this._updateBlendFunc();
1157             }
1158         }
1159     },
1160 
1161     /**
1162      * does the alpha value modify color getter
1163      * @return {Boolean}
1164      */
1165     isOpacityModifyRGB:function () {
1166         return this._opacityModifyRGB;
1167     },
1168 
1169     /**
1170      * does the alpha value modify color setter
1171      * @param newValue
1172      */
1173     setOpacityModifyRGB:function (newValue) {
1174         this._opacityModifyRGB = newValue;
1175     },
1176 
1177     /**
1178      * <p>whether or not the particles are using blend additive.<br/>
1179      *     If enabled, the following blending function will be used.<br/>
1180      * </p>
1181      * @return {Boolean}
1182      * @example
1183      *    source blend function = GL_SRC_ALPHA;
1184      *    dest blend function = GL_ONE;
1185      */
1186     isBlendAdditive:function () {
1187         return (( this._blendFunc.src === cc.SRC_ALPHA && this._blendFunc.dst === cc.ONE) || (this._blendFunc.src === cc.ONE && this._blendFunc.dst === cc.ONE));
1188     },
1189 
1190     /**
1191      * <p>whether or not the particles are using blend additive.<br/>
1192      *     If enabled, the following blending function will be used.<br/>
1193      * </p>
1194      * @param {Boolean} isBlendAdditive
1195      */
1196     setBlendAdditive:function (isBlendAdditive) {
1197         var locBlendFunc = this._blendFunc;
1198         if (isBlendAdditive) {
1199             locBlendFunc.src = cc.SRC_ALPHA;
1200             locBlendFunc.dst = cc.ONE;
1201         } else {
1202             this._renderCmd._setBlendAdditive();
1203         }
1204     },
1205 
1206     /**
1207      * get particles movement type: Free or Grouped
1208      * @return {Number}
1209      */
1210     getPositionType:function () {
1211         return this.positionType;
1212     },
1213 
1214     /**
1215      * set particles movement type: Free or Grouped
1216      * @param {Number} positionType
1217      */
1218     setPositionType:function (positionType) {
1219         this.positionType = positionType;
1220     },
1221 
1222     /**
1223      *  <p> return whether or not the node will be auto-removed when it has no particles left.<br/>
1224      *      By default it is false.<br/>
1225      *  </p>
1226      * @return {Boolean}
1227      */
1228     isAutoRemoveOnFinish:function () {
1229         return this.autoRemoveOnFinish;
1230     },
1231 
1232     /**
1233      *  <p> set whether or not the node will be auto-removed when it has no particles left.<br/>
1234      *      By default it is false.<br/>
1235      *  </p>
1236      * @param {Boolean} isAutoRemoveOnFinish
1237      */
1238     setAutoRemoveOnFinish:function (isAutoRemoveOnFinish) {
1239         this.autoRemoveOnFinish = isAutoRemoveOnFinish;
1240     },
1241 
1242     /**
1243      * return kind of emitter modes
1244      * @return {Number}
1245      */
1246     getEmitterMode:function () {
1247         return this.emitterMode;
1248     },
1249 
1250     /**
1251      * <p>Switch between different kind of emitter modes:<br/>
1252      *  - CCParticleSystem.MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration<br/>
1253      *  - CCParticleSystem.MODE_RADIUS: uses radius movement + rotation <br/>
1254      *  </p>
1255      * @param {Number} emitterMode
1256      */
1257     setEmitterMode:function (emitterMode) {
1258         this.emitterMode = emitterMode;
1259     },
1260 
1261     /**
1262      * initializes a cc.ParticleSystem
1263      */
1264     init:function () {
1265         return this.initWithTotalParticles(150);
1266     },
1267 
1268     /**
1269      * <p>
1270      *     initializes a CCParticleSystem from a plist file. <br/>
1271      *      This plist files can be creted manually or with Particle Designer:<br/>
1272      *      http://particledesigner.71squared.com/
1273      * </p>
1274      * @param {String} plistFile
1275      * @return {boolean}
1276      */
1277     initWithFile:function (plistFile) {
1278         this._plistFile = plistFile;
1279         var dict = cc.loader.getRes(plistFile);
1280         if(!dict){
1281             cc.log("cc.ParticleSystem.initWithFile(): Particles: file not found");
1282             return false;
1283         }
1284 
1285         // XXX compute path from a path, should define a function somewhere to do it
1286         return this.initWithDictionary(dict, "");
1287     },
1288 
1289     /**
1290      * return bounding box of particle system in world space
1291      * @return {cc.Rect}
1292      */
1293     getBoundingBoxToWorld:function () {
1294         return cc.rect(0, 0, cc._canvas.width, cc._canvas.height);
1295     },
1296 
1297     /**
1298      * initializes a particle system from a NSDictionary and the path from where to load the png
1299      * @param {object} dictionary
1300      * @param {String} dirname
1301      * @return {Boolean}
1302      */
1303     initWithDictionary:function (dictionary, dirname) {
1304         var ret = false;
1305         var buffer = null;
1306         var image = null;
1307         var locValueForKey = this._valueForKey;
1308 
1309         var maxParticles = parseInt(locValueForKey("maxParticles", dictionary));
1310         // self, not super
1311         if (this.initWithTotalParticles(maxParticles)) {
1312             // angle
1313             this.angle = parseFloat(locValueForKey("angle", dictionary));
1314             this.angleVar = parseFloat(locValueForKey("angleVariance", dictionary));
1315 
1316             // duration
1317             this.duration = parseFloat(locValueForKey("duration", dictionary));
1318 
1319             // blend function
1320             this._blendFunc.src = parseInt(locValueForKey("blendFuncSource", dictionary));
1321             this._blendFunc.dst = parseInt(locValueForKey("blendFuncDestination", dictionary));
1322 
1323             // color
1324             var locStartColor = this._startColor;
1325             locStartColor.r = parseFloat(locValueForKey("startColorRed", dictionary)) * 255;
1326             locStartColor.g = parseFloat(locValueForKey("startColorGreen", dictionary)) * 255;
1327             locStartColor.b = parseFloat(locValueForKey("startColorBlue", dictionary)) * 255;
1328             locStartColor.a = parseFloat(locValueForKey("startColorAlpha", dictionary)) * 255;
1329 
1330             var locStartColorVar = this._startColorVar;
1331             locStartColorVar.r = parseFloat(locValueForKey("startColorVarianceRed", dictionary)) * 255;
1332             locStartColorVar.g = parseFloat(locValueForKey("startColorVarianceGreen", dictionary)) * 255;
1333             locStartColorVar.b = parseFloat(locValueForKey("startColorVarianceBlue", dictionary)) * 255;
1334             locStartColorVar.a = parseFloat(locValueForKey("startColorVarianceAlpha", dictionary)) * 255;
1335 
1336             var locEndColor = this._endColor;
1337             locEndColor.r = parseFloat(locValueForKey("finishColorRed", dictionary)) * 255;
1338             locEndColor.g = parseFloat(locValueForKey("finishColorGreen", dictionary)) * 255;
1339             locEndColor.b = parseFloat(locValueForKey("finishColorBlue", dictionary)) * 255;
1340             locEndColor.a = parseFloat(locValueForKey("finishColorAlpha", dictionary)) * 255;
1341 
1342             var locEndColorVar = this._endColorVar;
1343             locEndColorVar.r = parseFloat(locValueForKey("finishColorVarianceRed", dictionary)) * 255;
1344             locEndColorVar.g = parseFloat(locValueForKey("finishColorVarianceGreen", dictionary)) * 255;
1345             locEndColorVar.b = parseFloat(locValueForKey("finishColorVarianceBlue", dictionary)) * 255;
1346             locEndColorVar.a = parseFloat(locValueForKey("finishColorVarianceAlpha", dictionary)) * 255;
1347 
1348             // particle size
1349             this.startSize = parseFloat(locValueForKey("startParticleSize", dictionary));
1350             this.startSizeVar = parseFloat(locValueForKey("startParticleSizeVariance", dictionary));
1351             this.endSize = parseFloat(locValueForKey("finishParticleSize", dictionary));
1352             this.endSizeVar = parseFloat(locValueForKey("finishParticleSizeVariance", dictionary));
1353 
1354             // position
1355             this.setPosition(parseFloat(locValueForKey("sourcePositionx", dictionary)),
1356                               parseFloat(locValueForKey("sourcePositiony", dictionary)));
1357             this._posVar.x = parseFloat(locValueForKey("sourcePositionVariancex", dictionary));
1358             this._posVar.y = parseFloat(locValueForKey("sourcePositionVariancey", dictionary));
1359 
1360             // Spinning
1361             this.startSpin = parseFloat(locValueForKey("rotationStart", dictionary));
1362             this.startSpinVar = parseFloat(locValueForKey("rotationStartVariance", dictionary));
1363             this.endSpin = parseFloat(locValueForKey("rotationEnd", dictionary));
1364             this.endSpinVar = parseFloat(locValueForKey("rotationEndVariance", dictionary));
1365 
1366             this.emitterMode = parseInt(locValueForKey("emitterType", dictionary));
1367 
1368             // Mode A: Gravity + tangential accel + radial accel
1369             if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) {
1370                 var locModeA = this.modeA;
1371                 // gravity
1372                 locModeA.gravity.x = parseFloat(locValueForKey("gravityx", dictionary));
1373                 locModeA.gravity.y = parseFloat(locValueForKey("gravityy", dictionary));
1374 
1375                 // speed
1376                 locModeA.speed = parseFloat(locValueForKey("speed", dictionary));
1377                 locModeA.speedVar = parseFloat(locValueForKey("speedVariance", dictionary));
1378 
1379                 // radial acceleration
1380                 var pszTmp = locValueForKey("radialAcceleration", dictionary);
1381                 locModeA.radialAccel = (pszTmp) ? parseFloat(pszTmp) : 0;
1382 
1383                 pszTmp = locValueForKey("radialAccelVariance", dictionary);
1384                 locModeA.radialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0;
1385 
1386                 // tangential acceleration
1387                 pszTmp = locValueForKey("tangentialAcceleration", dictionary);
1388                 locModeA.tangentialAccel = (pszTmp) ? parseFloat(pszTmp) : 0;
1389 
1390                 pszTmp = locValueForKey("tangentialAccelVariance", dictionary);
1391                 locModeA.tangentialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0;
1392 
1393                 // rotation is dir
1394                 var locRotationIsDir = locValueForKey("rotationIsDir", dictionary).toLowerCase();
1395                 locModeA.rotationIsDir = (locRotationIsDir != null && (locRotationIsDir === "true" || locRotationIsDir === "1"));
1396             } else if (this.emitterMode === cc.ParticleSystem.MODE_RADIUS) {
1397                 // or Mode B: radius movement
1398                 var locModeB = this.modeB;
1399                 locModeB.startRadius = parseFloat(locValueForKey("maxRadius", dictionary));
1400                 locModeB.startRadiusVar = parseFloat(locValueForKey("maxRadiusVariance", dictionary));
1401                 locModeB.endRadius = parseFloat(locValueForKey("minRadius", dictionary));
1402                 locModeB.endRadiusVar = 0;
1403                 locModeB.rotatePerSecond = parseFloat(locValueForKey("rotatePerSecond", dictionary));
1404                 locModeB.rotatePerSecondVar = parseFloat(locValueForKey("rotatePerSecondVariance", dictionary));
1405             } else {
1406                 cc.log("cc.ParticleSystem.initWithDictionary(): Invalid emitterType in config file");
1407                 return false;
1408             }
1409 
1410             // life span
1411             this.life = parseFloat(locValueForKey("particleLifespan", dictionary));
1412             this.lifeVar = parseFloat(locValueForKey("particleLifespanVariance", dictionary));
1413 
1414             // emission Rate
1415             this.emissionRate = this._totalParticles / this.life;
1416 
1417             //don't get the internal texture if a batchNode is used
1418             if (!this._batchNode) {
1419                 // Set a compatible default for the alpha transfer
1420                 this._opacityModifyRGB = false;
1421 
1422                 // texture
1423                 // Try to get the texture from the cache
1424                 var textureName = locValueForKey("textureFileName", dictionary);
1425                 var imgPath = cc.path.changeBasename(this._plistFile, textureName);
1426                 var tex = cc.textureCache.getTextureForKey(imgPath);
1427 
1428                 if (tex) {
1429                     this.setTexture(tex);
1430                 } else {
1431                     var textureData = locValueForKey("textureImageData", dictionary);
1432 
1433                     if (!textureData || textureData.length === 0) {
1434                         tex = cc.textureCache.addImage(imgPath);
1435                         if (!tex)
1436                             return false;
1437                         this.setTexture(tex);
1438                     } else {
1439                         buffer = cc.unzipBase64AsArray(textureData, 1);
1440                         if (!buffer) {
1441                             cc.log("cc.ParticleSystem: error decoding or ungzipping textureImageData");
1442                             return false;
1443                         }
1444 
1445                         var imageFormat = cc.getImageFormatByData(buffer);
1446 
1447                         if(imageFormat !== cc.FMT_TIFF && imageFormat !== cc.FMT_PNG){
1448                             cc.log("cc.ParticleSystem: unknown image format with Data");
1449                             return false;
1450                         }
1451 
1452                         var canvasObj = document.createElement("canvas");
1453                         if(imageFormat === cc.FMT_PNG){
1454                             var myPngObj = new cc.PNGReader(buffer);
1455                             myPngObj.render(canvasObj);
1456                         } else {
1457                             var myTIFFObj = cc.tiffReader;
1458                             myTIFFObj.parseTIFF(buffer,canvasObj);
1459                         }
1460 
1461                         cc.textureCache.cacheImage(imgPath, canvasObj);
1462 
1463                         var addTexture = cc.textureCache.getTextureForKey(imgPath);
1464                         if(!addTexture)
1465                             cc.log("cc.ParticleSystem.initWithDictionary() : error loading the texture");
1466                         this.setTexture(addTexture);
1467                     }
1468                 }
1469             }
1470             ret = true;
1471         }
1472         return ret;
1473     },
1474 
1475     /**
1476      * Initializes a system with a fixed number of particles
1477      * @param {Number} numberOfParticles
1478      * @return {Boolean}
1479      */
1480     initWithTotalParticles:function (numberOfParticles) {
1481         this._totalParticles = numberOfParticles;
1482 
1483         var i, locParticles = this._particles;
1484         locParticles.length = 0;
1485         for(i = 0; i< numberOfParticles; i++){
1486             locParticles[i] = new cc.Particle();
1487         }
1488 
1489         if (!locParticles) {
1490             cc.log("Particle system: not enough memory");
1491             return false;
1492         }
1493         this._allocatedParticles = numberOfParticles;
1494 
1495         if (this._batchNode)
1496             for (i = 0; i < this._totalParticles; i++)
1497                 locParticles[i].atlasIndex = i;
1498 
1499         // default, active
1500         this._isActive = true;
1501 
1502         // default blend function
1503         this._blendFunc.src = cc.BLEND_SRC;
1504         this._blendFunc.dst = cc.BLEND_DST;
1505 
1506         // default movement type;
1507         this.positionType = cc.ParticleSystem.TYPE_FREE;
1508 
1509         // by default be in mode A:
1510         this.emitterMode = cc.ParticleSystem.MODE_GRAVITY;
1511 
1512         // default: modulate
1513         // XXX: not used
1514         //  colorModulate = YES;
1515         this.autoRemoveOnFinish = false;
1516 
1517         //for batchNode
1518         this._transformSystemDirty = false;
1519 
1520         // udpate after action in run!
1521         this.scheduleUpdateWithPriority(1);
1522         this._renderCmd._initWithTotalParticles(numberOfParticles);
1523         return true;
1524     },
1525 
1526     /**
1527      * Unschedules the "update" method.
1528      * @function
1529      * @see scheduleUpdate();
1530      */
1531     destroyParticleSystem:function () {
1532         this.unscheduleUpdate();
1533     },
1534 
1535     /**
1536      * Add a particle to the emitter
1537      * @return {Boolean}
1538      */
1539     addParticle: function () {
1540         if (this.isFull())
1541             return false;
1542 
1543         var particle = this._renderCmd.addParticle();
1544         this.initParticle(particle);
1545         ++this.particleCount;
1546         return true;
1547     },
1548 
1549     /**
1550      * Initializes a particle
1551      * @param {cc.Particle} particle
1552      */
1553     initParticle:function (particle) {
1554         var locRandomMinus11 = cc.randomMinus1To1;
1555         // timeToLive
1556         // no negative life. prevent division by 0
1557         particle.timeToLive = this.life + this.lifeVar * locRandomMinus11();
1558         particle.timeToLive = Math.max(0, particle.timeToLive);
1559 
1560         // position
1561         particle.pos.x = this._sourcePosition.x + this._posVar.x * locRandomMinus11();
1562         particle.pos.y = this._sourcePosition.y + this._posVar.y * locRandomMinus11();
1563 
1564         // Color
1565         var start, end;
1566         var locStartColor = this._startColor, locStartColorVar = this._startColorVar;
1567         var locEndColor = this._endColor, locEndColorVar = this._endColorVar;
1568         start = {
1569             r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 255),
1570             g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 255),
1571             b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 255),
1572             a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 255)
1573         };
1574         end = {
1575             r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 255),
1576             g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 255),
1577             b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 255),
1578             a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 255)
1579         };
1580 
1581         particle.color = start;
1582         var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive;
1583         locParticleDeltaColor.r = (end.r - start.r) / locParticleTimeToLive;
1584         locParticleDeltaColor.g = (end.g - start.g) / locParticleTimeToLive;
1585         locParticleDeltaColor.b = (end.b - start.b) / locParticleTimeToLive;
1586         locParticleDeltaColor.a = (end.a - start.a) / locParticleTimeToLive;
1587 
1588         // size
1589         var startS = this.startSize + this.startSizeVar * locRandomMinus11();
1590         startS = Math.max(0, startS); // No negative value
1591 
1592         particle.size = startS;
1593         if (this.endSize === cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE) {
1594             particle.deltaSize = 0;
1595         } else {
1596             var endS = this.endSize + this.endSizeVar * locRandomMinus11();
1597             endS = Math.max(0, endS); // No negative values
1598             particle.deltaSize = (endS - startS) / locParticleTimeToLive;
1599         }
1600 
1601         // rotation
1602         var startA = this.startSpin + this.startSpinVar * locRandomMinus11();
1603         var endA = this.endSpin + this.endSpinVar * locRandomMinus11();
1604         particle.rotation = startA;
1605         particle.deltaRotation = (endA - startA) / locParticleTimeToLive;
1606 
1607         // position
1608         if (this.positionType === cc.ParticleSystem.TYPE_FREE)
1609             particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle);
1610         else if (this.positionType === cc.ParticleSystem.TYPE_RELATIVE){
1611             particle.startPos.x = this._position.x;
1612             particle.startPos.y = this._position.y;
1613         }
1614 
1615         // direction
1616         var a = cc.degreesToRadians(this.angle + this.angleVar * locRandomMinus11());
1617 
1618         // Mode Gravity: A
1619         if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) {
1620             var locModeA = this.modeA, locParticleModeA = particle.modeA;
1621             var s = locModeA.speed + locModeA.speedVar * locRandomMinus11();
1622 
1623             // direction
1624             locParticleModeA.dir.x = Math.cos(a);
1625             locParticleModeA.dir.y = Math.sin(a);
1626             cc.pMultIn(locParticleModeA.dir, s);
1627 
1628             // radial accel
1629             locParticleModeA.radialAccel = locModeA.radialAccel + locModeA.radialAccelVar * locRandomMinus11();
1630 
1631             // tangential accel
1632             locParticleModeA.tangentialAccel = locModeA.tangentialAccel + locModeA.tangentialAccelVar * locRandomMinus11();
1633 
1634             // rotation is dir
1635             if(locModeA.rotationIsDir)
1636                 particle.rotation = -cc.radiansToDegrees(cc.pToAngle(locParticleModeA.dir));
1637         } else {
1638             // Mode Radius: B
1639             var locModeB = this.modeB, locParitlceModeB = particle.modeB;
1640 
1641             // Set the default diameter of the particle from the source position
1642             var startRadius = locModeB.startRadius + locModeB.startRadiusVar * locRandomMinus11();
1643             var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11();
1644 
1645             locParitlceModeB.radius = startRadius;
1646             locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive;
1647 
1648             locParitlceModeB.angle = a;
1649             locParitlceModeB.degreesPerSecond = cc.degreesToRadians(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11());
1650         }
1651     },
1652 
1653     /**
1654      * stop emitting particles. Running particles will continue to run until they die
1655      */
1656     stopSystem:function () {
1657         this._isActive = false;
1658         this._elapsed = this.duration;
1659         this._emitCounter = 0;
1660     },
1661 
1662     /**
1663      * Kill all living particles.
1664      */
1665     resetSystem:function () {
1666         this._isActive = true;
1667         this._elapsed = 0;
1668         var locParticles = this._particles;
1669         for (this._particleIdx = 0; this._particleIdx < this.particleCount; ++this._particleIdx)
1670             locParticles[this._particleIdx].timeToLive = 0 ;
1671     },
1672 
1673     /**
1674      * whether or not the system is full
1675      * @return {Boolean}
1676      */
1677     isFull:function () {
1678         return (this.particleCount >= this._totalParticles);
1679     },
1680 
1681     /**
1682      * should be overridden by subclasses
1683      * @param {cc.Particle} particle
1684      * @param {cc.Point} newPosition
1685      */
1686     updateQuadWithParticle:function (particle, newPosition) {
1687         this._renderCmd.updateQuadWithParticle(particle, newPosition);
1688     },
1689 
1690     /**
1691      * should be overridden by subclasses
1692      */
1693     postStep:function () {
1694         this._renderCmd.postStep();
1695     },
1696 
1697     /**
1698      * update emitter's status
1699      * @override
1700      * @param {Number} dt delta time
1701      */
1702     update:function (dt) {
1703         if (this._isActive && this.emissionRate) {
1704             var rate = 1.0 / this.emissionRate;
1705             //issue #1201, prevent bursts of particles, due to too high emitCounter
1706             if (this.particleCount < this._totalParticles)
1707                 this._emitCounter += dt;
1708 
1709             while ((this.particleCount < this._totalParticles) && (this._emitCounter > rate)) {
1710                 this.addParticle();
1711                 this._emitCounter -= rate;
1712             }
1713 
1714             this._elapsed += dt;
1715             if (this.duration !== -1 && this.duration < this._elapsed)
1716                 this.stopSystem();
1717         }
1718         this._particleIdx = 0;
1719 
1720         var currentPosition = cc.Particle.TemporaryPoints[0];
1721         if (this.positionType === cc.ParticleSystem.TYPE_FREE) {
1722             cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle));
1723         } else if (this.positionType === cc.ParticleSystem.TYPE_RELATIVE) {
1724             currentPosition.x = this._position.x;
1725             currentPosition.y = this._position.y;
1726         }
1727 
1728         if (this._visible) {
1729             // Used to reduce memory allocation / creation within the loop
1730             var tpa = cc.Particle.TemporaryPoints[1],
1731                 tpb = cc.Particle.TemporaryPoints[2],
1732                 tpc = cc.Particle.TemporaryPoints[3];
1733 
1734             var locParticles = this._particles;
1735             while (this._particleIdx < this.particleCount) {
1736 
1737                 // Reset the working particles
1738                 cc.pZeroIn(tpa);
1739                 cc.pZeroIn(tpb);
1740                 cc.pZeroIn(tpc);
1741 
1742                 var selParticle = locParticles[this._particleIdx];
1743 
1744                 // life
1745                 selParticle.timeToLive -= dt;
1746 
1747                 if (selParticle.timeToLive > 0) {
1748                     // Mode A: gravity, direction, tangential accel & radial accel
1749                     if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) {
1750 
1751                         var tmp = tpc, radial = tpa, tangential = tpb;
1752 
1753                         // radial acceleration
1754                         if (selParticle.pos.x || selParticle.pos.y) {
1755                             cc.pIn(radial, selParticle.pos);
1756                             cc.pNormalizeIn(radial);
1757                         } else {
1758                             cc.pZeroIn(radial);
1759                         }
1760 
1761                         cc.pIn(tangential, radial);
1762                         cc.pMultIn(radial, selParticle.modeA.radialAccel);
1763 
1764                         // tangential acceleration
1765                         var newy = tangential.x;
1766                         tangential.x = -tangential.y;
1767                         tangential.y = newy;
1768 
1769                         cc.pMultIn(tangential, selParticle.modeA.tangentialAccel);
1770 
1771                         cc.pIn(tmp, radial);
1772                         cc.pAddIn(tmp, tangential);
1773                         cc.pAddIn(tmp, this.modeA.gravity);
1774                         cc.pMultIn(tmp, dt);
1775                         cc.pAddIn(selParticle.modeA.dir, tmp);
1776 
1777 
1778                         cc.pIn(tmp, selParticle.modeA.dir);
1779                         cc.pMultIn(tmp, dt);
1780                         cc.pAddIn(selParticle.pos, tmp);
1781                     } else {
1782                         // Mode B: radius movement
1783                         var selModeB = selParticle.modeB;
1784                         // Update the angle and radius of the particle.
1785                         selModeB.angle += selModeB.degreesPerSecond * dt;
1786                         selModeB.radius += selModeB.deltaRadius * dt;
1787 
1788                         selParticle.pos.x = -Math.cos(selModeB.angle) * selModeB.radius;
1789                         selParticle.pos.y = -Math.sin(selModeB.angle) * selModeB.radius;
1790                     }
1791 
1792                     // color
1793                     this._renderCmd._updateDeltaColor(selParticle, dt);
1794 
1795                     // size
1796                     selParticle.size += (selParticle.deltaSize * dt);
1797                     selParticle.size = Math.max(0, selParticle.size);
1798 
1799                     // angle
1800                     selParticle.rotation += (selParticle.deltaRotation * dt);
1801 
1802                     //
1803                     // update values in quad
1804                     //
1805                     var newPos = tpa;
1806                     if (this.positionType === cc.ParticleSystem.TYPE_FREE || this.positionType === cc.ParticleSystem.TYPE_RELATIVE) {
1807                         var diff = tpb;
1808                         cc.pIn(diff, currentPosition);
1809                         cc.pSubIn(diff, selParticle.startPos);
1810 
1811                         cc.pIn(newPos, selParticle.pos);
1812                         cc.pSubIn(newPos, diff);
1813                     } else {
1814                         cc.pIn(newPos, selParticle.pos);
1815                     }
1816 
1817                     // translate newPos to correct position, since matrix transform isn't performed in batchnode
1818                     // don't update the particle with the new position information, it will interfere with the radius and tangential calculations
1819                     if (this._batchNode) {
1820                         newPos.x += this._position.x;
1821                         newPos.y += this._position.y;
1822                     }
1823                     this._renderCmd.updateParticlePosition(selParticle, newPos);
1824 
1825                     // update particle counter
1826                     ++this._particleIdx;
1827                 } else {
1828                     // life < 0
1829                     var currentIndex = selParticle.atlasIndex;
1830                     if(this._particleIdx !== this.particleCount -1){
1831                          var deadParticle = locParticles[this._particleIdx];
1832                         locParticles[this._particleIdx] = locParticles[this.particleCount -1];
1833                         locParticles[this.particleCount -1] = deadParticle;
1834                     }
1835                     if (this._batchNode) {
1836                         //disable the switched particle
1837                         this._batchNode.disableParticle(this.atlasIndex + currentIndex);
1838                         //switch indexes
1839                         locParticles[this.particleCount - 1].atlasIndex = currentIndex;
1840                     }
1841 
1842                     --this.particleCount;
1843                     if (this.particleCount === 0 && this.autoRemoveOnFinish) {
1844                         this.unscheduleUpdate();
1845                         this._parent.removeChild(this, true);
1846                         return;
1847                     }
1848                 }
1849             }
1850             this._transformSystemDirty = false;
1851         }
1852 
1853         if (!this._batchNode)
1854             this.postStep();
1855     },
1856 
1857     /**
1858      * update emitter's status (dt = 0)
1859      */
1860     updateWithNoTime:function () {
1861         this.update(0);
1862     },
1863 
1864     //
1865     // return the string found by key in dict.
1866     // @param {string} key
1867     // @param {object} dict
1868     // @return {String} "" if not found; return the string if found.
1869     // @private
1870     //
1871     _valueForKey:function (key, dict) {
1872         if (dict) {
1873             var pString = dict[key];
1874             return pString != null ? pString : "";
1875         }
1876         return "";
1877     },
1878 
1879     _updateBlendFunc:function () {
1880         if(this._batchNode){
1881             cc.log("Can't change blending functions when the particle is being batched");
1882             return;
1883         }
1884 
1885         var locTexture = this._texture;
1886         if (locTexture && locTexture instanceof cc.Texture2D) {
1887             this._opacityModifyRGB = false;
1888             var locBlendFunc = this._blendFunc;
1889             if (locBlendFunc.src === cc.BLEND_SRC && locBlendFunc.dst === cc.BLEND_DST) {
1890                 if (locTexture.hasPremultipliedAlpha()) {
1891                     this._opacityModifyRGB = true;
1892                 } else {
1893                     locBlendFunc.src = cc.SRC_ALPHA;
1894                     locBlendFunc.dst = cc.ONE_MINUS_SRC_ALPHA;
1895                 }
1896             }
1897         }
1898     },
1899 
1900     /**
1901      * to copy object with deep copy.
1902      * returns a clone of action.
1903      *
1904      * @return {cc.ParticleSystem}
1905      */
1906     clone:function () {
1907         var retParticle = new cc.ParticleSystem();
1908 
1909         // self, not super
1910         if (retParticle.initWithTotalParticles(this.getTotalParticles())) {
1911             // angle
1912             retParticle.setAngle(this.getAngle());
1913             retParticle.setAngleVar(this.getAngleVar());
1914 
1915             // duration
1916             retParticle.setDuration(this.getDuration());
1917 
1918             // blend function
1919             var blend = this.getBlendFunc();
1920             retParticle.setBlendFunc(blend.src,blend.dst);
1921 
1922             // color
1923             retParticle.setStartColor(this.getStartColor());
1924 
1925             retParticle.setStartColorVar(this.getStartColorVar());
1926 
1927             retParticle.setEndColor(this.getEndColor());
1928 
1929             retParticle.setEndColorVar(this.getEndColorVar());
1930 
1931             // this size
1932             retParticle.setStartSize(this.getStartSize());
1933             retParticle.setStartSizeVar(this.getStartSizeVar());
1934             retParticle.setEndSize(this.getEndSize());
1935             retParticle.setEndSizeVar(this.getEndSizeVar());
1936 
1937             // position
1938             retParticle.setPosition(cc.p(this.x, this.y));
1939             retParticle.setPosVar(cc.p(this.getPosVar().x,this.getPosVar().y));
1940 
1941             retParticle.setPositionType(this.getPositionType());
1942 
1943             // Spinning
1944             retParticle.setStartSpin(this.getStartSpin()||0);
1945             retParticle.setStartSpinVar(this.getStartSpinVar()||0);
1946             retParticle.setEndSpin(this.getEndSpin()||0);
1947             retParticle.setEndSpinVar(this.getEndSpinVar()||0);
1948 
1949             retParticle.setEmitterMode(this.getEmitterMode());
1950 
1951             // Mode A: Gravity + tangential accel + radial accel
1952             if (this.getEmitterMode() === cc.ParticleSystem.MODE_GRAVITY) {
1953                 // gravity
1954                 var gra = this.getGravity();
1955                 retParticle.setGravity(cc.p(gra.x,gra.y));
1956 
1957                 // speed
1958                 retParticle.setSpeed(this.getSpeed());
1959                 retParticle.setSpeedVar(this.getSpeedVar());
1960 
1961                 // radial acceleration
1962                 retParticle.setRadialAccel(this.getRadialAccel());
1963                 retParticle.setRadialAccelVar(this.getRadialAccelVar());
1964 
1965                 // tangential acceleration
1966                 retParticle.setTangentialAccel(this.getTangentialAccel());
1967                 retParticle.setTangentialAccelVar(this.getTangentialAccelVar());
1968 
1969             } else if (this.getEmitterMode() === cc.ParticleSystem.MODE_RADIUS) {
1970                 // or Mode B: radius movement
1971                 retParticle.setStartRadius(this.getStartRadius());
1972                 retParticle.setStartRadiusVar(this.getStartRadiusVar());
1973                 retParticle.setEndRadius(this.getEndRadius());
1974                 retParticle.setEndRadiusVar(this.getEndRadiusVar());
1975 
1976                 retParticle.setRotatePerSecond(this.getRotatePerSecond());
1977                 retParticle.setRotatePerSecondVar(this.getRotatePerSecondVar());
1978             }
1979 
1980             // life span
1981             retParticle.setLife(this.getLife());
1982             retParticle.setLifeVar(this.getLifeVar());
1983 
1984             // emission Rate
1985             retParticle.setEmissionRate(this.getEmissionRate());
1986 
1987             //don't get the internal texture if a batchNode is used
1988             if (!this.getBatchNode()) {
1989                 // Set a compatible default for the alpha transfer
1990                 retParticle.setOpacityModifyRGB(this.isOpacityModifyRGB());
1991                 // texture
1992                 var texture = this.getTexture();
1993                 if(texture){
1994                     var size = texture.getContentSize();
1995                     retParticle.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height));
1996                 }
1997             }
1998         }
1999         return retParticle;
2000     },
2001 
2002     /**
2003      * <p> Sets a new CCSpriteFrame as particle.</br>
2004      * WARNING: this method is experimental. Use setTextureWithRect instead.
2005      * </p>
2006      * @param {cc.SpriteFrame} spriteFrame
2007      */
2008     setDisplayFrame: function (spriteFrame) {
2009         if (!spriteFrame)
2010             return;
2011 
2012         var locOffset = spriteFrame.getOffsetInPixels();
2013         if (locOffset.x !== 0 || locOffset.y !== 0)
2014             cc.log("cc.ParticleSystem.setDisplayFrame(): QuadParticle only supports SpriteFrames with no offsets");
2015 
2016         // update texture before updating texture rect
2017         var texture = spriteFrame.getTexture(), locTexture = this._texture;
2018         if (locTexture !== texture)
2019             this.setTexture(texture);
2020     },
2021 
2022     /**
2023      *  Sets a new texture with a rect. The rect is in Points.
2024      * @param {cc.Texture2D} texture
2025      * @param {cc.Rect} rect
2026      */
2027     setTextureWithRect: function (texture, rect) {
2028         var locTexture = this._texture;
2029         if (locTexture !== texture) {
2030             this._texture = texture;
2031             this._updateBlendFunc();
2032         }
2033         this.initTexCoordsWithRect(rect);
2034     },
2035 
2036     /**
2037      * listen the event that coming to foreground on Android  (An empty function for native)
2038      * @param {cc.Class} obj
2039      */
2040     listenBackToForeground:function (obj) {
2041         //do nothing
2042     }
2043 });
2044 
2045 var _p = cc.ParticleSystem.prototype;
2046 
2047 // Extended properties
2048 /** @expose */
2049 _p.opacityModifyRGB;
2050 cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpacityModifyRGB);
2051 /** @expose */
2052 _p.batchNode;
2053 cc.defineGetterSetter(_p, "batchNode", _p.getBatchNode, _p.setBatchNode);
2054 /** @expose */
2055 _p.drawMode;
2056 cc.defineGetterSetter(_p, "drawMode", _p.getDrawMode, _p.setDrawMode);
2057 /** @expose */
2058 _p.shapeType;
2059 cc.defineGetterSetter(_p, "shapeType", _p.getShapeType, _p.setShapeType);
2060 /** @expose */
2061 _p.active;
2062 cc.defineGetterSetter(_p, "active", _p.isActive);
2063 /** @expose */
2064 _p.sourcePos;
2065 cc.defineGetterSetter(_p, "sourcePos", _p.getSourcePosition, _p.setSourcePosition);
2066 /** @expose */
2067 _p.posVar;
2068 cc.defineGetterSetter(_p, "posVar", _p.getPosVar, _p.setPosVar);
2069 /** @expose */
2070 _p.gravity;
2071 cc.defineGetterSetter(_p, "gravity", _p.getGravity, _p.setGravity);
2072 /** @expose */
2073 _p.speed;
2074 cc.defineGetterSetter(_p, "speed", _p.getSpeed, _p.setSpeed);
2075 /** @expose */
2076 _p.speedVar;
2077 cc.defineGetterSetter(_p, "speedVar", _p.getSpeedVar, _p.setSpeedVar);
2078 /** @expose */
2079 _p.tangentialAccel;
2080 cc.defineGetterSetter(_p, "tangentialAccel", _p.getTangentialAccel, _p.setTangentialAccel);
2081 /** @expose */
2082 _p.tangentialAccelVar;
2083 cc.defineGetterSetter(_p, "tangentialAccelVar", _p.getTangentialAccelVar, _p.setTangentialAccelVar);
2084 /** @expose */
2085 _p.radialAccel;
2086 cc.defineGetterSetter(_p, "radialAccel", _p.getRadialAccel, _p.setRadialAccel);
2087 /** @expose */
2088 _p.radialAccelVar;
2089 cc.defineGetterSetter(_p, "radialAccelVar", _p.getRadialAccelVar, _p.setRadialAccelVar);
2090 /** @expose */
2091 _p.rotationIsDir;
2092 cc.defineGetterSetter(_p, "rotationIsDir", _p.getRotationIsDir, _p.setRotationIsDir);
2093 /** @expose */
2094 _p.startRadius;
2095 cc.defineGetterSetter(_p, "startRadius", _p.getStartRadius, _p.setStartRadius);
2096 /** @expose */
2097 _p.startRadiusVar;
2098 cc.defineGetterSetter(_p, "startRadiusVar", _p.getStartRadiusVar, _p.setStartRadiusVar);
2099 /** @expose */
2100 _p.endRadius;
2101 cc.defineGetterSetter(_p, "endRadius", _p.getEndRadius, _p.setEndRadius);
2102 /** @expose */
2103 _p.endRadiusVar;
2104 cc.defineGetterSetter(_p, "endRadiusVar", _p.getEndRadiusVar, _p.setEndRadiusVar);
2105 /** @expose */
2106 _p.rotatePerS;
2107 cc.defineGetterSetter(_p, "rotatePerS", _p.getRotatePerSecond, _p.setRotatePerSecond);
2108 /** @expose */
2109 _p.rotatePerSVar;
2110 cc.defineGetterSetter(_p, "rotatePerSVar", _p.getRotatePerSecondVar, _p.setRotatePerSecondVar);
2111 /** @expose */
2112 _p.startColor;
2113 cc.defineGetterSetter(_p, "startColor", _p.getStartColor, _p.setStartColor);
2114 /** @expose */
2115 _p.startColorVar;
2116 cc.defineGetterSetter(_p, "startColorVar", _p.getStartColorVar, _p.setStartColorVar);
2117 /** @expose */
2118 _p.endColor;
2119 cc.defineGetterSetter(_p, "endColor", _p.getEndColor, _p.setEndColor);
2120 /** @expose */
2121 _p.endColorVar;
2122 cc.defineGetterSetter(_p, "endColorVar", _p.getEndColorVar, _p.setEndColorVar);
2123 /** @expose */
2124 _p.totalParticles;
2125 cc.defineGetterSetter(_p, "totalParticles", _p.getTotalParticles, _p.setTotalParticles);
2126 /** @expose */
2127 _p.texture;
2128 cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture);
2129 
2130 
2131 /**
2132  * <p> return the string found by key in dict. <br/>
2133  *    This plist files can be create manually or with Particle Designer:<br/>
2134  *    http://particledesigner.71squared.com/<br/>
2135  * </p>
2136  * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead.
2137  * @param {String|Number} plistFile
2138  * @return {cc.ParticleSystem}
2139  */
2140 cc.ParticleSystem.create = function (plistFile) {
2141     return new cc.ParticleSystem(plistFile);
2142 };
2143 
2144 /**
2145  * <p> return the string found by key in dict. <br/>
2146  *    This plist files can be create manually or with Particle Designer:<br/>
2147  *    http://particledesigner.71squared.com/<br/>
2148  * </p>
2149  * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead.
2150  * @function
2151  * @param {String|Number} plistFile
2152  * @return {cc.ParticleSystem}
2153  */
2154 cc.ParticleSystem.createWithTotalParticles = cc.ParticleSystem.create;
2155 
2156 // Different modes
2157 /**
2158  * Mode A:Gravity + Tangential Accel + Radial Accel
2159  * @Class
2160  * @Construct
2161  * @param {cc.Point} [gravity=] Gravity value.
2162  * @param {Number} [speed=0] speed of each particle.
2163  * @param {Number} [speedVar=0] speed variance of each particle.
2164  * @param {Number} [tangentialAccel=0] tangential acceleration of each particle.
2165  * @param {Number} [tangentialAccelVar=0] tangential acceleration variance of each particle.
2166  * @param {Number} [radialAccel=0] radial acceleration of each particle.
2167  * @param {Number} [radialAccelVar=0] radial acceleration variance of each particle.
2168  * @param {boolean} [rotationIsDir=false]
2169  */
2170 cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, tangentialAccelVar, radialAccel, radialAccelVar, rotationIsDir) {
2171     /** Gravity value. Only available in 'Gravity' mode. */
2172     this.gravity = gravity ? gravity : cc.p(0,0);
2173     /** speed of each particle. Only available in 'Gravity' mode.  */
2174     this.speed = speed || 0;
2175     /** speed variance of each particle. Only available in 'Gravity' mode. */
2176     this.speedVar = speedVar || 0;
2177     /** tangential acceleration of each particle. Only available in 'Gravity' mode. */
2178     this.tangentialAccel = tangentialAccel || 0;
2179     /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */
2180     this.tangentialAccelVar = tangentialAccelVar || 0;
2181     /** radial acceleration of each particle. Only available in 'Gravity' mode. */
2182     this.radialAccel = radialAccel || 0;
2183     /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */
2184     this.radialAccelVar = radialAccelVar || 0;
2185     /** set the rotation of each particle to its direction Only available in 'Gravity' mode. */
2186     this.rotationIsDir = rotationIsDir || false;
2187 };
2188 
2189 /**
2190  * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode)
2191  * @Class
2192  * @Construct
2193  * @param {Number} [startRadius=0] The starting radius of the particles.
2194  * @param {Number} [startRadiusVar=0] The starting radius variance of the particles.
2195  * @param {Number} [endRadius=0] The ending radius of the particles.
2196  * @param {Number} [endRadiusVar=0] The ending radius variance of the particles.
2197  * @param {Number} [rotatePerSecond=0] Number of degrees to rotate a particle around the source pos per second.
2198  * @param {Number} [rotatePerSecondVar=0] Variance in degrees for rotatePerSecond.
2199  */
2200 cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) {
2201     /** The starting radius of the particles. Only available in 'Radius' mode. */
2202     this.startRadius = startRadius || 0;
2203     /** The starting radius variance of the particles. Only available in 'Radius' mode. */
2204     this.startRadiusVar = startRadiusVar || 0;
2205     /** The ending radius of the particles. Only available in 'Radius' mode. */
2206     this.endRadius = endRadius || 0;
2207     /** The ending radius variance of the particles. Only available in 'Radius' mode. */
2208     this.endRadiusVar = endRadiusVar || 0;
2209     /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */
2210     this.rotatePerSecond = rotatePerSecond || 0;
2211     /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */
2212     this.rotatePerSecondVar = rotatePerSecondVar || 0;
2213 };
2214 
2215 /**
2216  * Shape Mode of Particle Draw
2217  * @constant
2218  * @type Number
2219  */
2220 cc.ParticleSystem.SHAPE_MODE = 0;
2221 
2222 /**
2223  * Texture Mode of Particle Draw
2224  * @constant
2225  * @type Number
2226  */
2227 cc.ParticleSystem.TEXTURE_MODE = 1;
2228 
2229 /**
2230  * Star Shape for ShapeMode of Particle
2231  * @constant
2232  * @type Number
2233  */
2234 cc.ParticleSystem.STAR_SHAPE = 0;
2235 
2236 /**
2237  * Ball Shape for ShapeMode of Particle
2238  * @constant
2239  * @type Number
2240  */
2241 cc.ParticleSystem.BALL_SHAPE = 1;
2242 
2243 /**
2244  * The Particle emitter lives forever
2245  * @constant
2246  * @type Number
2247  */
2248 cc.ParticleSystem.DURATION_INFINITY = -1;
2249 
2250 /**
2251  * The starting size of the particle is equal to the ending size
2252  * @constant
2253  * @type Number
2254  */
2255 cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE = -1;
2256 
2257 /**
2258  * The starting radius of the particle is equal to the ending radius
2259  * @constant
2260  * @type Number
2261  */
2262 cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS = -1;
2263 
2264 /**
2265  * Gravity mode (A mode)
2266  * @constant
2267  * @type Number
2268  */
2269 cc.ParticleSystem.MODE_GRAVITY = 0;
2270 
2271 /**
2272  * Radius mode (B mode)
2273  * @constant
2274  * @type Number
2275  */
2276 cc.ParticleSystem.MODE_RADIUS = 1;
2277 
2278 /**
2279  * Living particles are attached to the world and are unaffected by emitter repositioning.
2280  * @constant
2281  * @type Number
2282  */
2283 cc.ParticleSystem.TYPE_FREE = 0;
2284 
2285 /**
2286  * Living particles are attached to the world but will follow the emitter repositioning.<br/>
2287  * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite.
2288  * @constant
2289  * @type Number
2290  */
2291 cc.ParticleSystem.TYPE_RELATIVE = 1;
2292 
2293 /**
2294  * Living particles are attached to the emitter and are translated along with it.
2295  * @constant
2296  * @type Number
2297  */
2298 cc.ParticleSystem.TYPE_GROUPED = 2;
2299