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