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     _gridRect:null,
 38     _texture:null,
 39     _step:null,
 40     _grabber:null,
 41     _isTextureFlipped:false,
 42     _shaderProgram:null,
 43     _directorProjection:0,
 44 
 45     _dirty:false,
 46 
 47     /**
 48      * create one cc.GridBase Object
 49      * Constructor of cc.GridBase
 50      * @param {cc.Size} gridSize
 51      * @param {cc.Texture2D} [texture=]
 52      * @param {Boolean} [flipped=]
 53      * @param {cc.Rect} rect
 54      */
 55     ctor:function (gridSize, texture, flipped, rect) {
 56         cc.sys._checkWebGLRenderMode();
 57         this._active=false;
 58         this._reuseGrid=0;
 59         this._gridSize=null;
 60         this._gridRect=new cc.rect();
 61         this._texture=null;
 62         this._step = cc.p(0, 0);
 63         this._grabber=null;
 64         this._isTextureFlipped=false;
 65         this._shaderProgram=null;
 66         this._directorProjection=0;
 67         this._dirty=false;
 68 
 69         if(gridSize !== undefined)
 70             this.initWithSize(gridSize, texture, flipped, rect);
 71     },
 72 
 73     /**
 74      * whether or not the grid is active
 75      * @return {Boolean}
 76      */
 77     isActive:function () {
 78         return this._active;
 79     },
 80 
 81     /**
 82      * whether or not the grid is active
 83      * @param {Number} active
 84      */
 85     setActive:function (active) {
 86         this._active = active;
 87         if (!active) {
 88             var director = cc.director;
 89             var proj = director.getProjection();
 90             director.setProjection(proj);
 91         }
 92     },
 93 
 94     /**
 95      * get number of times that the grid will be reused
 96      * @return {Number}
 97      */
 98     getReuseGrid:function () {
 99         return this._reuseGrid;
100     },
101     /**
102      * set number of times that the grid will be reused
103      * @param reuseGrid
104      */
105     setReuseGrid:function (reuseGrid) {
106         this._reuseGrid = reuseGrid;
107     },
108 
109     /**
110      * get size of the grid
111      * @return {cc.Size}
112      */
113     getGridSize:function () {
114         return cc.size(this._gridSize.width, this._gridSize.height);
115     },
116 
117     /**
118      * set size of the grid
119      * @param {cc.Size} gridSize
120      */
121     setGridSize:function (gridSize) {
122         this._gridSize.width = parseInt(gridSize.width);
123         this._gridSize.height = parseInt(gridSize.height);
124     },
125 
126     /**
127      * set rect of the grid
128      * @param {cc.Rect} rect
129      */
130     setGridRect:function (rect) {
131         this._gridRect = rect;
132     },
133 
134     /**
135      * get rect of the grid
136      * @return {cc.Rect} rect
137      */
138     getGridRect:function () {
139         return this._gridRect;
140     },
141 
142     /**
143      * get pixels between the grids
144      * @return {cc.Point}
145      */
146     getStep:function () {
147         return cc.p(this._step.x, this._step.y);
148     },
149 
150     /**
151      * set pixels between the grids
152      * @param {cc.Point} step
153      */
154     setStep:function (step) {
155         this._step.x = step.x;
156         this._step.y = step.y;
157     },
158 
159     /**
160      * get whether or not the texture is flipped
161      * @return {Boolean}
162      */
163     isTextureFlipped:function () {
164         return this._isTextureFlipped;
165     },
166 
167     /**
168      * set whether or not the texture is flipped
169      * @param {Boolean} flipped
170      */
171     setTextureFlipped:function (flipped) {
172         if (this._isTextureFlipped !== flipped) {
173             this._isTextureFlipped = flipped;
174             this.calculateVertexPoints();
175         }
176     },
177 
178     /**
179      *
180      * @param {cc.Size} gridSize
181      * @param {cc.Texture2D} [texture=]
182      * @param {Boolean} [flipped=false]
183      * @param {cc.Rect} [rect=]
184      * @returns {boolean}
185      */
186     initWithSize:function (gridSize, texture, flipped, rect) {
187         if (!texture) {
188             var director = cc.director;
189             var winSize = director.getWinSizeInPixels();
190 
191             var POTWide = cc.NextPOT(winSize.width);
192             var POTHigh = cc.NextPOT(winSize.height);
193 
194             var data = new Uint8Array(POTWide * POTHigh * 4);
195             if (!data) {
196                 cc.log("cocos2d: CCGrid: not enough memory.");
197                 return false;
198             }
199 
200             texture = new cc.Texture2D();
201             // we only use rgba8888
202             texture.initWithData(data, cc.Texture2D.PIXEL_FORMAT_RGBA8888, POTWide, POTHigh, winSize);
203             if (!texture) {
204                 cc.log("cocos2d: CCGrid: error creating texture");
205                 return false;
206             }
207         }
208 
209         flipped = flipped || false;
210 
211         this._active = false;
212         this._reuseGrid = 0;
213         this._gridSize = gridSize;
214         this._texture = texture;
215         this._isTextureFlipped = flipped;
216         if(rect === undefined || cc._rectEqualToZero(rect))
217         {
218             var size = this._texture.getContentSize();
219             rect = new cc.rect(0,0,size.width,size.height);
220         }
221 
222         this._gridRect = rect;
223 
224         this._step.x = this._gridRect.width / gridSize.width;
225         this._step.y = this._gridRect.height / gridSize.height;
226 
227         this._grabber = new cc.Grabber();
228         if (!this._grabber)
229             return false;
230         this._grabber.grab(this._texture);
231         this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURE);
232         this.calculateVertexPoints();
233         return true;
234     },
235 
236     beforeDraw:function () {
237         // save projection
238         this._directorProjection = cc.director.getProjection();
239 
240         //this.set2DProjection();    //TODO why?
241         var size = cc.director.getWinSizeInPixels();
242         gl.viewport(0, 0, size.width , size.height);
243         this._grabber.beforeRender(this._texture);
244     },
245 
246     afterDraw:function (target) {
247         this._grabber.afterRender(this._texture);
248 
249         // restore projection
250         //cc.director.setProjection(this._directorProjection);
251         cc.director.setViewport();
252 
253         if (target && target.getCamera().isDirty()) {
254             var offset = target.getAnchorPointInPoints();
255 
256             //TODO hack
257             var stackMatrix = target._renderCmd._stackMatrix;
258             //
259             // XXX: Camera should be applied in the AnchorPoint
260             //
261             //cc.kmGLTranslatef(offset.x, offset.y, 0);
262             var translation = cc.math.Matrix4.createByTranslation(offset.x, offset.y, 0);
263             stackMatrix.multiply(translation);
264 
265             //target.getCamera().locate();
266             target._camera._locateForRenderer(stackMatrix);
267 
268             //cc.kmGLTranslatef(-offset.x, -offset.y, 0);
269             translation = cc.math.Matrix4.createByTranslation(-offset.x, -offset.y, 0, translation);
270             stackMatrix.multiply(translation);
271         }
272 
273         cc.glBindTexture2D(this._texture);
274         this.beforeBlit();
275         this.blit(target);
276         this.afterBlit();
277     },
278 
279     beforeBlit: function () {
280     },
281 
282     afterBlit: function () {
283     },
284 
285     blit:function () {
286         cc.log("cc.GridBase.blit(): Shall be overridden in subclass.");
287     },
288 
289     reuse:function () {
290         cc.log("cc.GridBase.reuse(): Shall be overridden in subclass.");
291     },
292 
293     calculateVertexPoints:function () {
294         cc.log("cc.GridBase.calculateVertexPoints(): Shall be overridden in subclass.");
295     },
296 
297     set2DProjection:function () {
298         var winSize = cc.director.getWinSizeInPixels();
299 
300         var gl = cc._renderContext;
301         gl.viewport(0, 0, winSize.width , winSize.height);
302         cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
303         cc.kmGLLoadIdentity();
304 
305         var orthoMatrix = cc.math.Matrix4.createOrthographicProjection(0, winSize.width, 0, winSize.height, -1, 1);
306         cc.kmGLMultMatrix(orthoMatrix);
307 
308         cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
309         cc.kmGLLoadIdentity();
310         cc.setProjectionMatrixDirty()
311     }
312 });
313 
314 /**
315  * create one cc.GridBase Object
316  * @deprecated
317  * @param {cc.Size} gridSize
318  * @param {cc.Texture2D} [texture=]
319  * @param {Boolean} [flipped=]
320  * @param {cc.Rect} [rect=]
321  * @return {cc.GridBase}
322  */
323 cc.GridBase.create = function (gridSize, texture, flipped, rect) {
324     return new cc.GridBase(gridSize, texture, flipped, rect);
325 };
326 
327 /**
328  * cc.Grid3D is a 3D grid implementation. Each vertex has 3 dimensions: x,y,z
329  * @class
330  * @extends cc.GridBase
331  */
332 cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{
333     _texCoordinates:null,
334     _vertices:null,
335     _originalVertices:null,
336     _indices:null,
337 
338     _texCoordinateBuffer:null,
339     _verticesBuffer:null,
340     _indicesBuffer:null,
341 
342     _needDepthTestForBlit: false,
343     _oldDepthTestValue: false,
344     _oldDepthWriteValue: false,
345 
346     /**
347      * create one Grid3D object
348      * Constructor of cc.Grid3D
349      * @param {cc.Size} gridSize
350      * @param {cc.Texture2D} [texture=]
351      * @param {Boolean} [flipped=]
352      * @param {cc.Rect} [rect=]
353      */
354     ctor:function (gridSize, texture, flipped, rect) {
355         cc.GridBase.prototype.ctor.call(this);
356         this._texCoordinates=null;
357         this._vertices=null;
358         this._originalVertices=null;
359         this._indices=null;
360 
361         this._texCoordinateBuffer=null;
362         this._verticesBuffer=null;
363         this._indicesBuffer=null;
364 
365         if(gridSize !== undefined)
366             this.initWithSize(gridSize, texture, flipped, rect);
367     },
368 
369     /**
370      * returns the vertex at a given position      <br/>
371      * It will be deprecated in future, please use getVertex instead.
372      * @param {cc.Point} pos
373      * @return {cc.Vertex3F}
374      */
375     vertex:function (pos) {
376          return this.getVertex(pos);
377     },
378 
379     /**
380      * returns the vertex at a given position
381      * @param {cc.Point} pos
382      * @return {cc.Vertex3F}
383      */
384     getVertex: function(pos){
385         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
386             cc.log("cc.Grid3D.vertex() : Numbers must be integers");
387         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
388         var locVertices = this._vertices;
389         return new cc.Vertex3F(locVertices[index], locVertices[index + 1], locVertices[index + 2]);
390     },
391 
392     /**
393      * returns the original (non-transformed) vertex at a given position             <br/>
394      * It will be deprecated in future, please use getOriginalVertex instead.
395      * @param {cc.Point} pos
396      * @return {cc.Vertex3F}
397      */
398     originalVertex:function (pos) {
399         return this.getOriginalVertex(pos);
400     },
401 
402     /**
403      * returns the original (non-transformed) vertex at a given position
404      * @param {cc.Point} pos
405      * @return {cc.Vertex3F}
406      */
407     getOriginalVertex: function(pos) {
408         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
409             cc.log("cc.Grid3D.originalVertex() : Numbers must be integers");
410         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
411         var locOriginalVertices = this._originalVertices;
412         return new cc.Vertex3F(locOriginalVertices[index], locOriginalVertices[index + 1], locOriginalVertices[index + 2]);
413     },
414 
415     /**
416      * sets a new vertex at a given position
417      * @param {cc.Point} pos
418      * @param {cc.Vertex3F} vertex
419      */
420     setVertex:function (pos, vertex) {
421         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
422             cc.log("cc.Grid3D.setVertex() : Numbers must be integers");
423         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
424         var vertArray = this._vertices;
425         vertArray[index] = vertex.x;
426         vertArray[index + 1] = vertex.y;
427         vertArray[index + 2] = vertex.z;
428         this._dirty = true;
429     },
430 
431     beforeBlit: function () {
432         if (this._needDepthTestForBlit) {
433             var gl = cc._renderContext;
434             this._oldDepthTestValue = gl.isEnabled(gl.DEPTH_TEST);
435             this._oldDepthWriteValue = gl.getParameter(gl.DEPTH_WRITEMASK);
436             //CHECK_GL_ERROR_DEBUG();
437             gl.enable(gl.DEPTH_TEST);
438             gl.depthMask(true);
439         }
440     },
441 
442     afterBlit: function () {
443         if (this._needDepthTestForBlit) {
444             var gl = cc._renderContext;
445             if (this._oldDepthTestValue)
446                 gl.enable(gl.DEPTH_TEST);
447             else
448                 gl.disable(gl.DEPTH_TEST);
449             gl.depthMask(this._oldDepthWriteValue);
450         }
451     },
452 
453     blit:function (target) {
454         var n = this._gridSize.width * this._gridSize.height;
455         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_TEX_COORDS);
456         this._shaderProgram.use();
457         //this._shaderProgram.setUniformsForBuiltins();
458         this._shaderProgram._setUniformForMVPMatrixWithMat4(target._renderCmd._stackMatrix);
459 
460         var gl = cc._renderContext, locDirty = this._dirty;
461         //
462         // Attributes
463         //
464         // position
465         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
466         if (locDirty)
467             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
468         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, 0);
469 
470         // texCoords
471         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
472         if (locDirty)
473             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
474         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, 0);
475 
476         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
477         if (locDirty)
478             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
479         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
480         if (locDirty)
481             this._dirty = false;
482         cc.incrementGLDraws(1);
483     },
484 
485     reuse:function () {
486         if (this._reuseGrid > 0) {
487             var locOriginalVertices = this._originalVertices, locVertices = this._vertices;
488             for (var i = 0, len =  this._vertices.length; i < len; i++)
489                 locOriginalVertices[i] = locVertices[i];
490             --this._reuseGrid;
491         }
492     },
493 
494     calculateVertexPoints:function () {
495         var gl = cc._renderContext;
496 
497         var width = this._texture.pixelsWidth;
498         var height = this._texture.pixelsHeight;
499         var imageH = this._texture.getContentSizeInPixels().height;
500         var locGridSize = this._gridSize;
501 
502         var numOfPoints = (locGridSize.width + 1) * (locGridSize.height + 1);
503         this._vertices = new Float32Array(numOfPoints * 3);
504         this._texCoordinates = new Float32Array(numOfPoints * 2);
505         this._indices = new Uint16Array(locGridSize.width * locGridSize.height * 6);
506 
507         if(this._verticesBuffer)
508             gl.deleteBuffer(this._verticesBuffer);
509         this._verticesBuffer = gl.createBuffer();
510         if(this._texCoordinateBuffer)
511             gl.deleteBuffer(this._texCoordinateBuffer);
512         this._texCoordinateBuffer = gl.createBuffer();
513         if(this._indicesBuffer)
514             gl.deleteBuffer(this._indicesBuffer);
515         this._indicesBuffer = gl.createBuffer();
516 
517         var x, y, i, locIndices = this._indices, locTexCoordinates = this._texCoordinates;
518         var locIsTextureFlipped = this._isTextureFlipped, locVertices = this._vertices;
519         for (x = 0; x < locGridSize.width; ++x) {
520             for (y = 0; y < locGridSize.height; ++y) {
521                 var idx = (y * locGridSize.width) + x;
522                 var x1 = x * this._step.x + this._gridRect.x;
523                 var x2 = x1 + this._step.x;
524                 var y1 = y * this._step.y + this._gridRect.y;
525                 var y2 = y1 + this._step.y;
526 
527                 var a = (x * (locGridSize.height + 1) + y);
528                 var b = ((x + 1) * (locGridSize.height + 1) + y);
529                 var c = ((x + 1) * (locGridSize.height + 1) + (y + 1));
530                 var d = (x * (locGridSize.height + 1) + (y + 1));
531 
532                 locIndices[idx * 6] = a;
533                 locIndices[idx * 6 + 1] = b;
534                 locIndices[idx * 6 + 2] = d;
535                 locIndices[idx * 6 + 3] = b;
536                 locIndices[idx * 6 + 4] = c;
537                 locIndices[idx * 6 + 5] = d;
538 
539                 var l1 = [a * 3, b * 3, c * 3, d * 3];
540                 var e = {x:x1, y:y1, z:0};   //new cc.Vertex3F(x1, y1, 0);
541                 var f = {x:x2, y:y1, z:0};   //new cc.Vertex3F(x2, y1, 0);
542                 var g = {x:x2, y:y2, z:0};   // new cc.Vertex3F(x2, y2, 0);
543                 var h = {x:x1, y:y2, z:0};   //new cc.Vertex3F(x1, y2, 0);
544 
545                 var l2 = [e, f, g, h];
546                 var tex1 = [a * 2, b * 2, c * 2, d * 2];
547                 var tex2 = [cc.p(x1, y1), cc.p(x2, y1), cc.p(x2, y2), cc.p(x1, y2)];
548                 for (i = 0; i < 4; ++i) {
549                     locVertices[l1[i]] = l2[i].x;
550                     locVertices[l1[i] + 1] = l2[i].y;
551                     locVertices[l1[i] + 2] = l2[i].z;
552                     locTexCoordinates[tex1[i]] = tex2[i].x / width;
553                     if (locIsTextureFlipped)
554                         locTexCoordinates[tex1[i] + 1] = (imageH - tex2[i].y) / height;
555                     else
556                         locTexCoordinates[tex1[i] + 1] = tex2[i].y / height;
557                 }
558             }
559         }
560         this._originalVertices = new Float32Array(this._vertices);
561 
562         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
563         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
564         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
565         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
566         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
567         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
568         this._dirty = true;
569     },
570 
571     setNeedDepthTestForBlit: function(needDepthTest){
572         this._needDepthTestForBlit = needDepthTest;
573     },
574 
575     getNeedDepthTestForBlit: function(){
576         return this._needDepthTestForBlit;
577     }
578 });
579 
580 /**
581  * create one Grid3D object
582  * @deprecated
583  * @param {cc.Size} gridSize
584  * @param {cc.Texture2D} [texture=]
585  * @param {Boolean} [flipped=]
586  * @return {cc.Grid3D}
587  */
588 cc.Grid3D.create = function (gridSize, texture, flipped) {
589     return new cc.Grid3D(gridSize, texture, flipped);
590 };
591 
592 /**
593  * cc.TiledGrid3D is a 3D grid implementation. It differs from Grid3D in that   <br/>
594  * the tiles can be separated from the grid.
595  * @class
596  * @extends cc.GridBase
597  */
598 cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{
599     _texCoordinates:null,
600     _vertices:null,
601     _originalVertices:null,
602     _indices:null,
603 
604     _texCoordinateBuffer:null,
605     _verticesBuffer:null,
606     _indicesBuffer:null,
607 
608     /**
609      * create one TiledGrid3D object
610      * Constructor of cc.TiledGrid3D
611      * @param {cc.Size} gridSize
612      * @param {cc.Texture2D} [texture=]
613      * @param {Boolean} [flipped=]
614      */
615     ctor:function (gridSize, texture, flipped, rect) {
616         cc.GridBase.prototype.ctor.call(this);
617         this._texCoordinates=null;
618         this._vertices=null;
619         this._originalVertices=null;
620         this._indices=null;
621 
622         this._texCoordinateBuffer=null;
623         this._verticesBuffer=null;
624         this._indicesBuffer=null;
625 
626         if(gridSize !== undefined)
627             this.initWithSize(gridSize, texture, flipped, rect);
628     },
629 
630     /**
631      * returns the tile at the given position    <br/>
632      * It will be deprecated in future, please use getTile instead.
633      * @param {cc.Point} pos
634      * @return {cc.Quad3}
635      */
636     tile:function (pos) {
637         return this.getTile(pos);
638     },
639 
640     /**
641      * returns the tile at the given position
642      * @param {cc.Point} pos
643      * @return {cc.Quad3}
644      */
645     getTile: function(pos){
646         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
647             cc.log("cc.TiledGrid3D.tile() : Numbers must be integers");
648 
649         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
650         var locVertices = this._vertices;
651         return new cc.Quad3(new cc.Vertex3F(locVertices[idx], locVertices[idx + 1], locVertices[idx + 2]),
652             new cc.Vertex3F(locVertices[idx + 3], locVertices[idx + 4], locVertices[idx + 5]),
653             new cc.Vertex3F(locVertices[idx + 6 ], locVertices[idx + 7], locVertices[idx + 8]),
654             new cc.Vertex3F(locVertices[idx + 9], locVertices[idx + 10], locVertices[idx + 11]));
655     },
656 
657     /**
658      * returns the original tile (untransformed) at the given position
659      * @param {cc.Point} pos
660      * @return {cc.Quad3}
661      */
662     getOriginalTile:function (pos) {
663         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
664             cc.log("cc.TiledGrid3D.originalTile() : Numbers must be integers");
665 
666         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
667         var locOriginalVertices = this._originalVertices;
668         return new cc.Quad3(new cc.Vertex3F(locOriginalVertices[idx], locOriginalVertices[idx + 1], locOriginalVertices[idx + 2]),
669             new cc.Vertex3F(locOriginalVertices[idx + 3], locOriginalVertices[idx + 4], locOriginalVertices[idx + 5]),
670             new cc.Vertex3F(locOriginalVertices[idx + 6 ], locOriginalVertices[idx + 7], locOriginalVertices[idx + 8]),
671             new cc.Vertex3F(locOriginalVertices[idx + 9], locOriginalVertices[idx + 10], locOriginalVertices[idx + 11]));
672     },
673 
674     /**
675      * returns the original tile (untransformed) at the given position.      <br/>
676      * It will be deprecated in future, please use getOriginalTile instead.
677      * @param {cc.Point} pos
678      * @return {cc.Quad3}
679      */
680     originalTile: function(pos) {
681         return this.getOriginalTile(pos);
682     },
683 
684     /**
685      * sets a new tile
686      * @param {cc.Point} pos
687      * @param {cc.Quad3} coords
688      */
689     setTile:function (pos, coords) {
690         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
691             cc.log("cc.TiledGrid3D.setTile() : Numbers must be integers");
692 
693         var idx = (this._gridSize.height * pos.x + pos.y) * 12;
694         var locVertices = this._vertices;
695         locVertices[idx] = coords.bl.x;
696         locVertices[idx + 1] = coords.bl.y;
697         locVertices[idx + 2] = coords.bl.z;
698         locVertices[idx + 3] = coords.br.x;
699         locVertices[idx + 4] = coords.br.y;
700         locVertices[idx + 5] = coords.br.z;
701         locVertices[idx + 6] = coords.tl.x;
702         locVertices[idx + 7] = coords.tl.y;
703         locVertices[idx + 8] = coords.tl.z;
704         locVertices[idx + 9] = coords.tr.x;
705         locVertices[idx + 10] = coords.tr.y;
706         locVertices[idx + 11] = coords.tr.z;
707         this._dirty = true;
708     },
709 
710     blit: function (target) {
711         var n = this._gridSize.width * this._gridSize.height;
712 
713         this._shaderProgram.use();
714         this._shaderProgram._setUniformForMVPMatrixWithMat4(target._renderCmd._stackMatrix);
715         //this._shaderProgram.setUniformsForBuiltins();
716 
717         //
718         // Attributes
719         //
720         var gl = cc._renderContext, locDirty = this._dirty;
721         cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_TEX_COORDS);
722 
723         // position
724         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
725         if (locDirty)
726             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
727         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, this._vertices);
728 
729         // texCoords
730         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
731         if (locDirty)
732             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
733         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, this._texCoordinates);
734 
735         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
736         if (locDirty)
737             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
738         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
739         if (locDirty)
740             this._dirty = false;
741         cc.incrementGLDraws(1);
742     },
743 
744     reuse:function () {
745         if (this._reuseGrid > 0) {
746             var locVertices = this._vertices, locOriginalVertices = this._originalVertices;
747             for (var i = 0; i < locVertices.length; i++)
748                 locOriginalVertices[i] = locVertices[i];
749             --this._reuseGrid;
750         }
751     },
752 
753     calculateVertexPoints:function () {
754         var width = this._texture.pixelsWidth;
755         var height = this._texture.pixelsHeight;
756         var imageH = this._texture.getContentSizeInPixels().height;
757         var locGridSize = this._gridSize;
758 
759         var numQuads = locGridSize.width * locGridSize.height;
760         this._vertices = new Float32Array(numQuads * 12);
761         this._texCoordinates = new Float32Array(numQuads * 8);
762         this._indices = new Uint16Array(numQuads * 6);
763 
764         var gl = cc._renderContext;
765         if(this._verticesBuffer)
766             gl.deleteBuffer(this._verticesBuffer);
767         this._verticesBuffer = gl.createBuffer();
768         if(this._texCoordinateBuffer)
769             gl.deleteBuffer(this._texCoordinateBuffer);
770         this._texCoordinateBuffer = gl.createBuffer();
771         if(this._indicesBuffer)
772             gl.deleteBuffer(this._indicesBuffer);
773         this._indicesBuffer = gl.createBuffer();
774 
775         var x, y, i = 0;
776         var locStep = this._step, locVertices = this._vertices, locTexCoords = this._texCoordinates, locIsTextureFlipped = this._isTextureFlipped;
777         for (x = 0; x < locGridSize.width; x++) {
778             for (y = 0; y < locGridSize.height; y++) {
779                 var x1 = x * locStep.x;
780                 var x2 = x1 + locStep.x;
781                 var y1 = y * locStep.y;
782                 var y2 = y1 + locStep.y;
783 
784                 locVertices[i * 12] = x1;
785                 locVertices[i * 12 + 1] = y1;
786                 locVertices[i * 12 + 2] = 0;
787                 locVertices[i * 12 + 3] = x2;
788                 locVertices[i * 12 + 4] = y1;
789                 locVertices[i * 12 + 5] = 0;
790                 locVertices[i * 12 + 6] = x1;
791                 locVertices[i * 12 + 7] = y2;
792                 locVertices[i * 12 + 8] = 0;
793                 locVertices[i * 12 + 9] = x2;
794                 locVertices[i * 12 + 10] = y2;
795                 locVertices[i * 12 + 11] = 0;
796 
797                 var newY1 = y1;
798                 var newY2 = y2;
799 
800                 if (locIsTextureFlipped) {
801                     newY1 = imageH - y1;
802                     newY2 = imageH - y2;
803                 }
804 
805                 locTexCoords[i * 8] = x1 / width;
806                 locTexCoords[i * 8 + 1] = newY1 / height;
807                 locTexCoords[i * 8 + 2] = x2 / width;
808                 locTexCoords[i * 8 + 3] = newY1 / height;
809                 locTexCoords[i * 8 + 4] = x1 / width;
810                 locTexCoords[i * 8 + 5] = newY2 / height;
811                 locTexCoords[i * 8 + 6] = x2 / width;
812                 locTexCoords[i * 8 + 7] = newY2 / height;
813                 i++;
814             }
815         }
816 
817         var locIndices = this._indices;
818         for (x = 0; x < numQuads; x++) {
819             locIndices[x * 6 + 0] = (x * 4 + 0);
820             locIndices[x * 6 + 1] = (x * 4 + 1);
821             locIndices[x * 6 + 2] = (x * 4 + 2);
822 
823             locIndices[x * 6 + 3] = (x * 4 + 1);
824             locIndices[x * 6 + 4] = (x * 4 + 2);
825             locIndices[x * 6 + 5] = (x * 4 + 3);
826         }
827         this._originalVertices = new Float32Array(this._vertices);
828 
829         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
830         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
831         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
832         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
833         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
834         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.DYNAMIC_DRAW);
835         this._dirty = true;
836     }
837 });
838 
839 /**
840  * create one TiledGrid3D object
841  * @deprecated since v3.0, please use new cc.TiledGrid3D(gridSize, texture, flipped) instead
842  * @param {cc.Size} gridSize
843  * @param {cc.Texture2D} [texture=]
844  * @param {Boolean} [flipped=]
845  * @return {cc.TiledGrid3D}
846  */
847 cc.TiledGrid3D.create = function (gridSize, texture, flipped) {
848     return new cc.TiledGrid3D(gridSize, texture, flipped);
849 };
850