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.SpriteBatchode 29 * @constant 30 * @type Number 31 */ 32 cc.SPRITE_INDEX_NOT_INITIALIZED = "0xffffffff"; 33 34 /** 35 * generate texture's cache for texture tint 36 * @function 37 * @param {HTMLImageElement} texture 38 * @return {Array} 39 */ 40 cc.generateTextureCacheForColor = function (texture) { 41 var w = texture.width; 42 var h = texture.height; 43 var textureCache = []; 44 45 var canvas = document.createElement("canvas"); 46 canvas.width = w; 47 canvas.height = h; 48 49 var ctx = canvas.getContext("2d"); 50 ctx.drawImage(texture, 0, 0); 51 52 var tempCanvas = document.createElement("canvas"); 53 tempCanvas.width = w; 54 tempCanvas.height = h; 55 var tempCtx = tempCanvas.getContext('2d'); 56 57 var pixels = ctx.getImageData(0, 0, w, h).data; 58 59 for (var rgbI = 0; rgbI < 3; rgbI++) { 60 var cacheCanvas = document.createElement("canvas"); 61 cacheCanvas.width = w; 62 cacheCanvas.height = h; 63 var cacheCtx = cacheCanvas.getContext('2d'); 64 65 tempCtx.drawImage(texture, 0, 0); 66 var to = tempCtx.getImageData(0, 0, w, h); 67 var toData = to.data; 68 69 for (var i = 0; i < pixels.length; i += 4) { 70 toData[i ] = (rgbI === 0) ? pixels[i ] : 0; 71 toData[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0; 72 toData[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0; 73 toData[i + 3] = pixels[i + 3]; 74 } 75 cacheCtx.putImageData(to, 0, 0); 76 textureCache.push(cacheCanvas); 77 } 78 return textureCache; 79 }; 80 81 cc.generateTintImage2 = function (texture, color, rect) { 82 if (!rect) { 83 rect = cc.rect(0, 0, texture.width, texture.height); 84 } 85 var selColor; 86 if (color instanceof cc.Color4F) { 87 selColor = cc.c4b(color.r * 255, color.g * 255, color.b * 255, color.a * 255); 88 } else { 89 selColor = cc.c4b(color.r, color.g, color.b, 50);//color; 90 } 91 92 var buff = document.createElement("canvas"); 93 var ctx = buff.getContext("2d"); 94 95 if (buff.width != rect.size.width) buff.width = rect.size.width; 96 if (buff.height != rect.size.height) buff.height = rect.size.height; 97 ctx.save(); 98 99 ctx.drawImage(texture, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, 0, 0, rect.size.width, rect.size.height); 100 101 ctx.globalCompositeOperation = "source-in"; 102 ctx.globalAlpha = selColor.a / 255.0; 103 ctx.fillStyle = "rgb(" + selColor.r + "," + selColor.g + "," + selColor.b + ")"; 104 ctx.fillRect(0, 0, rect.size.width, rect.size.height); 105 ctx.restore(); 106 107 return buff; 108 }; 109 110 /** 111 * generate tinted texture 112 * @function 113 * @param {HTMLImageElement} texture 114 * @param {Array} tintedImgCache 115 * @param {cc.Color3B|cc.Color4F} color 116 * @param {cc.Rect} rect 117 * @return {HTMLCanvasElement} 118 */ 119 cc.generateTintImage = function (texture, tintedImgCache, color, rect, renderCanvas) { 120 if (!rect) { 121 rect = cc.rect(0, 0, texture.width, texture.height); 122 } 123 var selColor; 124 if (color instanceof cc.Color4F) { 125 selColor = cc.c3b(color.r * 255, color.g * 255, color.b * 255); 126 } else { 127 selColor = color; 128 } 129 var buff = renderCanvas || document.createElement("canvas"); 130 buff.width = rect.size.width; 131 buff.height = rect.size.height; 132 var ctx = buff.getContext("2d"); 133 134 ctx.globalCompositeOperation = 'lighter'; 135 if (selColor.r > 0) { 136 ctx.globalAlpha = selColor.r / 255.0; 137 ctx.drawImage(tintedImgCache[0], rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, 0, 0, rect.size.width, rect.size.height); 138 } 139 if (selColor.g > 0) { 140 ctx.globalAlpha = selColor.g / 255.0; 141 ctx.drawImage(tintedImgCache[1], rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, 0, 0, rect.size.width, rect.size.height); 142 } 143 if (selColor.b > 0) { 144 ctx.globalAlpha = selColor.b / 255.0; 145 ctx.drawImage(tintedImgCache[2], rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, 0, 0, rect.size.width, rect.size.height); 146 } 147 return buff; 148 }; 149 150 cc.cutRotateImageToCanvas = function (texture, rect) { 151 if (!texture) 152 return null; 153 154 if (!rect) 155 return texture; 156 157 var nCanvas = document.createElement("canvas"); 158 nCanvas.width = rect.size.width; 159 nCanvas.height = rect.size.height; 160 161 var ctx = nCanvas.getContext("2d"); 162 ctx.translate(nCanvas.width / 2, nCanvas.height / 2); 163 ctx.rotate(-1.5707963267948966); 164 ctx.drawImage(texture, rect.origin.x, rect.origin.y, rect.size.height, rect.size.width, -rect.size.height / 2, -rect.size.width / 2, rect.size.height, rect.size.width); 165 return nCanvas; 166 }; 167 168 169 /** 170 * a Values object for transform 171 * @Class 172 * @Construct 173 * @param {cc.Point} pos position x and y 174 * @param {cc.Point} scale scale x and y 175 * @param {Number} rotation 176 * @param {cc.Point} skew skew x and y 177 * @param {cc.Point} ap anchor point in pixels 178 * @param {Boolean} visible 179 */ 180 cc.TransformValues = function (pos, scale, rotation, skew, ap, visible) { 181 this.pos = pos; // position x and y 182 this.scale = scale; // scale x and y 183 this.rotation = rotation; 184 this.skew = skew; // skew x and y 185 this.ap = ap; // anchor point in pixels 186 this.visible = visible; 187 }; 188 189 cc.RENDER_IN_SUBPIXEL = function (A) { 190 if (cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { 191 return A; 192 } else { 193 return parseInt(A); 194 } 195 }; 196 197 /** 198 * <p>cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) ) <br/> 199 * 200 * cc.Sprite can be created with an image, or with a sub-rectangle of an image. <br/> 201 * 202 * If the parent or any of its ancestors is a cc.SpriteBatchNode then the following features/limitations are valid <br/> 203 * - Features when the parent is a cc.BatchNode: <br/> 204 * - MUCH faster rendering, specially if the cc.SpriteBatchNode has many children. All the children will be drawn in a single batch. <br/> 205 * 206 * - Limitations <br/> 207 * - Camera is not supported yet (eg: CCOrbitCamera action doesn't work) <br/> 208 * - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl) <br/> 209 * - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property. <br/> 210 * - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property. <br/> 211 * - Parallax scroller is not supported, but can be simulated with a "proxy" sprite. <br/> 212 * 213 * If the parent is an standard cc.Node, then cc.Sprite behaves like any other cc.Node: <br/> 214 * - It supports blending functions <br/> 215 * - It supports aliasing / antialiasing <br/> 216 * - But the rendering will be slower: 1 draw per children. <br/> 217 * 218 * The default anchorPoint in cc.Sprite is (0.5, 0.5). </p> 219 * @class 220 * @extends cc.Node 221 * 222 * @example 223 * var aSprite = new cc.Sprite(); 224 * aSprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320)); 225 */ 226 cc.Sprite = cc.Node.extend(/** @lends cc.Sprite# */{ 227 RGBAProtocol:true, 228 // 229 // Data used when the sprite is rendered using a CCSpriteSheet 230 // 231 _textureAtlas:null, 232 _atlasIndex:0, 233 _batchNode:null, 234 _dirty:null, // Sprite needs to be updated 235 _recursiveDirty:null, 236 _hasChildren:null, 237 _shouldBeHidden:false, //should not be drawn because one of the ancestors is not visible 238 _transformToBatch:null, 239 240 // 241 // Data used when the sprite is self-rendered 242 // 243 _blendFunc:{src:cc.BLEND_SRC, dst:cc.BLEND_DST}, 244 _texture:null, 245 _originalTexture:null, 246 _color:null, 247 // 248 // Shared data 249 // 250 // texture 251 _rect:cc.rect(0, 0, 0, 0), 252 _rectRotated:null, 253 254 // Offset Position (used by Zwoptex) 255 _offsetPosition:cc.p(0, 0), // absolute 256 _unflippedOffsetPositionFromCenter:cc.PointZero(), 257 258 // vertex coords, texture coords and color info 259 _quad:cc.V3F_C4B_T2F_QuadZero(), 260 261 // opacity and RGB protocol 262 colorUnmodified:null, 263 _opacityModifyRGB:null, 264 265 // image is flipped 266 _flipX:null, 267 _flipY:null, 268 269 _opacity:255, 270 271 /** 272 * Constructor 273 * @param {String|cc.SpriteFrame|cc.SpriteBatchNode|HTMLImageElement|cc.Texture2D} fileName sprite construct parameter 274 */ 275 ctor:function (fileName) { 276 this._super(); 277 this._shouldBeHidden = false; 278 this._offsetPosition = cc.p(0, 0); 279 this._unflippedOffsetPositionFromCenter = cc.p(0, 0); 280 this._color = cc.white(); 281 282 if (fileName) { 283 if (typeof(fileName) == "string") { 284 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(fileName); 285 this.initWithSpriteFrame(frame); 286 } else if (typeof(fileName) == "object") { 287 if (fileName instanceof cc.SpriteFrame) { 288 this.initWithSpriteFrame(fileName); 289 } else if (fileName instanceof cc.SpriteBatchNode) { 290 if (arguments.length > 1) { 291 var rect = arguments[1]; 292 if (rect instanceof cc.Rect) { 293 this.initWithBatchNode(fileName, rect); 294 } 295 } 296 } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) { 297 this.initWithTexture(fileName) 298 } else if (fileName instanceof cc.Texture2D) { 299 this.initWithTexture(fileName) 300 } 301 } 302 } 303 }, 304 305 /** 306 * whether or not the Sprite needs to be updated in the Atlas 307 * @return {Boolean} 308 */ 309 isDirty:function () { 310 return this._dirty; 311 }, 312 313 /** 314 * make the Sprite to be updated in the Atlas. 315 * @param {Boolean} bDirty 316 */ 317 setDirty:function (bDirty) { 318 this._dirty = bDirty; 319 }, 320 321 /** 322 * get the quad (tex coords, vertex coords and color) information 323 * @return {cc.V3F_C4B_T2F_Quad} 324 */ 325 getQuad:function () { 326 return this._quad; 327 }, 328 329 /** 330 * returns whether or not the texture rectangle is rotated 331 * @return {Boolean} 332 */ 333 isTextureRectRotated:function () { 334 return this._rectRotated; 335 }, 336 337 /** 338 * Set the index used on the TextureAtlas. 339 * @return {Number} 340 */ 341 getAtlasIndex:function () { 342 return this._atlasIndex; 343 }, 344 345 /** 346 * Set the index used on the TextureAtlas. 347 * @warning Don't modify this value unless you know what you are doing 348 * @param {Number} atlasIndex 349 */ 350 setAtlasIndex:function (atlasIndex) { 351 this._atlasIndex = atlasIndex; 352 }, 353 354 /** 355 * returns the rect of the cc.Sprite in points 356 * @return {cc.Rect} 357 */ 358 getTextureRect:function () { 359 return cc.rect(this._rect.origin.x, this._rect.origin.y, this._rect.size.width, this._rect.size.height); 360 }, 361 362 /** 363 * return the TextureAtlas of the cc.Sprite 364 * @param {Boolean} pobTextureAtlas 365 * @return {cc.TextureAtlas} 366 */ 367 getTextureAtlas:function (pobTextureAtlas) { 368 return this._textureAtlas; 369 }, 370 371 /** 372 * set the TextureAtlas of the cc.Sprite 373 * @param {cc.TextureAtlas} textureAtlas 374 */ 375 setTextureAtlas:function (textureAtlas) { 376 this._textureAtlas = textureAtlas; 377 }, 378 379 /** 380 * return the SpriteBatchNode of the cc.Sprite 381 * @return {cc.SpriteBatchNode} 382 */ 383 getSpriteBatchNode:function () { 384 return this._batchNode; 385 }, 386 387 /** 388 * set the SpriteBatchNode of the cc.Sprite 389 * @param {cc.SpriteBatchNode} spriteBatchNode 390 */ 391 setSpriteBatchNode:function (spriteBatchNode) { 392 this._batchNode = spriteBatchNode; 393 }, 394 395 /** 396 * Get offset position of the sprite. Calculated automatically by editors like Zwoptex. 397 * @return {cc.Point} 398 */ 399 getOffsetPosition:function () { 400 return cc.p(this._offsetPosition.x, this._offsetPosition.y); 401 }, 402 403 /** 404 * conforms to cc.TextureProtocol protocol 405 * @return {cc.BlendFunc} 406 */ 407 getBlendFunc:function () { 408 return this._blendFunc; 409 }, 410 411 _isLighterMode:false, 412 /** 413 * conforms to cc.TextureProtocol protocol 414 * @param {Number} src 415 * @param {Number} dst 416 */ 417 setBlendFunc:function (src, dst) { 418 if (arguments.length == 1) 419 this._blendFunc = src; 420 else 421 this._blendFunc = {src:src, dst:dst}; 422 423 this._isLighterMode = (this._blendFunc && (this._blendFunc.src == gl.SRC_ALPHA) && (this._blendFunc.dst == gl.ONE)); 424 }, 425 426 /** 427 * Initializes a sprite 428 * @return {Boolean} 429 */ 430 init:function () { 431 this._super(); 432 433 this._dirty = this._recursiveDirty = false; 434 435 this._opacityModifyRGB = true; 436 this._opacity = 255; 437 this._color = cc.white(); 438 this._colorUnmodified = cc.white(); 439 440 this._blendFunc.src = cc.BLEND_SRC; 441 this._blendFunc.dst = cc.BLEND_DST; 442 443 // update texture (calls _updateBlendFunc) 444 this.setTexture(null); 445 446 this._flipX = this._flipY = false; 447 448 // default transform anchor: center 449 this.setAnchorPoint(cc.p(0.5, 0.5)); 450 451 // zwoptex default values 452 this._offsetPosition = cc.PointZero(); 453 this._hasChildren = false; 454 455 // Atlas: Color 456 var tmpColor = new cc.Color4B(255, 255, 255, 255); 457 this._quad.bl.colors = tmpColor; 458 this._quad.br.colors = tmpColor; 459 this._quad.tl.colors = tmpColor; 460 this._quad.tr.colors = tmpColor; 461 462 463 // updated in "useSelfRender" 464 // Atlas: TexCoords 465 this.setTextureRect(cc.RectZero(), false, cc.SizeZero()); 466 467 return true; 468 }, 469 470 /** 471 * Initializes a sprite with a texture and a rect in texture 472 * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture 473 * @param {cc.Rect} rect 474 * @return {Boolean} 475 * @example 476 * var img =cc.TextureCache.getInstance().addImage("HelloHTML5World.png"); 477 * var mySprite = new cc.Sprite(); 478 * mySprite.initWithTexture(img,cc.rect(0,0,480,320)); 479 */ 480 initWithTexture:function (texture, rect, rotated) { 481 var argnum = arguments.length; 482 if (argnum == 0) 483 throw "Sprite.initWithTexture(): Argument must be non-nil "; 484 485 rotated = rotated || false; 486 487 this._batchNode = null; 488 //this.setShaderProgram(CCShaderCache::getInstance()->programForKey(kCCShader_PositionTextureColor)); 489 490 this._recursiveDirty = false; 491 this.setDirty(false); 492 this._opacityModifyRGB = true; 493 this._opacity = 255; 494 this._color = cc.white(); 495 this._colorUnmodified = cc.white(); 496 497 this._blendFunc.src = cc.BLEND_SRC; 498 this._blendFunc.dst = cc.BLEND_DST; 499 500 this._flipX = this._flipY = false; 501 502 // default transform anchor: center 503 this.setAnchorPoint(cc.p(0.5, 0.5)); 504 505 // zwoptex default values 506 this._offsetPosition = cc.p(0, 0); 507 this._hasChildren = false; 508 509 // Atlas: Color 510 var tmpColor = new cc.Color4B(255, 255, 255, 255); 511 this._quad.bl.colors = tmpColor; 512 this._quad.br.colors = tmpColor; 513 this._quad.tl.colors = tmpColor; 514 this._quad.tr.colors = tmpColor; 515 516 if (!rect) { 517 rect = cc.rect(0, 0, 0, 0); 518 if (texture instanceof cc.Texture2D) { 519 rect.size = texture.getContentSize(); 520 } else if ((texture instanceof HTMLImageElement) || (texture instanceof HTMLCanvasElement)) 521 rect.size = cc.size(texture.width, texture.height); 522 } 523 524 if (cc.renderContextType == cc.CANVAS) { 525 this._originalTexture = texture; 526 } 527 528 this.setTexture(texture); 529 this.setTextureRect(rect, rotated, rect.size); 530 531 // by default use "Self Render". 532 // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" 533 this.setBatchNode(null); 534 return true; 535 }, 536 537 /** 538 * Initializes a sprite with a texture's filename and a rect in texture 539 * @param {String} filename 540 * @param {cc.Rect} rect 541 * @return {Boolean} 542 * @example 543 * var mySprite = new cc.Sprite(); 544 * mySprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320)); 545 */ 546 initWithFile:function (filename, rect) { 547 cc.Assert(filename != null, "Sprite#initWithFile():Invalid filename for sprite"); 548 var selfPointer = this; 549 550 var texture = cc.TextureCache.getInstance().textureForKey(filename); 551 if (!texture) { 552 //texture = cc.TextureCache.getInstance().addImage(filename); 553 this._visible = false; 554 var loadImg = new Image(); 555 loadImg.addEventListener("load", function () { 556 if (!rect) { 557 rect = cc.rect(0, 0, loadImg.width, loadImg.height); 558 } 559 selfPointer.initWithTexture(loadImg, rect); 560 cc.TextureCache.getInstance().cacheImage(filename, loadImg); 561 selfPointer._visible = true; 562 }); 563 loadImg.addEventListener("error", function () { 564 cc.log("load failure:" + filename); 565 }); 566 loadImg.src = filename; 567 return true; 568 } else { 569 if (texture) { 570 if (!rect) { 571 rect = cc.rect(0, 0, 0, 0); 572 if (texture instanceof cc.Texture2D) 573 rect.size = texture.getContentSize(); 574 else if ((texture instanceof HTMLImageElement) || (texture instanceof HTMLCanvasElement)) 575 rect.size = cc.size(texture.width, texture.height); 576 } 577 return this.initWithTexture(texture, rect); 578 } 579 } 580 return false; 581 }, 582 583 /** 584 * Initializes a sprite with a sprite frame. 585 * @param {cc.SpriteFrame} spriteFrame 586 * @return {Boolean} 587 * @example 588 * var spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame("grossini_dance_01.png"); 589 * var sprite = new cc.Sprite(); 590 * sprite.initWithSpriteFrame(spriteFrame); 591 */ 592 initWithSpriteFrame:function (spriteFrame) { 593 cc.Assert(spriteFrame != null, ""); 594 var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect()); 595 this.setDisplayFrame(spriteFrame); 596 597 return ret; 598 }, 599 600 /** 601 * Initializes a sprite with a sprite frame name. <br/> 602 * A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name. <br/> 603 * If the cc.SpriteFrame doesn't exist it will raise an exception. <br/> 604 * @param {String} spriteFrameName 605 * @return {Boolean} 606 * @example 607 * var sprite = new cc.Sprite(); 608 * sprite.initWithSpriteFrameName("grossini_dance_01.png"); 609 */ 610 initWithSpriteFrameName:function (spriteFrameName) { 611 cc.Assert(spriteFrameName != null, ""); 612 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName); 613 return this.initWithSpriteFrame(frame); 614 }, 615 616 /** 617 * tell the sprite to use batch node render. 618 * @param {cc.SpriteBatchNode} batchNode 619 */ 620 useBatchNode:function (batchNode) { 621 this._textureAtlas = batchNode.getTextureAtlas(); // weak ref 622 this._batchNode = batchNode; 623 }, 624 625 /** 626 * updates the texture rect of the CCSprite in points. 627 * @param {cc.Rect} rect a rect of texture 628 * @param {Boolean} rotated 629 * @param {cc.Size} untrimmedSize 630 */ 631 setTextureRect:function (rect, rotated, untrimmedSize) { 632 this._rectRotated = rotated || false; 633 untrimmedSize = untrimmedSize || rect.size; 634 635 this.setContentSize(untrimmedSize); 636 this.setVertexRect(rect); 637 this._setTextureCoords(rect); 638 639 var relativeOffset = this._unflippedOffsetPositionFromCenter; 640 641 /* WEBGL Code 642 if (this._flipX) { 643 //relativeOffset.x = -relativeOffset.x; 644 } 645 if (this._flipY) { 646 //relativeOffset.y = -relativeOffset.y; 647 } 648 */ 649 650 this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - this._rect.size.width) / 2; 651 this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - this._rect.size.height) / 2; 652 653 // rendering using batch node 654 if (this._batchNode) { 655 // update dirty_, don't update recursiveDirty_ 656 //this.setDirty(true); 657 this._dirty = true; 658 } else { 659 // self rendering 660 661 // Atlas: Vertex 662 var x1 = 0 + this._offsetPosition.x; 663 var y1 = 0 + this._offsetPosition.y; 664 var x2 = x1 + this._rect.size.width; 665 var y2 = y1 + this._rect.size.height; 666 667 // Don't update Z. 668 this._quad.bl.vertices = cc.vertex3(x1, y1, 0); 669 this._quad.br.vertices = cc.vertex3(x2, y1, 0); 670 this._quad.tl.vertices = cc.vertex3(x1, y2, 0); 671 this._quad.tr.vertices = cc.vertex3(x2, y2, 0); 672 } 673 }, 674 675 /** 676 * <p> 677 * set the vertex rect.<br/> 678 * It will be called internally by setTextureRect. Useful if you want to create 2x images from SD images in Retina Display. <br/> 679 * Do not call it manually. Use setTextureRect instead. <br/> 680 * (override this method to generate "double scale" sprites) 681 * </p> 682 * @param rect 683 */ 684 setVertexRect:function (rect) { 685 this._rect = rect; 686 }, 687 688 _setTextureCoords:function (rect) { 689 if (cc.renderContextType == cc.WEBGL) { 690 rect = cc.RECT_POINTS_TO_PIXELS(rect); 691 692 var tex = this._batchNode ? this._textureAtlas.getTexture() : this._texture; 693 if (!tex) { 694 return; 695 } 696 697 var atlasWidth = tex.getPixelsWide(); 698 var atlasHeight = tex.getPixelsHigh(); 699 700 var left, right, top, bottom; 701 702 if (this._rectRotated) { 703 if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { 704 left = (2 * rect.origin.x + 1) / (2 * atlasWidth); 705 right = left + (rect.size.height * 2 - 2) / (2 * atlasWidth); 706 top = (2 * rect.origin.y + 1) / (2 * atlasHeight); 707 bottom = top + (rect.size.width * 2 - 2) / (2 * atlasHeight); 708 } else { 709 left = rect.origin.x / atlasWidth; 710 right = (rect.origin.x + rect.size.height) / atlasWidth; 711 top = rect.origin.y / atlasHeight; 712 bottom = (rect.origin.y + rect.size.width) / atlasHeight; 713 }// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 714 715 716 if (this._flipX) { 717 cc.SWAP(top, bottom); 718 } 719 720 if (this._flipY) { 721 cc.SWAP(left, right); 722 } 723 724 this._quad.bl.texCoords.u = left; 725 this._quad.bl.texCoords.v = top; 726 this._quad.br.texCoords.u = left; 727 this._quad.br.texCoords.v = bottom; 728 this._quad.tl.texCoords.u = right; 729 this._quad.tl.texCoords.v = top; 730 this._quad.tr.texCoords.u = right; 731 this._quad.tr.texCoords.v = bottom; 732 } else { 733 if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { 734 left = (2 * rect.origin.x + 1) / (2 * atlasWidth); 735 right = left + (rect.size.width * 2 - 2) / (2 * atlasWidth); 736 top = (2 * rect.origin.y + 1) / (2 * atlasHeight); 737 bottom = top + (rect.size.height * 2 - 2) / (2 * atlasHeight); 738 } 739 else { 740 left = rect.origin.x / atlasWidth; 741 right = (rect.origin.x + rect.size.width) / atlasWidth; 742 top = rect.origin.y / atlasHeight; 743 bottom = (rect.origin.y + rect.size.height) / atlasHeight; 744 } // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 745 746 if (this._flipX) { 747 cc.SWAP(left, right); 748 } 749 750 if (this._flipY) { 751 cc.SWAP(top, bottom); 752 } 753 754 this._quad.bl.texCoords.u = left; 755 this._quad.bl.texCoords.v = bottom; 756 this._quad.br.texCoords.u = right; 757 this._quad.br.texCoords.v = bottom; 758 this._quad.tl.texCoords.u = left; 759 this._quad.tl.texCoords.v = top; 760 this._quad.tr.texCoords.u = right; 761 this._quad.tr.texCoords.v = top; 762 } 763 } 764 }, 765 766 // BatchNode methods 767 /** 768 * updates the quad according the the rotation, position, scale values. 769 */ 770 updateTransform:function () { 771 cc.Assert(this._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode"); 772 773 // recaculate matrix only if it is dirty 774 if (this.isDirty()) { 775 776 // If it is not visible, or one of its ancestors is not visible, then do nothing: 777 if (!this._visible || ( this._parent && this._parent != this._batchNode && this._parent._shouldBeHidden)) { 778 this._quad.br.vertices = this._quad.tl.vertices = this._quad.tr.vertices = this._quad.bl.vertices = cc.vertex3(0, 0, 0); 779 this._shouldBeHidden = true; 780 } else { 781 this._shouldBeHidden = false; 782 783 if (!this._parent || this._parent == this._batchNode) { 784 this._transformToBatch = this.nodeToParentTransform(); 785 } else { 786 cc.Assert(this._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite"); 787 this._transformToBatch = cc.AffineTransformConcat(this.nodeToParentTransform(), this._parent._transformToBatch); 788 } 789 790 // 791 // calculate the Quad based on the Affine Matrix 792 // 793 var size = this._rect.size; 794 795 var x1 = this._offsetPosition.x; 796 var y1 = this._offsetPosition.y; 797 798 var x2 = x1 + size.width; 799 var y2 = y1 + size.height; 800 var x = this._transformToBatch.tx; 801 var y = this._transformToBatch.ty; 802 803 var cr = this._transformToBatch.a; 804 var sr = this._transformToBatch.b; 805 var cr2 = this._transformToBatch.d; 806 var sr2 = -this._transformToBatch.c; 807 var ax = x1 * cr - y1 * sr2 + x; 808 var ay = x1 * sr + y1 * cr2 + y; 809 810 var bx = x2 * cr - y1 * sr2 + x; 811 var by = x2 * sr + y1 * cr2 + y; 812 813 var cx = x2 * cr - y2 * sr2 + x; 814 var cy = x2 * sr + y2 * cr2 + y; 815 816 var dx = x1 * cr - y2 * sr2 + x; 817 var dy = x1 * sr + y2 * cr2 + y; 818 819 this._quad.bl.vertices = cc.vertex3(cc.RENDER_IN_SUBPIXEL(ax), cc.RENDER_IN_SUBPIXEL(ay), this._vertexZ); 820 this._quad.br.vertices = cc.vertex3(cc.RENDER_IN_SUBPIXEL(bx), cc.RENDER_IN_SUBPIXEL(by), this._vertexZ); 821 this._quad.tl.vertices = cc.vertex3(cc.RENDER_IN_SUBPIXEL(dx), cc.RENDER_IN_SUBPIXEL(dy), this._vertexZ); 822 this._quad.tr.vertices = cc.vertex3(cc.RENDER_IN_SUBPIXEL(cx), cc.RENDER_IN_SUBPIXEL(cy), this._vertexZ); 823 } 824 825 this._textureAtlas.updateQuad(this._quad, this._atlasIndex); 826 this._recursiveDirty = false; 827 this.setDirty(false); 828 } 829 830 // recursively iterate over children 831 if (this._hasChildren) { 832 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform); 833 } 834 835 if (cc.SPRITE_DEBUG_DRAW) { 836 // draw bounding box 837 var vertices = [ 838 cc.p(this._quad.bl.vertices.x, this._quad.bl.vertices.y), 839 cc.p(this._quad.br.vertices.x, this._quad.br.vertices.y), 840 cc.p(this._quad.tr.vertices.x, this._quad.tr.vertices.y), 841 cc.p(this._quad.tl.vertices.x, this._quad.tl.vertices.y) 842 ]; 843 cc.drawingUtil.drawPoly(vertices, 4, true); 844 } 845 }, 846 847 /** 848 * <p>Optimization: instead of calling 5 times the parent sprite to obtain: position, scale.x, scale.y, anchorpoint and rotation,<br/> 849 * this fuction return the 5 values in 1 single call <p/> 850 * @param {cc.TransformValues} tv 851 * @return {cc.TransformValues} 852 * @private 853 */ 854 //TODO 855 _getTransformValues:function (tv) { 856 tv.pos = this._position; 857 tv.scale.x = this._scaleX; 858 tv.scale.y = this._scaleY; 859 tv.rotation = this._rotation; 860 tv.skew.x = this._skewX; 861 tv.skew.y = this._skewY; 862 tv.ap = this._anchorPointInPoints; 863 tv.visible = this._visible; 864 return tv; 865 }, 866 867 /** 868 * draw sprite to canvas 869 * @param {CanvasContext} ctx 2d context of canvas 870 */ 871 draw:function (ctx) { 872 //draw for canvas 873 //cc.PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "cc.Sprite - draw"); 874 var context = ctx || cc.renderContext; 875 876 if (this._isLighterMode) 877 context.globalCompositeOperation = 'lighter'; 878 879 context.globalAlpha = this._opacity / 255; 880 var mpX = 0, mpY = 0; 881 if (this._flipX) { 882 mpX = 0 | (this._contentSize.width / 2 - this._anchorPointInPoints.x); 883 context.translate(mpX, 0); 884 context.scale(-1, 1); 885 } 886 if (this._flipY) { 887 mpY = -(0 | (this._contentSize.height / 2 - this._anchorPointInPoints.y)); 888 context.translate(0, mpY); 889 context.scale(1, -1); 890 } 891 892 var posX = 0 | ( -this._anchorPointInPoints.x - mpX + this._offsetPosition.x); 893 var posY = 0 | ( -this._anchorPointInPoints.y + mpY + this._offsetPosition.y); 894 895 if (this._texture) { 896 if (this._texture instanceof HTMLImageElement) { 897 if ((this._contentSize.width == 0) && (this._contentSize.height == 0)) { 898 this.setContentSize(cc.size(this._texture.width, this._texture.height)); 899 this._rect.size.width = this._texture.width; 900 this._rect.size.height = this._texture.height; 901 context.drawImage(this._texture, posX, -(posY + this._texture.height)); 902 } else { 903 context.drawImage(this._texture, 904 this._rect.origin.x, this._rect.origin.y, 905 this._rect.size.width, this._rect.size.height, 906 posX, -(posY + this._rect.size.height), 907 this._rect.size.width, this._rect.size.height); 908 } 909 } else { 910 if ((this._contentSize.width == 0) && (this._contentSize.height == 0)) { 911 this.setContentSize(cc.size(this._texture.width, this._texture.height)); 912 this._rect.size.width = this._texture.width; 913 this._rect.size.height = this._texture.height; 914 context.drawImage(this._texture, posX, -(posY + this._texture.height)); 915 } else { 916 context.drawImage(this._texture, 917 0, 0, 918 this._rect.size.width, this._rect.size.height, 919 posX, -(posY + this._rect.size.height), 920 this._rect.size.width, this._rect.size.height); 921 } 922 } 923 } else { 924 context.fillStyle = "rgba(" + this._color.r + "," + this._color.g + "," + this._color.b + ",1)"; 925 context.fillRect(posX, posY, this._contentSize.width, this._contentSize.height); 926 } 927 928 if (cc.SPRITE_DEBUG_DRAW == 1) { 929 // draw bounding box 930 context.strokeStyle = "rgba(0,255,0,1)"; 931 var vertices1 = [cc.p(posX, posY), cc.p(posX + this._rect.size.width, posY), cc.p(posX + this._rect.size.width, posY + this._rect.size.height), 932 cc.p(posX, posY + this._rect.size.height)]; 933 cc.drawingUtil.drawPoly(vertices1, 4, true); 934 } else if (cc.SPRITE_DEBUG_DRAW == 2) { 935 // draw texture box 936 context.strokeStyle = "rgba(0,255,0,1)"; 937 var drawSize = this._rect.size; 938 var offsetPix = this.getOffsetPosition(); 939 var vertices2 = [cc.p(offsetPix.x, offsetPix.y), cc.p(offsetPix.x + drawSize.width, offsetPix.y), 940 cc.p(offsetPix.x + drawSize.width, offsetPix.y + drawSize.height), cc.p(offsetPix.x, offsetPix.y + drawSize.height)]; 941 cc.drawingUtil.drawPoly(vertices2, 4, true); 942 } 943 944 //cc.INCREMENT_GL_DRAWS(1); 945 cc.g_NumberOfDraws++; 946 947 //CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); 948 }, 949 950 _drawForWebGL:function (ctx) { 951 var context = ctx; 952 //cc.PROFILER_START_CATEGORY(kCCProfilerCategorySprite, "cc.Sprite - draw"); 953 //TODO WebGL Draw of sprite 954 cc.Assert(!this._batchNode, "If cc.Sprite is being rendered by cc.SpriteBatchNode, cc.Sprite#draw SHOULD NOT be called"); 955 956 cc.NODE_DRAW_SETUP(this); 957 958 //ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst ); 959 960 if (this._texture) { 961 //ccGLBindTexture2D(this._texture.getName()); 962 } else { 963 //ccGLBindTexture2D(0); 964 } 965 966 // 967 // Attributes 968 // 969 //ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex ); 970 971 //#define kQuadSize sizeof(this._quad.bl) 972 var offset = this._quad; 973 974 // vertex 975 //int diff = offsetof( ccV3F_C4B_T2F, vertices); 976 //glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff)); 977 978 // texCoods 979 //diff = offsetof( ccV3F_C4B_T2F, texCoords); 980 //glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff)); 981 982 // color 983 //diff = offsetof( ccV3F_C4B_T2F, colors); 984 //glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff)); 985 986 //glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 987 988 //CHECK_GL_ERROR_DEBUG(); 989 990 if (cc.SPRITE_DEBUG_DRAW == 1) { 991 // draw bounding box 992 var verticesG1 = [ 993 cc.p(this._quad.tl.vertices.x, this._quad.tl.vertices.y), 994 cc.p(this._quad.bl.vertices.x, this._quad.bl.vertices.y), 995 cc.p(this._quad.br.vertices.x, this._quad.br.vertices.y), 996 cc.p(this._quad.tr.vertices.x, this._quad.tr.vertices.y) 997 ]; 998 cc.drawingUtil.drawPoly(verticesG1, 4, true); 999 } 1000 else if (cc.SPRITE_DEBUG_DRAW == 2) { 1001 // draw texture box 1002 var drawSizeG2 = this.getTextureRect().size; 1003 var offsetPixG2 = this.getOffsetPosition(); 1004 var verticesG2 = [cc.p(offsetPixG2.x, offsetPixG2.y), cc.p(offsetPixG2.x + drawSizeG2.width, offsetPixG2.y), 1005 cc.p(offsetPixG2.x + drawSizeG2.width, offsetPixG2.y + drawSizeG2.height), cc.p(offsetPixG2.x, offsetPixG2.y + drawSizeG2.height)]; 1006 cc.drawingUtil.drawPoly(verticesG2, 4, true); 1007 } // CC_SPRITE_DEBUG_DRAW 1008 1009 cc.g_NumberOfDraws++; 1010 //CC_PROFILER_STOP_CATEGORY(kCCProfilerCategorySprite, "CCSprite - draw"); 1011 }, 1012 1013 /** 1014 * Add child to sprite (override cc.Node ) 1015 * @param {cc.Sprite} child 1016 * @param {Number} zOrder child's zOrder 1017 * @param {String} tag child's tag 1018 * @override 1019 */ 1020 addChild:function (child, zOrder, tag) { 1021 var argnum = arguments.length; 1022 switch (argnum) { 1023 case 1: 1024 this._super(child); 1025 break; 1026 case 2: 1027 this._super(child, zOrder); 1028 break; 1029 case 3: 1030 cc.Assert(child != null, "Argument must be non-NULL"); 1031 if (cc.renderContextType == cc.WEBGL) { 1032 //TODO 1033 if (this._batchNode) { 1034 cc.Assert((child instanceof cc.Sprite), "cc.Sprite only supports cc.Sprites as children when using cc.SpriteBatchNode"); 1035 cc.Assert(child.getTexture().getName() == this._textureAtlas.getTexture().getName(), ""); 1036 1037 //put it in descendants array of batch node 1038 this._batchNode.appendChild(child); 1039 if (!this._reorderChildDirty) { 1040 this._setReorderChildDirtyRecursively(); 1041 } 1042 } 1043 } 1044 1045 //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check 1046 this._super(child, zOrder, tag); 1047 this._hasChildren = true; 1048 break; 1049 default: 1050 throw "Sprite.addChild():Argument must be non-nil "; 1051 break; 1052 } 1053 }, 1054 1055 sortAllChildren:function () { 1056 if (this._reorderChildDirty) { 1057 var j; 1058 var tempItem = null; 1059 for (var i = 1; i < this._children.length; i++) { 1060 tempItem = this._children[i]; 1061 j = i - 1; 1062 1063 //continue moving element downwards while zOrder is smaller or when zOrder is the same but orderOfArrival is smaller 1064 while (j >= 0 && ( tempItem.getZOrder() < this._children[j].getZOrder() || ( tempItem.getZOrder() == this._children[j].getZOrder() 1065 && tempItem.getOrderOfArrival() < this._children[j].getOrderOfArrival() ) )) { 1066 this._children[j + 1] = this._children[j]; 1067 j = j - 1; 1068 } 1069 1070 this._children[j + 1] = tempItem; 1071 } 1072 1073 if (this._batchNode) { 1074 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.sortAllChildren); 1075 } 1076 this._reorderChildDirty = false; 1077 } 1078 }, 1079 1080 /** 1081 * Reorders a child according to a new z value. (override cc.Node ) 1082 * @param {cc.Node} child 1083 * @param {Number} zOrder 1084 * @override 1085 */ 1086 reorderChild:function (child, zOrder) { 1087 cc.Assert(child != null, "child is null"); 1088 cc.Assert(this._children.indexOf(child) > -1, "this child is not in children list"); 1089 1090 if (zOrder == child.getZOrder()) { 1091 return; 1092 } 1093 1094 if (this._batchNode && this._reorderChildDirty) { 1095 this._setReorderChildDirtyRecursively(); 1096 this._batchNode.reorderBatch(true); 1097 } 1098 1099 this._super(child, zOrder); 1100 }, 1101 1102 /** 1103 * Removes a child from the sprite. (override cc.Node ) 1104 * @param child 1105 * @param cleanup whether or not cleanup all running actions 1106 * @override 1107 */ 1108 removeChild:function (child, cleanup) { 1109 if (this._batchNode) { 1110 this._batchNode.removeSpriteFromAtlas(child); 1111 } 1112 this._super(child, cleanup); 1113 }, 1114 1115 /** 1116 * Removes all children from the container (override cc.Node ) 1117 * @param cleanup whether or not cleanup all running actions 1118 * @override 1119 */ 1120 removeAllChildren:function (cleanup) { 1121 if (this._batchNode) { 1122 if (this._children != null) { 1123 for (var i = 0; i < this._children.length; i++) { 1124 if (this._children[i] instanceof cc.Sprite) { 1125 this._batchNode.removeSpriteFromAtlas(this._children[i]); 1126 } 1127 } 1128 } 1129 } 1130 1131 this._super(cleanup); 1132 this._hasChildren = false; 1133 }, 1134 // 1135 // CCNode property overloads 1136 // 1137 1138 /** 1139 * set Recursively is or isn't Dirty 1140 * used only when parent is CCSpriteBatchNode 1141 * @param {Boolean} value 1142 */ 1143 setDirtyRecursively:function (value) { 1144 this._recursiveDirty = value; 1145 this.setDirty(value); 1146 // recursively set dirty 1147 if (this._children != null) { 1148 for (var i = 0; i < this._children.length; i++) { 1149 if (this._children[i] instanceof cc.Sprite) { 1150 this._children[i].setDirtyRecursively(true); 1151 } 1152 } 1153 } 1154 }, 1155 1156 /** 1157 * HACK: optimization 1158 */ 1159 SET_DIRTY_RECURSIVELY:function () { 1160 if (this._batchNode && !this._recursiveDirty) { 1161 this._recursiveDirty = true; 1162 //this.setDirty(true); 1163 this._dirty = true; 1164 if (this._hasChildren) 1165 this.setDirtyRecursively(true); 1166 } 1167 }, 1168 1169 /** 1170 * position setter (override cc.Node ) 1171 * @param {cc.Point} pos 1172 * @override 1173 */ 1174 setPosition:function (pos) { 1175 if (arguments.length >= 2) 1176 cc.Node.prototype.setPosition.call(this, pos, arguments[1]); 1177 else 1178 cc.Node.prototype.setPosition.call(this, pos); 1179 this.SET_DIRTY_RECURSIVELY(); 1180 }, 1181 1182 /** 1183 * Rotation setter (override cc.Node ) 1184 * @param {Number} rotation 1185 * @override 1186 */ 1187 setRotation:function (rotation) { 1188 cc.Node.prototype.setRotation.call(this, rotation); 1189 this.SET_DIRTY_RECURSIVELY(); 1190 }, 1191 1192 /** 1193 * SkewX setter (override cc.Node ) 1194 * @param {Number} sx SkewX value 1195 * @override 1196 */ 1197 setSkewX:function (sx) { 1198 cc.Node.prototype.setSkewX.call(this, sx); 1199 this.SET_DIRTY_RECURSIVELY(); 1200 }, 1201 1202 /** 1203 * SkewY setter (override cc.Node ) 1204 * @param {Number} sy SkewY value 1205 * @override 1206 */ 1207 setSkewY:function (sy) { 1208 cc.Node.prototype.setSkewY.call(this, sy); 1209 this.SET_DIRTY_RECURSIVELY(); 1210 }, 1211 1212 /** 1213 * ScaleX setter (override cc.Node ) 1214 * @param {Number} scaleX 1215 * @override 1216 */ 1217 setScaleX:function (scaleX) { 1218 cc.Node.prototype.setScaleX.call(this, scaleX); 1219 this.SET_DIRTY_RECURSIVELY(); 1220 }, 1221 1222 /** 1223 * ScaleY setter (override cc.Node ) 1224 * @param {Number} scaleY 1225 * @override 1226 */ 1227 setScaleY:function (scaleY) { 1228 cc.Node.prototype.setScaleY.call(this, scaleY); 1229 this.SET_DIRTY_RECURSIVELY(); 1230 }, 1231 1232 /** 1233 * <p>The scale factor of the node. 1.0 is the default scale factor. <br/> 1234 * It modifies the X and Y scale at the same time. (override cc.Node ) <p/> 1235 * @param {Number} scale 1236 * @override 1237 */ 1238 setScale:function (scale, scaleY) { 1239 cc.Node.prototype.setScale.call(this, scale, scaleY); 1240 this.SET_DIRTY_RECURSIVELY(); 1241 }, 1242 1243 /** 1244 * VertexZ setter (override cc.Node ) 1245 * @param {Number} vertexZ 1246 * @override 1247 */ 1248 setVertexZ:function (vertexZ) { 1249 cc.Node.prototype.setVertexZ.call(this, vertexZ); 1250 this.SET_DIRTY_RECURSIVELY(); 1251 }, 1252 1253 /** 1254 * AnchorPoint setter (override cc.Node ) 1255 * @param {cc.Point} anchor 1256 * @override 1257 */ 1258 setAnchorPoint:function (anchor) { 1259 cc.Node.prototype.setAnchorPoint.call(this, anchor); 1260 this.SET_DIRTY_RECURSIVELY(); 1261 }, 1262 1263 /** 1264 * visible setter (override cc.Node ) 1265 * @param {Boolean} visible 1266 * @override 1267 */ 1268 setVisible:function (visible) { 1269 cc.Node.prototype.setVisible.call(this, visible); 1270 this.SET_DIRTY_RECURSIVELY(); 1271 }, 1272 1273 /** 1274 * IsRelativeAnchorPoint setter (override cc.Node ) 1275 * @param {Boolean} relative 1276 * @override 1277 */ 1278 ignoreAnchorPointForPosition:function (relative) { 1279 cc.Assert(!this._batchNode, "ignoreAnchorPointForPosition is invalid in cc.Sprite"); 1280 this._super(relative); 1281 }, 1282 1283 /** 1284 * FlipX value setter (override cc.Node ) 1285 * @param {Boolean} flipX 1286 */ 1287 setFlipX:function (flipX) { 1288 if (this._flipX != flipX) { 1289 //save dirty region when before change 1290 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1291 1292 this._flipX = flipX; 1293 this.setTextureRect(this._rect, this._rectRotated, this._contentSize); 1294 1295 //save dirty region when after changed 1296 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1297 this.setNodeDirty(); 1298 } 1299 }, 1300 1301 /** 1302 * FlipY value setter (override cc.Node ) 1303 * @param {Boolean} flipY 1304 */ 1305 setFlipY:function (flipY) { 1306 if (this._flipY != flipY) { 1307 //save dirty region when before change 1308 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1309 1310 this._flipY = flipY; 1311 //this.setTextureRect(this._rect, this._rectRotated, this._contentSize); 1312 1313 //save dirty region when after changed 1314 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1315 this.setNodeDirty(); 1316 } 1317 }, 1318 1319 /** 1320 * <p>whether or not the sprite is flipped horizontally.<br/> 1321 * It only flips the texture of the sprite, and not the texture of the sprite's children. <br/> 1322 * Also, flipping the texture doesn't alter the anchorPoint.<br/> 1323 * If you want to flip the anchorPoint too, and/or to flip the children too use:<br/> 1324 * sprite->setScaleX(sprite->getScaleX() * -1); <p/> 1325 * @return {Boolean} 1326 */ 1327 isFlippedX:function () { 1328 return this._flipX; 1329 }, 1330 1331 /** 1332 * <p>whether or not the sprite is flipped vertically.<br/> 1333 * It only flips the texture of the sprite, and not the texture of the sprite's children.<br/> 1334 * Also, flipping the texture doesn't alter the anchorPoint.<br/> 1335 * If you want to flip the anchorPoint too, and/or to flip the children too use:<br/> 1336 * sprite->setScaleY(sprite->getScaleY() * -1); <p/> 1337 * @return {Boolean} 1338 */ 1339 isFlippedY:function () { 1340 return this._flipY; 1341 }, 1342 1343 // 1344 // RGBA protocol 1345 // 1346 1347 /** 1348 * Update sprite's color 1349 */ 1350 updateColor:function () { 1351 var color4 = new cc.Color4B(this._color.r, this._color.g, this._color.b, this._opacity); 1352 1353 this._quad.bl.colors = color4; 1354 this._quad.br.colors = color4; 1355 this._quad.tl.colors = color4; 1356 this._quad.tr.colors = color4; 1357 1358 // renders using Sprite Manager 1359 //TODO 1360 if (this._batchNode) { 1361 if (this._atlasIndex != cc.SPRITE_INDEX_NOT_INITIALIZED) { 1362 this._textureAtlas.updateQuad(this._quad, this._atlasIndex) 1363 } else { 1364 // no need to set it recursively 1365 // update dirty_, don't update recursiveDirty_ 1366 //this.setDirty(true); 1367 this._dirty = true; 1368 } 1369 } 1370 // self render 1371 // do nothing 1372 }, 1373 1374 /** 1375 * Return opacity of sprite 1376 * @return {Number} 1377 */ 1378 getOpacity:function () { 1379 return this._opacity; 1380 }, 1381 1382 /** 1383 * opacity setter 1384 * @param {Number} opacity 1385 */ 1386 setOpacity:function (opacity) { 1387 this._opacity = opacity; 1388 1389 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1390 this.setNodeDirty(); 1391 //TODO in canvas 1392 return; 1393 // special opacity for premultiplied textures 1394 if (this._opacityModifyRGB) { 1395 this.setColor(this._colorUnmodified); 1396 } 1397 1398 this.updateColor(); 1399 }, 1400 1401 /** 1402 * Return color of sprite 1403 * @return {cc.Color3B} 1404 */ 1405 getColor:function () { 1406 if (this._opacityModifyRGB) { 1407 return new cc.Color3B(this._colorUnmodified); 1408 } 1409 return new cc.Color3B(this._color); 1410 }, 1411 1412 /** 1413 * color setter 1414 * @param {cc.Color3B} color3 1415 */ 1416 setColor:function (color3) { 1417 if ((this._color.r == color3.r) && (this._color.g == color3.g) && (this._color.b == color3.b)) { 1418 return; 1419 } 1420 1421 this._color = this._colorUnmodified = new cc.Color3B(color3.r, color3.g, color3.b); 1422 this._changeTextureColor(); 1423 1424 /* 1425 if (this._opacityModifyRGB) { 1426 this._color.r = Math.round(color3.r * this._opacity / 255); 1427 this._color.g = Math.round(color3.g * this._opacity / 255); 1428 this._color.b = Math.round(color3.b * this._opacity / 255); 1429 } 1430 */ 1431 this.updateColor(); 1432 //save dirty region when after changed 1433 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 1434 1435 this.setNodeDirty(); 1436 }, 1437 1438 _changeTextureColor:function(){ 1439 if (this.getTexture()) { 1440 if (cc.renderContextType === cc.CANVAS) { 1441 var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(this._originalTexture); 1442 if (cacheTextureForColor) { 1443 //generate color texture cache 1444 if (this._texture instanceof HTMLCanvasElement && !this._rectRotated) { 1445 cc.generateTintImage(this.getTexture(), cacheTextureForColor, this._color, this.getTextureRect(), this._texture); 1446 } else { 1447 var colorTexture = cc.generateTintImage(this.getTexture(), cacheTextureForColor, this._color, this.getTextureRect()); 1448 this.setTexture(colorTexture); 1449 } 1450 } 1451 } 1452 } 1453 }, 1454 1455 // RGBAProtocol 1456 1457 /** 1458 * opacity: conforms to CCRGBAProtocol protocol 1459 * @param {Boolean} value 1460 */ 1461 setOpacityModifyRGB:function (value) { 1462 var oldColor = this._color; 1463 this._opacityModifyRGB = value; 1464 this._color = oldColor; 1465 }, 1466 1467 /** 1468 * return IsOpacityModifyRGB value 1469 * @return {Boolean} 1470 */ 1471 isOpacityModifyRGB:function () { 1472 return this._opacityModifyRGB; 1473 }, 1474 1475 // Frames 1476 /** 1477 * Sets a new display frame to the cc.Sprite. 1478 * @param {cc.SpriteFrame} newFrame 1479 */ 1480 setDisplayFrame:function (newFrame) { 1481 this.setNodeDirty(); 1482 this._unflippedOffsetPositionFromCenter = newFrame.getOffset(); 1483 var pNewTexture = newFrame.getTexture(); 1484 // update texture before updating texture rect 1485 if (pNewTexture != this._texture) { 1486 this.setTexture(pNewTexture); 1487 } 1488 // update rect 1489 this._rectRotated = newFrame.isRotated(); 1490 if(this._rectRotated) 1491 this._originalTexture = pNewTexture; 1492 1493 this.setTextureRect(newFrame.getRect(), this._rectRotated, newFrame.getOriginalSize()); 1494 1495 if(this._color.r !== 255 || this._color.g !== 255 || this._color.b !== 255) 1496 this._changeTextureColor(); 1497 }, 1498 1499 // Animation 1500 1501 /** 1502 * changes the display frame with animation name and index.<br/> 1503 * The animation name will be get from the CCAnimationCache 1504 * @param animationName 1505 * @param frameIndex 1506 */ 1507 setDisplayFrameWithAnimationName:function (animationName, frameIndex) { 1508 cc.Assert(animationName, "cc.Sprite#setDisplayFrameWithAnimationName. animationName must not be null"); 1509 var cache = cc.AnimationCache.getInstance().getAnimation(animationName); 1510 cc.Assert(cache, "cc.Sprite#setDisplayFrameWithAnimationName: Frame not found"); 1511 var animFrame = cache.getFrames()[frameIndex]; 1512 cc.Assert(animFrame, "cc.Sprite#setDisplayFrame. Invalid frame"); 1513 this.setDisplayFrame(animFrame.getSpriteFrame()); 1514 }, 1515 1516 /** 1517 * Returns whether or not a cc.SpriteFrame is being displayed 1518 * @param {cc.SpriteFrame} frame 1519 * @return {Boolean} 1520 */ 1521 isFrameDisplayed:function (frame) { 1522 if (cc.renderContextType == cc.CANVAS) { 1523 if (frame.getTexture() != this._texture) 1524 return false; 1525 return cc.Rect.CCRectEqualToRect(frame.getRect(), this._rect); 1526 } else { 1527 return (cc.Rect.CCRectEqualToRect(frame.getRect(), this._rect) && frame.getTexture().getName() == this._texture.getName() 1528 && cc.Point.CCPointEqualToPoint(frame.getOffset(), this._unflippedOffsetPositionFromCenter)); 1529 } 1530 }, 1531 1532 /** 1533 * Returns the current displayed frame. 1534 * @return {cc.SpriteFrame} 1535 */ 1536 displayFrame:function () { 1537 if (cc.renderContextType == cc.CANVAS) { 1538 return cc.SpriteFrame._frameWithTextureForCanvas(this._texture, 1539 cc.RECT_POINTS_TO_PIXELS(this._rect), 1540 this._rectRotated, 1541 this._unflippedOffsetPositionFromCenter, 1542 cc.SIZE_POINTS_TO_PIXELS(this._contentSize)); 1543 } else { 1544 return cc.SpriteFrame.createWithTexture(this._texture, 1545 cc.RECT_POINTS_TO_PIXELS(this._rect), 1546 this._rectRotated, 1547 this._unflippedOffsetPositionFromCenter, 1548 cc.SIZE_POINTS_TO_PIXELS(this._contentSize)); 1549 } 1550 }, 1551 1552 getBatchNode:function () { 1553 return this._batchNode; 1554 }, 1555 1556 setBatchNode:function (spriteBatchNode) { 1557 this._batchNode = spriteBatchNode; // weak reference 1558 1559 // self render 1560 if (!this._batchNode) { 1561 this._atlasIndex = cc.SPRITE_INDEX_NOT_INITIALIZED; 1562 this.setTextureAtlas(null); 1563 this._recursiveDirty = false; 1564 this.setDirty(false); 1565 1566 var x1 = this._offsetPosition.x; 1567 var y1 = this._offsetPosition.y; 1568 var x2 = x1 + this._rect.size.width; 1569 var y2 = y1 + this._rect.size.height; 1570 this._quad.bl.vertices = cc.vertex3(x1, y1, 0); 1571 this._quad.br.vertices = cc.vertex3(x2, y1, 0); 1572 this._quad.tl.vertices = cc.vertex3(x1, y2, 0); 1573 this._quad.tr.vertices = cc.vertex3(x2, y2, 0); 1574 1575 } else { 1576 // using batch 1577 this._transformToBatch = cc.AffineTransformIdentity(); 1578 this.setTextureAtlas(this._batchNode.getTextureAtlas()); // weak ref 1579 } 1580 }, 1581 1582 // Texture protocol 1583 _updateBlendFunc:function () { 1584 if (cc.renderContextType == cc.WEBGL) { 1585 //TODO 1586 cc.Assert(!this._batchNode, "cc.Sprite: _updateBlendFunc doesn't work when the sprite is rendered using a cc.SpriteSheet"); 1587 // it's possible to have an untextured sprite 1588 if (!this._texture || !this._texture.hasPremultipliedAlpha()) { 1589 this._blendFunc.src = gl.SRC_ALPHA; 1590 this._blendFunc.dst = gl.ONE_MINUS_SRC_ALPHA; 1591 this.setOpacityModifyRGB(false); 1592 } else { 1593 this._blendFunc.src = cc.BLEND_SRC; 1594 this._blendFunc.dst = cc.BLEND_DST; 1595 this.setOpacityModifyRGB(true); 1596 } 1597 } 1598 }, 1599 1600 _setReorderChildDirtyRecursively:function () { 1601 //only set parents flag the first time 1602 if (!this._reorderChildDirty) { 1603 this._reorderChildDirty = true; 1604 var pNode = this._parent; 1605 while (pNode && pNode != this._batchNode) { 1606 pNode._setReorderChildDirtyRecursively(); 1607 pNode = pNode.getParent(); 1608 } 1609 } 1610 }, 1611 1612 // CCTextureProtocol 1613 /** 1614 * Texture of sprite setter 1615 * @param {HTMLImageElement|HTMLCanvasElement|cc.Texture2D} texture 1616 */ 1617 setTexture:function (texture) { 1618 // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet 1619 cc.Assert(!texture || texture instanceof cc.Texture2D || texture instanceof HTMLImageElement 1620 || texture instanceof HTMLCanvasElement, "setTexture expects a CCTexture2D. Invalid argument"); 1621 1622 if (cc.renderContextType != cc.CANVAS) { 1623 //TODO 1624 cc.Assert(!this._batchNode, "cc.Sprite: Batched sprites should use the same texture as the batchnode"); 1625 1626 if (!this._batchNode && this._texture != texture) { 1627 this._texture = texture; 1628 this._updateBlendFunc(); 1629 } 1630 } else { 1631 if (this._texture != texture) { 1632 if (texture instanceof HTMLImageElement) { 1633 if(!this._rect || cc.rectEqualToRect(this._rect,cc.RectZero())) 1634 this._rect = cc.rect(0, 0, texture.width, texture.height); 1635 this._texture = texture; 1636 this._originalTexture = texture; 1637 } else { 1638 this._texture = texture; 1639 this._updateBlendFunc(); 1640 } 1641 } 1642 } 1643 }, 1644 1645 getTexture:function () { 1646 return this._texture; 1647 } 1648 }); 1649 1650 /** 1651 * Create a sprite with texture 1652 * @constructs 1653 * @param {HTMLImageElement|HTMLCanvasElement|cc.Texture2D} texture 1654 * @param {cc.Rect} rect rect of the texture 1655 * @param {cc.Point} offset offset of the texture 1656 * @return {cc.Sprite} 1657 * @example 1658 * //get an image 1659 * var img = cc.TextureCache.getInstance().addImage("HelloHTML5World.png"); 1660 * 1661 * //create a sprite with texture 1662 * var sprite1 = cc.Sprite.createWithTexture(img); 1663 * 1664 * //create a sprite with texture and rect 1665 * var sprite2 = cc.Sprite.createWithTexture(img, cc.rect(0,0,480,320)); 1666 * 1667 * //create a sprite with texture and rect and offset 1668 * var sprite3 = cc.Sprite.createWithTexture(img, cc.rect(0,0,480,320),cc.p(0,0)); 1669 */ 1670 cc.Sprite.createWithTexture = function (texture, rect, offset) { 1671 var argnum = arguments.length; 1672 var sprite = new cc.Sprite(); 1673 switch (argnum) { 1674 case 1: 1675 /** Creates an sprite with a texture. 1676 The rect used will be the size of the texture. 1677 The offset will be (0,0). 1678 */ 1679 if (sprite && sprite.initWithTexture(texture)) { 1680 return sprite; 1681 } 1682 return null; 1683 break; 1684 1685 case 2: 1686 /** Creates an sprite with a texture and a rect. 1687 The offset will be (0,0). 1688 */ 1689 if (sprite && sprite.initWithTexture(texture, rect)) { 1690 return sprite; 1691 } 1692 return null; 1693 break; 1694 1695 case 3: 1696 /** Creates an sprite with a texture, a rect and offset. */ 1697 // not implement 1698 cc.Assert(0, ""); 1699 return null; 1700 break; 1701 1702 default: 1703 throw "Sprite.createWithTexture(): Argument must be non-nil "; 1704 break; 1705 } 1706 }; 1707 1708 /** 1709 * Create a sprite with filename and rect 1710 * @constructs 1711 * @param {String} fileName 1712 * @param {cc.Rect} rect 1713 * @return {cc.Sprite} 1714 * @example 1715 * //create a sprite with filename 1716 * var sprite1 = cc.Sprite.create("HelloHTML5World.png"); 1717 * 1718 * //create a sprite with filename and rect 1719 * var sprite2 = cc.Sprite.create("HelloHTML5World.png",cc.rect(0,0,480,320)); 1720 */ 1721 cc.Sprite.create = function (fileName, rect) { 1722 var argnum = arguments.length; 1723 var sprite = new cc.Sprite(); 1724 if (argnum === 0) { 1725 if (sprite.init()) 1726 return sprite; 1727 return null; 1728 } else if (argnum < 2) { 1729 /** Creates an sprite with an image filename. 1730 The rect used will be the size of the image. 1731 The offset will be (0,0). 1732 */ 1733 if (sprite && sprite.initWithFile(fileName)) { 1734 return sprite; 1735 } 1736 return null; 1737 } else { 1738 /** Creates an sprite with an CCBatchNode and a rect 1739 */ 1740 if (sprite && sprite.initWithFile(fileName, rect)) { 1741 return sprite; 1742 } 1743 return null; 1744 } 1745 }; 1746 1747 /** 1748 * Creates a sprite with a sprite frame name 1749 * @param {String} spriteFrame name 1750 * @return {cc.Sprite} 1751 * @example 1752 * 1753 * //create a sprite with a sprite frame 1754 * var sprite = cc.Sprite.createWithSpriteFrameName('grossini_dance_01.png'); 1755 */ 1756 cc.Sprite.createWithSpriteFrameName = function (spriteFrameName) { 1757 var spriteFrame = null; 1758 if (typeof(spriteFrameName) == 'string') { 1759 spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName); 1760 if (!spriteFrame) { 1761 cc.log("Invalid spriteFrameName: " + spriteFrameName); 1762 return null; 1763 } 1764 } else { 1765 cc.log("Invalid argument. Expecting string."); 1766 return null; 1767 } 1768 var sprite = new cc.Sprite(); 1769 if (sprite && sprite.initWithSpriteFrame(spriteFrame)) { 1770 return sprite; 1771 } 1772 return null; 1773 }; 1774 1775 /** 1776 * Creates a sprite with a sprite frame. 1777 * @param {cc.SpriteFrame} spriteFrame 1778 * @return {cc.Sprite} 1779 * @example 1780 * //get a sprite frame 1781 * var spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame("grossini_dance_01.png"); 1782 * 1783 * //create a sprite with a sprite frame 1784 * var sprite = cc.Sprite.createWithSpriteFrameName(spriteFrame); 1785 */ 1786 cc.Sprite.createWithSpriteFrame = function (spriteFrame) { 1787 var sprite = new cc.Sprite(); 1788 if (sprite && sprite.initWithSpriteFrame(spriteFrame)) { 1789 return sprite; 1790 } 1791 return null; 1792 }; 1793