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