1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** 28 * <p> 29 * A cc.SpriteFrame has:<br/> 30 * - texture: A cc.Texture2D that will be used by the cc.Sprite<br/> 31 * - rectangle: A rectangle of the texture<br/> 32 * <br/> 33 * You can modify the frame of a cc.Sprite by doing:<br/> 34 * </p> 35 * @class 36 * @extends cc.Class 37 * 38 * @param {String|cc.Texture2D} filename 39 * @param {cc.Rect} rect If parameters' length equal 2, rect in points, else rect in pixels 40 * @param {Boolean} [rotated] Whether the frame is rotated in the texture 41 * @param {cc.Point} [offset] The offset of the frame in the texture 42 * @param {cc.Size} [originalSize] The size of the frame in the texture 43 * 44 * @example 45 * // 1. Create a cc.SpriteFrame with image path 46 * var frame1 = new cc.SpriteFrame("res/grossini_dance.png",cc.rect(0,0,90,128)); 47 * var frame2 = new cc.SpriteFrame("res/grossini_dance.png",cc.rect(0,0,90,128),false,0,cc.size(90,128)); 48 * 49 * // 2. Create a cc.SpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. 50 * var texture = cc.textureCache.addImage("res/grossini_dance.png"); 51 * var frame1 = new cc.SpriteFrame(texture, cc.rect(0,0,90,128)); 52 * var frame2 = new cc.SpriteFrame(texture, cc.rect(0,0,90,128),false,0,cc.size(90,128)); 53 */ 54 cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ 55 _offset:null, 56 _originalSize:null, 57 _rectInPixels:null, 58 _rotated:false, 59 _rect:null, 60 _offsetInPixels:null, 61 _originalSizeInPixels:null, 62 _texture:null, 63 _textureFilename:"", 64 _textureLoaded:false, 65 _eventListeners:null, 66 67 ctor:function (filename, rect, rotated, offset, originalSize) { 68 this._offset = cc.p(0, 0); 69 this._offsetInPixels = cc.p(0, 0); 70 this._originalSize = cc.size(0, 0); 71 this._rotated = false; 72 this._originalSizeInPixels = cc.size(0, 0); 73 this._textureFilename = ""; 74 this._texture = null; 75 this._textureLoaded = false; 76 77 if(filename !== undefined && rect !== undefined ){ 78 if(rotated === undefined || offset === undefined || originalSize === undefined) 79 this.initWithTexture(filename, rect); 80 else 81 this.initWithTexture(filename, rect, rotated, offset, originalSize) 82 } 83 }, 84 85 /** 86 * Returns whether the texture have been loaded 87 * @returns {boolean} 88 */ 89 textureLoaded:function(){ 90 return this._textureLoaded; 91 }, 92 93 /** 94 * Add a event listener for texture loaded event. 95 * @param {Function} callback 96 * @param {Object} target 97 */ 98 addLoadedEventListener:function(callback, target){ 99 if (this._eventListeners == null){ 100 this._eventListeners = []; 101 } 102 this._eventListeners.push({eventCallback:callback, eventTarget:target}); 103 }, 104 105 _callLoadedEventCallbacks:function(){ 106 var locListeners = this._eventListeners; 107 if (!locListeners) return; 108 for(var i = 0, len = locListeners.length; i < len; i++){ 109 var selCallback = locListeners[i]; 110 selCallback.eventCallback.call(selCallback.eventTarget, this); 111 } 112 locListeners.length = 0; 113 }, 114 115 /** 116 * Gets the rect of the frame in the texture 117 * @return {cc.Rect} 118 */ 119 getRectInPixels:function () { 120 var locRectInPixels = this._rectInPixels; 121 return cc.rect(locRectInPixels.x, locRectInPixels.y, locRectInPixels.width, locRectInPixels.height); 122 }, 123 124 /** 125 * Sets the rect of the frame in the texture 126 * @param {cc.Rect} rectInPixels 127 */ 128 setRectInPixels:function (rectInPixels) { 129 if (!this._rectInPixels){ 130 this._rectInPixels = cc.rect(0,0,0,0); 131 } 132 this._rectInPixels.x = rectInPixels.x; 133 this._rectInPixels.y = rectInPixels.y; 134 this._rectInPixels.width = rectInPixels.width; 135 this._rectInPixels.height = rectInPixels.height; 136 this._rect = cc.rectPixelsToPoints(rectInPixels); 137 }, 138 139 /** 140 * Returns whether the sprite frame is rotated in the texture. 141 * @return {Boolean} 142 */ 143 isRotated:function () { 144 return this._rotated; 145 }, 146 147 /** 148 * Set whether the sprite frame is rotated in the texture. 149 * @param {Boolean} bRotated 150 */ 151 setRotated:function (bRotated) { 152 this._rotated = bRotated; 153 }, 154 155 /** 156 * Returns the rect of the sprite frame in the texture 157 * @return {cc.Rect} 158 */ 159 getRect:function () { 160 var locRect = this._rect; 161 return cc.rect(locRect.x, locRect.y, locRect.width, locRect.height); 162 }, 163 164 /** 165 * Sets the rect of the sprite frame in the texture 166 * @param {cc.Rect} rect 167 */ 168 setRect:function (rect) { 169 if (!this._rect){ 170 this._rect = cc.rect(0,0,0,0); 171 } 172 this._rect.x = rect.x; 173 this._rect.y = rect.y; 174 this._rect.width = rect.width; 175 this._rect.height = rect.height; 176 this._rectInPixels = cc.rectPointsToPixels(this._rect); 177 }, 178 179 /** 180 * Returns the offset of the sprite frame in the texture in pixel 181 * @return {cc.Point} 182 */ 183 getOffsetInPixels:function () { 184 return cc.p(this._offsetInPixels); 185 }, 186 187 /** 188 * Sets the offset of the sprite frame in the texture in pixel 189 * @param {cc.Point} offsetInPixels 190 */ 191 setOffsetInPixels:function (offsetInPixels) { 192 this._offsetInPixels.x = offsetInPixels.x; 193 this._offsetInPixels.y = offsetInPixels.y; 194 cc._pointPixelsToPointsOut(this._offsetInPixels, this._offset); 195 }, 196 197 /** 198 * Returns the original size of the trimmed image 199 * @return {cc.Size} 200 */ 201 getOriginalSizeInPixels:function () { 202 return cc.size(this._originalSizeInPixels); 203 }, 204 205 /** 206 * Sets the original size of the trimmed image 207 * @param {cc.Size} sizeInPixels 208 */ 209 setOriginalSizeInPixels:function (sizeInPixels) { 210 this._originalSizeInPixels.width = sizeInPixels.width; 211 this._originalSizeInPixels.height = sizeInPixels.height; 212 }, 213 214 /** 215 * Returns the original size of the trimmed image 216 * @return {cc.Size} 217 */ 218 getOriginalSize:function () { 219 return cc.size(this._originalSize); 220 }, 221 222 /** 223 * Sets the original size of the trimmed image 224 * @param {cc.Size} sizeInPixels 225 */ 226 setOriginalSize:function (sizeInPixels) { 227 this._originalSize.width = sizeInPixels.width; 228 this._originalSize.height = sizeInPixels.height; 229 }, 230 231 /** 232 * Returns the texture of the frame 233 * @return {cc.Texture2D} 234 */ 235 getTexture:function () { 236 if (this._texture) 237 return this._texture; 238 if (this._textureFilename !== "") { 239 var locTexture = cc.textureCache.addImage(this._textureFilename); 240 if (locTexture) 241 this._textureLoaded = locTexture.isLoaded(); 242 return locTexture; 243 } 244 return null; 245 }, 246 247 /** 248 * Sets the texture of the frame, the texture is retained automatically 249 * @param {cc.Texture2D} texture 250 */ 251 setTexture:function (texture) { 252 if (this._texture != texture) { 253 var locLoaded = texture.isLoaded(); 254 this._textureLoaded = locLoaded; 255 this._texture = texture; 256 if(!locLoaded){ 257 texture.addLoadedEventListener(function(sender){ 258 this._textureLoaded = true; 259 if(this._rotated && cc._renderType === cc._RENDER_TYPE_CANVAS){ 260 var tempElement = sender.getHtmlElementObj(); 261 tempElement = cc.cutRotateImageToCanvas(tempElement, this.getRect()); 262 var tempTexture = new cc.Texture2D(); 263 tempTexture.initWithElement(tempElement); 264 tempTexture.handleLoadedTexture(); 265 this.setTexture(tempTexture); 266 267 var rect = this.getRect(); 268 this.setRect(cc.rect(0, 0, rect.width, rect.height)); 269 } 270 var locRect = this._rect; 271 if(locRect.width === 0 && locRect.height === 0){ 272 var w = sender.width, h = sender.height; 273 this._rect.width = w; 274 this._rect.height = h; 275 this._rectInPixels = cc.rectPointsToPixels(this._rect); 276 this._originalSizeInPixels.width = this._rectInPixels.width; 277 this._originalSizeInPixels.height = this._rectInPixels.height; 278 this._originalSize.width = w; 279 this._originalSize.height = h; 280 } 281 this._callLoadedEventCallbacks(); 282 }, this); 283 } 284 } 285 }, 286 287 /** 288 * Returns the offset of the frame in the texture 289 * @return {cc.Point} 290 */ 291 getOffset:function () { 292 return cc.p(this._offset); 293 }, 294 295 /** 296 * Sets the offset of the frame in the texture 297 * @param {cc.Point} offsets 298 */ 299 setOffset:function (offsets) { 300 this._offset.x = offsets.x; 301 this._offset.y = offsets.y; 302 }, 303 304 /** 305 * Clone the sprite frame 306 * @returns {SpriteFrame} 307 */ 308 clone: function(){ 309 var frame = new cc.SpriteFrame(); 310 frame.initWithTexture(this._textureFilename, this._rectInPixels, this._rotated, this._offsetInPixels, this._originalSizeInPixels); 311 frame.setTexture(this._texture); 312 return frame; 313 }, 314 315 /** 316 * Copy the sprite frame 317 * @return {cc.SpriteFrame} 318 */ 319 copyWithZone:function () { 320 var copy = new cc.SpriteFrame(); 321 copy.initWithTexture(this._textureFilename, this._rectInPixels, this._rotated, this._offsetInPixels, this._originalSizeInPixels); 322 copy.setTexture(this._texture); 323 return copy; 324 }, 325 326 /** 327 * Copy the sprite frame 328 * @returns {cc.SpriteFrame} 329 */ 330 copy:function () { 331 return this.copyWithZone(); 332 }, 333 334 /** 335 * Initializes SpriteFrame with Texture, rect, rotated, offset and originalSize in pixels.<br/> 336 * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. 337 * @param {String|cc.Texture2D} texture 338 * @param {cc.Rect} rect if parameters' length equal 2, rect in points, else rect in pixels 339 * @param {Boolean} [rotated=false] 340 * @param {cc.Point} [offset=cc.p(0,0)] 341 * @param {cc.Size} [originalSize=rect.size] 342 * @return {Boolean} 343 */ 344 initWithTexture:function (texture, rect, rotated, offset, originalSize) { 345 if(arguments.length === 2) 346 rect = cc.rectPointsToPixels(rect); 347 348 offset = offset || cc.p(0, 0); 349 originalSize = originalSize || rect; 350 rotated = rotated || false; 351 352 if (cc.isString(texture)){ 353 this._texture = null; 354 this._textureFilename = texture; 355 } else if (texture instanceof cc.Texture2D){ 356 this.setTexture(texture); 357 } 358 359 texture = this.getTexture(); 360 361 this._rectInPixels = rect; 362 rect = this._rect = cc.rectPixelsToPoints(rect); 363 364 if(texture && texture.url && texture.isLoaded()) { 365 var _x, _y; 366 if(rotated){ 367 _x = rect.x + rect.height; 368 _y = rect.y + rect.width; 369 }else{ 370 _x = rect.x + rect.width; 371 _y = rect.y + rect.height; 372 } 373 if(_x > texture.getPixelsWide()){ 374 cc.error(cc._LogInfos.RectWidth, texture.url); 375 } 376 if(_y > texture.getPixelsHigh()){ 377 cc.error(cc._LogInfos.RectHeight, texture.url); 378 } 379 } 380 381 this._offsetInPixels.x = offset.x; 382 this._offsetInPixels.y = offset.y; 383 cc._pointPixelsToPointsOut(offset, this._offset); 384 this._originalSizeInPixels.width = originalSize.width; 385 this._originalSizeInPixels.height = originalSize.height; 386 cc._sizePixelsToPointsOut(originalSize, this._originalSize); 387 this._rotated = rotated; 388 return true; 389 } 390 }); 391 392 /** 393 * <p> 394 * Create a cc.SpriteFrame with a texture filename, rect, rotated, offset and originalSize in pixels.<br/> 395 * The originalSize is the size in pixels of the frame before being trimmed. 396 * </p> 397 * @deprecated since v3.0, please use new construction instead 398 * @see cc.SpriteFrame 399 * @param {String|cc.Texture2D} filename 400 * @param {cc.Rect} rect if parameters' length equal 2, rect in points, else rect in pixels 401 * @param {Boolean} rotated 402 * @param {cc.Point} offset 403 * @param {cc.Size} originalSize 404 * @return {cc.SpriteFrame} 405 */ 406 cc.SpriteFrame.create = function (filename, rect, rotated, offset, originalSize) { 407 return new cc.SpriteFrame(filename,rect,rotated,offset,originalSize); 408 }; 409 410 /** 411 * @deprecated since v3.0, please use new construction instead 412 * @see cc.SpriteFrame 413 * @function 414 */ 415 cc.SpriteFrame.createWithTexture = cc.SpriteFrame.create; 416 417 cc.SpriteFrame._frameWithTextureForCanvas = function (texture, rect, rotated, offset, originalSize) { 418 var spriteFrame = new cc.SpriteFrame(); 419 spriteFrame._texture = texture; 420 spriteFrame._rectInPixels = rect; 421 spriteFrame._rect = cc.rectPixelsToPoints(rect); 422 spriteFrame._offsetInPixels.x = offset.x; 423 spriteFrame._offsetInPixels.y = offset.y; 424 cc._pointPixelsToPointsOut(spriteFrame._offsetInPixels, spriteFrame._offset); 425 spriteFrame._originalSizeInPixels.width = originalSize.width; 426 spriteFrame._originalSizeInPixels.height = originalSize.height; 427 cc._sizePixelsToPointsOut(spriteFrame._originalSizeInPixels, spriteFrame._originalSize); 428 spriteFrame._rotated = rotated; 429 return spriteFrame; 430 }; 431