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         cc.glBindTexture2D(this._texture);
254         this.beforeBlit();
255         this.blit(target);
256         this.afterBlit();
257     },
258 
259     beforeBlit: function () {
260     },
261 
262     afterBlit: function () {
263     },
264 
265     blit:function () {
266         cc.log("cc.GridBase.blit(): Shall be overridden in subclass.");
267     },
268 
269     reuse:function () {
270         cc.log("cc.GridBase.reuse(): Shall be overridden in subclass.");
271     },
272 
273     calculateVertexPoints:function () {
274         cc.log("cc.GridBase.calculateVertexPoints(): Shall be overridden in subclass.");
275     },
276 
277     set2DProjection:function () {
278         var winSize = cc.director.getWinSizeInPixels();
279 
280         var gl = cc._renderContext;
281         gl.viewport(0, 0, winSize.width , winSize.height);
282         cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
283         cc.kmGLLoadIdentity();
284 
285         var orthoMatrix = cc.math.Matrix4.createOrthographicProjection(0, winSize.width, 0, winSize.height, -1, 1);
286         cc.kmGLMultMatrix(orthoMatrix);
287 
288         cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
289         cc.kmGLLoadIdentity();
290         cc.setProjectionMatrixDirty()
291     }
292 });
293 
294 /**
295  * create one cc.GridBase Object
296  * @deprecated
297  * @param {cc.Size} gridSize
298  * @param {cc.Texture2D} [texture=]
299  * @param {Boolean} [flipped=]
300  * @param {cc.Rect} [rect=]
301  * @return {cc.GridBase}
302  */
303 cc.GridBase.create = function (gridSize, texture, flipped, rect) {
304     return new cc.GridBase(gridSize, texture, flipped, rect);
305 };
306 
307 /**
308  * cc.Grid3D is a 3D grid implementation. Each vertex has 3 dimensions: x,y,z
309  * @class
310  * @extends cc.GridBase
311  */
312 cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{
313     _texCoordinates:null,
314     _vertices:null,
315     _originalVertices:null,
316     _indices:null,
317 
318     _texCoordinateBuffer:null,
319     _verticesBuffer:null,
320     _indicesBuffer:null,
321 
322     _needDepthTestForBlit: false,
323     _oldDepthTestValue: false,
324     _oldDepthWriteValue: false,
325 
326     /**
327      * create one Grid3D object
328      * Constructor of cc.Grid3D
329      * @param {cc.Size} gridSize
330      * @param {cc.Texture2D} [texture=]
331      * @param {Boolean} [flipped=]
332      * @param {cc.Rect} [rect=]
333      */
334     ctor:function (gridSize, texture, flipped, rect) {
335         cc.GridBase.prototype.ctor.call(this);
336         this._texCoordinates=null;
337         this._vertices=null;
338         this._originalVertices=null;
339         this._indices=null;
340 
341         this._texCoordinateBuffer=null;
342         this._verticesBuffer=null;
343         this._indicesBuffer=null;
344 
345         this._matrix = new cc.math.Matrix4();
346         this._matrix.identity();
347 
348         if(gridSize !== undefined)
349             this.initWithSize(gridSize, texture, flipped, rect);
350     },
351 
352     /**
353      * returns the vertex at a given position      <br/>
354      * It will be deprecated in future, please use getVertex instead.
355      * @param {cc.Point} pos
356      * @return {cc.Vertex3F}
357      */
358     vertex:function (pos) {
359          return this.getVertex(pos);
360     },
361 
362     /**
363      * returns the vertex at a given position
364      * @param {cc.Point} pos
365      * @return {cc.Vertex3F}
366      */
367     getVertex: function(pos){
368         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
369             cc.log("cc.Grid3D.vertex() : Numbers must be integers");
370         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
371         var locVertices = this._vertices;
372         return new cc.Vertex3F(locVertices[index], locVertices[index + 1], locVertices[index + 2]);
373     },
374 
375     /**
376      * returns the original (non-transformed) vertex at a given position             <br/>
377      * It will be deprecated in future, please use getOriginalVertex instead.
378      * @param {cc.Point} pos
379      * @return {cc.Vertex3F}
380      */
381     originalVertex:function (pos) {
382         return this.getOriginalVertex(pos);
383     },
384 
385     /**
386      * returns the original (non-transformed) vertex at a given position
387      * @param {cc.Point} pos
388      * @return {cc.Vertex3F}
389      */
390     getOriginalVertex: function(pos) {
391         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
392             cc.log("cc.Grid3D.originalVertex() : Numbers must be integers");
393         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
394         var locOriginalVertices = this._originalVertices;
395         return new cc.Vertex3F(locOriginalVertices[index], locOriginalVertices[index + 1], locOriginalVertices[index + 2]);
396     },
397 
398     /**
399      * sets a new vertex at a given position
400      * @param {cc.Point} pos
401      * @param {cc.Vertex3F} vertex
402      */
403     setVertex:function (pos, vertex) {
404         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
405             cc.log("cc.Grid3D.setVertex() : Numbers must be integers");
406         var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3);
407         var vertArray = this._vertices;
408         vertArray[index] = vertex.x;
409         vertArray[index + 1] = vertex.y;
410         vertArray[index + 2] = vertex.z;
411         this._dirty = true;
412     },
413 
414     beforeBlit: function () {
415         if (this._needDepthTestForBlit) {
416             var gl = cc._renderContext;
417             this._oldDepthTestValue = gl.isEnabled(gl.DEPTH_TEST);
418             this._oldDepthWriteValue = gl.getParameter(gl.DEPTH_WRITEMASK);
419             //CHECK_GL_ERROR_DEBUG();
420             gl.enable(gl.DEPTH_TEST);
421             gl.depthMask(true);
422         }
423     },
424 
425     afterBlit: function () {
426         if (this._needDepthTestForBlit) {
427             var gl = cc._renderContext;
428             if (this._oldDepthTestValue)
429                 gl.enable(gl.DEPTH_TEST);
430             else
431                 gl.disable(gl.DEPTH_TEST);
432             gl.depthMask(this._oldDepthWriteValue);
433         }
434     },
435 
436     blit:function (target) {
437         var n = this._gridSize.width * this._gridSize.height;
438 
439         var wt = target._renderCmd._worldTransform;
440         this._matrix.mat[0] = wt.a;
441         this._matrix.mat[4] = wt.c;
442         this._matrix.mat[12] = wt.tx;
443         this._matrix.mat[1] = wt.b;
444         this._matrix.mat[5] = wt.d;
445         this._matrix.mat[13] = wt.ty;
446 
447         this._shaderProgram.use();
448         //this._shaderProgram.setUniformsForBuiltins();
449         this._shaderProgram._setUniformForMVPMatrixWithMat4(this._matrix);
450 
451         var gl = cc._renderContext, locDirty = this._dirty;
452 
453         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_POSITION);
454         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_TEX_COORDS);
455         //
456         // Attributes
457         //
458         // position
459         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
460         if (locDirty)
461             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
462         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, 0);
463 
464         // texCoords
465         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
466         if (locDirty)
467             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
468         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, 0);
469 
470         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
471         if (locDirty)
472             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
473         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
474         if (locDirty)
475             this._dirty = false;
476         cc.incrementGLDraws(1);
477     },
478 
479     reuse:function () {
480         if (this._reuseGrid > 0) {
481             var locOriginalVertices = this._originalVertices, locVertices = this._vertices;
482             for (var i = 0, len =  this._vertices.length; i < len; i++)
483                 locOriginalVertices[i] = locVertices[i];
484             --this._reuseGrid;
485         }
486     },
487 
488     calculateVertexPoints:function () {
489         var gl = cc._renderContext;
490 
491         var width = this._texture.pixelsWidth;
492         var height = this._texture.pixelsHeight;
493         var imageH = this._texture.getContentSizeInPixels().height;
494         var locGridSize = this._gridSize;
495 
496         var numOfPoints = (locGridSize.width + 1) * (locGridSize.height + 1);
497         this._vertices = new Float32Array(numOfPoints * 3);
498         this._texCoordinates = new Float32Array(numOfPoints * 2);
499         this._indices = new Uint16Array(locGridSize.width * locGridSize.height * 6);
500 
501         if(this._verticesBuffer)
502             gl.deleteBuffer(this._verticesBuffer);
503         this._verticesBuffer = gl.createBuffer();
504         if(this._texCoordinateBuffer)
505             gl.deleteBuffer(this._texCoordinateBuffer);
506         this._texCoordinateBuffer = gl.createBuffer();
507         if(this._indicesBuffer)
508             gl.deleteBuffer(this._indicesBuffer);
509         this._indicesBuffer = gl.createBuffer();
510 
511         var x, y, i, locIndices = this._indices, locTexCoordinates = this._texCoordinates;
512         var locIsTextureFlipped = this._isTextureFlipped, locVertices = this._vertices;
513         for (x = 0; x < locGridSize.width; ++x) {
514             for (y = 0; y < locGridSize.height; ++y) {
515                 var idx = (y * locGridSize.width) + x;
516                 var x1 = x * this._step.x + this._gridRect.x;
517                 var x2 = x1 + this._step.x;
518                 var y1 = y * this._step.y + this._gridRect.y;
519                 var y2 = y1 + this._step.y;
520 
521                 var a = (x * (locGridSize.height + 1) + y);
522                 var b = ((x + 1) * (locGridSize.height + 1) + y);
523                 var c = ((x + 1) * (locGridSize.height + 1) + (y + 1));
524                 var d = (x * (locGridSize.height + 1) + (y + 1));
525 
526                 locIndices[idx * 6] = a;
527                 locIndices[idx * 6 + 1] = b;
528                 locIndices[idx * 6 + 2] = d;
529                 locIndices[idx * 6 + 3] = b;
530                 locIndices[idx * 6 + 4] = c;
531                 locIndices[idx * 6 + 5] = d;
532 
533                 var l1 = [a * 3, b * 3, c * 3, d * 3];
534                 var e = {x:x1, y:y1, z:0};   //new cc.Vertex3F(x1, y1, 0);
535                 var f = {x:x2, y:y1, z:0};   //new cc.Vertex3F(x2, y1, 0);
536                 var g = {x:x2, y:y2, z:0};   // new cc.Vertex3F(x2, y2, 0);
537                 var h = {x:x1, y:y2, z:0};   //new cc.Vertex3F(x1, y2, 0);
538 
539                 var l2 = [e, f, g, h];
540                 var tex1 = [a * 2, b * 2, c * 2, d * 2];
541                 var tex2 = [cc.p(x1, y1), cc.p(x2, y1), cc.p(x2, y2), cc.p(x1, y2)];
542                 for (i = 0; i < 4; ++i) {
543                     locVertices[l1[i]] = l2[i].x;
544                     locVertices[l1[i] + 1] = l2[i].y;
545                     locVertices[l1[i] + 2] = l2[i].z;
546                     locTexCoordinates[tex1[i]] = tex2[i].x / width;
547                     if (locIsTextureFlipped)
548                         locTexCoordinates[tex1[i] + 1] = (imageH - tex2[i].y) / height;
549                     else
550                         locTexCoordinates[tex1[i] + 1] = tex2[i].y / height;
551                 }
552             }
553         }
554         this._originalVertices = new Float32Array(this._vertices);
555 
556         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
557         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
558         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
559         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
560         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
561         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
562         this._dirty = true;
563     },
564 
565     setNeedDepthTestForBlit: function(needDepthTest){
566         this._needDepthTestForBlit = needDepthTest;
567     },
568 
569     getNeedDepthTestForBlit: function(){
570         return this._needDepthTestForBlit;
571     }
572 });
573 
574 /**
575  * create one Grid3D object
576  * @deprecated
577  * @param {cc.Size} gridSize
578  * @param {cc.Texture2D} [texture=]
579  * @param {Boolean} [flipped=]
580  * @return {cc.Grid3D}
581  */
582 cc.Grid3D.create = function (gridSize, texture, flipped) {
583     return new cc.Grid3D(gridSize, texture, flipped);
584 };
585 
586 /**
587  * cc.TiledGrid3D is a 3D grid implementation. It differs from Grid3D in that   <br/>
588  * the tiles can be separated from the grid.
589  * @class
590  * @extends cc.GridBase
591  */
592 cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{
593     _texCoordinates:null,
594     _vertices:null,
595     _originalVertices:null,
596     _indices:null,
597 
598     _texCoordinateBuffer:null,
599     _verticesBuffer:null,
600     _indicesBuffer:null,
601 
602     /**
603      * create one TiledGrid3D object
604      * Constructor of cc.TiledGrid3D
605      * @param {cc.Size} gridSize
606      * @param {cc.Texture2D} [texture=]
607      * @param {Boolean} [flipped=]
608      */
609     ctor:function (gridSize, texture, flipped, rect) {
610         cc.GridBase.prototype.ctor.call(this);
611         this._texCoordinates=null;
612         this._vertices=null;
613         this._originalVertices=null;
614         this._indices=null;
615 
616         this._texCoordinateBuffer=null;
617         this._verticesBuffer=null;
618         this._indicesBuffer=null;
619 
620         this._matrix = new cc.math.Matrix4();
621         this._matrix.identity();
622 
623         if(gridSize !== undefined)
624             this.initWithSize(gridSize, texture, flipped, rect);
625     },
626 
627     /**
628      * returns the tile at the given position    <br/>
629      * It will be deprecated in future, please use getTile instead.
630      * @param {cc.Point} pos
631      * @return {cc.Quad3}
632      */
633     tile:function (pos) {
634         return this.getTile(pos);
635     },
636 
637     /**
638      * returns the tile at the given position
639      * @param {cc.Point} pos
640      * @return {cc.Quad3}
641      */
642     getTile: function(pos){
643         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
644             cc.log("cc.TiledGrid3D.tile() : Numbers must be integers");
645 
646         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
647         var locVertices = this._vertices;
648         return new cc.Quad3(new cc.Vertex3F(locVertices[idx], locVertices[idx + 1], locVertices[idx + 2]),
649             new cc.Vertex3F(locVertices[idx + 3], locVertices[idx + 4], locVertices[idx + 5]),
650             new cc.Vertex3F(locVertices[idx + 6 ], locVertices[idx + 7], locVertices[idx + 8]),
651             new cc.Vertex3F(locVertices[idx + 9], locVertices[idx + 10], locVertices[idx + 11]));
652     },
653 
654     /**
655      * returns the original tile (untransformed) at the given position
656      * @param {cc.Point} pos
657      * @return {cc.Quad3}
658      */
659     getOriginalTile:function (pos) {
660         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
661             cc.log("cc.TiledGrid3D.originalTile() : Numbers must be integers");
662 
663         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
664         var locOriginalVertices = this._originalVertices;
665         return new cc.Quad3(new cc.Vertex3F(locOriginalVertices[idx], locOriginalVertices[idx + 1], locOriginalVertices[idx + 2]),
666             new cc.Vertex3F(locOriginalVertices[idx + 3], locOriginalVertices[idx + 4], locOriginalVertices[idx + 5]),
667             new cc.Vertex3F(locOriginalVertices[idx + 6 ], locOriginalVertices[idx + 7], locOriginalVertices[idx + 8]),
668             new cc.Vertex3F(locOriginalVertices[idx + 9], locOriginalVertices[idx + 10], locOriginalVertices[idx + 11]));
669     },
670 
671     /**
672      * returns the original tile (untransformed) at the given position.      <br/>
673      * It will be deprecated in future, please use getOriginalTile instead.
674      * @param {cc.Point} pos
675      * @return {cc.Quad3}
676      */
677     originalTile: function(pos) {
678         return this.getOriginalTile(pos);
679     },
680 
681     /**
682      * sets a new tile
683      * @param {cc.Point} pos
684      * @param {cc.Quad3} coords
685      */
686     setTile:function (pos, coords) {
687         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
688             cc.log("cc.TiledGrid3D.setTile() : Numbers must be integers");
689 
690         var idx = (this._gridSize.height * pos.x + pos.y) * 12;
691         var locVertices = this._vertices;
692         locVertices[idx] = coords.bl.x;
693         locVertices[idx + 1] = coords.bl.y;
694         locVertices[idx + 2] = coords.bl.z;
695         locVertices[idx + 3] = coords.br.x;
696         locVertices[idx + 4] = coords.br.y;
697         locVertices[idx + 5] = coords.br.z;
698         locVertices[idx + 6] = coords.tl.x;
699         locVertices[idx + 7] = coords.tl.y;
700         locVertices[idx + 8] = coords.tl.z;
701         locVertices[idx + 9] = coords.tr.x;
702         locVertices[idx + 10] = coords.tr.y;
703         locVertices[idx + 11] = coords.tr.z;
704         this._dirty = true;
705     },
706 
707     blit: function (target) {
708         var n = this._gridSize.width * this._gridSize.height;
709 
710         var wt = target._renderCmd._worldTransform;
711         this._matrix.mat[0] = wt.a;
712         this._matrix.mat[4] = wt.c;
713         this._matrix.mat[12] = wt.tx;
714         this._matrix.mat[1] = wt.b;
715         this._matrix.mat[5] = wt.d;
716         this._matrix.mat[13] = wt.ty;
717 
718         this._shaderProgram.use();
719         this._shaderProgram._setUniformForMVPMatrixWithMat4(this._matrix);
720         //this._shaderProgram.setUniformsForBuiltins();
721 
722         //
723         // Attributes
724         //
725         var gl = cc._renderContext, locDirty = this._dirty;
726         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_POSITION);
727         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_TEX_COORDS);
728 
729         // position
730         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
731         if (locDirty)
732             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
733         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, this._vertices);
734 
735         // texCoords
736         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
737         if (locDirty)
738             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
739         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, this._texCoordinates);
740 
741         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
742         if (locDirty)
743             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
744         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
745         if (locDirty)
746             this._dirty = false;
747         cc.incrementGLDraws(1);
748     },
749 
750     reuse:function () {
751         if (this._reuseGrid > 0) {
752             var locVertices = this._vertices, locOriginalVertices = this._originalVertices;
753             for (var i = 0; i < locVertices.length; i++)
754                 locOriginalVertices[i] = locVertices[i];
755             --this._reuseGrid;
756         }
757     },
758 
759     calculateVertexPoints:function () {
760         var width = this._texture.pixelsWidth;
761         var height = this._texture.pixelsHeight;
762         var imageH = this._texture.getContentSizeInPixels().height;
763         var locGridSize = this._gridSize;
764 
765         var numQuads = locGridSize.width * locGridSize.height;
766         this._vertices = new Float32Array(numQuads * 12);
767         this._texCoordinates = new Float32Array(numQuads * 8);
768         this._indices = new Uint16Array(numQuads * 6);
769 
770         var gl = cc._renderContext;
771         if(this._verticesBuffer)
772             gl.deleteBuffer(this._verticesBuffer);
773         this._verticesBuffer = gl.createBuffer();
774         if(this._texCoordinateBuffer)
775             gl.deleteBuffer(this._texCoordinateBuffer);
776         this._texCoordinateBuffer = gl.createBuffer();
777         if(this._indicesBuffer)
778             gl.deleteBuffer(this._indicesBuffer);
779         this._indicesBuffer = gl.createBuffer();
780 
781         var x, y, i = 0;
782         var locStep = this._step, locVertices = this._vertices, locTexCoords = this._texCoordinates, locIsTextureFlipped = this._isTextureFlipped;
783         for (x = 0; x < locGridSize.width; x++) {
784             for (y = 0; y < locGridSize.height; y++) {
785                 var x1 = x * locStep.x;
786                 var x2 = x1 + locStep.x;
787                 var y1 = y * locStep.y;
788                 var y2 = y1 + locStep.y;
789 
790                 locVertices[i * 12] = x1;
791                 locVertices[i * 12 + 1] = y1;
792                 locVertices[i * 12 + 2] = 0;
793                 locVertices[i * 12 + 3] = x2;
794                 locVertices[i * 12 + 4] = y1;
795                 locVertices[i * 12 + 5] = 0;
796                 locVertices[i * 12 + 6] = x1;
797                 locVertices[i * 12 + 7] = y2;
798                 locVertices[i * 12 + 8] = 0;
799                 locVertices[i * 12 + 9] = x2;
800                 locVertices[i * 12 + 10] = y2;
801                 locVertices[i * 12 + 11] = 0;
802 
803                 var newY1 = y1;
804                 var newY2 = y2;
805 
806                 if (locIsTextureFlipped) {
807                     newY1 = imageH - y1;
808                     newY2 = imageH - y2;
809                 }
810 
811                 locTexCoords[i * 8] = x1 / width;
812                 locTexCoords[i * 8 + 1] = newY1 / height;
813                 locTexCoords[i * 8 + 2] = x2 / width;
814                 locTexCoords[i * 8 + 3] = newY1 / height;
815                 locTexCoords[i * 8 + 4] = x1 / width;
816                 locTexCoords[i * 8 + 5] = newY2 / height;
817                 locTexCoords[i * 8 + 6] = x2 / width;
818                 locTexCoords[i * 8 + 7] = newY2 / height;
819                 i++;
820             }
821         }
822 
823         var locIndices = this._indices;
824         for (x = 0; x < numQuads; x++) {
825             locIndices[x * 6 + 0] = (x * 4 + 0);
826             locIndices[x * 6 + 1] = (x * 4 + 1);
827             locIndices[x * 6 + 2] = (x * 4 + 2);
828 
829             locIndices[x * 6 + 3] = (x * 4 + 1);
830             locIndices[x * 6 + 4] = (x * 4 + 2);
831             locIndices[x * 6 + 5] = (x * 4 + 3);
832         }
833         this._originalVertices = new Float32Array(this._vertices);
834 
835         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
836         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
837         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
838         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
839         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
840         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.DYNAMIC_DRAW);
841         this._dirty = true;
842     }
843 });
844 
845 /**
846  * create one TiledGrid3D object
847  * @deprecated since v3.0, please use new cc.TiledGrid3D(gridSize, texture, flipped) instead
848  * @param {cc.Size} gridSize
849  * @param {cc.Texture2D} [texture=]
850  * @param {Boolean} [flipped=]
851  * @return {cc.TiledGrid3D}
852  */
853 cc.TiledGrid3D.create = function (gridSize, texture, flipped) {
854     return new cc.TiledGrid3D(gridSize, texture, flipped);
855 };
856