/****************************************************************************
Copyright (c) 2008-2010 Ricardo Quesada
Copyright (c) 2011-2012 cocos2d-x.org
Copyright (c) 2013-2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* Tint a texture using the "multiply" operation
* @param {HTMLImageElement} image
* @param {cc.Color} color
* @param {cc.Rect} [rect]
* @param {HTMLCanvasElement} renderCanvas
* @returns {HTMLCanvasElement}
*/
cc.generateTintImageWithMultiply = function(image, color, rect, renderCanvas){
renderCanvas = renderCanvas || cc.newElement("canvas");
rect = rect || cc.rect(0,0, image.width, image.height);
var context = renderCanvas.getContext( "2d" );
if(renderCanvas.width != rect.width || renderCanvas.height != rect.height){
renderCanvas.width = rect.width;
renderCanvas.height = rect.height;
}else{
context.globalCompositeOperation = "source-over";
}
context.fillStyle = "rgb(" + (0|color.r) + "," + (0|color.g) + "," + (0|color.b) + ")";
context.fillRect(0, 0, rect.width, rect.height);
context.globalCompositeOperation = "multiply";
context.drawImage(image,
rect.x,
rect.y,
rect.width,
rect.height,
0,
0,
rect.width,
rect.height);
context.globalCompositeOperation = "destination-atop";
context.drawImage(image,
rect.x,
rect.y,
rect.width,
rect.height,
0,
0,
rect.width,
rect.height);
return renderCanvas;
};
/**
* Generate tinted texture with lighter.
* lighter: The source and destination colors are added to each other, resulting in brighter colors,
* moving towards color values of 1 (maximum brightness for that color).
* @function
* @param {HTMLImageElement} texture
* @param {Array} tintedImgCache
* @param {cc.Color} color
* @param {cc.Rect} rect
* @param {HTMLCanvasElement} [renderCanvas]
* @return {HTMLCanvasElement}
*/
cc.generateTintImage = function (texture, tintedImgCache, color, rect, renderCanvas) {
if (!rect)
rect = cc.rect(0, 0, texture.width, texture.height);
var r = color.r / 255;
var g = color.g / 255;
var b = color.b / 255;
var w = Math.min(rect.width, tintedImgCache[0].width);
var h = Math.min(rect.height, tintedImgCache[0].height);
var buff = renderCanvas;
var ctx;
// Create a new buffer if required
if (!buff) {
buff = cc.newElement("canvas");
buff.width = w;
buff.height = h;
ctx = buff.getContext("2d");
} else {
ctx = buff.getContext("2d");
ctx.clearRect(0, 0, w, h);
}
ctx.save();
ctx.globalCompositeOperation = 'lighter';
// Make sure to keep the renderCanvas alpha in mind in case of overdraw
var a = ctx.globalAlpha;
if (r > 0) {
ctx.globalAlpha = r * a;
ctx.drawImage(tintedImgCache[0], rect.x, rect.y, w, h, 0, 0, w, h);
}
if (g > 0) {
ctx.globalAlpha = g * a;
ctx.drawImage(tintedImgCache[1], rect.x, rect.y, w, h, 0, 0, w, h);
}
if (b > 0) {
ctx.globalAlpha = b * a;
ctx.drawImage(tintedImgCache[2], rect.x, rect.y, w, h, 0, 0, w, h);
}
if (r + g + b < 1) {
ctx.globalAlpha = a;
ctx.drawImage(tintedImgCache[3], rect.x, rect.y, w, h, 0, 0, w, h);
}
ctx.restore();
return buff;
};
/**
* Generates texture's cache for texture tint
* @function
* @param {HTMLImageElement} texture
* @return {Array}
*/
cc.generateTextureCacheForColor = function (texture) {
if (texture.channelCache) {
return texture.channelCache;
}
var textureCache = [
cc.newElement("canvas"),
cc.newElement("canvas"),
cc.newElement("canvas"),
cc.newElement("canvas")
];
function renderToCache() {
var ref = cc.generateTextureCacheForColor;
var w = texture.width;
var h = texture.height;
textureCache[0].width = w;
textureCache[0].height = h;
textureCache[1].width = w;
textureCache[1].height = h;
textureCache[2].width = w;
textureCache[2].height = h;
textureCache[3].width = w;
textureCache[3].height = h;
ref.canvas.width = w;
ref.canvas.height = h;
var ctx = ref.canvas.getContext("2d");
ctx.drawImage(texture, 0, 0);
ref.tempCanvas.width = w;
ref.tempCanvas.height = h;
var pixels = ctx.getImageData(0, 0, w, h).data;
for (var rgbI = 0; rgbI < 4; rgbI++) {
var cacheCtx = textureCache[rgbI].getContext('2d');
cacheCtx.getImageData(0, 0, w, h).data;
ref.tempCtx.drawImage(texture, 0, 0);
var to = ref.tempCtx.getImageData(0, 0, w, h);
var toData = to.data;
for (var i = 0; i < pixels.length; i += 4) {
toData[i ] = (rgbI === 0) ? pixels[i ] : 0;
toData[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0;
toData[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0;
toData[i + 3] = pixels[i + 3];
}
cacheCtx.putImageData(to, 0, 0);
}
texture.onload = null;
}
try {
renderToCache();
} catch (e) {
texture.onload = renderToCache;
}
texture.channelCache = textureCache;
return textureCache;
};
cc.generateTextureCacheForColor.canvas = cc.newElement('canvas');
cc.generateTextureCacheForColor.tempCanvas = cc.newElement('canvas');
cc.generateTextureCacheForColor.tempCtx = cc.generateTextureCacheForColor.tempCanvas.getContext('2d');
cc.cutRotateImageToCanvas = function (texture, rect) {
if (!texture)
return null;
if (!rect)
return texture;
var nCanvas = cc.newElement("canvas");
nCanvas.width = rect.width;
nCanvas.height = rect.height;
var ctx = nCanvas.getContext("2d");
ctx.translate(nCanvas.width / 2, nCanvas.height / 2);
ctx.rotate(-1.5707963267948966);
ctx.drawImage(texture, rect.x, rect.y, rect.height, rect.width, -rect.height / 2, -rect.width / 2, rect.height, rect.width);
return nCanvas;
};
cc._getCompositeOperationByBlendFunc = function(blendFunc){
if(!blendFunc)
return "source";
else{
if(( blendFunc.src == cc.SRC_ALPHA && blendFunc.dst == cc.ONE) || (blendFunc.src == cc.ONE && blendFunc.dst == cc.ONE))
return "lighter";
else if(blendFunc.src == cc.ZERO && blendFunc.dst == cc.SRC_ALPHA)
return "destination-in";
else if(blendFunc.src == cc.ZERO && blendFunc.dst == cc.ONE_MINUS_SRC_ALPHA)
return "destination-out";
else
return "source";
}
};
/**
*
cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) )
*
* cc.Sprite can be created with an image, or with a sub-rectangle of an image.
*
* If the parent or any of its ancestors is a cc.SpriteBatchNode then the following features/limitations are valid
* - Features when the parent is a cc.BatchNode:
* - MUCH faster rendering, specially if the cc.SpriteBatchNode has many children. All the children will be drawn in a single batch.
*
* - Limitations
* - Camera is not supported yet (eg: CCOrbitCamera action doesn't work)
* - GridBase actions are not supported (eg: CCLens, CCRipple, CCTwirl)
* - The Alias/Antialias property belongs to CCSpriteBatchNode, so you can't individually set the aliased property.
* - The Blending function property belongs to CCSpriteBatchNode, so you can't individually set the blending function property.
* - Parallax scroller is not supported, but can be simulated with a "proxy" sprite.
*
* If the parent is an standard cc.Node, then cc.Sprite behaves like any other cc.Node:
* - It supports blending functions
* - It supports aliasing / antialiasing
* - But the rendering will be slower: 1 draw per children.
*
* The default anchorPoint in cc.Sprite is (0.5, 0.5).
* @class
* @extends cc.Node
*
* @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName The string which indicates a path to image file, e.g., "scene1/monster.png".
* @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite.
* @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
* @example
*
* 1.Create a sprite with image path and rect
* var sprite1 = new cc.Sprite("res/HelloHTML5World.png");
* var sprite2 = new cc.Sprite("res/HelloHTML5World.png",cc.rect(0,0,480,320));
*
* 2.Create a sprite with a sprite frame name. Must add "#" before frame name.
* var sprite = new cc.Sprite('#grossini_dance_01.png');
*
* 3.Create a sprite with a sprite frame
* var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png");
* var sprite = new cc.Sprite(spriteFrame);
*
* 4.Create a sprite with an existing texture contained in a CCTexture2D object
* After creation, the rect will be the size of the texture, and the offset will be (0,0).
* var texture = cc.textureCache.addImage("HelloHTML5World.png");
* var sprite1 = new cc.Sprite(texture);
* var sprite2 = new cc.Sprite(texture, cc.rect(0,0,480,320));
*
* @property {Boolean} dirty - Indicates whether the sprite needs to be updated.
* @property {Boolean} flippedX - Indicates whether or not the spirte is flipped on x axis.
* @property {Boolean} flippedY - Indicates whether or not the spirte is flipped on y axis.
* @property {Number} offsetX - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex.
* @property {Number} offsetY - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex.
* @property {Number} atlasIndex - The index used on the TextureAtlas.
* @property {cc.Texture2D} texture - Texture used to render the sprite.
* @property {Boolean} textureRectRotated - <@readonly> Indicate whether the texture rectangle is rotated.
* @property {cc.TextureAtlas} textureAtlas - The weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode.
* @property {cc.SpriteBatchNode} batchNode - The batch node object if this sprite is rendered by cc.SpriteBatchNode.
* @property {cc.V3F_C4B_T2F_Quad} quad - <@readonly> The quad (tex coords, vertex coords and color) information.
*/
cc.Sprite = cc.Node.extend(/** @lends cc.Sprite# */{
dirty:false,
atlasIndex:0,
textureAtlas:null,
_batchNode:null,
_recursiveDirty:null, //Whether all of the sprite's children needs to be updated
_hasChildren:null, //Whether the sprite contains children
_shouldBeHidden:false, //should not be drawn because one of the ancestors is not visible
_transformToBatch:null,
//
// Data used when the sprite is self-rendered
//
_blendFunc:null, //It's required for CCTextureProtocol inheritance
_texture:null, //cc.Texture2D object that is used to render the sprite
//
// Shared data
//
// texture
_rect:null, //Retangle of cc.Texture2D
_rectRotated:false, //Whether the texture is rotated
// Offset Position (used by Zwoptex)
_offsetPosition:null, // absolute
_unflippedOffsetPositionFromCenter:null,
_opacityModifyRGB:false,
// image is flipped
_flippedX:false, //Whether the sprite is flipped horizontally or not.
_flippedY:false, //Whether the sprite is flipped vertically or not.
_textureLoaded:false,
_loadedEventListeners: null,
_newTextureWhenChangeColor: null, //hack property for LabelBMFont
_className:"Sprite",
//Only for texture update judgment
_oldDisplayColor: cc.color.WHITE,
/**
* Returns whether the texture have been loaded
* @returns {boolean}
*/
textureLoaded:function(){
return this._textureLoaded;
},
/**
* Add a event listener for texture loaded event.
* @param {Function} callback
* @param {Object} target
*/
addLoadedEventListener:function(callback, target){
if(!this._loadedEventListeners)
this._loadedEventListeners = [];
this._loadedEventListeners.push({eventCallback:callback, eventTarget:target});
},
_callLoadedEventCallbacks:function(){
if(!this._loadedEventListeners)
return;
var locListeners = this._loadedEventListeners;
for(var i = 0, len = locListeners.length; i < len; i++){
var selCallback = locListeners[i];
selCallback.eventCallback.call(selCallback.eventTarget, this);
}
locListeners.length = 0;
},
/**
* Returns whether or not the Sprite needs to be updated in the Atlas
* @return {Boolean} True if the sprite needs to be updated in the Atlas, false otherwise.
*/
isDirty:function () {
return this.dirty;
},
/**
* Makes the sprite to be updated in the Atlas.
* @param {Boolean} bDirty
*/
setDirty:function (bDirty) {
this.dirty = bDirty;
},
/**
* Returns whether or not the texture rectangle is rotated.
* @return {Boolean}
*/
isTextureRectRotated:function () {
return this._rectRotated;
},
/**
* Returns the index used on the TextureAtlas.
* @return {Number}
*/
getAtlasIndex:function () {
return this.atlasIndex;
},
/**
* Sets the index used on the TextureAtlas.
* @warning Don't modify this value unless you know what you are doing
* @param {Number} atlasIndex
*/
setAtlasIndex:function (atlasIndex) {
this.atlasIndex = atlasIndex;
},
/**
* Returns the rect of the cc.Sprite in points
* @return {cc.Rect}
*/
getTextureRect:function () {
return cc.rect(this._rect.x, this._rect.y, this._rect.width, this._rect.height);
},
/**
* Returns the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
* @return {cc.TextureAtlas}
*/
getTextureAtlas:function () {
return this.textureAtlas;
},
/**
* Sets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode
* @param {cc.TextureAtlas} textureAtlas
*/
setTextureAtlas:function (textureAtlas) {
this.textureAtlas = textureAtlas;
},
/**
* Returns the offset position of the sprite. Calculated automatically by editors like Zwoptex.
* @return {cc.Point}
*/
getOffsetPosition:function () {
return cc.p(this._offsetPosition);
},
_getOffsetX: function () {
return this._offsetPosition.x;
},
_getOffsetY: function () {
return this._offsetPosition.y;
},
/**
* Returns the blend function
* @return {cc.BlendFunc}
*/
getBlendFunc:function () {
return this._blendFunc;
},
/**
* Initializes a sprite with an SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite.
* Please pass parameters to the constructor to initialize the sprite, do not call this function yourself,
* @param {cc.SpriteFrame} spriteFrame A CCSpriteFrame object. It should includes a valid texture and a rect
* @return {Boolean} true if the sprite is initialized properly, false otherwise.
*/
initWithSpriteFrame:function (spriteFrame) {
cc.assert(spriteFrame, cc._LogInfos.Sprite_initWithSpriteFrame);
if(!spriteFrame.textureLoaded()){
//add event listener
this._textureLoaded = false;
spriteFrame.addLoadedEventListener(this._spriteFrameLoadedCallback, this);
}
var rotated = cc._renderType === cc._RENDER_TYPE_CANVAS ? false : spriteFrame._rotated;
var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect(), rotated);
this.setSpriteFrame(spriteFrame);
return ret;
},
_spriteFrameLoadedCallback:null,
/**
* Initializes a sprite with a sprite frame name.
* A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name.
* If the cc.SpriteFrame doesn't exist it will raise an exception.
* Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
* @param {String} spriteFrameName A key string that can fected a volid cc.SpriteFrame from cc.SpriteFrameCache
* @return {Boolean} true if the sprite is initialized properly, false otherwise.
* @example
* var sprite = new cc.Sprite();
* sprite.initWithSpriteFrameName("grossini_dance_01.png");
*/
initWithSpriteFrameName:function (spriteFrameName) {
cc.assert(spriteFrameName, cc._LogInfos.Sprite_initWithSpriteFrameName);
var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName);
cc.assert(frame, spriteFrameName + cc._LogInfos.Sprite_initWithSpriteFrameName1);
return this.initWithSpriteFrame(frame);
},
/**
* Tell the sprite to use batch node render.
* @param {cc.SpriteBatchNode} batchNode
*/
useBatchNode:function (batchNode) {
this.textureAtlas = batchNode.textureAtlas; // weak ref
this._batchNode = batchNode;
},
/**
*
* set the vertex rect.
* It will be called internally by setTextureRect.
* Useful if you want to create 2x images from SD images in Retina Display.
* Do not call it manually. Use setTextureRect instead.
* (override this method to generate "double scale" sprites)
*
* @param {cc.Rect} rect
*/
setVertexRect:function (rect) {
this._rect.x = rect.x;
this._rect.y = rect.y;
this._rect.width = rect.width;
this._rect.height = rect.height;
},
/**
* Sort all children of this sprite node.
* @override
*/
sortAllChildren:function () {
if (this._reorderChildDirty) {
var _children = this._children;
// insertion sort
var len = _children.length, i, j, tmp;
for(i=1; i= 0){
if(tmp._localZOrder < _children[j]._localZOrder){
_children[j+1] = _children[j];
}else if(tmp._localZOrder === _children[j]._localZOrder && tmp.arrivalOrder < _children[j].arrivalOrder){
_children[j+1] = _children[j];
}else{
break;
}
j--;
}
_children[j+1] = tmp;
}
if (this._batchNode) {
this._arrayMakeObjectsPerformSelector(_children, cc.Node._StateCallbackType.sortAllChildren);
}
//don't need to check children recursively, that's done in visit of each child
this._reorderChildDirty = false;
}
},
/**
* Reorders a child according to a new z value. (override cc.Node )
* @param {cc.Node} child
* @param {Number} zOrder
* @override
*/
reorderChild:function (child, zOrder) {
cc.assert(child, cc._LogInfos.Sprite_reorderChild_2);
if(this._children.indexOf(child) === -1){
cc.log(cc._LogInfos.Sprite_reorderChild);
return;
}
if (zOrder === child.zIndex)
return;
if (this._batchNode && !this._reorderChildDirty) {
this._setReorderChildDirtyRecursively();
this._batchNode.reorderBatch(true);
}
cc.Node.prototype.reorderChild.call(this, child, zOrder);
},
/**
* Removes a child from the sprite.
* @param child
* @param cleanup whether or not cleanup all running actions
* @override
*/
removeChild:function (child, cleanup) {
if (this._batchNode)
this._batchNode.removeSpriteFromAtlas(child);
cc.Node.prototype.removeChild.call(this, child, cleanup);
},
/**
* Sets whether the sprite is visible or not.
* @param {Boolean} visible
* @override
*/
setVisible:function (visible) {
cc.Node.prototype.setVisible.call(this, visible);
this.setDirtyRecursively(true);
},
/**
* Removes all children from the container.
* @param cleanup whether or not cleanup all running actions
* @override
*/
removeAllChildren:function (cleanup) {
var locChildren = this._children, locBatchNode = this._batchNode;
if (locBatchNode && locChildren != null) {
for (var i = 0, len = locChildren.length; i < len; i++)
locBatchNode.removeSpriteFromAtlas(locChildren[i]);
}
cc.Node.prototype.removeAllChildren.call(this, cleanup);
this._hasChildren = false;
},
//
// cc.Node property overloads
//
/**
* Sets recursively the dirty flag.
* Used only when parent is cc.SpriteBatchNode
* @param {Boolean} value
*/
setDirtyRecursively:function (value) {
this._recursiveDirty = value;
this.dirty = value;
// recursively set dirty
var locChildren = this._children, child, l = locChildren ? locChildren.length : 0;
for (var i = 0; i < l; i++) {
child = locChildren[i];
(child instanceof cc.Sprite) && child.setDirtyRecursively(true);
}
},
/**
* Make the node dirty
* @param {Boolean} norecursive When true children will not be set dirty recursively, by default, they will be.
* @override
*/
setNodeDirty: function(norecursive) {
cc.Node.prototype.setNodeDirty.call(this);
// Lazy set dirty
if (!norecursive && this._batchNode && !this._recursiveDirty) {
if (this._hasChildren)
this.setDirtyRecursively(true);
else {
this._recursiveDirty = true;
this.dirty = true;
}
}
},
/**
* Sets whether ignore anchor point for positioning
* @param {Boolean} relative
* @override
*/
ignoreAnchorPointForPosition:function (relative) {
if(this._batchNode){
cc.log(cc._LogInfos.Sprite_ignoreAnchorPointForPosition);
return;
}
cc.Node.prototype.ignoreAnchorPointForPosition.call(this, relative);
},
/**
* Sets whether the sprite should be flipped horizontally or not.
* @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise.
*/
setFlippedX:function (flippedX) {
if (this._flippedX != flippedX) {
this._flippedX = flippedX;
this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
this.setNodeDirty(true);
}
},
/**
* Sets whether the sprite should be flipped vertically or not.
* @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise.
*/
setFlippedY:function (flippedY) {
if (this._flippedY != flippedY) {
this._flippedY = flippedY;
this.setTextureRect(this._rect, this._rectRotated, this._contentSize);
this.setNodeDirty(true);
}
},
/**
*
* Returns the flag which indicates whether the sprite is flipped horizontally or not.
*
* It only flips the texture of the sprite, and not the texture of the sprite's children.
* Also, flipping the texture doesn't alter the anchorPoint.
* If you want to flip the anchorPoint too, and/or to flip the children too use:
* sprite.setScaleX(sprite.getScaleX() * -1);
* @return {Boolean} true if the sprite is flipped horizontally, false otherwise.
*/
isFlippedX:function () {
return this._flippedX;
},
/**
*
* Return the flag which indicates whether the sprite is flipped vertically or not.
*
* It only flips the texture of the sprite, and not the texture of the sprite's children.
* Also, flipping the texture doesn't alter the anchorPoint.
* If you want to flip the anchorPoint too, and/or to flip the children too use:
* sprite.setScaleY(sprite.getScaleY() * -1);
* @return {Boolean} true if the sprite is flipped vertically, false otherwise.
*/
isFlippedY:function () {
return this._flippedY;
},
//
// RGBA protocol
//
/**
* Sets whether opacity modify color or not.
* @function
* @param {Boolean} modify
*/
setOpacityModifyRGB:null,
/**
* Returns whether opacity modify color or not.
* @return {Boolean}
*/
isOpacityModifyRGB:function () {
return this._opacityModifyRGB;
},
/**
* Update the display opacity.
* @function
*/
updateDisplayedOpacity: null,
// Animation
/**
* Changes the display frame with animation name and index.
* The animation name will be get from the CCAnimationCache
* @param {String} animationName
* @param {Number} frameIndex
*/
setDisplayFrameWithAnimationName:function (animationName, frameIndex) {
cc.assert(animationName, cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_3);
var cache = cc.animationCache.getAnimation(animationName);
if(!cache){
cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName);
return;
}
var animFrame = cache.getFrames()[frameIndex];
if(!animFrame){
cc.log(cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_2);
return;
}
this.setSpriteFrame(animFrame.getSpriteFrame());
},
/**
* Returns the batch node object if this sprite is rendered by cc.SpriteBatchNode
* @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.
*/
getBatchNode:function () {
return this._batchNode;
},
_setReorderChildDirtyRecursively:function () {
//only set parents flag the first time
if (!this._reorderChildDirty) {
this._reorderChildDirty = true;
var pNode = this._parent;
while (pNode && pNode != this._batchNode) {
pNode._setReorderChildDirtyRecursively();
pNode = pNode.parent;
}
}
},
// CCTextureProtocol
/**
* Returns the texture of the sprite node
* @returns {cc.Texture2D}
*/
getTexture:function () {
return this._texture;
},
_quad: null, // vertex coords, texture coords and color info
_quadWebBuffer: null,
_quadDirty: false,
_colorized: false,
_blendFuncStr: "source",
_originalTexture: null,
_textureRect_Canvas: null,
_drawSize_Canvas: null,
ctor: null,
_softInit: function (fileName, rect, rotated) {
if (fileName === undefined)
cc.Sprite.prototype.init.call(this);
else if (typeof(fileName) === "string") {
if (fileName[0] === "#") {
// Init with a sprite frame name
var frameName = fileName.substr(1, fileName.length - 1);
var spriteFrame = cc.spriteFrameCache.getSpriteFrame(frameName);
this.initWithSpriteFrame(spriteFrame);
} else {
// Init with filename and rect
cc.Sprite.prototype.init.call(this, fileName, rect);
}
}
else if (typeof(fileName) === "object") {
if (fileName instanceof cc.Texture2D) {
// Init with texture and rect
this.initWithTexture(fileName, rect, rotated);
} else if (fileName instanceof cc.SpriteFrame) {
// Init with a sprite frame
this.initWithSpriteFrame(fileName);
} else if ((fileName instanceof HTMLImageElement) || (fileName instanceof HTMLCanvasElement)) {
// Init with a canvas or image element
var texture2d = new cc.Texture2D();
texture2d.initWithElement(fileName);
texture2d.handleLoadedTexture();
this.initWithTexture(texture2d);
}
}
},
/**
* Returns the quad (tex coords, vertex coords and color) information.
* @return {cc.V3F_C4B_T2F_Quad}
*/
getQuad:function () {
return this._quad;
},
/**
* conforms to cc.TextureProtocol protocol
* @function
* @param {Number|cc.BlendFunc} src
* @param {Number} dst
*/
setBlendFunc: null,
/**
* Initializes an empty sprite with nothing init.
* Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
* @function
* @return {Boolean}
*/
init:null,
/**
*
* Initializes a sprite with an image filename.
*
* This method will find pszFilename from local file system, load its content to CCTexture2D,
* then use CCTexture2D to create a sprite.
* After initialization, the rect used will be the size of the image. The offset will be (0,0).
* Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
*
* @param {String} filename The path to an image file in local file system
* @param {cc.Rect} rect The rectangle assigned the content area from texture.
* @return {Boolean} true if the sprite is initialized properly, false otherwise.
*/
initWithFile:function (filename, rect) {
cc.assert(filename, cc._LogInfos.Sprite_initWithFile);
var tex = cc.textureCache.getTextureForKey(filename);
if (!tex) {
tex = cc.textureCache.addImage(filename);
return this.initWithTexture(tex, rect || cc.rect(0, 0, tex._contentSize.width, tex._contentSize.height));
} else {
if (!rect) {
var size = tex.getContentSize();
rect = cc.rect(0, 0, size.width, size.height);
}
return this.initWithTexture(tex, rect);
}
},
/**
* Initializes a sprite with a texture and a rect in points, optionally rotated.
* After initialization, the rect used will be the size of the texture, and the offset will be (0,0).
* Please pass parameters to the constructor to initialize the sprite, do not call this function yourself.
* @function
* @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites.
* @param {cc.Rect} rect Only the contents inside rect of this texture will be applied for this sprite.
* @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
* @return {Boolean} true if the sprite is initialized properly, false otherwise.
*/
initWithTexture: null,
_textureLoadedCallback: null,
/**
* Updates the texture rect of the CCSprite in points.
* @function
* @param {cc.Rect} rect a rect of texture
* @param {Boolean} [rotated] Whether or not the texture is rotated
* @param {cc.Size} [untrimmedSize] The original pixels size of the texture
*/
setTextureRect:null,
// BatchNode methods
/**
* Updates the quad according the the rotation, position, scale values.
* @function
*/
updateTransform: null,
/**
* Add child to sprite (override cc.Node)
* @function
* @param {cc.Sprite} child
* @param {Number} localZOrder child's zOrder
* @param {String} tag child's tag
* @override
*/
addChild: null,
/**
* Update sprite's color
*/
updateColor:function () {
var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity;
var color4 = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: locDisplayedOpacity};
// special opacity for premultiplied textures
if (this._opacityModifyRGB) {
color4.r *= locDisplayedOpacity / 255.0;
color4.g *= locDisplayedOpacity / 255.0;
color4.b *= locDisplayedOpacity / 255.0;
}
var locQuad = this._quad;
locQuad.bl.colors = color4;
locQuad.br.colors = color4;
locQuad.tl.colors = color4;
locQuad.tr.colors = color4;
// renders using Sprite Manager
if (this._batchNode) {
if (this.atlasIndex != cc.Sprite.INDEX_NOT_INITIALIZED) {
this.textureAtlas.updateQuad(locQuad, this.atlasIndex)
} else {
// no need to set it recursively
// update dirty_, don't update recursiveDirty_
this.dirty = true;
}
}
// self render
// do nothing
this._quadDirty = true;
},
/**
* Sets opacity of the sprite
* @function
* @param {Number} opacity
*/
setOpacity:null,
/**
* Sets color of the sprite
* @function
* @param {cc.Color} color3
*/
setColor: null,
/**
* Updates the display color
* @function
*/
updateDisplayedColor: null,
// Frames
/**
* Sets a new sprite frame to the sprite.
* @function
* @param {cc.SpriteFrame|String} newFrame
*/
setSpriteFrame: null,
/**
* Sets a new display frame to the sprite.
* @param {cc.SpriteFrame|String} newFrame
* @deprecated
*/
setDisplayFrame: function(newFrame){
cc.log(cc._LogInfos.Sprite_setDisplayFrame);
this.setSpriteFrame(newFrame);
},
/**
* Returns whether or not a cc.SpriteFrame is being displayed
* @function
* @param {cc.SpriteFrame} frame
* @return {Boolean}
*/
isFrameDisplayed: null,
/**
* Returns the current displayed frame.
* @return {cc.SpriteFrame}
*/
displayFrame: function () {
return cc.SpriteFrame.create(this._texture,
cc.rectPointsToPixels(this._rect),
this._rectRotated,
cc.pointPointsToPixels(this._unflippedOffsetPositionFromCenter),
cc.sizePointsToPixels(this._contentSize));
},
/**
* Sets the batch node to sprite
* @function
* @param {cc.SpriteBatchNode|null} spriteBatchNode
* @example
* var batch = cc.SpriteBatchNode.create("Images/grossini_dance_atlas.png", 15);
* var sprite = cc.Sprite.create(batch.texture, cc.rect(0, 0, 57, 57));
* batch.addChild(sprite);
* layer.addChild(batch);
*/
setBatchNode:null,
// CCTextureProtocol
/**
* Sets the texture of sprite
* @function
* @param {cc.Texture2D|String} texture
*/
setTexture: null,
// Texture protocol
_updateBlendFunc:function () {
if(this._batchNode){
cc.log(cc._LogInfos.Sprite__updateBlendFunc);
return;
}
// it's possible to have an untextured sprite
if (!this._texture || !this._texture.hasPremultipliedAlpha()) {
this._blendFunc.src = cc.SRC_ALPHA;
this._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA;
this.opacityModifyRGB = false;
} else {
this._blendFunc.src = cc.BLEND_SRC;
this._blendFunc.dst = cc.BLEND_DST;
this.opacityModifyRGB = true;
}
},
_changeTextureColor: function () {
var locElement, locTexture = this._texture, locRect = this._textureRect_Canvas; //this.getTextureRect();
if (locTexture && locRect.validRect && this._originalTexture) {
locElement = locTexture.getHtmlElementObj();
if (!locElement)
return;
this._colorized = true;
if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor
&& this._originalTexture._htmlElementObj != locElement)
cc.generateTintImageWithMultiply(this._originalTexture._htmlElementObj, this._displayedColor, locRect, locElement);
else {
locElement = cc.generateTintImageWithMultiply(this._originalTexture._htmlElementObj, this._displayedColor, locRect);
locTexture = new cc.Texture2D();
locTexture.initWithElement(locElement);
locTexture.handleLoadedTexture();
this.texture = locTexture;
}
}
},
_setTextureCoords:function (rect) {
rect = cc.rectPointsToPixels(rect);
var tex = this._batchNode ? this.textureAtlas.texture : this._texture;
if (!tex)
return;
var atlasWidth = tex.pixelsWidth;
var atlasHeight = tex.pixelsHeight;
var left, right, top, bottom, tempSwap, locQuad = this._quad;
if (this._rectRotated) {
if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
left = (2 * rect.x + 1) / (2 * atlasWidth);
right = left + (rect.height * 2 - 2) / (2 * atlasWidth);
top = (2 * rect.y + 1) / (2 * atlasHeight);
bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight);
} else {
left = rect.x / atlasWidth;
right = (rect.x + rect.height) / atlasWidth;
top = rect.y / atlasHeight;
bottom = (rect.y + rect.width) / atlasHeight;
}// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
if (this._flippedX) {
tempSwap = top;
top = bottom;
bottom = tempSwap;
}
if (this._flippedY) {
tempSwap = left;
left = right;
right = tempSwap;
}
locQuad.bl.texCoords.u = left;
locQuad.bl.texCoords.v = top;
locQuad.br.texCoords.u = left;
locQuad.br.texCoords.v = bottom;
locQuad.tl.texCoords.u = right;
locQuad.tl.texCoords.v = top;
locQuad.tr.texCoords.u = right;
locQuad.tr.texCoords.v = bottom;
} else {
if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) {
left = (2 * rect.x + 1) / (2 * atlasWidth);
right = left + (rect.width * 2 - 2) / (2 * atlasWidth);
top = (2 * rect.y + 1) / (2 * atlasHeight);
bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight);
} else {
left = rect.x / atlasWidth;
right = (rect.x + rect.width) / atlasWidth;
top = rect.y / atlasHeight;
bottom = (rect.y + rect.height) / atlasHeight;
} // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
if (this._flippedX) {
tempSwap = left;
left = right;
right = tempSwap;
}
if (this._flippedY) {
tempSwap = top;
top = bottom;
bottom = tempSwap;
}
locQuad.bl.texCoords.u = left;
locQuad.bl.texCoords.v = bottom;
locQuad.br.texCoords.u = right;
locQuad.br.texCoords.v = bottom;
locQuad.tl.texCoords.u = left;
locQuad.tl.texCoords.v = top;
locQuad.tr.texCoords.u = right;
locQuad.tr.texCoords.v = top;
}
this._quadDirty = true;
},
/**
* draw sprite to canvas
* @function
*/
draw: null
});
/**
* Create a sprite with image path or frame name or texture or spriteFrame.
* @deprecated since v3.0, please use new construction instead
* @see cc.Sprite
* @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName The string which indicates a path to image file, e.g., "scene1/monster.png".
* @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite.
* @param {Boolean} [rotated] Whether or not the texture rectangle is rotated.
* @return {cc.Sprite} A valid sprite object
*/
cc.Sprite.create = function (fileName, rect, rotated) {
return new cc.Sprite(fileName, rect, rotated);
};
/**
* @deprecated since v3.0, please use new construction instead
* @see cc.Sprite
* @function
*/
cc.Sprite.createWithTexture = cc.Sprite.create;
/**
* @deprecated since v3.0, please use new construction instead
* @see cc.Sprite
* @function
*/
cc.Sprite.createWithSpriteFrameName = cc.Sprite.create;
/**
* @deprecated since v3.0, please use new construction instead
* @see cc.Sprite
* @function
*/
cc.Sprite.createWithSpriteFrame = cc.Sprite.create;
/**
* cc.Sprite invalid index on the cc.SpriteBatchNode
* @constant
* @type {Number}
*/
cc.Sprite.INDEX_NOT_INITIALIZED = -1;
if (cc._renderType === cc._RENDER_TYPE_CANVAS) {
var _p = cc.Sprite.prototype;
_p._spriteFrameLoadedCallback = function(spriteFrame){
var _t = this;
_t.setNodeDirty(true);
_t.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize());
var curColor = _t.color;
if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
_t._changeTextureColor();
_t._callLoadedEventCallbacks();
};
_p.setOpacityModifyRGB = function (modify) {
if (this._opacityModifyRGB !== modify) {
this._opacityModifyRGB = modify;
this.setNodeDirty(true);
}
};
_p.updateDisplayedOpacity = function (parentOpacity) {
cc.Node.prototype.updateDisplayedOpacity.call(this, parentOpacity);
this._setNodeDirtyForCache();
};
_p.ctor = function (fileName, rect, rotated) {
var self = this;
cc.Node.prototype.ctor.call(self);
self._shouldBeHidden = false;
self._offsetPosition = cc.p(0, 0);
self._unflippedOffsetPositionFromCenter = cc.p(0, 0);
self._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST};
self._rect = cc.rect(0, 0, 0, 0);
self._newTextureWhenChangeColor = false;
self._textureLoaded = true;
self._textureRect_Canvas = {x: 0, y: 0, width: 0, height:0, validRect: false};
self._drawSize_Canvas = cc.size(0, 0);
self._softInit(fileName, rect, rotated);
};
_p.setBlendFunc = function (src, dst) {
var _t = this, locBlendFunc = this._blendFunc;
if (dst === undefined) {
locBlendFunc.src = src.src;
locBlendFunc.dst = src.dst;
} else {
locBlendFunc.src = src;
locBlendFunc.dst = dst;
}
if (cc._renderType === cc._RENDER_TYPE_CANVAS)
_t._blendFuncStr = cc._getCompositeOperationByBlendFunc(locBlendFunc);
};
_p.init = function () {
var _t = this;
if (arguments.length > 0)
return _t.initWithFile(arguments[0], arguments[1]);
cc.Node.prototype.init.call(_t);
_t.dirty = _t._recursiveDirty = false;
_t._opacityModifyRGB = true;
_t._blendFunc.src = cc.BLEND_SRC;
_t._blendFunc.dst = cc.BLEND_DST;
// update texture (calls _updateBlendFunc)
_t.texture = null;
_t._textureLoaded = true;
_t._flippedX = _t._flippedY = false;
// default transform anchor: center
_t.anchorX = 0.5;
_t.anchorY = 0.5;
// zwoptex default values
_t._offsetPosition.x = 0;
_t._offsetPosition.y = 0;
_t._hasChildren = false;
// updated in "useSelfRender"
// Atlas: TexCoords
_t.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0));
return true;
};
_p.initWithTexture = function (texture, rect, rotated) {
var _t = this;
cc.assert(arguments.length != 0, cc._LogInfos.CCSpriteBatchNode_initWithTexture);
rotated = rotated || false;
if (rotated && texture.isLoaded()) {
var tempElement = texture.getHtmlElementObj();
tempElement = cc.cutRotateImageToCanvas(tempElement, rect);
var tempTexture = new cc.Texture2D();
tempTexture.initWithElement(tempElement);
tempTexture.handleLoadedTexture();
texture = tempTexture;
_t._rect = cc.rect(0, 0, rect.width, rect.height);
}
if (!cc.Node.prototype.init.call(_t))
return false;
_t._batchNode = null;
_t._recursiveDirty = false;
_t.dirty = false;
_t._opacityModifyRGB = true;
_t._blendFunc.src = cc.BLEND_SRC;
_t._blendFunc.dst = cc.BLEND_DST;
_t._flippedX = _t._flippedY = false;
// default transform anchor: center
_t.anchorX = 0.5;
_t.anchorY = 0.5;
// zwoptex default values
_t._offsetPosition.x = 0;
_t._offsetPosition.y = 0;
_t._hasChildren = false;
var locTextureLoaded = texture.isLoaded();
_t._textureLoaded = locTextureLoaded;
if (!locTextureLoaded) {
_t._rectRotated = rotated;
if (rect) {
_t._rect.x = rect.x;
_t._rect.y = rect.y;
_t._rect.width = rect.width;
_t._rect.height = rect.height;
}
if(_t.texture)
_t.texture.removeLoadedEventListener(_t);
texture.addLoadedEventListener(_t._textureLoadedCallback, _t);
_t.texture = texture;
return true;
}
if (!rect) {
rect = cc.rect(0, 0, texture.width, texture.height);
}
if(texture && texture.url) {
var _x = rect.x + rect.width, _y = rect.y + rect.height;
if(_x > texture.width){
cc.error(cc._LogInfos.RectWidth, texture.url);
}
if(_y > texture.height){
cc.error(cc._LogInfos.RectHeight, texture.url);
}
}
_t._originalTexture = texture;
_t.texture = texture;
_t.setTextureRect(rect, rotated);
// by default use "Self Render".
// if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
_t.batchNode = null;
return true;
};
_p._textureLoadedCallback = function (sender) {
var _t = this;
if(_t._textureLoaded)
return;
_t._textureLoaded = true;
var locRect = _t._rect;
if (!locRect) {
locRect = cc.rect(0, 0, sender.width, sender.height);
} else if (cc._rectEqualToZero(locRect)) {
locRect.width = sender.width;
locRect.height = sender.height;
}
_t._originalTexture = sender;
_t.texture = sender;
_t.setTextureRect(locRect, _t._rectRotated);
//set the texture's color after the it loaded
var locColor = this._displayedColor;
if(locColor.r != 255 || locColor.g != 255 || locColor.b != 255)
_t._changeTextureColor();
// by default use "Self Render".
// if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render"
_t.batchNode = _t._batchNode;
_t._callLoadedEventCallbacks();
};
_p.setTextureRect = function (rect, rotated, untrimmedSize) {
var _t = this;
_t._rectRotated = rotated || false;
_t.setContentSize(untrimmedSize || rect);
_t.setVertexRect(rect);
var locTextureRect = _t._textureRect_Canvas, scaleFactor = cc.contentScaleFactor();
locTextureRect.x = 0 | (rect.x * scaleFactor);
locTextureRect.y = 0 | (rect.y * scaleFactor);
locTextureRect.width = 0 | (rect.width * scaleFactor);
locTextureRect.height = 0 | (rect.height * scaleFactor);
locTextureRect.validRect = !(locTextureRect.width === 0 || locTextureRect.height === 0 || locTextureRect.x < 0 || locTextureRect.y < 0);
var relativeOffset = _t._unflippedOffsetPositionFromCenter;
if (_t._flippedX)
relativeOffset.x = -relativeOffset.x;
if (_t._flippedY)
relativeOffset.y = -relativeOffset.y;
_t._offsetPosition.x = relativeOffset.x + (_t._contentSize.width - _t._rect.width) / 2;
_t._offsetPosition.y = relativeOffset.y + (_t._contentSize.height - _t._rect.height) / 2;
// rendering using batch node
if (_t._batchNode) {
// update dirty, don't update _recursiveDirty
_t.dirty = true;
}
};
_p.updateTransform = function () {
var _t = this;
//cc.assert(_t._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode");
// recaculate matrix only if it is dirty
if (_t.dirty) {
// If it is not visible, or one of its ancestors is not visible, then do nothing:
var locParent = _t._parent;
if (!_t._visible || ( locParent && locParent != _t._batchNode && locParent._shouldBeHidden)) {
_t._shouldBeHidden = true;
} else {
_t._shouldBeHidden = false;
if (!locParent || locParent == _t._batchNode) {
_t._transformToBatch = _t.nodeToParentTransform();
} else {
//cc.assert(_t._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite");
_t._transformToBatch = cc.affineTransformConcat(_t.nodeToParentTransform(), locParent._transformToBatch);
}
}
_t._recursiveDirty = false;
_t.dirty = false;
}
// recursively iterate over children
if (_t._hasChildren)
_t._arrayMakeObjectsPerformSelector(_t._children, cc.Node._StateCallbackType.updateTransform);
};
_p.addChild = function (child, localZOrder, tag) {
cc.assert(child, cc._LogInfos.CCSpriteBatchNode_addChild_2);
if (localZOrder == null)
localZOrder = child._localZOrder;
if (tag == null)
tag = child.tag;
//cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check
cc.Node.prototype.addChild.call(this, child, localZOrder, tag);
this._hasChildren = true;
};
_p.setOpacity = function (opacity) {
cc.Node.prototype.setOpacity.call(this, opacity);
this._setNodeDirtyForCache();
};
_p.setColor = function (color3) {
var _t = this;
var curColor = _t.color;
this._oldDisplayColor = curColor;
if ((curColor.r === color3.r) && (curColor.g === color3.g) && (curColor.b === color3.b))
return;
cc.Node.prototype.setColor.call(_t, color3);
};
_p.updateDisplayedColor = function (parentColor) {
var _t = this;
cc.Node.prototype.updateDisplayedColor.call(_t, parentColor);
var oColor = _t._oldDisplayColor;
var nColor = _t._displayedColor;
if (oColor.r === nColor.r && oColor.g === nColor.g && oColor.b === nColor.b)
return;
_t._changeTextureColor();
_t._setNodeDirtyForCache();
};
_p.setSpriteFrame = function (newFrame) {
var _t = this;
if(typeof(newFrame) == "string"){
newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame);
cc.assert(newFrame, cc._LogInfos.CCSpriteBatchNode_setSpriteFrame)
}
_t.setNodeDirty(true);
var frameOffset = newFrame.getOffset();
_t._unflippedOffsetPositionFromCenter.x = frameOffset.x;
_t._unflippedOffsetPositionFromCenter.y = frameOffset.y;
// update rect
_t._rectRotated = newFrame.isRotated();
var pNewTexture = newFrame.getTexture();
var locTextureLoaded = newFrame.textureLoaded();
if (!locTextureLoaded) {
_t._textureLoaded = false;
newFrame.addLoadedEventListener(function (sender) {
_t._textureLoaded = true;
var locNewTexture = sender.getTexture();
if (locNewTexture != _t._texture)
_t.texture = locNewTexture;
_t.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize());
_t._callLoadedEventCallbacks();
}, _t);
}
// update texture before updating texture rect
if (pNewTexture != _t._texture)
_t.texture = pNewTexture;
if (_t._rectRotated)
_t._originalTexture = pNewTexture;
_t.setTextureRect(newFrame.getRect(), _t._rectRotated, newFrame.getOriginalSize());
_t._colorized = false;
if (locTextureLoaded) {
var curColor = _t.color;
if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255)
_t._changeTextureColor();
}
};
_p.isFrameDisplayed = function (frame) {
if (frame.getTexture() != this._texture)
return false;
return cc.rectEqualToRect(frame.getRect(), this._rect);
};
_p.setBatchNode = function (spriteBatchNode) {
var _t = this;
_t._batchNode = spriteBatchNode; // weak reference
// self render
if (!_t._batchNode) {
_t.atlasIndex = cc.Sprite.INDEX_NOT_INITIALIZED;
_t.textureAtlas = null;
_t._recursiveDirty = false;
_t.dirty = false;
} else {
// using batch
_t._transformToBatch = cc.affineTransformIdentity();
_t.textureAtlas = _t._batchNode.textureAtlas; // weak ref
}
};
_p.setTexture = function (texture) {
var _t = this;
if(texture && (typeof(texture) === "string")){
texture = cc.textureCache.addImage(texture);
_t.setTexture(texture);
//TODO
var size = texture.getContentSize();
_t.setTextureRect(cc.rect(0,0, size.width, size.height));
return;
}
// CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet
cc.assert(!texture || texture instanceof cc.Texture2D, cc._LogInfos.CCSpriteBatchNode_setTexture);
if (_t._texture != texture) {
if (texture && texture.getHtmlElementObj() instanceof HTMLImageElement) {
_t._originalTexture = texture;
}
_t._texture = texture;
}
};
_p.draw = function (ctx) {
var _t = this;
if (!_t._textureLoaded)
return;
var context = ctx || cc._renderContext;
if (_t._blendFuncStr != "source")
context.globalCompositeOperation = _t._blendFuncStr;
var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY();
context.globalAlpha = _t._displayedOpacity / 255;
var locRect = _t._rect, locContentSize = _t._contentSize, locOffsetPosition = _t._offsetPosition, locDrawSizeCanvas = _t._drawSize_Canvas;
var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = _t._textureRect_Canvas;
locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX;
locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY;
if (_t._flippedX || _t._flippedY) {
context.save();
if (_t._flippedX) {
flipXOffset = -locOffsetPosition.x - locRect.width;
context.scale(-1, 1);
}
if (_t._flippedY) {
flipYOffset = locOffsetPosition.y;
context.scale(1, -1);
}
}
flipXOffset *= locEGL_ScaleX;
flipYOffset *= locEGL_ScaleY;
if (_t._texture && locTextureCoord.validRect) {
var image = _t._texture.getHtmlElementObj();
if (_t._colorized) {
context.drawImage(image,
0, 0, locTextureCoord.width, locTextureCoord.height,
flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height);
} else {
context.drawImage(image,
locTextureCoord.x, locTextureCoord.y, locTextureCoord.width, locTextureCoord.height,
flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height);
}
} else if (!_t._texture && locTextureCoord.validRect) {
var curColor = _t.color;
context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)";
context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY);
}
if (cc.SPRITE_DEBUG_DRAW === 1 || _t._showNode) {
// draw bounding box
context.strokeStyle = "rgba(0,255,0,1)";
flipXOffset /= locEGL_ScaleX;
flipYOffset /= locEGL_ScaleY;
flipYOffset = -flipYOffset;
var vertices1 = [cc.p(flipXOffset, flipYOffset),
cc.p(flipXOffset + locRect.width, flipYOffset),
cc.p(flipXOffset + locRect.width, flipYOffset - locRect.height),
cc.p(flipXOffset, flipYOffset - locRect.height)];
cc._drawingUtil.drawPoly(vertices1, 4, true);
} else if (cc.SPRITE_DEBUG_DRAW === 2) {
// draw texture box
context.strokeStyle = "rgba(0,255,0,1)";
var drawRect = _t._rect;
flipYOffset = -flipYOffset;
var vertices2 = [cc.p(flipXOffset, flipYOffset), cc.p(flipXOffset + drawRect.width, flipYOffset),
cc.p(flipXOffset + drawRect.width, flipYOffset - drawRect.height), cc.p(flipXOffset, flipYOffset - drawRect.height)];
cc._drawingUtil.drawPoly(vertices2, 4, true);
}
if (_t._flippedX || _t._flippedY)
context.restore();
cc.g_NumberOfDraws++;
};
if(!cc.sys._supportCanvasNewBlendModes)
_p._changeTextureColor = function () {
var locElement, locTexture = this._texture, locRect = this._textureRect_Canvas; //this.getTextureRect();
if (locTexture && locRect.validRect && this._originalTexture) {
locElement = locTexture.getHtmlElementObj();
if (!locElement)
return;
var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj());
if (cacheTextureForColor) {
this._colorized = true;
//generate color texture cache
if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor)
cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect, locElement);
else {
locElement = cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect);
locTexture = new cc.Texture2D();
locTexture.initWithElement(locElement);
locTexture.handleLoadedTexture();
this.texture = locTexture;
}
}
}
};
delete _p;
} else {
cc.assert(typeof cc._tmp.WebGLSprite === "function", cc._LogInfos.MissingFile, "SpritesWebGL.js");
cc._tmp.WebGLSprite();
delete cc._tmp.WebGLSprite;
}
cc.assert(typeof cc._tmp.PrototypeSprite === "function", cc._LogInfos.MissingFile, "SpritesPropertyDefine.js");
cc._tmp.PrototypeSprite();
delete cc._tmp.PrototypeSprite;