1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 28 /** 29 * <p> 30 * A cc.SpriteBatchNode can reference one and only one texture (one image file, one texture atlas).<br/> 31 * Only the cc.Sprites that are contained in that texture can be added to the cc.SpriteBatchNode.<br/> 32 * All cc.Sprites added to a cc.SpriteBatchNode are drawn in one WebGL draw call. <br/> 33 * If the cc.Sprites are not added to a cc.SpriteBatchNode then an WebGL draw call will be needed for each one, which is less efficient. <br/> 34 * <br/> 35 * Limitations:<br/> 36 * - The only object that is accepted as child (or grandchild, grand-grandchild, etc...) is cc.Sprite or any subclass of cc.Sprite. <br/> 37 * eg: particles, labels and layer can't be added to a cc.SpriteBatchNode. <br/> 38 * - Either all its children are Aliased or Antialiased. It can't be a mix. <br/> 39 * This is because "alias" is a property of the texture, and all the sprites share the same texture. </br> 40 * </p> 41 * @class 42 * @extends cc.Node 43 * 44 * @param {String|cc.Texture2D} fileImage 45 * @example 46 * 47 * // 1. create a SpriteBatchNode with image path 48 * var spriteBatchNode = new cc.SpriteBatchNode("res/animations/grossini.png"); 49 * 50 * // 2. create a SpriteBatchNode with texture 51 * var texture = cc.textureCache.addImage("res/animations/grossini.png"); 52 * var spriteBatchNode = new cc.SpriteBatchNode(texture); 53 * 54 * @property {cc.TextureAtlas} textureAtlas - The texture atlas 55 * @property {Array} descendants - <@readonly> Descendants of sprite batch node 56 */ 57 cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ 58 _blendFunc: null, 59 // all descendants: chlidren, gran children, etc... 60 _texture: null, 61 _className: "SpriteBatchNode", 62 63 ctor: function (fileImage) { 64 cc.Node.prototype.ctor.call(this); 65 this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); 66 67 var texture2D; 68 if (cc.isString(fileImage)) { 69 texture2D = cc.textureCache.getTextureForKey(fileImage); 70 if (!texture2D) 71 texture2D = cc.textureCache.addImage(fileImage); 72 }else if (fileImage instanceof cc.Texture2D) 73 texture2D = fileImage; 74 75 texture2D && this.initWithTexture(texture2D); 76 }, 77 78 /** 79 * <p> 80 * Same as addChild 81 * </p> 82 * @param {cc.Sprite} child 83 * @param {Number} z zOrder 84 * @param {Number} aTag 85 * @return {cc.SpriteBatchNode} 86 * @deprecated since v3.12 87 */ 88 addSpriteWithoutQuad: function (child, z, aTag) { 89 this.addChild(child, z, aTag); 90 return this; 91 }, 92 93 // property 94 /** 95 * Return null, no texture atlas is used any more 96 * @return {cc.TextureAtlas} 97 * @deprecated since v3.12 98 */ 99 getTextureAtlas: function () { 100 return null; 101 }, 102 103 /** 104 * TextureAtlas of cc.SpriteBatchNode setter 105 * @param {cc.TextureAtlas} textureAtlas 106 * @deprecated since v3.12 107 */ 108 setTextureAtlas: function (textureAtlas) {}, 109 110 /** 111 * Return Descendants of cc.SpriteBatchNode 112 * @return {Array} 113 * @deprecated since v3.12 114 */ 115 getDescendants: function () { 116 return this._children; 117 }, 118 119 /** 120 * <p> 121 * Initializes a cc.SpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and a capacity of children.<br/> 122 * The capacity will be increased in 33% in runtime if it run out of space.<br/> 123 * The file will be loaded using the TextureMgr.<br/> 124 * Please pass parameters to constructor to initialize the sprite batch node, do not call this function yourself. 125 * </p> 126 * @param {String} fileImage 127 * @param {Number} capacity 128 * @return {Boolean} 129 */ 130 initWithFile: function (fileImage, capacity) { 131 var texture2D = cc.textureCache.getTextureForKey(fileImage); 132 if (!texture2D) 133 texture2D = cc.textureCache.addImage(fileImage); 134 return this.initWithTexture(texture2D, capacity); 135 }, 136 137 /** 138 * <p> 139 * initializes a cc.SpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and a capacity of children.<br/> 140 * The capacity will be increased in 33% in runtime if it run out of space.<br/> 141 * The file will be loaded using the TextureMgr.<br/> 142 * Please pass parameters to constructor to initialize the sprite batch node, do not call this function yourself. 143 * </p> 144 * @param {String} fileImage 145 * @param {Number} capacity 146 * @return {Boolean} 147 */ 148 init: function (fileImage, capacity) { 149 var texture2D = cc.textureCache.getTextureForKey(fileImage); 150 if (!texture2D) 151 texture2D = cc.textureCache.addImage(fileImage); 152 return this.initWithTexture(texture2D, capacity); 153 }, 154 155 /** 156 * Do nothing 157 * @deprecated since v3.12 158 */ 159 increaseAtlasCapacity: function () {}, 160 161 /** 162 * Removes a child given a certain index. It will also cleanup the running actions depending on the cleanup parameter. 163 * @warning Removing a child from a cc.SpriteBatchNode is very slow 164 * @param {Number} index 165 * @param {Boolean} doCleanup 166 */ 167 removeChildAtIndex: function (index, doCleanup) { 168 this.removeChild(this._children[index], doCleanup); 169 }, 170 171 /** 172 * Do nothing 173 * @param {cc.Sprite} pobParent 174 * @param {Number} index 175 * @return {Number} 176 * @deprecated since v3.12 177 */ 178 rebuildIndexInOrder: function (pobParent, index) { 179 return index; 180 }, 181 182 /** 183 * Returns highest atlas index in child 184 * @param {cc.Sprite} sprite 185 * @return {Number} 186 * @deprecated since v3.12 187 */ 188 highestAtlasIndexInChild: function (sprite) { 189 var children = sprite.children; 190 if (!children || children.length === 0) 191 return sprite.zIndex; 192 else 193 return this.highestAtlasIndexInChild(children[children.length - 1]); 194 }, 195 196 /** 197 * Returns lowest atlas index in child 198 * @param {cc.Sprite} sprite 199 * @return {Number} 200 * @deprecated since v3.12 201 */ 202 lowestAtlasIndexInChild: function (sprite) { 203 var children = sprite.children; 204 if (!children || children.length === 0) 205 return sprite.zIndex; 206 else 207 return this.lowestAtlasIndexInChild(children[children.length - 1]); 208 }, 209 210 /** 211 * Returns index for child 212 * @param {cc.Sprite} sprite 213 * @return {Number} 214 * @deprecated since v3.12 215 */ 216 atlasIndexForChild: function (sprite) { 217 return sprite.zIndex; 218 }, 219 220 /** 221 * Sprites use this to start sortChildren, don't call this manually 222 * @param {Boolean} reorder 223 * @deprecated since v3.12 224 */ 225 reorderBatch: function (reorder) { 226 this._reorderChildDirty = reorder; 227 }, 228 229 /** 230 * Sets the source and destination blending function for the texture 231 * @param {Number | cc.BlendFunc} src 232 * @param {Number} dst 233 */ 234 setBlendFunc: function (src, dst) { 235 if (dst === undefined) 236 this._blendFunc = src; 237 else 238 this._blendFunc = {src: src, dst: dst}; 239 }, 240 241 /** 242 * Returns the blending function used for the texture 243 * @return {cc.BlendFunc} 244 */ 245 getBlendFunc: function () { 246 return new cc.BlendFunc(this._blendFunc.src,this._blendFunc.dst); 247 }, 248 249 /** 250 * <p> 251 * Updates a quad at a certain index into the texture atlas. The CCSprite won't be added into the children array. <br/> 252 * This method should be called only when you are dealing with very big AtlasSrite and when most of the cc.Sprite won't be updated.<br/> 253 * For example: a tile map (cc.TMXMap) or a label with lots of characters (BitmapFontAtlas)<br/> 254 * </p> 255 * @function 256 * @param {cc.Sprite} sprite 257 * @param {Number} index 258 */ 259 updateQuadFromSprite: function (sprite, index) { 260 cc.assert(sprite, cc._LogInfos.CCSpriteBatchNode_updateQuadFromSprite_2); 261 if (!(sprite instanceof cc.Sprite)) { 262 cc.log(cc._LogInfos.CCSpriteBatchNode_updateQuadFromSprite); 263 return; 264 } 265 266 // 267 // update the quad directly. Don't add the sprite to the scene graph 268 // 269 sprite.dirty = true; 270 // UpdateTransform updates the textureAtlas quad 271 sprite._renderCmd.transform(this._renderCmd, true); 272 }, 273 274 /** 275 * <p> 276 * Same as addChild(sprite, index) 277 * </p> 278 * @function 279 * @param {cc.Sprite} sprite 280 * @param {Number} index 281 * @deprecated since v3.12 282 */ 283 insertQuadFromSprite: function (sprite, index) { 284 this.addChild(sprite, index); 285 }, 286 287 /** 288 * Same as addChild(sprite, index) 289 * @param {cc.Sprite} sprite The child sprite 290 * @param {Number} index The insert index 291 * @deprecated since v3.12 292 */ 293 insertChild: function (sprite, index) { 294 this.addChild(sprite, index); 295 }, 296 297 /** 298 * Add child at the end 299 * @function 300 * @param {cc.Sprite} sprite 301 */ 302 appendChild: function (sprite) { 303 this.sortAllChildren(); 304 var lastLocalZOrder = this._children[this._children.length-1]._localZOrder; 305 this.addChild(sprite. lastLocalZOrder + 1); 306 }, 307 308 /** 309 * Same as removeChild 310 * @function 311 * @param {cc.Sprite} sprite 312 * @param {Boolean} [cleanup=true] true if all running actions and callbacks on the child node will be cleanup, false otherwise. 313 * @deprecated since v3.12 314 */ 315 removeSpriteFromAtlas: function (sprite, cleanup) { 316 this.removeChild(sprite, cleanup); 317 }, 318 319 /** 320 * Set the texture property 321 * @function 322 * @param {cc.Texture2D} tex 323 * @return {Boolean} 324 */ 325 initWithTexture: function (tex) { 326 this.setTexture(tex); 327 return true; 328 }, 329 330 // CCTextureProtocol 331 /** 332 * Returns texture of the sprite batch node 333 * @function 334 * @return {cc.Texture2D} 335 */ 336 getTexture: function () { 337 return this._texture; 338 }, 339 340 /** 341 * Sets the texture of the sprite batch node. 342 * @function 343 * @param {cc.Texture2D} texture 344 */ 345 setTexture: function(texture){ 346 this._texture = texture; 347 348 if (texture._textureLoaded) { 349 var children = this._children, i, len = children.length; 350 for (i = 0; i < len; ++i) { 351 children[i].setTexture(texture); 352 } 353 } 354 else { 355 texture.addEventListener("load", function(){ 356 var children = this._children, i, len = children.length; 357 for (i = 0; i < len; ++i) { 358 children[i].setTexture(texture); 359 } 360 }, this); 361 } 362 }, 363 364 setShaderProgram: function (newShaderProgram) { 365 this._renderCmd.setShaderProgram(newShaderProgram); 366 var children = this._children, i, len = children.length; 367 for (i = 0; i < len; ++i) { 368 children[i].setShaderProgram(newShaderProgram); 369 } 370 }, 371 372 /** 373 * Add child to the sprite batch node (override addChild of cc.Node) 374 * @function 375 * @override 376 * @param {cc.Sprite} child 377 * @param {Number} [zOrder] 378 * @param {Number} [tag] 379 */ 380 addChild: function (child, zOrder, tag) { 381 cc.assert(child !== undefined, cc._LogInfos.CCSpriteBatchNode_addChild_3); 382 383 if(!this._isValidChild(child)) 384 return; 385 386 zOrder = (zOrder === undefined) ? child.zIndex : zOrder; 387 tag = (tag === undefined) ? child.tag : tag; 388 cc.Node.prototype.addChild.call(this, child, zOrder, tag); 389 390 // Apply shader 391 if (this._renderCmd._shaderProgram) { 392 child.shaderProgram = this._renderCmd._shaderProgram; 393 } 394 }, 395 396 _isValidChild: function (child) { 397 if (!(child instanceof cc.Sprite)) { 398 cc.log(cc._LogInfos.Sprite_addChild_4); 399 return false; 400 } 401 if (child.texture !== this._texture) { 402 cc.log(cc._LogInfos.Sprite_addChild_5); 403 return false; 404 } 405 return true; 406 } 407 }); 408 409 var _p = cc.SpriteBatchNode.prototype; 410 411 // Override properties 412 cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); 413 cc.defineGetterSetter(_p, "shaderProgram", _p.getShaderProgram, _p.setShaderProgram); 414 415 416 /** 417 * <p> 418 * creates a cc.SpriteBatchNodeCanvas with a file image (.png, .jpg etc) with a default capacity of 29 children.<br/> 419 * The capacity will be increased in 33% in runtime if it run out of space.<br/> 420 * The file will be loaded using the TextureMgr.<br/> 421 * </p> 422 * @deprecated since v3.0, please use new construction instead 423 * @see cc.SpriteBatchNode 424 * @param {String|cc.Texture2D} fileImage 425 * @return {cc.SpriteBatchNode} 426 */ 427 cc.SpriteBatchNode.create = function (fileImage) { 428 return new cc.SpriteBatchNode(fileImage); 429 }; 430 431 /** 432 * @deprecated since v3.0, please use new construction instead 433 * @see cc.SpriteBatchNode 434 * @function 435 */ 436 cc.SpriteBatchNode.createWithTexture = cc.SpriteBatchNode.create; 437