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:null, //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         if(!spriteFrame)
462            throw "cc.Sprite.initWithSpriteFrame(): spriteFrame should be non-null";
463         if(!spriteFrame.textureLoaded()){
464             //add event listener
465             this._textureLoaded = false;
466             spriteFrame.addLoadedEventListener(this._spriteFrameLoadedCallback, this);
467         }
468         var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect());
469         this.setDisplayFrame(spriteFrame);
470 
471         return ret;
472     },
473 
474     _spriteFrameLoadedCallback:null,
475 
476     _spriteFrameLoadedCallbackForWebGL:function(spriteFrame){
477         this.setNodeDirty();
478         this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize());
479         this._callLoadedEventCallbacks();
480     },
481 
482     _spriteFrameLoadedCallbackForCanvas:function(spriteFrame){
483         this.setNodeDirty();
484         this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize());
485         var curColor = this.getColor();
486         if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
487             this._changeTextureColor();
488 
489         this._callLoadedEventCallbacks();
490     },
491 
492     /**
493      * Initializes a sprite with a sprite frame name. <br/>
494      * A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name.  <br/>
495      * If the cc.SpriteFrame doesn't exist it will raise an exception. <br/>
496      * @param {String} spriteFrameName A key string that can fected a volid cc.SpriteFrame from cc.SpriteFrameCache
497      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
498      * @example
499      * var sprite = new cc.Sprite();
500      * sprite.initWithSpriteFrameName("grossini_dance_01.png");
501      */
502     initWithSpriteFrameName:function (spriteFrameName) {
503         if(!spriteFrameName)
504             throw "cc.Sprite.initWithSpriteFrameName(): spriteFrameName should be non-null";
505         var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName);
506         return this.initWithSpriteFrame(frame);
507     },
508 
509     /**
510      * tell the sprite to use batch node render.
511      * @param {cc.SpriteBatchNode} batchNode
512      */
513     useBatchNode:function (batchNode) {
514         this._textureAtlas = batchNode.getTextureAtlas(); // weak ref
515         this._batchNode = batchNode;
516     },
517 
518     /**
519      * <p>
520      *    set the vertex rect.<br/>
521      *    It will be called internally by setTextureRect.                           <br/>
522      *    Useful if you want to create 2x images from SD images in Retina Display.  <br/>
523      *    Do not call it manually. Use setTextureRect instead.  <br/>
524      *    (override this method to generate "double scale" sprites)
525      * </p>
526      * @param {cc.Rect} rect
527      */
528     setVertexRect:function (rect) {
529         this._rect.x = rect.x;
530         this._rect.y = rect.y;
531         this._rect.width = rect.width;
532         this._rect.height = rect.height;
533     },
534 
535     sortAllChildren:function () {
536         if (this._reorderChildDirty) {
537             var j, tempItem, locChildren = this._children, tempChild;
538             for (var i = 1; i < locChildren.length; i++) {
539                 tempItem = locChildren[i];
540                 j = i - 1;
541                 tempChild =  locChildren[j];
542 
543                 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller
544                 while (j >= 0 && ( tempItem._zOrder < tempChild._zOrder ||
545                     ( tempItem._zOrder == tempChild._zOrder && tempItem._orderOfArrival < tempChild._orderOfArrival ))) {
546                     locChildren[j + 1] = tempChild;
547                     j = j - 1;
548                     tempChild =  locChildren[j];
549                 }
550                 locChildren[j + 1] = tempItem;
551             }
552 
553             if (this._batchNode) {
554                 this._arrayMakeObjectsPerformSelector(locChildren, cc.Node.StateCallbackType.sortAllChildren);
555             }
556             this._reorderChildDirty = false;
557         }
558     },
559 
560     /**
561      * Reorders a child according to a new z value.  (override cc.Node )
562      * @param {cc.Node} child
563      * @param {Number} zOrder
564      * @override
565      */
566     reorderChild:function (child, zOrder) {
567         if(!child)
568             throw "cc.Sprite.reorderChild(): child should be non-null";
569         if(this._children.indexOf(child) === -1){
570             cc.log("cc.Sprite.reorderChild(): this child is not in children list");
571             return;
572         }
573 
574         if (zOrder === child.getZOrder())
575             return;
576 
577         if (this._batchNode && !this._reorderChildDirty) {
578             this._setReorderChildDirtyRecursively();
579             this._batchNode.reorderBatch(true);
580         }
581         cc.Node.prototype.reorderChild.call(this, child, zOrder);
582     },
583 
584     /**
585      * Removes a child from the sprite. (override cc.Node )
586      * @param child
587      * @param cleanup  whether or not cleanup all running actions
588      * @override
589      */
590     removeChild:function (child, cleanup) {
591         if (this._batchNode)
592             this._batchNode.removeSpriteFromAtlas(child);
593         cc.Node.prototype.removeChild.call(this, child, cleanup);
594     },
595 
596     /**
597      * Removes all children from the container  (override cc.Node )
598      * @param cleanup whether or not cleanup all running actions
599      * @override
600      */
601     removeAllChildren:function (cleanup) {
602         var locChildren = this._children, locBatchNode = this._batchNode;
603         if (locBatchNode && locChildren != null) {
604             for (var i = 0, len = locChildren.length; i < len; i++)
605                 locBatchNode.removeSpriteFromAtlas(locChildren[i]);
606         }
607 
608         cc.Node.prototype.removeAllChildren.call(this, cleanup);
609         this._hasChildren = false;
610     },
611 
612     //
613     // cc.Node property overloads
614     //
615 
616     /**
617      * set Recursively is or isn't Dirty
618      * used only when parent is cc.SpriteBatchNode
619      * @param {Boolean} value
620      */
621     setDirtyRecursively:function (value) {
622         this._recursiveDirty = value;
623         this.setDirty(value);
624         // recursively set dirty
625         var locChildren = this._children;
626         if (locChildren != null) {
627             for (var i = 0; i < locChildren.length; i++) {
628                 if (locChildren[i] instanceof cc.Sprite)
629                     locChildren[i].setDirtyRecursively(true);
630             }
631         }
632     },
633 
634     /**
635      * HACK: optimization
636      */
637     SET_DIRTY_RECURSIVELY:function () {
638         if (this._batchNode && !this._recursiveDirty) {
639             this._recursiveDirty = true;
640             this._dirty = true;
641             if (this._hasChildren)
642                 this.setDirtyRecursively(true);
643         }
644     },
645 
646     /**
647      * position setter (override cc.Node )
648      * @param {cc.Point} pos
649      * @override
650      */
651     setPosition:function (pos) {
652         if (arguments.length >= 2)
653             cc.Node.prototype.setPosition.call(this, pos, arguments[1]);
654         else
655             cc.Node.prototype.setPosition.call(this, pos);
656         this.SET_DIRTY_RECURSIVELY();
657     },
658 
659     /**
660      * Rotation setter (override cc.Node )
661      * @param {Number} rotation
662      * @override
663      */
664     setRotation:function (rotation) {
665         cc.Node.prototype.setRotation.call(this, rotation);
666         this.SET_DIRTY_RECURSIVELY();
667     },
668 
669     setRotationX:function (rotationX) {
670         cc.Node.prototype.setRotationX.call(this, rotationX);
671         this.SET_DIRTY_RECURSIVELY();
672     },
673 
674     setRotationY:function (rotationY) {
675         cc.Node.prototype.setRotationY.call(this, rotationY);
676         this.SET_DIRTY_RECURSIVELY();
677     },
678 
679     /**
680      * SkewX setter (override cc.Node )
681      * @param {Number} sx SkewX value
682      * @override
683      */
684     setSkewX:function (sx) {
685         cc.Node.prototype.setSkewX.call(this, sx);
686         this.SET_DIRTY_RECURSIVELY();
687     },
688 
689     /**
690      * SkewY setter (override cc.Node )
691      * @param {Number} sy SkewY value
692      * @override
693      */
694     setSkewY:function (sy) {
695         cc.Node.prototype.setSkewY.call(this, sy);
696         this.SET_DIRTY_RECURSIVELY();
697     },
698 
699     /**
700      * ScaleX setter (override cc.Node )
701      * @param {Number} scaleX
702      * @override
703      */
704     setScaleX:function (scaleX) {
705         cc.Node.prototype.setScaleX.call(this, scaleX);
706         this.SET_DIRTY_RECURSIVELY();
707     },
708 
709     /**
710      * ScaleY setter (override cc.Node )
711      * @param {Number} scaleY
712      * @override
713      */
714     setScaleY:function (scaleY) {
715         cc.Node.prototype.setScaleY.call(this, scaleY);
716         this.SET_DIRTY_RECURSIVELY();
717     },
718 
719     /**
720      * <p>The scale factor of the node. 1.0 is the default scale factor. <br/>
721      * It modifies the X and Y scale at the same time. (override cc.Node ) <p/>
722      * @param {Number} scale
723      * @param {Number|null} [scaleY=]
724      * @override
725      */
726     setScale:function (scale, scaleY) {
727         cc.Node.prototype.setScale.call(this, scale, scaleY);
728         this.SET_DIRTY_RECURSIVELY();
729     },
730 
731     /**
732      * VertexZ setter (override cc.Node )
733      * @param {Number} vertexZ
734      * @override
735      */
736     setVertexZ:function (vertexZ) {
737         cc.Node.prototype.setVertexZ.call(this, vertexZ);
738         this.SET_DIRTY_RECURSIVELY();
739     },
740 
741     /**
742      * AnchorPoint setter  (override cc.Node )
743      * @param {cc.Point} anchor
744      * @override
745      */
746     setAnchorPoint:function (anchor) {
747         cc.Node.prototype.setAnchorPoint.call(this, anchor);
748         this.SET_DIRTY_RECURSIVELY();
749     },
750 
751     /**
752      * visible setter  (override cc.Node )
753      * @param {Boolean} visible
754      * @override
755      */
756     setVisible:function (visible) {
757         cc.Node.prototype.setVisible.call(this, visible);
758         this.SET_DIRTY_RECURSIVELY();
759     },
760 
761     /**
762      * IsRelativeAnchorPoint setter  (override cc.Node )
763      * @param {Boolean} relative
764      * @override
765      */
766     ignoreAnchorPointForPosition:function (relative) {
767         if(this._batchNode){
768             cc.log("cc.Sprite.ignoreAnchorPointForPosition(): it is invalid in cc.Sprite when using SpriteBatchNode");
769             return;
770         }
771         cc.Node.prototype.ignoreAnchorPointForPosition.call(this, relative);
772     },
773 
774     /**
775      * Sets whether the sprite should be flipped horizontally or not.
776      * @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise.
777      */
778     setFlippedX:function (flippedX) {
779         if (this._flippedX != flippedX) {
780             this._flippedX = flippedX;
781             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
782             this.setNodeDirty();
783         }
784     },
785 
786     /**
787      * Sets whether the sprite should be flipped vertically or not.
788      * @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise.
789      */
790     setFlippedY:function (flippedY) {
791         if (this._flippedY != flippedY) {
792             this._flippedY = flippedY;
793             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
794             this.setNodeDirty();
795         }
796     },
797 
798     /**
799      * <p>
800      *     Returns the flag which indicates whether the sprite is flipped horizontally or not.                      <br/>
801      *                                                                                                              <br/>
802      * It only flips the texture of the sprite, and not the texture of the sprite's children.                       <br/>
803      * Also, flipping the texture doesn't alter the anchorPoint.                                                    <br/>
804      * If you want to flip the anchorPoint too, and/or to flip the children too use:                                <br/>
805      *      sprite->setScaleX(sprite->getScaleX() * -1);  <p/>
806      * @return {Boolean} true if the sprite is flipped horizaontally, false otherwise.
807      */
808     isFlippedX:function () {
809         return this._flippedX;
810     },
811 
812     /**
813      * <p>
814      *     Return the flag which indicates whether the sprite is flipped vertically or not.                         <br/>
815      *                                                                                                              <br/>
816      *      It only flips the texture of the sprite, and not the texture of the sprite's children.                  <br/>
817      *      Also, flipping the texture doesn't alter the anchorPoint.                                               <br/>
818      *      If you want to flip the anchorPoint too, and/or to flip the children too use:                           <br/>
819      *         sprite->setScaleY(sprite->getScaleY() * -1); <p/>
820      * @return {Boolean} true if the sprite is flipped vertically, flase otherwise.
821      */
822     isFlippedY:function () {
823         return this._flippedY;
824     },
825 
826     //
827     // RGBA protocol
828     //
829     /**
830      * opacity: conforms to CCRGBAProtocol protocol
831      * @param {Boolean} modify
832      */
833     setOpacityModifyRGB:null,
834 
835     _setOpacityModifyRGBForWebGL: function (modify) {
836         if (this._opacityModifyRGB !== modify) {
837             this._opacityModifyRGB = modify;
838             this.updateColor();
839         }
840     },
841 
842     _setOpacityModifyRGBForCanvas: function (modify) {
843         if (this._opacityModifyRGB !== modify) {
844             this._opacityModifyRGB = modify;
845             this.setNodeDirty();
846         }
847     },
848 
849     /**
850      * return IsOpacityModifyRGB value
851      * @return {Boolean}
852      */
853     isOpacityModifyRGB:function () {
854         return this._opacityModifyRGB;
855     },
856 
857     updateDisplayedOpacity: null,
858     _updateDisplayedOpacityForWebGL:function (parentOpacity) {
859         cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity);
860         this.updateColor();
861     },
862 
863     _updateDisplayedOpacityForCanvas:function (parentOpacity) {
864         cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity);
865         this._setNodeDirtyForCache();
866     },
867 
868     // Animation
869 
870     /**
871      * changes the display frame with animation name and index.<br/>
872      * The animation name will be get from the CCAnimationCache
873      * @param animationName
874      * @param frameIndex
875      */
876     setDisplayFrameWithAnimationName:function (animationName, frameIndex) {
877         if(!animationName)
878             throw "cc.Sprite.setDisplayFrameWithAnimationName(): animationName must be non-null";
879         var cache = cc.AnimationCache.getInstance().getAnimation(animationName);
880         if(!cache){
881             cc.log("cc.Sprite.setDisplayFrameWithAnimationName(): Frame not found");
882             return;
883         }
884         var animFrame = cache.getFrames()[frameIndex];
885         if(!animFrame){
886             cc.log("cc.Sprite.setDisplayFrameWithAnimationName(): Invalid frame index");
887             return;
888         }
889         this.setDisplayFrame(animFrame.getSpriteFrame());
890     },
891 
892     /**
893      * Returns the batch node object if this sprite is rendered by cc.SpriteBatchNode
894      * @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.
895      */
896     getBatchNode:function () {
897         return this._batchNode;
898     },
899 
900     _setReorderChildDirtyRecursively:function () {
901         //only set parents flag the first time
902         if (!this._reorderChildDirty) {
903             this._reorderChildDirty = true;
904             var pNode = this._parent;
905             while (pNode && pNode != this._batchNode) {
906                 pNode._setReorderChildDirtyRecursively();
907                 pNode = pNode.getParent();
908             }
909         }
910     },
911 
912     // CCTextureProtocol
913     getTexture:function () {
914         return this._texture;
915     },
916 
917     _quad:null, // vertex coords, texture coords and color info
918     _quadWebBuffer:null,
919     _quadDirty:false,
920     _colorized:false,
921     _isLighterMode:false,
922     _originalTexture:null,
923     _textureRect_Canvas:null,
924     _drawSize_Canvas:null,
925 
926     /**
927      * Constructor
928      * @param {String|cc.SpriteFrame|cc.SpriteBatchNode|HTMLImageElement|cc.Texture2D} fileName sprite construct parameter
929      */
930     ctor: null,
931 
932     _ctorForWebGL: function (fileName) {
933         cc.NodeRGBA.prototype.ctor.call(this);
934         this._shouldBeHidden = false;
935         this._offsetPosition = cc.p(0, 0);
936         this._unflippedOffsetPositionFromCenter = cc.p(0, 0);
937         this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST};
938         this._rect = cc.rect(0,0,0,0);
939 
940         this._quad = new cc.V3F_C4B_T2F_Quad();
941         this._quadWebBuffer = cc.renderContext.createBuffer();
942         this._quadDirty = true;
943 
944         this._textureLoaded = true;
945         this._loadedEventListeners = [];
946 
947         if (fileName) {
948             if (typeof(fileName) === "string") {
949                 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(fileName);
950                 this.initWithSpriteFrame(frame);
951             } else if (typeof(fileName) === "object") {
952                 if (fileName instanceof cc.SpriteFrame) {
953                     this.initWithSpriteFrame(fileName);
954                 } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) {
955                     var texture2d = new cc.Texture2D();
956                     texture2d.initWithElement(fileName);
957                     texture2d.handleLoadedTexture();
958                     this.initWithTexture(texture2d);
959                 } else if (fileName instanceof cc.Texture2D) {
960                     this.initWithTexture(fileName);
961                 }
962             }
963         }
964     },
965 
966     _ctorForCanvas: function (fileName) {
967         cc.NodeRGBA.prototype.ctor.call(this);
968         this._shouldBeHidden = false;
969         this._offsetPosition = cc.p(0, 0);
970         this._unflippedOffsetPositionFromCenter = cc.p(0, 0);
971         this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST};
972         this._rect = cc.rect(0, 0, 0, 0);
973 
974         this._newTextureWhenChangeColor = false;
975         this._textureLoaded = true;
976         this._loadedEventListeners = [];
977         this._textureRect_Canvas = cc.rect(0, 0, 0, 0);
978         this._drawSize_Canvas = cc.size(0, 0);
979 
980         if (fileName) {
981             if (typeof(fileName) === "string") {
982                 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(fileName);
983                 this.initWithSpriteFrame(frame);
984             } else if (typeof(fileName) === "object") {
985                 if (fileName instanceof cc.SpriteFrame) {
986                     this.initWithSpriteFrame(fileName);
987                 } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) {
988                     var texture2d = new cc.Texture2D();
989                     texture2d.initWithElement(fileName);
990                     texture2d.handleLoadedTexture();
991                     this.initWithTexture(texture2d);
992                 } else if (fileName instanceof cc.Texture2D) {
993                     this.initWithTexture(fileName);
994                 }
995             }
996         }
997     },
998 
999     /**
1000      * Returns the quad (tex coords, vertex coords and color) information.
1001      * @return {cc.V3F_C4B_T2F_Quad}
1002      */
1003     getQuad:function () {
1004         return this._quad;
1005     },
1006 
1007     /**
1008      * conforms to cc.TextureProtocol protocol
1009      * @param {Number|cc.BlendFunc} src
1010      * @param {Number} dst
1011      */
1012     setBlendFunc: null,
1013 
1014     _setBlendFuncForWebGL: function (src, dst) {
1015         if (arguments.length == 1)
1016             this._blendFunc = src;
1017         else
1018             this._blendFunc = {src: src, dst: dst};
1019     },
1020 
1021     _setBlendFuncForCanvas: function (src, dst) {
1022         if (arguments.length == 1)
1023             this._blendFunc = src;
1024         else
1025             this._blendFunc = {src: src, dst: dst};
1026         this._isLighterMode = (this._blendFunc &&
1027             (( this._blendFunc.src == gl.SRC_ALPHA && this._blendFunc.dst == gl.ONE) || (this._blendFunc.src == gl.ONE && this._blendFunc.dst == gl.ONE)));
1028     },
1029 
1030     /**
1031      * Initializes an empty sprite with nothing init.
1032      * @return {Boolean}
1033      */
1034     init:null,
1035 
1036     _initForWebGL: function () {
1037         if (arguments.length > 0)
1038             return this.initWithFile(arguments[0], arguments[1]);
1039 
1040         cc.NodeRGBA.prototype.init.call(this);
1041         this._dirty = this._recursiveDirty = false;
1042         this._opacityModifyRGB = true;
1043 
1044         this._blendFunc.src = cc.BLEND_SRC;
1045         this._blendFunc.dst = cc.BLEND_DST;
1046 
1047         // update texture (calls _updateBlendFunc)
1048         this.setTexture(null);
1049         this._textureLoaded = true;
1050         this._flippedX = this._flippedY = false;
1051 
1052         // default transform anchor: center
1053         this.setAnchorPoint(cc.p(0.5, 0.5));
1054 
1055         // zwoptex default values
1056         this._offsetPosition = cc.PointZero();
1057         this._hasChildren = false;
1058 
1059         // Atlas: Color
1060         var tempColor = {r: 255, g: 255, b: 255, a: 255};
1061         this._quad.bl.colors = tempColor;
1062         this._quad.br.colors = tempColor;
1063         this._quad.tl.colors = tempColor;
1064         this._quad.tr.colors = tempColor;
1065         this._quadDirty = true;
1066 
1067         // updated in "useSelfRender"
1068         // Atlas: TexCoords
1069         this.setTextureRect(cc.RectZero(), false, cc.SizeZero());
1070         return true;
1071     },
1072 
1073     _initForCanvas: function () {
1074         if (arguments.length > 0)
1075             return this.initWithFile(arguments[0], arguments[1]);
1076 
1077         cc.NodeRGBA.prototype.init.call(this);
1078         this._dirty = this._recursiveDirty = false;
1079         this._opacityModifyRGB = true;
1080 
1081         this._blendFunc.src = cc.BLEND_SRC;
1082         this._blendFunc.dst = cc.BLEND_DST;
1083 
1084         // update texture (calls _updateBlendFunc)
1085         this.setTexture(null);
1086         this._textureLoaded = true;
1087         this._flippedX = this._flippedY = false;
1088 
1089         // default transform anchor: center
1090         this.setAnchorPoint(cc.p(0.5, 0.5));
1091 
1092         // zwoptex default values
1093         this._offsetPosition = cc.PointZero();
1094         this._hasChildren = false;
1095 
1096         // updated in "useSelfRender"
1097         // Atlas: TexCoords
1098         this.setTextureRect(cc.RectZero(), false, cc.SizeZero());
1099         return true;
1100     },
1101 
1102     /**
1103      * <p>
1104      *     Initializes a sprite with an image filename.
1105      *
1106      *     This method will find pszFilename from local file system, load its content to CCTexture2D,
1107      *     then use CCTexture2D to create a sprite.
1108      *     After initialization, the rect used will be the size of the image. The offset will be (0,0).
1109      * </p>
1110      * @param {String} filename The path to an image file in local file system
1111      * @param {cc.Rect} rect The rectangle assigned the content area from texture.
1112      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
1113      * @example
1114      * var mySprite = new cc.Sprite();
1115      * mySprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320));
1116      */
1117     initWithFile:function (filename, rect) {
1118         if(!filename)
1119             throw "cc.Sprite.initWithFile(): filename should be non-null";
1120 
1121         var texture = cc.TextureCache.getInstance().textureForKey(filename);
1122         if (!texture) {
1123             texture = cc.TextureCache.getInstance().addImage(filename);
1124             return this.initWithTexture(texture, rect);
1125         } else {
1126             if (!rect) {
1127                 var size = texture.getContentSize();
1128                 rect = cc.rect(0, 0, size.width, size.height);
1129             }
1130             return this.initWithTexture(texture, rect);
1131         }
1132     },
1133 
1134     /**
1135      * Initializes a sprite with a texture and a rect in points, optionally rotated.  <br/>
1136      * After initialization, the rect used will be the size of the texture, and the offset will be (0,0).
1137      * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites.
1138      * @param {cc.Rect} rect Only the contents inside rect of this texture will be applied for this sprite.
1139      * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
1140      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
1141      * @example
1142      * var img =cc.TextureCache.getInstance().addImage("HelloHTML5World.png");
1143      * var mySprite = new cc.Sprite();
1144      * mySprite.initWithTexture(img,cc.rect(0,0,480,320));
1145      */
1146     initWithTexture: null,
1147 
1148     _initWithTextureForWebGL: function (texture, rect, rotated) {
1149         var argnum = arguments.length;
1150         if (argnum == 0)
1151             throw "Sprite.initWithTexture(): Argument must be non-nil ";
1152 
1153         rotated = rotated || false;
1154 
1155         if (!cc.NodeRGBA.prototype.init.call(this))
1156             return false;
1157 
1158         this._batchNode = null;
1159         this._recursiveDirty = false;
1160         this._dirty = false;
1161         this._opacityModifyRGB = true;
1162 
1163         this._blendFunc.src = cc.BLEND_SRC;
1164         this._blendFunc.dst = cc.BLEND_DST;
1165 
1166         this._flippedX = this._flippedY = false;
1167 
1168         // default transform anchor: center
1169         this.setAnchorPoint(cc.p(0.5, 0.5));
1170 
1171         // zwoptex default values
1172         this._offsetPosition = cc.p(0, 0);
1173         this._hasChildren = false;
1174 
1175         // Atlas: Color
1176         var tmpColor = new cc.Color4B(255, 255, 255, 255);
1177         var locQuad = this._quad;
1178         locQuad.bl.colors = tmpColor;
1179         locQuad.br.colors = tmpColor;
1180         locQuad.tl.colors = tmpColor;
1181         locQuad.tr.colors = tmpColor;
1182 
1183         var locTextureLoaded = texture.isLoaded();
1184         this._textureLoaded = locTextureLoaded;
1185 
1186         if (!locTextureLoaded) {
1187             this._rectRotated = rotated || false;
1188             if (rect) {
1189                 var locRect = this._rect;
1190                 locRect.x = rect.x;
1191                 locRect.y = rect.y;
1192                 locRect.width = rect.width;
1193                 locRect.height = rect.height;
1194             }
1195             texture.addLoadedEventListener(this._textureLoadedCallback, this);
1196             return true;
1197         }
1198 
1199         if (!rect) {
1200             rect = cc.rect(0, 0, 0, 0);
1201             rect.size = texture.getContentSize();
1202         }
1203         this.setTexture(texture);
1204         this.setTextureRect(rect, rotated, rect.size);
1205 
1206         // by default use "Self Render".
1207         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1208         this.setBatchNode(null);
1209         this._quadDirty = true;
1210         return true;
1211     },
1212 
1213     _initWithTextureForCanvas: function (texture, rect, rotated) {
1214         var argnum = arguments.length;
1215         if (argnum == 0)
1216             throw "Sprite.initWithTexture(): Argument must be non-nil ";
1217 
1218         rotated = rotated || false;
1219 
1220         if (!cc.NodeRGBA.prototype.init.call(this))
1221             return false;
1222 
1223         this._batchNode = null;
1224 
1225         this._recursiveDirty = false;
1226         this._dirty = false;
1227         this._opacityModifyRGB = true;
1228 
1229         this._blendFunc.src = cc.BLEND_SRC;
1230         this._blendFunc.dst = cc.BLEND_DST;
1231 
1232         this._flippedX = this._flippedY = false;
1233 
1234         // default transform anchor: center
1235         this.setAnchorPoint(cc.p(0.5, 0.5));
1236 
1237         // zwoptex default values
1238         this._offsetPosition = cc.p(0, 0);
1239         this._hasChildren = false;
1240 
1241         var locTextureLoaded = texture.isLoaded();
1242         this._textureLoaded = locTextureLoaded;
1243 
1244         if (!locTextureLoaded) {
1245             this._rectRotated = rotated || false;
1246             if (rect) {
1247                 this._rect.x = rect.x;
1248                 this._rect.y = rect.y;
1249                 this._rect.width = rect.width;
1250                 this._rect.height = rect.height;
1251             }
1252             texture.addLoadedEventListener(this._textureLoadedCallback, this);
1253             return true;
1254         }
1255 
1256         if (!rect) {
1257             rect = cc.rect(0, 0, 0, 0);
1258             rect.size = texture.getContentSize();
1259         }
1260         this._originalTexture = texture;
1261 
1262         this.setTexture(texture);
1263         this.setTextureRect(rect, rotated, rect.size);
1264 
1265         // by default use "Self Render".
1266         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1267         this.setBatchNode(null);
1268         return true;
1269     },
1270 
1271     _textureLoadedCallback: null,
1272 
1273     _textureLoadedCallbackForWebGL: function (sender) {
1274         this._textureLoaded = true;
1275         var locRect = this._rect;
1276         if (!locRect) {
1277             locRect = cc.rect(0, 0, 0, 0);
1278             locRect.size = sender.getContentSize();
1279         } else if (cc._rectEqualToZero(locRect)) {
1280             locRect.size = sender.getContentSize();
1281         }
1282 
1283         this.setTexture(sender);
1284         this.setTextureRect(locRect, this._rectRotated, locRect.size);
1285 
1286         // by default use "Self Render".
1287         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1288         this.setBatchNode(null);
1289         this._quadDirty = true;
1290         this._callLoadedEventCallbacks();
1291     },
1292 
1293     _textureLoadedCallbackForCanvas: function (sender) {
1294         this._textureLoaded = true;
1295         var locRect = this._rect;
1296         if (!locRect) {
1297             locRect = cc.rect(0, 0, 0, 0);
1298             locRect.size = sender.getContentSize();
1299         } else if (cc._rectEqualToZero(locRect)) {
1300             locRect.size = sender.getContentSize();
1301         }
1302         this._originalTexture = sender;
1303 
1304         this.setTexture(sender);
1305         this.setTextureRect(locRect, this._rectRotated, locRect.size);
1306 
1307         // by default use "Self Render".
1308         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1309         this.setBatchNode(null);
1310         this._callLoadedEventCallbacks();
1311     },
1312 
1313     /**
1314      * updates the texture rect of the CCSprite in points.
1315      * @param {cc.Rect} rect a rect of texture
1316      * @param {Boolean} rotated
1317      * @param {cc.Size} untrimmedSize
1318      */
1319     setTextureRect:null,
1320 
1321     _setTextureRectForWebGL:function (rect, rotated, untrimmedSize) {
1322         this._rectRotated = rotated || false;
1323         untrimmedSize = untrimmedSize || rect.size;
1324 
1325         this.setContentSize(untrimmedSize);
1326         this.setVertexRect(rect);
1327         this._setTextureCoords(rect);
1328 
1329         var relativeOffset = this._unflippedOffsetPositionFromCenter;
1330         if (this._flippedX)
1331             relativeOffset.x = -relativeOffset.x;
1332         if (this._flippedY)
1333             relativeOffset.y = -relativeOffset.y;
1334 
1335         var locRect = this._rect;
1336         this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - locRect.width) / 2;
1337         this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - locRect.height) / 2;
1338 
1339         // rendering using batch node
1340         if (this._batchNode) {
1341             // update dirty_, don't update recursiveDirty_
1342             //this.setDirty(true);
1343             this._dirty = true;
1344         } else {
1345             // self rendering
1346             // Atlas: Vertex
1347             var x1 = 0 + this._offsetPosition.x;
1348             var y1 = 0 + this._offsetPosition.y;
1349             var x2 = x1 + locRect.width;
1350             var y2 = y1 + locRect.height;
1351 
1352             // Don't update Z.
1353             var locQuad = this._quad;
1354             locQuad.bl.vertices = {x:x1, y:y1, z:0};
1355             locQuad.br.vertices = {x:x2, y:y1, z:0};
1356             locQuad.tl.vertices = {x:x1, y:y2, z:0};
1357             locQuad.tr.vertices = {x:x2, y:y2, z:0};
1358 
1359             this._quadDirty = true;
1360         }
1361     },
1362 
1363     _setTextureRectForCanvas: function (rect, rotated, untrimmedSize) {
1364         this._rectRotated = rotated || false;
1365         untrimmedSize = untrimmedSize || rect.size;
1366 
1367         this.setContentSize(untrimmedSize);
1368         this.setVertexRect(rect);
1369         //this._textureRect_Canvas = cc.RECT_POINTS_TO_PIXELS(rect);                      //this._setTextureCoords(rect);
1370         var locTextureRect = this._textureRect_Canvas;
1371         var scaleFactor = cc.CONTENT_SCALE_FACTOR();
1372         locTextureRect.x = 0|(rect.x * scaleFactor);
1373         locTextureRect.y = 0|(rect.y * scaleFactor);
1374         locTextureRect.width = 0|(rect.width * scaleFactor);
1375         locTextureRect.height = 0|(rect.height * scaleFactor);
1376 
1377         var relativeOffset = this._unflippedOffsetPositionFromCenter;
1378         if (this._flippedX)
1379             relativeOffset.x = -relativeOffset.x;
1380         if (this._flippedY)
1381             relativeOffset.y = -relativeOffset.y;
1382         this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - this._rect.width) / 2;
1383         this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - this._rect.height) / 2;
1384 
1385         // rendering using batch node
1386         if (this._batchNode) {
1387             // update dirty_, don't update recursiveDirty_
1388             //this.setDirty(true);
1389             this._dirty = true;
1390         }
1391     },
1392 
1393     // BatchNode methods
1394     /**
1395      * updates the quad according the the rotation, position, scale values.
1396      */
1397     updateTransform: null,
1398 
1399     _updateTransformForWebGL: function () {
1400         //cc.Assert(this._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode");
1401 
1402         // recaculate matrix only if it is dirty
1403         if (this.isDirty()) {
1404             var locQuad = this._quad, locParent = this._parent;
1405             // If it is not visible, or one of its ancestors is not visible, then do nothing:
1406             if (!this._visible || ( locParent && locParent != this._batchNode && locParent._shouldBeHidden)) {
1407                 locQuad.br.vertices = {x: 0, y: 0, z: 0};
1408                 locQuad.tl.vertices = {x: 0, y: 0, z: 0};
1409                 locQuad.tr.vertices = {x: 0, y: 0, z: 0};
1410                 locQuad.bl.vertices = {x: 0, y: 0, z: 0};
1411                 this._shouldBeHidden = true;
1412             } else {
1413                 this._shouldBeHidden = false;
1414 
1415                 if (!locParent || locParent == this._batchNode) {
1416                     this._transformToBatch = this.nodeToParentTransform();
1417                 } else {
1418                     //cc.Assert(this._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite");
1419                     this._transformToBatch = cc.AffineTransformConcat(this.nodeToParentTransform(), locParent._transformToBatch);
1420                 }
1421 
1422                 //
1423                 // calculate the Quad based on the Affine Matrix
1424                 //
1425                 var locTransformToBatch = this._transformToBatch;
1426                 var size = this._rect.size;
1427                 var x1 = this._offsetPosition.x;
1428                 var y1 = this._offsetPosition.y;
1429 
1430                 var x2 = x1 + size.width;
1431                 var y2 = y1 + size.height;
1432                 var x = locTransformToBatch.tx;
1433                 var y = locTransformToBatch.ty;
1434 
1435                 var cr = locTransformToBatch.a;
1436                 var sr = locTransformToBatch.b;
1437                 var cr2 = locTransformToBatch.d;
1438                 var sr2 = -locTransformToBatch.c;
1439                 var ax = x1 * cr - y1 * sr2 + x;
1440                 var ay = x1 * sr + y1 * cr2 + y;
1441 
1442                 var bx = x2 * cr - y1 * sr2 + x;
1443                 var by = x2 * sr + y1 * cr2 + y;
1444 
1445                 var cx = x2 * cr - y2 * sr2 + x;
1446                 var cy = x2 * sr + y2 * cr2 + y;
1447 
1448                 var dx = x1 * cr - y2 * sr2 + x;
1449                 var dy = x1 * sr + y2 * cr2 + y;
1450 
1451                 var locVertexZ = this._vertexZ;
1452                 locQuad.bl.vertices = {x: cc.RENDER_IN_SUBPIXEL(ax), y: cc.RENDER_IN_SUBPIXEL(ay), z: locVertexZ};
1453                 locQuad.br.vertices = {x: cc.RENDER_IN_SUBPIXEL(bx), y: cc.RENDER_IN_SUBPIXEL(by), z: locVertexZ};
1454                 locQuad.tl.vertices = {x: cc.RENDER_IN_SUBPIXEL(dx), y: cc.RENDER_IN_SUBPIXEL(dy), z: locVertexZ};
1455                 locQuad.tr.vertices = {x: cc.RENDER_IN_SUBPIXEL(cx), y: cc.RENDER_IN_SUBPIXEL(cy), z: locVertexZ};
1456             }
1457             this._textureAtlas.updateQuad(locQuad, this._atlasIndex);
1458             this._recursiveDirty = false;
1459             this.setDirty(false);
1460         }
1461 
1462         // recursively iterate over children
1463         if (this._hasChildren)
1464             this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform);
1465 
1466         if (cc.SPRITE_DEBUG_DRAW) {
1467             // draw bounding box
1468             var vertices = [
1469                 cc.p(this._quad.bl.vertices.x, this._quad.bl.vertices.y),
1470                 cc.p(this._quad.br.vertices.x, this._quad.br.vertices.y),
1471                 cc.p(this._quad.tr.vertices.x, this._quad.tr.vertices.y),
1472                 cc.p(this._quad.tl.vertices.x, this._quad.tl.vertices.y)
1473             ];
1474             cc.drawingUtil.drawPoly(vertices, 4, true);
1475         }
1476     },
1477 
1478     _updateTransformForCanvas: function () {
1479         //cc.Assert(this._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode");
1480 
1481         // recaculate matrix only if it is dirty
1482         if (this._dirty) {
1483             // If it is not visible, or one of its ancestors is not visible, then do nothing:
1484             var locParent = this._parent;
1485             if (!this._visible || ( locParent && locParent != this._batchNode && locParent._shouldBeHidden)) {
1486                 this._shouldBeHidden = true;
1487             } else {
1488                 this._shouldBeHidden = false;
1489 
1490                 if (!locParent || locParent == this._batchNode) {
1491                     this._transformToBatch = this.nodeToParentTransform();
1492                 } else {
1493                     //cc.Assert(this._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite");
1494                     this._transformToBatch = cc.AffineTransformConcat(this.nodeToParentTransform(), locParent._transformToBatch);
1495                 }
1496             }
1497             this._recursiveDirty = false;
1498             this._dirty = false;
1499         }
1500 
1501         // recursively iterate over children
1502         if (this._hasChildren)
1503             this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform);
1504     },
1505 
1506     /**
1507      * Add child to sprite (override cc.Node )
1508      * @param {cc.Sprite} child
1509      * @param {Number} zOrder  child's zOrder
1510      * @param {String} tag child's tag
1511      * @override
1512      */
1513     addChild: null,
1514 
1515     _addChildForWebGL:function (child, zOrder, tag) {
1516         if(!child)
1517             throw "cc.Sprite.addChild(): child should be non-null";
1518         if (zOrder == null)
1519             zOrder = child._zOrder;
1520         if (tag == null)
1521             tag = child._tag;
1522 
1523         if (this._batchNode) {
1524             if(!(child instanceof cc.Sprite)){
1525                 cc.log("cc.Sprite.addChild(): cc.Sprite only supports cc.Sprites as children when using cc.SpriteBatchNode");
1526                 return;
1527             }
1528             if(child.getTexture()._webTextureObj !== this._textureAtlas.getTexture()._webTextureObj)
1529                 cc.log("cc.Sprite.addChild(): cc.Sprite only supports a sprite using same texture as children when using cc.SpriteBatchNode");
1530 
1531             //put it in descendants array of batch node
1532             this._batchNode.appendChild(child);
1533             if (!this._reorderChildDirty)
1534                 this._setReorderChildDirtyRecursively();
1535         }
1536 
1537         //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check
1538         cc.Node.prototype.addChild.call(this, child, zOrder, tag);
1539         this._hasChildren = true;
1540     },
1541 
1542     _addChildForCanvas: function (child, zOrder, tag) {
1543         if(!child)
1544             throw "cc.Sprite.addChild(): child should be non-null";
1545         if (zOrder == null)
1546             zOrder = child._zOrder;
1547         if (tag == null)
1548             tag = child._tag;
1549 
1550         //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check
1551         cc.Node.prototype.addChild.call(this, child, zOrder, tag);
1552         this._hasChildren = true;
1553     },
1554 
1555     /**
1556      * Update sprite's color
1557      */
1558     updateColor:function () {
1559         var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity;
1560         var color4 = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: locDisplayedOpacity};
1561         // special opacity for premultiplied textures
1562         if (this._opacityModifyRGB) {
1563             color4.r *= locDisplayedOpacity / 255.0;
1564             color4.g *= locDisplayedOpacity / 255.0;
1565             color4.b *= locDisplayedOpacity / 255.0;
1566         }
1567         var locQuad = this._quad;
1568         locQuad.bl.colors = color4;
1569         locQuad.br.colors = color4;
1570         locQuad.tl.colors = color4;
1571         locQuad.tr.colors = color4;
1572 
1573         // renders using Sprite Manager
1574         if (this._batchNode) {
1575             if (this._atlasIndex != cc.SPRITE_INDEX_NOT_INITIALIZED) {
1576                 this._textureAtlas.updateQuad(locQuad, this._atlasIndex)
1577             } else {
1578                 // no need to set it recursively
1579                 // update dirty_, don't update recursiveDirty_
1580                 //this.setDirty(true);
1581                 this._dirty = true;
1582             }
1583         }
1584         // self render
1585         // do nothing
1586         this._quadDirty = true;
1587     },
1588 
1589     /**
1590      * opacity setter
1591      * @param {Number} opacity
1592      */
1593     setOpacity:null,
1594 
1595     _setOpacityForWebGL: function (opacity) {
1596         cc.NodeRGBA.prototype.setOpacity.call(this, opacity);
1597         this.updateColor();
1598     },
1599 
1600     _setOpacityForCanvas: function (opacity) {
1601         cc.NodeRGBA.prototype.setOpacity.call(this, opacity);
1602         this._setNodeDirtyForCache();
1603     },
1604 
1605     /**
1606      * color setter
1607      * @param {cc.Color3B} color3
1608      */
1609     setColor: null,
1610 
1611     _setColorForWebGL: function (color3) {
1612         cc.NodeRGBA.prototype.setColor.call(this, color3);
1613         this.updateColor();
1614     },
1615 
1616     _setColorForCanvas: function (color3) {
1617         var curColor = this.getColor();
1618         if ((curColor.r === color3.r) && (curColor.g === color3.g) && (curColor.b === color3.b))
1619             return;
1620 
1621         cc.NodeRGBA.prototype.setColor.call(this, color3);
1622         this._changeTextureColor();
1623         this._setNodeDirtyForCache();
1624     },
1625 
1626     updateDisplayedColor: null,
1627 
1628     _updateDisplayedColorForWebGL: function (parentColor) {
1629         cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor);
1630         this.updateColor();
1631     },
1632 
1633     _updateDisplayedColorForCanvas: function (parentColor) {
1634         var oldColor = this.getColor();
1635         cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor);
1636         var newColor = this._displayedColor;
1637         if ((oldColor.r === newColor.r) && (oldColor.g === newColor.g) && (oldColor.b === newColor.b))
1638             return;
1639         this._changeTextureColor();
1640         this._setNodeDirtyForCache();
1641     },
1642 
1643     // Frames
1644     /**
1645      * Sets a new display frame to the cc.Sprite.
1646      * @param {cc.SpriteFrame} newFrame
1647      */
1648     setDisplayFrame: null,
1649 
1650     _setDisplayFrameForWebGL: function (newFrame) {
1651         this.setNodeDirty();
1652         var frameOffset = newFrame.getOffset();
1653         this._unflippedOffsetPositionFromCenter.x = frameOffset.x;
1654         this._unflippedOffsetPositionFromCenter.y = frameOffset.y;
1655 
1656         var pNewTexture = newFrame.getTexture();
1657         var locTextureLoaded = newFrame.textureLoaded();
1658         if (!locTextureLoaded) {
1659             this._textureLoaded = false;
1660             newFrame.addLoadedEventListener(function (sender) {
1661                 this._textureLoaded = true;
1662                 var locNewTexture = sender.getTexture();
1663                 if (locNewTexture != this._texture)
1664                     this.setTexture(locNewTexture);
1665                 this.setTextureRect(sender.getRect(), sender._rectRotated, sender.getOriginalSize());
1666                 this._callLoadedEventCallbacks();
1667             }, this);
1668         }
1669         // update texture before updating texture rect
1670         if (pNewTexture != this._texture)
1671             this.setTexture(pNewTexture);
1672 
1673         // update rect
1674         this._rectRotated = newFrame.isRotated();
1675         this.setTextureRect(newFrame.getRect(), this._rectRotated, newFrame.getOriginalSize());
1676     },
1677 
1678     _setDisplayFrameForCanvas: function (newFrame) {
1679         this.setNodeDirty();
1680 
1681         var frameOffset = newFrame.getOffset();
1682         this._unflippedOffsetPositionFromCenter.x = frameOffset.x;
1683         this._unflippedOffsetPositionFromCenter.y = frameOffset.y;
1684 
1685         // update rect
1686         this._rectRotated = newFrame.isRotated();
1687 
1688         var pNewTexture = newFrame.getTexture();
1689         var locTextureLoaded = newFrame.textureLoaded();
1690         if (!locTextureLoaded) {
1691             this._textureLoaded = false;
1692             newFrame.addLoadedEventListener(function (sender) {
1693                 this._textureLoaded = true;
1694                 var locNewTexture = sender.getTexture();
1695                 if (locNewTexture != this._texture)
1696                     this.setTexture(locNewTexture);
1697                 this.setTextureRect(sender.getRect(), this._rectRotated, sender.getOriginalSize());
1698                 this._callLoadedEventCallbacks();
1699             }, this);
1700         }
1701         // update texture before updating texture rect
1702         if (pNewTexture != this._texture)
1703             this.setTexture(pNewTexture);
1704 
1705         if (this._rectRotated)
1706             this._originalTexture = pNewTexture;
1707 
1708         this.setTextureRect(newFrame.getRect(), this._rectRotated, newFrame.getOriginalSize());
1709         this._colorized = false;
1710         if (locTextureLoaded) {
1711             var curColor = this.getColor();
1712             if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
1713                 this._changeTextureColor();
1714         }
1715     },
1716 
1717     /**
1718      * Returns whether or not a cc.SpriteFrame is being displayed
1719      * @param {cc.SpriteFrame} frame
1720      * @return {Boolean}
1721      */
1722     isFrameDisplayed: null,
1723 
1724     _isFrameDisplayedForWebGL: function (frame) {
1725         return (cc.rectEqualToRect(frame.getRect(), this._rect) && frame.getTexture().getName() == this._texture.getName()
1726             && cc.pointEqualToPoint(frame.getOffset(), this._unflippedOffsetPositionFromCenter));
1727     },
1728 
1729     _isFrameDisplayedForCanvas: function (frame) {
1730         if (frame.getTexture() != this._texture)
1731             return false;
1732         return cc.rectEqualToRect(frame.getRect(), this._rect);
1733     },
1734 
1735     /**
1736      * Returns the current displayed frame.
1737      * @return {cc.SpriteFrame}
1738      */
1739     displayFrame: function () {
1740         return cc.SpriteFrame.createWithTexture(this._texture,
1741             cc.RECT_POINTS_TO_PIXELS(this._rect),
1742             this._rectRotated,
1743             cc.POINT_POINTS_TO_PIXELS(this._unflippedOffsetPositionFromCenter),
1744             cc.SIZE_POINTS_TO_PIXELS(this._contentSize));
1745     },
1746 
1747     /**
1748      * Sets the batch node to sprite
1749      * @param {cc.SpriteBatchNode|null} spriteBatchNode
1750      * @example
1751      *  var batch = cc.SpriteBatchNode.create("Images/grossini_dance_atlas.png", 15);
1752      *  var sprite = cc.Sprite.createWithTexture(batch.getTexture(), cc.rect(0, 0, 57, 57));
1753      *  batch.addChild(sprite);
1754      *  layer.addChild(batch);
1755      */
1756     setBatchNode:null,
1757 
1758     _setBatchNodeForWebGL:function (spriteBatchNode) {
1759         this._batchNode = spriteBatchNode; // weak reference
1760 
1761         // self render
1762         if (!this._batchNode) {
1763             this._atlasIndex = cc.SPRITE_INDEX_NOT_INITIALIZED;
1764             this.setTextureAtlas(null);
1765             this._recursiveDirty = false;
1766             this.setDirty(false);
1767 
1768             var x1 = this._offsetPosition.x;
1769             var y1 = this._offsetPosition.y;
1770             var x2 = x1 + this._rect.width;
1771             var y2 = y1 + this._rect.height;
1772             var locQuad = this._quad;
1773             locQuad.bl.vertices = {x:x1, y:y1, z:0};
1774             locQuad.br.vertices = {x:x2, y:y1, z:0};
1775             locQuad.tl.vertices = {x:x1, y:y2, z:0};
1776             locQuad.tr.vertices = {x:x2, y:y2, z:0};
1777 
1778             this._quadDirty = true;
1779         } else {
1780             // using batch
1781             this._transformToBatch = cc.AffineTransformIdentity();
1782             this.setTextureAtlas(this._batchNode.getTextureAtlas()); // weak ref
1783         }
1784     },
1785 
1786     _setBatchNodeForCanvas:function (spriteBatchNode) {
1787         this._batchNode = spriteBatchNode; // weak reference
1788 
1789         // self render
1790         if (!this._batchNode) {
1791             this._atlasIndex = cc.SPRITE_INDEX_NOT_INITIALIZED;
1792             this.setTextureAtlas(null);
1793             this._recursiveDirty = false;
1794             this.setDirty(false);
1795         } else {
1796             // using batch
1797             this._transformToBatch = cc.AffineTransformIdentity();
1798             this.setTextureAtlas(this._batchNode.getTextureAtlas()); // weak ref
1799         }
1800     },
1801 
1802     // CCTextureProtocol
1803     /**
1804      * Texture of sprite setter
1805      * @param {cc.Texture2D} texture
1806      */
1807     setTexture: null,
1808 
1809     _setTextureForWebGL: function (texture) {
1810         // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet
1811         if(texture && !(texture instanceof cc.Texture2D))
1812             throw "cc.Sprite.setTexture(): setTexture expects a CCTexture2D. Invalid argument";
1813 
1814         // If batchnode, then texture id should be the same
1815         if(this._batchNode && this._batchNode.getTexture() != texture) {
1816             cc.log("cc.Sprite.setTexture(): Batched sprites should use the same texture as the batchnode");
1817             return;
1818         }
1819 
1820         if (texture)
1821             this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_TEXTURECOLOR));
1822         else
1823             this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_COLOR));
1824 
1825         if (!this._batchNode && this._texture != texture) {
1826             this._texture = texture;
1827             this._updateBlendFunc();
1828         }
1829     },
1830 
1831     _setTextureForCanvas: function (texture) {
1832         // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet
1833         if(texture && !(texture instanceof cc.Texture2D))
1834             throw "cc.Sprite.setTexture(): setTexture expects a CCTexture2D. Invalid argument";
1835 
1836         if (this._texture != texture) {
1837             if (texture && texture.getHtmlElementObj() instanceof  HTMLImageElement) {
1838                 this._originalTexture = texture;
1839             }
1840             this._texture = texture;
1841         }
1842     },
1843 
1844     // Texture protocol
1845     _updateBlendFunc:function () {
1846         if(this._batchNode){
1847             cc.log("cc.Sprite._updateBlendFunc(): _updateBlendFunc doesn't work when the sprite is rendered using a cc.CCSpriteBatchNode");
1848             return;
1849         }
1850 
1851         // it's possible to have an untextured sprite
1852         if (!this._texture || !this._texture.hasPremultipliedAlpha()) {
1853             this._blendFunc.src = gl.SRC_ALPHA;
1854             this._blendFunc.dst = gl.ONE_MINUS_SRC_ALPHA;
1855             this.setOpacityModifyRGB(false);
1856         } else {
1857             this._blendFunc.src = cc.BLEND_SRC;
1858             this._blendFunc.dst = cc.BLEND_DST;
1859             this.setOpacityModifyRGB(true);
1860         }
1861     },
1862 
1863     _changeTextureColor: function () {
1864         var locElement, locTexture = this._texture, locRect = this._textureRect_Canvas; //this.getTextureRect();
1865         if (locTexture && locRect.width > 0 && this._originalTexture) {
1866             locElement = locTexture.getHtmlElementObj();
1867             if (!locElement)
1868                 return;
1869 
1870             var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(this._originalTexture.getHtmlElementObj());
1871             if (cacheTextureForColor) {
1872                 this._colorized = true;
1873                 //generate color texture cache
1874                 if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor)
1875                     cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect, locElement);
1876                 else {
1877                     locElement = cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect);
1878                     locTexture = new cc.Texture2D();
1879                     locTexture.initWithElement(locElement);
1880                     locTexture.handleLoadedTexture();
1881                     this.setTexture(locTexture);
1882                 }
1883             }
1884         }
1885     },
1886 
1887     _setTextureCoords:function (rect) {
1888         rect = cc.RECT_POINTS_TO_PIXELS(rect);
1889 
1890         var tex = this._batchNode ? this._textureAtlas.getTexture() : this._texture;
1891         if (!tex)
1892             return;
1893 
1894         var atlasWidth = tex.getPixelsWide();
1895         var atlasHeight = tex.getPixelsHigh();
1896 
1897         var left, right, top, bottom, tempSwap, locQuad = this._quad;
1898         if (this._rectRotated) {
1899             if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
1900                 left = (2 * rect.x + 1) / (2 * atlasWidth);
1901                 right = left + (rect.height * 2 - 2) / (2 * atlasWidth);
1902                 top = (2 * rect.y + 1) / (2 * atlasHeight);
1903                 bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight);
1904             } else {
1905                 left = rect.x / atlasWidth;
1906                 right = (rect.x + rect.height) / atlasWidth;
1907                 top = rect.y / atlasHeight;
1908                 bottom = (rect.y + rect.width) / atlasHeight;
1909             }// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
1910 
1911             if (this._flippedX) {
1912                 tempSwap = top;
1913                 top = bottom;
1914                 bottom = tempSwap;
1915             }
1916 
1917             if (this._flippedY) {
1918                 tempSwap = left;
1919                 left = right;
1920                 right = tempSwap;
1921             }
1922 
1923             locQuad.bl.texCoords.u = left;
1924             locQuad.bl.texCoords.v = top;
1925             locQuad.br.texCoords.u = left;
1926             locQuad.br.texCoords.v = bottom;
1927             locQuad.tl.texCoords.u = right;
1928             locQuad.tl.texCoords.v = top;
1929             locQuad.tr.texCoords.u = right;
1930             locQuad.tr.texCoords.v = bottom;
1931         } else {
1932             if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
1933                 left = (2 * rect.x + 1) / (2 * atlasWidth);
1934                 right = left + (rect.width * 2 - 2) / (2 * atlasWidth);
1935                 top = (2 * rect.y + 1) / (2 * atlasHeight);
1936                 bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight);
1937             } else {
1938                 left = rect.x / atlasWidth;
1939                 right = (rect.x + rect.width) / atlasWidth;
1940                 top = rect.y / atlasHeight;
1941                 bottom = (rect.y + rect.height) / atlasHeight;
1942             } // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
1943 
1944             if (this._flippedX) {
1945                 tempSwap = left;
1946                 left = right;
1947                 right = tempSwap;
1948             }
1949 
1950             if (this._flippedY) {
1951                 tempSwap = top;
1952                 top = bottom;
1953                 bottom = tempSwap;
1954             }
1955 
1956             locQuad.bl.texCoords.u = left;
1957             locQuad.bl.texCoords.v = bottom;
1958             locQuad.br.texCoords.u = right;
1959             locQuad.br.texCoords.v = bottom;
1960             locQuad.tl.texCoords.u = left;
1961             locQuad.tl.texCoords.v = top;
1962             locQuad.tr.texCoords.u = right;
1963             locQuad.tr.texCoords.v = top;
1964         }
1965         this._quadDirty = true;
1966     },
1967     /**
1968      * draw sprite to canvas
1969      */
1970     draw: null,
1971 
1972     _drawForWebGL: function () {
1973         if (!this._textureLoaded)
1974             return;
1975 
1976         var gl = cc.renderContext, locTexture = this._texture;
1977         //cc.Assert(!this._batchNode, "If cc.Sprite is being rendered by cc.SpriteBatchNode, cc.Sprite#draw SHOULD NOT be called");
1978 
1979         if (locTexture) {
1980             if (locTexture._isLoaded) {
1981                 this._shaderProgram.use();
1982                 this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4();
1983 
1984                 cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst);
1985                 //optimize performance for javascript
1986                 cc.glBindTexture2DN(0, locTexture);                   // = cc.glBindTexture2D(locTexture);
1987                 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSCOLORTEX);
1988 
1989                 gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer);
1990                 if (this._quadDirty) {
1991                     gl.bufferData(gl.ARRAY_BUFFER, this._quad.arrayBuffer, gl.DYNAMIC_DRAW);
1992                     this._quadDirty = false;
1993                 }
1994                 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0);                   //cc.VERTEX_ATTRIB_POSITION
1995                 gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 24, 12);           //cc.VERTEX_ATTRIB_COLOR
1996                 gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 24, 16);                  //cc.VERTEX_ATTRIB_TEX_COORDS
1997 
1998                 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
1999             }
2000         } else {
2001             this._shaderProgram.use();
2002             this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4();
2003 
2004             cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst);
2005             cc.glBindTexture2D(null);
2006 
2007             cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR);
2008 
2009             gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer);
2010             if (this._quadDirty) {
2011                 cc.renderContext.bufferData(cc.renderContext.ARRAY_BUFFER, this._quad.arrayBuffer, cc.renderContext.STATIC_DRAW);
2012                 this._quadDirty = false;
2013             }
2014             gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0);
2015             gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12);
2016             gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
2017         }
2018         cc.g_NumberOfDraws++;
2019         if (cc.SPRITE_DEBUG_DRAW === 0)
2020             return;
2021 
2022         if (cc.SPRITE_DEBUG_DRAW === 1) {
2023             // draw bounding box
2024             var locQuad = this._quad;
2025             var verticesG1 = [
2026                 cc.p(locQuad.tl.vertices.x, locQuad.tl.vertices.y),
2027                 cc.p(locQuad.bl.vertices.x, locQuad.bl.vertices.y),
2028                 cc.p(locQuad.br.vertices.x, locQuad.br.vertices.y),
2029                 cc.p(locQuad.tr.vertices.x, locQuad.tr.vertices.y)
2030             ];
2031             cc.drawingUtil.drawPoly(verticesG1, 4, true);
2032         } else if (cc.SPRITE_DEBUG_DRAW === 2) {
2033             // draw texture box
2034             var drawSizeG2 = this.getTextureRect().size;
2035             var offsetPixG2 = this.getOffsetPosition();
2036             var verticesG2 = [cc.p(offsetPixG2.x, offsetPixG2.y), cc.p(offsetPixG2.x + drawSizeG2.width, offsetPixG2.y),
2037                 cc.p(offsetPixG2.x + drawSizeG2.width, offsetPixG2.y + drawSizeG2.height), cc.p(offsetPixG2.x, offsetPixG2.y + drawSizeG2.height)];
2038             cc.drawingUtil.drawPoly(verticesG2, 4, true);
2039         } // CC_SPRITE_DEBUG_DRAW
2040     },
2041 
2042     _drawForCanvas: function (ctx) {
2043         if (!this._textureLoaded)
2044             return;
2045 
2046         var context = ctx || cc.renderContext;
2047         if (this._isLighterMode)
2048             context.globalCompositeOperation = 'lighter';
2049 
2050         var locEGL_ScaleX = cc.EGLView.getInstance().getScaleX(), locEGL_ScaleY = cc.EGLView.getInstance().getScaleY();
2051 
2052         context.globalAlpha = this._displayedOpacity / 255;
2053         var locRect = this._rect, locContentSize = this._contentSize, locOffsetPosition = this._offsetPosition, locDrawSizeCanvas = this._drawSize_Canvas;
2054         var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = this._textureRect_Canvas;
2055         locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX;
2056         locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY;
2057 
2058         if (this._flippedX || this._flippedY) {
2059             context.save();
2060             if (this._flippedX) {
2061                 flipXOffset = -locOffsetPosition.x - locRect.width;
2062                 context.scale(-1, 1);
2063             }
2064             if (this._flippedY) {
2065                 flipYOffset = locOffsetPosition.y;
2066                 context.scale(1, -1);
2067             }
2068         }
2069 
2070         flipXOffset *= locEGL_ScaleX;
2071         flipYOffset *= locEGL_ScaleY;
2072 
2073         if (this._texture && locTextureCoord.width > 0) {
2074             var image = this._texture.getHtmlElementObj();
2075             if (this._colorized) {
2076                 context.drawImage(image,
2077                     0, 0, locTextureCoord.width, locTextureCoord.height,
2078                     flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height);
2079             } else {
2080                 context.drawImage(image,
2081                     locTextureCoord.x, locTextureCoord.y, locTextureCoord.width,  locTextureCoord.height,
2082                     flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height);
2083             }
2084         } else if (locContentSize.width !== 0) {
2085             var curColor = this.getColor();
2086             context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)";
2087             context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY);
2088         }
2089 
2090         if (cc.SPRITE_DEBUG_DRAW === 1) {
2091             // draw bounding box
2092             context.strokeStyle = "rgba(0,255,0,1)";
2093             flipXOffset /= locEGL_ScaleX;
2094             flipYOffset /= locEGL_ScaleY;
2095             flipYOffset = -flipYOffset;
2096             var vertices1 = [cc.p(flipXOffset, flipYOffset),
2097                 cc.p(flipXOffset + locRect.width, flipYOffset),
2098                 cc.p(flipXOffset + locRect.width, flipYOffset - locRect.height),
2099                 cc.p(flipXOffset, flipYOffset - locRect.height)];
2100             cc.drawingUtil.drawPoly(vertices1, 4, true);
2101         } else if (cc.SPRITE_DEBUG_DRAW === 2) {
2102             // draw texture box
2103             context.strokeStyle = "rgba(0,255,0,1)";
2104             var drawSize = this._rect.size;
2105             flipYOffset = -flipYOffset;
2106             var vertices2 = [cc.p(flipXOffset, flipYOffset), cc.p(flipXOffset + drawSize.width, flipYOffset),
2107                 cc.p(flipXOffset + drawSize.width, flipYOffset - drawSize.height), cc.p(flipXOffset, flipYOffset - drawSize.height)];
2108             cc.drawingUtil.drawPoly(vertices2, 4, true);
2109         }
2110         if (this._flippedX || this._flippedY)
2111             context.restore();
2112         cc.g_NumberOfDraws++;
2113     }
2114 });
2115 
2116 if(cc.Browser.supportWebGL){
2117     cc.Sprite.prototype._spriteFrameLoadedCallback = cc.Sprite.prototype._spriteFrameLoadedCallbackForWebGL;
2118     cc.Sprite.prototype.setOpacityModifyRGB = cc.Sprite.prototype._setOpacityModifyRGBForWebGL;
2119     cc.Sprite.prototype.updateDisplayedOpacity = cc.Sprite.prototype._updateDisplayedOpacityForWebGL;
2120     cc.Sprite.prototype.ctor = cc.Sprite.prototype._ctorForWebGL;
2121     cc.Sprite.prototype.setBlendFunc = cc.Sprite.prototype._setBlendFuncForWebGL;
2122     cc.Sprite.prototype.init = cc.Sprite.prototype._initForWebGL;
2123     cc.Sprite.prototype.initWithTexture = cc.Sprite.prototype._initWithTextureForWebGL;
2124     cc.Sprite.prototype._textureLoadedCallback = cc.Sprite.prototype._textureLoadedCallbackForWebGL;
2125     cc.Sprite.prototype.setTextureRect = cc.Sprite.prototype._setTextureRectForWebGL;
2126     cc.Sprite.prototype.updateTransform = cc.Sprite.prototype._updateTransformForWebGL;
2127     cc.Sprite.prototype.addChild = cc.Sprite.prototype._addChildForWebGL;
2128     cc.Sprite.prototype.setOpacity = cc.Sprite.prototype._setOpacityForWebGL;
2129     cc.Sprite.prototype.setColor = cc.Sprite.prototype._setColorForWebGL;
2130     cc.Sprite.prototype.updateDisplayedColor = cc.Sprite.prototype._updateDisplayedColorForWebGL;
2131     cc.Sprite.prototype.setDisplayFrame = cc.Sprite.prototype._setDisplayFrameForWebGL;
2132     cc.Sprite.prototype.isFrameDisplayed = cc.Sprite.prototype._isFrameDisplayedForWebGL;
2133     cc.Sprite.prototype.setBatchNode = cc.Sprite.prototype._setBatchNodeForWebGL;
2134     cc.Sprite.prototype.setTexture = cc.Sprite.prototype._setTextureForWebGL;
2135     cc.Sprite.prototype.draw = cc.Sprite.prototype._drawForWebGL;
2136 }else{
2137     cc.Sprite.prototype._spriteFrameLoadedCallback = cc.Sprite.prototype._spriteFrameLoadedCallbackForCanvas;
2138     cc.Sprite.prototype.setOpacityModifyRGB = cc.Sprite.prototype._setOpacityModifyRGBForCanvas;
2139     cc.Sprite.prototype.updateDisplayedOpacity = cc.Sprite.prototype._updateDisplayedOpacityForCanvas;
2140     cc.Sprite.prototype.ctor = cc.Sprite.prototype._ctorForCanvas;
2141     cc.Sprite.prototype.setBlendFunc = cc.Sprite.prototype._setBlendFuncForCanvas;
2142     cc.Sprite.prototype.init = cc.Sprite.prototype._initForCanvas;
2143     cc.Sprite.prototype.initWithTexture = cc.Sprite.prototype._initWithTextureForCanvas;
2144     cc.Sprite.prototype._textureLoadedCallback = cc.Sprite.prototype._textureLoadedCallbackForCanvas;
2145     cc.Sprite.prototype.setTextureRect = cc.Sprite.prototype._setTextureRectForCanvas;
2146     cc.Sprite.prototype.updateTransform = cc.Sprite.prototype._updateTransformForCanvas;
2147     cc.Sprite.prototype.addChild = cc.Sprite.prototype._addChildForCanvas;
2148     cc.Sprite.prototype.setOpacity = cc.Sprite.prototype._setOpacityForCanvas;
2149     cc.Sprite.prototype.setColor = cc.Sprite.prototype._setColorForCanvas;
2150     cc.Sprite.prototype.updateDisplayedColor = cc.Sprite.prototype._updateDisplayedColorForCanvas;
2151     cc.Sprite.prototype.setDisplayFrame = cc.Sprite.prototype._setDisplayFrameForCanvas;
2152     cc.Sprite.prototype.isFrameDisplayed = cc.Sprite.prototype._isFrameDisplayedForCanvas;
2153     cc.Sprite.prototype.setBatchNode = cc.Sprite.prototype._setBatchNodeForCanvas;
2154     cc.Sprite.prototype.setTexture = cc.Sprite.prototype._setTextureForCanvas;
2155     cc.Sprite.prototype.draw = cc.Sprite.prototype._drawForCanvas;
2156 }
2157 
2158 /**
2159  * <p>
2160  *     Creates a sprite with an exsiting texture contained in a CCTexture2D object                           <br/>
2161  *     After creation, the rect will be the size of the texture, and the offset will be (0,0).
2162  * </p>
2163  * @constructs
2164  * @param {cc.Texture2D} texture  A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites.
2165  * @param {cc.Rect} rect Only the contents inside the rect of this texture will be applied for this sprite.
2166  * @return {cc.Sprite} A valid sprite object
2167  * @example
2168  * //get an image
2169  * var img = cc.TextureCache.getInstance().addImage("HelloHTML5World.png");
2170  *
2171  * //create a sprite with texture
2172  * var sprite1 = cc.Sprite.createWithTexture(img);
2173  *
2174  * //create a sprite with texture and rect
2175  * var sprite2 = cc.Sprite.createWithTexture(img, cc.rect(0,0,480,320));
2176  *
2177  */
2178 cc.Sprite.createWithTexture = function (texture, rect) {
2179     var argnum = arguments.length;
2180     var sprite = new cc.Sprite();
2181     switch (argnum) {
2182         case 1:
2183             /** Creates an sprite with a texture.
2184              The rect used will be the size of the texture.
2185              The offset will be (0,0).
2186              */
2187             if (sprite && sprite.initWithTexture(texture))
2188                 return sprite;
2189             return null;
2190             break;
2191 
2192         case 2:
2193             /** Creates an sprite with a texture and a rect.
2194              The offset will be (0,0).
2195              */
2196             if (sprite && sprite.initWithTexture(texture, rect))
2197                 return sprite;
2198             return null;
2199             break;
2200 
2201         default:
2202             throw "Sprite.createWithTexture(): Argument must be non-nil ";
2203             break;
2204     }
2205 };
2206 
2207 /**
2208  * Create a sprite with filename and rect
2209  * @constructs
2210  * @param {String} fileName  The string which indicates a path to image file, e.g., "scene1/monster.png".
2211  * @param {cc.Rect} rect  Only the contents inside rect of pszFileName's texture will be applied for this sprite.
2212  * @return {cc.Sprite} A valid sprite object
2213  * @example
2214  * //create a sprite with filename
2215  * var sprite1 = cc.Sprite.create("HelloHTML5World.png");
2216  *
2217  * //create a sprite with filename and rect
2218  * var sprite2 = cc.Sprite.create("HelloHTML5World.png",cc.rect(0,0,480,320));
2219  */
2220 cc.Sprite.create = function (fileName, rect) {
2221     var argnum = arguments.length;
2222     var sprite = new cc.Sprite();
2223     if (argnum === 0) {
2224         if (sprite.init())
2225             return sprite;
2226     } else {
2227         /** Creates an sprite with an image filename.
2228          If the rect equal undefined, the rect used will be the size of the image.
2229          The offset will be (0,0).
2230          */
2231         if (sprite && sprite.init(fileName, rect))
2232             return sprite;
2233     }
2234     return null;
2235 };
2236 
2237 /**
2238  * <p>
2239  *     Creates a sprite with a sprite frame.                                                                  <br/>
2240  *                                                                                                            <br/>
2241  *    A CCSpriteFrame will be fetched from the CCSpriteFrameCache by pszSpriteFrameName param.                <br/>
2242  *    If the CCSpriteFrame doesn't exist it will raise an exception.
2243  * </p>
2244  * @param {String} spriteFrameName A sprite frame which involves a texture and a rect
2245  * @return {cc.Sprite} A valid sprite object
2246  * @example
2247  *
2248  * //create a sprite with a sprite frame
2249  * var sprite = cc.Sprite.createWithSpriteFrameName('grossini_dance_01.png');
2250  */
2251 cc.Sprite.createWithSpriteFrameName = function (spriteFrameName) {
2252     var spriteFrame = null;
2253     if (typeof(spriteFrameName) == 'string') {
2254         spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName);
2255         if (!spriteFrame) {
2256             cc.log("Invalid spriteFrameName: " + spriteFrameName);
2257             return null;
2258         }
2259     } else {
2260         cc.log("Invalid argument. Expecting string.");
2261         return null;
2262     }
2263     var sprite = new cc.Sprite();
2264     if (sprite && sprite.initWithSpriteFrame(spriteFrame)) {
2265         return sprite;
2266     }
2267     return null;
2268 };
2269 
2270 /**
2271  * <p>
2272  *     Creates a sprite with a sprite frame.                                                                  <br/>
2273  *                                                                                                            <br/>
2274  *    A CCSpriteFrame will be fetched from the CCSpriteFrameCache by pszSpriteFrameName param.                <br/>
2275  *    If the CCSpriteFrame doesn't exist it will raise an exception.
2276  * </p>
2277  * @param {cc.SpriteFrame} spriteFrame A sprite frame which involves a texture and a rect
2278  * @return {cc.Sprite} A valid sprite object
2279  * @example
2280  * //get a sprite frame
2281  * var spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame("grossini_dance_01.png");
2282  *
2283  * //create a sprite with a sprite frame
2284  * var sprite = cc.Sprite.createWithSpriteFrame(spriteFrame);
2285  */
2286 cc.Sprite.createWithSpriteFrame = function (spriteFrame) {
2287     var sprite = new cc.Sprite();
2288     if (sprite && sprite.initWithSpriteFrame(spriteFrame)) {
2289         return sprite;
2290     }
2291     return null;
2292 };
2293