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         this._shaderProgram.use();
456         //this._shaderProgram.setUniformsForBuiltins();
457         this._shaderProgram._setUniformForMVPMatrixWithMat4(target._renderCmd._stackMatrix);
458 
459         var gl = cc._renderContext, locDirty = this._dirty;
460 
461         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_POSITION);
462         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_TEX_COORDS);
463         //
464         // Attributes
465         //
466         // position
467         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
468         if (locDirty)
469             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
470         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, 0);
471 
472         // texCoords
473         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
474         if (locDirty)
475             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
476         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, 0);
477 
478         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
479         if (locDirty)
480             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
481         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
482         if (locDirty)
483             this._dirty = false;
484         cc.incrementGLDraws(1);
485     },
486 
487     reuse:function () {
488         if (this._reuseGrid > 0) {
489             var locOriginalVertices = this._originalVertices, locVertices = this._vertices;
490             for (var i = 0, len =  this._vertices.length; i < len; i++)
491                 locOriginalVertices[i] = locVertices[i];
492             --this._reuseGrid;
493         }
494     },
495 
496     calculateVertexPoints:function () {
497         var gl = cc._renderContext;
498 
499         var width = this._texture.pixelsWidth;
500         var height = this._texture.pixelsHeight;
501         var imageH = this._texture.getContentSizeInPixels().height;
502         var locGridSize = this._gridSize;
503 
504         var numOfPoints = (locGridSize.width + 1) * (locGridSize.height + 1);
505         this._vertices = new Float32Array(numOfPoints * 3);
506         this._texCoordinates = new Float32Array(numOfPoints * 2);
507         this._indices = new Uint16Array(locGridSize.width * locGridSize.height * 6);
508 
509         if(this._verticesBuffer)
510             gl.deleteBuffer(this._verticesBuffer);
511         this._verticesBuffer = gl.createBuffer();
512         if(this._texCoordinateBuffer)
513             gl.deleteBuffer(this._texCoordinateBuffer);
514         this._texCoordinateBuffer = gl.createBuffer();
515         if(this._indicesBuffer)
516             gl.deleteBuffer(this._indicesBuffer);
517         this._indicesBuffer = gl.createBuffer();
518 
519         var x, y, i, locIndices = this._indices, locTexCoordinates = this._texCoordinates;
520         var locIsTextureFlipped = this._isTextureFlipped, locVertices = this._vertices;
521         for (x = 0; x < locGridSize.width; ++x) {
522             for (y = 0; y < locGridSize.height; ++y) {
523                 var idx = (y * locGridSize.width) + x;
524                 var x1 = x * this._step.x + this._gridRect.x;
525                 var x2 = x1 + this._step.x;
526                 var y1 = y * this._step.y + this._gridRect.y;
527                 var y2 = y1 + this._step.y;
528 
529                 var a = (x * (locGridSize.height + 1) + y);
530                 var b = ((x + 1) * (locGridSize.height + 1) + y);
531                 var c = ((x + 1) * (locGridSize.height + 1) + (y + 1));
532                 var d = (x * (locGridSize.height + 1) + (y + 1));
533 
534                 locIndices[idx * 6] = a;
535                 locIndices[idx * 6 + 1] = b;
536                 locIndices[idx * 6 + 2] = d;
537                 locIndices[idx * 6 + 3] = b;
538                 locIndices[idx * 6 + 4] = c;
539                 locIndices[idx * 6 + 5] = d;
540 
541                 var l1 = [a * 3, b * 3, c * 3, d * 3];
542                 var e = {x:x1, y:y1, z:0};   //new cc.Vertex3F(x1, y1, 0);
543                 var f = {x:x2, y:y1, z:0};   //new cc.Vertex3F(x2, y1, 0);
544                 var g = {x:x2, y:y2, z:0};   // new cc.Vertex3F(x2, y2, 0);
545                 var h = {x:x1, y:y2, z:0};   //new cc.Vertex3F(x1, y2, 0);
546 
547                 var l2 = [e, f, g, h];
548                 var tex1 = [a * 2, b * 2, c * 2, d * 2];
549                 var tex2 = [cc.p(x1, y1), cc.p(x2, y1), cc.p(x2, y2), cc.p(x1, y2)];
550                 for (i = 0; i < 4; ++i) {
551                     locVertices[l1[i]] = l2[i].x;
552                     locVertices[l1[i] + 1] = l2[i].y;
553                     locVertices[l1[i] + 2] = l2[i].z;
554                     locTexCoordinates[tex1[i]] = tex2[i].x / width;
555                     if (locIsTextureFlipped)
556                         locTexCoordinates[tex1[i] + 1] = (imageH - tex2[i].y) / height;
557                     else
558                         locTexCoordinates[tex1[i] + 1] = tex2[i].y / height;
559                 }
560             }
561         }
562         this._originalVertices = new Float32Array(this._vertices);
563 
564         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
565         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
566         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
567         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
568         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
569         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
570         this._dirty = true;
571     },
572 
573     setNeedDepthTestForBlit: function(needDepthTest){
574         this._needDepthTestForBlit = needDepthTest;
575     },
576 
577     getNeedDepthTestForBlit: function(){
578         return this._needDepthTestForBlit;
579     }
580 });
581 
582 /**
583  * create one Grid3D object
584  * @deprecated
585  * @param {cc.Size} gridSize
586  * @param {cc.Texture2D} [texture=]
587  * @param {Boolean} [flipped=]
588  * @return {cc.Grid3D}
589  */
590 cc.Grid3D.create = function (gridSize, texture, flipped) {
591     return new cc.Grid3D(gridSize, texture, flipped);
592 };
593 
594 /**
595  * cc.TiledGrid3D is a 3D grid implementation. It differs from Grid3D in that   <br/>
596  * the tiles can be separated from the grid.
597  * @class
598  * @extends cc.GridBase
599  */
600 cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{
601     _texCoordinates:null,
602     _vertices:null,
603     _originalVertices:null,
604     _indices:null,
605 
606     _texCoordinateBuffer:null,
607     _verticesBuffer:null,
608     _indicesBuffer:null,
609 
610     /**
611      * create one TiledGrid3D object
612      * Constructor of cc.TiledGrid3D
613      * @param {cc.Size} gridSize
614      * @param {cc.Texture2D} [texture=]
615      * @param {Boolean} [flipped=]
616      */
617     ctor:function (gridSize, texture, flipped, rect) {
618         cc.GridBase.prototype.ctor.call(this);
619         this._texCoordinates=null;
620         this._vertices=null;
621         this._originalVertices=null;
622         this._indices=null;
623 
624         this._texCoordinateBuffer=null;
625         this._verticesBuffer=null;
626         this._indicesBuffer=null;
627 
628         if(gridSize !== undefined)
629             this.initWithSize(gridSize, texture, flipped, rect);
630     },
631 
632     /**
633      * returns the tile at the given position    <br/>
634      * It will be deprecated in future, please use getTile instead.
635      * @param {cc.Point} pos
636      * @return {cc.Quad3}
637      */
638     tile:function (pos) {
639         return this.getTile(pos);
640     },
641 
642     /**
643      * returns the tile at the given position
644      * @param {cc.Point} pos
645      * @return {cc.Quad3}
646      */
647     getTile: function(pos){
648         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
649             cc.log("cc.TiledGrid3D.tile() : Numbers must be integers");
650 
651         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
652         var locVertices = this._vertices;
653         return new cc.Quad3(new cc.Vertex3F(locVertices[idx], locVertices[idx + 1], locVertices[idx + 2]),
654             new cc.Vertex3F(locVertices[idx + 3], locVertices[idx + 4], locVertices[idx + 5]),
655             new cc.Vertex3F(locVertices[idx + 6 ], locVertices[idx + 7], locVertices[idx + 8]),
656             new cc.Vertex3F(locVertices[idx + 9], locVertices[idx + 10], locVertices[idx + 11]));
657     },
658 
659     /**
660      * returns the original tile (untransformed) at the given position
661      * @param {cc.Point} pos
662      * @return {cc.Quad3}
663      */
664     getOriginalTile:function (pos) {
665         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
666             cc.log("cc.TiledGrid3D.originalTile() : Numbers must be integers");
667 
668         var idx = (this._gridSize.height * pos.x + pos.y) * 4 * 3;
669         var locOriginalVertices = this._originalVertices;
670         return new cc.Quad3(new cc.Vertex3F(locOriginalVertices[idx], locOriginalVertices[idx + 1], locOriginalVertices[idx + 2]),
671             new cc.Vertex3F(locOriginalVertices[idx + 3], locOriginalVertices[idx + 4], locOriginalVertices[idx + 5]),
672             new cc.Vertex3F(locOriginalVertices[idx + 6 ], locOriginalVertices[idx + 7], locOriginalVertices[idx + 8]),
673             new cc.Vertex3F(locOriginalVertices[idx + 9], locOriginalVertices[idx + 10], locOriginalVertices[idx + 11]));
674     },
675 
676     /**
677      * returns the original tile (untransformed) at the given position.      <br/>
678      * It will be deprecated in future, please use getOriginalTile instead.
679      * @param {cc.Point} pos
680      * @return {cc.Quad3}
681      */
682     originalTile: function(pos) {
683         return this.getOriginalTile(pos);
684     },
685 
686     /**
687      * sets a new tile
688      * @param {cc.Point} pos
689      * @param {cc.Quad3} coords
690      */
691     setTile:function (pos, coords) {
692         if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y))
693             cc.log("cc.TiledGrid3D.setTile() : Numbers must be integers");
694 
695         var idx = (this._gridSize.height * pos.x + pos.y) * 12;
696         var locVertices = this._vertices;
697         locVertices[idx] = coords.bl.x;
698         locVertices[idx + 1] = coords.bl.y;
699         locVertices[idx + 2] = coords.bl.z;
700         locVertices[idx + 3] = coords.br.x;
701         locVertices[idx + 4] = coords.br.y;
702         locVertices[idx + 5] = coords.br.z;
703         locVertices[idx + 6] = coords.tl.x;
704         locVertices[idx + 7] = coords.tl.y;
705         locVertices[idx + 8] = coords.tl.z;
706         locVertices[idx + 9] = coords.tr.x;
707         locVertices[idx + 10] = coords.tr.y;
708         locVertices[idx + 11] = coords.tr.z;
709         this._dirty = true;
710     },
711 
712     blit: function (target) {
713         var n = this._gridSize.width * this._gridSize.height;
714 
715         this._shaderProgram.use();
716         this._shaderProgram._setUniformForMVPMatrixWithMat4(target._renderCmd._stackMatrix);
717         //this._shaderProgram.setUniformsForBuiltins();
718 
719         //
720         // Attributes
721         //
722         var gl = cc._renderContext, locDirty = this._dirty;
723         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_POSITION);
724         gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_TEX_COORDS);
725 
726         // position
727         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
728         if (locDirty)
729             gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
730         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 0, this._vertices);
731 
732         // texCoords
733         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
734         if (locDirty)
735             gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
736         gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 0, this._texCoordinates);
737 
738         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
739         if (locDirty)
740             gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW);
741         gl.drawElements(gl.TRIANGLES, n * 6, gl.UNSIGNED_SHORT, 0);
742         if (locDirty)
743             this._dirty = false;
744         cc.incrementGLDraws(1);
745     },
746 
747     reuse:function () {
748         if (this._reuseGrid > 0) {
749             var locVertices = this._vertices, locOriginalVertices = this._originalVertices;
750             for (var i = 0; i < locVertices.length; i++)
751                 locOriginalVertices[i] = locVertices[i];
752             --this._reuseGrid;
753         }
754     },
755 
756     calculateVertexPoints:function () {
757         var width = this._texture.pixelsWidth;
758         var height = this._texture.pixelsHeight;
759         var imageH = this._texture.getContentSizeInPixels().height;
760         var locGridSize = this._gridSize;
761 
762         var numQuads = locGridSize.width * locGridSize.height;
763         this._vertices = new Float32Array(numQuads * 12);
764         this._texCoordinates = new Float32Array(numQuads * 8);
765         this._indices = new Uint16Array(numQuads * 6);
766 
767         var gl = cc._renderContext;
768         if(this._verticesBuffer)
769             gl.deleteBuffer(this._verticesBuffer);
770         this._verticesBuffer = gl.createBuffer();
771         if(this._texCoordinateBuffer)
772             gl.deleteBuffer(this._texCoordinateBuffer);
773         this._texCoordinateBuffer = gl.createBuffer();
774         if(this._indicesBuffer)
775             gl.deleteBuffer(this._indicesBuffer);
776         this._indicesBuffer = gl.createBuffer();
777 
778         var x, y, i = 0;
779         var locStep = this._step, locVertices = this._vertices, locTexCoords = this._texCoordinates, locIsTextureFlipped = this._isTextureFlipped;
780         for (x = 0; x < locGridSize.width; x++) {
781             for (y = 0; y < locGridSize.height; y++) {
782                 var x1 = x * locStep.x;
783                 var x2 = x1 + locStep.x;
784                 var y1 = y * locStep.y;
785                 var y2 = y1 + locStep.y;
786 
787                 locVertices[i * 12] = x1;
788                 locVertices[i * 12 + 1] = y1;
789                 locVertices[i * 12 + 2] = 0;
790                 locVertices[i * 12 + 3] = x2;
791                 locVertices[i * 12 + 4] = y1;
792                 locVertices[i * 12 + 5] = 0;
793                 locVertices[i * 12 + 6] = x1;
794                 locVertices[i * 12 + 7] = y2;
795                 locVertices[i * 12 + 8] = 0;
796                 locVertices[i * 12 + 9] = x2;
797                 locVertices[i * 12 + 10] = y2;
798                 locVertices[i * 12 + 11] = 0;
799 
800                 var newY1 = y1;
801                 var newY2 = y2;
802 
803                 if (locIsTextureFlipped) {
804                     newY1 = imageH - y1;
805                     newY2 = imageH - y2;
806                 }
807 
808                 locTexCoords[i * 8] = x1 / width;
809                 locTexCoords[i * 8 + 1] = newY1 / height;
810                 locTexCoords[i * 8 + 2] = x2 / width;
811                 locTexCoords[i * 8 + 3] = newY1 / height;
812                 locTexCoords[i * 8 + 4] = x1 / width;
813                 locTexCoords[i * 8 + 5] = newY2 / height;
814                 locTexCoords[i * 8 + 6] = x2 / width;
815                 locTexCoords[i * 8 + 7] = newY2 / height;
816                 i++;
817             }
818         }
819 
820         var locIndices = this._indices;
821         for (x = 0; x < numQuads; x++) {
822             locIndices[x * 6 + 0] = (x * 4 + 0);
823             locIndices[x * 6 + 1] = (x * 4 + 1);
824             locIndices[x * 6 + 2] = (x * 4 + 2);
825 
826             locIndices[x * 6 + 3] = (x * 4 + 1);
827             locIndices[x * 6 + 4] = (x * 4 + 2);
828             locIndices[x * 6 + 5] = (x * 4 + 3);
829         }
830         this._originalVertices = new Float32Array(this._vertices);
831 
832         gl.bindBuffer(gl.ARRAY_BUFFER, this._verticesBuffer);
833         gl.bufferData(gl.ARRAY_BUFFER, this._vertices, gl.DYNAMIC_DRAW);
834         gl.bindBuffer(gl.ARRAY_BUFFER, this._texCoordinateBuffer);
835         gl.bufferData(gl.ARRAY_BUFFER, this._texCoordinates, gl.DYNAMIC_DRAW);
836         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer);
837         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.DYNAMIC_DRAW);
838         this._dirty = true;
839     }
840 });
841 
842 /**
843  * create one TiledGrid3D object
844  * @deprecated since v3.0, please use new cc.TiledGrid3D(gridSize, texture, flipped) instead
845  * @param {cc.Size} gridSize
846  * @param {cc.Texture2D} [texture=]
847  * @param {Boolean} [flipped=]
848  * @return {cc.TiledGrid3D}
849  */
850 cc.TiledGrid3D.create = function (gridSize, texture, flipped) {
851     return new cc.TiledGrid3D(gridSize, texture, flipped);
852 };
853