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  Copyright (c) 2009      On-Core
  6 
  7  http://www.cocos2d-x.org
  8 
  9  Permission is hereby granted, free of charge, to any person obtaining a copy
 10  of this software and associated documentation files (the "Software"), to deal
 11  in the Software without restriction, including without limitation the rights
 12  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 13  copies of the Software, and to permit persons to whom the Software is
 14  furnished to do so, subject to the following conditions:
 15 
 16  The above copyright notice and this permission notice shall be included in
 17  all copies or substantial portions of the Software.
 18 
 19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 24  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 25  THE SOFTWARE.
 26  ****************************************************************************/
 27 
 28 /**
 29  * Base class for cc.Grid
 30  * @class
 31  * @extends cc.Class
 32  */
 33 cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{
 34     _active:false,
 35     _reuseGrid:0,
 36     _gridSize:null,
 37     _texture:null,
 38     _step:null,
 39     _grabber:null,
 40     _isTextureFlipped:false,
 41     _shaderProgram:null,
 42     _directorProjection:0,
 43 
 44     _dirty:false,
 45 
 46     /**
 47      * create one cc.GridBase Object
 48      * Constructor of cc.GridBase
 49      * @param {cc.Size} gridSize
 50      * @param {cc.Texture2D} [texture=]
 51      * @param {Boolean} [flipped=]
 52      */
 53     ctor:function (gridSize, texture, flipped) {
 54         cc._checkWebGLRenderMode();
 55         this._active=false;
 56         this._reuseGrid=0;
 57         this._gridSize=null;
 58         this._texture=null;
 59         this._step = cc.p(0, 0);
 60         this._grabber=null;
 61         this._isTextureFlipped=false;
 62         this._shaderProgram=null;
 63         this._directorProjection=0;
 64         this._dirty=false;
 65 
 66         if(gridSize !== undefined)
 67             this.initWithSize(gridSize, texture, flipped);
 68     },
 69 
 70     /**
 71      * whether or not the grid is active
 72      * @return {Boolean}
 73      */
 74     isActive:function () {
 75         return this._active;
 76     },
 77 
 78     /**
 79      * whether or not the grid is active
 80      * @param {Number} active
 81      */
 82     setActive:function (active) {
 83         this._active = active;
 84         if (!active) {
 85             var director = cc.director;
 86             var proj = director.getProjection();
 87             director.setProjection(proj);
 88         }
 89     },
 90 
 91     /**
 92      * get number of times that the grid will be reused
 93      * @return {Number}
 94      */
 95     getReuseGrid:function () {
 96         return this._reuseGrid;
 97     },
 98     /**
 99      * set number of times that the grid will be reused
100      * @param reuseGrid
101      */
102     setReuseGrid:function (reuseGrid) {
103         this._reuseGrid = reuseGrid;
104     },
105 
106     /**
107      * get size of the grid
108      * @return {cc.Size}
109      */
110     getGridSize:function () {
111         return cc.size(this._gridSize.width, this._gridSize.height);
112     },
113 
114     /**
115      * set size of the grid
116      * @param {cc.Size} gridSize
117      */
118     setGridSize:function (gridSize) {
119         this._gridSize.width = parseInt(gridSize.width);
120         this._gridSize.height = parseInt(gridSize.height);
121     },
122 
123     /**
124      * get pixels between the grids
125      * @return {cc.Point}
126      */
127     getStep:function () {
128         return cc.p(this._step.x, this._step.y);
129     },
130 
131     /**
132      * set pixels between the grids
133      * @param {cc.Point} step
134      */
135     setStep:function (step) {
136         this._step.x = step.x;
137         this._step.y = step.y;
138     },
139 
140     /**
141      * get wheter or not the texture is flipped
142      * @return {Boolean}
143      */
144     isTextureFlipped:function () {
145         return this._isTextureFlipped;
146     },
147 
148     /**
149      * set wheter or not the texture is flipped
150      * @param {Boolean} flipped
151      */
152     setTextureFlipped:function (flipped) {
153         if (this._isTextureFlipped != flipped) {
154             this._isTextureFlipped = flipped;
155             this.calculateVertexPoints();
156         }
157     },
158 
159     /**
160      *
161      * @param {cc.Size} gridSize
162      * @param {cc.Texture2D} [texture=]
163      * @param {Boolean} [flipped=false]
164      * @returns {boolean}
165      */
166     initWithSize:function (gridSize, texture, flipped) {
167         if (!texture) {
168             var director = cc.director;
169             var winSize = director.getWinSizeInPixels();
170 
171             var POTWide = cc.NextPOT(winSize.width);
172             var POTHigh = cc.NextPOT(winSize.height);
173 
174             var data = new Uint8Array(POTWide * POTHigh * 4);
175             if (!data) {
176                 cc.log("cocos2d: CCGrid: not enough memory.");
177                 return false;
178             }
179 
180             texture = new cc.Texture2D();
181             // we only use rgba8888
182             texture.initWithData(data, cc.Texture2D.PIXEL_FORMAT_RGBA8888, POTWide, POTHigh, winSize);
183             if (!texture) {
184                 cc.log("cocos2d: CCGrid: error creating texture");
185                 return false;
186             }
187         }
188 
189         flipped = flipped || false;
190 
191         this._active = false;
192         this._reuseGrid = 0;
193         this._gridSize = gridSize;
194         this._texture = texture;
195         this._isTextureFlipped = flipped;
196 
197         this._step.x = this._texture.width / gridSize.width;
198         this._step.y = this._texture.height / gridSize.height;
199 
200         this._grabber = new cc.Grabber();
201         if (!this._grabber)
202             return false;
203         this._grabber.grab(this._texture);
204         this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURE);
205         this.calculateVertexPoints();
206         return true;
207     },
208 
209     beforeDraw:function () {
210         // save projection
211         this._directorProjection = cc.director.getProjection();
212 
213         // 2d projection
214         //    [director setProjection:kCCDirectorProjection2D];
215         this.set2DProjection();
216         this._grabber.beforeRender(this._texture);
217     },
218 
219     afterDraw:function (target) {
220         this._grabber.afterRender(this._texture);
221 
222         // restore projection
223         cc.director.setProjection(this._directorProjection);
224 
225         if (target.getCamera().isDirty()) {
226             var offset = target.getAnchorPointInPoints();
227 
228             //
229             // XXX: Camera should be applied in the AnchorPoint
230             //
231             cc.kmGLTranslatef(offset.x, offset.y, 0);
232             target.getCamera().locate();
233             cc.kmGLTranslatef(-offset.x, -offset.y, 0);
234         }
235 
236         cc.glBindTexture2D(this._texture);
237 
238         // restore projection for default FBO .fixed bug #543 #544
239         //TODO:         CCDirector::sharedDirector().setProjection(CCDirector::sharedDirector().getProjection());
240         //TODO:         CCDirector::sharedDirector().applyOrientation();
241         this.blit();
242     },
243 
244     blit:function () {
245         cc.log("cc.GridBase.blit(): Shall be overridden in subclass.");
246     },
247 
248     reuse:function () {
249         cc.log("cc.GridBase.reuse(): Shall be overridden in subclass.");
250     },
251 
252     calculateVertexPoints:function () {
253         cc.log("cc.GridBase.calculateVertexPoints(): Shall be overridden in subclass.");
254     },
255 
256     set2DProjection:function () {
257         var winSize = cc.director.getWinSizeInPixels();
258 
259         var gl = cc._renderContext;
260         gl.viewport(0, 0, winSize.width , winSize.height);
261         cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
262         cc.kmGLLoadIdentity();
263 
264         var orthoMatrix = new cc.kmMat4();
265         cc.kmMat4OrthographicProjection(orthoMatrix, 0, winSize.width, 0, winSize.height, -1, 1);
266         cc.kmGLMultMatrix(orthoMatrix);
267 
268         cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
269         cc.kmGLLoadIdentity();
270         cc.setProjectionMatrixDirty()
271     }
272 });
273 
274 /**
275  * create one cc.GridBase Object
276  * @param {cc.Size} gridSize
277  * @param {cc.Texture2D} [texture=]
278  * @param {Boolean} [flipped=]
279  * @return {cc.GridBase}
280  */
281 cc.GridBase.create = function (gridSize, texture, flipped) {
282     return new cc.GridBase(gridSize, texture, flipped);
283 };
284 
285 /**
286  * cc.Grid3D is a 3D grid implementation. Each vertex has 3 dimensions: x,y,z
287  * @class
288  * @extends cc.GridBase
289  */
290 cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{
291     _texCoordinates:null,
292     _vertices:null,
293     _originalVertices:null,
294     _indices:null,
295 
296     _texCoordinateBuffer:null,
297     _verticesBuffer:null,
298     _indicesBuffer:null,
299 
300     /**
301      * create one Grid3D object
302      * Constructor of cc.Grid3D
303      * @param {cc.Size} gridSize
304      * @param {cc.Texture2D} [texture=]
305      * @param {Boolean} [flipped=]
306      */
307     ctor:function (gridSize, texture, flipped) {
308         cc.GridBase.prototype.ctor.call(this);
309         this._texCoordinates=null;
310         this._vertices=null;
311         this._originalVertices=null;
312         this._indices=null;
313 
314         this._texCoordinateBuffer=null;
315         this._verticesBuffer=null;
316         this._indicesBuffer=null;
317 
318         if(gridSize !== undefined)
319             this.initWithSize(gridSize, texture, flipped);
320     },
321 
322     /**
323      * returns the vertex at a given position
324      * @param {cc.Point} pos
325      * @return {cc.Vertex3F}
326      */
327     vertex:function (pos) {
328         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
329             cc.log("cc.Grid3D.vertex() : Numbers must be integers");
330         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
331         var locVertices = this._vertices;
332         return new cc.Vertex3F(locVertices[index], locVertices[index + 1], locVertices[index + 2]);
333     },
334 
335     /**
336      * returns the original (non-transformed) vertex at a given position
337      * @param {cc.Point} pos
338      * @return {cc.Vertex3F}
339      */
340     originalVertex:function (pos) {
341         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
342             cc.log("cc.Grid3D.originalVertex() : Numbers must be integers");
343         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
344         var locOriginalVertices = this._originalVertices;
345         return new cc.Vertex3F(locOriginalVertices[index], locOriginalVertices[index + 1], locOriginalVertices[index + 2]);
346     },
347 
348     /**
349      * sets a new vertex at a given position
350      * @param {cc.Point} pos
351      * @param {cc.Vertex3F} vertex
352      */
353     setVertex:function (pos, vertex) {
354         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
355             cc.log("cc.Grid3D.setVertex() : Numbers must be integers");
356         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
357         var vertArray = this._vertices;
358         vertArray[index] = vertex.x;
359         vertArray[index + 1] = vertex.y;
360         vertArray[index + 2] = vertex.z;
361         this._dirty = true;
362     },
363 
364     blit:function () {
365         var n = this._gridSize.width * this._gridSize.height;
366         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_TEX_COORDS);
367         this._shaderProgram.use();
368         this._shaderProgram.setUniformsForBuiltins();
369 
370         var gl = cc._renderContext, locDirty = this._dirty;
371         //
372         // Attributes
373         //
374         // position
375         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
376         if (locDirty)
377             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
378         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, 0);
379 
380         // texCoords
381         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
382         if (locDirty)
383             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
384         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, 0);
385 
386         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
387         if (locDirty)
388             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
389         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
390         if (locDirty)
391             this._dirty = false;
392         cc.incrementGLDraws(1);
393     },
394 
395     reuse:function () {
396         if (this._reuseGrid > 0) {
397             var locOriginalVertices = this._originalVertices, locVertices = this._vertices;
398             for (var i = 0, len =  this._vertices.length; i < len; i++)
399                 locOriginalVertices[i] = locVertices[i];
400             --this._reuseGrid;
401         }
402     },
403 
404     calculateVertexPoints:function () {
405         var gl = cc._renderContext;
406 
407         var width = this._texture.pixelsWidth;
408         var height = this._texture.pixelsHeight;
409         var imageH = this._texture.getContentSizeInPixels().height;
410         var locGridSize = this._gridSize;
411 
412         var numOfPoints = (locGridSize.width + 1) * (locGridSize.height + 1);
413         this._vertices = new Float32Array(numOfPoints * 3);
414         this._texCoordinates = new Float32Array(numOfPoints * 2);
415         this._indices = new Uint16Array(locGridSize.width * locGridSize.height * 6);
416 
417         if(this._verticesBuffer)
418             gl.deleteBuffer(this._verticesBuffer);
419         this._verticesBuffer = gl.createBuffer();
420         if(this._texCoordinateBuffer)
421             gl.deleteBuffer(this._texCoordinateBuffer);
422         this._texCoordinateBuffer = gl.createBuffer();
423         if(this._indicesBuffer)
424             gl.deleteBuffer(this._indicesBuffer);
425         this._indicesBuffer = gl.createBuffer();
426 
427         var x, y, i, locIndices = this._indices, locTexCoordinates = this._texCoordinates;
428         var locIsTextureFlipped = this._isTextureFlipped, locVertices = this._vertices;
429         for (x = 0; x < locGridSize.width; ++x) {
430             for (y = 0; y < locGridSize.height; ++y) {
431                 var idx = (y * locGridSize.width) + x;
432                 var x1 = x * this._step.x;
433                 var x2 = x1 + this._step.x;
434                 var y1 = y * this._step.y;
435                 var y2 = y1 + this._step.y;
436 
437                 var a = (x * (locGridSize.height + 1) + y);
438                 var b = ((x + 1) * (locGridSize.height + 1) + y);
439                 var c = ((x + 1) * (locGridSize.height + 1) + (y + 1));
440                 var d = (x * (locGridSize.height + 1) + (y + 1));
441 
442                 locIndices[idx * 6] = a;
443                 locIndices[idx * 6 + 1] = b;
444                 locIndices[idx * 6 + 2] = d;
445                 locIndices[idx * 6 + 3] = b;
446                 locIndices[idx * 6 + 4] = c;
447                 locIndices[idx * 6 + 5] = d;
448 
449                 var l1 = [a * 3, b * 3, c * 3, d * 3];
450                 var e = {x:x1, y:y1, z:0};   //new cc.Vertex3F(x1, y1, 0);
451                 var f = {x:x2, y:y1, z:0};   //new cc.Vertex3F(x2, y1, 0);
452                 var g = {x:x2, y:y2, z:0};   // new cc.Vertex3F(x2, y2, 0);
453                 var h = {x:x1, y:y2, z:0};   //new cc.Vertex3F(x1, y2, 0);
454 
455                 var l2 = [e, f, g, h];
456                 var tex1 = [a * 2, b * 2, c * 2, d * 2];
457                 var tex2 = [cc.p(x1, y1), cc.p(x2, y1), cc.p(x2, y2), cc.p(x1, y2)];
458                 for (i = 0; i < 4; ++i) {
459                     locVertices[l1[i]] = l2[i].x;
460                     locVertices[l1[i] + 1] = l2[i].y;
461                     locVertices[l1[i] + 2] = l2[i].z;
462                     locTexCoordinates[tex1[i]] = tex2[i].x / width;
463                     if (locIsTextureFlipped)
464                         locTexCoordinates[tex1[i] + 1] = (imageH - tex2[i].y) / height;
465                     else
466                         locTexCoordinates[tex1[i] + 1] = tex2[i].y / height;
467                 }
468             }
469         }
470         this._originalVertices = new Float32Array(this._vertices);
471 
472         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
473         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
474         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
475         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
476         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
477         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
478         this._dirty = true;
479     }
480 });
481 
482 /**
483  * create one Grid3D object
484  * @param {cc.Size} gridSize
485  * @param {cc.Texture2D} [texture=]
486  * @param {Boolean} [flipped=]
487  * @return {cc.Grid3D}
488  */
489 cc.Grid3D.create = function (gridSize, texture, flipped) {
490     return new cc.Grid3D(gridSize, texture, flipped);
491 };
492 
493 /**
494  * cc.TiledGrid3D is a 3D grid implementation. It differs from Grid3D in that   <br/>
495  * the tiles can be separated from the grid.
496  * @class
497  * @extends cc.GridBase
498  */
499 cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{
500     _texCoordinates:null,
501     _vertices:null,
502     _originalVertices:null,
503     _indices:null,
504 
505     _texCoordinateBuffer:null,
506     _verticesBuffer:null,
507     _indicesBuffer:null,
508 
509     /**
510      * create one TiledGrid3D object
511      * Constructor of cc.TiledGrid3D
512      * @param {cc.Size} gridSize
513      * @param {cc.Texture2D} [texture=]
514      * @param {Boolean} [flipped=]
515      */
516     ctor:function (gridSize, texture, flipped) {
517         cc.GridBase.prototype.ctor.call(this);
518         this._texCoordinates=null;
519         this._vertices=null;
520         this._originalVertices=null;
521         this._indices=null;
522 
523         this._texCoordinateBuffer=null;
524         this._verticesBuffer=null;
525         this._indicesBuffer=null;
526 
527         if(gridSize !== undefined)
528             this.initWithSize(gridSize, texture, flipped);
529     },
530 
531     /**
532      * returns the tile at the given position
533      * @param {cc.Point} pos
534      * @return {cc.Quad3}
535      */
536     tile:function (pos) {
537         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
538             cc.log("cc.TiledGrid3D.tile() : Numbers must be integers");
539 
540         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
541         var locVertices = this._vertices;
542         return new cc.Quad3(new cc.Vertex3F(locVertices[idx], locVertices[idx + 1], locVertices[idx + 2]),
543             new cc.Vertex3F(locVertices[idx + 3], locVertices[idx + 4], locVertices[idx + 5]),
544             new cc.Vertex3F(locVertices[idx + 6 ], locVertices[idx + 7], locVertices[idx + 8]),
545             new cc.Vertex3F(locVertices[idx + 9], locVertices[idx + 10], locVertices[idx + 11]));
546     },
547 
548     /**
549      * returns the original tile (untransformed) at the given position
550      * @param {cc.Point} pos
551      * @return {cc.Quad3}
552      */
553     originalTile:function (pos) {
554         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
555             cc.log("cc.TiledGrid3D.originalTile() : Numbers must be integers");
556 
557         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
558         var locOriginalVertices = this._originalVertices;
559         return new cc.Quad3(new cc.Vertex3F(locOriginalVertices[idx], locOriginalVertices[idx + 1], locOriginalVertices[idx + 2]),
560             new cc.Vertex3F(locOriginalVertices[idx + 3], locOriginalVertices[idx + 4], locOriginalVertices[idx + 5]),
561             new cc.Vertex3F(locOriginalVertices[idx + 6 ], locOriginalVertices[idx + 7], locOriginalVertices[idx + 8]),
562             new cc.Vertex3F(locOriginalVertices[idx + 9], locOriginalVertices[idx + 10], locOriginalVertices[idx + 11]));
563     },
564 
565     /**
566      * sets a new tile
567      * @param {cc.Point} pos
568      * @param {cc.Quad3} coords
569      */
570     setTile:function (pos, coords) {
571         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
572             cc.log("cc.TiledGrid3D.setTile() : Numbers must be integers");
573 
574         var idx = (this._gridSize.height * pos.x + pos.y) * 12;
575         var locVertices = this._vertices;
576         locVertices[idx] = coords.bl.x;
577         locVertices[idx + 1] = coords.bl.y;
578         locVertices[idx + 2] = coords.bl.z;
579         locVertices[idx + 3] = coords.br.x;
580         locVertices[idx + 4] = coords.br.y;
581         locVertices[idx + 5] = coords.br.z;
582         locVertices[idx + 6] = coords.tl.x;
583         locVertices[idx + 7] = coords.tl.y;
584         locVertices[idx + 8] = coords.tl.z;
585         locVertices[idx + 9] = coords.tr.x;
586         locVertices[idx + 10] = coords.tr.y;
587         locVertices[idx + 11] = coords.tr.z;
588         this._dirty = true;
589     },
590 
591     blit:function () {
592         var n = this._gridSize.width * this._gridSize.height;
593 
594         this._shaderProgram.use();
595         this._shaderProgram.setUniformsForBuiltins();
596 
597         //
598         // Attributes
599         //
600         var gl = cc._renderContext, locDirty = this._dirty;
601         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_TEX_COORDS);
602 
603         // position
604         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
605         if (locDirty)
606             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
607         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, this._vertices);
608 
609         // texCoords
610         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
611         if (locDirty)
612             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
613         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, this._texCoordinates);
614 
615         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
616         if (locDirty)
617             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
618         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
619         if (locDirty)
620             this._dirty = false;
621         cc.incrementGLDraws(1);
622     },
623 
624     reuse:function () {
625         if (this._reuseGrid > 0) {
626             var locVertices = this._vertices, locOriginalVertices = this._originalVertices;
627             for (var i = 0; i < locVertices.length; i++)
628                 locOriginalVertices[i] = locVertices[i];
629             --this._reuseGrid;
630         }
631     },
632 
633     calculateVertexPoints:function () {
634         var width = this._texture.pixelsWidth;
635         var height = this._texture.pixelsHeight;
636         var imageH = this._texture.getContentSizeInPixels().height;
637         var locGridSize = this._gridSize;
638 
639         var numQuads = locGridSize.width * locGridSize.height;
640         this._vertices = new Float32Array(numQuads * 12);
641         this._texCoordinates = new Float32Array(numQuads * 8);
642         this._indices = new Uint16Array(numQuads * 6);
643 
644         var gl = cc._renderContext;
645         if(this._verticesBuffer)
646             gl.deleteBuffer(this._verticesBuffer);
647         this._verticesBuffer = gl.createBuffer();
648         if(this._texCoordinateBuffer)
649             gl.deleteBuffer(this._texCoordinateBuffer);
650         this._texCoordinateBuffer = gl.createBuffer();
651         if(this._indicesBuffer)
652             gl.deleteBuffer(this._indicesBuffer);
653         this._indicesBuffer = gl.createBuffer();
654 
655         var x, y, i = 0;
656         var locStep = this._step, locVertices = this._vertices, locTexCoords = this._texCoordinates, locIsTextureFlipped = this._isTextureFlipped;
657         for (x = 0; x < locGridSize.width; x++) {
658             for (y = 0; y < locGridSize.height; y++) {
659                 var x1 = x * locStep.x;
660                 var x2 = x1 + locStep.x;
661                 var y1 = y * locStep.y;
662                 var y2 = y1 + locStep.y;
663 
664                 locVertices[i * 12] = x1;
665                 locVertices[i * 12 + 1] = y1;
666                 locVertices[i * 12 + 2] = 0;
667                 locVertices[i * 12 + 3] = x2;
668                 locVertices[i * 12 + 4] = y1;
669                 locVertices[i * 12 + 5] = 0;
670                 locVertices[i * 12 + 6] = x1;
671                 locVertices[i * 12 + 7] = y2;
672                 locVertices[i * 12 + 8] = 0;
673                 locVertices[i * 12 + 9] = x2;
674                 locVertices[i * 12 + 10] = y2;
675                 locVertices[i * 12 + 11] = 0;
676 
677                 var newY1 = y1;
678                 var newY2 = y2;
679 
680                 if (locIsTextureFlipped) {
681                     newY1 = imageH - y1;
682                     newY2 = imageH - y2;
683                 }
684 
685                 locTexCoords[i * 8] = x1 / width;
686                 locTexCoords[i * 8 + 1] = newY1 / height;
687                 locTexCoords[i * 8 + 2] = x2 / width;
688                 locTexCoords[i * 8 + 3] = newY1 / height;
689                 locTexCoords[i * 8 + 4] = x1 / width;
690                 locTexCoords[i * 8 + 5] = newY2 / height;
691                 locTexCoords[i * 8 + 6] = x2 / width;
692                 locTexCoords[i * 8 + 7] = newY2 / height;
693                 i++;
694             }
695         }
696 
697         var locIndices = this._indices;
698         for (x = 0; x < numQuads; x++) {
699             locIndices[x * 6 + 0] = (x * 4 + 0);
700             locIndices[x * 6 + 1] = (x * 4 + 1);
701             locIndices[x * 6 + 2] = (x * 4 + 2);
702 
703             locIndices[x * 6 + 3] = (x * 4 + 1);
704             locIndices[x * 6 + 4] = (x * 4 + 2);
705             locIndices[x * 6 + 5] = (x * 4 + 3);
706         }
707         this._originalVertices = new Float32Array(this._vertices);
708 
709         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
710         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
711         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
712         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
713         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
714         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.DYNAMIC_DRAW);
715         this._dirty = true;
716     }
717 });
718 
719 /**
720  * create one TiledGrid3D object
721  * @param {cc.Size} gridSize
722  * @param {cc.Texture2D} [texture=]
723  * @param {Boolean} [flipped=]
724  * @return {cc.TiledGrid3D}
725  */
726 cc.TiledGrid3D.create = function (gridSize, texture, flipped) {
727     return new cc.TiledGrid3D(gridSize, texture, flipped);
728 };
729