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