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