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