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