1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * cc.Sprite invalid index on the cc.SpriteBatchNode
 29  * @constant
 30  * @type Number
 31  */
 32 cc.SPRITE_INDEX_NOT_INITIALIZED = -1;
 33 
 34 /**
 35  * generate texture's cache for texture tint
 36  * @function
 37  * @param {HTMLImageElement} texture
 38  * @return {Array}
 39  */
 40 
 41 cc.generateTextureCacheForColor = function (texture) {
 42     if (texture.hasOwnProperty('channelCache')) {
 43         return texture.channelCache;
 44     }
 45 
 46     var textureCache = [
 47         document.createElement("canvas"),
 48         document.createElement("canvas"),
 49         document.createElement("canvas"),
 50         document.createElement("canvas")
 51     ];
 52 
 53     function renderToCache() {
 54         var ref = cc.generateTextureCacheForColor;
 55 
 56         var w = texture.width;
 57         var h = texture.height;
 58 
 59         textureCache[0].width = w;
 60         textureCache[0].height = h;
 61         textureCache[1].width = w;
 62         textureCache[1].height = h;
 63         textureCache[2].width = w;
 64         textureCache[2].height = h;
 65         textureCache[3].width = w;
 66         textureCache[3].height = h;
 67 
 68         ref.canvas.width = w;
 69         ref.canvas.height = h;
 70 
 71         var ctx = ref.canvas.getContext("2d");
 72         ctx.drawImage(texture, 0, 0);
 73 
 74         ref.tempCanvas.width = w;
 75         ref.tempCanvas.height = h;
 76 
 77         var pixels = ctx.getImageData(0, 0, w, h).data;
 78 
 79         for (var rgbI = 0; rgbI < 4; rgbI++) {
 80             var cacheCtx = textureCache[rgbI].getContext('2d');
 81             cacheCtx.getImageData(0, 0, w, h).data;
 82             ref.tempCtx.drawImage(texture, 0, 0);
 83 
 84             var to = ref.tempCtx.getImageData(0, 0, w, h);
 85             var toData = to.data;
 86 
 87             for (var i = 0; i < pixels.length; i += 4) {
 88                 toData[i  ] = (rgbI === 0) ? pixels[i  ] : 0;
 89                 toData[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0;
 90                 toData[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0;
 91                 toData[i + 3] = pixels[i + 3];
 92             }
 93             cacheCtx.putImageData(to, 0, 0);
 94         }
 95         texture.onload = null;
 96     }
 97 
 98     try {
 99         renderToCache();
100     } catch (e) {
101         texture.onload = renderToCache;
102     }
103 
104     texture.channelCache = textureCache;
105     return textureCache;
106 };
107 
108 cc.generateTextureCacheForColor.canvas = document.createElement('canvas');
109 cc.generateTextureCacheForColor.tempCanvas = document.createElement('canvas');
110 cc.generateTextureCacheForColor.tempCtx = cc.generateTextureCacheForColor.tempCanvas.getContext('2d');
111 
112 /**
113  * generate tinted texture
114  * source-in: Where source and destination overlaps and both are opaque, the source is displayed.
115  * Everywhere else transparency is displayed.
116  * @function
117  * @param {HTMLImageElement} texture
118  * @param {cc.Color3B|cc.Color4F} color
119  * @param {cc.Rect} rect
120  * @return {HTMLCanvasElement}
121  */
122 cc.generateTintImage2 = function (texture, color, rect) {
123     if (!rect) {
124         rect = cc.rect(0, 0, texture.width, texture.height);
125         rect = cc.RECT_PIXELS_TO_POINTS(rect);
126     }
127     var selColor;
128     if (color instanceof cc.Color4F) {
129         selColor = cc.c4b(color.r * 255, color.g * 255, color.b * 255, color.a * 255);
130     } else {
131         selColor = cc.c4b(color.r, color.g, color.b, 50);//color;
132     }
133 
134     var buff = document.createElement("canvas");
135     var ctx = buff.getContext("2d");
136 
137     if (buff.width != rect.width) buff.width = rect.width;
138     if (buff.height != rect.height) buff.height = rect.height;
139     ctx.save();
140 
141     ctx.drawImage(texture, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height);
142 
143     ctx.globalCompositeOperation = "source-in";
144     ctx.globalAlpha = selColor.a / 255.0;
145     ctx.fillStyle = "rgb(" + selColor.r + "," + selColor.g + "," + selColor.b + ")";
146     ctx.fillRect(0, 0, rect.width, rect.height);
147     ctx.restore();
148 
149     return buff;
150 };
151 
152 /**
153  * generate tinted texture
154  * lighter:    The source and destination colors are added to each other, resulting in brighter colors,
155  * moving towards color values of 1 (maximum brightness for that color).
156  * @function
157  * @param {HTMLImageElement} texture
158  * @param {Array} tintedImgCache
159  * @param {cc.Color3B|cc.Color4F} color
160  * @param {cc.Rect} rect
161  * @param {HTMLCanvasElement} [renderCanvas]
162  * @return {HTMLCanvasElement}
163  */
164 cc.generateTintImage = function (texture, tintedImgCache, color, rect, renderCanvas) {
165     if (!rect)
166         rect = cc.rect(0, 0, texture.width, texture.height);
167 
168     var selColor;
169     if (color.a == null) {
170         // Optimization for the particle system which mainly uses c4f colors
171         selColor = cc.c4f(color.r / 255.0, color.g / 255.0, color.b / 255, 1);
172     } else {
173         selColor = color;
174     }
175 
176     var w = Math.min(rect.width, tintedImgCache[0].width);
177     var h = Math.min(rect.height, tintedImgCache[0].height);
178     var buff = renderCanvas;
179     var ctx;
180 
181     // Create a new buffer if required
182     if (!buff) {
183         buff = document.createElement("canvas");
184         buff.width = w;
185         buff.height = h;
186         ctx = buff.getContext("2d");
187     } else {
188         ctx = buff.getContext("2d");
189         ctx.clearRect(0, 0, w, h);
190     }
191 
192     ctx.save();
193     ctx.globalCompositeOperation = 'lighter';
194 
195     // Make sure to keep the renderCanvas alpha in mind in case of overdraw
196     var a = ctx.globalAlpha;
197     if (selColor.r > 0) {
198         ctx.globalAlpha = selColor.r * a;
199         ctx.drawImage(tintedImgCache[0], rect.x, rect.y, w, h, 0, 0, w, h);
200     }
201     if (selColor.g > 0) {
202         ctx.globalAlpha = selColor.g * a;
203         ctx.drawImage(tintedImgCache[1], rect.x, rect.y, w, h, 0, 0, w, h);
204     }
205     if (selColor.b > 0) {
206         ctx.globalAlpha = selColor.b * a;
207         ctx.drawImage(tintedImgCache[2], rect.x, rect.y, w, h, 0, 0, w, h);
208     }
209 
210     if ((selColor.r === 0) && (selColor.g === 0) && (selColor.b === 0)) {
211         ctx.globalAlpha = a;
212         ctx.drawImage(tintedImgCache[3], rect.x, rect.y, w, h, 0, 0, w, h);
213     }
214 
215     ctx.restore();
216     return buff;
217 };
218 
219 cc.cutRotateImageToCanvas = function (texture, rect) {
220     if (!texture)
221         return null;
222 
223     if (!rect)
224         return texture;
225 
226     var nCanvas = document.createElement("canvas");
227     nCanvas.width = rect.width;
228     nCanvas.height = rect.height;
229 
230     var ctx = nCanvas.getContext("2d");
231     ctx.translate(nCanvas.width / 2, nCanvas.height / 2);
232     ctx.rotate(-1.5707963267948966);
233     ctx.drawImage(texture, rect.x, rect.y, rect.height, rect.width, -rect.height / 2, -rect.width / 2, rect.height, rect.width);
234     return nCanvas;
235 };
236 
237 /**
238  * a Values object for transform
239  * @Class
240  * @Construct
241  * @param {cc.Point} pos position x and y
242  * @param {cc.Point} scale scale x and y
243  * @param {Number} rotation
244  * @param {cc.Point} skew skew x and y
245  * @param {cc.Point} ap anchor point in pixels
246  * @param {Boolean} visible
247  */
248 cc.TransformValues = function (pos, scale, rotation, skew, ap, visible) {
249     this.pos = pos;		// position x and y
250     this.scale = scale;		// scale x and y
251     this.rotation = rotation;
252     this.skew = skew;		// skew x and y
253     this.ap = ap;			// anchor point in pixels
254     this.visible = visible;
255 };
256 
257 cc.RENDER_IN_SUBPIXEL = function (A) {
258     return (0 | A);
259 };
260 if (cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) {
261     cc.RENDER_IN_SUBPIXEL = function (A) {
262         return A;
263     };
264 }
265 
266 /**
267  * <p>cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) )  <br/>
268  *
269  * cc.Sprite can be created with an image, or with a sub-rectangle of an image.  <br/>
270  *
271  * If the parent or any of its ancestors is a cc.SpriteBatchNode then the following features/limitations are valid   <br/>
272  *    - Features when the parent is a cc.BatchNode: <br/>
273  *        - MUCH faster rendering, specially if the cc.SpriteBatchNode has many children. All the children will be drawn in a single batch.  <br/>
274  *
275  *    - Limitations   <br/>
276  *        - Camera is not supported yet (eg: CCOrbitCamera action doesn't work)  <br/>
277  *        - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl) <br/>
278  *        - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property.  <br/>
279  *        - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property. <br/>
280  *        - Parallax scroller is not supported, but can be simulated with a "proxy" sprite.        <br/>
281  *
282  *  If the parent is an standard cc.Node, then cc.Sprite behaves like any other cc.Node:      <br/>
283  *    - It supports blending functions    <br/>
284  *    - It supports aliasing / antialiasing    <br/>
285  *    - But the rendering will be slower: 1 draw per children.   <br/>
286  *
287  * The default anchorPoint in cc.Sprite is (0.5, 0.5). </p>
288  * @class
289  * @extends cc.NodeRGBA
290  *
291  * @example
292  * var aSprite = new cc.Sprite();
293  * aSprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320));
294  */
295 cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{
296     RGBAProtocol:true,
297     //
298     // Data used when the sprite is rendered using a CCSpriteSheet
299     //
300     _textureAtlas:null, //cc.SpriteBatchNode texture atlas
301 
302     _atlasIndex:0,
303     _batchNode:null,
304     _dirty:false, //Whether the sprite needs to be updated
305     _recursiveDirty:null, //Whether all of the sprite's children needs to be updated
306     _hasChildren:null, //Whether the sprite contains children
307     _shouldBeHidden:false, //should not be drawn because one of the ancestors is not visible
308     _transformToBatch:null,
309 
310     //
311     // Data used when the sprite is self-rendered
312     //
313     _blendFunc:null, //It's required for CCTextureProtocol inheritance
314     _texture:null, //cc.Texture2D object that is used to render the sprite
315 
316     //
317     // Shared data
318     //
319     // texture
320     _rect:cc.rect(0, 0, 0, 0), //Retangle of cc.Texture2D
321     _rectRotated:false, //Whether the texture is rotated
322 
323     // Offset Position (used by Zwoptex)
324     _offsetPosition:null, // absolute
325     _unflippedOffsetPositionFromCenter:null,
326 
327     _opacityModifyRGB:false,
328 
329     // image is flipped
330     _flippedX:false, //Whether the sprite is flipped horizontally or not.
331     _flippedY:false, //Whether the sprite is flipped vertically or not.
332 
333     _textureLoaded:false,
334     _loadedEventListeners: null,
335     _newTextureWhenChangeColor: null,         //hack property for LabelBMFont
336 
337     textureLoaded:function(){
338         return this._textureLoaded;
339     },
340 
341     addLoadedEventListener:function(callback, target){
342         this._loadedEventListeners.push({eventCallback:callback, eventTarget:target});
343     },
344 
345     _callLoadedEventCallbacks:function(){
346         var locListeners = this._loadedEventListeners;
347         for(var i = 0, len = locListeners.length;  i < len; i++){
348             var selCallback = locListeners[i];
349             selCallback.eventCallback.call(selCallback.eventTarget, this);
350         }
351         locListeners.length = 0;
352     },
353 
354     /**
355      * Whether or not the Sprite needs to be updated in the Atlas
356      * @return {Boolean} true if the sprite needs to be updated in the Atlas, false otherwise.
357      */
358     isDirty:function () {
359         return this._dirty;
360     },
361 
362     /**
363      * Makes the Sprite to be updated in the Atlas.
364      * @param {Boolean} bDirty
365      */
366     setDirty:function (bDirty) {
367         this._dirty = bDirty;
368     },
369 
370     /**
371      * Returns whether or not the texture rectangle is rotated.
372      * @return {Boolean}
373      */
374     isTextureRectRotated:function () {
375         return this._rectRotated;
376     },
377 
378     /**
379      * Returns the index used on the TextureAtlas.
380      * @return {Number}
381      */
382     getAtlasIndex:function () {
383         return this._atlasIndex;
384     },
385 
386     /**
387      * Set the index used on the TextureAtlas.
388      * @warning Don't modify this value unless you know what you are doing
389      * @param {Number} atlasIndex
390      */
391     setAtlasIndex:function (atlasIndex) {
392         this._atlasIndex = atlasIndex;
393     },
394 
395     /**
396      * returns the rect of the cc.Sprite in points
397      * @return {cc.Rect}
398      */
399     getTextureRect:function () {
400         return cc.rect(this._rect.x, this._rect.y, this._rect.width, this._rect.height);
401     },
402 
403     /**
404      * Gets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
405      * @return {cc.TextureAtlas}
406      */
407     getTextureAtlas:function () {
408         return this._textureAtlas;
409     },
410 
411     /**
412      * Sets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
413      * @param {cc.TextureAtlas} textureAtlas
414      */
415     setTextureAtlas:function (textureAtlas) {
416         this._textureAtlas = textureAtlas;
417     },
418 
419     /**
420      * return the SpriteBatchNode of the cc.Sprite
421      * @return {cc.SpriteBatchNode}
422      */
423     getSpriteBatchNode:function () {
424         return this._batchNode;
425     },
426 
427     /**
428      * set the SpriteBatchNode of the cc.Sprite
429      * @param {cc.SpriteBatchNode} spriteBatchNode
430      */
431     setSpriteBatchNode:function (spriteBatchNode) {
432         this._batchNode = spriteBatchNode;
433     },
434 
435     /**
436      * Gets the offset position of the sprite. Calculated automatically by editors like Zwoptex.
437      * @return {cc.Point}
438      */
439     getOffsetPosition:function () {
440         return cc.p(this._offsetPosition.x, this._offsetPosition.y);
441     },
442 
443     /**
444      * conforms to cc.TextureProtocol protocol
445      * @return {cc.BlendFunc}
446      */
447     getBlendFunc:function () {
448         return this._blendFunc;
449     },
450 
451     /**
452      * Initializes a sprite with an SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite
453      * @param {cc.SpriteFrame} spriteFrame A CCSpriteFrame object. It should includes a valid texture and a rect
454      * @return {Boolean}  true if the sprite is initialized properly, false otherwise.
455      * @example
456      * var spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame("grossini_dance_01.png");
457      * var sprite = new cc.Sprite();
458      * sprite.initWithSpriteFrame(spriteFrame);
459      */
460     initWithSpriteFrame:function (spriteFrame) {
461         cc.Assert(spriteFrame != null, "");
462         if(!spriteFrame.textureLoaded()){
463             //add event listener
464             this._textureLoaded = false;
465             spriteFrame.addLoadedEventListener(this._spriteFrameLoadedCallback, this);
466         }
467         var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect());
468         this.setDisplayFrame(spriteFrame);
469 
470         return ret;
471     },
472 
473     _spriteFrameLoadedCallback:null,
474 
475     _spriteFrameLoadedCallbackForWebGL:function(spriteFrame){
476         this.setNodeDirty();
477         this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize());
478         this._callLoadedEventCallbacks();
479     },
480 
481     _spriteFrameLoadedCallbackForCanvas:function(spriteFrame){
482         this.setNodeDirty();
483         this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize());
484         var curColor = this.getColor();
485         if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
486             this._changeTextureColor();
487 
488         this._callLoadedEventCallbacks();
489     },
490 
491     /**
492      * Initializes a sprite with a sprite frame name. <br/>
493      * A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name.  <br/>
494      * If the cc.SpriteFrame doesn't exist it will raise an exception. <br/>
495      * @param {String} spriteFrameName A key string that can fected a volid cc.SpriteFrame from cc.SpriteFrameCache
496      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
497      * @example
498      * var sprite = new cc.Sprite();
499      * sprite.initWithSpriteFrameName("grossini_dance_01.png");
500      */
501     initWithSpriteFrameName:function (spriteFrameName) {
502         cc.Assert(spriteFrameName != null, "");
503         var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName);
504         return this.initWithSpriteFrame(frame);
505     },
506 
507     /**
508      * tell the sprite to use batch node render.
509      * @param {cc.SpriteBatchNode} batchNode
510      */
511     useBatchNode:function (batchNode) {
512         this._textureAtlas = batchNode.getTextureAtlas(); // weak ref
513         this._batchNode = batchNode;
514     },
515 
516     /**
517      * <p>
518      *    set the vertex rect.<br/>
519      *    It will be called internally by setTextureRect.                           <br/>
520      *    Useful if you want to create 2x images from SD images in Retina Display.  <br/>
521      *    Do not call it manually. Use setTextureRect instead.  <br/>
522      *    (override this method to generate "double scale" sprites)
523      * </p>
524      * @param rect
525      */
526     setVertexRect:function (rect) {
527         this._rect = rect;
528     },
529 
530     sortAllChildren:function () {
531         if (this._reorderChildDirty) {
532             var j, tempItem, locChildren = this._children, tempChild;
533             for (var i = 1; i < locChildren.length; i++) {
534                 tempItem = locChildren[i];
535                 j = i - 1;
536                 tempChild =  locChildren[j];
537 
538                 //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller
539                 while (j >= 0 && ( tempItem._zOrder < tempChild._zOrder ||
540                     ( tempItem._zOrder == tempChild._zOrder && tempItem._orderOfArrival < tempChild._orderOfArrival ))) {
541                     locChildren[j + 1] = tempChild;
542                     j = j - 1;
543                     tempChild =  locChildren[j];
544                 }
545                 locChildren[j + 1] = tempItem;
546             }
547 
548             if (this._batchNode) {
549                 this._arrayMakeObjectsPerformSelector(locChildren, cc.Node.StateCallbackType.sortAllChildren);
550             }
551             this._reorderChildDirty = false;
552         }
553     },
554 
555     /**
556      * Reorders a child according to a new z value.  (override cc.Node )
557      * @param {cc.Node} child
558      * @param {Number} zOrder
559      * @override
560      */
561     reorderChild:function (child, zOrder) {
562         cc.Assert(child != null, "child is null");
563         cc.Assert(this._children.indexOf(child) > -1, "this child is not in children list");
564 
565         if (zOrder === child.getZOrder())
566             return;
567 
568         if (this._batchNode && !this._reorderChildDirty) {
569             this._setReorderChildDirtyRecursively();
570             this._batchNode.reorderBatch(true);
571         }
572         cc.Node.prototype.reorderChild.call(this, child, zOrder);
573     },
574 
575     /**
576      * Removes a child from the sprite. (override cc.Node )
577      * @param child
578      * @param cleanup  whether or not cleanup all running actions
579      * @override
580      */
581     removeChild:function (child, cleanup) {
582         if (this._batchNode)
583             this._batchNode.removeSpriteFromAtlas(child);
584         cc.Node.prototype.removeChild.call(this, child, cleanup);
585     },
586 
587     /**
588      * Removes all children from the container  (override cc.Node )
589      * @param cleanup whether or not cleanup all running actions
590      * @override
591      */
592     removeAllChildren:function (cleanup) {
593         var locChildren = this._children, locBatchNode = this._batchNode;
594         if (locBatchNode && locChildren != null) {
595             for (var i = 0, len = locChildren.length; i < len; i++)
596                 locBatchNode.removeSpriteFromAtlas(locChildren[i]);
597         }
598 
599         cc.Node.prototype.removeAllChildren.call(this, cleanup);
600         this._hasChildren = false;
601     },
602 
603     //
604     // cc.Node property overloads
605     //
606 
607     /**
608      * set Recursively is or isn't Dirty
609      * used only when parent is cc.SpriteBatchNode
610      * @param {Boolean} value
611      */
612     setDirtyRecursively:function (value) {
613         this._recursiveDirty = value;
614         this.setDirty(value);
615         // recursively set dirty
616         var locChildren = this._children;
617         if (locChildren != null) {
618             for (var i = 0; i < locChildren.length; i++) {
619                 if (locChildren[i] instanceof cc.Sprite)
620                     locChildren[i].setDirtyRecursively(true);
621             }
622         }
623     },
624 
625     /**
626      * HACK: optimization
627      */
628     SET_DIRTY_RECURSIVELY:function () {
629         if (this._batchNode && !this._recursiveDirty) {
630             this._recursiveDirty = true;
631             this._dirty = true;
632             if (this._hasChildren)
633                 this.setDirtyRecursively(true);
634         }
635     },
636 
637     /**
638      * position setter (override cc.Node )
639      * @param {cc.Point} pos
640      * @override
641      */
642     setPosition:function (pos) {
643         if (arguments.length >= 2)
644             cc.Node.prototype.setPosition.call(this, pos, arguments[1]);
645         else
646             cc.Node.prototype.setPosition.call(this, pos);
647         this.SET_DIRTY_RECURSIVELY();
648     },
649 
650     /**
651      * Rotation setter (override cc.Node )
652      * @param {Number} rotation
653      * @override
654      */
655     setRotation:function (rotation) {
656         cc.Node.prototype.setRotation.call(this, rotation);
657         this.SET_DIRTY_RECURSIVELY();
658     },
659 
660     setRotationX:function (rotationX) {
661         cc.Node.prototype.setRotationX.call(this, rotationX);
662         this.SET_DIRTY_RECURSIVELY();
663     },
664 
665     setRotationY:function (rotationY) {
666         cc.Node.prototype.setRotationY.call(this, rotationY);
667         this.SET_DIRTY_RECURSIVELY();
668     },
669 
670     /**
671      * SkewX setter (override cc.Node )
672      * @param {Number} sx SkewX value
673      * @override
674      */
675     setSkewX:function (sx) {
676         cc.Node.prototype.setSkewX.call(this, sx);
677         this.SET_DIRTY_RECURSIVELY();
678     },
679 
680     /**
681      * SkewY setter (override cc.Node )
682      * @param {Number} sy SkewY value
683      * @override
684      */
685     setSkewY:function (sy) {
686         cc.Node.prototype.setSkewY.call(this, sy);
687         this.SET_DIRTY_RECURSIVELY();
688     },
689 
690     /**
691      * ScaleX setter (override cc.Node )
692      * @param {Number} scaleX
693      * @override
694      */
695     setScaleX:function (scaleX) {
696         cc.Node.prototype.setScaleX.call(this, scaleX);
697         this.SET_DIRTY_RECURSIVELY();
698     },
699 
700     /**
701      * ScaleY setter (override cc.Node )
702      * @param {Number} scaleY
703      * @override
704      */
705     setScaleY:function (scaleY) {
706         cc.Node.prototype.setScaleY.call(this, scaleY);
707         this.SET_DIRTY_RECURSIVELY();
708     },
709 
710     /**
711      * <p>The scale factor of the node. 1.0 is the default scale factor. <br/>
712      * It modifies the X and Y scale at the same time. (override cc.Node ) <p/>
713      * @param {Number} scale
714      * @param {Number|null} [scaleY=]
715      * @override
716      */
717     setScale:function (scale, scaleY) {
718         cc.Node.prototype.setScale.call(this, scale, scaleY);
719         this.SET_DIRTY_RECURSIVELY();
720     },
721 
722     /**
723      * VertexZ setter (override cc.Node )
724      * @param {Number} vertexZ
725      * @override
726      */
727     setVertexZ:function (vertexZ) {
728         cc.Node.prototype.setVertexZ.call(this, vertexZ);
729         this.SET_DIRTY_RECURSIVELY();
730     },
731 
732     /**
733      * AnchorPoint setter  (override cc.Node )
734      * @param {cc.Point} anchor
735      * @override
736      */
737     setAnchorPoint:function (anchor) {
738         cc.Node.prototype.setAnchorPoint.call(this, anchor);
739         this.SET_DIRTY_RECURSIVELY();
740     },
741 
742     /**
743      * visible setter  (override cc.Node )
744      * @param {Boolean} visible
745      * @override
746      */
747     setVisible:function (visible) {
748         cc.Node.prototype.setVisible.call(this, visible);
749         this.SET_DIRTY_RECURSIVELY();
750     },
751 
752     /**
753      * IsRelativeAnchorPoint setter  (override cc.Node )
754      * @param {Boolean} relative
755      * @override
756      */
757     ignoreAnchorPointForPosition:function (relative) {
758         cc.Assert(!this._batchNode, "ignoreAnchorPointForPosition is invalid in cc.Sprite");
759         cc.Node.prototype.ignoreAnchorPointForPosition.call(this, relative);
760     },
761 
762     /**
763      * Sets whether the sprite should be flipped horizontally or not.
764      * @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise.
765      */
766     setFlippedX:function (flippedX) {
767         if (this._flippedX != flippedX) {
768             this._flippedX = flippedX;
769             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
770             this.setNodeDirty();
771         }
772     },
773 
774     /**
775      * Sets whether the sprite should be flipped vertically or not.
776      * @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise.
777      */
778     setFlippedY:function (flippedY) {
779         if (this._flippedY != flippedY) {
780             this._flippedY = flippedY;
781             this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
782             this.setNodeDirty();
783         }
784     },
785 
786     /**
787      * <p>
788      *     Returns the flag which indicates whether the sprite is flipped horizontally or not.                      <br/>
789      *                                                                                                              <br/>
790      * It only flips the texture of the sprite, and not the texture of the sprite's children.                       <br/>
791      * Also, flipping the texture doesn't alter the anchorPoint.                                                    <br/>
792      * If you want to flip the anchorPoint too, and/or to flip the children too use:                                <br/>
793      *      sprite->setScaleX(sprite->getScaleX() * -1);  <p/>
794      * @return {Boolean} true if the sprite is flipped horizaontally, false otherwise.
795      */
796     isFlippedX:function () {
797         return this._flippedX;
798     },
799 
800     /**
801      * <p>
802      *     Return the flag which indicates whether the sprite is flipped vertically or not.                         <br/>
803      *                                                                                                              <br/>
804      *      It only flips the texture of the sprite, and not the texture of the sprite's children.                  <br/>
805      *      Also, flipping the texture doesn't alter the anchorPoint.                                               <br/>
806      *      If you want to flip the anchorPoint too, and/or to flip the children too use:                           <br/>
807      *         sprite->setScaleY(sprite->getScaleY() * -1); <p/>
808      * @return {Boolean} true if the sprite is flipped vertically, flase otherwise.
809      */
810     isFlippedY:function () {
811         return this._flippedY;
812     },
813 
814     //
815     // RGBA protocol
816     //
817     /**
818      * opacity: conforms to CCRGBAProtocol protocol
819      * @param {Boolean} modify
820      */
821     setOpacityModifyRGB:null,
822 
823     _setOpacityModifyRGBForWebGL: function (modify) {
824         if (this._opacityModifyRGB !== modify) {
825             this._opacityModifyRGB = modify;
826             this.updateColor();
827         }
828     },
829 
830     _setOpacityModifyRGBForCanvas: function (modify) {
831         if (this._opacityModifyRGB !== modify) {
832             this._opacityModifyRGB = modify;
833             this.setNodeDirty();
834         }
835     },
836 
837     /**
838      * return IsOpacityModifyRGB value
839      * @return {Boolean}
840      */
841     isOpacityModifyRGB:function () {
842         return this._opacityModifyRGB;
843     },
844 
845     updateDisplayedOpacity: null,
846     _updateDisplayedOpacityForWebGL:function (parentOpacity) {
847         cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity);
848         this.updateColor();
849     },
850 
851     _updateDisplayedOpacityForCanvas:function (parentOpacity) {
852         cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity);
853         this._changeTextureColor();
854         this.setNodeDirty();
855     },
856 
857     // Animation
858 
859     /**
860      * changes the display frame with animation name and index.<br/>
861      * The animation name will be get from the CCAnimationCache
862      * @param animationName
863      * @param frameIndex
864      */
865     setDisplayFrameWithAnimationName:function (animationName, frameIndex) {
866         cc.Assert(animationName, "cc.Sprite#setDisplayFrameWithAnimationName. animationName must not be null");
867         var cache = cc.AnimationCache.getInstance().getAnimation(animationName);
868         cc.Assert(cache, "cc.Sprite#setDisplayFrameWithAnimationName: Frame not found");
869         var animFrame = cache.getFrames()[frameIndex];
870         cc.Assert(animFrame, "cc.Sprite#setDisplayFrame. Invalid frame");
871         this.setDisplayFrame(animFrame.getSpriteFrame());
872     },
873 
874     /**
875      * Returns the batch node object if this sprite is rendered by cc.SpriteBatchNode
876      * @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.
877      */
878     getBatchNode:function () {
879         return this._batchNode;
880     },
881 
882     _setReorderChildDirtyRecursively:function () {
883         //only set parents flag the first time
884         if (!this._reorderChildDirty) {
885             this._reorderChildDirty = true;
886             var pNode = this._parent;
887             while (pNode && pNode != this._batchNode) {
888                 pNode._setReorderChildDirtyRecursively();
889                 pNode = pNode.getParent();
890             }
891         }
892     },
893 
894     // CCTextureProtocol
895     getTexture:function () {
896         return this._texture;
897     },
898 
899     _quad:null, // vertex coords, texture coords and color info
900     _quadWebBuffer:null,
901     _quadDirty:false,
902     _colorized:false,
903     _isLighterMode:false,
904     _originalTexture:null,
905 
906     /**
907      * Constructor
908      * @param {String|cc.SpriteFrame|cc.SpriteBatchNode|HTMLImageElement|cc.Texture2D} fileName sprite construct parameter
909      */
910     ctor: null,
911 
912     _ctorForWebGL: function (fileName) {
913         cc.NodeRGBA.prototype.ctor.call(this);
914         this._shouldBeHidden = false;
915         this._offsetPosition = cc.p(0, 0);
916         this._unflippedOffsetPositionFromCenter = cc.p(0, 0);
917         this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST};
918 
919         this._quad = new cc.V3F_C4B_T2F_Quad();
920         this._quadWebBuffer = cc.renderContext.createBuffer();
921         this._quadDirty = true;
922 
923         this._textureLoaded = true;
924         this._loadedEventListeners = [];
925 
926         if (fileName) {
927             if (typeof(fileName) === "string") {
928                 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(fileName);
929                 this.initWithSpriteFrame(frame);
930             } else if (typeof(fileName) === "object") {
931                 if (fileName instanceof cc.SpriteFrame) {
932                     this.initWithSpriteFrame(fileName);
933                 } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) {
934                     var texture2d = new cc.Texture2D();
935                     texture2d.initWithElement(fileName);
936                     texture2d.handleLoadedTexture();
937                     this.initWithTexture(texture2d);
938                 } else if (fileName instanceof cc.Texture2D) {
939                     this.initWithTexture(fileName);
940                 }
941             }
942         }
943     },
944 
945     _ctorForCanvas: function (fileName) {
946         cc.NodeRGBA.prototype.ctor.call(this);
947         this._shouldBeHidden = false;
948         this._offsetPosition = cc.p(0, 0);
949         this._unflippedOffsetPositionFromCenter = cc.p(0, 0);
950         this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST};
951 
952         this._newTextureWhenChangeColor = false;
953         this._textureLoaded = true;
954         this._loadedEventListeners = [];
955 
956         if (fileName) {
957             if (typeof(fileName) === "string") {
958                 var frame = cc.SpriteFrameCache.getInstance().getSpriteFrame(fileName);
959                 this.initWithSpriteFrame(frame);
960             } else if (typeof(fileName) === "object") {
961                 if (fileName instanceof cc.SpriteFrame) {
962                     this.initWithSpriteFrame(fileName);
963                 } else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) {
964                     var texture2d = new cc.Texture2D();
965                     texture2d.initWithElement(fileName);
966                     texture2d.handleLoadedTexture();
967                     this.initWithTexture(texture2d);
968                 } else if (fileName instanceof cc.Texture2D) {
969                     this.initWithTexture(fileName);
970                 }
971             }
972         }
973     },
974 
975     /**
976      * Returns the quad (tex coords, vertex coords and color) information.
977      * @return {cc.V3F_C4B_T2F_Quad}
978      */
979     getQuad:function () {
980         return this._quad;
981     },
982 
983     /**
984      * conforms to cc.TextureProtocol protocol
985      * @param {Number|cc.BlendFunc} src
986      * @param {Number} dst
987      */
988     setBlendFunc: null,
989 
990     _setBlendFuncForWebGL: function (src, dst) {
991         if (arguments.length == 1)
992             this._blendFunc = src;
993         else
994             this._blendFunc = {src: src, dst: dst};
995     },
996 
997     _setBlendFuncForCanvas: function (src, dst) {
998         if (arguments.length == 1)
999             this._blendFunc = src;
1000         else
1001             this._blendFunc = {src: src, dst: dst};
1002         this._isLighterMode = (this._blendFunc &&
1003             (( this._blendFunc.src == gl.SRC_ALPHA && this._blendFunc.dst == gl.ONE) || (this._blendFunc.src == gl.ONE && this._blendFunc.dst == gl.ONE)));
1004     },
1005 
1006     /**
1007      * Initializes an empty sprite with nothing init.
1008      * @return {Boolean}
1009      */
1010     init:null,
1011 
1012     _initForWebGL: function () {
1013         if (arguments.length > 0)
1014             return this.initWithFile(arguments[0], arguments[1]);
1015 
1016         cc.NodeRGBA.prototype.init.call(this);
1017         this._dirty = this._recursiveDirty = false;
1018         this._opacityModifyRGB = true;
1019 
1020         this._blendFunc.src = cc.BLEND_SRC;
1021         this._blendFunc.dst = cc.BLEND_DST;
1022 
1023         // update texture (calls _updateBlendFunc)
1024         this.setTexture(null);
1025         this._textureLoaded = true;
1026         this._flippedX = this._flippedY = false;
1027 
1028         // default transform anchor: center
1029         this.setAnchorPoint(cc.p(0.5, 0.5));
1030 
1031         // zwoptex default values
1032         this._offsetPosition = cc.PointZero();
1033         this._hasChildren = false;
1034 
1035         // Atlas: Color
1036         var tempColor = {r: 255, g: 255, b: 255, a: 255};
1037         this._quad.bl.colors = tempColor;
1038         this._quad.br.colors = tempColor;
1039         this._quad.tl.colors = tempColor;
1040         this._quad.tr.colors = tempColor;
1041         this._quadDirty = true;
1042 
1043         // updated in "useSelfRender"
1044         // Atlas: TexCoords
1045         this.setTextureRect(cc.RectZero(), false, cc.SizeZero());
1046         return true;
1047     },
1048 
1049     _initForCanvas: function () {
1050         if (arguments.length > 0)
1051             return this.initWithFile(arguments[0], arguments[1]);
1052 
1053         cc.NodeRGBA.prototype.init.call(this);
1054         this._dirty = this._recursiveDirty = false;
1055         this._opacityModifyRGB = true;
1056 
1057         this._blendFunc.src = cc.BLEND_SRC;
1058         this._blendFunc.dst = cc.BLEND_DST;
1059 
1060         // update texture (calls _updateBlendFunc)
1061         this.setTexture(null);
1062         this._textureLoaded = true;
1063         this._flippedX = this._flippedY = false;
1064 
1065         // default transform anchor: center
1066         this.setAnchorPoint(cc.p(0.5, 0.5));
1067 
1068         // zwoptex default values
1069         this._offsetPosition = cc.PointZero();
1070         this._hasChildren = false;
1071 
1072         // updated in "useSelfRender"
1073         // Atlas: TexCoords
1074         this.setTextureRect(cc.RectZero(), false, cc.SizeZero());
1075         return true;
1076     },
1077 
1078     /**
1079      * <p>
1080      *     Initializes a sprite with an image filename.
1081      *
1082      *     This method will find pszFilename from local file system, load its content to CCTexture2D,
1083      *     then use CCTexture2D to create a sprite.
1084      *     After initialization, the rect used will be the size of the image. The offset will be (0,0).
1085      * </p>
1086      * @param {String} filename The path to an image file in local file system
1087      * @param {cc.Rect} rect The rectangle assigned the content area from texture.
1088      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
1089      * @example
1090      * var mySprite = new cc.Sprite();
1091      * mySprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320));
1092      */
1093     initWithFile:function (filename, rect) {
1094         cc.Assert(filename != null, "Sprite#initWithFile():Invalid filename for sprite");
1095         var texture = cc.TextureCache.getInstance().textureForKey(filename);
1096         if (!texture) {
1097             texture = cc.TextureCache.getInstance().addImage(filename);
1098             return this.initWithTexture(texture, rect);
1099         } else {
1100             if (!rect) {
1101                 var size = texture.getContentSize();
1102                 rect = cc.rect(0, 0, size.width, size.height);
1103             }
1104             return this.initWithTexture(texture, rect);
1105         }
1106     },
1107 
1108     /**
1109      * Initializes a sprite with a texture and a rect in points, optionally rotated.  <br/>
1110      * After initialization, the rect used will be the size of the texture, and the offset will be (0,0).
1111      * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites.
1112      * @param {cc.Rect} rect Only the contents inside rect of this texture will be applied for this sprite.
1113      * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
1114      * @return {Boolean} true if the sprite is initialized properly, false otherwise.
1115      * @example
1116      * var img =cc.TextureCache.getInstance().addImage("HelloHTML5World.png");
1117      * var mySprite = new cc.Sprite();
1118      * mySprite.initWithTexture(img,cc.rect(0,0,480,320));
1119      */
1120     initWithTexture: null,
1121 
1122     _initWithTextureForWebGL: function (texture, rect, rotated) {
1123         var argnum = arguments.length;
1124         if (argnum == 0)
1125             throw "Sprite.initWithTexture(): Argument must be non-nil ";
1126 
1127         rotated = rotated || false;
1128 
1129         if (!cc.NodeRGBA.prototype.init.call(this))
1130             return false;
1131 
1132         this._batchNode = null;
1133         this._recursiveDirty = false;
1134         this._dirty = false;
1135         this._opacityModifyRGB = true;
1136 
1137         this._blendFunc.src = cc.BLEND_SRC;
1138         this._blendFunc.dst = cc.BLEND_DST;
1139 
1140         this._flippedX = this._flippedY = false;
1141 
1142         // default transform anchor: center
1143         this.setAnchorPoint(cc.p(0.5, 0.5));
1144 
1145         // zwoptex default values
1146         this._offsetPosition = cc.p(0, 0);
1147         this._hasChildren = false;
1148 
1149         // Atlas: Color
1150         var tmpColor = new cc.Color4B(255, 255, 255, 255);
1151         var locQuad = this._quad;
1152         locQuad.bl.colors = tmpColor;
1153         locQuad.br.colors = tmpColor;
1154         locQuad.tl.colors = tmpColor;
1155         locQuad.tr.colors = tmpColor;
1156 
1157         var locTextureLoaded = texture.isLoaded();
1158         this._textureLoaded = locTextureLoaded;
1159 
1160         if (!locTextureLoaded) {
1161             this._rectRotated = rotated || false;
1162             this._rect = rect;
1163             texture.addLoadedEventListener(this._textureLoadedCallback, this);
1164             return true;
1165         }
1166 
1167         if (!rect) {
1168             rect = cc.rect(0, 0, 0, 0);
1169             rect.size = texture.getContentSize();
1170         }
1171         this.setTexture(texture);
1172         this.setTextureRect(rect, rotated, rect.size);
1173 
1174         // by default use "Self Render".
1175         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1176         this.setBatchNode(null);
1177         this._quadDirty = true;
1178         return true;
1179     },
1180 
1181     _initWithTextureForCanvas: function (texture, rect, rotated) {
1182         var argnum = arguments.length;
1183         if (argnum == 0)
1184             throw "Sprite.initWithTexture(): Argument must be non-nil ";
1185 
1186         rotated = rotated || false;
1187 
1188         if (!cc.NodeRGBA.prototype.init.call(this))
1189             return false;
1190 
1191         this._batchNode = null;
1192 
1193         this._recursiveDirty = false;
1194         this._dirty = false;
1195         this._opacityModifyRGB = true;
1196 
1197         this._blendFunc.src = cc.BLEND_SRC;
1198         this._blendFunc.dst = cc.BLEND_DST;
1199 
1200         this._flippedX = this._flippedY = false;
1201 
1202         // default transform anchor: center
1203         this.setAnchorPoint(cc.p(0.5, 0.5));
1204 
1205         // zwoptex default values
1206         this._offsetPosition = cc.p(0, 0);
1207         this._hasChildren = false;
1208 
1209         var locTextureLoaded = texture.isLoaded();
1210         this._textureLoaded = locTextureLoaded;
1211 
1212         if (!locTextureLoaded) {
1213             this._rectRotated = rotated || false;
1214             this._rect = rect;
1215             texture.addLoadedEventListener(this._textureLoadedCallback, this);
1216             return true;
1217         }
1218 
1219         if (!rect) {
1220             rect = cc.rect(0, 0, 0, 0);
1221             rect.size = texture.getContentSize();
1222         }
1223         this._originalTexture = texture;
1224 
1225         this.setTexture(texture);
1226         this.setTextureRect(rect, rotated, rect.size);
1227 
1228         // by default use "Self Render".
1229         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1230         this.setBatchNode(null);
1231         return true;
1232     },
1233 
1234     _textureLoadedCallback: null,
1235 
1236     _textureLoadedCallbackForWebGL: function (sender) {
1237         this._textureLoaded = true;
1238         var locRect = this._rect;
1239         if (!locRect) {
1240             locRect = cc.rect(0, 0, 0, 0);
1241             locRect.size = sender.getContentSize();
1242         } else if (cc._rectEqualToZero(locRect)) {
1243             locRect.size = sender.getContentSize();
1244         }
1245 
1246         this.setTexture(sender);
1247         this.setTextureRect(locRect, this._rectRotated, locRect.size);
1248 
1249         // by default use "Self Render".
1250         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1251         this.setBatchNode(null);
1252         this._quadDirty = true;
1253         this._callLoadedEventCallbacks();
1254     },
1255 
1256     _textureLoadedCallbackForCanvas: function (sender) {
1257         this._textureLoaded = true;
1258         var locRect = this._rect;
1259         if (!locRect) {
1260             locRect = cc.rect(0, 0, 0, 0);
1261             locRect.size = sender.getContentSize();
1262         } else if (cc._rectEqualToZero(locRect)) {
1263             locRect.size = sender.getContentSize();
1264         }
1265         this._originalTexture = sender;
1266 
1267         this.setTexture(sender);
1268         this.setTextureRect(locRect, this._rectRotated, locRect.size);
1269 
1270         // by default use "Self Render".
1271         // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
1272         this.setBatchNode(null);
1273         this._callLoadedEventCallbacks();
1274     },
1275 
1276     /**
1277      * updates the texture rect of the CCSprite in points.
1278      * @param {cc.Rect} rect a rect of texture
1279      * @param {Boolean} rotated
1280      * @param {cc.Size} untrimmedSize
1281      */
1282     setTextureRect:null,
1283 
1284     _setTextureRectForWebGL:function (rect, rotated, untrimmedSize) {
1285         this._rectRotated = rotated || false;
1286         untrimmedSize = untrimmedSize || rect.size;
1287 
1288         this.setContentSize(untrimmedSize);
1289         this.setVertexRect(rect);
1290         this._setTextureCoords(rect);
1291 
1292         var relativeOffset = this._unflippedOffsetPositionFromCenter;
1293         if (this._flippedX)
1294             relativeOffset.x = -relativeOffset.x;
1295         if (this._flippedY)
1296             relativeOffset.y = -relativeOffset.y;
1297 
1298         var locRect = this._rect;
1299         this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - locRect.width) / 2;
1300         this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - locRect.height) / 2;
1301 
1302         // rendering using batch node
1303         if (this._batchNode) {
1304             // update dirty_, don't update recursiveDirty_
1305             //this.setDirty(true);
1306             this._dirty = true;
1307         } else {
1308             // self rendering
1309             // Atlas: Vertex
1310             var x1 = 0 + this._offsetPosition.x;
1311             var y1 = 0 + this._offsetPosition.y;
1312             var x2 = x1 + locRect.width;
1313             var y2 = y1 + locRect.height;
1314 
1315             // Don't update Z.
1316             var locQuad = this._quad;
1317             locQuad.bl.vertices = {x:x1, y:y1, z:0};
1318             locQuad.br.vertices = {x:x2, y:y1, z:0};
1319             locQuad.tl.vertices = {x:x1, y:y2, z:0};
1320             locQuad.tr.vertices = {x:x2, y:y2, z:0};
1321 
1322             this._quadDirty = true;
1323         }
1324     },
1325 
1326     _setTextureRectForCanvas: function (rect, rotated, untrimmedSize) {
1327         this._rectRotated = rotated || false;
1328         untrimmedSize = untrimmedSize || rect.size;
1329 
1330         this.setContentSize(untrimmedSize);
1331         this.setVertexRect(rect);
1332 
1333         var relativeOffset = this._unflippedOffsetPositionFromCenter;
1334         if (this._flippedX)
1335             relativeOffset.x = -relativeOffset.x;
1336         if (this._flippedY)
1337             relativeOffset.y = -relativeOffset.y;
1338         this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - this._rect.width) / 2;
1339         this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - this._rect.height) / 2;
1340 
1341         // rendering using batch node
1342         if (this._batchNode) {
1343             // update dirty_, don't update recursiveDirty_
1344             //this.setDirty(true);
1345             this._dirty = true;
1346         }
1347     },
1348 
1349     // BatchNode methods
1350     /**
1351      * updates the quad according the the rotation, position, scale values.
1352      */
1353     updateTransform: null,
1354 
1355     _updateTransformForWebGL: function () {
1356         //cc.Assert(this._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode");
1357 
1358         // recaculate matrix only if it is dirty
1359         if (this.isDirty()) {
1360             var locQuad = this._quad, locParent = this._parent;
1361             // If it is not visible, or one of its ancestors is not visible, then do nothing:
1362             if (!this._visible || ( locParent && locParent != this._batchNode && locParent._shouldBeHidden)) {
1363                 locQuad.br.vertices = {x: 0, y: 0, z: 0};
1364                 locQuad.tl.vertices = {x: 0, y: 0, z: 0};
1365                 locQuad.tr.vertices = {x: 0, y: 0, z: 0};
1366                 locQuad.bl.vertices = {x: 0, y: 0, z: 0};
1367                 this._shouldBeHidden = true;
1368             } else {
1369                 this._shouldBeHidden = false;
1370 
1371                 if (!locParent || locParent == this._batchNode) {
1372                     this._transformToBatch = this.nodeToParentTransform();
1373                 } else {
1374                     //cc.Assert(this._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite");
1375                     this._transformToBatch = cc.AffineTransformConcat(this.nodeToParentTransform(), locParent._transformToBatch);
1376                 }
1377 
1378                 //
1379                 // calculate the Quad based on the Affine Matrix
1380                 //
1381                 var locTransformToBatch = this._transformToBatch;
1382                 var size = this._rect.size;
1383                 var x1 = this._offsetPosition.x;
1384                 var y1 = this._offsetPosition.y;
1385 
1386                 var x2 = x1 + size.width;
1387                 var y2 = y1 + size.height;
1388                 var x = locTransformToBatch.tx;
1389                 var y = locTransformToBatch.ty;
1390 
1391                 var cr = locTransformToBatch.a;
1392                 var sr = locTransformToBatch.b;
1393                 var cr2 = locTransformToBatch.d;
1394                 var sr2 = -locTransformToBatch.c;
1395                 var ax = x1 * cr - y1 * sr2 + x;
1396                 var ay = x1 * sr + y1 * cr2 + y;
1397 
1398                 var bx = x2 * cr - y1 * sr2 + x;
1399                 var by = x2 * sr + y1 * cr2 + y;
1400 
1401                 var cx = x2 * cr - y2 * sr2 + x;
1402                 var cy = x2 * sr + y2 * cr2 + y;
1403 
1404                 var dx = x1 * cr - y2 * sr2 + x;
1405                 var dy = x1 * sr + y2 * cr2 + y;
1406 
1407                 var locVertexZ = this._vertexZ;
1408                 locQuad.bl.vertices = {x: cc.RENDER_IN_SUBPIXEL(ax), y: cc.RENDER_IN_SUBPIXEL(ay), z: locVertexZ};
1409                 locQuad.br.vertices = {x: cc.RENDER_IN_SUBPIXEL(bx), y: cc.RENDER_IN_SUBPIXEL(by), z: locVertexZ};
1410                 locQuad.tl.vertices = {x: cc.RENDER_IN_SUBPIXEL(dx), y: cc.RENDER_IN_SUBPIXEL(dy), z: locVertexZ};
1411                 locQuad.tr.vertices = {x: cc.RENDER_IN_SUBPIXEL(cx), y: cc.RENDER_IN_SUBPIXEL(cy), z: locVertexZ};
1412             }
1413             this._textureAtlas.updateQuad(locQuad, this._atlasIndex);
1414             this._recursiveDirty = false;
1415             this.setDirty(false);
1416         }
1417 
1418         // recursively iterate over children
1419         if (this._hasChildren)
1420             this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform);
1421 
1422         if (cc.SPRITE_DEBUG_DRAW) {
1423             // draw bounding box
1424             var vertices = [
1425                 cc.p(this._quad.bl.vertices.x, this._quad.bl.vertices.y),
1426                 cc.p(this._quad.br.vertices.x, this._quad.br.vertices.y),
1427                 cc.p(this._quad.tr.vertices.x, this._quad.tr.vertices.y),
1428                 cc.p(this._quad.tl.vertices.x, this._quad.tl.vertices.y)
1429             ];
1430             cc.drawingUtil.drawPoly(vertices, 4, true);
1431         }
1432     },
1433 
1434     _updateTransformForCanvas: function () {
1435         //cc.Assert(this._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode");
1436 
1437         // recaculate matrix only if it is dirty
1438         if (this._dirty) {
1439             // If it is not visible, or one of its ancestors is not visible, then do nothing:
1440             var locParent = this._parent;
1441             if (!this._visible || ( locParent && locParent != this._batchNode && locParent._shouldBeHidden)) {
1442                 this._shouldBeHidden = true;
1443             } else {
1444                 this._shouldBeHidden = false;
1445 
1446                 if (!locParent || locParent == this._batchNode) {
1447                     this._transformToBatch = this.nodeToParentTransform();
1448                 } else {
1449                     //cc.Assert(this._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite");
1450                     this._transformToBatch = cc.AffineTransformConcat(this.nodeToParentTransform(), locParent._transformToBatch);
1451                 }
1452             }
1453             this._recursiveDirty = false;
1454             this._dirty = false;
1455         }
1456 
1457         // recursively iterate over children
1458         if (this._hasChildren)
1459             this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform);
1460     },
1461 
1462     /**
1463      * Add child to sprite (override cc.Node )
1464      * @param {cc.Sprite} child
1465      * @param {Number} zOrder  child's zOrder
1466      * @param {String} tag child's tag
1467      * @override
1468      */
1469     addChild: null,
1470 
1471     _addChildForWebGL:function (child, zOrder, tag) {
1472         cc.Assert(child != null, "Argument must be non-NULL");
1473         if (zOrder == null)
1474             zOrder = child._zOrder;
1475         if (tag == null)
1476             tag = child._tag;
1477 
1478         if (this._batchNode) {
1479             cc.Assert((child instanceof cc.Sprite), "cc.Sprite only supports cc.Sprites as children when using cc.SpriteBatchNode");
1480             cc.Assert(child.getTexture()._webTextureObj === this._textureAtlas.getTexture()._webTextureObj, "");
1481 
1482             //put it in descendants array of batch node
1483             this._batchNode.appendChild(child);
1484             if (!this._reorderChildDirty)
1485                 this._setReorderChildDirtyRecursively();
1486         }
1487 
1488         //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check
1489         cc.Node.prototype.addChild.call(this, child, zOrder, tag);
1490         this._hasChildren = true;
1491     },
1492 
1493     _addChildForCanvas: function (child, zOrder, tag) {
1494         cc.Assert(child != null, "Argument must be non-NULL");
1495         if (zOrder == null)
1496             zOrder = child._zOrder;
1497         if (tag == null)
1498             tag = child._tag;
1499 
1500         //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check
1501         cc.Node.prototype.addChild.call(this, child, zOrder, tag);
1502         this._hasChildren = true;
1503     },
1504 
1505     /**
1506      * Update sprite's color
1507      */
1508     updateColor:function () {
1509         var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity;
1510         var color4 = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: locDisplayedOpacity};
1511         // special opacity for premultiplied textures
1512         if (this._opacityModifyRGB) {
1513             color4.r *= locDisplayedOpacity / 255.0;
1514             color4.g *= locDisplayedOpacity / 255.0;
1515             color4.b *= locDisplayedOpacity / 255.0;
1516         }
1517         var locQuad = this._quad;
1518         locQuad.bl.colors = color4;
1519         locQuad.br.colors = color4;
1520         locQuad.tl.colors = color4;
1521         locQuad.tr.colors = color4;
1522 
1523         // renders using Sprite Manager
1524         if (this._batchNode) {
1525             if (this._atlasIndex != cc.SPRITE_INDEX_NOT_INITIALIZED) {
1526                 this._textureAtlas.updateQuad(locQuad, this._atlasIndex)
1527             } else {
1528                 // no need to set it recursively
1529                 // update dirty_, don't update recursiveDirty_
1530                 //this.setDirty(true);
1531                 this._dirty = true;
1532             }
1533         }
1534         // self render
1535         // do nothing
1536         this._quadDirty = true;
1537     },
1538 
1539     /**
1540      * opacity setter
1541      * @param {Number} opacity
1542      */
1543     setOpacity:null,
1544 
1545     _setOpacityForWebGL: function (opacity) {
1546         cc.NodeRGBA.prototype.setOpacity.call(this, opacity);
1547         this.updateColor();
1548     },
1549 
1550     _setOpacityForCanvas: function (opacity) {
1551         cc.NodeRGBA.prototype.setOpacity.call(this, opacity);
1552         this.setNodeDirty();
1553     },
1554 
1555     /**
1556      * color setter
1557      * @param {cc.Color3B} color3
1558      */
1559     setColor: null,
1560 
1561     _setColorForWebGL: function (color3) {
1562         cc.NodeRGBA.prototype.setColor.call(this, color3);
1563         this.updateColor();
1564     },
1565 
1566     _setColorForCanvas: function (color3) {
1567         var curColor = this.getColor();
1568         if ((curColor.r === color3.r) && (curColor.g === color3.g) && (curColor.b === color3.b))
1569             return;
1570 
1571         cc.NodeRGBA.prototype.setColor.call(this, color3);
1572         this._changeTextureColor();
1573         this.setNodeDirty();
1574     },
1575 
1576     updateDisplayedColor: null,
1577 
1578     _updateDisplayedColorForWebGL: function (parentColor) {
1579         cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor);
1580         this.updateColor();
1581     },
1582 
1583     _updateDisplayedColorForCanvas: function (parentColor) {
1584         cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor);
1585         this._changeTextureColor();
1586         this.setNodeDirty();
1587     },
1588 
1589     // Frames
1590     /**
1591      * Sets a new display frame to the cc.Sprite.
1592      * @param {cc.SpriteFrame} newFrame
1593      */
1594     setDisplayFrame: null,
1595 
1596     _setDisplayFrameForWebGL: function (newFrame) {
1597         this.setNodeDirty();
1598         var frameOffset = newFrame.getOffset();
1599         this._unflippedOffsetPositionFromCenter.x = frameOffset.x;
1600         this._unflippedOffsetPositionFromCenter.y = frameOffset.y;
1601 
1602         var pNewTexture = newFrame.getTexture();
1603         var locTextureLoaded = newFrame.textureLoaded();
1604         if (!locTextureLoaded) {
1605             this._textureLoaded = false;
1606             newFrame.addLoadedEventListener(function (sender) {
1607                 this._textureLoaded = true;
1608                 var locNewTexture = sender.getTexture();
1609                 if (locNewTexture != this._texture)
1610                     this.setTexture(locNewTexture);
1611                 this.setTextureRect(sender.getRect(), sender._rectRotated, sender.getOriginalSize());
1612                 this._callLoadedEventCallbacks();
1613             }, this);
1614         }
1615         // update texture before updating texture rect
1616         if (pNewTexture != this._texture)
1617             this.setTexture(pNewTexture);
1618 
1619         // update rect
1620         this._rectRotated = newFrame.isRotated();
1621         this.setTextureRect(newFrame.getRect(), this._rectRotated, newFrame.getOriginalSize());
1622     },
1623 
1624     _setDisplayFrameForCanvas: function (newFrame) {
1625         this.setNodeDirty();
1626 
1627         var frameOffset = newFrame.getOffset();
1628         this._unflippedOffsetPositionFromCenter.x = frameOffset.x;
1629         this._unflippedOffsetPositionFromCenter.y = frameOffset.y;
1630 
1631         // update rect
1632         this._rectRotated = newFrame.isRotated();
1633 
1634         var pNewTexture = newFrame.getTexture();
1635         var locTextureLoaded = newFrame.textureLoaded();
1636         if (!locTextureLoaded) {
1637             this._textureLoaded = false;
1638             newFrame.addLoadedEventListener(function (sender) {
1639                 this._textureLoaded = true;
1640                 var locNewTexture = sender.getTexture();
1641                 if (locNewTexture != this._texture)
1642                     this.setTexture(locNewTexture);
1643                 this.setTextureRect(sender.getRect(), this._rectRotated, sender.getOriginalSize());
1644                 this._callLoadedEventCallbacks();
1645             }, this);
1646         }
1647         // update texture before updating texture rect
1648         if (pNewTexture != this._texture)
1649             this.setTexture(pNewTexture);
1650 
1651         if (this._rectRotated)
1652             this._originalTexture = pNewTexture;
1653 
1654         this.setTextureRect(newFrame.getRect(), this._rectRotated, newFrame.getOriginalSize());
1655         this._colorized = false;
1656         if (locTextureLoaded) {
1657             var curColor = this.getColor();
1658             if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
1659                 this._changeTextureColor();
1660         }
1661     },
1662 
1663     /**
1664      * Returns whether or not a cc.SpriteFrame is being displayed
1665      * @param {cc.SpriteFrame} frame
1666      * @return {Boolean}
1667      */
1668     isFrameDisplayed: null,
1669 
1670     _isFrameDisplayedForWebGL: function (frame) {
1671         return (cc.rectEqualToRect(frame.getRect(), this._rect) && frame.getTexture().getName() == this._texture.getName()
1672             && cc.pointEqualToPoint(frame.getOffset(), this._unflippedOffsetPositionFromCenter));
1673     },
1674 
1675     _isFrameDisplayedForCanvas: function (frame) {
1676         if (frame.getTexture() != this._texture)
1677             return false;
1678         return cc.rectEqualToRect(frame.getRect(), this._rect);
1679     },
1680 
1681     /**
1682      * Returns the current displayed frame.
1683      * @return {cc.SpriteFrame}
1684      */
1685     displayFrame: function () {
1686         return cc.SpriteFrame.createWithTexture(this._texture,
1687             cc.RECT_POINTS_TO_PIXELS(this._rect),
1688             this._rectRotated,
1689             cc.POINT_POINTS_TO_PIXELS(this._unflippedOffsetPositionFromCenter),
1690             cc.SIZE_POINTS_TO_PIXELS(this._contentSize));
1691     },
1692 
1693     /**
1694      * Sets the batch node to sprite
1695      * @param {cc.SpriteBatchNode|null} spriteBatchNode
1696      * @example
1697      *  var batch = cc.SpriteBatchNode.create("Images/grossini_dance_atlas.png", 15);
1698      *  var sprite = cc.Sprite.createWithTexture(batch.getTexture(), cc.rect(0, 0, 57, 57));
1699      *  batch.addChild(sprite);
1700      *  layer.addChild(batch);
1701      */
1702     setBatchNode:null,
1703 
1704     _setBatchNodeForWebGL:function (spriteBatchNode) {
1705         this._batchNode = spriteBatchNode; // weak reference
1706 
1707         // self render
1708         if (!this._batchNode) {
1709             this._atlasIndex = cc.SPRITE_INDEX_NOT_INITIALIZED;
1710             this.setTextureAtlas(null);
1711             this._recursiveDirty = false;
1712             this.setDirty(false);
1713 
1714             var x1 = this._offsetPosition.x;
1715             var y1 = this._offsetPosition.y;
1716             var x2 = x1 + this._rect.width;
1717             var y2 = y1 + this._rect.height;
1718             var locQuad = this._quad;
1719             locQuad.bl.vertices = {x:x1, y:y1, z:0};
1720             locQuad.br.vertices = {x:x2, y:y1, z:0};
1721             locQuad.tl.vertices = {x:x1, y:y2, z:0};
1722             locQuad.tr.vertices = {x:x2, y:y2, z:0};
1723 
1724             this._quadDirty = true;
1725         } else {
1726             // using batch
1727             this._transformToBatch = cc.AffineTransformIdentity();
1728             this.setTextureAtlas(this._batchNode.getTextureAtlas()); // weak ref
1729         }
1730     },
1731 
1732     _setBatchNodeForCanvas:function (spriteBatchNode) {
1733         this._batchNode = spriteBatchNode; // weak reference
1734 
1735         // self render
1736         if (!this._batchNode) {
1737             this._atlasIndex = cc.SPRITE_INDEX_NOT_INITIALIZED;
1738             this.setTextureAtlas(null);
1739             this._recursiveDirty = false;
1740             this.setDirty(false);
1741         } else {
1742             // using batch
1743             this._transformToBatch = cc.AffineTransformIdentity();
1744             this.setTextureAtlas(this._batchNode.getTextureAtlas()); // weak ref
1745         }
1746     },
1747 
1748     // CCTextureProtocol
1749     /**
1750      * Texture of sprite setter
1751      * @param {HTMLImageElement|HTMLCanvasElement|cc.Texture2D} texture
1752      */
1753     setTexture: null,
1754 
1755     _setTextureForWebGL: function (texture) {
1756         // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet
1757         cc.Assert(!texture || texture instanceof cc.Texture2D, "setTexture expects a CCTexture2D. Invalid argument");
1758 
1759         // If batchnode, then texture id should be the same
1760         cc.Assert(!this._batchNode, "cc.Sprite: Batched sprites should use the same texture as the batchnode");
1761 
1762         if (texture)
1763             this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_TEXTURECOLOR));
1764         else
1765             this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(cc.SHADER_POSITION_COLOR));
1766 
1767         if (!this._batchNode && this._texture != texture) {
1768             this._texture = texture;
1769             this._updateBlendFunc();
1770         }
1771     },
1772 
1773     _setTextureForCanvas: function (texture) {
1774         // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet
1775         cc.Assert(!texture || texture instanceof cc.Texture2D, "setTexture expects a CCTexture2D. Invalid argument");
1776         if (this._texture != texture) {
1777             if (texture && texture.getHtmlElementObj() instanceof  HTMLImageElement) {
1778                 this._originalTexture = texture;
1779             }
1780             this._texture = texture;
1781         }
1782     },
1783 
1784     // Texture protocol
1785     _updateBlendFunc:function () {
1786         cc.Assert(!this._batchNode, "cc.Sprite: _updateBlendFunc doesn't work when the sprite is rendered using a cc.CCSpriteBatchNode");
1787         // it's possible to have an untextured sprite
1788         if (!this._texture || !this._texture.hasPremultipliedAlpha()) {
1789             this._blendFunc.src = gl.SRC_ALPHA;
1790             this._blendFunc.dst = gl.ONE_MINUS_SRC_ALPHA;
1791             this.setOpacityModifyRGB(false);
1792         } else {
1793             this._blendFunc.src = cc.BLEND_SRC;
1794             this._blendFunc.dst = cc.BLEND_DST;
1795             this.setOpacityModifyRGB(true);
1796         }
1797     },
1798 
1799     _changeTextureColor: function () {
1800         var locElement, locTexture = this._texture, locRect = this.getTextureRect();
1801         if (locTexture && locRect.width > 0) {
1802             locElement = locTexture.getHtmlElementObj();
1803             if (!locElement)
1804                 return;
1805 
1806             var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(this._originalTexture.getHtmlElementObj());
1807             if (cacheTextureForColor) {
1808                 this._colorized = true;
1809                 //generate color texture cache
1810                 if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor)
1811                     cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect, locElement);
1812                 else {
1813                     locElement = cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect);
1814                     locTexture = new cc.Texture2D();
1815                     locTexture.initWithElement(locElement);
1816                     locTexture.handleLoadedTexture();
1817                     this.setTexture(locTexture);
1818                 }
1819             }
1820         }
1821     },
1822 
1823     _setTextureCoords:function (rect) {
1824         rect = cc.RECT_POINTS_TO_PIXELS(rect);
1825 
1826         var tex = this._batchNode ? this._textureAtlas.getTexture() : this._texture;
1827         if (!tex)
1828             return;
1829 
1830         var atlasWidth = tex.getPixelsWide();
1831         var atlasHeight = tex.getPixelsHigh();
1832 
1833         var left, right, top, bottom, tempSwap, locQuad = this._quad;
1834         if (this._rectRotated) {
1835             if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
1836                 left = (2 * rect.x + 1) / (2 * atlasWidth);
1837                 right = left + (rect.height * 2 - 2) / (2 * atlasWidth);
1838                 top = (2 * rect.y + 1) / (2 * atlasHeight);
1839                 bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight);
1840             } else {
1841                 left = rect.x / atlasWidth;
1842                 right = (rect.x + rect.height) / atlasWidth;
1843                 top = rect.y / atlasHeight;
1844                 bottom = (rect.y + rect.width) / atlasHeight;
1845             }// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
1846 
1847             if (this._flippedX) {
1848                 tempSwap = top;
1849                 top = bottom;
1850                 bottom = tempSwap;
1851             }
1852 
1853             if (this._flippedY) {
1854                 tempSwap = left;
1855                 left = right;
1856                 right = tempSwap;
1857             }
1858 
1859             locQuad.bl.texCoords.u = left;
1860             locQuad.bl.texCoords.v = top;
1861             locQuad.br.texCoords.u = left;
1862             locQuad.br.texCoords.v = bottom;
1863             locQuad.tl.texCoords.u = right;
1864             locQuad.tl.texCoords.v = top;
1865             locQuad.tr.texCoords.u = right;
1866             locQuad.tr.texCoords.v = bottom;
1867         } else {
1868             if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
1869                 left = (2 * rect.x + 1) / (2 * atlasWidth);
1870                 right = left + (rect.width * 2 - 2) / (2 * atlasWidth);
1871                 top = (2 * rect.y + 1) / (2 * atlasHeight);
1872                 bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight);
1873             } else {
1874                 left = rect.x / atlasWidth;
1875                 right = (rect.x + rect.width) / atlasWidth;
1876                 top = rect.y / atlasHeight;
1877                 bottom = (rect.y + rect.height) / atlasHeight;
1878             } // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
1879 
1880             if (this._flippedX) {
1881                 tempSwap = left;
1882                 left = right;
1883                 right = tempSwap;
1884             }
1885 
1886             if (this._flippedY) {
1887                 tempSwap = top;
1888                 top = bottom;
1889                 bottom = tempSwap;
1890             }
1891 
1892             locQuad.bl.texCoords.u = left;
1893             locQuad.bl.texCoords.v = bottom;
1894             locQuad.br.texCoords.u = right;
1895             locQuad.br.texCoords.v = bottom;
1896             locQuad.tl.texCoords.u = left;
1897             locQuad.tl.texCoords.v = top;
1898             locQuad.tr.texCoords.u = right;
1899             locQuad.tr.texCoords.v = top;
1900         }
1901         this._quadDirty = true;
1902     },
1903     /**
1904      * draw sprite to canvas
1905      */
1906     draw: null,
1907 
1908     _drawForWebGL: function () {
1909         if (!this._textureLoaded)
1910             return;
1911 
1912         var gl = cc.renderContext, locTexture = this._texture;
1913         //cc.Assert(!this._batchNode, "If cc.Sprite is being rendered by cc.SpriteBatchNode, cc.Sprite#draw SHOULD NOT be called");
1914 
1915         if (locTexture) {
1916             if (locTexture._isLoaded) {
1917                 this._shaderProgram.use();
1918                 this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4();
1919 
1920                 cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst);
1921                 //optimize performance for javascript
1922                 cc.glBindTexture2DN(0, locTexture);                   // = cc.glBindTexture2D(locTexture);
1923                 cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSCOLORTEX);
1924 
1925                 gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer);
1926                 if (this._quadDirty) {
1927                     gl.bufferData(gl.ARRAY_BUFFER, this._quad.arrayBuffer, gl.DYNAMIC_DRAW);
1928                     this._quadDirty = false;
1929                 }
1930                 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0);                   //cc.VERTEX_ATTRIB_POSITION
1931                 gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 24, 12);           //cc.VERTEX_ATTRIB_COLOR
1932                 gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 24, 16);                  //cc.VERTEX_ATTRIB_TEX_COORDS
1933 
1934                 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
1935             }
1936         } else {
1937             this._shaderProgram.use();
1938             this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4();
1939 
1940             cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst);
1941             cc.glBindTexture2D(null);
1942 
1943             cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR);
1944 
1945             gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer);
1946             if (this._quadDirty) {
1947                 cc.renderContext.bufferData(cc.renderContext.ARRAY_BUFFER, this._quad.arrayBuffer, cc.renderContext.STATIC_DRAW);
1948                 this._quadDirty = false;
1949             }
1950             gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0);
1951             gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12);
1952             gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
1953         }
1954         cc.g_NumberOfDraws++;
1955         if (cc.SPRITE_DEBUG_DRAW === 0)
1956             return;
1957 
1958         if (cc.SPRITE_DEBUG_DRAW === 1) {
1959             // draw bounding box
1960             var locQuad = this._quad;
1961             var verticesG1 = [
1962                 cc.p(locQuad.tl.vertices.x, locQuad.tl.vertices.y),
1963                 cc.p(locQuad.bl.vertices.x, locQuad.bl.vertices.y),
1964                 cc.p(locQuad.br.vertices.x, locQuad.br.vertices.y),
1965                 cc.p(locQuad.tr.vertices.x, locQuad.tr.vertices.y)
1966             ];
1967             cc.drawingUtil.drawPoly(verticesG1, 4, true);
1968         } else if (cc.SPRITE_DEBUG_DRAW === 2) {
1969             // draw texture box
1970             var drawSizeG2 = this.getTextureRect().size;
1971             var offsetPixG2 = this.getOffsetPosition();
1972             var verticesG2 = [cc.p(offsetPixG2.x, offsetPixG2.y), cc.p(offsetPixG2.x + drawSizeG2.width, offsetPixG2.y),
1973                 cc.p(offsetPixG2.x + drawSizeG2.width, offsetPixG2.y + drawSizeG2.height), cc.p(offsetPixG2.x, offsetPixG2.y + drawSizeG2.height)];
1974             cc.drawingUtil.drawPoly(verticesG2, 4, true);
1975         } // CC_SPRITE_DEBUG_DRAW
1976     },
1977 
1978     _drawForCanvas: function (ctx) {
1979         if (!this._textureLoaded)
1980             return;
1981 
1982         var context = ctx || cc.renderContext;
1983         if (this._isLighterMode)
1984             context.globalCompositeOperation = 'lighter';
1985 
1986         context.globalAlpha = this._displayedOpacity / 255;
1987         var locRect = this._rect, locContentSize = this._contentSize, locOffsetPosition = this._offsetPosition;
1988         var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height;
1989         if (this._flippedX || this._flippedY) {
1990             context.save();
1991             if (this._flippedX) {
1992                 flipXOffset = -locOffsetPosition.x - locRect.width;
1993                 context.scale(-1, 1);
1994             }
1995             if (this._flippedY) {
1996                 flipYOffset = locOffsetPosition.y;
1997                 context.scale(1, -1);
1998             }
1999         }
2000 
2001         if (this._texture && locRect.width > 0) {
2002             var image = this._texture.getHtmlElementObj();
2003             if (this._colorized) {
2004                 context.drawImage(image,
2005                     0, 0, locRect.width, locRect.height,
2006                     flipXOffset, flipYOffset, locRect.width, locRect.height);
2007             } else {
2008                 context.drawImage(image,
2009                     locRect.x, locRect.y, locRect.width,  locRect.height,
2010                     flipXOffset, flipYOffset, locRect.width, locRect.height);
2011             }
2012         } else if (locContentSize.width !== 0) {
2013             var curColor = this.getColor();
2014             context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)";
2015             context.fillRect(flipXOffset, flipYOffset, locContentSize.width, locContentSize.height);
2016         }
2017 
2018         if (cc.SPRITE_DEBUG_DRAW === 1) {
2019             // draw bounding box
2020             context.strokeStyle = "rgba(0,255,0,1)";
2021             flipYOffset = -flipYOffset;
2022             var vertices1 = [cc.p(flipXOffset, flipYOffset), cc.p(flipXOffset + locRect.width, flipYOffset), cc.p(flipXOffset + locRect.width, flipYOffset - locRect.height),
2023                 cc.p(flipXOffset, flipYOffset - locRect.height)];
2024             cc.drawingUtil.drawPoly(vertices1, 4, true);
2025         } else if (cc.SPRITE_DEBUG_DRAW === 2) {
2026             // draw texture box
2027             context.strokeStyle = "rgba(0,255,0,1)";
2028             var drawSize = this._rect.size;
2029             flipYOffset = -flipYOffset;
2030             var vertices2 = [cc.p(flipXOffset, flipYOffset), cc.p(flipXOffset + drawSize.width, flipYOffset),
2031                 cc.p(flipXOffset + drawSize.width, flipYOffset - drawSize.height), cc.p(flipXOffset, flipYOffset - drawSize.height)];
2032             cc.drawingUtil.drawPoly(vertices2, 4, true);
2033         }
2034         if (this._flippedX || this._flippedY)
2035             context.restore();
2036         cc.g_NumberOfDraws++;
2037     }
2038 });
2039 
2040 if(cc.Browser.supportWebGL){
2041     cc.Sprite.prototype._spriteFrameLoadedCallback = cc.Sprite.prototype._spriteFrameLoadedCallbackForWebGL;
2042     cc.Sprite.prototype.setOpacityModifyRGB = cc.Sprite.prototype._setOpacityModifyRGBForWebGL;
2043     cc.Sprite.prototype.updateDisplayedOpacity = cc.Sprite.prototype._updateDisplayedOpacityForWebGL;
2044     cc.Sprite.prototype.ctor = cc.Sprite.prototype._ctorForWebGL;
2045     cc.Sprite.prototype.setBlendFunc = cc.Sprite.prototype._setBlendFuncForWebGL;
2046     cc.Sprite.prototype.init = cc.Sprite.prototype._initForWebGL;
2047     cc.Sprite.prototype.initWithTexture = cc.Sprite.prototype._initWithTextureForWebGL;
2048     cc.Sprite.prototype._textureLoadedCallback = cc.Sprite.prototype._textureLoadedCallbackForWebGL;
2049     cc.Sprite.prototype.setTextureRect = cc.Sprite.prototype._setTextureRectForWebGL;
2050     cc.Sprite.prototype.updateTransform = cc.Sprite.prototype._updateTransformForWebGL;
2051     cc.Sprite.prototype.addChild = cc.Sprite.prototype._addChildForWebGL;
2052     cc.Sprite.prototype.setOpacity = cc.Sprite.prototype._setOpacityForWebGL;
2053     cc.Sprite.prototype.setColor = cc.Sprite.prototype._setColorForWebGL;
2054     cc.Sprite.prototype.updateDisplayedColor = cc.Sprite.prototype._updateDisplayedColorForWebGL;
2055     cc.Sprite.prototype.setDisplayFrame = cc.Sprite.prototype._setDisplayFrameForWebGL;
2056     cc.Sprite.prototype.isFrameDisplayed = cc.Sprite.prototype._isFrameDisplayedForWebGL;
2057     cc.Sprite.prototype.setBatchNode = cc.Sprite.prototype._setBatchNodeForWebGL;
2058     cc.Sprite.prototype.setTexture = cc.Sprite.prototype._setTextureForWebGL;
2059     cc.Sprite.prototype.draw = cc.Sprite.prototype._drawForWebGL;
2060 }else{
2061     cc.Sprite.prototype._spriteFrameLoadedCallback = cc.Sprite.prototype._spriteFrameLoadedCallbackForCanvas;
2062     cc.Sprite.prototype.setOpacityModifyRGB = cc.Sprite.prototype._setOpacityModifyRGBForCanvas;
2063     cc.Sprite.prototype.updateDisplayedOpacity = cc.Sprite.prototype._updateDisplayedOpacityForCanvas;
2064     cc.Sprite.prototype.ctor = cc.Sprite.prototype._ctorForCanvas;
2065     cc.Sprite.prototype.setBlendFunc = cc.Sprite.prototype._setBlendFuncForCanvas;
2066     cc.Sprite.prototype.init = cc.Sprite.prototype._initForCanvas;
2067     cc.Sprite.prototype.initWithTexture = cc.Sprite.prototype._initWithTextureForCanvas;
2068     cc.Sprite.prototype._textureLoadedCallback = cc.Sprite.prototype._textureLoadedCallbackForCanvas;
2069     cc.Sprite.prototype.setTextureRect = cc.Sprite.prototype._setTextureRectForCanvas;
2070     cc.Sprite.prototype.updateTransform = cc.Sprite.prototype._updateTransformForCanvas;
2071     cc.Sprite.prototype.addChild = cc.Sprite.prototype._addChildForCanvas;
2072     cc.Sprite.prototype.setOpacity = cc.Sprite.prototype._setOpacityForCanvas;
2073     cc.Sprite.prototype.setColor = cc.Sprite.prototype._setColorForCanvas;
2074     cc.Sprite.prototype.updateDisplayedColor = cc.Sprite.prototype._updateDisplayedColorForCanvas;
2075     cc.Sprite.prototype.setDisplayFrame = cc.Sprite.prototype._setDisplayFrameForCanvas;
2076     cc.Sprite.prototype.isFrameDisplayed = cc.Sprite.prototype._isFrameDisplayedForCanvas;
2077     cc.Sprite.prototype.setBatchNode = cc.Sprite.prototype._setBatchNodeForCanvas;
2078     cc.Sprite.prototype.setTexture = cc.Sprite.prototype._setTextureForCanvas;
2079     cc.Sprite.prototype.draw = cc.Sprite.prototype._drawForCanvas;
2080 }
2081 
2082 /**
2083  * <p>
2084  *     Creates a sprite with an exsiting texture contained in a CCTexture2D object                           <br/>
2085  *     After creation, the rect will be the size of the texture, and the offset will be (0,0).
2086  * </p>
2087  * @constructs
2088  * @param {cc.Texture2D} texture  A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites.
2089  * @param {cc.Rect} rect Only the contents inside the rect of this texture will be applied for this sprite.
2090  * @return {cc.Sprite} A valid sprite object
2091  * @example
2092  * //get an image
2093  * var img = cc.TextureCache.getInstance().addImage("HelloHTML5World.png");
2094  *
2095  * //create a sprite with texture
2096  * var sprite1 = cc.Sprite.createWithTexture(img);
2097  *
2098  * //create a sprite with texture and rect
2099  * var sprite2 = cc.Sprite.createWithTexture(img, cc.rect(0,0,480,320));
2100  *
2101  */
2102 cc.Sprite.createWithTexture = function (texture, rect) {
2103     var argnum = arguments.length;
2104     var sprite = new cc.Sprite();
2105     switch (argnum) {
2106         case 1:
2107             /** Creates an sprite with a texture.
2108              The rect used will be the size of the texture.
2109              The offset will be (0,0).
2110              */
2111             if (sprite && sprite.initWithTexture(texture))
2112                 return sprite;
2113             return null;
2114             break;
2115 
2116         case 2:
2117             /** Creates an sprite with a texture and a rect.
2118              The offset will be (0,0).
2119              */
2120             if (sprite && sprite.initWithTexture(texture, rect))
2121                 return sprite;
2122             return null;
2123             break;
2124 
2125         default:
2126             throw "Sprite.createWithTexture(): Argument must be non-nil ";
2127             break;
2128     }
2129 };
2130 
2131 /**
2132  * Create a sprite with filename and rect
2133  * @constructs
2134  * @param {String} fileName  The string which indicates a path to image file, e.g., "scene1/monster.png".
2135  * @param {cc.Rect} rect  Only the contents inside rect of pszFileName's texture will be applied for this sprite.
2136  * @return {cc.Sprite} A valid sprite object
2137  * @example
2138  * //create a sprite with filename
2139  * var sprite1 = cc.Sprite.create("HelloHTML5World.png");
2140  *
2141  * //create a sprite with filename and rect
2142  * var sprite2 = cc.Sprite.create("HelloHTML5World.png",cc.rect(0,0,480,320));
2143  */
2144 cc.Sprite.create = function (fileName, rect) {
2145     var argnum = arguments.length;
2146     var sprite = new cc.Sprite();
2147     if (argnum === 0) {
2148         if (sprite.init())
2149             return sprite;
2150     } else {
2151         /** Creates an sprite with an image filename.
2152          If the rect equal undefined, the rect used will be the size of the image.
2153          The offset will be (0,0).
2154          */
2155         if (sprite && sprite.init(fileName, rect))
2156             return sprite;
2157     }
2158     return null;
2159 };
2160 
2161 /**
2162  * <p>
2163  *     Creates a sprite with a sprite frame.                                                                  <br/>
2164  *                                                                                                            <br/>
2165  *    A CCSpriteFrame will be fetched from the CCSpriteFrameCache by pszSpriteFrameName param.                <br/>
2166  *    If the CCSpriteFrame doesn't exist it will raise an exception.
2167  * </p>
2168  * @param {String} spriteFrameName A sprite frame which involves a texture and a rect
2169  * @return {cc.Sprite} A valid sprite object
2170  * @example
2171  *
2172  * //create a sprite with a sprite frame
2173  * var sprite = cc.Sprite.createWithSpriteFrameName('grossini_dance_01.png');
2174  */
2175 cc.Sprite.createWithSpriteFrameName = function (spriteFrameName) {
2176     var spriteFrame = null;
2177     if (typeof(spriteFrameName) == 'string') {
2178         spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame(spriteFrameName);
2179         if (!spriteFrame) {
2180             cc.log("Invalid spriteFrameName: " + spriteFrameName);
2181             return null;
2182         }
2183     } else {
2184         cc.log("Invalid argument. Expecting string.");
2185         return null;
2186     }
2187     var sprite = new cc.Sprite();
2188     if (sprite && sprite.initWithSpriteFrame(spriteFrame)) {
2189         return sprite;
2190     }
2191     return null;
2192 };
2193 
2194 /**
2195  * <p>
2196  *     Creates a sprite with a sprite frame.                                                                  <br/>
2197  *                                                                                                            <br/>
2198  *    A CCSpriteFrame will be fetched from the CCSpriteFrameCache by pszSpriteFrameName param.                <br/>
2199  *    If the CCSpriteFrame doesn't exist it will raise an exception.
2200  * </p>
2201  * @param {cc.SpriteFrame} spriteFrame A sprite frame which involves a texture and a rect
2202  * @return {cc.Sprite} A valid sprite object
2203  * @example
2204  * //get a sprite frame
2205  * var spriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame("grossini_dance_01.png");
2206  *
2207  * //create a sprite with a sprite frame
2208  * var sprite = cc.Sprite.createWithSpriteFrame(spriteFrame);
2209  */
2210 cc.Sprite.createWithSpriteFrame = function (spriteFrame) {
2211     var sprite = new cc.Sprite();
2212     if (sprite && sprite.initWithSpriteFrame(spriteFrame)) {
2213         return sprite;
2214     }
2215     return null;
2216 };
2217