1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga 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  * Shape Mode of Particle Draw
 46  * @constant
 47  * @type Number
 48  */
 49 cc.PARTICLE_SHAPE_MODE = 0;
 50 /**
 51  * Texture Mode of Particle Draw
 52  * @constant
 53  * @type Number
 54  */
 55 cc.PARTICLE_TEXTURE_MODE = 1;
 56 
 57 /**
 58  * Star Shape for ShapeMode of Particle
 59  * @constant
 60  * @type Number
 61  */
 62 cc.PARTICLE_STAR_SHAPE = 0;
 63 /**
 64  * Ball Shape for ShapeMode of Particle
 65  * @constant
 66  * @type Number
 67  */
 68 cc.PARTICLE_BALL_SHAPE = 1;
 69 
 70 /**
 71  * The Particle emitter lives forever
 72  * @constant
 73  * @type Number
 74  */
 75 cc.PARTICLE_DURATION_INFINITY = -1;
 76 
 77 /**
 78  * The starting size of the particle is equal to the ending size
 79  * @constant
 80  * @type Number
 81  */
 82 cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE = -1;
 83 
 84 /**
 85  * The starting radius of the particle is equal to the ending radius
 86  * @constant
 87  * @type Number
 88  */
 89 cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS = -1;
 90 
 91 /**
 92  * Gravity mode (A mode)
 93  * @constant
 94  * @type Number
 95  */
 96 cc.PARTICLE_MODE_GRAVITY = 0;
 97 
 98 /**
 99  * Radius mode (B mode)
100  * @constant
101  * @type Number
102  */
103 cc.PARTICLE_MODE_RADIUS = 1;
104 
105 // tCCPositionType
106 // possible types of particle positions
107 
108 /**
109  * Living particles are attached to the world and are unaffected by emitter repositioning.
110  * @constant
111  * @type Number
112  */
113 cc.PARTICLE_TYPE_FREE = 0;
114 
115 /**
116  * Living particles are attached to the world but will follow the emitter repositioning.<br/>
117  * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite.
118  * @constant
119  * @type Number
120  */
121 cc.PARTICLE_TYPE_RELATIVE = 1;
122 
123 /**
124  * Living particles are attached to the emitter and are translated along with it.
125  * @constant
126  * @type Number
127  */
128 cc.PARTICLE_TYPE_GROUPED = 2;
129 
130 /**
131  * Structure that contains the values of each particle
132  * @Class
133  * @Construct
134  * @param {cc.Point} [pos=cc.PointZero()] Position of particle
135  * @param {cc.Point} [startPos=cc.PointZero()]
136  * @param {cc.Color4F} [color= cc.Color4F(0, 0, 0, 1)]
137  * @param {cc.Color4F} [deltaColor=cc.Color4F(0, 0, 0, 1)]
138  * @param {cc.Size} [size=0]
139  * @param {cc.Size} [deltaSize=0]
140  * @param {Number} [rotation=0]
141  * @param {Number} [deltaRotation=0]
142  * @param {Number} [timeToLive=0]
143  * @param {Number} [atlasIndex=0]
144  * @param {cc.Particle.ModeA} [modeA=]
145  * @param {cc.Particle.ModeA} [modeB=]
146  */
147 cc.Particle = function (pos, startPos, color, deltaColor, size, deltaSize, rotation, deltaRotation, timeToLive, atlasIndex, modeA, modeB) {
148     this.pos = pos ? pos : cc.PointZero();
149     this.startPos = startPos ? startPos : cc.PointZero();
150     this.color = color ? color : new cc.Color4F(0, 0, 0, 1);
151     this.deltaColor = deltaColor ? deltaColor : new cc.Color4F(0, 0, 0, 1);
152     this.size = size || 0;
153     this.deltaSize = deltaSize || 0;
154     this.rotation = rotation || 0;
155     this.deltaRotation = deltaRotation || 0;
156     this.timeToLive = timeToLive || 0;
157     this.atlasIndex = atlasIndex || 0;
158     this.modeA = modeA ? modeA : new cc.Particle.ModeA();
159     this.modeB = modeB ? modeB : new cc.Particle.ModeB();
160     this.isChangeColor = false;
161     this.drawPos = cc.p(0, 0);
162 };
163 
164 /**
165  * Mode A: gravity, direction, radial accel, tangential accel
166  * @Class
167  * @Construct
168  * @param {cc.Point} dir direction of particle
169  * @param {Number} radialAccel
170  * @param {Number} tangentialAccel
171  */
172 cc.Particle.ModeA = function (dir, radialAccel, tangentialAccel) {
173     this.dir = dir ? dir : cc.PointZero();
174     this.radialAccel = radialAccel || 0;
175     this.tangentialAccel = tangentialAccel || 0;
176 };
177 
178 /**
179  * Mode B: radius mode
180  * @Class
181  * @Construct
182  * @param {Number} angle
183  * @param {Number} degreesPerSecond
184  * @param {Number} radius
185  * @param {Number} deltaRadius
186  */
187 cc.Particle.ModeB = function (angle, degreesPerSecond, radius, deltaRadius) {
188     this.angle = angle || 0;
189     this.degreesPerSecond = degreesPerSecond || 0;
190     this.radius = radius || 0;
191     this.deltaRadius = deltaRadius || 0;
192 };
193 
194 /**
195   * Array of Point instances used to optimize particle updates
196   */
197 cc.Particle.TemporaryPoints = [
198     cc.p(),
199     cc.p(),
200     cc.p(),
201     cc.p()
202 ];
203 
204 /**
205  * <p>
206  *     Particle System base class. <br/>
207  *     Attributes of a Particle System:<br/>
208  *     - emmision rate of the particles<br/>
209  *     - Gravity Mode (Mode A): <br/>
210  *     - gravity <br/>
211  *     - direction <br/>
212  *     - speed +-  variance <br/>
213  *     - tangential acceleration +- variance<br/>
214  *     - radial acceleration +- variance<br/>
215  *     - Radius Mode (Mode B):      <br/>
216  *     - startRadius +- variance    <br/>
217  *     - endRadius +- variance      <br/>
218  *     - rotate +- variance         <br/>
219  *     - Properties common to all modes: <br/>
220  *     - life +- life variance      <br/>
221  *     - start spin +- variance     <br/>
222  *     - end spin +- variance       <br/>
223  *     - start size +- variance     <br/>
224  *     - end size +- variance       <br/>
225  *     - start color +- variance    <br/>
226  *     - end color +- variance      <br/>
227  *     - life +- variance           <br/>
228  *     - blending function          <br/>
229  *     - texture                    <br/>
230  *                                  <br/>
231  *     cocos2d also supports particles generated by Particle Designer (http://particledesigner.71squared.com/).<br/>
232  *     'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d,  <br/>
233  *     cocos2d uses a another approach, but the results are almost identical.<br/>
234  *     cocos2d supports all the variables used by Particle Designer plus a bit more:  <br/>
235  *     - spinning particles (supported when using ParticleSystem)       <br/>
236  *     - tangential acceleration (Gravity mode)                               <br/>
237  *     - radial acceleration (Gravity mode)                                   <br/>
238  *     - radius direction (Radius mode) (Particle Designer supports outwards to inwards direction only) <br/>
239  *     It is possible to customize any of the above mentioned properties in runtime. Example:   <br/>
240  * </p>
241  * @class
242  * @extends cc.Node
243  *
244  * @example
245  *  emitter.radialAccel = 15;
246  *  emitter.startSpin = 0;
247  */
248 cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{
249     //***********variables*************
250     _plistFile: "",
251     //! time elapsed since the start of the system (in seconds)
252     _elapsed: 0,
253 
254     _dontTint: false,
255 
256     // Different modes
257     //! Mode A:Gravity + Tangential Accel + Radial Accel
258     modeA: null,
259     //! Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode)
260     modeB: null,
261 
262     //private POINTZERO for ParticleSystem
263     _pointZeroForParticle: cc.p(0, 0),
264 
265     //! Array of particles
266     _particles: null,
267 
268     // color modulate
269     //  BOOL colorModulate;
270 
271     //! How many particles can be emitted per second
272     _emitCounter: 0,
273     //!  particle idx
274     _particleIdx: 0,
275 
276     _batchNode: null,
277     _atlasIndex: 0,
278 
279     //true if scaled or rotated
280     _transformSystemDirty: false,
281     _allocatedParticles: 0,
282 
283     //drawMode
284     _drawMode: cc.PARTICLE_SHAPE_MODE,
285 
286     //shape type
287     _shapeType: cc.PARTICLE_BALL_SHAPE,
288     _isActive: false,
289     _particleCount: 0,
290     _duration: 0,
291     _sourcePosition: null,
292     _posVar: null,
293     _life: 0,
294     _lifeVar: 0,
295     _angle: 0,
296     _angleVar: 0,
297     _startSize: 0,
298     _startSizeVar: 0,
299     _endSize: 0,
300     _endSizeVar: 0,
301     _startColor: null,
302     _startColorVar: null,
303     _endColor: null,
304     _endColorVar: null,
305     _startSpin: 0,
306     _startSpinVar: 0,
307     _endSpin: 0,
308     _endSpinVar: 0,
309     _emissionRate: 0,
310     _totalParticles: 0,
311     _texture: null,
312     _blendFunc: null,
313     _opacityModifyRGB: false,
314     _positionType: cc.PARTICLE_TYPE_FREE,
315     _isAutoRemoveOnFinish: false,
316     _emitterMode: 0,
317 
318     // quads to be rendered
319     _quads:null,
320     // indices
321     _indices:null,
322 
323     //_VAOname:0,
324     //0: vertex  1: indices
325     _buffersVBO:null,
326     _pointRect:null,
327 
328     _textureLoaded: null,
329     _quadsArrayBuffer:null,
330 
331     /**
332      * Constructor
333      * @override
334      */
335     ctor:function () {
336         cc.Node.prototype.ctor.call(this);
337         this._emitterMode = cc.PARTICLE_MODE_GRAVITY;
338         this.modeA = new cc.ParticleSystem.ModeA();
339         this.modeB = new cc.ParticleSystem.ModeB();
340         this._blendFunc = {src:cc.BLEND_SRC, dst:cc.BLEND_DST};
341 
342         this._particles = [];
343         this._sourcePosition = new cc.Point(0, 0);
344         this._posVar = new cc.Point(0, 0);
345 
346         this._startColor = new cc.Color4F(1, 1, 1, 1);
347         this._startColorVar = new cc.Color4F(1, 1, 1, 1);
348         this._endColor = new cc.Color4F(1, 1, 1, 1);
349         this._endColorVar = new cc.Color4F(1, 1, 1, 1);
350 
351         this._plistFile = "";
352         this._elapsed = 0;
353         this._dontTint = false;
354         this._pointZeroForParticle = cc.p(0, 0);
355         this._emitCounter = 0;
356         this._particleIdx = 0;
357         this._batchNode = null;
358         this._atlasIndex = 0;
359 
360         this._transformSystemDirty = false;
361         this._allocatedParticles = 0;
362         this._drawMode = cc.PARTICLE_SHAPE_MODE;
363         this._shapeType = cc.PARTICLE_BALL_SHAPE;
364         this._isActive = false;
365         this._particleCount = 0;
366         this._duration = 0;
367         this._life = 0;
368         this._lifeVar = 0;
369         this._angle = 0;
370         this._angleVar = 0;
371         this._startSize = 0;
372         this._startSizeVar = 0;
373         this._endSize = 0;
374         this._endSizeVar = 0;
375 
376         this._startSpin = 0;
377         this._startSpinVar = 0;
378         this._endSpin = 0;
379         this._endSpinVar = 0;
380         this._emissionRate = 0;
381         this._totalParticles = 0;
382         this._texture = null;
383         this._opacityModifyRGB = false;
384         this._positionType = cc.PARTICLE_TYPE_FREE;
385         this._isAutoRemoveOnFinish = false;
386 
387         this._buffersVBO = [0, 0];
388         this._quads = [];
389         this._indices = [];
390         this._pointRect = cc.RectZero();
391         this._textureLoaded = true;
392 
393         if (cc.renderContextType === cc.WEBGL) {
394             this._quadsArrayBuffer = null;
395         }
396     },
397 
398     /**
399      * initializes the indices for the vertices
400      */
401     initIndices:function () {
402         var locIndices = this._indices;
403         for (var i = 0, len = this._totalParticles; i < len; ++i) {
404             var i6 = i * 6;
405             var i4 = i * 4;
406             locIndices[i6 + 0] = i4 + 0;
407             locIndices[i6 + 1] = i4 + 1;
408             locIndices[i6 + 2] = i4 + 2;
409 
410             locIndices[i6 + 5] = i4 + 1;
411             locIndices[i6 + 4] = i4 + 2;
412             locIndices[i6 + 3] = i4 + 3;
413         }
414     },
415 
416     /**
417      * <p> initializes the texture with a rectangle measured Points<br/>
418      * pointRect should be in Texture coordinates, not pixel coordinates
419      * </p>
420      * @param {cc.Rect} pointRect
421      */
422     initTexCoordsWithRect:function (pointRect) {
423         var scaleFactor = cc.CONTENT_SCALE_FACTOR();
424         // convert to pixels coords
425         var rect = cc.rect(
426             pointRect.x * scaleFactor,
427             pointRect.y * scaleFactor,
428             pointRect.width * scaleFactor,
429             pointRect.height * scaleFactor);
430 
431         var wide = pointRect.width;
432         var high = pointRect.height;
433 
434         if (this._texture) {
435             wide = this._texture.getPixelsWide();
436             high = this._texture.getPixelsHigh();
437         }
438 
439         if(cc.renderContextType === cc.CANVAS)
440             return;
441 
442         var left, bottom, right, top;
443         if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
444             left = (rect.x * 2 + 1) / (wide * 2);
445             bottom = (rect.y * 2 + 1) / (high * 2);
446             right = left + (rect.width * 2 - 2) / (wide * 2);
447             top = bottom + (rect.height * 2 - 2) / (high * 2);
448         } else {
449             left = rect.x / wide;
450             bottom = rect.y / high;
451             right = left + rect.width / wide;
452             top = bottom + rect.height / high;
453         }
454 
455         // Important. Texture in cocos2d are inverted, so the Y component should be inverted
456         var temp = top;
457         top = bottom;
458         bottom = temp;
459 
460         var quads;
461         var start = 0, end = 0;
462         if (this._batchNode) {
463             quads = this._batchNode.getTextureAtlas().getQuads();
464             start = this._atlasIndex;
465             end = this._atlasIndex + this._totalParticles;
466         } else {
467             quads = this._quads;
468             start = 0;
469             end = this._totalParticles;
470         }
471 
472         for (var i = start; i < end; i++) {
473             if (!quads[i])
474                 quads[i] = cc.V3F_C4B_T2F_QuadZero();
475 
476             // bottom-left vertex:
477             var selQuad = quads[i];
478             selQuad.bl.texCoords.u = left;
479             selQuad.bl.texCoords.v = bottom;
480             // bottom-right vertex:
481             selQuad.br.texCoords.u = right;
482             selQuad.br.texCoords.v = bottom;
483             // top-left vertex:
484             selQuad.tl.texCoords.u = left;
485             selQuad.tl.texCoords.v = top;
486             // top-right vertex:
487             selQuad.tr.texCoords.u = right;
488             selQuad.tr.texCoords.v = top;
489         }
490     },
491 
492     /**
493      * return weak reference to the cc.SpriteBatchNode that renders the cc.Sprite
494      * @return {cc.ParticleBatchNode}
495      */
496     getBatchNode:function () {
497         return this._batchNode;
498     },
499 
500     /**
501      *  set weak reference to the cc.SpriteBatchNode that renders the cc.Sprite
502      * @param {cc.ParticleBatchNode} batchNode
503      */
504     setBatchNode:function (batchNode) {
505         if (this._batchNode != batchNode) {
506             var oldBatch = this._batchNode;
507 
508             this._batchNode = batchNode; //weak reference
509 
510             if (batchNode) {
511                 var locParticles = this._particles;
512                 for (var i = 0; i < this._totalParticles; i++)
513                     locParticles[i].atlasIndex = i;
514             }
515 
516             // NEW: is self render ?
517             if (!batchNode) {
518                 this._allocMemory();
519                 this.initIndices();
520                 this.setTexture(oldBatch.getTexture());
521                 //if (cc.TEXTURE_ATLAS_USE_VAO)
522                 //    this._setupVBOandVAO();
523                 //else
524                 this._setupVBO();
525             } else if (!oldBatch) {
526                 // OLD: was it self render cleanup  ?
527                 // copy current state to batch
528                 this._batchNode.getTextureAtlas()._copyQuadsToTextureAtlas(this._quads, this._atlasIndex);
529 
530                 //delete buffer
531                 cc.renderContext.deleteBuffer(this._buffersVBO[1]);     //where is re-bindBuffer code?
532 
533                 //if (cc.TEXTURE_ATLAS_USE_VAO)
534                 //    glDeleteVertexArrays(1, this._VAOname);
535             }
536         }
537     },
538 
539     /**
540      * return index of system in batch node array
541      * @return {Number}
542      */
543     getAtlasIndex:function () {
544         return this._atlasIndex;
545     },
546 
547     /**
548      * set index of system in batch node array
549      * @param {Number} atlasIndex
550      */
551     setAtlasIndex:function (atlasIndex) {
552         this._atlasIndex = atlasIndex;
553     },
554 
555     /**
556      * Return DrawMode of ParticleSystem
557      * @return {Number}
558      */
559     getDrawMode:function () {
560         return this._drawMode;
561     },
562 
563     /**
564      * DrawMode of ParticleSystem setter
565      * @param {Number} drawMode
566      */
567     setDrawMode:function (drawMode) {
568         this._drawMode = drawMode;
569     },
570 
571     /**
572      * Return ShapeType of ParticleSystem
573      * @return {Number}
574      */
575     getShapeType:function () {
576         return this._shapeType;
577     },
578 
579     /**
580      * ShapeType of ParticleSystem setter
581      * @param {Number} shapeType
582      */
583     setShapeType:function (shapeType) {
584         this._shapeType = shapeType;
585     },
586 
587     /**
588      * Return ParticleSystem is active
589      * @return {Boolean}
590      */
591     isActive:function () {
592         return this._isActive;
593     },
594 
595     /**
596      * Quantity of particles that are being simulated at the moment
597      * @return {Number}
598      */
599     getParticleCount:function () {
600         return this._particleCount;
601     },
602 
603     /**
604      * Quantity of particles setter
605      * @param {Number} particleCount
606      */
607     setParticleCount:function (particleCount) {
608         this._particleCount = particleCount;
609     },
610 
611     /**
612      * How many seconds the emitter wil run. -1 means 'forever'
613      * @return {Number}
614      */
615     getDuration:function () {
616         return this._duration;
617     },
618 
619     /**
620      * set run seconds of the emitter
621      * @param {Number} duration
622      */
623     setDuration:function (duration) {
624         this._duration = duration;
625     },
626 
627     /**
628      * Return sourcePosition of the emitter
629      * @return {cc.Point | Object}
630      */
631     getSourcePosition:function () {
632         return {x:this._sourcePosition.x, y:this._sourcePosition.y};
633     },
634 
635     /**
636      * sourcePosition of the emitter setter
637      * @param sourcePosition
638      */
639     setSourcePosition:function (sourcePosition) {
640         this._sourcePosition = sourcePosition;
641     },
642 
643     /**
644      * Return Position variance of the emitter
645      * @return {cc.Point | Object}
646      */
647     getPosVar:function () {
648         return {x: this._posVar.x, y: this._posVar.y};
649     },
650 
651     /**
652      * Position variance of the emitter setter
653      * @param {cc.Point} posVar
654      */
655     setPosVar:function (posVar) {
656         this._posVar = posVar;
657     },
658 
659     /**
660      * Return life of each particle
661      * @return {Number}
662      */
663     getLife:function () {
664         return this._life;
665     },
666 
667     /**
668      * life of each particle setter
669      * @param {Number} life
670      */
671     setLife:function (life) {
672         this._life = life;
673     },
674 
675     /**
676      * Return life variance of each particle
677      * @return {Number}
678      */
679     getLifeVar:function () {
680         return this._lifeVar;
681     },
682 
683     /**
684      * life variance of each particle setter
685      * @param {Number} lifeVar
686      */
687     setLifeVar:function (lifeVar) {
688         this._lifeVar = lifeVar;
689     },
690 
691     /**
692      * Return angle of each particle
693      * @return {Number}
694      */
695     getAngle:function () {
696         return this._angle;
697     },
698 
699     /**
700      * angle of each particle setter
701      * @param {Number} angle
702      */
703     setAngle:function (angle) {
704         this._angle = angle;
705     },
706 
707     /**
708      * Return angle variance of each particle
709      * @return {Number}
710      */
711     getAngleVar:function () {
712         return this._angleVar;
713     },
714 
715     /**
716      * angle variance of each particle setter
717      * @param angleVar
718      */
719     setAngleVar:function (angleVar) {
720         this._angleVar = angleVar;
721     },
722 
723     // mode A
724     /**
725      * Return Gravity of emitter
726      * @return {cc.Point}
727      */
728     getGravity:function () {
729         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
730         return this.modeA.gravity;
731     },
732 
733     /**
734      * Gravity of emitter setter
735      * @param {cc.Point} gravity
736      */
737     setGravity:function (gravity) {
738         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
739         this.modeA.gravity = gravity;
740     },
741 
742     /**
743      * Return Speed of each particle
744      * @return {Number}
745      */
746     getSpeed:function () {
747         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
748         return this.modeA.speed;
749     },
750 
751     /**
752      * Speed of each particle setter
753      * @param {Number} speed
754      */
755     setSpeed:function (speed) {
756         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
757         this.modeA.speed = speed;
758     },
759 
760     /**
761      * return speed variance of each particle. Only available in 'Gravity' mode.
762      * @return {Number}
763      */
764     getSpeedVar:function () {
765         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
766         return this.modeA.speedVar;
767     },
768 
769     /**
770      * speed variance of each particle setter. Only available in 'Gravity' mode.
771      * @param {Number} speedVar
772      */
773     setSpeedVar:function (speedVar) {
774         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
775         this.modeA.speedVar = speedVar;
776     },
777 
778     /**
779      * Return tangential acceleration of each particle. Only available in 'Gravity' mode.
780      * @return {Number}
781      */
782     getTangentialAccel:function () {
783         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
784         return this.modeA.tangentialAccel;
785     },
786 
787     /**
788      * Tangential acceleration of each particle setter. Only available in 'Gravity' mode.
789      * @param {Number} tangentialAccel
790      */
791     setTangentialAccel:function (tangentialAccel) {
792         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
793         this.modeA.tangentialAccel = tangentialAccel;
794     },
795 
796     /**
797      * Return tangential acceleration variance of each particle. Only available in 'Gravity' mode.
798      * @return {Number}
799      */
800     getTangentialAccelVar:function () {
801         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
802         return this.modeA.tangentialAccelVar;
803     },
804 
805     /**
806      * tangential acceleration variance of each particle setter. Only available in 'Gravity' mode.
807      * @param {Number} tangentialAccelVar
808      */
809     setTangentialAccelVar:function (tangentialAccelVar) {
810         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
811         this.modeA.tangentialAccelVar = tangentialAccelVar;
812     },
813 
814     /**
815      * Return radial acceleration of each particle. Only available in 'Gravity' mode.
816      * @return {Number}
817      */
818     getRadialAccel:function () {
819         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
820         return this.modeA.radialAccel;
821     },
822 
823     /**
824      * radial acceleration of each particle setter. Only available in 'Gravity' mode.
825      * @param {Number} radialAccel
826      */
827     setRadialAccel:function (radialAccel) {
828         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
829         this.modeA.radialAccel = radialAccel;
830     },
831 
832     /**
833      * Return radial acceleration variance of each particle. Only available in 'Gravity' mode.
834      * @return {Number}
835      */
836     getRadialAccelVar:function () {
837         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
838         return this.modeA.radialAccelVar;
839     },
840 
841     /**
842      * radial acceleration variance of each particle setter. Only available in 'Gravity' mode.
843      * @param {Number} radialAccelVar
844      */
845     setRadialAccelVar:function (radialAccelVar) {
846         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
847         this.modeA.radialAccelVar = radialAccelVar;
848     },
849 
850     /**
851      * get the rotation of each particle to its direction Only available in 'Gravity' mode.
852      * @returns {boolean}
853      */
854     getRotationIsDir: function(){
855         cc.Assert( this._emitterMode === cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
856         return this.modeA.rotationIsDir;
857     },
858 
859     /**
860      * set the rotation of each particle to its direction Only available in 'Gravity' mode.
861      * @param {boolean} t
862      */
863     setRotationIsDir: function(t){
864         cc.Assert( this._emitterMode === cc.PARTICLE_MODE_GRAVITY, "Particle Mode should be Gravity");
865         this.modeA.rotationIsDir = t;
866     },
867 
868     // mode B
869     /**
870      * Return starting radius of the particles. Only available in 'Radius' mode.
871      * @return {Number}
872      */
873     getStartRadius:function () {
874         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
875         return this.modeB.startRadius;
876     },
877 
878     /**
879      * starting radius of the particles setter. Only available in 'Radius' mode.
880      * @param {Number} startRadius
881      */
882     setStartRadius:function (startRadius) {
883         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
884         this.modeB.startRadius = startRadius;
885     },
886 
887     /**
888      * Return starting radius variance of the particles. Only available in 'Radius' mode.
889      * @return {Number}
890      */
891     getStartRadiusVar:function () {
892         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
893         return this.modeB.startRadiusVar;
894     },
895 
896     /**
897      * starting radius variance of the particles setter. Only available in 'Radius' mode.
898      * @param {Number} startRadiusVar
899      */
900     setStartRadiusVar:function (startRadiusVar) {
901         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
902         this.modeB.startRadiusVar = startRadiusVar;
903     },
904 
905     /**
906      * Return ending radius of the particles. Only available in 'Radius' mode.
907      * @return {Number}
908      */
909     getEndRadius:function () {
910         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
911         return this.modeB.endRadius;
912     },
913 
914     /**
915      * ending radius of the particles setter. Only available in 'Radius' mode.
916      * @param {Number} endRadius
917      */
918     setEndRadius:function (endRadius) {
919         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
920         this.modeB.endRadius = endRadius;
921     },
922 
923     /**
924      * Return ending radius variance of the particles. Only available in 'Radius' mode.
925      * @return {Number}
926      */
927     getEndRadiusVar:function () {
928         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
929         return this.modeB.endRadiusVar;
930     },
931 
932     /**
933      * ending radius variance of the particles setter. Only available in 'Radius' mode.
934      * @param endRadiusVar
935      */
936     setEndRadiusVar:function (endRadiusVar) {
937         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
938         this.modeB.endRadiusVar = endRadiusVar;
939     },
940 
941     /**
942      * get Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode.
943      * @return {Number}
944      */
945     getRotatePerSecond:function () {
946         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
947         return this.modeB.rotatePerSecond;
948     },
949 
950     /**
951      * set Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode.
952      * @param {Number} degrees
953      */
954     setRotatePerSecond:function (degrees) {
955         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
956         this.modeB.rotatePerSecond = degrees;
957     },
958 
959     /**
960      * Return Variance in degrees for rotatePerSecond. Only available in 'Radius' mode.
961      * @return {Number}
962      */
963     getRotatePerSecondVar:function () {
964         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
965         return this.modeB.rotatePerSecondVar;
966     },
967 
968     /**
969      * Variance in degrees for rotatePerSecond setter. Only available in 'Radius' mode.
970      * @param degrees
971      */
972     setRotatePerSecondVar:function (degrees) {
973         cc.Assert(this._emitterMode == cc.PARTICLE_MODE_RADIUS, "Particle Mode should be Radius");
974         this.modeB.rotatePerSecondVar = degrees;
975     },
976     //////////////////////////////////////////////////////////////////////////
977 
978     //don't use a transform matrix, this is faster
979     setScale:function (scale, scaleY) {
980         this._transformSystemDirty = true;
981         cc.Node.prototype.setScale.call(this, scale, scaleY);
982     },
983 
984     setRotation:function (newRotation) {
985         this._transformSystemDirty = true;
986         cc.Node.prototype.setRotation.call(this, newRotation);
987     },
988 
989     setScaleX:function (newScaleX) {
990         this._transformSystemDirty = true;
991         cc.Node.prototype.setScaleX.call(this, newScaleX);
992     },
993 
994     setScaleY:function (newScaleY) {
995         this._transformSystemDirty = true;
996         cc.Node.prototype.setScaleY.call(this, newScaleY);
997     },
998 
999     /**
1000      * get start size in pixels of each particle
1001      * @return {Number}
1002      */
1003     getStartSize:function () {
1004         return this._startSize;
1005     },
1006 
1007     /**
1008      * set start size in pixels of each particle
1009      * @param {Number} startSize
1010      */
1011     setStartSize:function (startSize) {
1012         this._startSize = startSize;
1013     },
1014 
1015     /**
1016      * get size variance in pixels of each particle
1017      * @return {Number}
1018      */
1019     getStartSizeVar:function () {
1020         return this._startSizeVar;
1021     },
1022 
1023     /**
1024      * set size variance in pixels of each particle
1025      * @param {Number} startSizeVar
1026      */
1027     setStartSizeVar:function (startSizeVar) {
1028         this._startSizeVar = startSizeVar;
1029     },
1030 
1031     /**
1032      * get end size in pixels of each particle
1033      * @return {Number}
1034      */
1035     getEndSize:function () {
1036         return this._endSize;
1037     },
1038 
1039     /**
1040      * set end size in pixels of each particle
1041      * @param endSize
1042      */
1043     setEndSize:function (endSize) {
1044         this._endSize = endSize;
1045     },
1046 
1047     /**
1048      * get end size variance in pixels of each particle
1049      * @return {Number}
1050      */
1051     getEndSizeVar:function () {
1052         return this._endSizeVar;
1053     },
1054 
1055     /**
1056      * set end size variance in pixels of each particle
1057      * @param {Number} endSizeVar
1058      */
1059     setEndSizeVar:function (endSizeVar) {
1060         this._endSizeVar = endSizeVar;
1061     },
1062 
1063     /**
1064      * set start color of each particle
1065      * @return {cc.Color4F}
1066      */
1067     getStartColor:function () {
1068         return this._startColor;
1069     },
1070 
1071     /**
1072      * get start color of each particle
1073      * @param {cc.Color4F} startColor
1074      */
1075     setStartColor:function (startColor) {
1076         if (startColor instanceof cc.Color3B)
1077             startColor = cc.c4FFromccc3B(startColor);
1078         this._startColor = startColor;
1079     },
1080 
1081     /**
1082      * get start color variance of each particle
1083      * @return {cc.Color4F}
1084      */
1085     getStartColorVar:function () {
1086         return this._startColorVar;
1087     },
1088 
1089     /**
1090      * set start color variance of each particle
1091      * @param {cc.Color4F} startColorVar
1092      */
1093     setStartColorVar:function (startColorVar) {
1094         if (startColorVar instanceof cc.Color3B)
1095             startColorVar = cc.c4FFromccc3B(startColorVar);
1096         this._startColorVar = startColorVar;
1097     },
1098 
1099     /**
1100      * get end color and end color variation of each particle
1101      * @return {cc.Color4F}
1102      */
1103     getEndColor:function () {
1104         return this._endColor;
1105     },
1106 
1107     /**
1108      * set end color and end color variation of each particle
1109      * @param {cc.Color4F} endColor
1110      */
1111     setEndColor:function (endColor) {
1112         if (endColor instanceof cc.Color3B)
1113             endColor = cc.c4FFromccc3B(endColor);
1114         this._endColor = endColor;
1115     },
1116 
1117     /**
1118      * get end color variance of each particle
1119      * @return {cc.Color4F}
1120      */
1121     getEndColorVar:function () {
1122         return this._endColorVar;
1123     },
1124 
1125     /**
1126      * set end color variance of each particle
1127      * @param {cc.Color4F} endColorVar
1128      */
1129     setEndColorVar:function (endColorVar) {
1130         if (endColorVar instanceof cc.Color3B)
1131             endColorVar = cc.c4FFromccc3B(endColorVar);
1132         this._endColorVar = endColorVar;
1133     },
1134 
1135     /**
1136      * get initial angle of each particle
1137      * @return {Number}
1138      */
1139     getStartSpin:function () {
1140         return this._startSpin;
1141     },
1142 
1143     /**
1144      * set initial angle of each particle
1145      * @param {Number} startSpin
1146      */
1147     setStartSpin:function (startSpin) {
1148         this._startSpin = startSpin;
1149     },
1150 
1151     /**
1152      * get initial angle variance of each particle
1153      * @return {Number}
1154      */
1155     getStartSpinVar:function () {
1156         return this._startSpinVar;
1157     },
1158 
1159     /**
1160      * set initial angle variance of each particle
1161      * @param {Number} startSpinVar
1162      */
1163     setStartSpinVar:function (startSpinVar) {
1164         this._startSpinVar = startSpinVar;
1165     },
1166 
1167     /**
1168      * get end angle of each particle
1169      * @return {Number}
1170      */
1171     getEndSpin:function () {
1172         return this._endSpin;
1173     },
1174 
1175     /**
1176      * set end angle of each particle
1177      * @param {Number} endSpin
1178      */
1179     setEndSpin:function (endSpin) {
1180         this._endSpin = endSpin;
1181     },
1182 
1183     /**
1184      * get end angle variance of each particle
1185      * @return {Number}
1186      */
1187     getEndSpinVar:function () {
1188         return this._endSpinVar;
1189     },
1190 
1191     /**
1192      * set end angle variance of each particle
1193      * @param {Number} endSpinVar
1194      */
1195     setEndSpinVar:function (endSpinVar) {
1196         this._endSpinVar = endSpinVar;
1197     },
1198 
1199     /**
1200      * get emission rate of the particles
1201      * @return {Number}
1202      */
1203     getEmissionRate:function () {
1204         return this._emissionRate;
1205     },
1206 
1207     /**
1208      * set emission rate of the particles
1209      * @param {Number} emissionRate
1210      */
1211     setEmissionRate:function (emissionRate) {
1212         this._emissionRate = emissionRate;
1213     },
1214 
1215     /**
1216      * get maximum particles of the system
1217      * @return {Number}
1218      */
1219     getTotalParticles:function () {
1220         return this._totalParticles;
1221     },
1222 
1223     /**
1224      * set maximum particles of the system
1225      * @param {Number} tp totalParticles
1226      */
1227     setTotalParticles:function (tp) {
1228         //cc.Assert(tp <= this._allocatedParticles, "Particle: resizing particle array only supported for quads");
1229         if (cc.renderContextType === cc.CANVAS){
1230             this._totalParticles = (tp < 200) ? tp : 200;
1231             return;
1232         }
1233 
1234         // If we are setting the total numer of particles to a number higher
1235         // than what is allocated, we need to allocate new arrays
1236         if (tp > this._allocatedParticles) {
1237             var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
1238             // Allocate new memory
1239             this._indices = new Uint16Array(tp * 6);
1240             var locQuadsArrayBuffer = new ArrayBuffer(tp * quadSize);
1241             //TODO need fix
1242             // Assign pointers
1243             var locParticles = [];
1244             var locQuads = [];
1245             for (var j = 0; j < tp; j++) {
1246                 locParticles[j] = new cc.Particle();
1247                 locQuads[j] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, j * quadSize);
1248             }
1249             this._allocatedParticles = tp;
1250             this._totalParticles = tp;
1251 
1252             // Init particles
1253             if (this._batchNode) {
1254                 for (var i = 0; i < tp; i++)
1255                     locParticles[i].atlasIndex = i;
1256             }
1257 
1258             this._particles = locParticles;
1259             this._quadsArrayBuffer = locQuadsArrayBuffer;
1260             this._quads = locQuads;
1261 
1262             this.initIndices();
1263             //if (cc.TEXTURE_ATLAS_USE_VAO)
1264             //    this._setupVBOandVAO();
1265             //else
1266             this._setupVBO();
1267 
1268             //set the texture coord
1269             if(this._texture){
1270                 var size = this._texture.getContentSize();
1271                 this.initTexCoordsWithRect(cc.rect(0, 0, size.width, size.height));
1272             }
1273         } else
1274             this._totalParticles = tp;
1275         this.resetSystem();
1276     },
1277 
1278     /**
1279      * get Texture of Particle System
1280      * @return {cc.Texture2D}
1281      */
1282     getTexture:function () {
1283         return this._texture;
1284     },
1285 
1286     /**
1287      * set Texture of Particle System
1288      * @param {cc.Texture2D } texture
1289      */
1290     setTexture:function (texture) {
1291         if(texture.isLoaded()){
1292             var  size = texture.getContentSize();
1293             this.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height));
1294         } else {
1295             this._textureLoaded = false;
1296             texture.addLoadedEventListener(function(sender){
1297                 this._textureLoaded = true;
1298                 var  size = sender.getContentSize();
1299                 this.setTextureWithRect(sender, cc.rect(0, 0, size.width, size.height));
1300             }, this);
1301         }
1302     },
1303 
1304     /** conforms to CocosNodeTexture protocol */
1305     /**
1306      * get BlendFunc of Particle System
1307      * @return {cc.BlendFunc}
1308      */
1309     getBlendFunc:function () {
1310         return this._blendFunc;
1311     },
1312 
1313     /**
1314      * set BlendFunc of Particle System
1315      * @param {Number} src
1316      * @param {Number} dst
1317      */
1318     setBlendFunc:function (src, dst) {
1319         if (arguments.length == 1) {
1320             if (this._blendFunc != src) {
1321                 this._blendFunc = src;
1322                 this._updateBlendFunc();
1323             }
1324         } else {
1325             if (this._blendFunc.src != src || this._blendFunc.dst != dst) {
1326                 this._blendFunc = {src:src, dst:dst};
1327                 this._updateBlendFunc();
1328             }
1329         }
1330     },
1331 
1332     /**
1333      * does the alpha value modify color getter
1334      * @return {Boolean}
1335      */
1336     getOpacityModifyRGB:function () {
1337         return this._opacityModifyRGB;
1338     },
1339 
1340     /**
1341      * does the alpha value modify color setter
1342      * @param newValue
1343      */
1344     setOpacityModifyRGB:function (newValue) {
1345         this._opacityModifyRGB = newValue;
1346     },
1347 
1348     /**
1349      * <p>whether or not the particles are using blend additive.<br/>
1350      *     If enabled, the following blending function will be used.<br/>
1351      * </p>
1352      * @return {Boolean}
1353      * @example
1354      *    source blend function = GL_SRC_ALPHA;
1355      *    dest blend function = GL_ONE;
1356      */
1357     isBlendAdditive:function () {
1358         return (( this._blendFunc.src == gl.SRC_ALPHA && this._blendFunc.dst == gl.ONE) || (this._blendFunc.src == gl.ONE && this._blendFunc.dst == gl.ONE));
1359     },
1360 
1361     /**
1362      * <p>whether or not the particles are using blend additive.<br/>
1363      *     If enabled, the following blending function will be used.<br/>
1364      * </p>
1365      * @param {Boolean} isBlendAdditive
1366      */
1367     setBlendAdditive:function (isBlendAdditive) {
1368         var locBlendFunc = this._blendFunc;
1369         if (isBlendAdditive) {
1370             locBlendFunc.src = gl.SRC_ALPHA;
1371             locBlendFunc.dst = gl.ONE;
1372         } else {
1373             if (cc.renderContextType === cc.WEBGL) {
1374                 if (this._texture && !this._texture.hasPremultipliedAlpha()) {
1375                     locBlendFunc.src = gl.SRC_ALPHA;
1376                     locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA;
1377                 } else {
1378                     locBlendFunc.src = cc.BLEND_SRC;
1379                     locBlendFunc.dst = cc.BLEND_DST;
1380                 }
1381             } else {
1382                 locBlendFunc.src = cc.BLEND_SRC;
1383                 locBlendFunc.dst = cc.BLEND_DST;
1384             }
1385         }
1386     },
1387 
1388     /**
1389      * get particles movement type: Free or Grouped
1390      * @return {Number}
1391      */
1392     getPositionType:function () {
1393         return this._positionType;
1394     },
1395 
1396     /**
1397      * set particles movement type: Free or Grouped
1398      * @param {Number} positionType
1399      */
1400     setPositionType:function (positionType) {
1401         this._positionType = positionType;
1402     },
1403 
1404     /**
1405      *  <p> return whether or not the node will be auto-removed when it has no particles left.<br/>
1406      *      By default it is false.<br/>
1407      *  </p>
1408      * @return {Boolean}
1409      */
1410     isAutoRemoveOnFinish:function () {
1411         return this._isAutoRemoveOnFinish;
1412     },
1413 
1414     /**
1415      *  <p> set whether or not the node will be auto-removed when it has no particles left.<br/>
1416      *      By default it is false.<br/>
1417      *  </p>
1418      * @param {Boolean} isAutoRemoveOnFinish
1419      */
1420     setAutoRemoveOnFinish:function (isAutoRemoveOnFinish) {
1421         this._isAutoRemoveOnFinish = isAutoRemoveOnFinish;
1422     },
1423 
1424     /**
1425      * return kind of emitter modes
1426      * @return {Number}
1427      */
1428     getEmitterMode:function () {
1429         return this._emitterMode;
1430     },
1431 
1432     /**
1433      * <p>Switch between different kind of emitter modes:<br/>
1434      *  - CCPARTICLE_MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration<br/>
1435      *  - CCPARTICLE_MODE_RADIUS: uses radius movement + rotation <br/>
1436      *  </p>
1437      * @param {Number} emitterMode
1438      */
1439     setEmitterMode:function (emitterMode) {
1440         this._emitterMode = emitterMode;
1441     },
1442 
1443     /**
1444      * initializes a cc.ParticleSystem
1445      */
1446     init:function () {
1447         return this.initWithTotalParticles(150);
1448     },
1449 
1450     /**
1451      * <p>
1452      *     initializes a CCParticleSystem from a plist file. <br/>
1453      *      This plist files can be creted manually or with Particle Designer:<br/>
1454      *      http://particledesigner.71squared.com/
1455      * </p>
1456      * @param {String} plistFile
1457      * @return {boolean}
1458      */
1459     initWithFile:function (plistFile) {
1460         this._plistFile = plistFile;
1461         var dict = cc.FileUtils.getInstance().dictionaryWithContentsOfFileThreadSafe(this._plistFile);
1462 
1463         cc.Assert(dict != null, "Particles: file not found");
1464 
1465         // XXX compute path from a path, should define a function somewhere to do it
1466         return this.initWithDictionary(dict, "");
1467     },
1468 
1469     /**
1470      * return bounding box of particle system in world space
1471      * @return {cc.Rect}
1472      */
1473     getBoundingBoxToWorld:function () {
1474         return cc.rect(0, 0, cc.canvas.width, cc.canvas.height);
1475     },
1476 
1477     /**
1478      * initializes a particle system from a NSDictionary and the path from where to load the png
1479      * @param {object} dictionary
1480      * @param {String} dirname
1481      * @return {Boolean}
1482      */
1483     initWithDictionary:function (dictionary, dirname) {
1484         var ret = false;
1485         var buffer = null;
1486         var image = null;
1487         var locValueForKey = this._valueForKey;
1488 
1489         var maxParticles = parseInt(locValueForKey("maxParticles", dictionary));
1490         // self, not super
1491         if (this.initWithTotalParticles(maxParticles)) {
1492             // angle
1493             this._angle = parseFloat(locValueForKey("angle", dictionary));
1494             this._angleVar = parseFloat(locValueForKey("angleVariance", dictionary));
1495 
1496             // duration
1497             this._duration = parseFloat(locValueForKey("duration", dictionary));
1498 
1499             // blend function
1500             this._blendFunc.src = parseInt(locValueForKey("blendFuncSource", dictionary));
1501             this._blendFunc.dst = parseInt(locValueForKey("blendFuncDestination", dictionary));
1502 
1503             // color
1504             var locStartColor = this._startColor;
1505             locStartColor.r = parseFloat(locValueForKey("startColorRed", dictionary));
1506             locStartColor.g = parseFloat(locValueForKey("startColorGreen", dictionary));
1507             locStartColor.b = parseFloat(locValueForKey("startColorBlue", dictionary));
1508             locStartColor.a = parseFloat(locValueForKey("startColorAlpha", dictionary));
1509 
1510             var locStartColorVar = this._startColorVar;
1511             locStartColorVar.r = parseFloat(locValueForKey("startColorVarianceRed", dictionary));
1512             locStartColorVar.g = parseFloat(locValueForKey("startColorVarianceGreen", dictionary));
1513             locStartColorVar.b = parseFloat(locValueForKey("startColorVarianceBlue", dictionary));
1514             locStartColorVar.a = parseFloat(locValueForKey("startColorVarianceAlpha", dictionary));
1515 
1516             var locEndColor = this._endColor;
1517             locEndColor.r = parseFloat(locValueForKey("finishColorRed", dictionary));
1518             locEndColor.g = parseFloat(locValueForKey("finishColorGreen", dictionary));
1519             locEndColor.b = parseFloat(locValueForKey("finishColorBlue", dictionary));
1520             locEndColor.a = parseFloat(locValueForKey("finishColorAlpha", dictionary));
1521 
1522             var locEndColorVar = this._endColorVar;
1523             locEndColorVar.r = parseFloat(locValueForKey("finishColorVarianceRed", dictionary));
1524             locEndColorVar.g = parseFloat(locValueForKey("finishColorVarianceGreen", dictionary));
1525             locEndColorVar.b = parseFloat(locValueForKey("finishColorVarianceBlue", dictionary));
1526             locEndColorVar.a = parseFloat(locValueForKey("finishColorVarianceAlpha", dictionary));
1527 
1528             // particle size
1529             this._startSize = parseFloat(locValueForKey("startParticleSize", dictionary));
1530             this._startSizeVar = parseFloat(locValueForKey("startParticleSizeVariance", dictionary));
1531             this._endSize = parseFloat(locValueForKey("finishParticleSize", dictionary));
1532             this._endSizeVar = parseFloat(locValueForKey("finishParticleSizeVariance", dictionary));
1533 
1534             // position
1535             var x = parseFloat(locValueForKey("sourcePositionx", dictionary));
1536             var y = parseFloat(locValueForKey("sourcePositiony", dictionary));
1537             this.setPosition(x, y);
1538             this._posVar.x = parseFloat(locValueForKey("sourcePositionVariancex", dictionary));
1539             this._posVar.y = parseFloat(locValueForKey("sourcePositionVariancey", dictionary));
1540 
1541             // Spinning
1542             this._startSpin = parseFloat(locValueForKey("rotationStart", dictionary));
1543             this._startSpinVar = parseFloat(locValueForKey("rotationStartVariance", dictionary));
1544             this._endSpin = parseFloat(locValueForKey("rotationEnd", dictionary));
1545             this._endSpinVar = parseFloat(locValueForKey("rotationEndVariance", dictionary));
1546 
1547             this._emitterMode = parseInt(locValueForKey("emitterType", dictionary));
1548 
1549             // Mode A: Gravity + tangential accel + radial accel
1550             if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) {
1551                 var locModeA = this.modeA;
1552                 // gravity
1553                 locModeA.gravity.x = parseFloat(locValueForKey("gravityx", dictionary));
1554                 locModeA.gravity.y = parseFloat(locValueForKey("gravityy", dictionary));
1555 
1556                 // speed
1557                 locModeA.speed = parseFloat(locValueForKey("speed", dictionary));
1558                 locModeA.speedVar = parseFloat(locValueForKey("speedVariance", dictionary));
1559 
1560                 // radial acceleration
1561                 var pszTmp = locValueForKey("radialAcceleration", dictionary);
1562                 locModeA.radialAccel = (pszTmp) ? parseFloat(pszTmp) : 0;
1563 
1564                 pszTmp = locValueForKey("radialAccelVariance", dictionary);
1565                 locModeA.radialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0;
1566 
1567                 // tangential acceleration
1568                 pszTmp = locValueForKey("tangentialAcceleration", dictionary);
1569                 locModeA.tangentialAccel = (pszTmp) ? parseFloat(pszTmp) : 0;
1570 
1571                 pszTmp = locValueForKey("tangentialAccelVariance", dictionary);
1572                 locModeA.tangentialAccelVar = (pszTmp) ? parseFloat(pszTmp) : 0;
1573 
1574                 // rotation is dir
1575                 var locRotationIsDir = locValueForKey("rotationIsDir", dictionary).toLowerCase();
1576                 locModeA.rotationIsDir = (locRotationIsDir != null && (locRotationIsDir === "true" || locRotationIsDir === "1"));
1577             } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) {
1578                 // or Mode B: radius movement
1579                 var locModeB = this.modeB;
1580                 locModeB.startRadius = parseFloat(locValueForKey("maxRadius", dictionary));
1581                 locModeB.startRadiusVar = parseFloat(locValueForKey("maxRadiusVariance", dictionary));
1582                 locModeB.endRadius = parseFloat(locValueForKey("minRadius", dictionary));
1583                 locModeB.endRadiusVar = 0;
1584                 locModeB.rotatePerSecond = parseFloat(locValueForKey("rotatePerSecond", dictionary));
1585                 locModeB.rotatePerSecondVar = parseFloat(locValueForKey("rotatePerSecondVariance", dictionary));
1586             } else {
1587                 cc.Assert(false, "Invalid emitterType in config file");
1588                 return false;
1589             }
1590 
1591             // life span
1592             this._life = parseFloat(locValueForKey("particleLifespan", dictionary));
1593             this._lifeVar = parseFloat(locValueForKey("particleLifespanVariance", dictionary));
1594 
1595             // emission Rate
1596             this._emissionRate = this._totalParticles / this._life;
1597 
1598             //don't get the internal texture if a batchNode is used
1599             if (!this._batchNode) {
1600                 // Set a compatible default for the alpha transfer
1601                 this._opacityModifyRGB = false;
1602 
1603                 // texture
1604                 // Try to get the texture from the cache
1605                 var textureName = locValueForKey("textureFileName", dictionary);
1606                 var fullpath = cc.FileUtils.getInstance().fullPathFromRelativeFile(textureName, this._plistFile);
1607 
1608                 var tex = cc.TextureCache.getInstance().textureForKey(fullpath);
1609 
1610                 if (tex) {
1611                     this.setTexture(tex);
1612                 } else {
1613                     var textureData = locValueForKey("textureImageData", dictionary);
1614 
1615                     if (textureData && textureData.length == 0) {
1616                         cc.Assert(textureData, "cc.ParticleSystem.initWithDictory:textureImageData is null");
1617                         tex = cc.TextureCache.getInstance().addImage(fullpath);
1618                         if (!tex)
1619                             return false;
1620                         this.setTexture(tex);
1621                     } else {
1622                         buffer = cc.unzipBase64AsArray(textureData, 1);
1623                         if (!buffer) {
1624                             cc.log("cc.ParticleSystem: error decoding or ungzipping textureImageData");
1625                             return false;
1626                         }
1627 
1628                         var imageFormat = cc.getImageFormatByData(buffer);
1629 
1630                         if(imageFormat !== cc.FMT_TIFF && imageFormat !== cc.FMT_PNG){
1631                             cc.log("cc.ParticleSystem: unknown image format with Data");
1632                             return false;
1633                         }
1634 
1635                         var canvasObj = document.createElement("canvas");
1636                         if(imageFormat === cc.FMT_PNG){
1637                             var myPngObj = new cc.PNGReader(buffer);
1638                             myPngObj.render(canvasObj);
1639 
1640                         } else {
1641                             var myTIFFObj = cc.TIFFReader.getInstance();
1642                             myTIFFObj.parseTIFF(buffer,canvasObj);
1643                         }
1644 
1645                         cc.TextureCache.getInstance().cacheImage(fullpath, canvasObj);
1646 
1647                         var addTexture = cc.TextureCache.getInstance().textureForKey(fullpath);
1648 
1649                         cc.Assert(addTexture != null, "cc.ParticleSystem: error loading the texture");
1650 
1651                         this.setTexture(addTexture);
1652                     }
1653                 }
1654 
1655             }
1656             ret = true;
1657         }
1658         return ret;
1659     },
1660 
1661     /**
1662      * Initializes a system with a fixed number of particles
1663      * @param {Number} numberOfParticles
1664      * @return {Boolean}
1665      */
1666     initWithTotalParticles:function (numberOfParticles) {
1667         this._totalParticles = numberOfParticles;
1668 
1669         var i;
1670         this._particles = [];
1671         for(i = 0; i< numberOfParticles; i++){
1672             this._particles[i] = new cc.Particle();
1673         }
1674 
1675         if (!this._particles) {
1676             cc.log("Particle system: not enough memory");
1677             return false;
1678         }
1679         this._allocatedParticles = numberOfParticles;
1680 
1681         if (this._batchNode)
1682             for (i = 0; i < this._totalParticles; i++)
1683                 this._particles[i].atlasIndex = i;
1684 
1685         // default, active
1686         this._isActive = true;
1687 
1688         // default blend function
1689         this._blendFunc.src = cc.BLEND_SRC;
1690         this._blendFunc.dst = cc.BLEND_DST;
1691 
1692         // default movement type;
1693         this._positionType = cc.PARTICLE_TYPE_FREE;
1694 
1695         // by default be in mode A:
1696         this._emitterMode = cc.PARTICLE_MODE_GRAVITY;
1697 
1698         // default: modulate
1699         // XXX: not used
1700         //  colorModulate = YES;
1701         this._isAutoRemoveOnFinish = false;
1702 
1703         // Optimization: compile udpateParticle method
1704         //updateParticleSel = @selector(updateQuadWithParticle:newPosition:);
1705         //updateParticleImp = (CC_UPDATE_PARTICLE_IMP) [self methodForSelector:updateParticleSel];
1706 
1707         //for batchNode
1708         this._transformSystemDirty = false;
1709 
1710         // udpate after action in run!
1711         this.scheduleUpdateWithPriority(1);
1712 
1713         if(cc.renderContextType === cc.WEBGL){
1714             // allocating data space
1715             if (!this._allocMemory())
1716                 return false;
1717 
1718             this.initIndices();
1719             //if (cc.TEXTURE_ATLAS_USE_VAO)
1720             //    this._setupVBOandVAO();
1721             //else
1722             this._setupVBO();
1723 
1724             this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_TEXTURECOLOR));
1725         }
1726 
1727         return true;
1728     },
1729 
1730     destroyParticleSystem:function () {
1731         this.unscheduleUpdate();
1732     },
1733 
1734     /**
1735      * Add a particle to the emitter
1736      * @return {Boolean}
1737      */
1738     addParticle: function () {
1739         if (this.isFull())
1740             return false;
1741         var particle, particles = this._particles;
1742         if (cc.renderContextType === cc.CANVAS) {
1743             if (this._particleCount < particles.length) {
1744                 particle = particles[this._particleCount];
1745             } else {
1746                 particle = new cc.Particle();
1747                 particles.push(particle);
1748             }
1749         } else {
1750             particle = particles[this._particleCount];
1751         }
1752         this.initParticle(particle);
1753         ++this._particleCount;
1754         return true;
1755     },
1756 
1757     /**
1758      * Initializes a particle
1759      * @param {cc.Particle} particle
1760      */
1761     initParticle:function (particle) {
1762         var locRandomMinus11 = cc.RANDOM_MINUS1_1;
1763         // timeToLive
1764         // no negative life. prevent division by 0
1765         particle.timeToLive = this._life + this._lifeVar * locRandomMinus11();
1766         particle.timeToLive = Math.max(0, particle.timeToLive);
1767 
1768         // position
1769         particle.pos.x = this._sourcePosition.x + this._posVar.x * locRandomMinus11();
1770         particle.pos.y = this._sourcePosition.y + this._posVar.y * locRandomMinus11();
1771 
1772         // Color
1773         var start, end;
1774         var locStartColor = this._startColor, locStartColorVar = this._startColorVar;
1775         var locEndColor = this._endColor, locEndColorVar = this._endColorVar;
1776         if (cc.renderContextType === cc.CANVAS) {
1777             start = new cc.Color4F(
1778                 cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1),
1779                 cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1),
1780                 cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1),
1781                 cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1)
1782             );
1783             end = new cc.Color4F(
1784                 cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1),
1785                 cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1),
1786                 cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1),
1787                 cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1)
1788             );
1789         } else {
1790             start = {
1791                 r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 1),
1792                 g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 1),
1793                 b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 1),
1794                 a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 1)
1795             };
1796             end = {
1797                 r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 1),
1798                 g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 1),
1799                 b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 1),
1800                 a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 1)
1801             };
1802         }
1803 
1804         particle.color = start;
1805         var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive;
1806         locParticleDeltaColor.r = (end.r - start.r) / locParticleTimeToLive;
1807         locParticleDeltaColor.g = (end.g - start.g) / locParticleTimeToLive;
1808         locParticleDeltaColor.b = (end.b - start.b) / locParticleTimeToLive;
1809         locParticleDeltaColor.a = (end.a - start.a) / locParticleTimeToLive;
1810 
1811         // size
1812         var startS = this._startSize + this._startSizeVar * locRandomMinus11();
1813         startS = Math.max(0, startS); // No negative value
1814 
1815         particle.size = startS;
1816         if (this._endSize === cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE) {
1817             particle.deltaSize = 0;
1818         } else {
1819             var endS = this._endSize + this._endSizeVar * locRandomMinus11();
1820             endS = Math.max(0, endS); // No negative values
1821             particle.deltaSize = (endS - startS) / locParticleTimeToLive;
1822         }
1823 
1824         // rotation
1825         var startA = this._startSpin + this._startSpinVar * locRandomMinus11();
1826         var endA = this._endSpin + this._endSpinVar * locRandomMinus11();
1827         particle.rotation = startA;
1828         particle.deltaRotation = (endA - startA) / locParticleTimeToLive;
1829 
1830         // position
1831         if (this._positionType == cc.PARTICLE_TYPE_FREE)
1832             particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle);
1833         else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE)
1834             particle.startPos = this._position;
1835 
1836         // direction
1837         var a = cc.DEGREES_TO_RADIANS(this._angle + this._angleVar * locRandomMinus11());
1838 
1839         // Mode Gravity: A
1840         if (this._emitterMode === cc.PARTICLE_MODE_GRAVITY) {
1841             var locModeA = this.modeA, locParticleModeA = particle.modeA;
1842             var s = locModeA.speed + locModeA.speedVar * locRandomMinus11();
1843 
1844             // direction
1845             locParticleModeA.dir.x = Math.cos(a);
1846             locParticleModeA.dir.y = Math.sin(a);
1847             cc.pMultIn(locParticleModeA.dir, s);
1848 
1849             // radial accel
1850             locParticleModeA.radialAccel = locModeA.radialAccel + locModeA.radialAccelVar * locRandomMinus11();
1851 
1852             // tangential accel
1853             locParticleModeA.tangentialAccel = locModeA.tangentialAccel + locModeA.tangentialAccelVar * locRandomMinus11();
1854 
1855             // rotation is dir
1856             if(locModeA.rotationIsDir)
1857                 particle.rotation = -cc.RADIANS_TO_DEGREES(cc.pToAngle(locParticleModeA.dir));
1858         } else {
1859             // Mode Radius: B
1860             var locModeB = this.modeB, locParitlceModeB = particle.modeB;
1861 
1862             // Set the default diameter of the particle from the source position
1863             var startRadius = locModeB.startRadius + locModeB.startRadiusVar * locRandomMinus11();
1864             var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11();
1865 
1866             locParitlceModeB.radius = startRadius;
1867             locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive;
1868 
1869             locParitlceModeB.angle = a;
1870             locParitlceModeB.degreesPerSecond = cc.DEGREES_TO_RADIANS(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11());
1871         }
1872     },
1873 
1874     /**
1875      * stop emitting particles. Running particles will continue to run until they die
1876      */
1877     stopSystem:function () {
1878         this._isActive = false;
1879         this._elapsed = this._duration;
1880         this._emitCounter = 0;
1881     },
1882 
1883     /**
1884      * Kill all living particles.
1885      */
1886     resetSystem:function () {
1887         this._isActive = true;
1888         this._elapsed = 0;
1889         var locParticles = this._particles;
1890         for (this._particleIdx = 0; this._particleIdx < this._particleCount; ++this._particleIdx)
1891             locParticles[this._particleIdx].timeToLive = 0 ;
1892     },
1893 
1894     /**
1895      * whether or not the system is full
1896      * @return {Boolean}
1897      */
1898     isFull:function () {
1899         return (this._particleCount >= this._totalParticles);
1900     },
1901 
1902     /**
1903      * should be overridden by subclasses
1904      * @param {cc.Particle} particle
1905      * @param {cc.Point} newPosition
1906      */
1907     updateQuadWithParticle:function (particle, newPosition) {
1908         var quad = null;
1909         if (this._batchNode) {
1910             var batchQuads = this._batchNode.getTextureAtlas().getQuads();
1911             quad = batchQuads[this._atlasIndex + particle.atlasIndex];
1912             this._batchNode.getTextureAtlas()._dirty = true;
1913         } else
1914             quad = this._quads[this._particleIdx];
1915 
1916         var r, g, b, a;
1917         if(this._opacityModifyRGB){
1918             r = 0 | (particle.color.r * particle.color.a * 255);
1919             g = 0 | (particle.color.g * particle.color.a * 255);
1920             b = 0 | (particle.color.b * particle.color.a * 255);
1921             a = 0 | (particle.color.a * 255);
1922         }else{
1923             r = 0 | (particle.color.r * 255);
1924             g = 0 | (particle.color.g * 255);
1925             b = 0 | (particle.color.b * 255);
1926             a = 0 | (particle.color.a * 255);
1927         }
1928 
1929         var locColors = quad.bl.colors;
1930         locColors.r = r;
1931         locColors.g = g;
1932         locColors.b = b;
1933         locColors.a = a;
1934 
1935         locColors = quad.br.colors;
1936         locColors.r = r;
1937         locColors.g = g;
1938         locColors.b = b;
1939         locColors.a = a;
1940 
1941         locColors = quad.tl.colors;
1942         locColors.r = r;
1943         locColors.g = g;
1944         locColors.b = b;
1945         locColors.a = a;
1946 
1947         locColors = quad.tr.colors;
1948         locColors.r = r;
1949         locColors.g = g;
1950         locColors.b = b;
1951         locColors.a = a;
1952 
1953         // vertices
1954         var size_2 = particle.size / 2;
1955         if (particle.rotation) {
1956             var x1 = -size_2;
1957             var y1 = -size_2;
1958 
1959             var x2 = size_2;
1960             var y2 = size_2;
1961             var x = newPosition.x;
1962             var y = newPosition.y;
1963 
1964             var rad = -cc.DEGREES_TO_RADIANS(particle.rotation);
1965             var cr = Math.cos(rad);
1966             var sr = Math.sin(rad);
1967             var ax = x1 * cr - y1 * sr + x;
1968             var ay = x1 * sr + y1 * cr + y;
1969             var bx = x2 * cr - y1 * sr + x;
1970             var by = x2 * sr + y1 * cr + y;
1971             var cx = x2 * cr - y2 * sr + x;
1972             var cy = x2 * sr + y2 * cr + y;
1973             var dx = x1 * cr - y2 * sr + x;
1974             var dy = x1 * sr + y2 * cr + y;
1975 
1976             // bottom-left
1977             quad.bl.vertices.x = ax;
1978             quad.bl.vertices.y = ay;
1979 
1980             // bottom-right vertex:
1981             quad.br.vertices.x = bx;
1982             quad.br.vertices.y = by;
1983 
1984             // top-left vertex:
1985             quad.tl.vertices.x = dx;
1986             quad.tl.vertices.y = dy;
1987 
1988             // top-right vertex:
1989             quad.tr.vertices.x = cx;
1990             quad.tr.vertices.y = cy;
1991         } else {
1992             // bottom-left vertex:
1993             quad.bl.vertices.x = newPosition.x - size_2;
1994             quad.bl.vertices.y = newPosition.y - size_2;
1995 
1996             // bottom-right vertex:
1997             quad.br.vertices.x = newPosition.x + size_2;
1998             quad.br.vertices.y = newPosition.y - size_2;
1999 
2000             // top-left vertex:
2001             quad.tl.vertices.x = newPosition.x - size_2;
2002             quad.tl.vertices.y = newPosition.y + size_2;
2003 
2004             // top-right vertex:
2005             quad.tr.vertices.x = newPosition.x + size_2;
2006             quad.tr.vertices.y = newPosition.y + size_2;
2007         }
2008     },
2009 
2010     /**
2011      * should be overridden by subclasses
2012      */
2013     postStep:function () {
2014         if (cc.renderContextType === cc.WEBGL) {
2015             var gl = cc.renderContext;
2016 
2017             gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]);
2018             gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW);
2019 
2020             // Option 2: Data
2021             //	glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW);
2022 
2023             // Option 3: Orphaning + glMapBuffer
2024             // glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*m_uTotalParticles, NULL, GL_STREAM_DRAW);
2025             // void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
2026             // memcpy(buf, m_pQuads, sizeof(m_pQuads[0])*m_uTotalParticles);
2027             // glUnmapBuffer(GL_ARRAY_BUFFER);
2028 
2029             //cc.CHECK_GL_ERROR_DEBUG();
2030         }
2031     },
2032 
2033     /**
2034      * update emitter's status
2035      * @override
2036      * @param {Number} dt delta time
2037      */
2038     update:function (dt) {
2039         if (this._isActive && this._emissionRate) {
2040             var rate = 1.0 / this._emissionRate;
2041             //issue #1201, prevent bursts of particles, due to too high emitCounter
2042             if (this._particleCount < this._totalParticles)
2043                 this._emitCounter += dt;
2044 
2045             while ((this._particleCount < this._totalParticles) && (this._emitCounter > rate)) {
2046                 this.addParticle();
2047                 this._emitCounter -= rate;
2048             }
2049 
2050             this._elapsed += dt;
2051             if (this._duration != -1 && this._duration < this._elapsed)
2052                 this.stopSystem();
2053         }
2054         this._particleIdx = 0;
2055 
2056         var currentPosition = cc.Particle.TemporaryPoints[0];
2057         if (this._positionType == cc.PARTICLE_TYPE_FREE) {
2058             cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle));
2059 
2060         } else if (this._positionType == cc.PARTICLE_TYPE_RELATIVE) {
2061             currentPosition.x = this._position.x;
2062             currentPosition.y = this._position.y;
2063         }
2064 
2065         if (this._visible) {
2066 
2067             // Used to reduce memory allocation / creation within the loop
2068             var tpa = cc.Particle.TemporaryPoints[1],
2069                 tpb = cc.Particle.TemporaryPoints[2],
2070                 tpc = cc.Particle.TemporaryPoints[3];
2071 
2072             var locParticles = this._particles;
2073             while (this._particleIdx < this._particleCount) {
2074 
2075                 // Reset the working particles
2076                 cc.pZeroIn(tpa);
2077                 cc.pZeroIn(tpb);
2078                 cc.pZeroIn(tpc);
2079 
2080                 var selParticle = locParticles[this._particleIdx];
2081 
2082                 // life
2083                 selParticle.timeToLive -= dt;
2084 
2085                 if (selParticle.timeToLive > 0) {
2086                     // Mode A: gravity, direction, tangential accel & radial accel
2087                     if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) {
2088 
2089                         var tmp = tpc, radial = tpa, tangential = tpb;
2090 
2091                         // radial acceleration
2092                         if (selParticle.pos.x || selParticle.pos.y) {
2093                             cc.pIn(radial, selParticle.pos);
2094                             cc.pNormalizeIn(radial);
2095                         } else {
2096                             cc.pZeroIn(radial);
2097                         }
2098 
2099                         cc.pIn(tangential, radial);
2100                         cc.pMultIn(radial, selParticle.modeA.radialAccel);
2101 
2102                         // tangential acceleration
2103                         var newy = tangential.x;
2104                         tangential.x = -tangential.y;
2105                         tangential.y = newy;
2106 
2107                         cc.pMultIn(tangential, selParticle.modeA.tangentialAccel);
2108 
2109                         cc.pIn(tmp, radial);
2110                         cc.pAddIn(tmp, tangential);
2111                         cc.pAddIn(tmp, this.modeA.gravity);
2112                         cc.pMultIn(tmp, dt);
2113                         cc.pAddIn(selParticle.modeA.dir, tmp);
2114 
2115 
2116                         cc.pIn(tmp, selParticle.modeA.dir);
2117                         cc.pMultIn(tmp, dt);
2118                         cc.pAddIn(selParticle.pos, tmp);
2119 
2120                     } else {
2121                         // Mode B: radius movement
2122                         var selModeB = selParticle.modeB;
2123                         // Update the angle and radius of the particle.
2124                         selModeB.angle += selModeB.degreesPerSecond * dt;
2125                         selModeB.radius += selModeB.deltaRadius * dt;
2126 
2127                         selParticle.pos.x = -Math.cos(selModeB.angle) * selModeB.radius;
2128                         selParticle.pos.y = -Math.sin(selModeB.angle) * selModeB.radius;
2129                     }
2130 
2131                     // color
2132                     if (!this._dontTint) {
2133                         selParticle.color.r += (selParticle.deltaColor.r * dt);
2134                         selParticle.color.g += (selParticle.deltaColor.g * dt);
2135                         selParticle.color.b += (selParticle.deltaColor.b * dt);
2136                         selParticle.color.a += (selParticle.deltaColor.a * dt);
2137                         selParticle.isChangeColor = true;
2138                     }
2139 
2140                     // size
2141                     selParticle.size += (selParticle.deltaSize * dt);
2142                     selParticle.size = Math.max(0, selParticle.size);
2143 
2144                     // angle
2145                     selParticle.rotation += (selParticle.deltaRotation * dt);
2146 
2147                     //
2148                     // update values in quad
2149                     //
2150                     var newPos = tpa;
2151                     if (this._positionType == cc.PARTICLE_TYPE_FREE || this._positionType == cc.PARTICLE_TYPE_RELATIVE) {
2152 
2153                         var diff = tpb;
2154                         cc.pIn(diff, currentPosition);
2155                         cc.pSubIn(diff, selParticle.startPos);
2156 
2157                         cc.pIn(newPos, selParticle.pos);
2158                         cc.pSubIn(newPos, diff);
2159 
2160                     } else {
2161                         cc.pIn(newPos, selParticle.pos);
2162                     }
2163 
2164                     // translate newPos to correct position, since matrix transform isn't performed in batchnode
2165                     // don't update the particle with the new position information, it will interfere with the radius and tangential calculations
2166                     if (this._batchNode) {
2167                         newPos.x += this._position.x;
2168                         newPos.y += this._position.y;
2169                     }
2170 
2171                     if (cc.renderContextType == cc.WEBGL) {
2172                         // IMPORTANT: newPos may not be used as a reference here! (as it is just the temporary tpa point)
2173                         // the implementation of updateQuadWithParticle must use
2174                         // the x and y values directly
2175                         this.updateQuadWithParticle(selParticle, newPos);
2176                     } else {
2177                         cc.pIn(selParticle.drawPos, newPos);
2178                     }
2179                     //updateParticleImp(self, updateParticleSel, p, newPos);
2180 
2181                     // update particle counter
2182                     ++this._particleIdx;
2183                 } else {
2184                     // life < 0
2185                     var currentIndex = selParticle.atlasIndex;
2186                     if(this._particleIdx !== this._particleCount -1){
2187                          var deadParticle = locParticles[this._particleIdx];
2188                         locParticles[this._particleIdx] = locParticles[this._particleCount -1];
2189                         locParticles[this._particleCount -1] = deadParticle;
2190                     }
2191                     if (this._batchNode) {
2192                         //disable the switched particle
2193                         this._batchNode.disableParticle(this._atlasIndex + currentIndex);
2194 
2195                         //switch indexes
2196                         locParticles[this._particleCount - 1].atlasIndex = currentIndex;
2197                     }
2198 
2199                     --this._particleCount;
2200                     if (this._particleCount == 0 && this._isAutoRemoveOnFinish) {
2201                         this.unscheduleUpdate();
2202                         this._parent.removeChild(this, true);
2203                         return;
2204                     }
2205                 }
2206             }
2207             this._transformSystemDirty = false;
2208         }
2209 
2210         if (!this._batchNode)
2211             this.postStep();
2212     },
2213 
2214     updateWithNoTime:function () {
2215         this.update(0);
2216     },
2217 
2218     /**
2219      * return the string found by key in dict.
2220      * @param {string} key
2221      * @param {object} dict
2222      * @return {String} "" if not found; return the string if found.
2223      * @private
2224      */
2225     _valueForKey:function (key, dict) {
2226         if (dict) {
2227             var pString = dict[key];
2228             return pString != null ? pString : "";
2229         }
2230         return "";
2231     },
2232 
2233     _updateBlendFunc:function () {
2234         cc.Assert(!this._batchNode, "Can't change blending functions when the particle is being batched");
2235 
2236         var locTexture = this._texture;
2237         if (locTexture && locTexture instanceof cc.Texture2D) {
2238             this._opacityModifyRGB = false;
2239             var locBlendFunc = this._blendFunc;
2240             if (locBlendFunc.src == cc.BLEND_SRC && locBlendFunc.dst == cc.BLEND_DST) {
2241                 if (locTexture.hasPremultipliedAlpha()) {
2242                     this._opacityModifyRGB = true;
2243                 } else {
2244                     locBlendFunc.src = gl.SRC_ALPHA;
2245                     locBlendFunc.dst = gl.ONE_MINUS_SRC_ALPHA;
2246                 }
2247             }
2248         }
2249     },
2250 
2251     clone:function () {
2252         var retParticle = new cc.ParticleSystem();
2253 
2254         // self, not super
2255         if (retParticle.initWithTotalParticles(this._totalParticles)) {
2256             // angle
2257             retParticle._angle = this._angle;
2258             retParticle._angleVar = this._angleVar;
2259 
2260             // duration
2261             retParticle._duration = this._duration;
2262 
2263             // blend function
2264             retParticle._blendFunc.src = this._blendFunc.src;
2265             retParticle._blendFunc.dst = this._blendFunc.dst;
2266 
2267             // color
2268             var particleStartColor = retParticle._startColor, locStartColor = this._startColor;
2269             particleStartColor.r = locStartColor.r;
2270             particleStartColor.g = locStartColor.g;
2271             particleStartColor.b = locStartColor.b;
2272             particleStartColor.a = locStartColor.a;
2273 
2274             var particleStartColorVar =  retParticle._startColorVar, locStartColorVar = this._startColorVar;
2275             particleStartColorVar.r = locStartColorVar.r;
2276             particleStartColorVar.g = locStartColorVar.g;
2277             particleStartColorVar.b = locStartColorVar.b;
2278             particleStartColorVar.a = locStartColorVar.a;
2279 
2280             var particleEndColor = retParticle._endColor, locEndColor = this._endColor;
2281             particleEndColor.r = locEndColor.r;
2282             particleEndColor.g = locEndColor.g;
2283             particleEndColor.b = locEndColor.b;
2284             particleEndColor.a = locEndColor.a;
2285 
2286             var particleEndColorVar = retParticle._endColorVar, locEndColorVar = this._endColorVar;
2287             particleEndColorVar.r = locEndColorVar.r;
2288             particleEndColorVar.g = locEndColorVar.g;
2289             particleEndColorVar.b = locEndColorVar.b;
2290             particleEndColorVar.a = locEndColorVar.a;
2291 
2292             // particle size
2293             retParticle._startSize = this._startSize;
2294             retParticle._startSizeVar = this._startSizeVar;
2295             retParticle._endSize = this._endSize;
2296             retParticle._endSizeVar = this._endSizeVar;
2297 
2298             // position
2299             retParticle.setPosition(new cc.Point(this._position.x, this._position.y));
2300             retParticle._posVar.x = this._posVar.x;
2301             retParticle._posVar.y = this._posVar.y;
2302 
2303             // Spinning
2304             retParticle._startSpin = this._startSpin;
2305             retParticle._startSpinVar = this._startSpinVar;
2306             retParticle._endSpin = this._endSpin;
2307             retParticle._endSpinVar = this._endSpinVar;
2308 
2309             retParticle._emitterMode = this._emitterMode;
2310 
2311             // Mode A: Gravity + tangential accel + radial accel
2312             if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) {
2313                 var particleModeA = retParticle.modeA, locModeA = this.modeA;
2314                 // gravity
2315                 particleModeA.gravity.x = locModeA.gravity.x;
2316                 particleModeA.gravity.y = locModeA.gravity.y;
2317 
2318                 // speed
2319                 particleModeA.speed = locModeA.speed;
2320                 particleModeA.speedVar = locModeA.speedVar;
2321 
2322                 // radial acceleration
2323                 particleModeA.radialAccel = locModeA.radialAccel;
2324 
2325                 particleModeA.radialAccelVar = locModeA.radialAccelVar;
2326 
2327                 // tangential acceleration
2328                 particleModeA.tangentialAccel = locModeA.tangentialAccel;
2329 
2330                 particleModeA.tangentialAccelVar = locModeA.tangentialAccelVar;
2331             } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) {
2332                 var particleModeB = retParticle.modeB, locModeB = this.modeB;
2333                 // or Mode B: radius movement
2334                 particleModeB.startRadius = locModeB.startRadius;
2335                 particleModeB.startRadiusVar = locModeB.startRadiusVar;
2336                 particleModeB.endRadius = locModeB.endRadius;
2337                 particleModeB.endRadiusVar = locModeB.endRadiusVar;
2338                 particleModeB.rotatePerSecond = locModeB.rotatePerSecond;
2339                 particleModeB.rotatePerSecondVar = locModeB.rotatePerSecondVar;
2340             }
2341 
2342             // life span
2343             retParticle._life = this._life;
2344             retParticle._lifeVar = this._lifeVar;
2345 
2346             // emission Rate
2347             retParticle._emissionRate = this._emissionRate;
2348 
2349             //don't get the internal texture if a batchNode is used
2350             if (!this._batchNode) {
2351                 // Set a compatible default for the alpha transfer
2352                 retParticle._opacityModifyRGB = this._opacityModifyRGB;
2353 
2354                 // texture
2355                 retParticle._texture = this._texture;
2356             }
2357         }
2358         return retParticle;
2359     },
2360 
2361     /**
2362      * <p> Sets a new CCSpriteFrame as particle.</br>
2363      * WARNING: this method is experimental. Use setTextureWithRect instead.
2364      * </p>
2365      * @param {cc.SpriteFrame} spriteFrame
2366      */
2367     setDisplayFrame:function (spriteFrame) {
2368         cc.Assert(cc._rectEqualToZero(spriteFrame.getOffsetInPixels()), "QuadParticle only supports SpriteFrames with no offsets");
2369 
2370         // update texture before updating texture rect
2371         if (cc.renderContextType === cc.WEBGL)
2372             if (!this._texture || spriteFrame.getTexture()._webTextureObj != this._texture._webTextureObj)
2373                 this.setTexture(spriteFrame.getTexture());
2374     },
2375 
2376     /**
2377      *  Sets a new texture with a rect. The rect is in Points.
2378      * @param {cc.Texture2D} texture
2379      * @param {cc.Rect} rect
2380      */
2381     setTextureWithRect:function (texture, rect) {
2382         var locTexture = this._texture;
2383         if (cc.renderContextType === cc.WEBGL) {
2384             // Only update the texture if is different from the current one
2385             if ((!locTexture || texture._webTextureObj != locTexture._webTextureObj) && (locTexture != texture)) {
2386                 this._texture = texture;
2387                 this._updateBlendFunc();
2388             }
2389         } else {
2390             if ((!locTexture || texture != locTexture) && (locTexture != texture)) {
2391                 this._texture = texture;
2392                 this._updateBlendFunc();
2393             }
2394         }
2395 
2396         this._pointRect = rect;
2397         this.initTexCoordsWithRect(rect);
2398     },
2399 
2400     /**
2401      * draw particle
2402      * @param {CanvasRenderingContext2D} ctx CanvasContext
2403      * @override
2404      */
2405     draw:function (ctx) {
2406         cc.Assert(!this._batchNode, "draw should not be called when added to a particleBatchNode");
2407         if(!this._textureLoaded)
2408             return;
2409 
2410         if (cc.renderContextType === cc.CANVAS)
2411             this._drawForCanvas(ctx);
2412         else
2413             this._drawForWebGL(ctx);
2414 
2415         cc.g_NumberOfDraws++;
2416     },
2417 
2418     _drawForCanvas:function (ctx) {
2419         var context = ctx || cc.renderContext;
2420         context.save();
2421         if (this.isBlendAdditive())
2422             context.globalCompositeOperation = 'lighter';
2423         else
2424             context.globalCompositeOperation = 'source-over';
2425 
2426         for (var i = 0; i < this._particleCount; i++) {
2427             var particle = this._particles[i];
2428             var lpx = (0 | (particle.size * 0.5));
2429 
2430             if (this._drawMode == cc.PARTICLE_TEXTURE_MODE) {
2431 
2432                 var element = this._texture.getHtmlElementObj();
2433 
2434                 // Delay drawing until the texture is fully loaded by the browser
2435                 if (!element.width || !element.height)
2436                     continue;
2437 
2438                 context.save();
2439                 context.globalAlpha = particle.color.a;
2440                 context.translate((0 | particle.drawPos.x), -(0 | particle.drawPos.y));
2441 
2442                 var size = Math.floor(particle.size / 4) * 4;
2443                 var w = this._pointRect.width;
2444                 var h = this._pointRect.height;
2445 
2446                 context.scale(
2447                     Math.max((1 / w) * size, 0.000001),
2448                     Math.max((1 / h) * size, 0.000001)
2449                 );
2450 
2451 
2452                 if (particle.rotation)
2453                     context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation));
2454 
2455                 context.translate(-(0 | (w / 2)), -(0 | (h / 2)));
2456                 if (particle.isChangeColor) {
2457 
2458                     var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(element);
2459                     if (cacheTextureForColor) {
2460                         // Create another cache for the tinted version
2461                         // This speeds up things by a fair bit
2462                         if (!cacheTextureForColor.tintCache) {
2463                             cacheTextureForColor.tintCache = document.createElement('canvas');
2464                             cacheTextureForColor.tintCache.width = element.width;
2465                             cacheTextureForColor.tintCache.height = element.height;
2466                         }
2467                         cc.generateTintImage(element, cacheTextureForColor, particle.color, this._pointRect, cacheTextureForColor.tintCache);
2468                         element = cacheTextureForColor.tintCache;
2469                     }
2470                 }
2471 
2472                 context.drawImage(element, 0, 0);
2473                 context.restore();
2474 
2475             } else {
2476                 context.save();
2477                 context.globalAlpha = particle.color.a;
2478 
2479                 context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y));
2480 
2481                 if (this._shapeType == cc.PARTICLE_STAR_SHAPE) {
2482                     if (particle.rotation)
2483                         context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation));
2484                     cc.drawingUtil.drawStar(context, lpx, particle.color);
2485                 } else
2486                     cc.drawingUtil.drawColorBall(context, lpx, particle.color);
2487                 context.restore();
2488             }
2489         }
2490         context.restore();
2491     },
2492 
2493     _drawForWebGL:function (ctx) {
2494         if(!this._texture)
2495             return;
2496 
2497         var gl = ctx || cc.renderContext;
2498 
2499         this._shaderProgram.use();
2500         this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4();
2501 
2502         cc.glBindTexture2D(this._texture);
2503         cc.glBlendFuncForParticle(this._blendFunc.src, this._blendFunc.dst);
2504 
2505         //cc.Assert(this._particleIdx == this._particleCount, "Abnormal error in particle quad");
2506 
2507         //
2508         // Using VBO without VAO
2509         //
2510         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSCOLORTEX);
2511 
2512         gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]);
2513         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0);               // vertices
2514         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12);          // colors
2515         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16);            // tex coords
2516 
2517         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
2518         gl.drawElements(gl.TRIANGLES, this._particleIdx * 6, gl.UNSIGNED_SHORT, 0);
2519     },
2520 
2521     /**
2522      * listen the event that coming to foreground on Android
2523      * @param {cc.Class} obj
2524      */
2525     listenBackToForeground:function (obj) {
2526         if (cc.TEXTURE_ATLAS_USE_VAO)
2527             this._setupVBOandVAO();
2528         else
2529             this._setupVBO();
2530     },
2531 
2532     _setupVBOandVAO:function () {
2533         //Not support on WebGL
2534         /*if (cc.renderContextType == cc.CANVAS) {
2535          return;
2536          }*/
2537 
2538         //NOT SUPPORTED
2539         /*glGenVertexArrays(1, this._VAOname);
2540          glBindVertexArray(this._VAOname);
2541 
2542          var kQuadSize = sizeof(m_pQuads[0].bl);
2543 
2544          glGenBuffers(2, this._buffersVBO[0]);
2545 
2546          glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]);
2547          glBufferData(GL_ARRAY_BUFFER, sizeof(this._quads[0]) * this._totalParticles, this._quads, GL_DYNAMIC_DRAW);
2548 
2549          // vertices
2550          glEnableVertexAttribArray(kCCVertexAttrib_Position);
2551          glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices));
2552 
2553          // colors
2554          glEnableVertexAttribArray(kCCVertexAttrib_Color);
2555          glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors));
2556 
2557          // tex coords
2558          glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
2559          glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords));
2560 
2561          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
2562          glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW);
2563 
2564          glBindVertexArray(0);
2565          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
2566          glBindBuffer(GL_ARRAY_BUFFER, 0);
2567 
2568          CHECK_GL_ERROR_DEBUG();*/
2569     },
2570 
2571     _setupVBO:function () {
2572         if (cc.renderContextType == cc.CANVAS)
2573             return;
2574 
2575         var gl = cc.renderContext;
2576 
2577         //gl.deleteBuffer(this._buffersVBO[0]);
2578         this._buffersVBO[0] = gl.createBuffer();
2579         gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]);
2580         gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW);
2581 
2582         this._buffersVBO[1] = gl.createBuffer();
2583         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
2584         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
2585 
2586         //cc.CHECK_GL_ERROR_DEBUG();
2587     },
2588 
2589     _allocMemory:function () {
2590         if (cc.renderContextType === cc.CANVAS)
2591             return true;
2592 
2593         //cc.Assert((!this._quads && !this._indices), "Memory already allocated");
2594         cc.Assert(!this._batchNode, "Memory should not be allocated when not using batchNode");
2595         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
2596         var totalParticles = this._totalParticles;
2597         var locQuads = [];
2598         this._indices = new Uint16Array(totalParticles * 6);
2599         var locQuadsArrayBuffer = new ArrayBuffer(quadSize * totalParticles);
2600 
2601         for (var i = 0; i < totalParticles; i++)
2602             locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, i * quadSize);
2603         if (!locQuads || !this._indices) {
2604             cc.log("cocos2d: Particle system: not enough memory");
2605             return false;
2606         }
2607         this._quads = locQuads;
2608         this._quadsArrayBuffer = locQuadsArrayBuffer;
2609         return true;
2610     }
2611 });
2612 
2613 /**
2614  * <p> return the string found by key in dict. <br/>
2615  *    This plist files can be create manually or with Particle Designer:<br/>
2616  *    http://particledesigner.71squared.com/<br/>
2617  * </p>
2618  * @param {String} plistFile
2619  * @return {cc.ParticleSystem}
2620  */
2621 cc.ParticleSystem.create = function (plistFile) {
2622     var ret = new cc.ParticleSystem();
2623     if (!plistFile || typeof(plistFile) === "number") {
2624         var ton = plistFile || 100;
2625         ret.setDrawMode(cc.PARTICLE_TEXTURE_MODE);
2626         ret.initWithTotalParticles(ton);
2627         return ret;
2628     }
2629 
2630     if (ret && ret.initWithFile(plistFile))
2631         return ret;
2632     return null;
2633 };
2634 
2635 /**
2636  * create a system with a fixed number of particles
2637  * @param {Number} number_of_particles
2638  * @return {cc.ParticleSystem}
2639  */
2640 cc.ParticleSystem.createWithTotalParticles = function (number_of_particles) {
2641     //emitter.initWithTotalParticles(number_of_particles);
2642     var particle = new cc.ParticleSystem();
2643     if (particle && particle.initWithTotalParticles(number_of_particles))
2644         return particle;
2645     return null;
2646 };
2647 
2648 // Different modes
2649 /**
2650  * Mode A:Gravity + Tangential Accel + Radial Accel
2651  * @Class
2652  * @Construct
2653  * @param {cc.Point} [gravity=] Gravity value.
2654  * @param {Number} [speed=0] speed of each particle.
2655  * @param {Number} [speedVar=0] speed variance of each particle.
2656  * @param {Number} [tangentialAccel=0] tangential acceleration of each particle.
2657  * @param {Number} [tangentialAccelVar=0] tangential acceleration variance of each particle.
2658  * @param {Number} [radialAccel=0] radial acceleration of each particle.
2659  * @param {Number} [radialAccelVar=0] radial acceleration variance of each particle.
2660  * @param {boolean} [rotationIsDir=false]
2661  */
2662 cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, tangentialAccelVar, radialAccel, radialAccelVar, rotationIsDir) {
2663     /** Gravity value. Only available in 'Gravity' mode. */
2664     this.gravity = gravity ? gravity : cc.PointZero();
2665     /** speed of each particle. Only available in 'Gravity' mode.  */
2666     this.speed = speed || 0;
2667     /** speed variance of each particle. Only available in 'Gravity' mode. */
2668     this.speedVar = speedVar || 0;
2669     /** tangential acceleration of each particle. Only available in 'Gravity' mode. */
2670     this.tangentialAccel = tangentialAccel || 0;
2671     /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */
2672     this.tangentialAccelVar = tangentialAccelVar || 0;
2673     /** radial acceleration of each particle. Only available in 'Gravity' mode. */
2674     this.radialAccel = radialAccel || 0;
2675     /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */
2676     this.radialAccelVar = radialAccelVar || 0;
2677     /** set the rotation of each particle to its direction Only available in 'Gravity' mode. */
2678     this.rotationIsDir = rotationIsDir || false;
2679 };
2680 
2681 /**
2682  * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode)
2683  * @Class
2684  * @Construct
2685  * @param {Number} startRadius The starting radius of the particles.
2686  * @param {Number} startRadiusVar The starting radius variance of the particles.
2687  * @param {Number} endRadius The ending radius of the particles.
2688  * @param {Number} endRadiusVar The ending radius variance of the particles.
2689  * @param {Number} rotatePerSecond Number of degress to rotate a particle around the source pos per second.
2690  * @param {Number} rotatePerSecondVar Variance in degrees for rotatePerSecond.
2691  */
2692 cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) {
2693     /** The starting radius of the particles. Only available in 'Radius' mode. */
2694     this.startRadius = startRadius || 0;
2695     /** The starting radius variance of the particles. Only available in 'Radius' mode. */
2696     this.startRadiusVar = startRadiusVar || 0;
2697     /** The ending radius of the particles. Only available in 'Radius' mode. */
2698     this.endRadius = endRadius || 0;
2699     /** The ending radius variance of the particles. Only available in 'Radius' mode. */
2700     this.endRadiusVar = endRadiusVar || 0;
2701     /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */
2702     this.rotatePerSecond = rotatePerSecond || 0;
2703     /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */
2704     this.rotatePerSecondVar = rotatePerSecondVar || 0;
2705 };
2706