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  * generate texture's cache for texture tint
 29  * @function
 30  * @param {HTMLImageElement} texture
 31  * @return {Array}
 32  */
 33 
 34 cc.generateTextureCacheForColor = function (texture) {
 35     if (texture.channelCache) {
 36         return texture.channelCache;
 37     }
 38 
 39     var textureCache = [
 40         cc.newElement("canvas"),
 41         cc.newElement("canvas"),
 42         cc.newElement("canvas"),
 43         cc.newElement("canvas")
 44     ];
 45 
 46     function renderToCache() {
 47         var ref = cc.generateTextureCacheForColor;
 48 
 49         var w = texture.width;
 50         var h = texture.height;
 51 
 52         textureCache[0].width = w;
 53         textureCache[0].height = h;
 54         textureCache[1].width = w;
 55         textureCache[1].height = h;
 56         textureCache[2].width = w;
 57         textureCache[2].height = h;
 58         textureCache[3].width = w;
 59         textureCache[3].height = h;
 60 
 61         ref.canvas.width = w;
 62         ref.canvas.height = h;
 63 
 64         var ctx = ref.canvas.getContext("2d");
 65         ctx.drawImage(texture, 0, 0);
 66 
 67         ref.tempCanvas.width = w;
 68         ref.tempCanvas.height = h;
 69 
 70         var pixels = ctx.getImageData(0, 0, w, h).data;
 71 
 72         for (var rgbI = 0; rgbI < 4; rgbI++) {
 73             var cacheCtx = textureCache[rgbI].getContext('2d');
 74             cacheCtx.getImageData(0, 0, w, h).data;
 75             ref.tempCtx.drawImage(texture, 0, 0);
 76 
 77             var to = ref.tempCtx.getImageData(0, 0, w, h);
 78             var toData = to.data;
 79 
 80             for (var i = 0; i < pixels.length; i += 4) {
 81                 toData[i  ] = (rgbI === 0) ? pixels[i  ] : 0;
 82                 toData[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0;
 83                 toData[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0;
 84                 toData[i + 3] = pixels[i + 3];
 85             }
 86             cacheCtx.putImageData(to, 0, 0);
 87         }
 88         texture.onload = null;
 89     }
 90 
 91     try {
 92         renderToCache();
 93     } catch (e) {
 94         texture.onload = renderToCache;
 95     }
 96 
 97     texture.channelCache = textureCache;
 98     return textureCache;
 99 };
100 
101 cc.generateTextureCacheForColor.canvas = cc.newElement('canvas');
102 cc.generateTextureCacheForColor.tempCanvas = cc.newElement('canvas');
103 cc.generateTextureCacheForColor.tempCtx = cc.generateTextureCacheForColor.tempCanvas.getContext('2d');
104 
105 /**
106  * generate tinted texture
107  * source-in: Where source and destination overlaps and both are opaque, the source is displayed.
108  * Everywhere else transparency is displayed.
109  * @function
110  * @param {HTMLImageElement} texture
111  * @param {cc.Color} color
112  * @param {cc.Rect} rect
113  * @return {HTMLCanvasElement}
114  */
115 cc.generateTintImage2 = function (texture, color, rect) {
116     if (!rect) {
117         rect = cc.rect(0, 0, texture.width, texture.height);
118         rect = cc.rectPixelsToPoints(rect);
119     }
120 
121     var buff = cc.newElement("canvas");
122     var ctx = buff.getContext("2d");
123 
124     if (buff.width != rect.width) buff.width = rect.width;
125     if (buff.height != rect.height) buff.height = rect.height;
126     ctx.save();
127 
128     ctx.drawImage(texture, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height);
129 
130     ctx.globalCompositeOperation = "source-in";
131     ctx.globalAlpha = color.a / 255.0;
132     ctx.fillStyle = "rgb(" + color.r + "," + color.g + "," + color.b + ")";
133     ctx.fillRect(0, 0, rect.width, rect.height);
134     ctx.restore();
135 
136     return buff;
137 };
138 
139 /**
140  * generate tinted texture
141  * lighter:    The source and destination colors are added to each other, resulting in brighter colors,
142  * moving towards color values of 1 (maximum brightness for that color).
143  * @function
144  * @param {HTMLImageElement} texture
145  * @param {Array} tintedImgCache
146  * @param {cc.Color} color
147  * @param {cc.Rect} rect
148  * @param {HTMLCanvasElement} [renderCanvas]
149  * @return {HTMLCanvasElement}
150  */
151 cc.generateTintImage = function (texture, tintedImgCache, color, rect, renderCanvas) {
152     if (!rect)
153         rect = cc.rect(0, 0, texture.width, texture.height);
154 
155     var r = color.r / 255;
156     var g = color.g / 255;
157     var b = color.b / 255;
158 
159     var w = Math.min(rect.width, tintedImgCache[0].width);
160     var h = Math.min(rect.height, tintedImgCache[0].height);
161     var buff = renderCanvas;
162     var ctx;
163 
164     // Create a new buffer if required
165     if (!buff) {
166         buff = cc.newElement("canvas");
167         buff.width = w;
168         buff.height = h;
169         ctx = buff.getContext("2d");
170     } else {
171         ctx = buff.getContext("2d");
172         ctx.clearRect(0, 0, w, h);
173     }
174 
175     ctx.save();
176     ctx.globalCompositeOperation = 'lighter';
177 
178     // Make sure to keep the renderCanvas alpha in mind in case of overdraw
179     var a = ctx.globalAlpha;
180     if (r > 0) {
181         ctx.globalAlpha = r * a;
182         ctx.drawImage(tintedImgCache[0], rect.x, rect.y, w, h, 0, 0, w, h);
183     }
184     if (g > 0) {
185         ctx.globalAlpha = g * a;
186         ctx.drawImage(tintedImgCache[1], rect.x, rect.y, w, h, 0, 0, w, h);
187     }
188     if (b > 0) {
189         ctx.globalAlpha = b * a;
190         ctx.drawImage(tintedImgCache[2], rect.x, rect.y, w, h, 0, 0, w, h);
191     }
192 
193     if (r + g + b < 1) {
194         ctx.globalAlpha = a;
195         ctx.drawImage(tintedImgCache[3], rect.x, rect.y, w, h, 0, 0, w, h);
196     }
197 
198     ctx.restore();
199     return buff;
200 };
201 
202 cc.cutRotateImageToCanvas = function (texture, rect) {
203     if (!texture)
204         return null;
205 
206     if (!rect)
207         return texture;
208 
209     var nCanvas = cc.newElement("canvas");
210     nCanvas.width = rect.width;
211     nCanvas.height = rect.height;
212 
213     var ctx = nCanvas.getContext("2d");
214     ctx.translate(nCanvas.width / 2, nCanvas.height / 2);
215     ctx.rotate(-1.5707963267948966);
216     ctx.drawImage(texture, rect.x, rect.y, rect.height, rect.width, -rect.height / 2, -rect.width / 2, rect.height, rect.width);
217     return nCanvas;
218 };
219 
220 /**
221  * <p>cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) )  <br/>
222  *
223  * cc.Sprite can be created with an image, or with a sub-rectangle of an image.  <br/>
224  *
225  * If the parent or any of its ancestors is a cc.SpriteBatchNode then the following features/limitations are valid   <br/>
226  *    - Features when the parent is a cc.BatchNode: <br/>
227  *        - MUCH faster rendering, specially if the cc.SpriteBatchNode has many children. All the children will be drawn in a single batch.  <br/>
228  *
229  *    - Limitations   <br/>
230  *        - Camera is not supported yet (eg: CCOrbitCamera action doesn't work)  <br/>
231  *        - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl) <br/>
232  *        - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property.  <br/>
233  *        - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property. <br/>
234  *        - Parallax scroller is not supported, but can be simulated with a "proxy" sprite.        <br/>
235  *
236  *  If the parent is an standard cc.Node, then cc.Sprite behaves like any other cc.Node:      <br/>
237  *    - It supports blending functions    <br/>
238  *    - It supports aliasing / antialiasing    <br/>
239  *    - But the rendering will be slower: 1 draw per children.   <br/>
240  *
241  * The default anchorPoint in cc.Sprite is (0.5, 0.5). </p>
242  * @class
243  * @extends cc.NodeRGBA
244  *
245  * @property {Boolean}              dirty               - Indicates whether the sprite needs to be updated.
246  * @property {Boolean}              flippedX            - Indicates whether or not the spirte is flipped on x axis.
247  * @property {Boolean}              flippedY            - Indicates whether or not the spirte is flipped on y axis.
248  * @property {Number}               offsetX             - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex.
249  * @property {Number}               offsetY             - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex.
250  * @property {Number}               atlasIndex          - The index used on the TextureAtlas.
251  * @property {cc.Texture2D}         texture             - Texture used to render the sprite.
252  * @property {Boolean}              textureRectRotated  - <@readonly> Indicate whether the texture rectangle is rotated.
253  * @property {cc.TextureAtlas}      textureAtlas        - The weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode.
254  * @property {cc.SpriteBatchNode}   batchNode           - The batch node object if this sprite is rendered by cc.SpriteBatchNode.
255  * @property {cc.V3F_C4B_T2F_Quad}  quad                - <@readonly> The quad (tex coords, vertex coords and color) information.
256  *
257  * @example
258  * var aSprite = new cc.Sprite();
259  * aSprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320));
260  */
261 cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{
262     RGBAProtocol:true,
263 	dirty:false,
264 	atlasIndex:0,
265     textureAtlas:null,
266 
267     _batchNode:null,
268     _recursiveDirty:null, //Whether all of the sprite's children needs to be updated
269     _hasChildren:null, //Whether the sprite contains children
270     _shouldBeHidden:false, //should not be drawn because one of the ancestors is not visible
271     _transformToBatch:null,
272 
273     //
274     // Data used when the sprite is self-rendered
275     //
276     _blendFunc:null, //It's required for CCTextureProtocol inheritance
277     _texture:null, //cc.Texture2D object that is used to render the sprite
278 
279     //
280     // Shared data
281     //
282     // texture
283     _rect:null, //Retangle of cc.Texture2D
284     _rectRotated:false, //Whether the texture is rotated
285 
286     // Offset Position (used by Zwoptex)
287     _offsetPosition:null, // absolute
288     _unflippedOffsetPositionFromCenter:null,
289 
290     _opacityModifyRGB:false,
291 
292     // image is flipped
293     _flippedX:false, //Whether the sprite is flipped horizontally or not.
294     _flippedY:false, //Whether the sprite is flipped vertically or not.
295 
296     _textureLoaded:false,
297     _loadedEventListeners: null,
298     _newTextureWhenChangeColor: null,         //hack property for LabelBMFont
299     _className:"Sprite",
300 
301     textureLoaded:function(){
302         return this._textureLoaded;
303     },
304 
305     addLoadedEventListener:function(callback, target){
306         if(!this._loadedEventListeners)
307             this._loadedEventListeners = [];
308         this._loadedEventListeners.push({eventCallback:callback, eventTarget:target});
309     },
310 
311     _callLoadedEventCallbacks:function(){
312         if(!this._loadedEventListeners)
313             return;
314         var locListeners = this._loadedEventListeners;
315         for(var i = 0, len = locListeners.length;  i < len; i++){
316             var selCallback = locListeners[i];
317             selCallback.eventCallback.call(selCallback.eventTarget, this);
318         }
319         locListeners.length = 0;
320     },
321 
322     /**
323      * Whether or not the Sprite needs to be updated in the Atlas
324      * @return {Boolean} true if the sprite needs to be updated in the Atlas, false otherwise.
325      */
326     isDirty:function () {
327         return this.dirty;
328     },
329 
330     /**
331      * Makes the Sprite to be updated in the Atlas.
332      * @param {Boolean} bDirty
333      */
334     setDirty:function (bDirty) {
335         this.dirty = bDirty;
336     },
337 
338     /**
339      * Returns whether or not the texture rectangle is rotated.
340      * @return {Boolean}
341      */
342     isTextureRectRotated:function () {
343         return this._rectRotated;
344     },
345 
346     /**
347      * Returns the index used on the TextureAtlas.
348      * @return {Number}
349      */
350     getAtlasIndex:function () {
351         return this.atlasIndex;
352     },
353 
354     /**
355      * Set the index used on the TextureAtlas.
356      * @warning Don't modify this value unless you know what you are doing
357      * @param {Number} atlasIndex
358      */
359     setAtlasIndex:function (atlasIndex) {
360         this.atlasIndex = atlasIndex;
361     },
362 
363     /**
364      * returns the rect of the cc.Sprite in points
365      * @return {cc.Rect}
366      */
367     getTextureRect:function () {
368         return cc.rect(this._rect.x, this._rect.y, this._rect.width, this._rect.height);
369     },
370 
371     /**
372      * Gets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
373      * @return {cc.TextureAtlas}
374      */
375     getTextureAtlas:function () {
376         return this.textureAtlas;
377     },
378 
379     /**
380      * Sets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
381      * @param {cc.TextureAtlas} textureAtlas
382      */
383     setTextureAtlas:function (textureAtlas) {
384         this.textureAtlas = textureAtlas;
385     },
386 
387     /**
388      * Gets the offset position of the sprite. Calculated automatically by editors like Zwoptex.
389      * @return {cc.Point}
390      */
391     getOffsetPosition:function () {
392         return this._offsetPosition;
393     },
394 
395 	_getOffsetX: function () {
396 		return this._offsetPosition.x;
397 	},
398 	_getOffsetY: function () {
399 		return this._offsetPosition.y;
400 	},
401 
402     /**
403      * conforms to cc.TextureProtocol protocol
404      * @return {cc.BlendFunc}
405      */
406     getBlendFunc:function () {
407         return this._blendFunc;
408     },
409 
410     /**
411      * Initializes a sprite with an SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite
412      * @param {cc.SpriteFrame} spriteFrame A CCSpriteFrame object. It should includes a valid texture and a rect
413      * @return {Boolean}  true if the sprite is initialized properly, false otherwise.
414      * @example
415      * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png");
416      * var sprite = new cc.Sprite();
417      * sprite.initWithSpriteFrame(spriteFrame);
418      */
419     initWithSpriteFrame:function (spriteFrame) {
420 
421         cc.assert(spriteFrame, cc._LogInfos.Sprite_initWithSpriteFrame);
422 
423         if(!spriteFrame.textureLoaded()){
424             //add event listener
425             this._textureLoaded = false;
426             spriteFrame.addLoadedEventListener(this._spriteFrameLoadedCallback, this);
427         }
428         var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect());
429         this.setSpriteFrame(spriteFrame);
430 
431         return ret;
432     },
433 
434     _spriteFrameLoadedCallback:null,
435 
436     /**
437      * Initializes a sprite with a sprite frame name. <br/>
438      * A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name.  <br/>
439      * If the cc.SpriteFrame doesn't exist it will raise an exception. <br/>
440      * @param {String} spriteFrameName A key string that can fected a volid cc.SpriteFrame from cc.SpriteFrameCache
441      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
442      * @example
443      * var sprite = new cc.Sprite();
444      * sprite.initWithSpriteFrameName("grossini_dance_01.png");
445      */
446     initWithSpriteFrameName:function (spriteFrameName) {
447         cc.assert(spriteFrameName, cc._LogInfos.Sprite_initWithSpriteFrameName);
448         var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName);
449         cc.assert(frame, spriteFrameName + cc._LogInfos.Sprite_initWithSpriteFrameName1);
450         return this.initWithSpriteFrame(frame);
451     },
452 
453     /**
454      * tell the sprite to use batch node render.
455      * @param {cc.SpriteBatchNode} batchNode
456      */
457     useBatchNode:function (batchNode) {
458         this.textureAtlas = batchNode.textureAtlas; // weak ref
459         this._batchNode = batchNode;
460     },
461 
462     /**
463      * <p>
464      *    set the vertex rect.<br/>
465      *    It will be called internally by setTextureRect.                           <br/>
466      *    Useful if you want to create 2x images from SD images in Retina Display.  <br/>
467      *    Do not call it manually. Use setTextureRect instead.  <br/>
468      *    (override this method to generate "double scale" sprites)
469      * </p>
470      * @param {cc.Rect} rect
471      */
472     setVertexRect:function (rect) {
473         this._rect.x = rect.x;
474         this._rect.y = rect.y;
475         this._rect.width = rect.width;
476         this._rect.height = rect.height;
477     },
478 
479     sortAllChildren:function () {
480         if (this._reorderChildDirty) {
481             var j, tempItem, locChildren = this._children, tempChild;
482             for (var i = 1; i < locChildren.length; i++) {
483                 tempItem = locChildren[i];
484                 j = i - 1;
485                 tempChild =  locChildren[j];
486 
487                 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller
488                 while (j >= 0 && ( tempItem._localZOrder < tempChild._localZOrder ||
489                     ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) {
490                     locChildren[j + 1] = tempChild;
491                     j = j - 1;
492                     tempChild =  locChildren[j];
493                 }
494                 locChildren[j + 1] = tempItem;
495             }
496 
497             if (this._batchNode) {
498                 this._arrayMakeObjectsPerformSelector(locChildren, cc.Node.StateCallbackType.sortAllChildren);
499             }
500             this._reorderChildDirty = false;
501         }
502     },
503 
504     /**
505      * Reorders a child according to a new z value.  (override cc.Node )
506      * @param {cc.Node} child
507      * @param {Number} zOrder
508      * @override
509      */
510     reorderChild:function (child, zOrder) {
511 
512         cc.assert(child, cc._LogInfos.Sprite_reorderChild_2);
513 
514         if(this._children.indexOf(child) === -1){
515             cc.log(cc._LogInfos.Sprite_reorderChild);
516             return;
517         }
518 
519         if (zOrder === child.zIndex)
520             return;
521 
522         if (this._batchNode && !this._reorderChildDirty) {
523             this._setReorderChildDirtyRecursively();
524             this._batchNode.reorderBatch(true);
525         }
526         cc.Node.prototype.reorderChild.call(this, child, zOrder);
527     },
528 
529     /**
530      * Removes a child from the sprite. (override cc.Node )
531      * @param child
532      * @param cleanup  whether or not cleanup all running actions
533      * @override
534      */
535     removeChild:function (child, cleanup) {
536         if (this._batchNode)
537             this._batchNode.removeSpriteFromAtlas(child);
538         cc.Node.prototype.removeChild.call(this, child, cleanup);
539     },
540 
541     /**
542      * Removes all children from the container  (override cc.Node )
543      * @param cleanup whether or not cleanup all running actions
544      * @override
545      */
546     removeAllChildren:function (cleanup) {
547         var locChildren = this._children, locBatchNode = this._batchNode;
548         if (locBatchNode && locChildren != null) {
549             for (var i = 0, len = locChildren.length; i < len; i++)
550                 locBatchNode.removeSpriteFromAtlas(locChildren[i]);
551         }
552 
553         cc.Node.prototype.removeAllChildren.call(this, cleanup);
554         this._hasChildren = false;
555     },
556 
557     //
558     // cc.Node property overloads
559     //
560 
561 	/**
562 	 * set Recursively is or isn't Dirty
563 	 * used only when parent is cc.SpriteBatchNode
564 	 * @param {Boolean} value
565 	 */
566 	setDirtyRecursively:function (value) {
567 		this._recursiveDirty = value;
568 		this.dirty = value;
569 		// recursively set dirty
570 		var locChildren = this._children, child, l = locChildren ? locChildren.length : 0;
571 		for (var i = 0; i < l; i++) {
572 			child = locChildren[i];
573 			(child instanceof cc.Sprite) && child.setDirtyRecursively(true);
574 		}
575 	},
576 
577 	/**
578 	 * Make the node dirty
579 	 * @param {Boolean} norecursive When true children will not be set dirty recursively, by default, they will be.
580 	 * @override
581 	 */
582 	setNodeDirty: function(norecursive) {
583 		cc.Node.prototype.setNodeDirty.call(this);
584 		// Lazy set dirty
585 		if (!norecursive && this._batchNode && !this._recursiveDirty) {
586 			if (this._hasChildren)
587 				this.setDirtyRecursively(true);
588 			else {
589 				this._recursiveDirty = true;
590 				this.dirty = true;
591 			}
592 		}
593 	},
594 
595     /**
596      * IsRelativeAnchorPoint setter  (override cc.Node )
597      * @param {Boolean} relative
598      * @override
599      */
600     ignoreAnchorPointForPosition:function (relative) {
601         if(this._batchNode){
602             cc.log(cc._LogInfos.Sprite_ignoreAnchorPointForPosition);
603             return;
604         }
605         cc.Node.prototype.ignoreAnchorPointForPosition.call(this, relative);
606     },
607 
608     /**
609      * Sets whether the sprite should be flipped horizontally or not.
610      * @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise.
611      */
612     setFlippedX:function (flippedX) {
613         if (this._flippedX != flippedX) {
614             this._flippedX = flippedX;
615             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
616             this.setNodeDirty(true);
617         }
618     },
619 
620     /**
621      * Sets whether the sprite should be flipped vertically or not.
622      * @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise.
623      */
624     setFlippedY:function (flippedY) {
625         if (this._flippedY != flippedY) {
626             this._flippedY = flippedY;
627             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
628             this.setNodeDirty(true);
629         }
630     },
631 
632     /**
633      * <p>
634      *     Returns the flag which indicates whether the sprite is flipped horizontally or not.                      <br/>
635      *                                                                                                              <br/>
636      * It only flips the texture of the sprite, and not the texture of the sprite's children.                       <br/>
637      * Also, flipping the texture doesn't alter the anchorPoint.                                                    <br/>
638      * If you want to flip the anchorPoint too, and/or to flip the children too use:                                <br/>
639      *      sprite->setScaleX(sprite->getScaleX() * -1);  <p/>
640      * @return {Boolean} true if the sprite is flipped horizaontally, false otherwise.
641      */
642     isFlippedX:function () {
643         return this._flippedX;
644     },
645 
646     /**
647      * <p>
648      *     Return the flag which indicates whether the sprite is flipped vertically or not.                         <br/>
649      *                                                                                                              <br/>
650      *      It only flips the texture of the sprite, and not the texture of the sprite's children.                  <br/>
651      *      Also, flipping the texture doesn't alter the anchorPoint.                                               <br/>
652      *      If you want to flip the anchorPoint too, and/or to flip the children too use:                           <br/>
653      *         sprite->setScaleY(sprite->getScaleY() * -1); <p/>
654      * @return {Boolean} true if the sprite is flipped vertically, flase otherwise.
655      */
656     isFlippedY:function () {
657         return this._flippedY;
658     },
659 
660     //
661     // RGBA protocol
662     //
663     /**
664      * opacity: conforms to CCRGBAProtocol protocol
665      * @function
666      * @param {Boolean} modify
667      */
668     setOpacityModifyRGB:null,
669 
670     /**
671      * return IsOpacityModifyRGB value
672      * @return {Boolean}
673      */
674     isOpacityModifyRGB:function () {
675         return this._opacityModifyRGB;
676     },
677 
678     updateDisplayedOpacity: null,
679 
680     // Animation
681 
682     /**
683      * changes the display frame with animation name and index.<br/>
684      * The animation name will be get from the CCAnimationCache
685      * @param animationName
686      * @param frameIndex
687      */
688     setDisplayFrameWithAnimationName:function (animationName, frameIndex) {
689 
690         cc.assert(animationName, cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_3);
691 
692         var cache = cc.animationCache.getAnimation(animationName);
693         if(!cache){
694             cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName);
695             return;
696         }
697         var animFrame = cache.getFrames()[frameIndex];
698         if(!animFrame){
699             cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_2);
700             return;
701         }
702         this.setSpriteFrame(animFrame.getSpriteFrame());
703     },
704 
705     /**
706      * Returns the batch node object if this sprite is rendered by cc.SpriteBatchNode
707      * @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.
708      */
709     getBatchNode:function () {
710         return this._batchNode;
711     },
712 
713     _setReorderChildDirtyRecursively:function () {
714         //only set parents flag the first time
715         if (!this._reorderChildDirty) {
716             this._reorderChildDirty = true;
717             var pNode = this._parent;
718             while (pNode && pNode != this._batchNode) {
719                 pNode._setReorderChildDirtyRecursively();
720                 pNode = pNode.parent;
721             }
722         }
723     },
724 
725     // CCTextureProtocol
726     getTexture:function () {
727         return this._texture;
728     },
729 
730     _quad:null, // vertex coords, texture coords and color info
731     _quadWebBuffer:null,
732     _quadDirty:false,
733     _colorized:false,
734     _isLighterMode:false,
735     _originalTexture:null,
736     _textureRect_Canvas:null,
737     _drawSize_Canvas:null,
738 
739     /**
740      * Constructor
741      * @function
742      * @param {String|cc.SpriteFrame|cc.SpriteBatchNode|HTMLImageElement|cc.Texture2D} fileName sprite construct parameter
743      * @param {cc.Rect} rect  Only the contents inside rect of pszFileName's texture will be applied for this sprite.
744      */
745     ctor: null,
746 
747 	_softInit: function (fileName, rect) {
748 		if (fileName === undefined)
749 			cc.Sprite.prototype.init.call(this);
750 		else if (typeof(fileName) === "string") {
751 			if (fileName[0] === "#") {
752 				// Init with a sprite frame name
753 				var frameName = fileName.substr(1, fileName.length - 1);
754 				var spriteFrame = cc.spriteFrameCache.getSpriteFrame(frameName);
755 				this.initWithSpriteFrame(spriteFrame);
756 			} else {
757 				// Init  with filename and rect
758 				cc.Sprite.prototype.init.call(this, fileName, rect);
759 			}
760 		}
761 		else if (typeof(fileName) === "object") {
762 			if (fileName instanceof cc.Texture2D) {
763 				// Init  with texture and rect
764 				this.initWithTexture(fileName, rect);
765 			} else if (fileName instanceof cc.SpriteFrame) {
766 				// Init with a sprite frame
767 				this.initWithSpriteFrame(fileName);
768 			} else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) {
769 				// Init with a canvas or image element
770 				var texture2d = new cc.Texture2D();
771 				texture2d.initWithElement(fileName);
772 				texture2d.handleLoadedTexture();
773 				this.initWithTexture(texture2d);
774 			}
775 		}
776 	},
777 
778     /**
779      * Returns the quad (tex coords, vertex coords and color) information.
780      * @return {cc.V3F_C4B_T2F_Quad}
781      */
782     getQuad:function () {
783         return this._quad;
784     },
785 
786     /**
787      * conforms to cc.TextureProtocol protocol
788      * @function
789      * @param {Number|cc.BlendFunc} src
790      * @param {Number} dst
791      */
792     setBlendFunc: null,
793 
794     /**
795      * Initializes an empty sprite with nothing init.
796      * @function
797      * @return {Boolean}
798      */
799     init:null,
800 
801     /**
802      * <p>
803      *     Initializes a sprite with an image filename.
804      *
805      *     This method will find pszFilename from local file system, load its content to CCTexture2D,
806      *     then use CCTexture2D to create a sprite.
807      *     After initialization, the rect used will be the size of the image. The offset will be (0,0).
808      * </p>
809      * @param {String} filename The path to an image file in local file system
810      * @param {cc.Rect} rect The rectangle assigned the content area from texture.
811      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
812      * @example
813      * var mySprite = new cc.Sprite();
814      * mySprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320));
815      */
816     initWithFile:function (filename, rect) {
817 
818         cc.assert(filename, cc._LogInfos.Sprite_initWithFile);
819 
820         var texture = cc.textureCache.textureForKey(filename);
821         if (!texture) {
822             texture = cc.textureCache.addImage(filename);
823             return this.initWithTexture(texture, rect);
824         } else {
825             if (!rect) {
826                 var size = texture.getContentSize();
827                 rect = cc.rect(0, 0, size.width, size.height);
828             }
829             return this.initWithTexture(texture, rect);
830         }
831     },
832 
833     /**
834      * Initializes a sprite with a texture and a rect in points, optionally rotated.  <br/>
835      * After initialization, the rect used will be the size of the texture, and the offset will be (0,0).
836      * @function
837      * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites.
838      * @param {cc.Rect} rect Only the contents inside rect of this texture will be applied for this sprite.
839      * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
840      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
841      * @example
842      * var img =cc.textureCache.addImage("HelloHTML5World.png");
843      * var mySprite = new cc.Sprite();
844      * mySprite.initWithTexture(img,cc.rect(0,0,480,320));
845      */
846     initWithTexture: null,
847 
848     _textureLoadedCallback: null,
849 
850     /**
851      * updates the texture rect of the CCSprite in points.
852      * @function
853      * @param {cc.Rect} rect a rect of texture
854      * @param {Boolean} rotated
855      * @param {cc.Size} untrimmedSize
856      */
857     setTextureRect:null,
858 
859     // BatchNode methods
860     /**
861      * updates the quad according the the rotation, position, scale values.
862      * @function
863      */
864     updateTransform: null,
865 
866     /**
867      * Add child to sprite (override cc.Node )
868      * @function
869      * @param {cc.Sprite} child
870      * @param {Number} localZOrder  child's zOrder
871      * @param {String} tag child's tag
872      * @override
873      */
874     addChild: null,
875 
876     /**
877      * Update sprite's color
878      */
879     updateColor:function () {
880         var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity;
881         var color4 = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: locDisplayedOpacity};
882         // special opacity for premultiplied textures
883         if (this._opacityModifyRGB) {
884             color4.r *= locDisplayedOpacity / 255.0;
885             color4.g *= locDisplayedOpacity / 255.0;
886             color4.b *= locDisplayedOpacity / 255.0;
887         }
888         var locQuad = this._quad;
889         locQuad.bl.colors = color4;
890         locQuad.br.colors = color4;
891         locQuad.tl.colors = color4;
892         locQuad.tr.colors = color4;
893 
894         // renders using Sprite Manager
895         if (this._batchNode) {
896             if (this.atlasIndex != cc.Sprite.INDEX_NOT_INITIALIZED) {
897                 this.textureAtlas.updateQuad(locQuad, this.atlasIndex)
898             } else {
899                 // no need to set it recursively
900                 // update dirty_, don't update recursiveDirty_
901                 this.dirty = true;
902             }
903         }
904         // self render
905         // do nothing
906         this._quadDirty = true;
907     },
908 
909     /**
910      * Opacity setter
911      * @function
912      * @param {Number} opacity
913      */
914     setOpacity:null,
915 
916     /**
917      * Color setter
918      * @function
919      * @param {cc.Color} color3
920      */
921     setColor: null,
922 
923     updateDisplayedColor: null,
924 
925     // Frames
926     /**
927      * Sets a new spriteFrame to the cc.Sprite.
928      * @function
929      * @param {cc.SpriteFrame|String} newFrame
930      */
931     setSpriteFrame: null,
932 
933     /**
934      * Sets a new display frame to the cc.Sprite.
935      * @param {cc.SpriteFrame|String} newFrame
936      * @deprecated
937      */
938     setDisplayFrame: function(newFrame){
939         cc.log(cc._LogInfos.Sprite_setDisplayFrame);
940         this.setSpriteFrame(newFrame);
941     },
942 
943     /**
944      * Returns whether or not a cc.SpriteFrame is being displayed
945      * @function
946      * @param {cc.SpriteFrame} frame
947      * @return {Boolean}
948      */
949     isFrameDisplayed: null,
950 
951     /**
952      * Returns the current displayed frame.
953      * @return {cc.SpriteFrame}
954      */
955     displayFrame: function () {
956         return cc.SpriteFrame.create(this._texture,
957             cc.rectPointsToPixels(this._rect),
958             this._rectRotated,
959             cc.pointPointsToPixels(this._unflippedOffsetPositionFromCenter),
960             cc.sizePointsToPixels(this._contentSize));
961     },
962 
963     /**
964      * Sets the batch node to sprite
965      * @function
966      * @param {cc.SpriteBatchNode|null} spriteBatchNode
967      * @example
968      *  var batch = cc.SpriteBatchNode.create("Images/grossini_dance_atlas.png", 15);
969      *  var sprite = cc.Sprite.create(batch.texture, cc.rect(0, 0, 57, 57));
970      *  batch.addChild(sprite);
971      *  layer.addChild(batch);
972      */
973     setBatchNode:null,
974 
975     // CCTextureProtocol
976     /**
977      * Texture of sprite setter
978      * @function
979      * @param {cc.Texture2D|String} texture
980      */
981     setTexture: null,
982 
983     // Texture protocol
984     _updateBlendFunc:function () {
985         if(this._batchNode){
986             cc.log(cc._LogInfos.Sprite__updateBlendFunc);
987             return;
988         }
989 
990         // it's possible to have an untextured sprite
991         if (!this._texture || !this._texture.hasPremultipliedAlpha()) {
992             this._blendFunc.src = cc.SRC_ALPHA;
993             this._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA;
994             this.opacityModifyRGB = false;
995         } else {
996             this._blendFunc.src = cc.BLEND_SRC;
997             this._blendFunc.dst = cc.BLEND_DST;
998             this.opacityModifyRGB = true;
999         }
1000     },
1001 
1002     _changeTextureColor: function () {
1003         var locElement, locTexture = this._texture, locRect = this._textureRect_Canvas; //this.getTextureRect();
1004         if (locTexture && locRect.validRect && this._originalTexture) {
1005             locElement = locTexture.getHtmlElementObj();
1006             if (!locElement)
1007                 return;
1008 
1009             var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj());
1010             if (cacheTextureForColor) {
1011                 this._colorized = true;
1012                 //generate color texture cache
1013                 if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor)
1014                     cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect, locElement);
1015                 else {
1016                     locElement = cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect);
1017                     locTexture = new cc.Texture2D();
1018                     locTexture.initWithElement(locElement);
1019                     locTexture.handleLoadedTexture();
1020                     this.texture = locTexture;
1021                 }
1022             }
1023         }
1024     },
1025 
1026     _setTextureCoords:function (rect) {
1027         rect = cc.rectPointsToPixels(rect);
1028 
1029         var tex = this._batchNode ? this.textureAtlas.texture : this._texture;
1030         if (!tex)
1031             return;
1032 
1033         var atlasWidth = tex.pixelsWidth;
1034         var atlasHeight = tex.pixelsHeight;
1035 
1036         var left, right, top, bottom, tempSwap, locQuad = this._quad;
1037         if (this._rectRotated) {
1038             if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
1039                 left = (2 * rect.x + 1) / (2 * atlasWidth);
1040                 right = left + (rect.height * 2 - 2) / (2 * atlasWidth);
1041                 top = (2 * rect.y + 1) / (2 * atlasHeight);
1042                 bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight);
1043             } else {
1044                 left = rect.x / atlasWidth;
1045                 right = (rect.x + rect.height) / atlasWidth;
1046                 top = rect.y / atlasHeight;
1047                 bottom = (rect.y + rect.width) / atlasHeight;
1048             }// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
1049 
1050             if (this._flippedX) {
1051                 tempSwap = top;
1052                 top = bottom;
1053                 bottom = tempSwap;
1054             }
1055 
1056             if (this._flippedY) {
1057                 tempSwap = left;
1058                 left = right;
1059                 right = tempSwap;
1060             }
1061 
1062             locQuad.bl.texCoords.u = left;
1063             locQuad.bl.texCoords.v = top;
1064             locQuad.br.texCoords.u = left;
1065             locQuad.br.texCoords.v = bottom;
1066             locQuad.tl.texCoords.u = right;
1067             locQuad.tl.texCoords.v = top;
1068             locQuad.tr.texCoords.u = right;
1069             locQuad.tr.texCoords.v = bottom;
1070         } else {
1071             if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
1072                 left = (2 * rect.x + 1) / (2 * atlasWidth);
1073                 right = left + (rect.width * 2 - 2) / (2 * atlasWidth);
1074                 top = (2 * rect.y + 1) / (2 * atlasHeight);
1075                 bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight);
1076             } else {
1077                 left = rect.x / atlasWidth;
1078                 right = (rect.x + rect.width) / atlasWidth;
1079                 top = rect.y / atlasHeight;
1080                 bottom = (rect.y + rect.height) / atlasHeight;
1081             } // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
1082 
1083             if (this._flippedX) {
1084                 tempSwap = left;
1085                 left = right;
1086                 right = tempSwap;
1087             }
1088 
1089             if (this._flippedY) {
1090                 tempSwap = top;
1091                 top = bottom;
1092                 bottom = tempSwap;
1093             }
1094 
1095             locQuad.bl.texCoords.u = left;
1096             locQuad.bl.texCoords.v = bottom;
1097             locQuad.br.texCoords.u = right;
1098             locQuad.br.texCoords.v = bottom;
1099             locQuad.tl.texCoords.u = left;
1100             locQuad.tl.texCoords.v = top;
1101             locQuad.tr.texCoords.u = right;
1102             locQuad.tr.texCoords.v = top;
1103         }
1104         this._quadDirty = true;
1105     },
1106     /**
1107      * draw sprite to canvas
1108      * @function
1109      */
1110     draw: null
1111 });
1112 
1113 /**
1114  * Create a sprite with image path or frame name or texture or spriteFrame.
1115  * @constructs
1116  * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName  The string which indicates a path to image file, e.g., "scene1/monster.png".
1117  * @param {cc.Rect} rect  Only the contents inside rect of pszFileName's texture will be applied for this sprite.
1118  * @return {cc.Sprite} A valid sprite object
1119  * @example
1120  *
1121  * 1.Create a sprite with image path and rect
1122  * var sprite1 = cc.Sprite.create("res/HelloHTML5World.png");
1123  * var sprite2 = cc.Sprite.create("res/HelloHTML5World.png",cc.rect(0,0,480,320));
1124  *
1125  * 2.Create a sprite with a sprite frame name. Must add "#" before frame name.
1126  * var sprite = cc.Sprite.create('#grossini_dance_01.png');
1127  *
1128  * 3.Create a sprite with a sprite frame
1129  * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png");
1130  * var sprite = cc.Sprite.create(spriteFrame);
1131  *
1132  * 4.Create a sprite with an exsiting texture contained in a CCTexture2D object
1133  *      After creation, the rect will be the size of the texture, and the offset will be (0,0).
1134  * var texture = cc.textureCache.addImage("HelloHTML5World.png");
1135  * var sprite1 = cc.Sprite.create(texture);
1136  * var sprite2 = cc.Sprite.create(texture, cc.rect(0,0,480,320));
1137  *
1138  */
1139 cc.Sprite.create = function (fileName, rect) {
1140     return new cc.Sprite(fileName, rect);
1141 };
1142 
1143 
1144 /**
1145  * cc.Sprite invalid index on the cc.SpriteBatchNode
1146  * @constant
1147  * @type Number
1148  */
1149 cc.Sprite.INDEX_NOT_INITIALIZED = -1;
1150 
1151 
1152 if (cc._renderType === cc._RENDER_TYPE_CANVAS) {
1153 
1154     var _p = cc.Sprite.prototype;
1155 
1156     _p._spriteFrameLoadedCallback = function(spriteFrame){
1157         var _t = this;
1158         _t.setNodeDirty(true);
1159         _t.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize());
1160         var curColor = _t.color;
1161         if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
1162             _t._changeTextureColor();
1163 
1164         _t._callLoadedEventCallbacks();
1165     };
1166 
1167     _p.setOpacityModifyRGB = function (modify) {
1168         if (this._opacityModifyRGB !== modify) {
1169             this._opacityModifyRGB = modify;
1170             this.setNodeDirty(true);
1171         }
1172     };
1173 
1174     _p.updateDisplayedOpacity = function (parentOpacity) {
1175         cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity);
1176         this._setNodeDirtyForCache();
1177     };
1178 
1179     _p.ctor = function (fileName, rect) {
1180         var self = this;
1181         cc.NodeRGBA.prototype.ctor.call(self);
1182         self._shouldBeHidden = false;
1183         self._offsetPosition = cc.p(0, 0);
1184         self._unflippedOffsetPositionFromCenter = cc.p(0, 0);
1185         self._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST};
1186         self._rect = cc.rect(0, 0, 0, 0);
1187 
1188         self._newTextureWhenChangeColor = false;
1189         self._textureLoaded = true;
1190         self._textureRect_Canvas = {x: 0, y: 0, width: 0, height:0, validRect: false};
1191         self._drawSize_Canvas = cc.size(0, 0);
1192 
1193         self._softInit(fileName, rect);
1194     };
1195 
1196     _p.setBlendFunc = function (src, dst) {
1197         var locBlendFunc = this._blendFunc;
1198         if (dst === undefined) {
1199             locBlendFunc.src = src.src;
1200             locBlendFunc.dst = src.dst;
1201         } else {
1202             locBlendFunc.src = src;
1203             locBlendFunc.dst = dst;
1204         }
1205         this._isLighterMode = (locBlendFunc &&
1206             (( locBlendFunc.src == cc.SRC_ALPHA && locBlendFunc.dst == cc.ONE) || (locBlendFunc.src == cc.ONE && locBlendFunc.dst == cc.ONE)));
1207     };
1208 
1209     _p.init = function () {
1210         var _t = this;
1211         if (arguments.length > 0)
1212             return _t.initWithFile(arguments[0], arguments[1]);
1213 
1214         cc.NodeRGBA.prototype.init.call(_t);
1215         _t.dirty = _t._recursiveDirty = false;
1216         _t._opacityModifyRGB = true;
1217 
1218         _t._blendFunc.src = cc.BLEND_SRC;
1219         _t._blendFunc.dst = cc.BLEND_DST;
1220 
1221         // update texture (calls _updateBlendFunc)
1222         _t.texture = null;
1223         _t._textureLoaded = true;
1224         _t._flippedX = _t._flippedY = false;
1225 
1226         // default transform anchor: center
1227         _t.anchorX = 0.5;
1228         _t.anchorY = 0.5;
1229 
1230         // zwoptex default values
1231         _t._offsetPosition.x = 0;
1232         _t._offsetPosition.y = 0;
1233         _t._hasChildren = false;
1234 
1235         // updated in "useSelfRender"
1236         // Atlas: TexCoords
1237         _t.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0));
1238         return true;
1239     };
1240 
1241     _p.initWithTexture = function (texture, rect, rotated) {
1242         var _t = this;
1243         var argnum = arguments.length;
1244 
1245         cc.assert(argnum != 0, cc._LogInfos.CCSpriteBatchNode_initWithTexture);
1246 
1247         rotated = rotated || false;
1248 
1249         if (!cc.NodeRGBA.prototype.init.call(_t))
1250             return false;
1251 
1252         _t._batchNode = null;
1253 
1254         _t._recursiveDirty = false;
1255         _t.dirty = false;
1256         _t._opacityModifyRGB = true;
1257 
1258         _t._blendFunc.src = cc.BLEND_SRC;
1259         _t._blendFunc.dst = cc.BLEND_DST;
1260 
1261         _t._flippedX = _t._flippedY = false;
1262 
1263         // default transform anchor: center
1264         _t.anchorX = 0.5;
1265         _t.anchorY = 0.5;
1266 
1267         // zwoptex default values
1268         _t._offsetPosition.x = 0;
1269         _t._offsetPosition.y = 0;
1270         _t._hasChildren = false;
1271 
1272         var locTextureLoaded = texture.isLoaded();
1273         _t._textureLoaded = locTextureLoaded;
1274 
1275         if (!locTextureLoaded) {
1276             _t._rectRotated = rotated || false;
1277             if (rect) {
1278                 _t._rect.x = rect.x;
1279                 _t._rect.y = rect.y;
1280                 _t._rect.width = rect.width;
1281                 _t._rect.height = rect.height;
1282             }
1283             texture.addLoadedEventListener(_t._textureLoadedCallback, _t);
1284             return true;
1285         }
1286 
1287         if (!rect) {
1288             rect = cc.rect(0, 0, texture.width, texture.height);
1289         }
1290         _t._originalTexture = texture;
1291 
1292         _t.texture = texture;
1293         _t.setTextureRect(rect, rotated);
1294 
1295         // by default use "Self Render".
1296         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1297         _t.batchNode = null;
1298         return true;
1299     };
1300 
1301     _p._textureLoadedCallback = function (sender) {
1302         var _t = this;
1303         if(_t._textureLoaded)
1304             return;
1305 
1306         _t._textureLoaded = true;
1307         var locRect = _t._rect;
1308         if (!locRect) {
1309             locRect = cc.rect(0, 0, sender.width, sender.height);
1310         } else if (cc._rectEqualToZero(locRect)) {
1311             locRect.width = sender.width;
1312             locRect.height = sender.height;
1313         }
1314         _t._originalTexture = sender;
1315 
1316         _t.texture = sender;
1317         _t.setTextureRect(locRect, _t._rectRotated);
1318 
1319         // by default use "Self Render".
1320         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1321         _t.batchNode = _t._batchNode;
1322         _t._callLoadedEventCallbacks();
1323     };
1324 
1325     _p.setTextureRect = function (rect, rotated, untrimmedSize) {
1326         var _t = this;
1327         _t._rectRotated = rotated || false;
1328         _t.setContentSize(untrimmedSize || rect);
1329 
1330         _t.setVertexRect(rect);
1331 
1332         var locTextureRect = _t._textureRect_Canvas, scaleFactor = cc.contentScaleFactor();
1333         locTextureRect.x = 0 | (rect.x * scaleFactor);
1334         locTextureRect.y = 0 | (rect.y * scaleFactor);
1335         locTextureRect.width = 0 | (rect.width * scaleFactor);
1336         locTextureRect.height = 0 | (rect.height * scaleFactor);
1337         locTextureRect.validRect = !(locTextureRect.width === 0 || locTextureRect.height === 0 || locTextureRect.x < 0 || locTextureRect.y < 0);
1338 
1339         var relativeOffset = _t._unflippedOffsetPositionFromCenter;
1340         if (_t._flippedX)
1341             relativeOffset.x = -relativeOffset.x;
1342         if (_t._flippedY)
1343             relativeOffset.y = -relativeOffset.y;
1344         _t._offsetPosition.x = relativeOffset.x + (_t._contentSize.width - _t._rect.width) / 2;
1345         _t._offsetPosition.y = relativeOffset.y + (_t._contentSize.height - _t._rect.height) / 2;
1346 
1347         // rendering using batch node
1348         if (_t._batchNode) {
1349             // update dirty, don't update _recursiveDirty
1350             _t.dirty = true;
1351         }
1352     };
1353 
1354     _p.updateTransform = function () {
1355         var _t = this;
1356         //cc.assert(_t._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode");
1357 
1358         // recaculate matrix only if it is dirty
1359         if (_t.dirty) {
1360             // If it is not visible, or one of its ancestors is not visible, then do nothing:
1361             var locParent = _t._parent;
1362             if (!_t._visible || ( locParent && locParent != _t._batchNode && locParent._shouldBeHidden)) {
1363                 _t._shouldBeHidden = true;
1364             } else {
1365                 _t._shouldBeHidden = false;
1366 
1367                 if (!locParent || locParent == _t._batchNode) {
1368                     _t._transformToBatch = _t.nodeToParentTransform();
1369                 } else {
1370                     //cc.assert(_t._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite");
1371                     _t._transformToBatch = cc.AffineTransformConcat(_t.nodeToParentTransform(), locParent._transformToBatch);
1372                 }
1373             }
1374             _t._recursiveDirty = false;
1375             _t.dirty = false;
1376         }
1377 
1378         // recursively iterate over children
1379         if (_t._hasChildren)
1380             _t._arrayMakeObjectsPerformSelector(_t._children, cc.Node.StateCallbackType.updateTransform);
1381     };
1382 
1383     _p.addChild = function (child, localZOrder, tag) {
1384 
1385         cc.assert(child, cc._LogInfos.CCSpriteBatchNode_addChild_2);
1386 
1387         if (localZOrder == null)
1388             localZOrder = child._localZOrder;
1389         if (tag == null)
1390             tag = child.tag;
1391 
1392         //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check
1393         cc.NodeRGBA.prototype.addChild.call(this, child, localZOrder, tag);
1394         this._hasChildren = true;
1395     };
1396 
1397     _p.setOpacity = function (opacity) {
1398         cc.NodeRGBA.prototype.setOpacity.call(this, opacity);
1399         this._setNodeDirtyForCache();
1400     };
1401 
1402     _p.setColor = function (color3) {
1403         var _t = this;
1404         var curColor = _t.color;
1405         if ((curColor.r === color3.r) && (curColor.g === color3.g) && (curColor.b === color3.b) && (curColor.a === color3.a))
1406             return;
1407 
1408         cc.NodeRGBA.prototype.setColor.call(_t, color3);
1409         _t._changeTextureColor();
1410         _t._setNodeDirtyForCache();
1411     };
1412 
1413     _p.updateDisplayedColor = function (parentColor) {
1414         var _t = this;
1415         var oldColor = _t.color;
1416         cc.NodeRGBA.prototype.updateDisplayedColor.call(_t, parentColor);
1417         var newColor = _t._displayedColor;
1418         if ((oldColor.r === newColor.r) && (oldColor.g === newColor.g) && (oldColor.b === newColor.b))
1419             return;
1420         _t._changeTextureColor();
1421         _t._setNodeDirtyForCache();
1422     };
1423 
1424     _p.setSpriteFrame = function (newFrame) {
1425         var _t = this;
1426         if(typeof(newFrame) == "string"){
1427             newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame);
1428 
1429             cc.assert(newFrame, cc._LogInfos.CCSpriteBatchNode_setSpriteFrame)
1430 
1431         }
1432 
1433         _t.setNodeDirty(true);
1434 
1435         var frameOffset = newFrame.getOffset();
1436         _t._unflippedOffsetPositionFromCenter.x = frameOffset.x;
1437         _t._unflippedOffsetPositionFromCenter.y = frameOffset.y;
1438 
1439         // update rect
1440         _t._rectRotated = newFrame.isRotated();
1441 
1442         var pNewTexture = newFrame.getTexture();
1443         var locTextureLoaded = newFrame.textureLoaded();
1444         if (!locTextureLoaded) {
1445             _t._textureLoaded = false;
1446             newFrame.addLoadedEventListener(function (sender) {
1447                 _t._textureLoaded = true;
1448                 var locNewTexture = sender.getTexture();
1449                 if (locNewTexture != _t._texture)
1450                     _t.texture = locNewTexture;
1451                 _t.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize());
1452                 _t._callLoadedEventCallbacks();
1453             }, _t);
1454         }
1455         // update texture before updating texture rect
1456         if (pNewTexture != _t._texture)
1457             _t.texture = pNewTexture;
1458 
1459         if (_t._rectRotated)
1460             _t._originalTexture = pNewTexture;
1461 
1462         _t.setTextureRect(newFrame.getRect(), _t._rectRotated, newFrame.getOriginalSize());
1463         _t._colorized = false;
1464         if (locTextureLoaded) {
1465             var curColor = _t.color;
1466             if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
1467                 _t._changeTextureColor();
1468         }
1469     };
1470 
1471     _p.isFrameDisplayed = function (frame) {
1472         if (frame.getTexture() != this._texture)
1473             return false;
1474         return cc.rectEqualToRect(frame.getRect(), this._rect);
1475     };
1476 
1477     _p.setBatchNode = function (spriteBatchNode) {
1478         var _t = this;
1479         _t._batchNode = spriteBatchNode; // weak reference
1480 
1481         // self render
1482         if (!_t._batchNode) {
1483             _t.atlasIndex = cc.Sprite.INDEX_NOT_INITIALIZED;
1484             _t.textureAtlas = null;
1485             _t._recursiveDirty = false;
1486             _t.dirty = false;
1487         } else {
1488             // using batch
1489             _t._transformToBatch = cc.AffineTransformIdentity();
1490             _t.textureAtlas = _t._batchNode.textureAtlas; // weak ref
1491         }
1492     };
1493 
1494 
1495     _p.setTexture = function (texture) {
1496         var _t = this;
1497         if(texture && (typeof(texture) === "string")){
1498             texture = cc.textureCache.addImage(texture);
1499             _t.setTexture(texture);
1500 
1501             //TODO
1502             var size = texture.getContentSize();
1503             _t.setTextureRect(cc.rect(0,0, size.width, size.height));
1504             return;
1505         }
1506 
1507         // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet
1508 
1509         cc.assert(!texture || texture instanceof cc.Texture2D, cc._LogInfos.CCSpriteBatchNode_setTexture);
1510 
1511         if (_t._texture != texture) {
1512             if (texture && texture.getHtmlElementObj() instanceof  HTMLImageElement) {
1513                 _t._originalTexture = texture;
1514             }
1515             _t._texture = texture;
1516         }
1517     };
1518 
1519     _p.draw = function (ctx) {
1520         var _t = this;
1521         if (!_t._textureLoaded)
1522             return;
1523 
1524         var context = ctx || cc._renderContext;
1525         if (_t._isLighterMode)
1526             context.globalCompositeOperation = 'lighter';
1527 
1528         var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY();
1529 
1530         context.globalAlpha = _t._displayedOpacity / 255;
1531         var locRect = _t._rect, locContentSize = _t._contentSize, locOffsetPosition = _t._offsetPosition, locDrawSizeCanvas = _t._drawSize_Canvas;
1532         var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = _t._textureRect_Canvas;
1533         locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX;
1534         locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY;
1535 
1536         if (_t._flippedX || _t._flippedY) {
1537             context.save();
1538             if (_t._flippedX) {
1539                 flipXOffset = -locOffsetPosition.x - locRect.width;
1540                 context.scale(-1, 1);
1541             }
1542             if (_t._flippedY) {
1543                 flipYOffset = locOffsetPosition.y;
1544                 context.scale(1, -1);
1545             }
1546         }
1547 
1548         flipXOffset *= locEGL_ScaleX;
1549         flipYOffset *= locEGL_ScaleY;
1550 
1551         if (_t._texture && locTextureCoord.validRect) {
1552             var image = _t._texture.getHtmlElementObj();
1553             if (_t._colorized) {
1554                 context.drawImage(image,
1555                     0, 0, locTextureCoord.width, locTextureCoord.height,
1556                     flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height);
1557             } else {
1558                 context.drawImage(image,
1559                     locTextureCoord.x, locTextureCoord.y, locTextureCoord.width,  locTextureCoord.height,
1560                     flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height);
1561             }
1562         } else if (locContentSize.width !== 0) {
1563             var curColor = _t.color;
1564             context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)";
1565             context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY);
1566         }
1567 
1568         if (cc.SPRITE_DEBUG_DRAW === 1 || _t._showNode) {
1569             // draw bounding box
1570             context.strokeStyle = "rgba(0,255,0,1)";
1571             flipXOffset /= locEGL_ScaleX;
1572             flipYOffset /= locEGL_ScaleY;
1573             flipYOffset = -flipYOffset;
1574             var vertices1 = [cc.p(flipXOffset, flipYOffset),
1575                 cc.p(flipXOffset + locRect.width, flipYOffset),
1576                 cc.p(flipXOffset + locRect.width, flipYOffset - locRect.height),
1577                 cc.p(flipXOffset, flipYOffset - locRect.height)];
1578             cc._drawingUtil.drawPoly(vertices1, 4, true);
1579         } else if (cc.SPRITE_DEBUG_DRAW === 2) {
1580             // draw texture box
1581             context.strokeStyle = "rgba(0,255,0,1)";
1582             var drawRect = _t._rect;
1583             flipYOffset = -flipYOffset;
1584             var vertices2 = [cc.p(flipXOffset, flipYOffset), cc.p(flipXOffset + drawRect.width, flipYOffset),
1585                 cc.p(flipXOffset + drawRect.width, flipYOffset - drawRect.height), cc.p(flipXOffset, flipYOffset - drawRect.height)];
1586             cc._drawingUtil.drawPoly(vertices2, 4, true);
1587         }
1588         if (_t._flippedX || _t._flippedY)
1589             context.restore();
1590         cc.g_NumberOfDraws++;
1591     };
1592 
1593     delete _p;
1594 } else {
1595     _tmp.WebGLSprite();
1596     delete _tmp.WebGLSprite;
1597 }
1598 _tmp.PrototypeSprite();
1599 delete _tmp.PrototypeSprite;
1600 
1601