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# */{  //WebGL only
 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         //TODO need re-binding
145         this._quads = quads;
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         cc.assert(texture, cc._LogInfos.TextureAtlas_initWithTexture);
260 
261         capacity = 0 | (capacity);
262         this._capacity = capacity;
263         this._totalQuads = 0;
264 
265         // retained in property
266         this.texture = texture;
267 
268         // Re-initialization is not allowed
269         this._quads = [];
270         this._indices = new Uint16Array(capacity * 6);
271         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
272         this._quadsArrayBuffer = new ArrayBuffer(quadSize * capacity);
273         this._quadsReader = new Uint8Array(this._quadsArrayBuffer);
274 
275         if (!( this._quads && this._indices) && capacity > 0)
276             return false;
277 
278         var locQuads = this._quads;
279         for (var i = 0; i < capacity; i++)
280             locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, i * quadSize);
281 
282         this._setupIndices();
283         this._setupVBO();
284         this.dirty = true;
285         return true;
286     },
287 
288     /**
289      * <p>Updates a Quad (texture, vertex and color) at a certain index <br />
290      * index must be between 0 and the atlas capacity - 1 </p>
291      * @param {cc.V3F_C4B_T2F_Quad} quad
292      * @param {Number} index
293      */
294     updateQuad: function (quad, index) {
295         cc.assert(quad, cc._LogInfos.TextureAtlas_updateQuad);
296         cc.assert(index >= 0 && index < this._capacity, cc._LogInfos.TextureAtlas_updateQuad_2);
297 
298         this._totalQuads = Math.max(index + 1, this._totalQuads);
299         this._setQuadToArray(quad, index);
300         this.dirty = true;
301     },
302 
303     /**
304      * <p>Inserts a Quad (texture, vertex and color) at a certain index<br />
305      * index must be between 0 and the atlas capacity - 1 </p>
306      * @param {cc.V3F_C4B_T2F_Quad} quad
307      * @param {Number} index
308      */
309     insertQuad: function (quad, index) {
310         cc.assert(index < this._capacity, cc._LogInfos.TextureAtlas_insertQuad_2);
311 
312         this._totalQuads++;
313         if (this._totalQuads > this._capacity) {
314             cc.log(cc._LogInfos.TextureAtlas_insertQuad);
315             return;
316         }
317         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
318         // issue #575. index can be > totalQuads
319         var remaining = (this._totalQuads - 1) - index;
320         var startOffset = index * quadSize;
321         var moveLength = remaining * quadSize;
322         this._quads[this._totalQuads - 1] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, (this._totalQuads - 1) * quadSize);
323         this._quadsReader.set(this._quadsReader.subarray(startOffset, startOffset + moveLength), startOffset + quadSize);
324 
325         this._setQuadToArray(quad, index);
326         this.dirty = true;
327     },
328 
329     /**
330      * <p>
331      *      Inserts a c array of quads at a given index                                           <br />
332      *      index must be between 0 and the atlas capacity - 1                                    <br />
333      *      this method doesn't enlarge the array when amount + index > totalQuads                <br />
334      * </p>
335      * @param {Array} quads
336      * @param {Number} index
337      * @param {Number} amount
338      */
339     insertQuads: function (quads, index, amount) {
340         amount = amount || quads.length;
341 
342         cc.assert((index + amount) <= this._capacity, cc._LogInfos.TextureAtlas_insertQuads);
343 
344         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
345         this._totalQuads += amount;
346         if (this._totalQuads > this._capacity) {
347             cc.log(cc._LogInfos.TextureAtlas_insertQuad);
348             return;
349         }
350 
351         // issue #575. index can be > totalQuads
352         var remaining = (this._totalQuads - 1) - index - amount;
353         var startOffset = index * quadSize;
354         var moveLength = remaining * quadSize;
355         var lastIndex = (this._totalQuads - 1) - amount;
356 
357         var i;
358         for (i = 0; i < amount; i++)
359             this._quads[lastIndex + i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, (this._totalQuads - 1) * quadSize);
360         this._quadsReader.set(this._quadsReader.subarray(startOffset, startOffset + moveLength), startOffset + quadSize * amount);
361         for (i = 0; i < amount; i++)
362             this._setQuadToArray(quads[i], index + i);
363 
364         this.dirty = true;
365     },
366 
367     /**
368      * <p>Removes the quad that is located at a certain index and inserts it at a new index <br />
369      * This operation is faster than removing and inserting in a quad in 2 different steps</p>
370      * @param {Number} fromIndex
371      * @param {Number} newIndex
372      */
373     insertQuadFromIndex: function (fromIndex, newIndex) {
374         if (fromIndex === newIndex)
375             return;
376 
377         cc.assert(newIndex >= 0 || newIndex < this._totalQuads, cc._LogInfos.TextureAtlas_insertQuadFromIndex);
378 
379         cc.assert(fromIndex >= 0 || fromIndex < this._totalQuads, cc._LogInfos.TextureAtlas_insertQuadFromIndex_2);
380 
381         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
382         var locQuadsReader = this._quadsReader;
383         var sourceArr = locQuadsReader.subarray(fromIndex * quadSize, quadSize);
384         var startOffset, moveLength;
385         if (fromIndex > newIndex) {
386             startOffset = newIndex * quadSize;
387             moveLength = (fromIndex - newIndex) * quadSize;
388             locQuadsReader.set(locQuadsReader.subarray(startOffset, startOffset + moveLength), startOffset + quadSize);
389             locQuadsReader.set(sourceArr, startOffset);
390         } else {
391             startOffset = (fromIndex + 1) * quadSize;
392             moveLength = (newIndex - fromIndex) * quadSize;
393             locQuadsReader.set(locQuadsReader.subarray(startOffset, startOffset + moveLength), startOffset - quadSize);
394             locQuadsReader.set(sourceArr, newIndex * quadSize);
395         }
396         this.dirty = true;
397     },
398 
399     /**
400      * <p>Removes a quad at a given index number.<br />
401      * The capacity remains the same, but the total number of quads to be drawn is reduced in 1 </p>
402      * @param {Number} index
403      */
404     removeQuadAtIndex: function (index) {
405         cc.assert(index < this._totalQuads, cc._LogInfos.TextureAtlas_removeQuadAtIndex);
406 
407         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
408         this._totalQuads--;
409         this._quads.length = this._totalQuads;
410         if (index !== this._totalQuads) {
411             //move data
412             var startOffset = (index + 1) * quadSize;
413             var moveLength = (this._totalQuads - index) * quadSize;
414             this._quadsReader.set(this._quadsReader.subarray(startOffset, startOffset + moveLength), startOffset - quadSize);
415         }
416         this.dirty = true;
417     },
418 
419     /**
420      * Removes a given number of quads at a given index
421      * @param {Number} index
422      * @param {Number} amount
423      */
424     removeQuadsAtIndex: function (index, amount) {
425         cc.assert(index + amount <= this._totalQuads, cc._LogInfos.TextureAtlas_removeQuadsAtIndex);
426 
427         this._totalQuads -= amount;
428 
429         if (index !== this._totalQuads) {
430             //move data
431             var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
432             var srcOffset = (index + amount) * quadSize;
433             var moveLength = (this._totalQuads - index) * quadSize;
434             var dstOffset = index * quadSize;
435             this._quadsReader.set(this._quadsReader.subarray(srcOffset, srcOffset + moveLength), dstOffset);
436         }
437         this.dirty = true;
438     },
439 
440     /**
441      * <p>Removes all Quads. <br />
442      * The TextureAtlas capacity remains untouched. No memory is freed.<br />
443      * The total number of quads to be drawn will be 0</p>
444      */
445     removeAllQuads: function () {
446         this._quads.length = 0;
447         this._totalQuads = 0;
448     },
449 
450     _setDirty: function (dirty) {
451         this.dirty = dirty;
452     },
453 
454     /**
455      * <p>Resize the capacity of the CCTextureAtlas.<br />
456      * The new capacity can be lower or higher than the current one<br />
457      * It returns YES if the resize was successful. <br />
458      * If it fails to resize the capacity it will return NO with a new capacity of 0. <br />
459      * no used for js</p>
460      * @param {Number} newCapacity
461      * @return {Boolean}
462      */
463     resizeCapacity: function (newCapacity) {
464         if (newCapacity === this._capacity)
465             return true;
466 
467         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
468         var oldCapacity = this._capacity;
469         // update capacity and totolQuads
470         this._totalQuads = Math.min(this._totalQuads, newCapacity);
471         this._capacity = 0 | newCapacity;
472         var i, capacity = this._capacity, locTotalQuads = this._totalQuads;
473 
474         if (this._quads === null) {
475             this._quads = [];
476             this._quadsArrayBuffer = new ArrayBuffer(quadSize * capacity);
477             this._quadsReader = new Uint8Array(this._quadsArrayBuffer);
478             for (i = 0; i < capacity; i++)
479                 this._quads = new cc.V3F_C4B_T2F_Quad(null, null, null, null, this._quadsArrayBuffer, i * quadSize);
480         } else {
481             var newQuads, newArrayBuffer, quads = this._quads;
482             if (capacity > oldCapacity) {
483                 newQuads = [];
484                 newArrayBuffer = new ArrayBuffer(quadSize * capacity);
485                 for (i = 0; i < locTotalQuads; i++) {
486                     newQuads[i] = new cc.V3F_C4B_T2F_Quad(quads[i].tl, quads[i].bl, quads[i].tr, quads[i].br,
487                         newArrayBuffer, i * quadSize);
488                 }
489                 for (; i < capacity; i++)
490                     newQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, newArrayBuffer, i * quadSize);
491 
492                 this._quadsReader = new Uint8Array(newArrayBuffer);
493                 this._quads = newQuads;
494                 this._quadsArrayBuffer = newArrayBuffer;
495             } else {
496                 var count = Math.max(locTotalQuads, capacity);
497                 newQuads = [];
498                 newArrayBuffer = new ArrayBuffer(quadSize * capacity);
499                 for (i = 0; i < count; i++) {
500                     newQuads[i] = new cc.V3F_C4B_T2F_Quad(quads[i].tl, quads[i].bl, quads[i].tr, quads[i].br,
501                         newArrayBuffer, i * quadSize);
502                 }
503                 this._quadsReader = new Uint8Array(newArrayBuffer);
504                 this._quads = newQuads;
505                 this._quadsArrayBuffer = newArrayBuffer;
506             }
507         }
508 
509         if (this._indices === null) {
510             this._indices = new Uint16Array(capacity * 6);
511         } else {
512             if (capacity > oldCapacity) {
513                 var tempIndices = new Uint16Array(capacity * 6);
514                 tempIndices.set(this._indices, 0);
515                 this._indices = tempIndices;
516             } else {
517                 this._indices = this._indices.subarray(0, capacity * 6);
518             }
519         }
520 
521         this._setupIndices();
522         this._mapBuffers();
523         this.dirty = true;
524         return true;
525     },
526 
527     /**
528      * Used internally by CCParticleBatchNode                                    <br/>
529      * don't use this unless you know what you're doing
530      * @param {Number} amount
531      */
532     increaseTotalQuadsWith: function (amount) {
533         this._totalQuads += amount;
534     },
535 
536     /**
537      * Moves an amount of quads from oldIndex at newIndex
538      * @param {Number} oldIndex
539      * @param {Number} amount
540      * @param {Number} newIndex
541      */
542     moveQuadsFromIndex: function (oldIndex, amount, newIndex) {
543         if (newIndex === undefined) {
544             newIndex = amount;
545             amount = this._totalQuads - oldIndex;
546 
547             cc.assert((newIndex + (this._totalQuads - oldIndex)) <= this._capacity, cc._LogInfos.TextureAtlas_moveQuadsFromIndex);
548 
549             if (amount === 0)
550                 return;
551         } else {
552             cc.assert((newIndex + amount) <= this._totalQuads, cc._LogInfos.TextureAtlas_moveQuadsFromIndex_2);
553             cc.assert(oldIndex < this._totalQuads, cc._LogInfos.TextureAtlas_moveQuadsFromIndex_3);
554 
555             if (oldIndex === newIndex)
556                 return;
557         }
558 
559         var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
560         var srcOffset = oldIndex * quadSize;
561         var srcLength = amount * quadSize;
562         var locQuadsReader = this._quadsReader;
563         var sourceArr = locQuadsReader.subarray(srcOffset, srcOffset + srcLength);
564         var dstOffset = newIndex * quadSize;
565         var moveLength, moveStart;
566         if (newIndex < oldIndex) {
567             moveLength = (oldIndex - newIndex) * quadSize;
568             moveStart = newIndex * quadSize;
569             locQuadsReader.set(locQuadsReader.subarray(moveStart, moveStart + moveLength), moveStart + srcLength)
570         } else {
571             moveLength = (newIndex - oldIndex) * quadSize;
572             moveStart = (oldIndex + amount) * quadSize;
573             locQuadsReader.set(locQuadsReader.subarray(moveStart, moveStart + moveLength), srcOffset);
574         }
575         locQuadsReader.set(sourceArr, dstOffset);
576         this.dirty = true;
577     },
578 
579     /**
580      * Ensures that after a realloc quads are still empty                                <br/>
581      * Used internally by CCParticleBatchNode
582      * @param {Number} index
583      * @param {Number} amount
584      */
585     fillWithEmptyQuadsFromIndex: function (index, amount) {
586         var count = amount * cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT;
587         var clearReader = new Uint8Array(this._quadsArrayBuffer, index * cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT, count);
588         for (var i = 0; i < count; i++)
589             clearReader[i] = 0;
590     },
591 
592     // TextureAtlas - Drawing
593 
594     /**
595      * Draws all the Atlas's Quads
596      */
597     drawQuads: function () {
598         this.drawNumberOfQuads(this._totalQuads, 0);
599     },
600 
601     _releaseBuffer: function () {
602         var gl = cc._renderContext;
603         if (this._buffersVBO) {
604             if (this._buffersVBO[0])
605                 gl.deleteBuffer(this._buffersVBO[0]);
606             if (this._buffersVBO[1])
607                 gl.deleteBuffer(this._buffersVBO[1])
608         }
609         if (this._quadsWebBuffer)
610             gl.deleteBuffer(this._quadsWebBuffer);
611     }
612 });
613 
614 var _p = cc.TextureAtlas.prototype;
615 
616 // Extended properties
617 /** @expose */
618 _p.totalQuads;
619 cc.defineGetterSetter(_p, "totalQuads", _p.getTotalQuads);
620 /** @expose */
621 _p.capacity;
622 cc.defineGetterSetter(_p, "capacity", _p.getCapacity);
623 /** @expose */
624 _p.quads;
625 cc.defineGetterSetter(_p, "quads", _p.getQuads, _p.setQuads);
626 
627 /**
628  * <p>Creates a TextureAtlas with an filename and with an initial capacity for Quads. <br />
629  * The TextureAtlas capacity can be increased in runtime. </p>
630  * @deprecated since v3.0, please use new cc.TextureAtlas(fileName, capacity) instead
631  * @param {String|cc.Texture2D} fileName
632  * @param {Number} capacity
633  * @return {cc.TextureAtlas|Null}
634  */
635 cc.TextureAtlas.create = function (fileName, capacity) {
636     return new cc.TextureAtlas(fileName, capacity);
637 };
638 
639 /**
640  * @deprecated  since v3.0, please use new cc.TextureAtlas(texture) instead
641  * @function
642  */
643 cc.TextureAtlas.createWithTexture = cc.TextureAtlas.create;
644 
645 if (cc._renderType === cc._RENDER_TYPE_WEBGL) {
646     cc.assert(cc.isFunction(cc._tmp.WebGLTextureAtlas), cc._LogInfos.MissingFile, "TexturesWebGL.js");
647     cc._tmp.WebGLTextureAtlas();
648     delete cc._tmp.WebGLTextureAtlas;
649 }
650 
651 cc.assert(cc.isFunction(cc._tmp.PrototypeTextureAtlas), cc._LogInfos.MissingFile, "TexturesPropertyDefine.js");
652 cc._tmp.PrototypeTextureAtlas();
653 delete cc._tmp.PrototypeTextureAtlas;