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>A class that implements a Texture Atlas. <br />
 29  * Supported features: <br />
 30  * The atlas file can be a PNG, JPG. <br />
 31  * Quads can be updated in runtime <br />
 32  * Quads can be added in runtime <br />
 33  * Quads can be removed in runtime <br />
 34  * Quads can be re-ordered in runtime <br />
 35  * The TextureAtlas capacity can be increased or decreased in runtime.</p>
 36  * @class
 37  * @extends cc.Class
 38  *
 39  * @property {Boolean}  dirty           - Indicates whether or not the array buffer of the VBO needs to be updated.
 40  * @property {Image}    texture         - Image texture for cc.TextureAtlas.
 41  * @property {Number}   capacity        - <@readonly> Quantity of quads that can be stored with the current texture atlas size.
 42  * @property {Number}   totalQuads      - <@readonly> Quantity of quads that are going to be drawn.
 43  * @property {Array}    quads           - <@readonly> Quads that are going to be rendered
 44  */
 45 cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{
 46     dirty: false,
 47     texture: null,
 48 
 49     _indices: null,
 50     //0: vertex  1: indices
 51     _buffersVBO: null,
 52     _capacity: 0,
 53 
 54     _quads: null,
 55     _quadsArrayBuffer: null,
 56     _quadsWebBuffer: null,
 57     _quadsReader: null,
 58 
 59     /**
 60      * <p>Creates a TextureAtlas with an filename and with an initial capacity for Quads. <br />
 61      * The TextureAtlas capacity can be increased in runtime. </p>
 62      * Constructor of cc.TextureAtlas
 63      * @param {String|cc.Texture2D} fileName
 64      * @param {Number} capacity
 65      * @example
 66      * 1.
 67      * //creates a TextureAtlas with  filename
 68      * var textureAtlas = new cc.TextureAtlas("res/hello.png", 3);
 69      * 2.
 70      * //creates a TextureAtlas with texture
 71      * var texture = cc.textureCache.addImage("hello.png");
 72      * var textureAtlas = new cc.TextureAtlas(texture, 3);
 73      */
 74     ctor: function (fileName, capacity) {
 75         this._buffersVBO = [];
 76 
 77         if (typeof(fileName) == "string") {
 78             this.initWithFile(fileName, capacity);
 79         }
 80         else if (fileName instanceof cc.Texture2D) {
 81             this.initWithTexture(fileName, capacity);
 82         }
 83     },
 84 
 85     /**
 86      * Quantity of quads that are going to be drawn.
 87      * @return {Number}
 88      */
 89     getTotalQuads: function () {
 90         //return this._quads.length;
 91         return this._totalQuads;
 92     },
 93 
 94     /**
 95      * Quantity of quads that can be stored with the current texture atlas size
 96      * @return {Number}
 97      */
 98     getCapacity: function () {
 99         return this._capacity;
100     },
101 
102     /**
103      * Texture of the texture atlas
104      * @return {Image}
105      */
106     getTexture: function () {
107         return this.texture;
108     },
109 
110     /**
111      * @param {Image} texture
112      */
113     setTexture: function (texture) {
114         this.texture = texture;
115     },
116 
117     /**
118      * specify if the array buffer of the VBO needs to be updated
119      * @param {Boolean} dirty
120      */
121     setDirty: function (dirty) {
122         this.dirty = dirty;
123     },
124 
125     /**
126      * whether or not the array buffer of the VBO needs to be updated
127      * @returns {boolean}
128      */
129     isDirty: function () {
130         return this.dirty;
131     },
132 
133     /**
134      * Quads that are going to be rendered
135      * @return {Array}
136      */
137     getQuads: function () {
138         return this._quads;
139     },
140 
141     /**
142      * @param {Array} quads
143      */
144     setQuads: function (quads) {
145         this._quads = quads;
146         //TODO need re-binding
147     },
148 
149     _copyQuadsToTextureAtlas: function (quads, index) {
150         if (!quads)
151             return;
152 
153         for (var i = 0; i < quads.length; i++)
154             this._setQuadToArray(quads[i], index + i);
155     },
156 
157     _setQuadToArray: function (quad, index) {
158         var locQuads = this._quads;
159         if (!locQuads[index]) {
160             locQuads[index] = new cc.V3F_C4B_T2F_Quad(quad.tl, quad.bl, quad.tr, quad.br, this._quadsArrayBuffer, index * cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT);
161             return;
162         }
163         locQuads[index].bl = quad.bl;
164         locQuads[index].br = quad.br;
165         locQuads[index].tl = quad.tl;
166         locQuads[index].tr = quad.tr;
167     },
168 
169     /**
170      * Description
171      * @return {String}
172      */
173     description: function () {
174         return '<cc.TextureAtlas | totalQuads =' + this._totalQuads + '>';
175     },
176 
177     _setupIndices: function () {
178         if (this._capacity === 0)
179             return;
180         var locIndices = this._indices, locCapacity = this._capacity;
181         for (var i = 0; i < locCapacity; i++) {
182             if (cc.TEXTURE_ATLAS_USE_TRIANGLE_STRIP) {
183                 locIndices[i * 6 + 0] = i * 4 + 0;
184                 locIndices[i * 6 + 1] = i * 4 + 0;
185                 locIndices[i * 6 + 2] = i * 4 + 2;
186                 locIndices[i * 6 + 3] = i * 4 + 1;
187                 locIndices[i * 6 + 4] = i * 4 + 3;
188                 locIndices[i * 6 + 5] = i * 4 + 3;
189             } else {
190                 locIndices[i * 6 + 0] = i * 4 + 0;
191                 locIndices[i * 6 + 1] = i * 4 + 1;
192                 locIndices[i * 6 + 2] = i * 4 + 2;
193 
194                 // inverted index. issue #179
195                 locIndices[i * 6 + 3] = i * 4 + 3;
196                 locIndices[i * 6 + 4] = i * 4 + 2;
197                 locIndices[i * 6 + 5] = i * 4 + 1;
198             }
199         }
200     },
201 
202     _setupVBO: function () {
203         var gl = cc._renderContext;
204         //create WebGLBuffer
205         this._buffersVBO[0] = gl.createBuffer();
206         this._buffersVBO[1] = gl.createBuffer();
207 
208         this._quadsWebBuffer = gl.createBuffer();
209         this._mapBuffers();
210     },
211 
212     _mapBuffers: function () {
213         var gl = cc._renderContext;
214 
215         gl.bindBuffer(gl.ARRAY_BUFFER, this._quadsWebBuffer);
216         gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW);
217 
218         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]);
219         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
220     },
221 
222     /**
223      * <p>Initializes a TextureAtlas with a filename and with a certain capacity for Quads.<br />
224      * The TextureAtlas capacity can be increased in runtime.<br />
225      * WARNING: Do not reinitialize the TextureAtlas because it will leak memory. </p>
226      * @param {String} file
227      * @param {Number} capacity
228      * @return {Boolean}
229      * @example
230      * //example
231      * var textureAtlas = new cc.TextureAtlas();
232      * textureAtlas.initWithTexture("hello.png", 3);
233      */
234     initWithFile: function (file, capacity) {
235         // retained in property
236         var texture = cc.textureCache.addImage(file);
237         if (texture)
238             return this.initWithTexture(texture, capacity);
239         else {
240             cc.log(cc._LogInfos.TextureAtlas_initWithFile, file);
241             return false;
242         }
243     },
244 
245     /**
246      * <p>Initializes a TextureAtlas with a previously initialized Texture2D object, and<br />
247      * with an initial capacity for Quads.<br />
248      * The TextureAtlas capacity can be increased in runtime.<br />
249      * WARNING: Do not reinitialize the TextureAtlas because it will leak memory</p>
250      * @param {Image} texture
251      * @param {Number} capacity
252      * @return {Boolean}
253      * @example
254      * //example
255      * var texture = cc.textureCache.addImage("hello.png");
256      * var textureAtlas = new cc.TextureAtlas();
257      * textureAtlas.initWithTexture(texture, 3);
258      */
259     initWithTexture: function (texture, capacity) {
260 
261         cc.assert(texture, cc._LogInfos.TextureAtlas_initWithTexture);
262 
263         capacity = 0 | (capacity);
264         this._capacity = capacity;
265         this._totalQuads = 0;
266 
267         // retained in property
268         this.texture = texture;
269 
270         // Re-initialization is not allowed
271         this._quads = [];
272         this._indices = new Uint16Array(capacity * 6);
273         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
274         this._quadsArrayBuffer = new ArrayBuffer(quadSize * capacity);
275         this._quadsReader = new Uint8Array(this._quadsArrayBuffer);
276 
277         if (!( this._quads && this._indices) && capacity > 0)
278             return false;
279 
280         var locQuads = this._quads;
281         for (var i = 0; i < capacity; i++)
282             locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, i * quadSize);
283 
284         this._setupIndices();
285         this._setupVBO();
286         this.dirty = true;
287         return true;
288     },
289 
290     /**
291      * <p>Updates a Quad (texture, vertex and color) at a certain index <br />
292      * index must be between 0 and the atlas capacity - 1 </p>
293      * @param {cc.V3F_C4B_T2F_Quad} quad
294      * @param {Number} index
295      */
296     updateQuad: function (quad, index) {
297 
298         cc.assert(quad, cc._LogInfos.TextureAtlas_updateQuad);
299 
300         cc.assert(index >= 0 && index < this._capacity, cc._LogInfos.TextureAtlas_updateQuad_2);
301 
302         this._totalQuads = Math.max(index + 1, this._totalQuads);
303         this._setQuadToArray(quad, index);
304         this.dirty = true;
305     },
306 
307     /**
308      * <p>Inserts a Quad (texture, vertex and color) at a certain index<br />
309      * index must be between 0 and the atlas capacity - 1 </p>
310      * @param {cc.V3F_C4B_T2F_Quad} quad
311      * @param {Number} index
312      */
313     insertQuad: function (quad, index) {
314 
315         cc.assert(index < this._capacity, cc._LogInfos.TextureAtlas_insertQuad_2);
316 
317         this._totalQuads++;
318         if (this._totalQuads > this._capacity) {
319             cc.log(cc._LogInfos.TextureAtlas_insertQuad);
320             return;
321         }
322         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
323         // issue #575. index can be > totalQuads
324         var remaining = (this._totalQuads - 1) - index;
325         var startOffset = index * quadSize;
326         var moveLength = remaining * quadSize;
327         this._quads[this._totalQuads - 1] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, (this._totalQuads - 1) * quadSize);
328         this._quadsReader.set(this._quadsReader.subarray(startOffset, startOffset + moveLength), startOffset + quadSize);
329 
330         this._setQuadToArray(quad, index);
331         this.dirty = true;
332     },
333 
334     /**
335      * <p>
336      *      Inserts a c array of quads at a given index                                           <br />
337      *      index must be between 0 and the atlas capacity - 1                                    <br />
338      *      this method doesn't enlarge the array when amount + index > totalQuads                <br />
339      * </p>
340      * @param {Array} quads
341      * @param {Number} index
342      * @param {Number} amount
343      */
344     insertQuads: function (quads, index, amount) {
345         amount = amount || quads.length;
346 
347         cc.assert((index + amount) <= this._capacity, cc._LogInfos.TextureAtlas_insertQuads);
348 
349         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
350         this._totalQuads += amount;
351         if (this._totalQuads > this._capacity) {
352             cc.log(cc._LogInfos.TextureAtlas_insertQuad);
353             return;
354         }
355 
356         // issue #575. index can be > totalQuads
357         var remaining = (this._totalQuads - 1) - index - amount;
358         var startOffset = index * quadSize;
359         var moveLength = remaining * quadSize;
360         var lastIndex = (this._totalQuads - 1) - amount;
361 
362         var i;
363         for (i = 0; i < amount; i++)
364             this._quads[lastIndex + i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, (this._totalQuads - 1) * quadSize);
365         this._quadsReader.set(this._quadsReader.subarray(startOffset, startOffset + moveLength), startOffset + quadSize * amount);
366         for (i = 0; i < amount; i++)
367             this._setQuadToArray(quads[i], index + i);
368 
369         this.dirty = true;
370     },
371 
372     /**
373      * <p>Removes the quad that is located at a certain index and inserts it at a new index <br />
374      * This operation is faster than removing and inserting in a quad in 2 different steps</p>
375      * @param {Number} fromIndex
376      * @param {Number} newIndex
377      */
378     insertQuadFromIndex: function (fromIndex, newIndex) {
379         if (fromIndex === newIndex)
380             return;
381 
382         cc.assert(newIndex >= 0 || newIndex < this._totalQuads, cc._LogInfos.TextureAtlas_insertQuadFromIndex);
383 
384         cc.assert(fromIndex >= 0 || fromIndex < this._totalQuads, cc._LogInfos.TextureAtlas_insertQuadFromIndex_2);
385 
386         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
387         var locQuadsReader = this._quadsReader;
388         var sourceArr = locQuadsReader.subarray(fromIndex * quadSize, quadSize);
389         var startOffset, moveLength;
390         if (fromIndex > newIndex) {
391             startOffset = newIndex * quadSize;
392             moveLength = (fromIndex - newIndex) * quadSize;
393             locQuadsReader.set(locQuadsReader.subarray(startOffset, startOffset + moveLength), startOffset + quadSize);
394             locQuadsReader.set(sourceArr, startOffset);
395         } else {
396             startOffset = (fromIndex + 1) * quadSize;
397             moveLength = (newIndex - fromIndex) * quadSize;
398             locQuadsReader.set(locQuadsReader.subarray(startOffset, startOffset + moveLength), startOffset - quadSize);
399             locQuadsReader.set(sourceArr, newIndex * quadSize);
400         }
401         this.dirty = true;
402     },
403 
404     /**
405      * <p>Removes a quad at a given index number.<br />
406      * The capacity remains the same, but the total number of quads to be drawn is reduced in 1 </p>
407      * @param {Number} index
408      */
409     removeQuadAtIndex: function (index) {
410 
411         cc.assert(index < this._totalQuads, cc._LogInfos.TextureAtlas_removeQuadAtIndex);
412 
413         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
414         this._totalQuads--;
415         this._quads.length = this._totalQuads;
416         if (index !== this._totalQuads) {
417             //move data
418             var startOffset = (index + 1) * quadSize;
419             var moveLength = (this._totalQuads - index) * quadSize;
420             this._quadsReader.set(this._quadsReader.subarray(startOffset, startOffset + moveLength), startOffset - quadSize);
421         }
422         this.dirty = true;
423     },
424 
425     /**
426      * Removes a given number of quads at a given index
427      * @param {Number} index
428      * @param {Number} amount
429      */
430     removeQuadsAtIndex: function (index, amount) {
431 
432         cc.assert(index + amount <= this._totalQuads, cc._LogInfos.TextureAtlas_removeQuadsAtIndex);
433 
434         this._totalQuads -= amount;
435 
436         if (index !== this._totalQuads) {
437             //move data
438             var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
439             var srcOffset = (index + amount) * quadSize;
440             var moveLength = (this._totalQuads - index) * quadSize;
441             var dstOffset = index * quadSize;
442             this._quadsReader.set(this._quadsReader.subarray(srcOffset, srcOffset + moveLength), dstOffset);
443         }
444         this.dirty = true;
445     },
446 
447     /**
448      * <p>Removes all Quads. <br />
449      * The TextureAtlas capacity remains untouched. No memory is freed.<br />
450      * The total number of quads to be drawn will be 0</p>
451      */
452     removeAllQuads: function () {
453         this._quads.length = 0;
454         this._totalQuads = 0;
455     },
456 
457     _setDirty: function (dirty) {
458         this.dirty = dirty;
459     },
460 
461     /**
462      * <p>Resize the capacity of the CCTextureAtlas.<br />
463      * The new capacity can be lower or higher than the current one<br />
464      * It returns YES if the resize was successful. <br />
465      * If it fails to resize the capacity it will return NO with a new capacity of 0. <br />
466      * no used for js</p>
467      * @param {Number} newCapacity
468      * @return {Boolean}
469      */
470     resizeCapacity: function (newCapacity) {
471         if (newCapacity == this._capacity)
472             return true;
473 
474         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
475         var oldCapacity = this._capacity;
476         // update capacity and totolQuads
477         this._totalQuads = Math.min(this._totalQuads, newCapacity);
478         this._capacity = 0 | newCapacity;
479         var i, capacity = this._capacity, locTotalQuads = this._totalQuads;
480 
481         if (this._quads == null) {
482             this._quads = [];
483             this._quadsArrayBuffer = new ArrayBuffer(quadSize * capacity);
484             this._quadsReader = new Uint8Array(this._quadsArrayBuffer);
485             for (i = 0; i < capacity; i++)
486                 this._quads = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, i * quadSize);
487         } else {
488             var newQuads, newArrayBuffer, quads = this._quads;
489             if (capacity > oldCapacity) {
490                 newQuads = [];
491                 newArrayBuffer = new ArrayBuffer(quadSize * capacity);
492                 for (i = 0; i < locTotalQuads; i++) {
493                     newQuads[i] = new cc.V3F_C4B_T2F_Quad(quads[i].tl, quads[i].bl, quads[i].tr, quads[i].br,
494                         newArrayBuffer, i * quadSize);
495                 }
496                 for (; i < capacity; i++)
497                     newQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, newArrayBuffer, i * quadSize);
498 
499                 this._quadsReader = new Uint8Array(newArrayBuffer);
500                 this._quads = newQuads;
501                 this._quadsArrayBuffer = newArrayBuffer;
502             } else {
503                 var count = Math.max(locTotalQuads, capacity);
504                 newQuads = [];
505                 newArrayBuffer = new ArrayBuffer(quadSize * capacity);
506                 for (i = 0; i < count; i++) {
507                     newQuads[i] = new cc.V3F_C4B_T2F_Quad(quads[i].tl, quads[i].bl, quads[i].tr, quads[i].br,
508                         newArrayBuffer, i * quadSize);
509                 }
510                 this._quadsReader = new Uint8Array(newArrayBuffer);
511                 this._quads = newQuads;
512                 this._quadsArrayBuffer = newArrayBuffer;
513             }
514         }
515 
516         if (this._indices == null) {
517             this._indices = new Uint16Array(capacity * 6);
518         } else {
519             if (capacity > oldCapacity) {
520                 var tempIndices = new Uint16Array(capacity * 6);
521                 tempIndices.set(this._indices, 0);
522                 this._indices = tempIndices;
523             } else {
524                 this._indices = this._indices.subarray(0, capacity * 6);
525             }
526         }
527 
528         this._setupIndices();
529         this._mapBuffers();
530         this.dirty = true;
531         return true;
532     },
533 
534     /**
535      * Used internally by CCParticleBatchNode                                    <br/>
536      * don't use this unless you know what you're doing
537      * @param {Number} amount
538      */
539     increaseTotalQuadsWith: function (amount) {
540         this._totalQuads += amount;
541     },
542 
543     /**
544      * Moves an amount of quads from oldIndex at newIndex
545      * @param {Number} oldIndex
546      * @param {Number} amount
547      * @param {Number} newIndex
548      */
549     moveQuadsFromIndex: function (oldIndex, amount, newIndex) {
550         if (newIndex === undefined) {
551             newIndex = amount;
552             amount = this._totalQuads - oldIndex;
553 
554             cc.assert((newIndex + (this._totalQuads - oldIndex)) <= this._capacity, cc._LogInfos.TextureAtlas_moveQuadsFromIndex);
555 
556             if (amount === 0)
557                 return;
558         } else {
559 
560             cc.assert((newIndex + amount) <= this._totalQuads, cc._LogInfos.TextureAtlas_moveQuadsFromIndex_2);
561 
562             cc.assert(oldIndex < this._totalQuads, cc._LogInfos.TextureAtlas_moveQuadsFromIndex_3);
563 
564             if (oldIndex == newIndex)
565                 return;
566         }
567 
568         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
569         var srcOffset = oldIndex * quadSize;
570         var srcLength = amount * quadSize;
571         var locQuadsReader = this._quadsReader;
572         var sourceArr = locQuadsReader.subarray(srcOffset, srcOffset + srcLength);
573         var dstOffset = newIndex * quadSize;
574         var moveLength, moveStart;
575         if (newIndex < oldIndex) {
576             moveLength = (oldIndex - newIndex) * quadSize;
577             moveStart = newIndex * quadSize;
578             locQuadsReader.set(locQuadsReader.subarray(moveStart, moveStart + moveLength), moveStart + srcLength)
579         } else {
580             moveLength = (newIndex - oldIndex) * quadSize;
581             moveStart = (oldIndex + amount) * quadSize;
582             locQuadsReader.set(locQuadsReader.subarray(moveStart, moveStart + moveLength), srcOffset);
583         }
584         locQuadsReader.set(sourceArr, dstOffset);
585         this.dirty = true;
586     },
587 
588     /**
589      * Ensures that after a realloc quads are still empty                                <br/>
590      * Used internally by CCParticleBatchNode
591      * @param {Number} index
592      * @param {Number} amount
593      */
594     fillWithEmptyQuadsFromIndex: function (index, amount) {
595         var count = amount * cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
596         var clearReader = new Uint8Array(this._quadsArrayBuffer, index * cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT, count);
597         for (var i = 0; i < count; i++)
598             clearReader[i] = 0;
599     },
600 
601     // TextureAtlas - Drawing
602 
603     /**
604      * Draws all the Atlas's Quads
605      */
606     drawQuads: function () {
607         this.drawNumberOfQuads(this._totalQuads, 0);
608     },
609 
610     _releaseBuffer: function () {
611         var gl = cc._renderContext;
612         if (this._buffersVBO) {
613             if (this._buffersVBO[0])
614                 gl.deleteBuffer(this._buffersVBO[0]);
615             if (this._buffersVBO[1])
616                 gl.deleteBuffer(this._buffersVBO[1])
617         }
618         if (this._quadsWebBuffer)
619             gl.deleteBuffer(this._quadsWebBuffer);
620     }
621 });
622 
623 var _p = cc.TextureAtlas.prototype;
624 
625 // Extended properties
626 /** @expose */
627 _p.totalQuads;
628 cc.defineGetterSetter(_p, "totalQuads", _p.getTotalQuads);
629 /** @expose */
630 _p.capacity;
631 cc.defineGetterSetter(_p, "capacity", _p.getCapacity);
632 /** @expose */
633 _p.quads;
634 cc.defineGetterSetter(_p, "quads", _p.getQuads, _p.setQuads);
635 
636 /**
637  * <p>Creates a TextureAtlas with an filename and with an initial capacity for Quads. <br />
638  * The TextureAtlas capacity can be increased in runtime. </p>
639  * @deprecated since v3.0, please use new cc.TextureAtlas(fileName, capacity) instead
640  * @param {String|cc.Texture2D} fileName
641  * @param {Number} capacity
642  * @return {cc.TextureAtlas|Null}
643  * @example
644  * 1.
645  * //creates a TextureAtlas with  filename
646  * var textureAtlas = cc.TextureAtlas.create("res/hello.png", 3);
647  * 2.
648  * //creates a TextureAtlas with texture
649  * var texture = cc.textureCache.addImage("hello.png");
650  * var textureAtlas = cc.TextureAtlas.create(texture, 3);
651  */
652 cc.TextureAtlas.create = function (fileName, capacity) {
653     return new cc.TextureAtlas(fileName, capacity);
654 };
655 
656 /**
657  * @deprecated  since v3.0, please use new cc.TextureAtlas(texture) instead
658  * @function
659  */
660 cc.TextureAtlas.createWithTexture = cc.TextureAtlas.create;
661 
662 if (cc._renderType === cc._RENDER_TYPE_WEBGL) {
663     cc.assert(typeof cc._tmp.WebGLTextureAtlas === "function", cc._LogInfos.MissingFile, "TexturesWebGL.js");
664     cc._tmp.WebGLTextureAtlas();
665     delete cc._tmp.WebGLTextureAtlas;
666 }
667 
668 cc.assert(typeof cc._tmp.PrototypeTextureAtlas === "function", cc._LogInfos.MissingFile, "TexturesPropertyDefine.js");
669 cc._tmp.PrototypeTextureAtlas();
670 delete cc._tmp.PrototypeTextureAtlas;