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