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 /**
 28  * <p>
 29  *     CCParticleSystemQuad is a subclass of CCParticleSystem<br/>
 30  *     <br/>
 31  *     It includes all the features of ParticleSystem.<br/>
 32  *     <br/>
 33  *     Special features and Limitations:<br/>
 34  *      - Particle size can be any float number. <br/>
 35  *      - The system can be scaled <br/>
 36  *      - The particles can be rotated     <br/>
 37  *      - It supports subrects   <br/>
 38  *      - It supports batched rendering since 1.1<br/>
 39  * </p>
 40  * @class
 41  * @extends cc.ParticleSystem
 42  * @example
 43  * //create a particle system
 44  *   this._emitter = new cc.ParticleSystemQuad();
 45  *   this._emitter.initWithTotalParticles(150);
 46  */
 47 cc.ParticleSystemQuad = cc.ParticleSystem.extend(/** @lends cc.ParticleSystemQuad# */{
 48     // quads to be rendered
 49     _quads:null,
 50     // indices
 51     _indices:null,
 52 
 53     _VAOname:0,
 54     //0: vertex  1: indices
 55     _buffersVBO:[],
 56 
 57     _pointRect:null,
 58     /**
 59      * Constructor
 60      * @override
 61      */
 62     ctor:function () {
 63         this._super();
 64         this._buffersVBO = [0, 0];
 65         this._quads = [];
 66         this._indices = [];
 67         this._pointRect = cc.RectZero();
 68     },
 69 
 70     /**
 71      * initialices the indices for the vertices
 72      */
 73     setupIndices:function () {
 74         for (var i = 0; i < this._totalParticles; ++i) {
 75             var i6 = i * 6;
 76             var i4 = i * 4;
 77             this._indices[i6 + 0] = i4 + 0;
 78             this._indices[i6 + 1] = i4 + 1;
 79             this._indices[i6 + 2] = i4 + 2;
 80 
 81             this._indices[i6 + 5] = i4 + 1;
 82             this._indices[i6 + 4] = i4 + 2;
 83             this._indices[i6 + 3] = i4 + 3;
 84         }
 85     },
 86 
 87     /**
 88      * <p> initilizes the texture with a rectangle measured Points<br/>
 89      * pointRect should be in Texture coordinates, not pixel coordinates
 90      * </p>
 91      * @param {cc.Rect} pointRect
 92      */
 93     initTexCoordsWithRect:function (pointRect) {
 94         // convert to pixels coords
 95         var rect = cc.rect(
 96             pointRect.origin.x * cc.CONTENT_SCALE_FACTOR(),
 97             pointRect.origin.y * cc.CONTENT_SCALE_FACTOR(),
 98             pointRect.size.width * cc.CONTENT_SCALE_FACTOR(),
 99             pointRect.size.height * cc.CONTENT_SCALE_FACTOR());
100 
101         var wide = pointRect.size.width;
102         var high = pointRect.size.height;
103 
104         if (this._texture) {
105             if ((this._texture instanceof HTMLImageElement) || (this._texture instanceof HTMLCanvasElement)) {
106                 wide = this._texture.width;
107                 high = this._texture.height;
108             } else {
109                 wide = this._texture.getPixelsWide();
110                 high = this._texture.getPixelsHigh();
111             }
112         }
113 
114         var left, bottom, right, top;
115         if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
116             left = (rect.origin.x * 2 + 1) / (wide * 2);
117             bottom = (rect.origin.y * 2 + 1) / (high * 2);
118             right = left + (rect.size.width * 2 - 2) / (wide * 2);
119             top = bottom + (rect.size.height * 2 - 2) / (high * 2);
120         } else {
121             left = rect.origin.x / wide;
122             bottom = rect.origin.y / high;
123             right = left + rect.size.width / wide;
124             top = bottom + rect.size.height / high;
125         }
126 
127         // Important. Texture in cocos2d are inverted, so the Y component should be inverted
128         var temp = top;
129         top = bottom;
130         bottom = temp;
131 
132         var quads = null;
133         var start = 0, end = 0;
134         if (this._batchNode) {
135             quads = this._batchNode.getTextureAtlas().getQuads();
136             start = this._atlasIndex;
137             end = this._atlasIndex + this._totalParticles;
138         } else {
139             quads = this._quads;
140             start = 0;
141             end = this._totalParticles;
142         }
143 
144         for (var i = start; i < this.end; i++) {
145             if (!quads[i]) {
146                 quads[i] = cc.V3F_C4B_T2F_QuadZero();
147             }
148 
149             // bottom-left vertex:
150             quads[i].bl.texCoords.u = left;
151             quads[i].bl.texCoords.v = bottom;
152             // bottom-right vertex:
153             quads[i].br.texCoords.u = right;
154             quads[i].br.texCoords.v = bottom;
155             // top-left vertex:
156             quads[i].tl.texCoords.u = left;
157             quads[i].tl.texCoords.v = top;
158             // top-right vertex:
159             quads[i].tr.texCoords.u = right;
160             quads[i].tr.texCoords.v = top;
161         }
162     },
163 
164     clone:function () {
165         var retParticle = new cc.ParticleSystemQuad();
166 
167         // self, not super
168         if (retParticle.initWithTotalParticles(this._totalParticles)) {
169             // angle
170             retParticle._angle = this._angle;
171             retParticle._angleVar = this._angleVar;
172 
173             // duration
174             retParticle._duration = this._duration;
175 
176             // blend function
177             retParticle._blendFunc.src = this._blendFunc.src;
178             retParticle._blendFunc.dst = this._blendFunc.dst;
179 
180             // color
181             retParticle._startColor.r = this._startColor.r;
182             retParticle._startColor.g = this._startColor.g;
183             retParticle._startColor.b = this._startColor.b;
184             retParticle._startColor.a = this._startColor.a;
185 
186             retParticle._startColorVar.r = this._startColorVar.r;
187             retParticle._startColorVar.g = this._startColorVar.g;
188             retParticle._startColorVar.b = this._startColorVar.b;
189             retParticle._startColorVar.a = this._startColorVar.a;
190 
191             retParticle._endColor.r = this._endColor.r;
192             retParticle._endColor.g = this._endColor.g;
193             retParticle._endColor.b = this._endColor.b;
194             retParticle._endColor.a = this._endColor.a;
195 
196             retParticle._endColorVar.r = this._endColorVar.r;
197             retParticle._endColorVar.g = this._endColorVar.g;
198             retParticle._endColorVar.b = this._endColorVar.b;
199             retParticle._endColorVar.a = this._endColorVar.a;
200 
201             // particle size
202             retParticle._startSize = this._startSize;
203             retParticle._startSizeVar = this._startSizeVar;
204             retParticle._endSize = this._endSize;
205             retParticle._endSizeVar = this._endSizeVar;
206 
207             // position
208             retParticle.setPosition(new cc.Point(this._position.x, this._position.y));
209             retParticle._posVar.x = this._posVar.x;
210             retParticle._posVar.y = this._posVar.y;
211 
212             // Spinning
213             retParticle._startSpin = this._startSpin;
214             retParticle._startSpinVar = this._startSpinVar;
215             retParticle._endSpin = this._endSpin;
216             retParticle._endSpinVar = this._endSpinVar;
217 
218             retParticle._emitterMode = this._emitterMode;
219 
220             // Mode A: Gravity + tangential accel + radial accel
221             if (this._emitterMode == cc.PARTICLE_MODE_GRAVITY) {
222                 // gravity
223                 retParticle.modeA.gravity.x = this.modeA.gravity.x;
224                 retParticle.modeA.gravity.y = this.modeA.gravity.y;
225 
226                 // speed
227                 retParticle.modeA.speed = this.modeA.speed;
228                 retParticle.modeA.speedVar = this.modeA.speedVar;
229 
230                 // radial acceleration
231                 retParticle.modeA.radialAccel = this.modeA.radialAccel;
232 
233                 retParticle.modeA.radialAccelVar = this.modeA.radialAccelVar;
234 
235                 // tangential acceleration
236                 retParticle.modeA.tangentialAccel = this.modeA.tangentialAccel;
237 
238                 retParticle.modeA.tangentialAccelVar = this.modeA.tangentialAccelVar;
239             } else if (this._emitterMode == cc.PARTICLE_MODE_RADIUS) {
240                 // or Mode B: radius movement
241                 retParticle.modeB.startRadius = this.modeB.startRadius;
242                 retParticle.modeB.startRadiusVar = this.modeB.startRadiusVar;
243                 retParticle.modeB.endRadius = this.modeB.endRadius;
244                 retParticle.modeB.endRadiusVar = this.modeB.endRadiusVar;
245                 retParticle.modeB.rotatePerSecond = this.modeB.rotatePerSecond;
246                 retParticle.modeB.rotatePerSecondVar = this.modeB.rotatePerSecondVar;
247             }
248 
249             // life span
250             retParticle._life = this._life;
251             retParticle._lifeVar = this._lifeVar;
252 
253             // emission Rate
254             retParticle._emissionRate = this._emissionRate;
255 
256             //don't get the internal texture if a batchNode is used
257             if (!this._batchNode) {
258                 // Set a compatible default for the alpha transfer
259                 retParticle._opacityModifyRGB = this._opacityModifyRGB;
260 
261                 // texture
262                 if (this._texture instanceof cc.Texture2D) {
263                     retParticle._texture = this._texture;
264                 } else {
265                     retParticle._texture = this._texture;
266                 }
267             }
268         }
269         return retParticle;
270     },
271 
272     /**
273      * <p> Sets a new CCSpriteFrame as particle.</br>
274      * WARNING: this method is experimental. Use setTexture:withRect instead.
275      * </p>
276      * @param {cc.SpriteFrame} spriteFrame
277      */
278     setDisplayFrame:function (spriteFrame) {
279         cc.Assert(cc.Point.CCPointEqualToPoint(spriteFrame.getOffsetInPixels(), cc.PointZero()), "QuadParticle only supports SpriteFrames with no offsets");
280 
281         // update texture before updating texture rect
282         if (!this._texture || spriteFrame.getTexture().getName() != this._texture.getName()) {
283             this.setTexture(spriteFrame.getTexture());
284         }
285     },
286 
287     /**
288      *  Sets a new texture with a rect. The rect is in Points.
289      * @param {cc.Texture2D} texture
290      * @param {cc.Rect} rect
291      */
292     setTextureWithRect:function (texture, rect) {
293         if (texture instanceof  cc.Texture2D) {
294             // Only update the texture if is different from the current one
295             if (!this._texture || texture.getName() != this._texture.getName()) {
296                 this.setTexture(texture, true);
297             }
298             this._pointRect = rect;
299             this.initTexCoordsWithRect(rect);
300         }
301         if (texture  instanceof HTMLImageElement) {
302             if (!this._texture || texture != this._texture) {
303                 this.setTexture(texture, true);
304             }
305             this._pointRect = rect;
306             this.initTexCoordsWithRect(rect);
307         }
308     },
309 
310     // super methods
311     // overriding the init method
312     /**
313      * Initializes a system with a fixed number of particles
314      * @override
315      * @param {Number} numberOfParticles
316      * @return {Boolean}
317      */
318     initWithTotalParticles:function (numberOfParticles) {
319         // base initialization
320         if (this._super(numberOfParticles)) {
321             // allocating data space
322             if (!this._allocMemory()) {
323                 return false;
324             }
325             this.setupIndices();
326             if (cc.TEXTURE_ATLAS_USE_VAO) {
327                 this._setupVBOandVAO();
328             } else {
329                 this._setupVBO();
330             }
331 
332             //this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(kCCShader_PositionTextureColor));
333 
334             // Need to listen the event only when not use batchnode, because it will use VBO
335             //extension.CCNotificationCenter.sharedNotificationCenter().addObserver(this,
336             //    callfuncO_selector(cc.ParticleSystemQuad.listenBackToForeground),
337             //    EVNET_COME_TO_FOREGROUND,
338             //    null);
339 
340             return true;
341         }
342         return false;
343     },
344 
345     /**
346      * set Texture of Particle System
347      * @override
348      * @param {HTMLImageElement|HTMLCanvasElement|cc.Texture2D} texture
349      * @param {Boolean} isCallSuper is direct call super method
350      */
351     setTexture:function (texture, isCallSuper) {
352         if (isCallSuper) {
353             if (isCallSuper == true) {
354                 this._super(texture);
355                 return;
356             }
357         }
358         var size = null;
359         if ((texture instanceof HTMLImageElement) || (texture instanceof HTMLCanvasElement)) {
360             size = cc.size(texture.width, texture.height);
361         } else {
362             size = texture.getContentSize();
363         }
364 
365         this.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height));
366     },
367 
368     /**
369      * update particle's quad
370      * @override
371      * @param {cc.Particle} particle
372      * @param {cc.Point} newPosition
373      */
374     updateQuadWithParticle:function (particle, newPosition) {
375         // colors
376         var quad = null;
377         if (this._batchNode) {
378             var batchQuads = this._batchNode.getTextureAtlas().getQuads();
379             quad = batchQuads[this._atlasIndex + particle.atlasIndex]
380         } else {
381             quad = this._quads[this._particleIdx];
382         }
383 
384         var color = (this._opacityModifyRGB) ?
385             new cc.Color4B(0 | (particle.color.r * particle.color.a * 255), 0 | (particle.color.g * particle.color.a * 255),
386                 0 | (particle.color.b * particle.color.a * 255), 0 | (particle.color.a * 255)) :
387             new cc.Color4B(0 | (particle.color.r * 255), 0 | (particle.color.g * 255), 0 | (particle.color.b * 255), 0 | (particle.color.a * 255));
388 
389         quad.bl.colors = color;
390         quad.br.colors = color;
391         quad.tl.colors = color;
392         quad.tr.colors = color;
393 
394         // vertices
395         var size_2 = particle.size / 2;
396         if (particle.rotation) {
397             var x1 = -size_2;
398             var y1 = -size_2;
399 
400             var x2 = size_2;
401             var y2 = size_2;
402             var x = newPosition.x;
403             var y = newPosition.y;
404 
405             var r = -cc.DEGREES_TO_RADIANS(particle.rotation);
406             var cr = Math.cos(r);
407             var sr = Math.sin(r);
408             var ax = x1 * cr - y1 * sr + x;
409             var ay = x1 * sr + y1 * cr + y;
410             var bx = x2 * cr - y1 * sr + x;
411             var by = x2 * sr + y1 * cr + y;
412             var cx = x2 * cr - y2 * sr + x;
413             var cy = x2 * sr + y2 * cr + y;
414             var dx = x1 * cr - y2 * sr + x;
415             var dy = x1 * sr + y2 * cr + y;
416 
417             // bottom-left
418             quad.bl.vertices.x = ax;
419             quad.bl.vertices.y = ay;
420 
421             // bottom-right vertex:
422             quad.br.vertices.x = bx;
423             quad.br.vertices.y = by;
424 
425             // top-left vertex:
426             quad.tl.vertices.x = dx;
427             quad.tl.vertices.y = dy;
428 
429             // top-right vertex:
430             quad.tr.vertices.x = cx;
431             quad.tr.vertices.y = cy;
432         } else {
433             // bottom-left vertex:
434             quad.bl.vertices.x = newPosition.x - size_2;
435             quad.bl.vertices.y = newPosition.y - size_2;
436 
437             // bottom-right vertex:
438             quad.br.vertices.x = newPosition.x + size_2;
439             quad.br.vertices.y = newPosition.y - size_2;
440 
441             // top-left vertex:
442             quad.tl.vertices.x = newPosition.x - size_2;
443             quad.tl.vertices.y = newPosition.y + size_2;
444 
445             // top-right vertex:
446             quad.tr.vertices.x = newPosition.x + size_2;
447             quad.tr.vertices.y = newPosition.y + size_2;
448         }
449     },
450 
451     /**
452      * override cc.ParticleSystem
453      * @override
454      */
455     postStep:function () {
456         if (cc.renderContextType == cc.CANVAS) {
457 
458         } else {
459             //TODO
460             glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]);
461             glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(this._quads[0]) * particleCount, this._quads);
462             glBindBuffer(GL_ARRAY_BUFFER, 0);
463 
464             CHECK_GL_ERROR_DEBUG();
465         }
466     },
467 
468     /**
469      * draw particle
470      * @param {CanvasContext} ctx CanvasContext
471      * @override
472      */
473     draw:function (ctx) {
474         cc.Assert(!this._batchNode, "draw should not be called when added to a particleBatchNode");
475         //this._super();
476         var context = ctx || cc.renderContext;
477         context.save();
478         if (this.isBlendAdditive())
479             context.globalCompositeOperation = 'lighter';
480         else
481             context.globalCompositeOperation = 'source-over';
482 
483         for (var i = 0; i < this._particleCount; i++) {
484             var particle = this._particles[i];
485             var lpx = (0 | (particle.size * 0.5));
486 
487             //TODO these are temporary code, need modifier
488             if (this._drawMode == cc.PARTICLE_TEXTURE_MODE) {
489                 var drawTexture = this.getTexture();
490                 if (particle.isChangeColor) {
491                     var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(this.getTexture());
492                     if (cacheTextureForColor)
493                         drawTexture = cc.generateTintImage(this.getTexture(), cacheTextureForColor, particle.color, this._pointRect);
494                 }
495                 context.save();
496                 context.globalAlpha = particle.color.a;
497                 context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y));
498                 if (particle.rotation)
499                     context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation));
500                 context.drawImage(drawTexture, -lpx, -lpx,
501                     particle.size, particle.size);
502                 context.restore();
503             } else {
504                 context.save();
505                 context.globalAlpha = particle.color.a;
506                 context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y));
507 
508                 if (this._shapeType == cc.PARTICLE_STAR_SHAPE) {
509                     if (particle.rotation)
510                         context.rotate(cc.DEGREES_TO_RADIANS(particle.rotation));
511                     cc.drawingUtil.drawStar(context, lpx, particle.color);
512                 } else
513                     cc.drawingUtil.drawColorBall(context, lpx, particle.color);
514                 context.restore();
515             }
516         }
517         context.restore();
518 
519         cc.INCREMENT_GL_DRAWS(1);
520     },
521 
522     _drawForWebGL:function (ctx) {
523         cc.NODE_DRAW_SETUP();
524 
525         ccGLBindTexture2D(this._texture.getName());
526         ccGLBlendFunc(m_tBlendFunc.src, m_tBlendFunc.dst);
527 
528         cc.Assert(this._particleIdx == this._particleCount, "Abnormal error in particle quad");
529 
530         if (cc.TEXTURE_ATLAS_USE_VAO) {
531             //
532             // Using VBO and VAO
533             //
534             glBindVertexArray(this._VAOname);
535 
536             if (cc.REBIND_INDICES_BUFFER)
537                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
538 
539             glDrawElements(GL_TRIANGLES, this._particleIdx * 6, GL_UNSIGNED_SHORT, 0);
540 
541             if (cc.REBIND_INDICES_BUFFER)
542                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
543 
544             glBindVertexArray(0);
545         } else {
546             //
547             // Using VBO without VAO
548             //
549             var kQuadSize = sizeof(m_pQuads[0].bl);
550 
551             ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex);
552 
553             glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]);
554             // vertices
555             glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices));
556             // colors
557             glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors));
558             // tex coords
559             glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords));
560 
561             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
562 
563             glDrawElements(GL_TRIANGLES, this._particleIdx * 6, GL_UNSIGNED_SHORT, 0);
564 
565             glBindBuffer(GL_ARRAY_BUFFER, 0);
566             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
567         }
568         CHECK_GL_ERROR_DEBUG();
569 
570         cc.INCREMENT_GL_DRAWS(1);
571     },
572 
573     setBatchNode:function (batchNode) {
574         if (this._batchNode != batchNode) {
575             var oldBatch = this._batchNode;
576 
577             this._super(batchNode);
578 
579             // NEW: is self render ?
580             if (!batchNode) {
581                 this._allocMemory();
582                 this.setupIndices();
583                 this.setTexture(oldBatch.getTexture());
584                 if (cc.TEXTURE_ATLAS_USE_VAO)
585                     this._setupVBOandVAO();
586                 else
587                     this._setupVBO();
588             }
589             // OLD: was it self render ? cleanup
590             else if (!oldBatch) {
591                 // copy current state to batch
592                 var batchQuads = this._batchNode.getTextureAtlas().getQuads();
593                 var quad = batchQuads[this._atlasIndex];
594                 //memcpy( quad, m_pQuads, m_uTotalParticles * sizeof(m_pQuads[0]) );
595 
596                 glDeleteBuffers(2, this._buffersVBO[0]);
597                 if (cc.TEXTURE_ATLAS_USE_VAO)
598                     glDeleteVertexArrays(1, this._VAOname);
599             }
600         }
601     },
602 
603     setTotalParticles:function (tp) {
604         //TODO
605         if(tp < 200)
606             this._totalParticles = tp;
607         else
608             this._totalParticles = 200;
609 
610         return;
611 
612         // If we are setting the total numer of particles to a number higher
613         // than what is allocated, we need to allocate new arrays
614         if (tp > m_uAllocatedParticles) {
615             // Allocate new memory
616             var particlesSize = tp * sizeof(tCCParticle);
617             var quadsSize = sizeof(this._quads[0]) * tp * 1;
618             var indicesSize = sizeof(m_pIndices[0]) * tp * 6 * 1;
619 
620             //var particlesNew = (tCCParticle*)realloc(m_pParticles, particlesSize);
621             //ccV3F_C4B_T2F_Quad* quadsNew = (ccV3F_C4B_T2F_Quad*)realloc(m_pQuads, quadsSize);
622             //GLushort* indicesNew = (GLushort*)realloc(m_pIndices, indicesSize);
623 
624             if (particlesNew && quadsNew && indicesNew) {
625                 // Assign pointers
626                 m_pParticles = particlesNew;
627                 m_pQuads = quadsNew;
628                 m_pIndices = indicesNew;
629 
630                 // Clear the memory
631                 memset(m_pParticles, 0, particlesSize);
632                 memset(m_pQuads, 0, quadsSize);
633                 memset(m_pIndices, 0, indicesSize);
634 
635                 m_uAllocatedParticles = tp;
636             } else {
637                 // Out of memory, failed to resize some array
638                 if (particlesNew) m_pParticles = particlesNew;
639                 if (quadsNew) m_pQuads = quadsNew;
640                 if (indicesNew) m_pIndices = indicesNew;
641 
642                 cc.log("Particle system: out of memory");
643                 return;
644             }
645 
646             m_uTotalParticles = tp;
647 
648             // Init particles
649             if (this._batchNode) {
650                 for (var i = 0; i < m_uTotalParticles; i++) {
651                     this._particles[i].atlasIndex = i;
652                 }
653             }
654 
655             this.setupIndices();
656             if (cc.TEXTURE_ATLAS_USE_VAO)
657                 this._setupVBOandVAO();
658             else
659                 this._setupVBO();
660 
661         }
662         else {
663             m_uTotalParticles = tp;
664         }
665     },
666 
667     /**
668      * listen the event that coming to foreground on Android
669      * @param {cc.Class} obj
670      */
671     listenBackToForeground:function (obj) {
672         if (cc.TEXTURE_ATLAS_USE_VAO)
673             this._setupVBOandVAO();
674         else
675             this._setupVBO();
676     },
677 
678     _setupVBOandVAO:function () {
679         if (cc.renderContextType == cc.CANVAS) {
680             return;
681         }
682 
683         glGenVertexArrays(1, this._VAOname);
684         glBindVertexArray(this._VAOname);
685 
686         var kQuadSize = sizeof(m_pQuads[0].bl)
687 
688         glGenBuffers(2, this._buffersVBO[0]);
689 
690         glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]);
691         glBufferData(GL_ARRAY_BUFFER, sizeof(this._quads[0]) * this._totalParticles, this._quads, GL_DYNAMIC_DRAW);
692 
693         // vertices
694         glEnableVertexAttribArray(kCCVertexAttrib_Position);
695         glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices));
696 
697         // colors
698         glEnableVertexAttribArray(kCCVertexAttrib_Color);
699         glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors));
700 
701         // tex coords
702         glEnableVertexAttribArray(kCCVertexAttrib_TexCoords);
703         glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords));
704 
705         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
706         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW);
707 
708         glBindVertexArray(0);
709         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
710         glBindBuffer(GL_ARRAY_BUFFER, 0);
711 
712         CHECK_GL_ERROR_DEBUG();
713     },
714 
715     _setupVBO:function () {
716         if (cc.renderContextType == cc.CANVAS) {
717             return;
718         }
719 
720         glGenBuffers(2, this._buffersVBO[0]);
721 
722         glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]);
723         glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * m_uTotalParticles, m_pQuads, GL_DYNAMIC_DRAW);
724         glBindBuffer(GL_ARRAY_BUFFER, 0);
725 
726         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
727         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW);
728         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
729 
730         CHECK_GL_ERROR_DEBUG();
731     },
732 
733     _allocMemory:function () {
734         //cc.Assert(( !this._quads && !this._indices), "Memory already alloced");
735         cc.Assert(!this._batchNode, "Memory should not be alloced when not using batchNode");
736         this._quads = [];
737         this._indices = [];
738         for (var i = 0; i < this._totalParticles; i++) {
739             this._quads[i] = new cc.V3F_C4B_T2F_Quad();
740             this._indices[i * 6] = 0;
741             this._indices[(i * 6) + 1] = 0;
742             this._indices[(i * 6) + 2] = 0;
743             this._indices[(i * 6) + 3] = 0;
744             this._indices[(i * 6) + 4] = 0;
745             this._indices[(i * 6) + 5] = 0;
746         }
747 
748         if (!this._quads || !this._indices) {
749             cc.log("cocos2d: Particle system: not enough memory");
750             return false;
751         }
752 
753         return true;
754     }
755 });
756 
757 /**
758  * <p>
759  *   creates an initializes a CCParticleSystemQuad from a plist file.<br/>
760  *   This plist files can be creted manually or with Particle Designer:<br/>
761  *   http://particledesigner.71squared.com/<br/>
762  * </p>
763  * @param {String} pListFile
764  * @return {cc.ParticleSystem}
765  * @example
766  *  //creates an initializes a CCParticleSystemQuad from a plist file.
767  *  var system = cc.ParticleSystemQuad.create("Images/SpinningPeas.plist");
768  */
769 cc.ParticleSystemQuad.create = function (pListFile) {
770     var ret = new cc.ParticleSystemQuad();
771     if (!pListFile || typeof(pListFile) === "number") {
772         var ton = pListFile || 100;
773         ret.setDrawMode(cc.PARTICLE_TEXTURE_MODE);
774         ret.initWithTotalParticles(ton);
775         return ret;
776     }
777 
778     if (ret && ret.initWithFile(pListFile)) {
779         return ret;
780     }
781     return null;
782 };
783 
784 cc.ARCH_OPTIMAL_PARTICLE_SYSTEM = cc.ParticleSystemQuad;
785