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 /**
 29  * <p>A class that implements a Texture Atlas. <br />
 30  * Supported features: <br />
 31  * The atlas file can be a PNG, JPG. <br />
 32  * Quads can be updated in runtime <br />
 33  * Quads can be added in runtime <br />
 34  * Quads can be removed in runtime <br />
 35  * Quads can be re-ordered in runtime <br />
 36  * The TextureAtlas capacity can be increased or decreased in runtime.</p>
 37  * @class
 38  * @extends cc.Class
 39  */
 40 cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{
 41     _indices:[],
 42     //0: vertex  1: indices
 43     _buffersVBO:[0, 1],
 44     //indicates whether or not the array buffer of the VBO needs to be updated
 45     _dirty:false,
 46     _capacity:0,
 47     _texture:null,
 48     _quads:[],
 49     /**
 50      * Quantity of quads that are going to be drawn.
 51      * @return {Number}
 52      */
 53     getTotalQuads:function () {
 54         return this._quads.length;
 55     },
 56 
 57     /**
 58      * Quantity of quads that can be stored with the current texture atlas size
 59      * @return {Number}
 60      */
 61     getCapacity:function () {
 62         return this._capacity;
 63     },
 64 
 65     /**
 66      * Texture of the texture atlas
 67      * @return {Image}
 68      */
 69     getTexture:function () {
 70         return this._texture;
 71     },
 72 
 73     /**
 74      * @param {Image} texture
 75      */
 76     setTexture:function (texture) {
 77         this._texture = texture;
 78     },
 79 
 80     /**
 81      * Quads that are going to be rendered
 82      * @return {Array}
 83      */
 84     getQuads:function () {
 85         return this._quads;
 86     },
 87 
 88     /**
 89      * @param {Array} quads
 90      */
 91     setQuads:function (quads) {
 92         this._quads = quads;
 93     },
 94 
 95     /**
 96      * Description
 97      * @return {String}
 98      */
 99     description:function () {
100         return '<CCTextureAtlas | totalQuads =' + this._totalQuads + '>';
101     },
102     _initIndices:function () {
103         if (this._capacity == 0)
104             return;
105 
106         for (var i = 0; i < this._capacity; i++) {
107             this._indices[i * 6 + 0] = i * 4 + 0;
108             this._indices[i * 6 + 1] = i * 4 + 0;
109             this._indices[i * 6 + 2] = i * 4 + 2;
110             this._indices[i * 6 + 3] = i * 4 + 1;
111             this._indices[i * 6 + 4] = i * 4 + 3;
112             this._indices[i * 6 + 5] = i * 4 + 3;
113         }
114     },
115 
116     /**
117      * <p>Initializes a TextureAtlas with a filename and with a certain capacity for Quads.<br />
118      * The TextureAtlas capacity can be increased in runtime.<br />
119      * WARNING: Do not reinitialize the TextureAtlas because it will leak memory. </p>
120      * @param {String} file
121      * @param {Number} capacity
122      * @return {Boolean|Null}
123      * @example
124      * //example
125      * var textureAtlas = new cc.TextureAtlas();
126      * textureAtlas.initWithTexture("hello.png", 3);
127      */
128     initWithFile:function (file, capacity) {
129         // retained in property
130         var texture = cc.TextureCache.getInstance().addImage(file);
131 
132         if (texture) {
133             return this.initWithTexture(texture, capacity);
134         } else {
135             cc.log("cocos2d: Could not open file: " + file);
136             return null;
137         }
138     },
139 
140     /**
141      * <p>Initializes a TextureAtlas with a previously initialized Texture2D object, and<br />
142      * with an initial capacity for Quads.<br />
143      * The TextureAtlas capacity can be increased in runtime.<br />
144      * WARNING: Do not reinitialize the TextureAtlas because it will leak memory</p>
145      * @param {Image} texture
146      * @param {Number} capacity
147      * @return {Boolean}
148      * @example
149      * //example
150      * var texture = cc.TextureCache.getInstance().addImage("hello.png");
151      * var textureAtlas = new cc.TextureAtlas();
152      * textureAtlas.initWithTexture(texture, 3);
153      */
154     initWithTexture:function (texture, capacity) {
155         cc.Assert(texture != null, "TextureAtlas.initWithTexture():texture should not be null");
156         this._capacity = capacity;
157 
158         // retained in property
159         this._texture = texture;
160 
161         // Re-initialization is not allowed
162         cc.Assert(this._quads.length == 0 && this._indices.length == 0, "TextureAtlas.initWithTexture():_quads and _indices should not be null");
163 
164         //TODO init array
165         this._quads = [];
166         this._indices = [];
167 
168         if (!( this._quads && this._indices) && this._capacity > 0) {
169             return false;
170         }
171 
172         this._dirty = true;
173         this._initIndices();
174         return true;
175     },
176 
177     /**
178      * <p>Updates a Quad (texture, vertex and color) at a certain index <br />
179      * index must be between 0 and the atlas capacity - 1 </p>
180      * @param {cc.V2F_C4B_T2F_Quad} quad
181      * @param {Number} index
182      */
183     updateQuad:function (quad, index) {
184         this._quads[index] = quad;
185         this._dirty = true;
186     },
187 
188     /**
189      * <p>Inserts a Quad (texture, vertex and color) at a certain index<br />
190      * index must be between 0 and the atlas capacity - 1 </p>
191      * @param {cc.V2F_C4B_T2F_Quad} quad
192      * @param {Number} index
193      */
194     insertQuad:function (quad, index) {
195         this._quads = cc.ArrayAppendObjectToIndex(this._quads, quad, index);
196         this._dirty = true;
197     },
198 
199     /**
200      * <p>Removes the quad that is located at a certain index and inserts it at a new index <br />
201      * This operation is faster than removing and inserting in a quad in 2 different steps</p>
202      * @param {Number} fromIndex
203      * @param {Number} newIndex
204      */
205     insertQuadFromIndex:function (fromIndex, newIndex) {
206         if (fromIndex == newIndex)
207             return;
208 
209         var quad = this._quads[fromIndex];
210         cc.ArrayRemoveObjectAtIndex(this._quads, fromIndex);
211         if (fromIndex > newIndex) {
212             this._quads = cc.ArrayAppendObjectToIndex(this._quads, quad, newIndex);
213         } else {
214             this._quads = cc.ArrayAppendObjectToIndex(this._quads, quad, newIndex - 1);
215         }
216 
217         this._dirty = true;
218     },
219 
220     /**
221      * <p>Removes a quad at a given index number.<br />
222      * The capacity remains the same, but the total number of quads to be drawn is reduced in 1 </p>
223      * @param {Number} index
224      */
225     removeQuadAtIndex:function (index) {
226         cc.ArrayRemoveObjectAtIndex(this._quads, index);
227 
228         this._dirty = true;
229     },
230 
231     /**
232      * <p>Removes all Quads. <br />
233      * The TextureAtlas capacity remains untouched. No memory is freed.<br />
234      * The total number of quads to be drawn will be 0</p>
235      */
236     removeAllQuads:function () {
237         this._quads.length = 0;
238     },
239 
240     /**
241      * <p>Resize the capacity of the CCTextureAtlas.<br />
242      * The new capacity can be lower or higher than the current one<br />
243      * It returns YES if the resize was successful. <br />
244      * If it fails to resize the capacity it will return NO with a new capacity of 0. <br />
245      * no used for js</p>
246      * @param {Number} newCapacity
247      * @return {Boolean}
248      */
249     resizeCapacity:function (newCapacity) {
250         if (newCapacity == this._capacity) {
251             return true;
252         }
253 
254         this._totalQuads = Math.min(this._totalQuads, newCapacity);
255         this._capacity = newCapacity;
256 
257         return true;
258     },
259 
260     /**
261      * <p>Draws n quads from an index (offset). <br />
262      * n + start can't be greater than the capacity of the atlas</p>
263      * @param {Number} n
264      * @param {Number} start
265      */
266     drawNumberOfQuads:function (n, start) {
267         if (0 == n)
268             return;
269     },
270     /**
271      * Draws all the Atlas's Quads
272      */
273     drawQuads:function () {
274         this.drawNumberOfQuads(this._quads.length, 0);
275     }
276 });
277 
278 /**
279  * <p>Creates a TextureAtlas with an filename and with an initial capacity for Quads. <br />
280  * The TextureAtlas capacity can be increased in runtime. </p>
281  * @param {String} file
282  * @param {Number} capacity
283  * @return {cc.TextureAtlas|Null}
284  * @example
285  * //example
286  * var textureAtlas = cc.TextureAtlas.create("hello.png", 3);
287  */
288 cc.TextureAtlas.create = function (file, capacity) {
289     var textureAtlas = new cc.TextureAtlas();
290     if (textureAtlas && textureAtlas.initWithFile(file, capacity)) {
291         return textureAtlas;
292     }
293     return null;
294 };
295 
296 /**
297  * <p>Creates a TextureAtlas with a previously initialized Texture2D object, and with an initial capacity for n Quads.
298  * The TextureAtlas capacity can be increased in runtime.</p>
299  * @param {Image} texture
300  * @param {Number} capacity
301  * @return {cc.TextureAtlas}
302  * @example
303  * //example
304  * var texture = cc.TextureCache.getInstance().addImage("hello.png");
305  * var textureAtlas = cc.TextureAtlas.createWithTexture(texture, 3);
306  */
307 cc.TextureAtlas.createWithTexture = function (texture, capacity) {
308     var textureAtlas = new cc.TextureAtlas();
309     if (textureAtlas && textureAtlas.initWithTexture(texture, capacity)) {
310         return textureAtlas;
311     }
312     return null;
313 };
314