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 /** 28 * cc.Sprite invalid index on the cc.SpriteBatchNode 29 * @constant 30 * @type Number 31 */ 32 cc.SPRITE_INDEX_NOT_INITIALIZED = -1; 33 34 /** 35 * generate texture's cache for texture tint 36 * @function 37 * @param {HTMLImageElement} texture 38 * @return {Array} 39 */ 40 41 cc.generateTextureCacheForColor = function (texture) { 42 if (texture.channelCache) { 43 return texture.channelCache; 44 } 45 46 var textureCache = [ 47 document.createElement("canvas"), 48 document.createElement("canvas"), 49 document.createElement("canvas"), 50 document.createElement("canvas") 51 ]; 52 53 function renderToCache() { 54 var ref = cc.generateTextureCacheForColor; 55 56 var w = texture.width; 57 var h = texture.height; 58 59 textureCache[0].width = w; 60 textureCache[0].height = h; 61 textureCache[1].width = w; 62 textureCache[1].height = h; 63 textureCache[2].width = w; 64 textureCache[2].height = h; 65 textureCache[3].width = w; 66 textureCache[3].height = h; 67 68 ref.canvas.width = w; 69 ref.canvas.height = h; 70 71 var ctx = ref.canvas.getContext("2d"); 72 ctx.drawImage(texture, 0, 0); 73 74 ref.tempCanvas.width = w; 75 ref.tempCanvas.height = h; 76 77 var pixels = ctx.getImageData(0, 0, w, h).data; 78 79 for (var rgbI = 0; rgbI < 4; rgbI++) { 80 var cacheCtx = textureCache[rgbI].getContext('2d'); 81 cacheCtx.getImageData(0, 0, w, h).data; 82 ref.tempCtx.drawImage(texture, 0, 0); 83 84 var to = ref.tempCtx.getImageData(0, 0, w, h); 85 var toData = to.data; 86 87 for (var i = 0; i < pixels.length; i += 4) { 88 toData[i ] = (rgbI === 0) ? pixels[i ] : 0; 89 toData[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0; 90 toData[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0; 91 toData[i + 3] = pixels[i + 3]; 92 } 93 cacheCtx.putImageData(to, 0, 0); 94 } 95 texture.onload = null; 96 } 97 98 try { 99 renderToCache(); 100 } catch (e) { 101 texture.onload = renderToCache; 102 } 103 104 texture.channelCache = textureCache; 105 return textureCache; 106 }; 107 108 cc.generateTextureCacheForColor.canvas = document.createElement('canvas'); 109 cc.generateTextureCacheForColor.tempCanvas = document.createElement('canvas'); 110 cc.generateTextureCacheForColor.tempCtx = cc.generateTextureCacheForColor.tempCanvas.getContext('2d'); 111 112 /** 113 * generate tinted texture 114 * source-in: Where source and destination overlaps and both are opaque, the source is displayed. 115 * Everywhere else transparency is displayed. 116 * @function 117 * @param {HTMLImageElement} texture 118 * @param {cc.Color} color 119 * @param {cc.Rect} rect 120 * @return {HTMLCanvasElement} 121 */ 122 cc.generateTintImage2 = function (texture, color, rect) { 123 if (!rect) { 124 rect = cc.rect(0, 0, texture.width, texture.height); 125 rect = cc.RECT_PIXELS_TO_POINTS(rect); 126 } 127 128 var buff = document.createElement("canvas"); 129 var ctx = buff.getContext("2d"); 130 131 if (buff.width != rect.width) buff.width = rect.width; 132 if (buff.height != rect.height) buff.height = rect.height; 133 ctx.save(); 134 135 ctx.drawImage(texture, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height); 136 137 ctx.globalCompositeOperation = "source-in"; 138 ctx.globalAlpha = color.a / 255.0; 139 ctx.fillStyle = "rgb(" + color.r + "," + color.g + "," + color.b + ")"; 140 ctx.fillRect(0, 0, rect.width, rect.height); 141 ctx.restore(); 142 143 return buff; 144 }; 145 146 /** 147 * generate tinted texture 148 * lighter: The source and destination colors are added to each other, resulting in brighter colors, 149 * moving towards color values of 1 (maximum brightness for that color). 150 * @function 151 * @param {HTMLImageElement} texture 152 * @param {Array} tintedImgCache 153 * @param {cc.Color} color 154 * @param {cc.Rect} rect 155 * @param {HTMLCanvasElement} [renderCanvas] 156 * @return {HTMLCanvasElement} 157 */ 158 cc.generateTintImage = function (texture, tintedImgCache, color, rect, renderCanvas) { 159 if (!rect) 160 rect = cc.rect(0, 0, texture.width, texture.height); 161 162 var r = color.r / 255; 163 var g = color.g / 255; 164 var b = color.b / 255; 165 166 var w = Math.min(rect.width, tintedImgCache[0].width); 167 var h = Math.min(rect.height, tintedImgCache[0].height); 168 var buff = renderCanvas; 169 var ctx; 170 171 // Create a new buffer if required 172 if (!buff) { 173 buff = document.createElement("canvas"); 174 buff.width = w; 175 buff.height = h; 176 ctx = buff.getContext("2d"); 177 } else { 178 ctx = buff.getContext("2d"); 179 ctx.clearRect(0, 0, w, h); 180 } 181 182 ctx.save(); 183 ctx.globalCompositeOperation = 'lighter'; 184 185 // Make sure to keep the renderCanvas alpha in mind in case of overdraw 186 var a = ctx.globalAlpha; 187 if (r > 0) { 188 ctx.globalAlpha = r * a; 189 ctx.drawImage(tintedImgCache[0], rect.x, rect.y, w, h, 0, 0, w, h); 190 } 191 if (g > 0) { 192 ctx.globalAlpha = g * a; 193 ctx.drawImage(tintedImgCache[1], rect.x, rect.y, w, h, 0, 0, w, h); 194 } 195 if (b > 0) { 196 ctx.globalAlpha = b * a; 197 ctx.drawImage(tintedImgCache[2], rect.x, rect.y, w, h, 0, 0, w, h); 198 } 199 200 if (r + g + b < 1) { 201 ctx.globalAlpha = a; 202 ctx.drawImage(tintedImgCache[3], rect.x, rect.y, w, h, 0, 0, w, h); 203 } 204 205 ctx.restore(); 206 return buff; 207 }; 208 209 cc.cutRotateImageToCanvas = function (texture, rect) { 210 if (!texture) 211 return null; 212 213 if (!rect) 214 return texture; 215 216 var nCanvas = document.createElement("canvas"); 217 nCanvas.width = rect.width; 218 nCanvas.height = rect.height; 219 220 var ctx = nCanvas.getContext("2d"); 221 ctx.translate(nCanvas.width / 2, nCanvas.height / 2); 222 ctx.rotate(-1.5707963267948966); 223 ctx.drawImage(texture, rect.x, rect.y, rect.height, rect.width, -rect.height / 2, -rect.width / 2, rect.height, rect.width); 224 return nCanvas; 225 }; 226 227 cc.RENDER_IN_SUBPIXEL = function (A) { 228 return (0 | A); 229 }; 230 if (cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { 231 cc.RENDER_IN_SUBPIXEL = function (A) { 232 return A; 233 }; 234 } 235 236 /** 237 * <p>cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) ) <br/> 238 * 239 * cc.Sprite can be created with an image, or with a sub-rectangle of an image. <br/> 240 * 241 * If the parent or any of its ancestors is a cc.SpriteBatchNode then the following features/limitations are valid <br/> 242 * - Features when the parent is a cc.BatchNode: <br/> 243 * - MUCH faster rendering, specially if the cc.SpriteBatchNode has many children. All the children will be drawn in a single batch. <br/> 244 * 245 * - Limitations <br/> 246 * - Camera is not supported yet (eg: CCOrbitCamera action doesn't work) <br/> 247 * - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl) <br/> 248 * - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property. <br/> 249 * - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property. <br/> 250 * - Parallax scroller is not supported, but can be simulated with a "proxy" sprite. <br/> 251 * 252 * If the parent is an standard cc.Node, then cc.Sprite behaves like any other cc.Node: <br/> 253 * - It supports blending functions <br/> 254 * - It supports aliasing / antialiasing <br/> 255 * - But the rendering will be slower: 1 draw per children. <br/> 256 * 257 * The default anchorPoint in cc.Sprite is (0.5, 0.5). </p> 258 * @class 259 * @extends cc.NodeRGBA 260 * 261 * @property {Boolean} dirty - Indicates whether the sprite needs to be updated. 262 * @property {Boolean} flippedX - Indicates whether or not the spirte is flipped on x axis. 263 * @property {Boolean} flippedY - Indicates whether or not the spirte is flipped on y axis. 264 * @property {Number} offsetX - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex. 265 * @property {Number} offsetY - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex. 266 * @property {Number} atlasIndex - The index used on the TextureAtlas. 267 * @property {cc.Texture2D} texture - Texture used to render the sprite. 268 * @property {Boolean} textureRectRotated - <@readonly> Indicate whether the texture rectangle is rotated. 269 * @property {cc.TextureAtlas} textureAtlas - The weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode. 270 * @property {cc.SpriteBatchNode} batchNode - The batch node object if this sprite is rendered by cc.SpriteBatchNode. 271 * @property {cc.V3F_C4B_T2F_Quad} quad - <@readonly> The quad (tex coords, vertex coords and color) information. 272 * 273 * @example 274 * var aSprite = new cc.Sprite(); 275 * aSprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320)); 276 */ 277 cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ 278 RGBAProtocol:true, 279 dirty:false, 280 atlasIndex:0, 281 textureAtlas:null, 282 283 _batchNode:null, 284 _recursiveDirty:null, //Whether all of the sprite's children needs to be updated 285 _hasChildren:null, //Whether the sprite contains children 286 _shouldBeHidden:false, //should not be drawn because one of the ancestors is not visible 287 _transformToBatch:null, 288 289 // 290 // Data used when the sprite is self-rendered 291 // 292 _blendFunc:null, //It's required for CCTextureProtocol inheritance 293 _texture:null, //cc.Texture2D object that is used to render the sprite 294 295 // 296 // Shared data 297 // 298 // texture 299 _rect:null, //Retangle of cc.Texture2D 300 _rectRotated:false, //Whether the texture is rotated 301 302 // Offset Position (used by Zwoptex) 303 _offsetPosition:null, // absolute 304 _unflippedOffsetPositionFromCenter:null, 305 306 _opacityModifyRGB:false, 307 308 // image is flipped 309 _flippedX:false, //Whether the sprite is flipped horizontally or not. 310 _flippedY:false, //Whether the sprite is flipped vertically or not. 311 312 _textureLoaded:false, 313 _loadedEventListeners: null, 314 _newTextureWhenChangeColor: null, //hack property for LabelBMFont 315 _className:"Sprite", 316 317 textureLoaded:function(){ 318 return this._textureLoaded; 319 }, 320 321 addLoadedEventListener:function(callback, target){ 322 if(!this._loadedEventListeners) 323 this._loadedEventListeners = []; 324 this._loadedEventListeners.push({eventCallback:callback, eventTarget:target}); 325 }, 326 327 _callLoadedEventCallbacks:function(){ 328 if(!this._loadedEventListeners) 329 return; 330 var locListeners = this._loadedEventListeners; 331 for(var i = 0, len = locListeners.length; i < len; i++){ 332 var selCallback = locListeners[i]; 333 selCallback.eventCallback.call(selCallback.eventTarget, this); 334 } 335 locListeners.length = 0; 336 }, 337 338 /** 339 * Whether or not the Sprite needs to be updated in the Atlas 340 * @return {Boolean} true if the sprite needs to be updated in the Atlas, false otherwise. 341 */ 342 isDirty:function () { 343 return this.dirty; 344 }, 345 346 /** 347 * Makes the Sprite to be updated in the Atlas. 348 * @param {Boolean} bDirty 349 */ 350 setDirty:function (bDirty) { 351 this.dirty = bDirty; 352 }, 353 354 /** 355 * Returns whether or not the texture rectangle is rotated. 356 * @return {Boolean} 357 */ 358 isTextureRectRotated:function () { 359 return this._rectRotated; 360 }, 361 362 /** 363 * Returns the index used on the TextureAtlas. 364 * @return {Number} 365 */ 366 getAtlasIndex:function () { 367 return this.atlasIndex; 368 }, 369 370 /** 371 * Set the index used on the TextureAtlas. 372 * @warning Don't modify this value unless you know what you are doing 373 * @param {Number} atlasIndex 374 */ 375 setAtlasIndex:function (atlasIndex) { 376 this.atlasIndex = atlasIndex; 377 }, 378 379 /** 380 * returns the rect of the cc.Sprite in points 381 * @return {cc.Rect} 382 */ 383 getTextureRect:function () { 384 return cc.rect(this._rect.x, this._rect.y, this._rect.width, this._rect.height); 385 }, 386 387 /** 388 * Gets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode 389 * @return {cc.TextureAtlas} 390 */ 391 getTextureAtlas:function () { 392 return this.textureAtlas; 393 }, 394 395 /** 396 * Sets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode 397 * @param {cc.TextureAtlas} textureAtlas 398 */ 399 setTextureAtlas:function (textureAtlas) { 400 this.textureAtlas = textureAtlas; 401 }, 402 403 /** 404 * Gets the offset position of the sprite. Calculated automatically by editors like Zwoptex. 405 * @return {cc.Point} 406 */ 407 getOffsetPosition:function () { 408 return this._offsetPosition; 409 }, 410 411 _getOffsetX: function () { 412 return this._offsetPosition.x; 413 }, 414 _getOffsetY: function () { 415 return this._offsetPosition.y; 416 }, 417 418 /** 419 * conforms to cc.TextureProtocol protocol 420 * @return {cc.BlendFunc} 421 */ 422 getBlendFunc:function () { 423 return this._blendFunc; 424 }, 425 426 /** 427 * Initializes a sprite with an SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite 428 * @param {cc.SpriteFrame} spriteFrame A CCSpriteFrame object. It should includes a valid texture and a rect 429 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 430 * @example 431 * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); 432 * var sprite = new cc.Sprite(); 433 * sprite.initWithSpriteFrame(spriteFrame); 434 */ 435 initWithSpriteFrame:function (spriteFrame) { 436 if(!spriteFrame) 437 throw "cc.Sprite.initWithSpriteFrame(): spriteFrame should be non-null"; 438 if(!spriteFrame.textureLoaded()){ 439 //add event listener 440 this._textureLoaded = false; 441 spriteFrame.addLoadedEventListener(this._spriteFrameLoadedCallback, this); 442 } 443 var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect()); 444 this.setSpriteFrame(spriteFrame); 445 446 return ret; 447 }, 448 449 _spriteFrameLoadedCallback:null, 450 451 _spriteFrameLoadedCallbackForWebGL:function(spriteFrame){ 452 this.setNodeDirty(true); 453 this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize()); 454 this._callLoadedEventCallbacks(); 455 }, 456 457 _spriteFrameLoadedCallbackForCanvas:function(spriteFrame){ 458 this.setNodeDirty(true); 459 this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize()); 460 var curColor = this.color; 461 if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255) 462 this._changeTextureColor(); 463 464 this._callLoadedEventCallbacks(); 465 }, 466 467 /** 468 * Initializes a sprite with a sprite frame name. <br/> 469 * A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name. <br/> 470 * If the cc.SpriteFrame doesn't exist it will raise an exception. <br/> 471 * @param {String} spriteFrameName A key string that can fected a volid cc.SpriteFrame from cc.SpriteFrameCache 472 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 473 * @example 474 * var sprite = new cc.Sprite(); 475 * sprite.initWithSpriteFrameName("grossini_dance_01.png"); 476 */ 477 initWithSpriteFrameName:function (spriteFrameName) { 478 if(!spriteFrameName) 479 throw "cc.Sprite.initWithSpriteFrameName(): spriteFrameName should be non-null"; 480 var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName); 481 return this.initWithSpriteFrame(frame); 482 }, 483 484 /** 485 * tell the sprite to use batch node render. 486 * @param {cc.SpriteBatchNode} batchNode 487 */ 488 useBatchNode:function (batchNode) { 489 this.textureAtlas = batchNode.textureAtlas; // weak ref 490 this._batchNode = batchNode; 491 }, 492 493 /** 494 * <p> 495 * set the vertex rect.<br/> 496 * It will be called internally by setTextureRect. <br/> 497 * Useful if you want to create 2x images from SD images in Retina Display. <br/> 498 * Do not call it manually. Use setTextureRect instead. <br/> 499 * (override this method to generate "double scale" sprites) 500 * </p> 501 * @param {cc.Rect} rect 502 */ 503 setVertexRect:function (rect) { 504 this._rect.x = rect.x; 505 this._rect.y = rect.y; 506 this._rect.width = rect.width; 507 this._rect.height = rect.height; 508 }, 509 510 sortAllChildren:function () { 511 if (this._reorderChildDirty) { 512 var j, tempItem, locChildren = this._children, tempChild; 513 for (var i = 1; i < locChildren.length; i++) { 514 tempItem = locChildren[i]; 515 j = i - 1; 516 tempChild = locChildren[j]; 517 518 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller 519 while (j >= 0 && ( tempItem._localZOrder < tempChild._localZOrder || 520 ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { 521 locChildren[j + 1] = tempChild; 522 j = j - 1; 523 tempChild = locChildren[j]; 524 } 525 locChildren[j + 1] = tempItem; 526 } 527 528 if (this._batchNode) { 529 this._arrayMakeObjectsPerformSelector(locChildren, cc.Node.StateCallbackType.sortAllChildren); 530 } 531 this._reorderChildDirty = false; 532 } 533 }, 534 535 /** 536 * Reorders a child according to a new z value. (override cc.Node ) 537 * @param {cc.Node} child 538 * @param {Number} zOrder 539 * @override 540 */ 541 reorderChild:function (child, zOrder) { 542 if(!child) 543 throw "cc.Sprite.reorderChild(): child should be non-null"; 544 if(this._children.indexOf(child) === -1){ 545 cc.log("cc.Sprite.reorderChild(): this child is not in children list"); 546 return; 547 } 548 549 if (zOrder === child.zIndex) 550 return; 551 552 if (this._batchNode && !this._reorderChildDirty) { 553 this._setReorderChildDirtyRecursively(); 554 this._batchNode.reorderBatch(true); 555 } 556 cc.Node.prototype.reorderChild.call(this, child, zOrder); 557 }, 558 559 /** 560 * Removes a child from the sprite. (override cc.Node ) 561 * @param child 562 * @param cleanup whether or not cleanup all running actions 563 * @override 564 */ 565 removeChild:function (child, cleanup) { 566 if (this._batchNode) 567 this._batchNode.removeSpriteFromAtlas(child); 568 cc.Node.prototype.removeChild.call(this, child, cleanup); 569 }, 570 571 /** 572 * Removes all children from the container (override cc.Node ) 573 * @param cleanup whether or not cleanup all running actions 574 * @override 575 */ 576 removeAllChildren:function (cleanup) { 577 var locChildren = this._children, locBatchNode = this._batchNode; 578 if (locBatchNode && locChildren != null) { 579 for (var i = 0, len = locChildren.length; i < len; i++) 580 locBatchNode.removeSpriteFromAtlas(locChildren[i]); 581 } 582 583 cc.Node.prototype.removeAllChildren.call(this, cleanup); 584 this._hasChildren = false; 585 }, 586 587 // 588 // cc.Node property overloads 589 // 590 591 /** 592 * set Recursively is or isn't Dirty 593 * used only when parent is cc.SpriteBatchNode 594 * @param {Boolean} value 595 */ 596 setDirtyRecursively:function (value) { 597 this._recursiveDirty = value; 598 this.dirty = value; 599 // recursively set dirty 600 var locChildren = this._children, child, l = locChildren ? locChildren.length : 0; 601 for (var i = 0; i < l; i++) { 602 child = locChildren[i]; 603 (child instanceof cc.Sprite) && child.setDirtyRecursively(true); 604 } 605 }, 606 607 /** 608 * Make the node dirty 609 * @param {Boolean} norecursive When true children will not be set dirty recursively, by default, they will be. 610 * @override 611 */ 612 setNodeDirty: function(norecursive) { 613 cc.Node.prototype.setNodeDirty.call(this); 614 // Lazy set dirty 615 if (!norecursive && this._batchNode && !this._recursiveDirty) { 616 if (this._hasChildren) 617 this.setDirtyRecursively(true); 618 else { 619 this._recursiveDirty = true; 620 this.dirty = true; 621 } 622 } 623 }, 624 625 /** 626 * IsRelativeAnchorPoint setter (override cc.Node ) 627 * @param {Boolean} relative 628 * @override 629 */ 630 ignoreAnchorPointForPosition:function (relative) { 631 if(this._batchNode){ 632 cc.log("cc.Sprite.ignoreAnchorPointForPosition(): it is invalid in cc.Sprite when using SpriteBatchNode"); 633 return; 634 } 635 cc.Node.prototype.ignoreAnchorPointForPosition.call(this, relative); 636 }, 637 638 /** 639 * Sets whether the sprite should be flipped horizontally or not. 640 * @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise. 641 */ 642 setFlippedX:function (flippedX) { 643 if (this._flippedX != flippedX) { 644 this._flippedX = flippedX; 645 this.setTextureRect(this._rect, this._rectRotated, this._contentSize); 646 this.setNodeDirty(true); 647 } 648 }, 649 650 /** 651 * Sets whether the sprite should be flipped vertically or not. 652 * @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise. 653 */ 654 setFlippedY:function (flippedY) { 655 if (this._flippedY != flippedY) { 656 this._flippedY = flippedY; 657 this.setTextureRect(this._rect, this._rectRotated, this._contentSize); 658 this.setNodeDirty(true); 659 } 660 }, 661 662 /** 663 * <p> 664 * Returns the flag which indicates whether the sprite is flipped horizontally or not. <br/> 665 * <br/> 666 * It only flips the texture of the sprite, and not the texture of the sprite's children. <br/> 667 * Also, flipping the texture doesn't alter the anchorPoint. <br/> 668 * If you want to flip the anchorPoint too, and/or to flip the children too use: <br/> 669 * sprite->setScaleX(sprite->getScaleX() * -1); <p/> 670 * @return {Boolean} true if the sprite is flipped horizaontally, false otherwise. 671 */ 672 isFlippedX:function () { 673 return this._flippedX; 674 }, 675 676 /** 677 * <p> 678 * Return the flag which indicates whether the sprite is flipped vertically or not. <br/> 679 * <br/> 680 * It only flips the texture of the sprite, and not the texture of the sprite's children. <br/> 681 * Also, flipping the texture doesn't alter the anchorPoint. <br/> 682 * If you want to flip the anchorPoint too, and/or to flip the children too use: <br/> 683 * sprite->setScaleY(sprite->getScaleY() * -1); <p/> 684 * @return {Boolean} true if the sprite is flipped vertically, flase otherwise. 685 */ 686 isFlippedY:function () { 687 return this._flippedY; 688 }, 689 690 // 691 // RGBA protocol 692 // 693 /** 694 * opacity: conforms to CCRGBAProtocol protocol 695 * @function 696 * @param {Boolean} modify 697 */ 698 setOpacityModifyRGB:null, 699 700 _setOpacityModifyRGBForWebGL: function (modify) { 701 if (this._opacityModifyRGB !== modify) { 702 this._opacityModifyRGB = modify; 703 this.updateColor(); 704 } 705 }, 706 707 _setOpacityModifyRGBForCanvas: function (modify) { 708 if (this._opacityModifyRGB !== modify) { 709 this._opacityModifyRGB = modify; 710 this.setNodeDirty(true); 711 } 712 }, 713 714 /** 715 * return IsOpacityModifyRGB value 716 * @return {Boolean} 717 */ 718 isOpacityModifyRGB:function () { 719 return this._opacityModifyRGB; 720 }, 721 722 updateDisplayedOpacity: null, 723 724 _updateDisplayedOpacityForWebGL:function (parentOpacity) { 725 cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity); 726 this.updateColor(); 727 }, 728 729 _updateDisplayedOpacityForCanvas:function (parentOpacity) { 730 cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity); 731 this._setNodeDirtyForCache(); 732 }, 733 734 // Animation 735 736 /** 737 * changes the display frame with animation name and index.<br/> 738 * The animation name will be get from the CCAnimationCache 739 * @param animationName 740 * @param frameIndex 741 */ 742 setDisplayFrameWithAnimationName:function (animationName, frameIndex) { 743 if(!animationName) 744 throw "cc.Sprite.setDisplayFrameWithAnimationName(): animationName must be non-null"; 745 var cache = cc.animationCache.getAnimation(animationName); 746 if(!cache){ 747 cc.log("cc.Sprite.setDisplayFrameWithAnimationName(): Frame not found"); 748 return; 749 } 750 var animFrame = cache.getFrames()[frameIndex]; 751 if(!animFrame){ 752 cc.log("cc.Sprite.setDisplayFrameWithAnimationName(): Invalid frame index"); 753 return; 754 } 755 this.setSpriteFrame(animFrame.getSpriteFrame()); 756 }, 757 758 /** 759 * Returns the batch node object if this sprite is rendered by cc.SpriteBatchNode 760 * @returns {cc.SpriteBatchNode|null} The cc.SpriteBatchNode object if this sprite is rendered by cc.SpriteBatchNode, null if the sprite isn't used batch node. 761 */ 762 getBatchNode:function () { 763 return this._batchNode; 764 }, 765 766 _setReorderChildDirtyRecursively:function () { 767 //only set parents flag the first time 768 if (!this._reorderChildDirty) { 769 this._reorderChildDirty = true; 770 var pNode = this._parent; 771 while (pNode && pNode != this._batchNode) { 772 pNode._setReorderChildDirtyRecursively(); 773 pNode = pNode.parent; 774 } 775 } 776 }, 777 778 // CCTextureProtocol 779 getTexture:function () { 780 return this._texture; 781 }, 782 783 _quad:null, // vertex coords, texture coords and color info 784 _quadWebBuffer:null, 785 _quadDirty:false, 786 _colorized:false, 787 _isLighterMode:false, 788 _originalTexture:null, 789 _textureRect_Canvas:null, 790 _drawSize_Canvas:null, 791 792 /** 793 * Constructor 794 * @function 795 * @param {String|cc.SpriteFrame|cc.SpriteBatchNode|HTMLImageElement|cc.Texture2D} fileName sprite construct parameter 796 * @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite. 797 */ 798 ctor: null, 799 800 _ctorForWebGL: function (fileName, rect) { 801 cc.NodeRGBA.prototype.ctor.call(this); 802 this._shouldBeHidden = false; 803 this._offsetPosition = cc.p(0, 0); 804 this._unflippedOffsetPositionFromCenter = cc.p(0, 0); 805 this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; 806 this._rect = cc.rect(0,0,0,0); 807 808 this._quad = new cc.V3F_C4B_T2F_Quad(); 809 this._quadWebBuffer = cc._renderContext.createBuffer(); 810 this._quadDirty = true; 811 812 this._textureLoaded = true; 813 814 this._softInit(fileName, rect); 815 }, 816 817 _ctorForCanvas: function (fileName, rect) { 818 cc.NodeRGBA.prototype.ctor.call(this); 819 this._shouldBeHidden = false; 820 this._offsetPosition = cc.p(0, 0); 821 this._unflippedOffsetPositionFromCenter = cc.p(0, 0); 822 this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; 823 this._rect = cc.rect(0, 0, 0, 0); 824 825 this._newTextureWhenChangeColor = false; 826 this._textureLoaded = true; 827 this._textureRect_Canvas = {x: 0, y: 0, width: 0, height:0, validRect: false}; 828 this._drawSize_Canvas = cc.size(0, 0); 829 830 this._softInit(fileName, rect); 831 }, 832 833 _softInit: function (fileName, rect) { 834 if (fileName === undefined) 835 cc.Sprite.prototype.init.call(this); 836 else if (typeof(fileName) === "string") { 837 if (fileName[0] === "#") { 838 // Init with a sprite frame name 839 var frameName = fileName.substr(1, fileName.length - 1); 840 var spriteFrame = cc.spriteFrameCache.getSpriteFrame(frameName); 841 this.initWithSpriteFrame(spriteFrame); 842 } else { 843 // Init with filename and rect 844 cc.Sprite.prototype.init.call(this, fileName, rect); 845 } 846 } 847 else if (typeof(fileName) === "object") { 848 if (fileName instanceof cc.Texture2D) { 849 // Init with texture and rect 850 this.initWithTexture(fileName, rect); 851 } else if (fileName instanceof cc.SpriteFrame) { 852 // Init with a sprite frame 853 this.initWithSpriteFrame(fileName); 854 } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) { 855 // Init with a canvas or image element 856 var texture2d = new cc.Texture2D(); 857 texture2d.initWithElement(fileName); 858 texture2d.handleLoadedTexture(); 859 this.initWithTexture(texture2d); 860 } 861 } 862 }, 863 864 /** 865 * Returns the quad (tex coords, vertex coords and color) information. 866 * @return {cc.V3F_C4B_T2F_Quad} 867 */ 868 getQuad:function () { 869 return this._quad; 870 }, 871 872 /** 873 * conforms to cc.TextureProtocol protocol 874 * @function 875 * @param {Number|cc.BlendFunc} src 876 * @param {Number} dst 877 */ 878 setBlendFunc: null, 879 880 _setBlendFuncForWebGL: function (src, dst) { 881 var locBlendFunc = this._blendFunc; 882 if (dst === undefined) { 883 locBlendFunc.src = src.src; 884 locBlendFunc.dst = src.dst; 885 } else { 886 locBlendFunc.src = src; 887 locBlendFunc.dst = dst; 888 } 889 }, 890 891 _setBlendFuncForCanvas: function (src, dst) { 892 var locBlendFunc = this._blendFunc; 893 if (dst === undefined) { 894 locBlendFunc.src = src.src; 895 locBlendFunc.dst = src.dst; 896 } else { 897 locBlendFunc.src = src; 898 locBlendFunc.dst = dst; 899 } 900 this._isLighterMode = (locBlendFunc && 901 (( locBlendFunc.src == cc.SRC_ALPHA && locBlendFunc.dst == cc.ONE) || (locBlendFunc.src == cc.ONE && locBlendFunc.dst == cc.ONE))); 902 }, 903 904 /** 905 * Initializes an empty sprite with nothing init. 906 * @function 907 * @return {Boolean} 908 */ 909 init:null, 910 911 _initForWebGL: function () { 912 if (arguments.length > 0) 913 return this.initWithFile(arguments[0], arguments[1]); 914 915 cc.NodeRGBA.prototype.init.call(this); 916 this.dirty = this._recursiveDirty = false; 917 this._opacityModifyRGB = true; 918 919 this._blendFunc.src = cc.BLEND_SRC; 920 this._blendFunc.dst = cc.BLEND_DST; 921 922 // update texture (calls _updateBlendFunc) 923 this.texture = null; 924 this._textureLoaded = true; 925 this._flippedX = this._flippedY = false; 926 927 // default transform anchor: center 928 this.anchorX = 0.5; 929 this.anchorY = 0.5; 930 931 // zwoptex default values 932 this._offsetPosition.x = 0; 933 this._offsetPosition.y = 0; 934 935 this._hasChildren = false; 936 937 // Atlas: Color 938 var tempColor = {r: 255, g: 255, b: 255, a: 255}; 939 this._quad.bl.colors = tempColor; 940 this._quad.br.colors = tempColor; 941 this._quad.tl.colors = tempColor; 942 this._quad.tr.colors = tempColor; 943 this._quadDirty = true; 944 945 // updated in "useSelfRender" 946 // Atlas: TexCoords 947 this.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0)); 948 return true; 949 }, 950 951 _initForCanvas: function () { 952 if (arguments.length > 0) 953 return this.initWithFile(arguments[0], arguments[1]); 954 955 cc.NodeRGBA.prototype.init.call(this); 956 this.dirty = this._recursiveDirty = false; 957 this._opacityModifyRGB = true; 958 959 this._blendFunc.src = cc.BLEND_SRC; 960 this._blendFunc.dst = cc.BLEND_DST; 961 962 // update texture (calls _updateBlendFunc) 963 this.texture = null; 964 this._textureLoaded = true; 965 this._flippedX = this._flippedY = false; 966 967 // default transform anchor: center 968 this.anchorX = 0.5; 969 this.anchorY = 0.5; 970 971 // zwoptex default values 972 this._offsetPosition.x = 0; 973 this._offsetPosition.y = 0; 974 this._hasChildren = false; 975 976 // updated in "useSelfRender" 977 // Atlas: TexCoords 978 this.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0)); 979 return true; 980 }, 981 982 /** 983 * <p> 984 * Initializes a sprite with an image filename. 985 * 986 * This method will find pszFilename from local file system, load its content to CCTexture2D, 987 * then use CCTexture2D to create a sprite. 988 * After initialization, the rect used will be the size of the image. The offset will be (0,0). 989 * </p> 990 * @param {String} filename The path to an image file in local file system 991 * @param {cc.Rect} rect The rectangle assigned the content area from texture. 992 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 993 * @example 994 * var mySprite = new cc.Sprite(); 995 * mySprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320)); 996 */ 997 initWithFile:function (filename, rect) { 998 if(!filename) 999 throw "cc.Sprite.initWithFile(): filename should be non-null"; 1000 1001 var texture = cc.textureCache.textureForKey(filename); 1002 if (!texture) { 1003 texture = cc.textureCache.addImage(filename); 1004 return this.initWithTexture(texture, rect); 1005 } else { 1006 if (!rect) { 1007 var size = texture.getContentSize(); 1008 rect = cc.rect(0, 0, size.width, size.height); 1009 } 1010 return this.initWithTexture(texture, rect); 1011 } 1012 }, 1013 1014 /** 1015 * Initializes a sprite with a texture and a rect in points, optionally rotated. <br/> 1016 * After initialization, the rect used will be the size of the texture, and the offset will be (0,0). 1017 * @function 1018 * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites. 1019 * @param {cc.Rect} rect Only the contents inside rect of this texture will be applied for this sprite. 1020 * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated. 1021 * @return {Boolean} true if the sprite is initialized properly, false otherwise. 1022 * @example 1023 * var img =cc.textureCache.addImage("HelloHTML5World.png"); 1024 * var mySprite = new cc.Sprite(); 1025 * mySprite.initWithTexture(img,cc.rect(0,0,480,320)); 1026 */ 1027 initWithTexture: null, 1028 1029 _initWithTextureForWebGL: function (texture, rect, rotated) { 1030 var argnum = arguments.length; 1031 if (argnum == 0) 1032 throw "Sprite.initWithTexture(): Argument must be non-nil "; 1033 1034 rotated = rotated || false; 1035 1036 if (!cc.NodeRGBA.prototype.init.call(this)) 1037 return false; 1038 1039 this._batchNode = null; 1040 this._recursiveDirty = false; 1041 this.dirty = false; 1042 this._opacityModifyRGB = true; 1043 1044 this._blendFunc.src = cc.BLEND_SRC; 1045 this._blendFunc.dst = cc.BLEND_DST; 1046 1047 this._flippedX = this._flippedY = false; 1048 1049 // default transform anchor: center 1050 this.anchorX = 0.5; 1051 this.anchorY = 0.5; 1052 1053 // zwoptex default values 1054 this._offsetPosition.x = 0; 1055 this._offsetPosition.y = 0; 1056 this._hasChildren = false; 1057 1058 // Atlas: Color 1059 var tmpColor = cc.color(255, 255, 255, 255); 1060 var locQuad = this._quad; 1061 locQuad.bl.colors = tmpColor; 1062 locQuad.br.colors = tmpColor; 1063 locQuad.tl.colors = tmpColor; 1064 locQuad.tr.colors = tmpColor; 1065 1066 var locTextureLoaded = texture.isLoaded(); 1067 this._textureLoaded = locTextureLoaded; 1068 1069 if (!locTextureLoaded) { 1070 this._rectRotated = rotated || false; 1071 if (rect) { 1072 var locRect = this._rect; 1073 locRect.x = rect.x; 1074 locRect.y = rect.y; 1075 locRect.width = rect.width; 1076 locRect.height = rect.height; 1077 } 1078 texture.addLoadedEventListener(this._textureLoadedCallback, this); 1079 return true; 1080 } 1081 1082 if (!rect) { 1083 rect = cc.rect(0, 0, texture.width, texture.height); 1084 } 1085 this.texture = texture; 1086 this.setTextureRect(rect, rotated); 1087 1088 // by default use "Self Render". 1089 // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" 1090 this.batchNode = null; 1091 this._quadDirty = true; 1092 return true; 1093 }, 1094 1095 _initWithTextureForCanvas: function (texture, rect, rotated) { 1096 var argnum = arguments.length; 1097 if (argnum == 0) 1098 throw "Sprite.initWithTexture(): Argument must be non-nil "; 1099 1100 rotated = rotated || false; 1101 1102 if (!cc.NodeRGBA.prototype.init.call(this)) 1103 return false; 1104 1105 this._batchNode = null; 1106 1107 this._recursiveDirty = false; 1108 this.dirty = false; 1109 this._opacityModifyRGB = true; 1110 1111 this._blendFunc.src = cc.BLEND_SRC; 1112 this._blendFunc.dst = cc.BLEND_DST; 1113 1114 this._flippedX = this._flippedY = false; 1115 1116 // default transform anchor: center 1117 this.anchorX = 0.5; 1118 this.anchorY = 0.5; 1119 1120 // zwoptex default values 1121 this._offsetPosition.x = 0; 1122 this._offsetPosition.y = 0; 1123 this._hasChildren = false; 1124 1125 var locTextureLoaded = texture.isLoaded(); 1126 this._textureLoaded = locTextureLoaded; 1127 1128 if (!locTextureLoaded) { 1129 this._rectRotated = rotated || false; 1130 if (rect) { 1131 this._rect.x = rect.x; 1132 this._rect.y = rect.y; 1133 this._rect.width = rect.width; 1134 this._rect.height = rect.height; 1135 } 1136 texture.addLoadedEventListener(this._textureLoadedCallback, this); 1137 return true; 1138 } 1139 1140 if (!rect) { 1141 rect = cc.rect(0, 0, texture.width, texture.height); 1142 } 1143 this._originalTexture = texture; 1144 1145 this.texture = texture; 1146 this.setTextureRect(rect, rotated); 1147 1148 // by default use "Self Render". 1149 // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" 1150 this.batchNode = null; 1151 return true; 1152 }, 1153 1154 _textureLoadedCallback: null, 1155 1156 _textureLoadedCallbackForWebGL: function (sender) { 1157 if(this._textureLoaded) 1158 return; 1159 1160 this._textureLoaded = true; 1161 var locRect = this._rect; 1162 if (!locRect) { 1163 locRect = cc.rect(0, 0, sender.width, sender.height); 1164 } else if (cc._rectEqualToZero(locRect)) { 1165 locRect.width = sender.width; 1166 locRect.height = sender.height; 1167 } 1168 1169 this.texture = sender; 1170 this.setTextureRect(locRect, this._rectRotated); 1171 1172 // by default use "Self Render". 1173 // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" 1174 this.batchNode = null; 1175 this._quadDirty = true; 1176 this._callLoadedEventCallbacks(); 1177 }, 1178 1179 _textureLoadedCallbackForCanvas: function (sender) { 1180 if(this._textureLoaded) 1181 return; 1182 1183 this._textureLoaded = true; 1184 var locRect = this._rect; 1185 if (!locRect) { 1186 locRect = cc.rect(0, 0, sender.width, sender.height); 1187 } else if (cc._rectEqualToZero(locRect)) { 1188 locRect.width = sender.width; 1189 locRect.height = sender.height; 1190 } 1191 this._originalTexture = sender; 1192 1193 this.texture = sender; 1194 this.setTextureRect(locRect, this._rectRotated); 1195 1196 // by default use "Self Render". 1197 // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" 1198 this.batchNode = null; 1199 this._callLoadedEventCallbacks(); 1200 }, 1201 1202 /** 1203 * updates the texture rect of the CCSprite in points. 1204 * @function 1205 * @param {cc.Rect} rect a rect of texture 1206 * @param {Boolean} rotated 1207 * @param {cc.Size} untrimmedSize 1208 */ 1209 setTextureRect:null, 1210 1211 _setTextureRectForWebGL:function (rect, rotated, untrimmedSize) { 1212 this._rectRotated = rotated || false; 1213 this.setContentSize(untrimmedSize || rect); 1214 1215 this.setVertexRect(rect); 1216 this._setTextureCoords(rect); 1217 1218 var relativeOffset = this._unflippedOffsetPositionFromCenter; 1219 if (this._flippedX) 1220 relativeOffset.x = -relativeOffset.x; 1221 if (this._flippedY) 1222 relativeOffset.y = -relativeOffset.y; 1223 1224 var locRect = this._rect; 1225 this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - locRect.width) / 2; 1226 this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - locRect.height) / 2; 1227 1228 // rendering using batch node 1229 if (this._batchNode) { 1230 // update dirty, don't update _recursiveDirty 1231 this.dirty = true; 1232 } else { 1233 // self rendering 1234 // Atlas: Vertex 1235 var x1 = 0 + this._offsetPosition.x; 1236 var y1 = 0 + this._offsetPosition.y; 1237 var x2 = x1 + locRect.width; 1238 var y2 = y1 + locRect.height; 1239 1240 // Don't update Z. 1241 var locQuad = this._quad; 1242 locQuad.bl.vertices = {x:x1, y:y1, z:0}; 1243 locQuad.br.vertices = {x:x2, y:y1, z:0}; 1244 locQuad.tl.vertices = {x:x1, y:y2, z:0}; 1245 locQuad.tr.vertices = {x:x2, y:y2, z:0}; 1246 1247 this._quadDirty = true; 1248 } 1249 }, 1250 1251 _setTextureRectForCanvas: function (rect, rotated, untrimmedSize) { 1252 this._rectRotated = rotated || false; 1253 this.setContentSize(untrimmedSize || rect); 1254 1255 this.setVertexRect(rect); 1256 1257 var locTextureRect = this._textureRect_Canvas, scaleFactor = cc.CONTENT_SCALE_FACTOR(); 1258 locTextureRect.x = 0 | (rect.x * scaleFactor); 1259 locTextureRect.y = 0 | (rect.y * scaleFactor); 1260 locTextureRect.width = 0 | (rect.width * scaleFactor); 1261 locTextureRect.height = 0 | (rect.height * scaleFactor); 1262 locTextureRect.validRect = !(locTextureRect.width === 0 || locTextureRect.height === 0 || locTextureRect.x < 0 || locTextureRect.y < 0); 1263 1264 var relativeOffset = this._unflippedOffsetPositionFromCenter; 1265 if (this._flippedX) 1266 relativeOffset.x = -relativeOffset.x; 1267 if (this._flippedY) 1268 relativeOffset.y = -relativeOffset.y; 1269 this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - this._rect.width) / 2; 1270 this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - this._rect.height) / 2; 1271 1272 // rendering using batch node 1273 if (this._batchNode) { 1274 // update dirty, don't update _recursiveDirty 1275 this.dirty = true; 1276 } 1277 }, 1278 1279 // BatchNode methods 1280 /** 1281 * updates the quad according the the rotation, position, scale values. 1282 * @function 1283 */ 1284 updateTransform: null, 1285 1286 _updateTransformForWebGL: function () { 1287 //cc.assert(this._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode"); 1288 1289 // recaculate matrix only if it is dirty 1290 if (this.dirty) { 1291 var locQuad = this._quad, locParent = this._parent; 1292 // If it is not visible, or one of its ancestors is not visible, then do nothing: 1293 if (!this._visible || ( locParent && locParent != this._batchNode && locParent._shouldBeHidden)) { 1294 locQuad.br.vertices = {x: 0, y: 0, z: 0}; 1295 locQuad.tl.vertices = {x: 0, y: 0, z: 0}; 1296 locQuad.tr.vertices = {x: 0, y: 0, z: 0}; 1297 locQuad.bl.vertices = {x: 0, y: 0, z: 0}; 1298 this._shouldBeHidden = true; 1299 } else { 1300 this._shouldBeHidden = false; 1301 1302 if (!locParent || locParent == this._batchNode) { 1303 this._transformToBatch = this.nodeToParentTransform(); 1304 } else { 1305 //cc.assert(this._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite"); 1306 this._transformToBatch = cc.AffineTransformConcat(this.nodeToParentTransform(), locParent._transformToBatch); 1307 } 1308 1309 // 1310 // calculate the Quad based on the Affine Matrix 1311 // 1312 var locTransformToBatch = this._transformToBatch; 1313 var rect = this._rect; 1314 var x1 = this._offsetPosition.x; 1315 var y1 = this._offsetPosition.y; 1316 1317 var x2 = x1 + rect.width; 1318 var y2 = y1 + rect.height; 1319 var x = locTransformToBatch.tx; 1320 var y = locTransformToBatch.ty; 1321 1322 var cr = locTransformToBatch.a; 1323 var sr = locTransformToBatch.b; 1324 var cr2 = locTransformToBatch.d; 1325 var sr2 = -locTransformToBatch.c; 1326 var ax = x1 * cr - y1 * sr2 + x; 1327 var ay = x1 * sr + y1 * cr2 + y; 1328 1329 var bx = x2 * cr - y1 * sr2 + x; 1330 var by = x2 * sr + y1 * cr2 + y; 1331 1332 var cx = x2 * cr - y2 * sr2 + x; 1333 var cy = x2 * sr + y2 * cr2 + y; 1334 1335 var dx = x1 * cr - y2 * sr2 + x; 1336 var dy = x1 * sr + y2 * cr2 + y; 1337 1338 var locVertexZ = this._vertexZ; 1339 locQuad.bl.vertices = {x: cc.RENDER_IN_SUBPIXEL(ax), y: cc.RENDER_IN_SUBPIXEL(ay), z: locVertexZ}; 1340 locQuad.br.vertices = {x: cc.RENDER_IN_SUBPIXEL(bx), y: cc.RENDER_IN_SUBPIXEL(by), z: locVertexZ}; 1341 locQuad.tl.vertices = {x: cc.RENDER_IN_SUBPIXEL(dx), y: cc.RENDER_IN_SUBPIXEL(dy), z: locVertexZ}; 1342 locQuad.tr.vertices = {x: cc.RENDER_IN_SUBPIXEL(cx), y: cc.RENDER_IN_SUBPIXEL(cy), z: locVertexZ}; 1343 } 1344 this.textureAtlas.updateQuad(locQuad, this.atlasIndex); 1345 this._recursiveDirty = false; 1346 this.dirty = false; 1347 } 1348 1349 // recursively iterate over children 1350 if (this._hasChildren) 1351 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform); 1352 1353 if (cc.SPRITE_DEBUG_DRAW) { 1354 // draw bounding box 1355 var vertices = [ 1356 cc.p(this._quad.bl.vertices.x, this._quad.bl.vertices.y), 1357 cc.p(this._quad.br.vertices.x, this._quad.br.vertices.y), 1358 cc.p(this._quad.tr.vertices.x, this._quad.tr.vertices.y), 1359 cc.p(this._quad.tl.vertices.x, this._quad.tl.vertices.y) 1360 ]; 1361 cc._drawingUtil.drawPoly(vertices, 4, true); 1362 } 1363 }, 1364 1365 _updateTransformForCanvas: function () { 1366 //cc.assert(this._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode"); 1367 1368 // recaculate matrix only if it is dirty 1369 if (this.dirty) { 1370 // If it is not visible, or one of its ancestors is not visible, then do nothing: 1371 var locParent = this._parent; 1372 if (!this._visible || ( locParent && locParent != this._batchNode && locParent._shouldBeHidden)) { 1373 this._shouldBeHidden = true; 1374 } else { 1375 this._shouldBeHidden = false; 1376 1377 if (!locParent || locParent == this._batchNode) { 1378 this._transformToBatch = this.nodeToParentTransform(); 1379 } else { 1380 //cc.assert(this._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite"); 1381 this._transformToBatch = cc.AffineTransformConcat(this.nodeToParentTransform(), locParent._transformToBatch); 1382 } 1383 } 1384 this._recursiveDirty = false; 1385 this.dirty = false; 1386 } 1387 1388 // recursively iterate over children 1389 if (this._hasChildren) 1390 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform); 1391 }, 1392 1393 /** 1394 * Add child to sprite (override cc.Node ) 1395 * @function 1396 * @param {cc.Sprite} child 1397 * @param {Number} localZOrder child's zOrder 1398 * @param {String} tag child's tag 1399 * @override 1400 */ 1401 addChild: null, 1402 1403 _addChildForWebGL:function (child, localZOrder, tag) { 1404 if(!child) 1405 throw "cc.Sprite.addChild(): child should be non-null"; 1406 if (localZOrder == null) 1407 localZOrder = child._localZOrder; 1408 if (tag == null) 1409 tag = child.tag; 1410 1411 if (this._batchNode) { 1412 if(!(child instanceof cc.Sprite)){ 1413 cc.log("cc.Sprite.addChild(): cc.Sprite only supports cc.Sprites as children when using cc.SpriteBatchNode"); 1414 return; 1415 } 1416 if(child.texture._webTextureObj !== this.textureAtlas.texture._webTextureObj) 1417 cc.log("cc.Sprite.addChild(): cc.Sprite only supports a sprite using same texture as children when using cc.SpriteBatchNode"); 1418 1419 //put it in descendants array of batch node 1420 this._batchNode.appendChild(child); 1421 if (!this._reorderChildDirty) 1422 this._setReorderChildDirtyRecursively(); 1423 } 1424 1425 //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check 1426 cc.NodeRGBA.prototype.addChild.call(this, child, localZOrder, tag); 1427 this._hasChildren = true; 1428 }, 1429 1430 _addChildForCanvas: function (child, localZOrder, tag) { 1431 if(!child) 1432 throw "cc.Sprite.addChild(): child should be non-null"; 1433 if (localZOrder == null) 1434 localZOrder = child._localZOrder; 1435 if (tag == null) 1436 tag = child.tag; 1437 1438 //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check 1439 cc.NodeRGBA.prototype.addChild.call(this, child, localZOrder, tag); 1440 this._hasChildren = true; 1441 }, 1442 1443 /** 1444 * Update sprite's color 1445 */ 1446 updateColor:function () { 1447 var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity; 1448 var color4 = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: locDisplayedOpacity}; 1449 // special opacity for premultiplied textures 1450 if (this._opacityModifyRGB) { 1451 color4.r *= locDisplayedOpacity / 255.0; 1452 color4.g *= locDisplayedOpacity / 255.0; 1453 color4.b *= locDisplayedOpacity / 255.0; 1454 } 1455 var locQuad = this._quad; 1456 locQuad.bl.colors = color4; 1457 locQuad.br.colors = color4; 1458 locQuad.tl.colors = color4; 1459 locQuad.tr.colors = color4; 1460 1461 // renders using Sprite Manager 1462 if (this._batchNode) { 1463 if (this.atlasIndex != cc.SPRITE_INDEX_NOT_INITIALIZED) { 1464 this.textureAtlas.updateQuad(locQuad, this.atlasIndex) 1465 } else { 1466 // no need to set it recursively 1467 // update dirty_, don't update recursiveDirty_ 1468 this.dirty = true; 1469 } 1470 } 1471 // self render 1472 // do nothing 1473 this._quadDirty = true; 1474 }, 1475 1476 /** 1477 * Opacity setter 1478 * @function 1479 * @param {Number} opacity 1480 */ 1481 setOpacity:null, 1482 1483 _setOpacityForWebGL: function (opacity) { 1484 cc.NodeRGBA.prototype.setOpacity.call(this, opacity); 1485 this.updateColor(); 1486 }, 1487 1488 _setOpacityForCanvas: function (opacity) { 1489 cc.NodeRGBA.prototype.setOpacity.call(this, opacity); 1490 this._setNodeDirtyForCache(); 1491 }, 1492 1493 /** 1494 * Color setter 1495 * @function 1496 * @param {cc.Color} color3 1497 */ 1498 setColor: null, 1499 1500 _setColorForWebGL: function (color3) { 1501 cc.NodeRGBA.prototype.setColor.call(this, color3); 1502 this.updateColor(); 1503 }, 1504 1505 _setColorForCanvas: function (color3) { 1506 var curColor = this.color; 1507 if ((curColor.r === color3.r) && (curColor.g === color3.g) && (curColor.b === color3.b) && (curColor.a === color3.a)) 1508 return; 1509 1510 cc.NodeRGBA.prototype.setColor.call(this, color3); 1511 this._changeTextureColor(); 1512 this._setNodeDirtyForCache(); 1513 }, 1514 1515 updateDisplayedColor: null, 1516 1517 _updateDisplayedColorForWebGL: function (parentColor) { 1518 cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor); 1519 this.updateColor(); 1520 }, 1521 1522 _updateDisplayedColorForCanvas: function (parentColor) { 1523 var oldColor = this.color; 1524 cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor); 1525 var newColor = this._displayedColor; 1526 if ((oldColor.r === newColor.r) && (oldColor.g === newColor.g) && (oldColor.b === newColor.b)) 1527 return; 1528 this._changeTextureColor(); 1529 this._setNodeDirtyForCache(); 1530 }, 1531 1532 // Frames 1533 /** 1534 * Sets a new spriteFrame to the cc.Sprite. 1535 * @function 1536 * @param {cc.SpriteFrame|String} newFrame 1537 * @deprecated 1538 */ 1539 setSpriteFrame: null, 1540 1541 _setSpriteFrameForWebGL: function (newFrame) { 1542 if(typeof(newFrame) == "string"){ 1543 newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame); 1544 if(!newFrame) 1545 throw "Invalid spriteFrameName"; 1546 } 1547 1548 this.setNodeDirty(true); 1549 var frameOffset = newFrame.getOffset(); 1550 this._unflippedOffsetPositionFromCenter.x = frameOffset.x; 1551 this._unflippedOffsetPositionFromCenter.y = frameOffset.y; 1552 1553 var pNewTexture = newFrame.getTexture(); 1554 var locTextureLoaded = newFrame.textureLoaded(); 1555 if (!locTextureLoaded) { 1556 this._textureLoaded = false; 1557 newFrame.addLoadedEventListener(function (sender) { 1558 this._textureLoaded = true; 1559 var locNewTexture = sender.getTexture(); 1560 if (locNewTexture != this._texture) 1561 this.texture = locNewTexture; 1562 this.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize()); 1563 1564 this._callLoadedEventCallbacks(); 1565 }, this); 1566 } 1567 // update texture before updating texture rect 1568 if (pNewTexture != this._texture) 1569 this.texture = pNewTexture; 1570 1571 // update rect 1572 this._rectRotated = newFrame.isRotated(); 1573 this.setTextureRect(newFrame.getRect(), this._rectRotated, newFrame.getOriginalSize()); 1574 }, 1575 1576 _setSpriteFrameForCanvas: function (newFrame) { 1577 if(typeof(newFrame) == "string"){ 1578 newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame); 1579 if(!newFrame) 1580 throw "Invalid spriteFrameName"; 1581 } 1582 1583 this.setNodeDirty(true); 1584 1585 var frameOffset = newFrame.getOffset(); 1586 this._unflippedOffsetPositionFromCenter.x = frameOffset.x; 1587 this._unflippedOffsetPositionFromCenter.y = frameOffset.y; 1588 1589 // update rect 1590 this._rectRotated = newFrame.isRotated(); 1591 1592 var pNewTexture = newFrame.getTexture(); 1593 var locTextureLoaded = newFrame.textureLoaded(); 1594 if (!locTextureLoaded) { 1595 this._textureLoaded = false; 1596 newFrame.addLoadedEventListener(function (sender) { 1597 this._textureLoaded = true; 1598 var locNewTexture = sender.getTexture(); 1599 if (locNewTexture != this._texture) 1600 this.texture = locNewTexture; 1601 this.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize()); 1602 this._callLoadedEventCallbacks(); 1603 }, this); 1604 } 1605 // update texture before updating texture rect 1606 if (pNewTexture != this._texture) 1607 this.texture = pNewTexture; 1608 1609 if (this._rectRotated) 1610 this._originalTexture = pNewTexture; 1611 1612 this.setTextureRect(newFrame.getRect(), this._rectRotated, newFrame.getOriginalSize()); 1613 this._colorized = false; 1614 if (locTextureLoaded) { 1615 var curColor = this.color; 1616 if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255) 1617 this._changeTextureColor(); 1618 } 1619 }, 1620 1621 /** 1622 * Sets a new display frame to the cc.Sprite. 1623 * @param {cc.SpriteFrame|String} newFrame 1624 * @deprecated 1625 */ 1626 setDisplayFrame: function(newFrame){ 1627 cc.log("setDisplayFrame is deprecated, please use setSpriteFrame instead."); 1628 this.setSpriteFrame(newFrame); 1629 }, 1630 1631 /** 1632 * Returns whether or not a cc.SpriteFrame is being displayed 1633 * @function 1634 * @param {cc.SpriteFrame} frame 1635 * @return {Boolean} 1636 */ 1637 isFrameDisplayed: null, 1638 1639 _isFrameDisplayedForWebGL: function (frame) { 1640 return (cc.rectEqualToRect(frame.getRect(), this._rect) && frame.getTexture().getName() == this._texture.getName() 1641 && cc.pointEqualToPoint(frame.getOffset(), this._unflippedOffsetPositionFromCenter)); 1642 }, 1643 1644 _isFrameDisplayedForCanvas: function (frame) { 1645 if (frame.getTexture() != this._texture) 1646 return false; 1647 return cc.rectEqualToRect(frame.getRect(), this._rect); 1648 }, 1649 1650 /** 1651 * Returns the current displayed frame. 1652 * @return {cc.SpriteFrame} 1653 */ 1654 displayFrame: function () { 1655 return cc.SpriteFrame.create(this._texture, 1656 cc.RECT_POINTS_TO_PIXELS(this._rect), 1657 this._rectRotated, 1658 cc.POINT_POINTS_TO_PIXELS(this._unflippedOffsetPositionFromCenter), 1659 cc.SIZE_POINTS_TO_PIXELS(this._contentSize)); 1660 }, 1661 1662 /** 1663 * Sets the batch node to sprite 1664 * @function 1665 * @param {cc.SpriteBatchNode|null} spriteBatchNode 1666 * @example 1667 * var batch = cc.SpriteBatchNode.create("Images/grossini_dance_atlas.png", 15); 1668 * var sprite = cc.Sprite.create(batch.texture, cc.rect(0, 0, 57, 57)); 1669 * batch.addChild(sprite); 1670 * layer.addChild(batch); 1671 */ 1672 setBatchNode:null, 1673 1674 _setBatchNodeForWebGL:function (spriteBatchNode) { 1675 this._batchNode = spriteBatchNode; // weak reference 1676 1677 // self render 1678 if (!this._batchNode) { 1679 this.atlasIndex = cc.SPRITE_INDEX_NOT_INITIALIZED; 1680 this.textureAtlas = null; 1681 this._recursiveDirty = false; 1682 this.dirty = false; 1683 1684 var x1 = this._offsetPosition.x; 1685 var y1 = this._offsetPosition.y; 1686 var x2 = x1 + this._rect.width; 1687 var y2 = y1 + this._rect.height; 1688 var locQuad = this._quad; 1689 locQuad.bl.vertices = {x:x1, y:y1, z:0}; 1690 locQuad.br.vertices = {x:x2, y:y1, z:0}; 1691 locQuad.tl.vertices = {x:x1, y:y2, z:0}; 1692 locQuad.tr.vertices = {x:x2, y:y2, z:0}; 1693 1694 this._quadDirty = true; 1695 } else { 1696 // using batch 1697 this._transformToBatch = cc.AffineTransformIdentity(); 1698 this.textureAtlas = this._batchNode.textureAtlas; // weak ref 1699 } 1700 }, 1701 1702 _setBatchNodeForCanvas:function (spriteBatchNode) { 1703 this._batchNode = spriteBatchNode; // weak reference 1704 1705 // self render 1706 if (!this._batchNode) { 1707 this.atlasIndex = cc.SPRITE_INDEX_NOT_INITIALIZED; 1708 this.textureAtlas = null; 1709 this._recursiveDirty = false; 1710 this.dirty = false; 1711 } else { 1712 // using batch 1713 this._transformToBatch = cc.AffineTransformIdentity(); 1714 this.textureAtlas = this._batchNode.textureAtlas; // weak ref 1715 } 1716 }, 1717 1718 // CCTextureProtocol 1719 /** 1720 * Texture of sprite setter 1721 * @function 1722 * @param {cc.Texture2D|String} texture 1723 */ 1724 setTexture: null, 1725 1726 _setTextureForWebGL: function (texture) { 1727 if(texture && (typeof(texture) === "string")){ 1728 texture = cc.textureCache.addImage(texture); 1729 this._setTextureForWebGL(texture); 1730 1731 //TODO 1732 var size = texture.getContentSize(); 1733 this.setTextureRect(cc.rect(0,0, size.width, size.height)); 1734 return; 1735 } 1736 // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet 1737 if(texture && !(texture instanceof cc.Texture2D)) 1738 throw "Invalid argument: cc.Sprite.texture setter expects a CCTexture2D."; 1739 1740 // If batchnode, then texture id should be the same 1741 if(this._batchNode && this._batchNode.texture != texture) { 1742 cc.log("cc.Sprite.texture setter: Batched sprites should use the same texture as the batchnode"); 1743 return; 1744 } 1745 1746 if (texture) 1747 this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); 1748 else 1749 this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_COLOR); 1750 1751 if (!this._batchNode && this._texture != texture) { 1752 this._texture = texture; 1753 this._updateBlendFunc(); 1754 } 1755 }, 1756 1757 _setTextureForCanvas: function (texture) { 1758 if(texture && (typeof(texture) === "string")){ 1759 texture = cc.textureCache.addImage(texture); 1760 this._setTextureForCanvas(texture); 1761 1762 //TODO 1763 var size = texture.getContentSize(); 1764 this.setTextureRect(cc.rect(0,0, size.width, size.height)); 1765 return; 1766 } 1767 1768 // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet 1769 if(texture && !(texture instanceof cc.Texture2D)) 1770 throw "Invalid argument: cc.Sprite texture setter expects a CCTexture2D."; 1771 1772 if (this._texture != texture) { 1773 if (texture && texture.getHtmlElementObj() instanceof HTMLImageElement) { 1774 this._originalTexture = texture; 1775 } 1776 this._texture = texture; 1777 } 1778 }, 1779 1780 // Texture protocol 1781 _updateBlendFunc:function () { 1782 if(this._batchNode){ 1783 cc.log("cc.Sprite._updateBlendFunc(): _updateBlendFunc doesn't work when the sprite is rendered using a cc.CCSpriteBatchNode"); 1784 return; 1785 } 1786 1787 // it's possible to have an untextured sprite 1788 if (!this._texture || !this._texture.hasPremultipliedAlpha()) { 1789 this._blendFunc.src = cc.SRC_ALPHA; 1790 this._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; 1791 this.opacityModifyRGB = false; 1792 } else { 1793 this._blendFunc.src = cc.BLEND_SRC; 1794 this._blendFunc.dst = cc.BLEND_DST; 1795 this.opacityModifyRGB = true; 1796 } 1797 }, 1798 1799 _changeTextureColor: function () { 1800 var locElement, locTexture = this._texture, locRect = this._textureRect_Canvas; //this.getTextureRect(); 1801 if (locTexture && locRect.validRect && this._originalTexture) { 1802 locElement = locTexture.getHtmlElementObj(); 1803 if (!locElement) 1804 return; 1805 1806 var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj()); 1807 if (cacheTextureForColor) { 1808 this._colorized = true; 1809 //generate color texture cache 1810 if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor) 1811 cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect, locElement); 1812 else { 1813 locElement = cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect); 1814 locTexture = new cc.Texture2D(); 1815 locTexture.initWithElement(locElement); 1816 locTexture.handleLoadedTexture(); 1817 this.texture = locTexture; 1818 } 1819 } 1820 } 1821 }, 1822 1823 _setTextureCoords:function (rect) { 1824 rect = cc.RECT_POINTS_TO_PIXELS(rect); 1825 1826 var tex = this._batchNode ? this.textureAtlas.texture : this._texture; 1827 if (!tex) 1828 return; 1829 1830 var atlasWidth = tex.pixelsWidth; 1831 var atlasHeight = tex.pixelsHeight; 1832 1833 var left, right, top, bottom, tempSwap, locQuad = this._quad; 1834 if (this._rectRotated) { 1835 if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { 1836 left = (2 * rect.x + 1) / (2 * atlasWidth); 1837 right = left + (rect.height * 2 - 2) / (2 * atlasWidth); 1838 top = (2 * rect.y + 1) / (2 * atlasHeight); 1839 bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight); 1840 } else { 1841 left = rect.x / atlasWidth; 1842 right = (rect.x + rect.height) / atlasWidth; 1843 top = rect.y / atlasHeight; 1844 bottom = (rect.y + rect.width) / atlasHeight; 1845 }// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1846 1847 if (this._flippedX) { 1848 tempSwap = top; 1849 top = bottom; 1850 bottom = tempSwap; 1851 } 1852 1853 if (this._flippedY) { 1854 tempSwap = left; 1855 left = right; 1856 right = tempSwap; 1857 } 1858 1859 locQuad.bl.texCoords.u = left; 1860 locQuad.bl.texCoords.v = top; 1861 locQuad.br.texCoords.u = left; 1862 locQuad.br.texCoords.v = bottom; 1863 locQuad.tl.texCoords.u = right; 1864 locQuad.tl.texCoords.v = top; 1865 locQuad.tr.texCoords.u = right; 1866 locQuad.tr.texCoords.v = bottom; 1867 } else { 1868 if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { 1869 left = (2 * rect.x + 1) / (2 * atlasWidth); 1870 right = left + (rect.width * 2 - 2) / (2 * atlasWidth); 1871 top = (2 * rect.y + 1) / (2 * atlasHeight); 1872 bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight); 1873 } else { 1874 left = rect.x / atlasWidth; 1875 right = (rect.x + rect.width) / atlasWidth; 1876 top = rect.y / atlasHeight; 1877 bottom = (rect.y + rect.height) / atlasHeight; 1878 } // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1879 1880 if (this._flippedX) { 1881 tempSwap = left; 1882 left = right; 1883 right = tempSwap; 1884 } 1885 1886 if (this._flippedY) { 1887 tempSwap = top; 1888 top = bottom; 1889 bottom = tempSwap; 1890 } 1891 1892 locQuad.bl.texCoords.u = left; 1893 locQuad.bl.texCoords.v = bottom; 1894 locQuad.br.texCoords.u = right; 1895 locQuad.br.texCoords.v = bottom; 1896 locQuad.tl.texCoords.u = left; 1897 locQuad.tl.texCoords.v = top; 1898 locQuad.tr.texCoords.u = right; 1899 locQuad.tr.texCoords.v = top; 1900 } 1901 this._quadDirty = true; 1902 }, 1903 /** 1904 * draw sprite to canvas 1905 * @function 1906 */ 1907 draw: null, 1908 1909 _drawForWebGL: function () { 1910 if (!this._textureLoaded) 1911 return; 1912 1913 var gl = cc._renderContext, locTexture = this._texture; 1914 //cc.assert(!this._batchNode, "If cc.Sprite is being rendered by cc.SpriteBatchNode, cc.Sprite#draw SHOULD NOT be called"); 1915 1916 if (locTexture) { 1917 if (locTexture._isLoaded) { 1918 this._shaderProgram.use(); 1919 this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); 1920 1921 cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); 1922 //optimize performance for javascript 1923 cc.glBindTexture2DN(0, locTexture); // = cc.glBindTexture2D(locTexture); 1924 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); 1925 1926 gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer); 1927 if (this._quadDirty) { 1928 gl.bufferData(gl.ARRAY_BUFFER, this._quad.arrayBuffer, gl.DYNAMIC_DRAW); 1929 this._quadDirty = false; 1930 } 1931 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0); //cc.VERTEX_ATTRIB_POSITION 1932 gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 24, 12); //cc.VERTEX_ATTRIB_COLOR 1933 gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 24, 16); //cc.VERTEX_ATTRIB_TEX_COORDS 1934 1935 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 1936 } 1937 } else { 1938 this._shaderProgram.use(); 1939 this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); 1940 1941 cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); 1942 cc.glBindTexture2D(null); 1943 1944 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR); 1945 1946 gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer); 1947 if (this._quadDirty) { 1948 cc._renderContext.bufferData(cc._renderContext.ARRAY_BUFFER, this._quad.arrayBuffer, cc._renderContext.STATIC_DRAW); 1949 this._quadDirty = false; 1950 } 1951 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); 1952 gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); 1953 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 1954 } 1955 cc.g_NumberOfDraws++; 1956 if (cc.SPRITE_DEBUG_DRAW === 0 && !this._showNode) 1957 return; 1958 1959 if (cc.SPRITE_DEBUG_DRAW === 1 || this._showNode) { 1960 // draw bounding box 1961 var locQuad = this._quad; 1962 var verticesG1 = [ 1963 cc.p(locQuad.tl.vertices.x, locQuad.tl.vertices.y), 1964 cc.p(locQuad.bl.vertices.x, locQuad.bl.vertices.y), 1965 cc.p(locQuad.br.vertices.x, locQuad.br.vertices.y), 1966 cc.p(locQuad.tr.vertices.x, locQuad.tr.vertices.y) 1967 ]; 1968 cc._drawingUtil.drawPoly(verticesG1, 4, true); 1969 } else if (cc.SPRITE_DEBUG_DRAW === 2) { 1970 // draw texture box 1971 var drawRectG2 = this.getTextureRect(); 1972 var offsetPixG2 = this.getOffsetPosition(); 1973 var verticesG2 = [cc.p(offsetPixG2.x, offsetPixG2.y), cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y), 1974 cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y + drawRectG2.height), cc.p(offsetPixG2.x, offsetPixG2.y + drawRectG2.height)]; 1975 cc._drawingUtil.drawPoly(verticesG2, 4, true); 1976 } // CC_SPRITE_DEBUG_DRAW 1977 }, 1978 1979 _drawForCanvas: function (ctx) { 1980 if (!this._textureLoaded) 1981 return; 1982 1983 var context = ctx || cc._renderContext; 1984 if (this._isLighterMode) 1985 context.globalCompositeOperation = 'lighter'; 1986 1987 var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY(); 1988 1989 context.globalAlpha = this._displayedOpacity / 255; 1990 var locRect = this._rect, locContentSize = this._contentSize, locOffsetPosition = this._offsetPosition, locDrawSizeCanvas = this._drawSize_Canvas; 1991 var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = this._textureRect_Canvas; 1992 locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX; 1993 locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY; 1994 1995 if (this._flippedX || this._flippedY) { 1996 context.save(); 1997 if (this._flippedX) { 1998 flipXOffset = -locOffsetPosition.x - locRect.width; 1999 context.scale(-1, 1); 2000 } 2001 if (this._flippedY) { 2002 flipYOffset = locOffsetPosition.y; 2003 context.scale(1, -1); 2004 } 2005 } 2006 2007 flipXOffset *= locEGL_ScaleX; 2008 flipYOffset *= locEGL_ScaleY; 2009 2010 if (this._texture && locTextureCoord.validRect) { 2011 var image = this._texture.getHtmlElementObj(); 2012 if (this._colorized) { 2013 context.drawImage(image, 2014 0, 0, locTextureCoord.width, locTextureCoord.height, 2015 flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height); 2016 } else { 2017 context.drawImage(image, 2018 locTextureCoord.x, locTextureCoord.y, locTextureCoord.width, locTextureCoord.height, 2019 flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height); 2020 } 2021 } else if (locContentSize.width !== 0) { 2022 var curColor = this.color; 2023 context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)"; 2024 context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY); 2025 } 2026 2027 if (cc.SPRITE_DEBUG_DRAW === 1 || this._showNode) { 2028 // draw bounding box 2029 context.strokeStyle = "rgba(0,255,0,1)"; 2030 flipXOffset /= locEGL_ScaleX; 2031 flipYOffset /= locEGL_ScaleY; 2032 flipYOffset = -flipYOffset; 2033 var vertices1 = [cc.p(flipXOffset, flipYOffset), 2034 cc.p(flipXOffset + locRect.width, flipYOffset), 2035 cc.p(flipXOffset + locRect.width, flipYOffset - locRect.height), 2036 cc.p(flipXOffset, flipYOffset - locRect.height)]; 2037 cc._drawingUtil.drawPoly(vertices1, 4, true); 2038 } else if (cc.SPRITE_DEBUG_DRAW === 2) { 2039 // draw texture box 2040 context.strokeStyle = "rgba(0,255,0,1)"; 2041 var drawRect = this._rect; 2042 flipYOffset = -flipYOffset; 2043 var vertices2 = [cc.p(flipXOffset, flipYOffset), cc.p(flipXOffset + drawRect.width, flipYOffset), 2044 cc.p(flipXOffset + drawRect.width, flipYOffset - drawRect.height), cc.p(flipXOffset, flipYOffset - drawRect.height)]; 2045 cc._drawingUtil.drawPoly(vertices2, 4, true); 2046 } 2047 if (this._flippedX || this._flippedY) 2048 context.restore(); 2049 cc.g_NumberOfDraws++; 2050 } 2051 }); 2052 2053 window._p = cc.Sprite.prototype; 2054 if (cc._renderType === cc._RENDER_TYPE_WEBGL) { 2055 _p._spriteFrameLoadedCallback = _p._spriteFrameLoadedCallbackForWebGL; 2056 _p.setOpacityModifyRGB = _p._setOpacityModifyRGBForWebGL; 2057 _p.updateDisplayedOpacity = _p._updateDisplayedOpacityForWebGL; 2058 _p.ctor = _p._ctorForWebGL; 2059 _p.setBlendFunc = _p._setBlendFuncForWebGL; 2060 _p.init = _p._initForWebGL; 2061 _p.initWithTexture = _p._initWithTextureForWebGL; 2062 _p._textureLoadedCallback = _p._textureLoadedCallbackForWebGL; 2063 _p.setTextureRect = _p._setTextureRectForWebGL; 2064 _p.updateTransform = _p._updateTransformForWebGL; 2065 _p.addChild = _p._addChildForWebGL; 2066 _p.setOpacity = _p._setOpacityForWebGL; 2067 _p.setColor = _p._setColorForWebGL; 2068 _p.updateDisplayedColor = _p._updateDisplayedColorForWebGL; 2069 _p.setSpriteFrame = _p._setSpriteFrameForWebGL; 2070 _p.isFrameDisplayed = _p._isFrameDisplayedForWebGL; 2071 _p.setBatchNode = _p._setBatchNodeForWebGL; 2072 _p.setTexture = _p._setTextureForWebGL; 2073 _p.draw = _p._drawForWebGL; 2074 }else{ 2075 _p._spriteFrameLoadedCallback = _p._spriteFrameLoadedCallbackForCanvas; 2076 _p.setOpacityModifyRGB = _p._setOpacityModifyRGBForCanvas; 2077 _p.updateDisplayedOpacity = _p._updateDisplayedOpacityForCanvas; 2078 _p.ctor = _p._ctorForCanvas; 2079 _p.setBlendFunc = _p._setBlendFuncForCanvas; 2080 _p.init = _p._initForCanvas; 2081 _p.initWithTexture = _p._initWithTextureForCanvas; 2082 _p._textureLoadedCallback = _p._textureLoadedCallbackForCanvas; 2083 _p.setTextureRect = _p._setTextureRectForCanvas; 2084 _p.updateTransform = _p._updateTransformForCanvas; 2085 _p.addChild = _p._addChildForCanvas; 2086 _p.setOpacity = _p._setOpacityForCanvas; 2087 _p.setColor = _p._setColorForCanvas; 2088 _p.updateDisplayedColor = _p._updateDisplayedColorForCanvas; 2089 _p.setSpriteFrame = _p._setSpriteFrameForCanvas; 2090 _p.isFrameDisplayed = _p._isFrameDisplayedForCanvas; 2091 _p.setBatchNode = _p._setBatchNodeForCanvas; 2092 _p.setTexture = _p._setTextureForCanvas; 2093 _p.draw = _p._drawForCanvas; 2094 } 2095 2096 // Override properties 2097 cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpacityModifyRGB); 2098 cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); 2099 cc.defineGetterSetter(_p, "color", _p.getColor, _p.setColor); 2100 2101 // Extended properties 2102 /** @expose */ 2103 _p.dirty; 2104 /** @expose */ 2105 _p.flippedX; 2106 cc.defineGetterSetter(_p, "flippedX", _p.isFlippedX, _p.setFlippedX); 2107 /** @expose */ 2108 _p.flippedY; 2109 cc.defineGetterSetter(_p, "flippedY", _p.isFlippedY, _p.setFlippedY); 2110 /** @expose */ 2111 _p.offsetX; 2112 cc.defineGetterSetter(_p, "offsetX", _p._getOffsetX); 2113 /** @expose */ 2114 _p.offsetY; 2115 cc.defineGetterSetter(_p, "offsetY", _p._getOffsetY); 2116 /** @expose */ 2117 _p.atlasIndex; 2118 /** @expose */ 2119 _p.texture; 2120 cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); 2121 /** @expose */ 2122 _p.textureRectRotated; 2123 cc.defineGetterSetter(_p, "textureRectRotated", _p.isTextureRectRotated); 2124 /** @expose */ 2125 _p.textureAtlas; 2126 /** @expose */ 2127 _p.batchNode; 2128 cc.defineGetterSetter(_p, "batchNode", _p.getBatchNode, _p.setBatchNode); 2129 /** @expose */ 2130 _p.quad; 2131 cc.defineGetterSetter(_p, "quad", _p.getQuad); 2132 2133 delete window._p; 2134 2135 /** 2136 * Create a sprite with image path or frame name or texture or spriteFrame. 2137 * @constructs 2138 * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName The string which indicates a path to image file, e.g., "scene1/monster.png". 2139 * @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite. 2140 * @return {cc.Sprite} A valid sprite object 2141 * @example 2142 * 2143 * 1.Create a sprite with image path and rect 2144 * var sprite1 = cc.Sprite.create("res/HelloHTML5World.png"); 2145 * var sprite2 = cc.Sprite.create("res/HelloHTML5World.png",cc.rect(0,0,480,320)); 2146 * 2147 * 2.Create a sprite with a sprite frame name. Must add "#" before frame name. 2148 * var sprite = cc.Sprite.create('#grossini_dance_01.png'); 2149 * 2150 * 3.Create a sprite with a sprite frame 2151 * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); 2152 * var sprite = cc.Sprite.create(spriteFrame); 2153 * 2154 * 4.Create a sprite with an exsiting texture contained in a CCTexture2D object 2155 * After creation, the rect will be the size of the texture, and the offset will be (0,0). 2156 * var texture = cc.textureCache.addImage("HelloHTML5World.png"); 2157 * var sprite1 = cc.Sprite.create(texture); 2158 * var sprite2 = cc.Sprite.create(texture, cc.rect(0,0,480,320)); 2159 * 2160 */ 2161 cc.Sprite.create = function (fileName, rect) { 2162 return new cc.Sprite(fileName, rect); 2163 }; 2164