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