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 || cc.isNumber(plistFile)) { 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.getTextureForKey(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.getTextureForKey(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 /** 1719 * Unschedules the "update" method. 1720 * @function 1721 * @see scheduleUpdate(); 1722 */ 1723 destroyParticleSystem:function () { 1724 this.unscheduleUpdate(); 1725 }, 1726 1727 /** 1728 * Add a particle to the emitter 1729 * @return {Boolean} 1730 */ 1731 addParticle: function () { 1732 if (this.isFull()) 1733 return false; 1734 var particle, particles = this._particles; 1735 if (cc._renderType === cc._RENDER_TYPE_CANVAS) { 1736 if (this.particleCount < particles.length) { 1737 particle = particles[this.particleCount]; 1738 } else { 1739 particle = new cc.Particle(); 1740 particles.push(particle); 1741 } 1742 } else { 1743 particle = particles[this.particleCount]; 1744 } 1745 this.initParticle(particle); 1746 ++this.particleCount; 1747 return true; 1748 }, 1749 1750 /** 1751 * Initializes a particle 1752 * @param {cc.Particle} particle 1753 */ 1754 initParticle:function (particle) { 1755 var locRandomMinus11 = cc.randomMinus1To1; 1756 // timeToLive 1757 // no negative life. prevent division by 0 1758 particle.timeToLive = this.life + this.lifeVar * locRandomMinus11(); 1759 particle.timeToLive = Math.max(0, particle.timeToLive); 1760 1761 // position 1762 particle.pos.x = this._sourcePosition.x + this._posVar.x * locRandomMinus11(); 1763 particle.pos.y = this._sourcePosition.y + this._posVar.y * locRandomMinus11(); 1764 1765 // Color 1766 var start, end; 1767 var locStartColor = this._startColor, locStartColorVar = this._startColorVar; 1768 var locEndColor = this._endColor, locEndColorVar = this._endColorVar; 1769 if (cc._renderType === cc._RENDER_TYPE_CANVAS) { 1770 start = cc.color( 1771 cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 255), 1772 cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 255), 1773 cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 255), 1774 cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 255) 1775 ); 1776 end = cc.color( 1777 cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 255), 1778 cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 255), 1779 cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 255), 1780 cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 255) 1781 ); 1782 } else { 1783 start = { 1784 r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 255), 1785 g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 255), 1786 b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 255), 1787 a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 255) 1788 }; 1789 end = { 1790 r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 255), 1791 g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 255), 1792 b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 255), 1793 a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 255) 1794 }; 1795 } 1796 1797 particle.color = start; 1798 var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive; 1799 locParticleDeltaColor.r = (end.r - start.r) / locParticleTimeToLive; 1800 locParticleDeltaColor.g = (end.g - start.g) / locParticleTimeToLive; 1801 locParticleDeltaColor.b = (end.b - start.b) / locParticleTimeToLive; 1802 locParticleDeltaColor.a = (end.a - start.a) / locParticleTimeToLive; 1803 1804 // size 1805 var startS = this.startSize + this.startSizeVar * locRandomMinus11(); 1806 startS = Math.max(0, startS); // No negative value 1807 1808 particle.size = startS; 1809 if (this.endSize === cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE) { 1810 particle.deltaSize = 0; 1811 } else { 1812 var endS = this.endSize + this.endSizeVar * locRandomMinus11(); 1813 endS = Math.max(0, endS); // No negative values 1814 particle.deltaSize = (endS - startS) / locParticleTimeToLive; 1815 } 1816 1817 // rotation 1818 var startA = this.startSpin + this.startSpinVar * locRandomMinus11(); 1819 var endA = this.endSpin + this.endSpinVar * locRandomMinus11(); 1820 particle.rotation = startA; 1821 particle.deltaRotation = (endA - startA) / locParticleTimeToLive; 1822 1823 // position 1824 if (this.positionType == cc.ParticleSystem.TYPE_FREE) 1825 particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle); 1826 else if (this.positionType == cc.ParticleSystem.TYPE_RELATIVE){ 1827 particle.startPos.x = this._position.x; 1828 particle.startPos.y = this._position.y; 1829 } 1830 1831 // direction 1832 var a = cc.degreesToRadians(this.angle + this.angleVar * locRandomMinus11()); 1833 1834 // Mode Gravity: A 1835 if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) { 1836 var locModeA = this.modeA, locParticleModeA = particle.modeA; 1837 var s = locModeA.speed + locModeA.speedVar * locRandomMinus11(); 1838 1839 // direction 1840 locParticleModeA.dir.x = Math.cos(a); 1841 locParticleModeA.dir.y = Math.sin(a); 1842 cc.pMultIn(locParticleModeA.dir, s); 1843 1844 // radial accel 1845 locParticleModeA.radialAccel = locModeA.radialAccel + locModeA.radialAccelVar * locRandomMinus11(); 1846 1847 // tangential accel 1848 locParticleModeA.tangentialAccel = locModeA.tangentialAccel + locModeA.tangentialAccelVar * locRandomMinus11(); 1849 1850 // rotation is dir 1851 if(locModeA.rotationIsDir) 1852 particle.rotation = -cc.radiansToDegrees(cc.pToAngle(locParticleModeA.dir)); 1853 } else { 1854 // Mode Radius: B 1855 var locModeB = this.modeB, locParitlceModeB = particle.modeB; 1856 1857 // Set the default diameter of the particle from the source position 1858 var startRadius = locModeB.startRadius + locModeB.startRadiusVar * locRandomMinus11(); 1859 var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11(); 1860 1861 locParitlceModeB.radius = startRadius; 1862 locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive; 1863 1864 locParitlceModeB.angle = a; 1865 locParitlceModeB.degreesPerSecond = cc.degreesToRadians(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11()); 1866 } 1867 }, 1868 1869 /** 1870 * stop emitting particles. Running particles will continue to run until they die 1871 */ 1872 stopSystem:function () { 1873 this._isActive = false; 1874 this._elapsed = this.duration; 1875 this._emitCounter = 0; 1876 }, 1877 1878 /** 1879 * Kill all living particles. 1880 */ 1881 resetSystem:function () { 1882 this._isActive = true; 1883 this._elapsed = 0; 1884 var locParticles = this._particles; 1885 for (this._particleIdx = 0; this._particleIdx < this.particleCount; ++this._particleIdx) 1886 locParticles[this._particleIdx].timeToLive = 0 ; 1887 }, 1888 1889 /** 1890 * whether or not the system is full 1891 * @return {Boolean} 1892 */ 1893 isFull:function () { 1894 return (this.particleCount >= this._totalParticles); 1895 }, 1896 1897 /** 1898 * should be overridden by subclasses 1899 * @param {cc.Particle} particle 1900 * @param {cc.Point} newPosition 1901 */ 1902 updateQuadWithParticle:function (particle, newPosition) { 1903 var quad = null; 1904 if (this._batchNode) { 1905 var batchQuads = this._batchNode.textureAtlas.quads; 1906 quad = batchQuads[this.atlasIndex + particle.atlasIndex]; 1907 this._batchNode.textureAtlas.dirty = true; 1908 } else 1909 quad = this._quads[this._particleIdx]; 1910 1911 var r, g, b, a; 1912 if (this._opacityModifyRGB) { 1913 r = 0 | (particle.color.r * particle.color.a/255); 1914 g = 0 | (particle.color.g * particle.color.a/255); 1915 b = 0 | (particle.color.b * particle.color.a/255); 1916 } else { 1917 r = 0 | (particle.color.r ); 1918 g = 0 | (particle.color.g ); 1919 b = 0 | (particle.color.b ); 1920 } 1921 a = 0 | (particle.color.a ); 1922 1923 var locColors = quad.bl.colors; 1924 locColors.r = r; 1925 locColors.g = g; 1926 locColors.b = b; 1927 locColors.a = a; 1928 1929 locColors = quad.br.colors; 1930 locColors.r = r; 1931 locColors.g = g; 1932 locColors.b = b; 1933 locColors.a = a; 1934 1935 locColors = quad.tl.colors; 1936 locColors.r = r; 1937 locColors.g = g; 1938 locColors.b = b; 1939 locColors.a = a; 1940 1941 locColors = quad.tr.colors; 1942 locColors.r = r; 1943 locColors.g = g; 1944 locColors.b = b; 1945 locColors.a = a; 1946 1947 // vertices 1948 var size_2 = particle.size / 2; 1949 if (particle.rotation) { 1950 var x1 = -size_2; 1951 var y1 = -size_2; 1952 1953 var x2 = size_2; 1954 var y2 = size_2; 1955 var x = newPosition.x; 1956 var y = newPosition.y; 1957 1958 var rad = -cc.degreesToRadians(particle.rotation); 1959 var cr = Math.cos(rad); 1960 var sr = Math.sin(rad); 1961 var ax = x1 * cr - y1 * sr + x; 1962 var ay = x1 * sr + y1 * cr + y; 1963 var bx = x2 * cr - y1 * sr + x; 1964 var by = x2 * sr + y1 * cr + y; 1965 var cx = x2 * cr - y2 * sr + x; 1966 var cy = x2 * sr + y2 * cr + y; 1967 var dx = x1 * cr - y2 * sr + x; 1968 var dy = x1 * sr + y2 * cr + y; 1969 1970 // bottom-left 1971 quad.bl.vertices.x = ax; 1972 quad.bl.vertices.y = ay; 1973 1974 // bottom-right vertex: 1975 quad.br.vertices.x = bx; 1976 quad.br.vertices.y = by; 1977 1978 // top-left vertex: 1979 quad.tl.vertices.x = dx; 1980 quad.tl.vertices.y = dy; 1981 1982 // top-right vertex: 1983 quad.tr.vertices.x = cx; 1984 quad.tr.vertices.y = cy; 1985 } else { 1986 // bottom-left vertex: 1987 quad.bl.vertices.x = newPosition.x - size_2; 1988 quad.bl.vertices.y = newPosition.y - size_2; 1989 1990 // bottom-right vertex: 1991 quad.br.vertices.x = newPosition.x + size_2; 1992 quad.br.vertices.y = newPosition.y - size_2; 1993 1994 // top-left vertex: 1995 quad.tl.vertices.x = newPosition.x - size_2; 1996 quad.tl.vertices.y = newPosition.y + size_2; 1997 1998 // top-right vertex: 1999 quad.tr.vertices.x = newPosition.x + size_2; 2000 quad.tr.vertices.y = newPosition.y + size_2; 2001 } 2002 }, 2003 2004 /** 2005 * should be overridden by subclasses 2006 */ 2007 postStep:function () { 2008 if (cc._renderType === cc._RENDER_TYPE_WEBGL) { 2009 var gl = cc._renderContext; 2010 2011 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2012 gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); 2013 2014 // Option 2: Data 2015 // glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW); 2016 2017 // Option 3: Orphaning + glMapBuffer 2018 // glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*m_uTotalParticles, NULL, GL_STREAM_DRAW); 2019 // void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); 2020 // memcpy(buf, m_pQuads, sizeof(m_pQuads[0])*m_uTotalParticles); 2021 // glUnmapBuffer(GL_ARRAY_BUFFER); 2022 2023 //cc.checkGLErrorDebug(); 2024 } 2025 }, 2026 2027 /** 2028 * update emitter's status 2029 * @override 2030 * @param {Number} dt delta time 2031 */ 2032 update:function (dt) { 2033 if (this._isActive && this.emissionRate) { 2034 var rate = 1.0 / this.emissionRate; 2035 //issue #1201, prevent bursts of particles, due to too high emitCounter 2036 if (this.particleCount < this._totalParticles) 2037 this._emitCounter += dt; 2038 2039 while ((this.particleCount < this._totalParticles) && (this._emitCounter > rate)) { 2040 this.addParticle(); 2041 this._emitCounter -= rate; 2042 } 2043 2044 this._elapsed += dt; 2045 if (this.duration != -1 && this.duration < this._elapsed) 2046 this.stopSystem(); 2047 } 2048 this._particleIdx = 0; 2049 2050 var currentPosition = cc.Particle.TemporaryPoints[0]; 2051 if (this.positionType == cc.ParticleSystem.TYPE_FREE) { 2052 cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle)); 2053 } else if (this.positionType == cc.ParticleSystem.TYPE_RELATIVE) { 2054 currentPosition.x = this._position.x; 2055 currentPosition.y = this._position.y; 2056 } 2057 2058 if (this._visible) { 2059 2060 // Used to reduce memory allocation / creation within the loop 2061 var tpa = cc.Particle.TemporaryPoints[1], 2062 tpb = cc.Particle.TemporaryPoints[2], 2063 tpc = cc.Particle.TemporaryPoints[3]; 2064 2065 var locParticles = this._particles; 2066 while (this._particleIdx < this.particleCount) { 2067 2068 // Reset the working particles 2069 cc.pZeroIn(tpa); 2070 cc.pZeroIn(tpb); 2071 cc.pZeroIn(tpc); 2072 2073 var selParticle = locParticles[this._particleIdx]; 2074 2075 // life 2076 selParticle.timeToLive -= dt; 2077 2078 if (selParticle.timeToLive > 0) { 2079 // Mode A: gravity, direction, tangential accel & radial accel 2080 if (this.emitterMode == cc.ParticleSystem.MODE_GRAVITY) { 2081 2082 var tmp = tpc, radial = tpa, tangential = tpb; 2083 2084 // radial acceleration 2085 if (selParticle.pos.x || selParticle.pos.y) { 2086 cc.pIn(radial, selParticle.pos); 2087 cc.pNormalizeIn(radial); 2088 } else { 2089 cc.pZeroIn(radial); 2090 } 2091 2092 cc.pIn(tangential, radial); 2093 cc.pMultIn(radial, selParticle.modeA.radialAccel); 2094 2095 // tangential acceleration 2096 var newy = tangential.x; 2097 tangential.x = -tangential.y; 2098 tangential.y = newy; 2099 2100 cc.pMultIn(tangential, selParticle.modeA.tangentialAccel); 2101 2102 cc.pIn(tmp, radial); 2103 cc.pAddIn(tmp, tangential); 2104 cc.pAddIn(tmp, this.modeA.gravity); 2105 cc.pMultIn(tmp, dt); 2106 cc.pAddIn(selParticle.modeA.dir, tmp); 2107 2108 2109 cc.pIn(tmp, selParticle.modeA.dir); 2110 cc.pMultIn(tmp, dt); 2111 cc.pAddIn(selParticle.pos, tmp); 2112 2113 } else { 2114 // Mode B: radius movement 2115 var selModeB = selParticle.modeB; 2116 // Update the angle and radius of the particle. 2117 selModeB.angle += selModeB.degreesPerSecond * dt; 2118 selModeB.radius += selModeB.deltaRadius * dt; 2119 2120 selParticle.pos.x = -Math.cos(selModeB.angle) * selModeB.radius; 2121 selParticle.pos.y = -Math.sin(selModeB.angle) * selModeB.radius; 2122 } 2123 2124 // color 2125 if (!this._dontTint || cc._renderType === cc._RENDER_TYPE_WEBGL) { 2126 selParticle.color.r += selParticle.deltaColor.r * dt; 2127 selParticle.color.g += selParticle.deltaColor.g * dt; 2128 selParticle.color.b += selParticle.deltaColor.b * dt; 2129 selParticle.color.a += selParticle.deltaColor.a * dt; 2130 selParticle.isChangeColor = true; 2131 } 2132 2133 // size 2134 selParticle.size += (selParticle.deltaSize * dt); 2135 selParticle.size = Math.max(0, selParticle.size); 2136 2137 // angle 2138 selParticle.rotation += (selParticle.deltaRotation * dt); 2139 2140 // 2141 // update values in quad 2142 // 2143 var newPos = tpa; 2144 if (this.positionType == cc.ParticleSystem.TYPE_FREE || this.positionType == cc.ParticleSystem.TYPE_RELATIVE) { 2145 2146 var diff = tpb; 2147 cc.pIn(diff, currentPosition); 2148 cc.pSubIn(diff, selParticle.startPos); 2149 2150 cc.pIn(newPos, selParticle.pos); 2151 cc.pSubIn(newPos, diff); 2152 2153 } else { 2154 cc.pIn(newPos, selParticle.pos); 2155 } 2156 2157 // translate newPos to correct position, since matrix transform isn't performed in batchnode 2158 // don't update the particle with the new position information, it will interfere with the radius and tangential calculations 2159 if (this._batchNode) { 2160 newPos.x += this._position.x; 2161 newPos.y += this._position.y; 2162 } 2163 2164 if (cc._renderType == cc._RENDER_TYPE_WEBGL) { 2165 // IMPORTANT: newPos may not be used as a reference here! (as it is just the temporary tpa point) 2166 // the implementation of updateQuadWithParticle must use 2167 // the x and y values directly 2168 this.updateQuadWithParticle(selParticle, newPos); 2169 } else { 2170 cc.pIn(selParticle.drawPos, newPos); 2171 } 2172 //updateParticleImp(self, updateParticleSel, p, newPos); 2173 2174 // update particle counter 2175 ++this._particleIdx; 2176 } else { 2177 // life < 0 2178 var currentIndex = selParticle.atlasIndex; 2179 if(this._particleIdx !== this.particleCount -1){ 2180 var deadParticle = locParticles[this._particleIdx]; 2181 locParticles[this._particleIdx] = locParticles[this.particleCount -1]; 2182 locParticles[this.particleCount -1] = deadParticle; 2183 } 2184 if (this._batchNode) { 2185 //disable the switched particle 2186 this._batchNode.disableParticle(this.atlasIndex + currentIndex); 2187 2188 //switch indexes 2189 locParticles[this.particleCount - 1].atlasIndex = currentIndex; 2190 } 2191 2192 --this.particleCount; 2193 if (this.particleCount == 0 && this.autoRemoveOnFinish) { 2194 this.unscheduleUpdate(); 2195 this._parent.removeChild(this, true); 2196 return; 2197 } 2198 } 2199 } 2200 this._transformSystemDirty = false; 2201 } 2202 2203 if (!this._batchNode) 2204 this.postStep(); 2205 }, 2206 2207 /** 2208 * update emitter's status (dt = 0) 2209 */ 2210 updateWithNoTime:function () { 2211 this.update(0); 2212 }, 2213 2214 // 2215 // return the string found by key in dict. 2216 // @param {string} key 2217 // @param {object} dict 2218 // @return {String} "" if not found; return the string if found. 2219 // @private 2220 // 2221 _valueForKey:function (key, dict) { 2222 if (dict) { 2223 var pString = dict[key]; 2224 return pString != null ? pString : ""; 2225 } 2226 return ""; 2227 }, 2228 2229 _updateBlendFunc:function () { 2230 if(this._batchNode){ 2231 cc.log("Can't change blending functions when the particle is being batched"); 2232 return; 2233 } 2234 2235 var locTexture = this._texture; 2236 if (locTexture && locTexture instanceof cc.Texture2D) { 2237 this._opacityModifyRGB = false; 2238 var locBlendFunc = this._blendFunc; 2239 if (locBlendFunc.src == cc.BLEND_SRC && locBlendFunc.dst == cc.BLEND_DST) { 2240 if (locTexture.hasPremultipliedAlpha()) { 2241 this._opacityModifyRGB = true; 2242 } else { 2243 locBlendFunc.src = cc.SRC_ALPHA; 2244 locBlendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; 2245 } 2246 } 2247 } 2248 }, 2249 2250 /** 2251 * to copy object with deep copy. 2252 * returns a clone of action. 2253 * 2254 * @return {cc.ParticleSystem} 2255 */ 2256 clone:function () { 2257 var retParticle = new cc.ParticleSystem(); 2258 2259 // self, not super 2260 if (retParticle.initWithTotalParticles(this.getTotalParticles())) { 2261 // angle 2262 retParticle.setAngle(this.getAngle()); 2263 retParticle.setAngleVar(this.getAngleVar()); 2264 2265 // duration 2266 retParticle.setDuration(this.getDuration()); 2267 2268 // blend function 2269 var blend = this.getBlendFunc(); 2270 retParticle.setBlendFunc(blend.src,blend.dst); 2271 2272 // color 2273 retParticle.setStartColor(this.getStartColor()); 2274 2275 retParticle.setStartColorVar(this.getStartColorVar()); 2276 2277 retParticle.setEndColor(this.getEndColor()); 2278 2279 retParticle.setEndColorVar(this.getEndColorVar()); 2280 2281 // this size 2282 retParticle.setStartSize(this.getStartSize()); 2283 retParticle.setStartSizeVar(this.getStartSizeVar()); 2284 retParticle.setEndSize(this.getEndSize()); 2285 retParticle.setEndSizeVar(this.getEndSizeVar()); 2286 2287 // position 2288 retParticle.setPosition(cc.p(this.x, this.y)); 2289 retParticle.setPosVar(cc.p(this.getPosVar().x,this.getPosVar().y)); 2290 2291 // Spinning 2292 retParticle.setStartSpin(this.getStartSpin()||0); 2293 retParticle.setStartSpinVar(this.getStartSpinVar()||0); 2294 retParticle.setEndSpin(this.getEndSpin()||0); 2295 retParticle.setEndSpinVar(this.getEndSpinVar()||0); 2296 2297 retParticle.setEmitterMode(this.getEmitterMode()); 2298 2299 // Mode A: Gravity + tangential accel + radial accel 2300 if (this.getEmitterMode() == cc.ParticleSystem.MODE_GRAVITY) { 2301 // gravity 2302 var gra = this.getGravity(); 2303 retParticle.setGravity(cc.p(gra.x,gra.y)); 2304 2305 // speed 2306 retParticle.setSpeed(this.getSpeed()); 2307 retParticle.setSpeedVar(this.getSpeedVar()); 2308 2309 // radial acceleration 2310 retParticle.setRadialAccel(this.getRadialAccel()); 2311 retParticle.setRadialAccelVar(this.getRadialAccelVar()); 2312 2313 // tangential acceleration 2314 retParticle.setTangentialAccel(this.getTangentialAccel()); 2315 retParticle.setTangentialAccelVar(this.getTangentialAccelVar()); 2316 2317 } else if (this.getEmitterMode() == cc.ParticleSystem.MODE_RADIUS) { 2318 // or Mode B: radius movement 2319 retParticle.setStartRadius(this.getStartRadius()); 2320 retParticle.setStartRadiusVar(this.getStartRadiusVar()); 2321 retParticle.setEndRadius(this.getEndRadius()); 2322 retParticle.setEndRadiusVar(this.getEndRadiusVar()); 2323 2324 retParticle.setRotatePerSecond(this.getRotatePerSecond()); 2325 retParticle.setRotatePerSecondVar(this.getRotatePerSecondVar()); 2326 } 2327 2328 // life span 2329 retParticle.setLife(this.getLife()); 2330 retParticle.setLifeVar(this.getLifeVar()); 2331 2332 // emission Rate 2333 retParticle.setEmissionRate(this.getEmissionRate()); 2334 2335 //don't get the internal texture if a batchNode is used 2336 if (!this.getBatchNode()) { 2337 // Set a compatible default for the alpha transfer 2338 retParticle.setOpacityModifyRGB(this.isOpacityModifyRGB()); 2339 // texture 2340 var texture = this.getTexture(); 2341 if(texture){ 2342 var size = texture.getContentSize(); 2343 retParticle.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height)); 2344 } 2345 } 2346 } 2347 return retParticle; 2348 }, 2349 2350 /** 2351 * <p> Sets a new CCSpriteFrame as particle.</br> 2352 * WARNING: this method is experimental. Use setTextureWithRect instead. 2353 * </p> 2354 * @param {cc.SpriteFrame} spriteFrame 2355 */ 2356 setDisplayFrame:function (spriteFrame) { 2357 var locOffset = spriteFrame.getOffsetInPixels(); 2358 if(locOffset.x != 0 || locOffset.y != 0) 2359 cc.log("cc.ParticleSystem.setDisplayFrame(): QuadParticle only supports SpriteFrames with no offsets"); 2360 2361 // update texture before updating texture rect 2362 if (cc._renderType === cc._RENDER_TYPE_WEBGL) 2363 if (!this._texture || spriteFrame.getTexture()._webTextureObj != this._texture._webTextureObj) 2364 this.setTexture(spriteFrame.getTexture()); 2365 }, 2366 2367 /** 2368 * Sets a new texture with a rect. The rect is in Points. 2369 * @param {cc.Texture2D} texture 2370 * @param {cc.Rect} rect 2371 */ 2372 setTextureWithRect:function (texture, rect) { 2373 var locTexture = this._texture; 2374 if (cc._renderType === cc._RENDER_TYPE_WEBGL) { 2375 // Only update the texture if is different from the current one 2376 if ((!locTexture || texture._webTextureObj != locTexture._webTextureObj) && (locTexture != texture)) { 2377 this._texture = texture; 2378 this._updateBlendFunc(); 2379 } 2380 } else { 2381 if ((!locTexture || texture != locTexture) && (locTexture != texture)) { 2382 this._texture = texture; 2383 this._updateBlendFunc(); 2384 } 2385 } 2386 2387 this._pointRect = rect; 2388 this.initTexCoordsWithRect(rect); 2389 }, 2390 2391 /** 2392 * draw particle 2393 * @param {CanvasRenderingContext2D} ctx CanvasContext 2394 * @override 2395 */ 2396 draw:function (ctx) { 2397 if(!this._textureLoaded || this._batchNode) // draw should not be called when added to a particleBatchNode 2398 return; 2399 2400 if (cc._renderType === cc._RENDER_TYPE_CANVAS) 2401 this._drawForCanvas(ctx); 2402 else 2403 this._drawForWebGL(ctx); 2404 2405 cc.g_NumberOfDraws++; 2406 }, 2407 2408 _drawForCanvas:function (ctx) { 2409 var context = ctx || cc._renderContext; 2410 context.save(); 2411 if (this.isBlendAdditive()) 2412 context.globalCompositeOperation = 'lighter'; 2413 else 2414 context.globalCompositeOperation = 'source-over'; 2415 2416 var element = this._texture.getHtmlElementObj(); 2417 for (var i = 0; i < this.particleCount; i++) { 2418 var particle = this._particles[i]; 2419 var lpx = (0 | (particle.size * 0.5)); 2420 2421 if (this.drawMode == cc.ParticleSystem.TEXTURE_MODE) { 2422 // Delay drawing until the texture is fully loaded by the browser 2423 if (!element.width || !element.height) 2424 continue; 2425 2426 context.save(); 2427 context.globalAlpha = particle.color.a / 255; 2428 context.translate((0 | particle.drawPos.x), -(0 | particle.drawPos.y)); 2429 2430 var size = Math.floor(particle.size / 4) * 4; 2431 var w = this._pointRect.width; 2432 var h = this._pointRect.height; 2433 2434 context.scale( 2435 Math.max((1 / w) * size, 0.000001), 2436 Math.max((1 / h) * size, 0.000001) 2437 ); 2438 2439 if (particle.rotation) 2440 context.rotate(cc.degreesToRadians(particle.rotation)); 2441 context.translate(-(0 | (w / 2)), -(0 | (h / 2))); 2442 var drawElement = particle.isChangeColor ? this._changeTextureColor(element, particle.color, this._pointRect) : element; 2443 if(drawElement) 2444 context.drawImage(drawElement, 0, 0); 2445 context.restore(); 2446 } else { 2447 context.save(); 2448 context.globalAlpha = particle.color.a / 255; 2449 2450 context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y)); 2451 2452 if (this.shapeType == cc.ParticleSystem.STAR_SHAPE) { 2453 if (particle.rotation) 2454 context.rotate(cc.degreesToRadians(particle.rotation)); 2455 cc._drawingUtil.drawStar(context, lpx, particle.color); 2456 } else 2457 cc._drawingUtil.drawColorBall(context, lpx, particle.color); 2458 context.restore(); 2459 } 2460 } 2461 context.restore(); 2462 }, 2463 2464 _changeTextureColor: function(element, color, rect){ 2465 if (!element.tintCache) { 2466 element.tintCache = document.createElement('canvas'); 2467 element.tintCache.width = element.width; 2468 element.tintCache.height = element.height; 2469 } 2470 return cc.generateTintImageWithMultiply(element, color, rect, element.tintCache); 2471 }, 2472 2473 _drawForWebGL:function (ctx) { 2474 if(!this._texture) 2475 return; 2476 2477 var gl = ctx || cc._renderContext; 2478 2479 this._shaderProgram.use(); 2480 this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); 2481 2482 cc.glBindTexture2D(this._texture); 2483 cc.glBlendFuncForParticle(this._blendFunc.src, this._blendFunc.dst); 2484 2485 //cc.assert(this._particleIdx == this.particleCount, "Abnormal error in particle quad"); 2486 2487 // 2488 // Using VBO without VAO 2489 // 2490 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); 2491 2492 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2493 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); // vertices 2494 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); // colors 2495 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); // tex coords 2496 2497 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2498 gl.drawElements(gl.TRIANGLES, this._particleIdx * 6, gl.UNSIGNED_SHORT, 0); 2499 }, 2500 2501 /** 2502 * listen the event that coming to foreground on Android 2503 * @param {cc.Class} obj 2504 */ 2505 listenBackToForeground:function (obj) { 2506 if (cc.TEXTURE_ATLAS_USE_VAO) 2507 this._setupVBOandVAO(); 2508 else 2509 this._setupVBO(); 2510 }, 2511 2512 _setupVBOandVAO:function () { 2513 //Not support on WebGL 2514 /*if (cc._renderType == cc._RENDER_TYPE_CANVAS) { 2515 return; 2516 }*/ 2517 2518 //NOT SUPPORTED 2519 /*glGenVertexArrays(1, this._VAOname); 2520 glBindVertexArray(this._VAOname); 2521 2522 var kQuadSize = sizeof(m_pQuads[0].bl); 2523 2524 glGenBuffers(2, this._buffersVBO[0]); 2525 2526 glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]); 2527 glBufferData(GL_ARRAY_BUFFER, sizeof(this._quads[0]) * this._totalParticles, this._quads, GL_DYNAMIC_DRAW); 2528 2529 // vertices 2530 glEnableVertexAttribArray(kCCVertexAttrib_Position); 2531 glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices)); 2532 2533 // colors 2534 glEnableVertexAttribArray(kCCVertexAttrib_Color); 2535 glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors)); 2536 2537 // tex coords 2538 glEnableVertexAttribArray(kCCVertexAttrib_TexCoords); 2539 glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords)); 2540 2541 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2542 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW); 2543 2544 glBindVertexArray(0); 2545 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 2546 glBindBuffer(GL_ARRAY_BUFFER, 0); 2547 2548 CHECK_GL_ERROR_DEBUG();*/ 2549 }, 2550 2551 _setupVBO:function () { 2552 if (cc._renderType == cc._RENDER_TYPE_CANVAS) 2553 return; 2554 2555 var gl = cc._renderContext; 2556 2557 //gl.deleteBuffer(this._buffersVBO[0]); 2558 this._buffersVBO[0] = gl.createBuffer(); 2559 gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); 2560 gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); 2561 2562 this._buffersVBO[1] = gl.createBuffer(); 2563 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); 2564 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW); 2565 2566 //cc.checkGLErrorDebug(); 2567 }, 2568 2569 _allocMemory:function () { 2570 if (cc._renderType === cc._RENDER_TYPE_CANVAS) 2571 return true; 2572 2573 //cc.assert((!this._quads && !this._indices), "Memory already allocated"); 2574 if(this._batchNode){ 2575 cc.log("cc.ParticleSystem._allocMemory(): Memory should not be allocated when not using batchNode"); 2576 return false; 2577 } 2578 2579 var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; 2580 var totalParticles = this._totalParticles; 2581 var locQuads = this._quads; 2582 locQuads.length = 0; 2583 this._indices = new Uint16Array(totalParticles * 6); 2584 var locQuadsArrayBuffer = new ArrayBuffer(quadSize * totalParticles); 2585 2586 for (var i = 0; i < totalParticles; i++) 2587 locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, i * quadSize); 2588 if (!locQuads || !this._indices) { 2589 cc.log("cocos2d: Particle system: not enough memory"); 2590 return false; 2591 } 2592 this._quadsArrayBuffer = locQuadsArrayBuffer; 2593 return true; 2594 } 2595 }); 2596 2597 var _p = cc.ParticleSystem.prototype; 2598 2599 if(cc._renderType === cc._RENDER_TYPE_CANVAS && !cc.sys._supportCanvasNewBlendModes) 2600 _p._changeTextureColor = function (element, color, rect) { 2601 var cacheTextureForColor = cc.textureCache.getTextureColors(element); 2602 if (cacheTextureForColor) { 2603 // Create another cache for the tinted version 2604 // This speeds up things by a fair bit 2605 if (!cacheTextureForColor.tintCache) { 2606 cacheTextureForColor.tintCache = document.createElement('canvas'); 2607 cacheTextureForColor.tintCache.width = element.width; 2608 cacheTextureForColor.tintCache.height = element.height; 2609 } 2610 cc.generateTintImage(element, cacheTextureForColor, color, rect, cacheTextureForColor.tintCache); 2611 return cacheTextureForColor.tintCache; 2612 } 2613 return null 2614 }; 2615 2616 // Extended properties 2617 /** @expose */ 2618 _p.opacityModifyRGB; 2619 cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpacityModifyRGB); 2620 /** @expose */ 2621 _p.batchNode; 2622 cc.defineGetterSetter(_p, "batchNode", _p.getBatchNode, _p.setBatchNode); 2623 /** @expose */ 2624 _p.active; 2625 cc.defineGetterSetter(_p, "active", _p.isActive); 2626 /** @expose */ 2627 _p.sourcePos; 2628 cc.defineGetterSetter(_p, "sourcePos", _p.getSourcePosition, _p.setSourcePosition); 2629 /** @expose */ 2630 _p.posVar; 2631 cc.defineGetterSetter(_p, "posVar", _p.getPosVar, _p.setPosVar); 2632 /** @expose */ 2633 _p.gravity; 2634 cc.defineGetterSetter(_p, "gravity", _p.getGravity, _p.setGravity); 2635 /** @expose */ 2636 _p.speed; 2637 cc.defineGetterSetter(_p, "speed", _p.getSpeed, _p.setSpeed); 2638 /** @expose */ 2639 _p.speedVar; 2640 cc.defineGetterSetter(_p, "speedVar", _p.getSpeedVar, _p.setSpeedVar); 2641 /** @expose */ 2642 _p.tangentialAccel; 2643 cc.defineGetterSetter(_p, "tangentialAccel", _p.getTangentialAccel, _p.setTangentialAccel); 2644 /** @expose */ 2645 _p.tangentialAccelVar; 2646 cc.defineGetterSetter(_p, "tangentialAccelVar", _p.getTangentialAccelVar, _p.setTangentialAccelVar); 2647 /** @expose */ 2648 _p.radialAccel; 2649 cc.defineGetterSetter(_p, "radialAccel", _p.getRadialAccel, _p.setRadialAccel); 2650 /** @expose */ 2651 _p.radialAccelVar; 2652 cc.defineGetterSetter(_p, "radialAccelVar", _p.getRadialAccelVar, _p.setRadialAccelVar); 2653 /** @expose */ 2654 _p.rotationIsDir; 2655 cc.defineGetterSetter(_p, "rotationIsDir", _p.getRotationIsDir, _p.setRotationIsDir); 2656 /** @expose */ 2657 _p.startRadius; 2658 cc.defineGetterSetter(_p, "startRadius", _p.getStartRadius, _p.setStartRadius); 2659 /** @expose */ 2660 _p.startRadiusVar; 2661 cc.defineGetterSetter(_p, "startRadiusVar", _p.getStartRadiusVar, _p.setStartRadiusVar); 2662 /** @expose */ 2663 _p.endRadius; 2664 cc.defineGetterSetter(_p, "endRadius", _p.getEndRadius, _p.setEndRadius); 2665 /** @expose */ 2666 _p.endRadiusVar; 2667 cc.defineGetterSetter(_p, "endRadiusVar", _p.getEndRadiusVar, _p.setEndRadiusVar); 2668 /** @expose */ 2669 _p.rotatePerS; 2670 cc.defineGetterSetter(_p, "rotatePerS", _p.getRotatePerSecond, _p.setRotatePerSecond); 2671 /** @expose */ 2672 _p.rotatePerSVar; 2673 cc.defineGetterSetter(_p, "rotatePerSVar", _p.getRotatePerSecondVar, _p.setRotatePerSecondVar); 2674 /** @expose */ 2675 _p.startColor; 2676 cc.defineGetterSetter(_p, "startColor", _p.getStartColor, _p.setStartColor); 2677 /** @expose */ 2678 _p.startColorVar; 2679 cc.defineGetterSetter(_p, "startColorVar", _p.getStartColorVar, _p.setStartColorVar); 2680 /** @expose */ 2681 _p.endColor; 2682 cc.defineGetterSetter(_p, "endColor", _p.getEndColor, _p.setEndColor); 2683 /** @expose */ 2684 _p.endColorVar; 2685 cc.defineGetterSetter(_p, "endColorVar", _p.getEndColorVar, _p.setEndColorVar); 2686 /** @expose */ 2687 _p.totalParticles; 2688 cc.defineGetterSetter(_p, "totalParticles", _p.getTotalParticles, _p.setTotalParticles); 2689 /** @expose */ 2690 _p.texture; 2691 cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); 2692 2693 2694 /** 2695 * <p> return the string found by key in dict. <br/> 2696 * This plist files can be create manually or with Particle Designer:<br/> 2697 * http://particledesigner.71squared.com/<br/> 2698 * </p> 2699 * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead. 2700 * @param {String|Number} plistFile 2701 * @return {cc.ParticleSystem} 2702 */ 2703 cc.ParticleSystem.create = function (plistFile) { 2704 return new cc.ParticleSystem(plistFile); 2705 }; 2706 2707 /** 2708 * <p> return the string found by key in dict. <br/> 2709 * This plist files can be create manually or with Particle Designer:<br/> 2710 * http://particledesigner.71squared.com/<br/> 2711 * </p> 2712 * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead. 2713 * @function 2714 * @param {String|Number} plistFile 2715 * @return {cc.ParticleSystem} 2716 */ 2717 cc.ParticleSystem.createWithTotalParticles = cc.ParticleSystem.create; 2718 2719 // Different modes 2720 /** 2721 * Mode A:Gravity + Tangential Accel + Radial Accel 2722 * @Class 2723 * @Construct 2724 * @param {cc.Point} [gravity=] Gravity value. 2725 * @param {Number} [speed=0] speed of each particle. 2726 * @param {Number} [speedVar=0] speed variance of each particle. 2727 * @param {Number} [tangentialAccel=0] tangential acceleration of each particle. 2728 * @param {Number} [tangentialAccelVar=0] tangential acceleration variance of each particle. 2729 * @param {Number} [radialAccel=0] radial acceleration of each particle. 2730 * @param {Number} [radialAccelVar=0] radial acceleration variance of each particle. 2731 * @param {boolean} [rotationIsDir=false] 2732 */ 2733 cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, tangentialAccelVar, radialAccel, radialAccelVar, rotationIsDir) { 2734 /** Gravity value. Only available in 'Gravity' mode. */ 2735 this.gravity = gravity ? gravity : cc.p(0,0); 2736 /** speed of each particle. Only available in 'Gravity' mode. */ 2737 this.speed = speed || 0; 2738 /** speed variance of each particle. Only available in 'Gravity' mode. */ 2739 this.speedVar = speedVar || 0; 2740 /** tangential acceleration of each particle. Only available in 'Gravity' mode. */ 2741 this.tangentialAccel = tangentialAccel || 0; 2742 /** tangential acceleration variance of each particle. Only available in 'Gravity' mode. */ 2743 this.tangentialAccelVar = tangentialAccelVar || 0; 2744 /** radial acceleration of each particle. Only available in 'Gravity' mode. */ 2745 this.radialAccel = radialAccel || 0; 2746 /** radial acceleration variance of each particle. Only available in 'Gravity' mode. */ 2747 this.radialAccelVar = radialAccelVar || 0; 2748 /** set the rotation of each particle to its direction Only available in 'Gravity' mode. */ 2749 this.rotationIsDir = rotationIsDir || false; 2750 }; 2751 2752 /** 2753 * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) 2754 * @Class 2755 * @Construct 2756 * @param {Number} startRadius The starting radius of the particles. 2757 * @param {Number} startRadiusVar The starting radius variance of the particles. 2758 * @param {Number} endRadius The ending radius of the particles. 2759 * @param {Number} endRadiusVar The ending radius variance of the particles. 2760 * @param {Number} rotatePerSecond Number of degress to rotate a particle around the source pos per second. 2761 * @param {Number} rotatePerSecondVar Variance in degrees for rotatePerSecond. 2762 */ 2763 cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) { 2764 /** The starting radius of the particles. Only available in 'Radius' mode. */ 2765 this.startRadius = startRadius || 0; 2766 /** The starting radius variance of the particles. Only available in 'Radius' mode. */ 2767 this.startRadiusVar = startRadiusVar || 0; 2768 /** The ending radius of the particles. Only available in 'Radius' mode. */ 2769 this.endRadius = endRadius || 0; 2770 /** The ending radius variance of the particles. Only available in 'Radius' mode. */ 2771 this.endRadiusVar = endRadiusVar || 0; 2772 /** Number of degress to rotate a particle around the source pos per second. Only available in 'Radius' mode. */ 2773 this.rotatePerSecond = rotatePerSecond || 0; 2774 /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */ 2775 this.rotatePerSecondVar = rotatePerSecondVar || 0; 2776 }; 2777 2778 /** 2779 * Shape Mode of Particle Draw 2780 * @constant 2781 * @type Number 2782 */ 2783 cc.ParticleSystem.SHAPE_MODE = 0; 2784 2785 /** 2786 * Texture Mode of Particle Draw 2787 * @constant 2788 * @type Number 2789 */ 2790 cc.ParticleSystem.TEXTURE_MODE = 1; 2791 2792 /** 2793 * Star Shape for ShapeMode of Particle 2794 * @constant 2795 * @type Number 2796 */ 2797 cc.ParticleSystem.STAR_SHAPE = 0; 2798 2799 /** 2800 * Ball Shape for ShapeMode of Particle 2801 * @constant 2802 * @type Number 2803 */ 2804 cc.ParticleSystem.BALL_SHAPE = 1; 2805 2806 /** 2807 * The Particle emitter lives forever 2808 * @constant 2809 * @type Number 2810 */ 2811 cc.ParticleSystem.DURATION_INFINITY = -1; 2812 2813 /** 2814 * The starting size of the particle is equal to the ending size 2815 * @constant 2816 * @type Number 2817 */ 2818 cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE = -1; 2819 2820 /** 2821 * The starting radius of the particle is equal to the ending radius 2822 * @constant 2823 * @type Number 2824 */ 2825 cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS = -1; 2826 2827 /** 2828 * Gravity mode (A mode) 2829 * @constant 2830 * @type Number 2831 */ 2832 cc.ParticleSystem.MODE_GRAVITY = 0; 2833 2834 /** 2835 * Radius mode (B mode) 2836 * @constant 2837 * @type Number 2838 */ 2839 cc.ParticleSystem.MODE_RADIUS = 1; 2840 2841 /** 2842 * Living particles are attached to the world and are unaffected by emitter repositioning. 2843 * @constant 2844 * @type Number 2845 */ 2846 cc.ParticleSystem.TYPE_FREE = 0; 2847 2848 /** 2849 * Living particles are attached to the world but will follow the emitter repositioning.<br/> 2850 * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite. 2851 * @constant 2852 * @type Number 2853 */ 2854 cc.ParticleSystem.TYPE_RELATIVE = 1; 2855 2856 /** 2857 * Living particles are attached to the emitter and are translated along with it. 2858 * @constant 2859 * @type Number 2860 */ 2861 cc.ParticleSystem.TYPE_GROUPED = 2; 2862