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