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