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