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  * <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  * @example
 39  * var texture = cc.TextureCache.getInstance().addImage(s_dragon_animation);
 40  * var frame0 = cc.SpriteFrame.createWithTexture(texture, cc.rect(132 * 0, 132 * 0, 132, 132));
 41  */
 42 cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{
 43     _offset:null,
 44     _originalSize:null,
 45     _rectInPixels:null,
 46     _rotated:false,
 47     _rect:null,
 48     _offsetInPixels:null,
 49     _originalSizeInPixels:null,
 50     _texture:null,
 51     _textureFilename:"",
 52     _textureLoaded:false,
 53     _eventListeners:null,
 54 
 55     ctor:function () {
 56         this._offset = cc.p(0, 0);
 57         this._offsetInPixels = cc.p(0, 0);
 58         this._originalSize = cc.size(0, 0);
 59         this._rectInPixels = cc.rect(0, 0, 0, 0);
 60         this._rotated = false;
 61         this._rect = cc.rect(0, 0, 0, 0);
 62         this._originalSizeInPixels = cc.size(0, 0);
 63         this._textureFilename = "";
 64         this._texture = null;
 65         this._textureLoaded = false;
 66         this._eventListeners = [];
 67     },
 68 
 69     // attributes
 70     textureLoaded:function(){
 71         return this._textureLoaded;
 72     },
 73 
 74     addLoadedEventListener:function(callback, target){
 75         this._eventListeners.push({eventCallback:callback, eventTarget:target});
 76     },
 77 
 78     _callLoadedEventCallbacks:function(){
 79         var locListeners = this._eventListeners;
 80         for(var i = 0, len = locListeners.length;  i < len; i++){
 81             var selCallback = locListeners[i];
 82             selCallback.eventCallback.call(selCallback.eventTarget, this);
 83         }
 84         locListeners.length = 0;
 85     },
 86 
 87     /**
 88      * @return {cc.Rect}
 89      */
 90     getRectInPixels:function () {
 91         return this._rectInPixels;
 92     },
 93 
 94     /**
 95      * @param {cc.Rect} rectInPixels
 96      */
 97     setRectInPixels:function (rectInPixels) {
 98         this._rectInPixels = rectInPixels;
 99         this._rect = cc.RECT_PIXELS_TO_POINTS(rectInPixels);
100     },
101 
102     /**
103      * <p>
104      *     return is rotated of SpriteFrame. <br/>
105      * </p>
106      * @return {Boolean}
107      */
108     isRotated:function () {
109         return this._rotated;
110     },
111 
112     /**
113      * set SpriteFrame is rotated
114      * @param {Boolean} bRotated
115      */
116     setRotated:function (bRotated) {
117         this._rotated = bRotated;
118     },
119 
120     /**
121      * get rect of the frame
122      * @return {cc.Rect}
123      */
124     getRect:function () {
125         return this._rect;
126     },
127 
128     /**
129      * set rect of the frame
130      * @param {cc.Rect} rect
131      */
132     setRect:function (rect) {
133         this._rect = rect;
134         this._rectInPixels = cc.RECT_POINTS_TO_PIXELS(this._rect);
135     },
136 
137     /**
138      * get offset of the frame
139      * @return {cc.Point}
140      */
141     getOffsetInPixels:function () {
142         return cc.p(this._offsetInPixels.x, this._offsetInPixels.y);
143     },
144 
145     /**
146      * set offset of the frame
147      * @param {cc.Point} offsetInPixels
148      */
149     setOffsetInPixels:function (offsetInPixels) {
150         this._offsetInPixels = offsetInPixels;
151         this._offset = cc.POINT_PIXELS_TO_POINTS(this._offsetInPixels);
152     },
153 
154     /**
155      * get original size of the trimmed image
156      * @const
157      * @return {cc.Size}
158      */
159     getOriginalSizeInPixels:function () {
160         return this._originalSizeInPixels;
161     },
162 
163     /**
164      * set original size of the trimmed image
165      * @param {cc.Size} sizeInPixels
166      */
167     setOriginalSizeInPixels:function (sizeInPixels) {
168         this._originalSizeInPixels = sizeInPixels;
169     },
170 
171     /**
172      * get original size of the trimmed image
173      * @const
174      * @return {cc.Size}
175      */
176     getOriginalSize:function () {
177         return cc.size(this._originalSize.width, this._originalSize.height);
178     },
179 
180     /**
181      * set original size of the trimmed image
182      * @param {cc.Size} sizeInPixels
183      */
184     setOriginalSize:function (sizeInPixels) {
185         this._originalSize = sizeInPixels;
186     },
187 
188     /**
189      * get texture of the frame
190      * @return {cc.Texture2D}
191      */
192     getTexture:function () {
193         if (this._texture)
194             return this._texture;
195         if (this._textureFilename !== "") {
196             var locTexture = cc.TextureCache.getInstance().addImage(this._textureFilename);
197             if (locTexture)
198                 this._textureLoaded = locTexture.isLoaded();
199             return locTexture;
200         }
201         return null;
202     },
203 
204     /**
205      * set texture of the frame, the texture is retained
206      * @param {cc.Texture2D} texture
207      */
208     setTexture:function (texture) {
209         if (this._texture != texture) {
210             var locLoaded = texture.isLoaded();
211             this._textureLoaded = locLoaded;
212             this._texture = texture;
213             if(!locLoaded){
214                 texture.addLoadedEventListener(function(sender){
215                     this._textureLoaded = true;
216                     if(this._rotated){
217                         var tempElement = sender.getHtmlElementObj();
218                         tempElement = cc.cutRotateImageToCanvas(tempElement, this.getRect());
219                         var tempTexture = new cc.Texture2D();
220                         tempTexture.initWithElement(tempElement);
221                         tempTexture.handleLoadedTexture();
222                         this.setTexture(tempTexture);
223 
224                         var rect = this.getRect();
225                         this.setRect(cc.rect(0, 0, rect.width, rect.height));
226                     }
227                     var locRect = this._rect;
228                     if(locRect.width === 0 && locRect.height === 0){
229                         var locContentSize = sender.getContentSize();
230                         this._rect.width = locContentSize.width;
231                         this._rect.height = locContentSize.height;
232                         this._rectInPixels = cc.RECT_POINTS_TO_PIXELS(this._rect);
233                         this._originalSizeInPixels.width = this._rectInPixels.width;
234                         this._originalSizeInPixels.height = this._rectInPixels.height;
235                         this._originalSize.width =  locContentSize.width;
236                         this._originalSize.height =  locContentSize.height;
237                     }
238                     this._callLoadedEventCallbacks();
239                 }, this);
240             }
241         }
242     },
243 
244     /**
245      * Offset getter
246      * @const
247      * @return {cc.Point}
248      */
249     getOffset:function () {
250         return cc.p(this._offset.x, this._offset.y);
251     },
252 
253     /**
254      * offset setter
255      * @param {cc.Point} offsets
256      */
257     setOffset:function (offsets) {
258         this._offset.x = offsets.x;
259         this._offset.y = offsets.y;
260     },
261 
262     clone: function(){
263         var frame = new cc.SpriteFrame();
264         frame.initWithTextureFilename(this._textureFilename, this._rectInPixels, this._rotated, this._offsetInPixels, this._originalSizeInPixels);
265         frame.setTexture(this._texture);
266         return frame;
267     },
268 
269     /**
270      * copy a new SpriteFrame
271      * @return {cc.SpriteFrame}
272      */
273     copyWithZone:function () {
274         var copy = new cc.SpriteFrame();
275         copy.initWithTextureFilename(this._textureFilename, this._rectInPixels, this._rotated, this._offsetInPixels, this._originalSizeInPixels);
276         copy.setTexture(this._texture);
277         return copy;
278     },
279 
280     copy:function () {
281         return this.copyWithZone();
282     },
283 
284     /**
285      * Initializes SpriteFrame with Texture, rect, rotated, offset and originalSize in pixels.
286      * @param {cc.Texture2D|HTMLImageElement} texture
287      * @param {cc.Rect} rect
288      * @param {Boolean} [rotated=false]
289      * @param {cc.Point} [offset=cc.size(0,0)]
290      * @param {cc.Size} [originalSize=rect.size]
291      * @return {Boolean}
292      */
293     initWithTexture:function (texture, rect, rotated, offset, originalSize) {
294         rotated = rotated || false;
295         offset = offset || cc.size(0, 0);
296         originalSize = originalSize || rect.size;
297 
298         this.setTexture(texture);
299         this._rectInPixels = rect;
300         this._rect = cc.RECT_PIXELS_TO_POINTS(rect);
301         this._offsetInPixels = offset;
302         this._offset = cc.POINT_PIXELS_TO_POINTS(offset);
303         this._originalSizeInPixels = originalSize;
304         this._originalSize = cc.SIZE_PIXELS_TO_POINTS(originalSize);
305         this._rotated = rotated;
306         return true;
307     },
308 
309     /**
310      * <p>
311      *    Initializes a cc.SpriteFrame with a texture, rect, rotated, offset and originalSize in pixels.<br/>
312      *    The originalSize is the size in pixels of the frame before being trimmed.
313      * </p>
314      * @param {string} filename
315      * @param {cc.Rect} rect
316      * @param {Boolean} rotated
317      * @param {cc.Point} [offset=cc.size(0,0)]
318      * @param {cc.Size} [originalSize=rect.size]
319      */
320     initWithTextureFilename:function (filename, rect, rotated, offset, originalSize) {
321         offset = offset || cc.size(0, 0);
322         originalSize = originalSize || rect.size;
323 
324         this._texture = null;
325         this._textureFilename = filename;
326         this._rectInPixels = rect;
327         this._rect = cc.RECT_PIXELS_TO_POINTS(rect);
328         this._rotated = rotated || false;
329         this._offsetInPixels = offset;
330         this._offset = cc.POINT_PIXELS_TO_POINTS(offset);
331         this._originalSizeInPixels = originalSize;
332         this._originalSize = cc.SIZE_PIXELS_TO_POINTS(originalSize);
333 
334         return true;
335     }
336 });
337 
338 /**
339  * <p>
340  *    Create a cc.SpriteFrame with a texture filename, rect, rotated, offset and originalSize in pixels.<br/>
341  *    The originalSize is the size in pixels of the frame before being trimmed.
342  * </p>
343  * @param {string} filename
344  * @param {cc.Rect} rect
345  * @param {Boolean} rotated
346  * @param {cc.Point} offset
347  * @param {cc.Size} originalSize
348  * @return {cc.SpriteFrame}
349  */
350 cc.SpriteFrame.create = function (filename, rect, rotated, offset, originalSize) {
351     var spriteFrame = new cc.SpriteFrame();
352     switch (arguments.length) {
353         case 2:
354             spriteFrame.initWithTextureFilename(filename, rect);
355             break;
356         case 5:
357             spriteFrame.initWithTextureFilename(filename, rect, rotated, offset, originalSize);
358             break;
359         default:
360             throw "Argument must be non-nil ";
361             break;
362     }
363     return spriteFrame;
364 };
365 
366 /**
367  * Create a cc.SpriteFrame with a texture, rect, rotated, offset and originalSize in pixels.
368  * @param {cc.Texture2D} texture
369  * @param {cc.Rect} rect
370  * @param {Boolean} [rotated=]
371  * @param {cc.Point} [offset=]
372  * @param {cc.Size} [originalSize=]
373  * @return {cc.SpriteFrame}
374  * @example
375  * //Create a cc.SpriteFrame with a texture, rect in texture.
376  * var frame1 = cc.SpriteFrame.createWithTexture("grossini_dance.png",cc.rect(0,0,90,128));
377  *
378  * //Create a cc.SpriteFrame with a texture, rect, rotated, offset and originalSize in pixels.
379  * var frame2 = cc.SpriteFrame.createWithTexture(texture, frameRect, rotated, offset, sourceSize);
380  */
381 cc.SpriteFrame.createWithTexture = function (texture, rect, rotated, offset, originalSize) {
382     var spriteFrame = new cc.SpriteFrame();
383     spriteFrame.initWithTexture(texture, rect, rotated, offset, originalSize);
384     return spriteFrame;
385 };
386 
387 cc.SpriteFrame._frameWithTextureForCanvas = function (texture, rect, rotated, offset, originalSize) {
388     var spriteFrame = new cc.SpriteFrame();
389     spriteFrame._texture = texture;
390     spriteFrame._rectInPixels = rect;
391     spriteFrame._rect = cc.RECT_PIXELS_TO_POINTS(rect);
392     spriteFrame._offsetInPixels = offset;
393     spriteFrame._offset = cc.POINT_PIXELS_TO_POINTS(spriteFrame._offsetInPixels);
394     spriteFrame._originalSizeInPixels = originalSize;
395     spriteFrame._originalSize = cc.SIZE_PIXELS_TO_POINTS(spriteFrame._originalSizeInPixels);
396     spriteFrame._rotated = rotated;
397     return spriteFrame;
398 };
399