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  * <p>cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) )  <br/>
 29  *
 30  * cc.Sprite can be created with an image, or with a sub-rectangle of an image.  <br/>
 31  *
 32  * If the parent or any of its ancestors is a cc.SpriteBatchNode then the following features/limitations are valid   <br/>
 33  *    - Features when the parent is a cc.BatchNode: <br/>
 34  *        - MUCH faster rendering, specially if the cc.SpriteBatchNode has many children. All the children will be drawn in a single batch.  <br/>
 35  *
 36  *    - Limitations   <br/>
 37  *        - Camera is not supported yet (eg: CCOrbitCamera action doesn't work)  <br/>
 38  *        - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl) <br/>
 39  *        - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property.  <br/>
 40  *        - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property. <br/>
 41  *        - Parallax scroller is not supported, but can be simulated with a "proxy" sprite.        <br/>
 42  *
 43  *  If the parent is an standard cc.Node, then cc.Sprite behaves like any other cc.Node:      <br/>
 44  *    - It supports blending functions    <br/>
 45  *    - It supports aliasing / antialiasing    <br/>
 46  *    - But the rendering will be slower: 1 draw per children.   <br/>
 47  *
 48  * The default anchorPoint in cc.Sprite is (0.5, 0.5). </p>
 49  * @class
 50  * @extends cc.Node
 51  *
 52  * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName  The string which indicates a path to image file, e.g., "scene1/monster.png".
 53  * @param {cc.Rect} [rect]  Only the contents inside rect of pszFileName's texture will be applied for this sprite.
 54  * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
 55  * @example
 56  *
 57  * 1.Create a sprite with image path and rect
 58  * var sprite1 = new cc.Sprite("res/HelloHTML5World.png");
 59  * var sprite2 = new cc.Sprite("res/HelloHTML5World.png",cc.rect(0,0,480,320));
 60  *
 61  * 2.Create a sprite with a sprite frame name. Must add "#" before frame name.
 62  * var sprite = new cc.Sprite('#grossini_dance_01.png');
 63  *
 64  * 3.Create a sprite with a sprite frame
 65  * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png");
 66  * var sprite = new cc.Sprite(spriteFrame);
 67  *
 68  * 4.Create a sprite with an existing texture contained in a CCTexture2D object
 69  *      After creation, the rect will be the size of the texture, and the offset will be (0,0).
 70  * var texture = cc.textureCache.addImage("HelloHTML5World.png");
 71  * var sprite1 = new cc.Sprite(texture);
 72  * var sprite2 = new cc.Sprite(texture, cc.rect(0,0,480,320));
 73  *
 74  * @property {Boolean}              dirty               - Indicates whether the sprite needs to be updated.
 75  * @property {Boolean}              flippedX            - Indicates whether or not the sprite is flipped on x axis.
 76  * @property {Boolean}              flippedY            - Indicates whether or not the sprite is flipped on y axis.
 77  * @property {Number}               offsetX             - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex.
 78  * @property {Number}               offsetY             - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex.
 79  * @property {Number}               atlasIndex          - The index used on the TextureAtlas.
 80  * @property {cc.Texture2D}         texture             - Texture used to render the sprite.
 81  * @property {Boolean}              textureRectRotated  - <@readonly> Indicate whether the texture rectangle is rotated.
 82  * @property {cc.TextureAtlas}      textureAtlas        - The weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode.
 83  * @property {cc.SpriteBatchNode}   batchNode           - The batch node object if this sprite is rendered by cc.SpriteBatchNode.
 84  * @property {cc.V3F_C4B_T2F_Quad}  quad                - <@readonly> The quad (tex coords, vertex coords and color) information.
 85  */
 86 cc.Sprite = cc.Node.extend(/** @lends cc.Sprite# */{
 87     dirty:false,
 88     atlasIndex:0,
 89     textureAtlas:null,
 90 
 91     _batchNode:null,
 92     _recursiveDirty:null, //Whether all of the sprite's children needs to be updated
 93     _hasChildren:null, //Whether the sprite contains children
 94     _shouldBeHidden:false, //should not be drawn because one of the ancestors is not visible
 95     _transformToBatch:null,
 96 
 97     //
 98     // Data used when the sprite is self-rendered
 99     //
100     _blendFunc:null, //It's required for CCTextureProtocol inheritance
101     _texture:null, //cc.Texture2D object that is used to render the sprite
102 
103     //
104     // Shared data
105     //
106     // texture
107     _rect:null, //Rectangle of cc.Texture2D
108     _rectRotated:false, //Whether the texture is rotated
109 
110     // Offset Position (used by Zwoptex)
111     _offsetPosition:null, // absolute
112     _unflippedOffsetPositionFromCenter:null,
113 
114     _opacityModifyRGB:false,
115 
116     // image is flipped
117     _flippedX:false, //Whether the sprite is flipped horizontally or not.
118     _flippedY:false, //Whether the sprite is flipped vertically or not.
119 
120     _textureLoaded:false,
121     _className:"Sprite",
122 
123     ctor: function (fileName, rect, rotated) {
124         var self = this;
125         cc.Node.prototype.ctor.call(self);
126         // default transform anchor: center
127         this.setAnchorPoint(0.5, 0.5);
128 
129         self._loader = new cc.Sprite.LoadManager();
130         self._shouldBeHidden = false;
131         self._offsetPosition = cc.p(0, 0);
132         self._unflippedOffsetPositionFromCenter = cc.p(0, 0);
133         self._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST};
134         self._rect = cc.rect(0, 0, 0, 0);
135 
136         self._softInit(fileName, rect, rotated);
137     },
138 
139     /**
140      * Returns whether the texture have been loaded
141      * @returns {boolean}
142      */
143     textureLoaded:function(){
144         return this._textureLoaded;
145     },
146 
147     /**
148      * Add a event listener for texture loaded event.
149      * @param {Function} callback
150      * @param {Object} target
151      * @deprecated since 3.1, please use addEventListener instead
152      */
153     addLoadedEventListener:function(callback, target){
154         this.addEventListener("load", callback, target);
155     },
156 
157     /**
158      * Returns whether or not the Sprite needs to be updated in the Atlas
159      * @return {Boolean} True if the sprite needs to be updated in the Atlas, false otherwise.
160      */
161     isDirty:function () {
162         return this.dirty;
163     },
164 
165     /**
166      * Makes the sprite to be updated in the Atlas.
167      * @param {Boolean} bDirty
168      */
169     setDirty:function (bDirty) {
170         this.dirty = bDirty;
171     },
172 
173     /**
174      * Returns whether or not the texture rectangle is rotated.
175      * @return {Boolean}
176      */
177     isTextureRectRotated:function () {
178         return this._rectRotated;
179     },
180 
181     /**
182      * Returns the index used on the TextureAtlas.
183      * @return {Number}
184      */
185     getAtlasIndex:function () {
186         return this.atlasIndex;
187     },
188 
189     /**
190      * Sets the index used on the TextureAtlas.
191      * @warning Don't modify this value unless you know what you are doing
192      * @param {Number} atlasIndex
193      */
194     setAtlasIndex:function (atlasIndex) {
195         this.atlasIndex = atlasIndex;
196     },
197 
198     /**
199      * Returns the rect of the cc.Sprite in points
200      * @return {cc.Rect}
201      */
202     getTextureRect:function () {
203         return cc.rect(this._rect);
204     },
205 
206     /**
207      * Returns the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
208      * @return {cc.TextureAtlas}
209      */
210     getTextureAtlas:function () {
211         return this.textureAtlas;
212     },
213 
214     /**
215      * Sets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
216      * @param {cc.TextureAtlas} textureAtlas
217      */
218     setTextureAtlas:function (textureAtlas) {
219         this.textureAtlas = textureAtlas;
220     },
221 
222     /**
223      * Returns the offset position of the sprite. Calculated automatically by editors like Zwoptex.
224      * @return {cc.Point}
225      */
226     getOffsetPosition:function () {
227         return cc.p(this._offsetPosition);
228     },
229 
230     _getOffsetX: function () {
231         return this._offsetPosition.x;
232     },
233     _getOffsetY: function () {
234         return this._offsetPosition.y;
235     },
236 
237     /**
238      * Returns the blend function
239      * @return {cc.BlendFunc}
240      */
241     getBlendFunc:function () {
242         return this._blendFunc;
243     },
244 
245     /**
246      * Initializes a sprite with a SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite.<br/>
247      * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself,
248      * @param {cc.SpriteFrame} spriteFrame A CCSpriteFrame object. It should includes a valid texture and a rect
249      * @return {Boolean}  true if the sprite is initialized properly, false otherwise.
250      */
251     initWithSpriteFrame:function (spriteFrame) {
252         cc.assert(spriteFrame, cc._LogInfos.Sprite_initWithSpriteFrame);
253         return this.setSpriteFrame(spriteFrame);
254     },
255 
256     /**
257      * Initializes a sprite with a sprite frame name. <br/>
258      * A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name.  <br/>
259      * If the cc.SpriteFrame doesn't exist it will raise an exception. <br/>
260      * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
261      * @param {String} spriteFrameName A key string that can fected a valid cc.SpriteFrame from cc.SpriteFrameCache
262      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
263      * @example
264      * var sprite = new cc.Sprite();
265      * sprite.initWithSpriteFrameName("grossini_dance_01.png");
266      */
267     initWithSpriteFrameName:function (spriteFrameName) {
268         cc.assert(spriteFrameName, cc._LogInfos.Sprite_initWithSpriteFrameName);
269         var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName);
270         cc.assert(frame, spriteFrameName + cc._LogInfos.Sprite_initWithSpriteFrameName1);
271         return this.initWithSpriteFrame(frame);
272     },
273 
274     /**
275      * Tell the sprite to use batch node render.
276      * @param {cc.SpriteBatchNode} batchNode
277      */
278     useBatchNode:function (batchNode) {
279         this.textureAtlas = batchNode.getTextureAtlas(); // weak ref
280         this._batchNode = batchNode;
281     },
282 
283     /**
284      * <p>
285      *    set the vertex rect.<br/>
286      *    It will be called internally by setTextureRect.                           <br/>
287      *    Useful if you want to create 2x images from SD images in Retina Display.  <br/>
288      *    Do not call it manually. Use setTextureRect instead.  <br/>
289      *    (override this method to generate "double scale" sprites)
290      * </p>
291      * @param {cc.Rect} rect
292      */
293     setVertexRect:function (rect) {
294         var locRect = this._rect;
295         locRect.x = rect.x;
296         locRect.y = rect.y;
297         locRect.width = rect.width;
298         locRect.height = rect.height;
299         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
300     },
301 
302     /**
303      * Sort all children of this sprite node.
304      * @override
305      */
306     sortAllChildren:function () {
307         if (this._reorderChildDirty) {
308             var _children = this._children;
309 
310             cc.Node.prototype.sortAllChildren.call(this);
311 
312             if (this._batchNode) {
313                 this._arrayMakeObjectsPerformSelector(_children, cc.Node._stateCallbackType.sortAllChildren);
314             }
315 
316             //don't need to check children recursively, that's done in visit of each child
317             this._reorderChildDirty = false;
318         }
319 
320     },
321 
322     /**
323      * Reorders a child according to a new z value.  (override cc.Node )
324      * @param {cc.Node} child
325      * @param {Number} zOrder
326      * @override
327      */
328     reorderChild:function (child, zOrder) {
329         cc.assert(child, cc._LogInfos.Sprite_reorderChild_2);
330         if(this._children.indexOf(child) === -1){
331             cc.log(cc._LogInfos.Sprite_reorderChild);
332             return;
333         }
334 
335         if (zOrder === child.zIndex)
336             return;
337 
338         if (this._batchNode && !this._reorderChildDirty) {
339             this._setReorderChildDirtyRecursively();
340             this._batchNode.reorderBatch(true);
341         }
342         cc.Node.prototype.reorderChild.call(this, child, zOrder);
343     },
344 
345     /**
346      * Removes a child from the sprite.
347      * @param child
348      * @param cleanup  whether or not cleanup all running actions
349      * @override
350      */
351     removeChild:function (child, cleanup) {
352         if (this._batchNode)
353             this._batchNode.removeSpriteFromAtlas(child);
354         cc.Node.prototype.removeChild.call(this, child, cleanup);
355     },
356 
357     /**
358      * Sets whether the sprite is visible or not.
359      * @param {Boolean} visible
360      * @override
361      */
362     setVisible:function (visible) {
363         cc.Node.prototype.setVisible.call(this, visible);
364         this._renderCmd.setDirtyRecursively(true);
365     },
366 
367     /**
368      * Removes all children from the container.
369      * @param cleanup whether or not cleanup all running actions
370      * @override
371      */
372     removeAllChildren:function (cleanup) {
373         var locChildren = this._children, locBatchNode = this._batchNode;
374         if (locBatchNode && locChildren != null) {
375             for (var i = 0, len = locChildren.length; i < len; i++)
376                 locBatchNode.removeSpriteFromAtlas(locChildren[i]);
377         }
378 
379         cc.Node.prototype.removeAllChildren.call(this, cleanup);
380         this._hasChildren = false;
381     },
382 
383     //
384     // cc.Node property overloads
385     //
386 
387     /**
388      * Sets whether ignore anchor point for positioning
389      * @param {Boolean} relative
390      * @override
391      */
392     ignoreAnchorPointForPosition:function (relative) {
393         if(this._batchNode){
394             cc.log(cc._LogInfos.Sprite_ignoreAnchorPointForPosition);
395             return;
396         }
397         cc.Node.prototype.ignoreAnchorPointForPosition.call(this, relative);
398     },
399 
400     /**
401      * Sets whether the sprite should be flipped horizontally or not.
402      * @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise.
403      */
404     setFlippedX:function (flippedX) {
405         if (this._flippedX !== flippedX) {
406             this._flippedX = flippedX;
407             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
408             this.setNodeDirty(true);
409         }
410     },
411 
412     /**
413      * Sets whether the sprite should be flipped vertically or not.
414      * @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise.
415      */
416     setFlippedY:function (flippedY) {
417         if (this._flippedY !== flippedY) {
418             this._flippedY = flippedY;
419             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
420             this.setNodeDirty(true);
421         }
422     },
423 
424     /**
425      * <p>
426      * Returns the flag which indicates whether the sprite is flipped horizontally or not.                      <br/>
427      *                                                                                                              <br/>
428      * It only flips the texture of the sprite, and not the texture of the sprite's children.                       <br/>
429      * Also, flipping the texture doesn't alter the anchorPoint.                                                    <br/>
430      * If you want to flip the anchorPoint too, and/or to flip the children too use:                                <br/>
431      *      sprite.setScaleX(sprite.getScaleX() * -1);  <p/>
432      * @return {Boolean} true if the sprite is flipped horizontally, false otherwise.
433      */
434     isFlippedX:function () {
435         return this._flippedX;
436     },
437 
438     /**
439      * <p>
440      *     Return the flag which indicates whether the sprite is flipped vertically or not.                         <br/>
441      *                                                                                                              <br/>
442      *      It only flips the texture of the sprite, and not the texture of the sprite's children.                  <br/>
443      *      Also, flipping the texture doesn't alter the anchorPoint.                                               <br/>
444      *      If you want to flip the anchorPoint too, and/or to flip the children too use:                           <br/>
445      *         sprite.setScaleY(sprite.getScaleY() * -1); <p/>
446      * @return {Boolean} true if the sprite is flipped vertically, false otherwise.
447      */
448     isFlippedY:function () {
449         return this._flippedY;
450     },
451 
452     //
453     // RGBA protocol
454     //
455     /**
456      * Sets whether opacity modify color or not.
457      * @function
458      * @param {Boolean} modify
459      */
460     setOpacityModifyRGB: function (modify) {
461         if (this._opacityModifyRGB !== modify) {
462             this._opacityModifyRGB = modify;
463             this._renderCmd._setColorDirty();
464         }
465     },
466 
467     /**
468      * Returns whether opacity modify color or not.
469      * @return {Boolean}
470      */
471     isOpacityModifyRGB:function () {
472         return this._opacityModifyRGB;
473     },
474 
475     // Animation
476 
477     /**
478      * Changes the display frame with animation name and index.<br/>
479      * The animation name will be get from the CCAnimationCache
480      * @param {String} animationName
481      * @param {Number} frameIndex
482      */
483     setDisplayFrameWithAnimationName:function (animationName, frameIndex) {
484         cc.assert(animationName, cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_3);
485 
486         var cache = cc.animationCache.getAnimation(animationName);
487         if(!cache){
488             cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName);
489             return;
490         }
491         var animFrame = cache.getFrames()[frameIndex];
492         if(!animFrame){
493             cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_2);
494             return;
495         }
496         this.setSpriteFrame(animFrame.getSpriteFrame());
497     },
498 
499     /**
500      * Returns the batch node object if this sprite is rendered by cc.SpriteBatchNode
501      * @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.
502      */
503     getBatchNode:function () {
504         return this._batchNode;
505     },
506 
507     _setReorderChildDirtyRecursively:function () {
508         //only set parents flag the first time
509         if (!this._reorderChildDirty) {
510             this._reorderChildDirty = true;
511             var pNode = this._parent;
512             while (pNode && pNode !== this._batchNode) {
513                 pNode._setReorderChildDirtyRecursively();
514                 pNode = pNode.parent;
515             }
516         }
517     },
518 
519     // CCTextureProtocol
520     /**
521      * Returns the texture of the sprite node
522      * @returns {cc.Texture2D}
523      */
524     getTexture:function () {
525         return this._texture;
526     },
527 
528     _softInit: function (fileName, rect, rotated) {
529         if (fileName === undefined)
530             cc.Sprite.prototype.init.call(this);
531         else if (cc.isString(fileName)) {
532             if (fileName[0] === "#") {
533                 // Init with a sprite frame name
534                 var frameName = fileName.substr(1, fileName.length - 1);
535                 var spriteFrame = cc.spriteFrameCache.getSpriteFrame(frameName);
536                 if (spriteFrame)
537                     this.initWithSpriteFrame(spriteFrame);
538                 else
539                     cc.log("%s does not exist", fileName);
540             } else {
541                 // Init  with filename and rect
542                 cc.Sprite.prototype.init.call(this, fileName, rect);
543             }
544         } else if (typeof fileName === "object") {
545             if (fileName instanceof cc.Texture2D) {
546                 // Init  with texture and rect
547                 this.initWithTexture(fileName, rect, rotated);
548             } else if (fileName instanceof cc.SpriteFrame) {
549                 // Init with a sprite frame
550                 this.initWithSpriteFrame(fileName);
551             } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) {
552                 // Init with a canvas or image element
553                 var texture2d = new cc.Texture2D();
554                 texture2d.initWithElement(fileName);
555                 texture2d.handleLoadedTexture();
556                 this.initWithTexture(texture2d);
557             }
558         }
559     },
560 
561     /**
562      * Returns the quad (tex coords, vertex coords and color) information.
563      * @return {cc.V3F_C4B_T2F_Quad|null} Returns a cc.V3F_C4B_T2F_Quad object when render mode is WebGL, returns null when render mode is Canvas.
564      */
565     getQuad:function () {
566         return null;
567     },
568 
569     /**
570      * conforms to cc.TextureProtocol protocol
571      * @function
572      * @param {Number|cc.BlendFunc} src
573      * @param {Number} dst
574      */
575     setBlendFunc: function (src, dst) {
576         var locBlendFunc = this._blendFunc;
577         if (dst === undefined) {
578             locBlendFunc.src = src.src;
579             locBlendFunc.dst = src.dst;
580         } else {
581             locBlendFunc.src = src;
582             locBlendFunc.dst = dst;
583         }
584         this._renderCmd.updateBlendFunc(locBlendFunc);
585     },
586 
587     /**
588      * Initializes an empty sprite with nothing init.<br/>
589      * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
590      * @function
591      * @return {Boolean}
592      */
593     init: function () {
594         var _t = this;
595         if (arguments.length > 0)
596             return _t.initWithFile(arguments[0], arguments[1]);
597 
598         cc.Node.prototype.init.call(_t);
599         _t.dirty = _t._recursiveDirty = false;
600 
601         _t._blendFunc.src = cc.BLEND_SRC;
602         _t._blendFunc.dst = cc.BLEND_DST;
603 
604         _t.texture = null;
605         _t._flippedX = _t._flippedY = false;
606 
607         // default transform anchor: center
608         _t.anchorX = 0.5;
609         _t.anchorY = 0.5;
610 
611         // zwoptex default values
612         _t._offsetPosition.x = 0;
613         _t._offsetPosition.y = 0;
614         _t._hasChildren = false;
615 
616         // updated in "useSelfRender"
617         // Atlas: TexCoords
618         _t.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0));
619         return true;
620     },
621 
622     /**
623      * <p>
624      *     Initializes a sprite with an image filename.<br/>
625      *
626      *     This method will find pszFilename from local file system, load its content to CCTexture2D,<br/>
627      *     then use CCTexture2D to create a sprite.<br/>
628      *     After initialization, the rect used will be the size of the image. The offset will be (0,0).<br/>
629      *     Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
630      * </p>
631      * @param {String} filename The path to an image file in local file system
632      * @param {cc.Rect} rect The rectangle assigned the content area from texture.
633      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
634      */
635     initWithFile:function (filename, rect) {
636         cc.assert(filename, cc._LogInfos.Sprite_initWithFile);
637 
638         var tex = cc.textureCache.getTextureForKey(filename);
639         if (!tex) {
640             tex = cc.textureCache.addImage(filename);
641         }
642 
643         if (!tex.isLoaded()) {
644             this._loader.clear();
645             this._loader.once(tex, function () {
646                 this.initWithFile(filename, rect);
647                 this.dispatchEvent("load");
648             }, this);
649             return false;
650         }
651 
652         if (!rect) {
653             var size = tex.getContentSize();
654             rect = cc.rect(0, 0, size.width, size.height);
655         }
656         return this.initWithTexture(tex, rect);
657     },
658 
659     /**
660      * Initializes a sprite with a texture and a rect in points, optionally rotated.  <br/>
661      * After initialization, the rect used will be the size of the texture, and the offset will be (0,0).<br/>
662      * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
663      * @function
664      * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites.
665      * @param {cc.Rect} [rect] Only the contents inside rect of this texture will be applied for this sprite.
666      * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
667      * @param {Boolean} [counterclockwise=true] Whether or not the texture rectangle rotation is counterclockwise (texture package is counterclockwise, spine is clockwise).
668      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
669      */
670     initWithTexture: function (texture, rect, rotated, counterclockwise) {
671         var _t = this;
672         cc.assert(arguments.length !== 0, cc._LogInfos.CCSpriteBatchNode_initWithTexture);
673         this._loader.clear();
674 
675         _t._textureLoaded = texture.isLoaded();
676         if (!_t._textureLoaded) {
677             this._loader.once(texture, function () {
678                 this.initWithTexture(texture, rect, rotated, counterclockwise);
679                 this.dispatchEvent("load");
680             }, this);
681             return false;
682         }
683 
684         rotated = rotated || false;
685         texture = this._renderCmd._handleTextureForRotatedTexture(texture, rect, rotated, counterclockwise);
686 
687         if (!cc.Node.prototype.init.call(_t))
688             return false;
689 
690         _t._batchNode = null;
691         _t._recursiveDirty = false;
692         _t.dirty = false;
693         _t._opacityModifyRGB = true;
694 
695         _t._blendFunc.src = cc.BLEND_SRC;
696         _t._blendFunc.dst = cc.BLEND_DST;
697 
698         _t._flippedX = _t._flippedY = false;
699 
700         // zwoptex default values
701         _t._offsetPosition.x = 0;
702         _t._offsetPosition.y = 0;
703         _t._hasChildren = false;
704 
705         _t._rectRotated = rotated;
706         if (rect) {
707             _t._rect.x = rect.x;
708             _t._rect.y = rect.y;
709             _t._rect.width = rect.width;
710             _t._rect.height = rect.height;
711         }
712 
713         if (!rect)
714             rect = cc.rect(0, 0, texture.width, texture.height);
715 
716         this._renderCmd._checkTextureBoundary(texture, rect, rotated);
717 
718         _t.setTexture(texture);
719         _t.setTextureRect(rect, rotated);
720 
721         // by default use "Self Render".
722         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
723         _t.setBatchNode(null);
724         return true;
725     },
726 
727     /**
728      * Updates the texture rect of the CCSprite in points.
729      * @function
730      * @param {cc.Rect} rect a rect of texture
731      * @param {Boolean} [rotated] Whether or not the texture is rotated
732      * @param {cc.Size} [untrimmedSize] The original pixels size of the texture
733      * @param {Boolean} [needConvert] contentScaleFactor switch
734      */
735     setTextureRect: function (rect, rotated, untrimmedSize, needConvert) {
736         var _t = this;
737         _t._rectRotated = rotated || false;
738         _t.setContentSize(untrimmedSize || rect);
739 
740         _t.setVertexRect(rect);
741         _t._renderCmd._setTextureCoords(rect, needConvert);
742 
743         var relativeOffsetX = _t._unflippedOffsetPositionFromCenter.x, relativeOffsetY = _t._unflippedOffsetPositionFromCenter.y;
744         if (_t._flippedX)
745             relativeOffsetX = -relativeOffsetX;
746         if (_t._flippedY)
747             relativeOffsetY = -relativeOffsetY;
748         var locRect = _t._rect;
749         _t._offsetPosition.x = relativeOffsetX + (_t._contentSize.width - locRect.width) / 2;
750         _t._offsetPosition.y = relativeOffsetY + (_t._contentSize.height - locRect.height) / 2;
751     },
752 
753     // BatchNode methods
754 
755     /**
756      * Add child to sprite (override cc.Node)
757      * @function
758      * @param {cc.Sprite} child
759      * @param {Number} localZOrder  child's zOrder
760      * @param {number|String} [tag] child's tag
761      * @override
762      */
763     addChild: function (child, localZOrder, tag) {
764         cc.assert(child, cc._LogInfos.CCSpriteBatchNode_addChild_2);
765 
766         if (localZOrder == null)
767             localZOrder = child._localZOrder;
768         if (tag == null)
769             tag = child.tag;
770 
771         if(this._renderCmd._setBatchNodeForAddChild(child)){
772             //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check
773             cc.Node.prototype.addChild.call(this, child, localZOrder, tag);
774             this._hasChildren = true;
775         }
776     },
777 
778     // Frames
779     /**
780      * Sets a new sprite frame to the sprite.
781      * @function
782      * @param {cc.SpriteFrame|String} newFrame
783      */
784     setSpriteFrame: function (newFrame) {
785         var _t = this;
786         if(cc.isString(newFrame)){
787             newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame);
788             cc.assert(newFrame, cc._LogInfos.Sprite_setSpriteFrame)
789         }
790         this._loader.clear();
791 
792         this.setNodeDirty(true);
793 
794         // update rect
795         var pNewTexture = newFrame.getTexture();
796         _t._textureLoaded = newFrame.textureLoaded();
797         this._loader.clear();
798         if (!_t._textureLoaded) {
799             this._loader.once(pNewTexture, function () {
800                 this.setSpriteFrame(newFrame);
801                 this.dispatchEvent("load");
802             }, this);
803             return false;
804         }
805 
806         var frameOffset = newFrame.getOffset();
807         _t._unflippedOffsetPositionFromCenter.x = frameOffset.x;
808         _t._unflippedOffsetPositionFromCenter.y = frameOffset.y;
809 
810         if (pNewTexture !== _t._texture) {
811             this._renderCmd._setTexture(pNewTexture);
812             _t.setColor(_t._realColor);
813         }
814         _t.setTextureRect(newFrame.getRect(), newFrame.isRotated(), newFrame.getOriginalSize());
815     },
816 
817     /**
818      * Sets a new display frame to the sprite.
819      * @param {cc.SpriteFrame|String} newFrame
820      * @deprecated
821      */
822     setDisplayFrame: function(newFrame){
823         cc.log(cc._LogInfos.Sprite_setDisplayFrame);
824         this.setSpriteFrame(newFrame);
825     },
826 
827     /**
828      * Returns whether or not a cc.SpriteFrame is being displayed
829      * @function
830      * @param {cc.SpriteFrame} frame
831      * @return {Boolean}
832      */
833     isFrameDisplayed: function(frame){
834         return this._renderCmd.isFrameDisplayed(frame);
835     },
836 
837     /**
838      * Returns the current displayed frame.
839      * @deprecated since 3.4, please use getSpriteFrame instead
840      * @return {cc.SpriteFrame}
841      */
842     displayFrame: function () {
843         return this.getSpriteFrame();
844     },
845 
846     /**
847      * Returns the current displayed frame.
848      * @return {cc.SpriteFrame}
849      */
850     getSpriteFrame: function () {
851         return new cc.SpriteFrame(this._texture,
852             cc.rectPointsToPixels(this._rect),
853             this._rectRotated,
854             cc.pointPointsToPixels(this._unflippedOffsetPositionFromCenter),
855             cc.sizePointsToPixels(this._contentSize));
856     },
857 
858     /**
859      * Sets the batch node to sprite
860      * @function
861      * @param {cc.SpriteBatchNode|null} spriteBatchNode
862      * @example
863      *  var batch = new cc.SpriteBatchNode("Images/grossini_dance_atlas.png", 15);
864      *  var sprite = new cc.Sprite(batch.texture, cc.rect(0, 0, 57, 57));
865      *  batch.addChild(sprite);
866      *  layer.addChild(batch);
867      */
868     setBatchNode:function (spriteBatchNode) {
869         var _t = this;
870         _t._batchNode = spriteBatchNode; // weak reference
871 
872         // self render
873         if (!_t._batchNode) {
874             _t.atlasIndex = cc.Sprite.INDEX_NOT_INITIALIZED;
875             _t.textureAtlas = null;
876             _t._recursiveDirty = false;
877             _t.dirty = false;
878         } else {
879             // using batch
880             _t._transformToBatch = cc.affineTransformIdentity();
881             _t.textureAtlas = _t._batchNode.getTextureAtlas(); // weak ref
882         }
883     },
884 
885     // CCTextureProtocol
886     /**
887      * Sets the texture of sprite
888      * @function
889      * @param {cc.Texture2D|String} texture
890      */
891     setTexture: function (texture) {
892         if(!texture)
893             return this._renderCmd._setTexture(null);
894 
895         //CCSprite.cpp 327 and 338
896         var isFileName = cc.isString(texture);
897 
898         if(isFileName)
899             texture = cc.textureCache.addImage(texture);
900 
901         this._loader.clear();
902         if (!texture._textureLoaded) {
903             // wait for the load to be set again
904             this._loader.once(texture, function () {
905                 this.setTexture(texture);
906                 this.dispatchEvent("load");
907             }, this);
908             return false;
909         }
910 
911         this._renderCmd._setTexture(texture);
912         if (isFileName)
913             this._changeRectWithTexture(texture);
914         this.setColor(this._realColor);
915         this._textureLoaded = true;
916     },
917 
918     _changeRectWithTexture: function(texture){
919         var contentSize = texture._contentSize;
920         var rect = cc.rect(
921             0, 0,
922             contentSize.width, contentSize.height
923         );
924         this.setTextureRect(rect);
925     },
926 
927     _createRenderCmd: function(){
928         if(cc._renderType === cc.game.RENDER_TYPE_CANVAS)
929             return new cc.Sprite.CanvasRenderCmd(this);
930         else
931             return new cc.Sprite.WebGLRenderCmd(this);
932     }
933 });
934 
935 /**
936  * Create a sprite with image path or frame name or texture or spriteFrame.
937  * @deprecated since v3.0, please use new construction instead
938  * @see cc.Sprite
939  * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName  The string which indicates a path to image file, e.g., "scene1/monster.png".
940  * @param {cc.Rect} rect  Only the contents inside rect of pszFileName's texture will be applied for this sprite.
941  * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
942  * @return {cc.Sprite} A valid sprite object
943  */
944 cc.Sprite.create = function (fileName, rect, rotated) {
945     return new cc.Sprite(fileName, rect, rotated);
946 };
947 
948 /**
949  * @deprecated since v3.0, please use new construction instead
950  * @see cc.Sprite
951  * @function
952  */
953 cc.Sprite.createWithTexture = cc.Sprite.create;
954 
955 /**
956  * @deprecated since v3.0, please use new construction instead
957  * @see cc.Sprite
958  * @function
959  */
960 cc.Sprite.createWithSpriteFrameName = cc.Sprite.create;
961 
962 /**
963  * @deprecated since v3.0, please use new construction instead
964  * @see cc.Sprite
965  * @function
966  */
967 cc.Sprite.createWithSpriteFrame = cc.Sprite.create;
968 /**
969  * cc.Sprite invalid index on the cc.SpriteBatchNode
970  * @constant
971  * @type {Number}
972  */
973 cc.Sprite.INDEX_NOT_INITIALIZED = -1;
974 
975 cc.EventHelper.prototype.apply(cc.Sprite.prototype);
976 
977 cc.assert(cc.isFunction(cc._tmp.PrototypeSprite), cc._LogInfos.MissingFile, "SpritesPropertyDefine.js");
978 cc._tmp.PrototypeSprite();
979 delete cc._tmp.PrototypeSprite;
980 
981 (function () {
982     var manager = cc.Sprite.LoadManager = function () {
983         this.list = [];
984     };
985 
986     manager.prototype.add = function (source, callback, target) {
987         if (!source || !source.addEventListener) return;
988         source.addEventListener('load', callback, target);
989         this.list.push({
990             source: source,
991             listener: callback,
992             target: target
993         });
994     };
995     manager.prototype.once = function (source, callback, target) {
996         if (!source || !source.addEventListener) return;
997         var tmpCallback = function (event) {
998             source.removeEventListener('load', tmpCallback, target);
999             callback.call(target, event);
1000         };
1001         source.addEventListener('load', tmpCallback, target);
1002         this.list.push({
1003             source: source,
1004             listener: tmpCallback,
1005             target: target
1006         });
1007     };
1008     manager.prototype.clear = function () {
1009         while (this.list.length > 0) {
1010             var item = this.list.pop();
1011             item.source.removeEventListener('load', item.listener, item.target);
1012         }
1013     };
1014 })();