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