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