1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2009      Jason Booth
  4  Copyright (c) 2008-2010 Ricardo Quesada
  5  Copyright (c) 2011      Zynga Inc.
  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  * enum for jpg
 30  * @constant
 31  * @type Number
 32  */
 33 cc.IMAGE_FORMAT_JPEG = 0;
 34 /**
 35  * enum for png
 36  * @constant
 37  * @type Number
 38  */
 39 cc.IMAGE_FORMAT_PNG = 1;
 40 /**
 41  * enum for raw
 42  * @constant
 43  * @type Number
 44  */
 45 cc.IMAGE_FORMAT_RAWDATA = 2;
 46 
 47 /**
 48  * @param {Number} x
 49  * @return {Number}
 50  * Constructor
 51  */
 52 cc.NextPOT = function (x) {
 53     x = x - 1;
 54     x = x | (x >> 1);
 55     x = x | (x >> 2);
 56     x = x | (x >> 4);
 57     x = x | (x >> 8);
 58     x = x | (x >> 16);
 59     return x + 1;
 60 };
 61 
 62 /**
 63  * cc.RenderTexture is a generic rendering target. To render things into it,<br/>
 64  * simply construct a render target, call begin on it, call visit on any cocos<br/>
 65  * scenes or objects to render them, and call end. For convenience, render texture<br/>
 66  * adds a sprite as it's display child with the results, so you can simply add<br/>
 67  * the render texture to your scene and treat it like any other CocosNode.<br/>
 68  * There are also functions for saving the render texture to disk in PNG or JPG format.
 69  * @class
 70  * @extends cc.Node
 71  */
 72 cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{
 73     /**
 74      * the off-screen canvas for rendering and storing the texture
 75      * @type HTMLCanvasElement
 76      */
 77     _cacheCanvas:null,
 78     /**
 79      * stores a reference to the canvas context object
 80      * @type CanvasRenderingContext2D
 81      */
 82     _cacheContext:null,
 83 
 84     _fBO:0,
 85     _depthRenderBuffer:0,
 86     _oldFBO:0,
 87     _texture:null,
 88     _textureCopy:null,
 89     _uITextureImage:null,
 90 
 91     _pixelFormat:cc.TEXTURE_2D_PIXEL_FORMAT_RGBA8888,
 92     _sprite:null,
 93 
 94     //code for "auto" update
 95     _clearFlags:0,
 96     _clearColor:null,
 97     _clearDepth:0,
 98     _clearStencil:0,
 99     _autoDraw:false,
100 
101     _clearColorStr:null,
102 
103     /**
104      * Constructor
105      */
106     ctor: null,
107 
108     _ctorForCanvas: function () {
109         cc.Node.prototype.ctor.call(this);
110         this._clearColor = cc.c4f(1, 1, 1, 1);
111         this._clearColorStr = "rgba(255,255,255,1)";
112 
113         this._cacheCanvas = document.createElement('canvas');
114         this._cacheContext = this._cacheCanvas.getContext('2d');
115         this.setAnchorPoint(0, 0);
116     },
117 
118     _ctorForWebGL: function () {
119         cc.Node.prototype.ctor.call(this);
120         this._clearColor = cc.c4f(0, 0, 0, 0);
121     },
122 
123     cleanup:null,
124 
125     _cleanupForCanvas:function () {
126         cc.Node.prototype.onExit.call(this);
127         this._cacheContext = null;
128         this._cacheCanvas = null;
129     },
130 
131     _cleanupForWebGL: function () {
132         cc.Node.prototype.onExit.call(this);
133 
134         //this._sprite = null;
135         this._textureCopy = null;
136 
137         var gl = cc.renderContext;
138         gl.deleteFramebuffer(this._fBO);
139         if (this._depthRenderBuffer)
140             gl.deleteRenderbuffer(this._depthRenderBuffer);
141         this._uITextureImage = null;
142         //if (this._texture)
143         //    this._texture.releaseTexture();
144     },
145 
146     /**
147      * The sprite
148      * @return {cc.Sprite}
149      */
150     getSprite:function () {
151         return this._sprite;
152     },
153 
154     /**
155      * @param {cc.Sprite} sprite
156      */
157     setSprite:function (sprite) {
158         this._sprite = sprite;
159     },
160 
161     /**
162      * @param {Number} width
163      * @param {Number} height
164      * @param {cc.IMAGE_FORMAT_JPEG|cc.IMAGE_FORMAT_PNG|cc.IMAGE_FORMAT_RAWDATA} format
165      * @param {Number} depthStencilFormat
166      * @return {Boolean}
167      */
168     initWithWidthAndHeight: null,
169 
170     _initWithWidthAndHeightForCanvas: function (width, height, format, depthStencilFormat) {
171         var locCacheCanvas = this._cacheCanvas, locScaleFactor = cc.CONTENT_SCALE_FACTOR();
172         locCacheCanvas.width = 0 | (width * locScaleFactor);
173         locCacheCanvas.height = 0 | (height * locScaleFactor);
174         this._cacheContext.translate(0, locCacheCanvas.height);
175         var texture = new cc.Texture2D();
176         texture.initWithElement(locCacheCanvas);
177         texture.handleLoadedTexture();
178         this._sprite = cc.Sprite.createWithTexture(texture);
179         return true;
180     },
181 
182     _initWithWidthAndHeightForWebGL: function (width, height, format, depthStencilFormat) {
183         if(format == cc.TEXTURE_2D_PIXEL_FORMAT_A8)
184             cc.log( "cc.RenderTexture._initWithWidthAndHeightForWebGL() : only RGB and RGBA formats are valid for a render texture;");
185 
186         var gl = cc.renderContext, locScaleFactor = cc.CONTENT_SCALE_FACTOR();
187 
188         width = 0 | (width * locScaleFactor);
189         height = 0 | (height * locScaleFactor);
190 
191         this._oldFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING);
192 
193         // textures must be power of two squared
194         var powW , powH;
195 
196         if (cc.Configuration.getInstance().supportsNPOT()) {
197             powW = width;
198             powH = height;
199         } else {
200             powW = cc.NextPOT(width);
201             powH = cc.NextPOT(height);
202         }
203 
204         //void *data = malloc(powW * powH * 4);
205         var dataLen = powW * powH * 4;
206         var data = new Uint8Array(dataLen);
207         //memset(data, 0, (int)(powW * powH * 4));
208         for (var i = 0; i < powW * powH * 4; i++)
209             data[i] = 0;
210 
211         this._pixelFormat = format;
212 
213         this._texture = new cc.Texture2D();
214         if (!this._texture)
215             return false;
216 
217         var locTexture = this._texture;
218         locTexture.initWithData(data, this._pixelFormat, powW, powH, cc.size(width, height));
219         //free( data );
220 
221         var oldRBO = gl.getParameter(gl.RENDERBUFFER_BINDING);
222 
223         if (cc.Configuration.getInstance().checkForGLExtension("GL_QCOM")) {
224             this._textureCopy = new cc.Texture2D();
225             if (!this._textureCopy) {
226                 return false;
227             }
228             this._textureCopy.initWithData(data, this._pixelFormat, powW, powH, cc.size(width, height));
229         }
230 
231         // generate FBO
232         this._fBO = gl.createFramebuffer();
233         gl.bindFramebuffer(gl.FRAMEBUFFER, this._fBO);
234 
235         // associate texture with FBO
236         gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, locTexture._webTextureObj, 0);
237 
238         if (depthStencilFormat != 0) {
239             //create and attach depth buffer
240             this._depthRenderBuffer = gl.createRenderbuffer();
241             gl.bindRenderbuffer(gl.RENDERBUFFER, this._depthRenderBuffer);
242             gl.renderbufferStorage(gl.RENDERBUFFER, depthStencilFormat, powW, powH);
243             gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this._depthRenderBuffer);
244 
245             // if depth format is the one with stencil part, bind same render buffer as stencil attachment
246             //if (depthStencilFormat == gl.DEPTH24_STENCIL8)
247             //    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this._depthRenderBuffer);
248         }
249 
250         // check if it worked (probably worth doing :) )
251         if(gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE)
252             cc.log("Could not attach texture to the framebuffer");
253 
254         locTexture.setAliasTexParameters();
255 
256         this._sprite = cc.Sprite.createWithTexture(locTexture);
257         var locSprite = this._sprite;
258         locSprite.setScaleY(-1);
259         locSprite.setBlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
260 
261         gl.bindRenderbuffer(gl.RENDERBUFFER, oldRBO);
262         gl.bindFramebuffer(gl.FRAMEBUFFER, this._oldFBO);
263 
264         // Disabled by default.
265         this._autoDraw = false;
266 
267         // add sprite for backward compatibility
268         this.addChild(locSprite);
269         return true;
270     },
271 
272     /**
273      * starts grabbing
274      */
275     begin: null,
276 
277     _beginForCanvas: function () {
278         cc.renderContext = this._cacheContext;
279         cc.EGLView.getInstance()._setScaleXYForRenderTexture();
280 
281         /*// Save the current matrix
282          cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
283          cc.kmGLPushMatrix();
284          cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
285          cc.kmGLPushMatrix();*/
286     },
287 
288     _beginForWebGL: function () {
289         // Save the current matrix
290         cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
291         cc.kmGLPushMatrix();
292         cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
293         cc.kmGLPushMatrix();
294 
295         var director = cc.Director.getInstance();
296         director.setProjection(director.getProjection());
297 
298         var texSize = this._texture.getContentSizeInPixels();
299 
300         // Calculate the adjustment ratios based on the old and new projections
301         var size = cc.Director.getInstance().getWinSizeInPixels();
302         var widthRatio = size.width / texSize.width;
303         var heightRatio = size.height / texSize.height;
304 
305         var gl = cc.renderContext;
306 
307         // Adjust the orthographic projection and viewport
308         gl.viewport(0, 0, texSize.width, texSize.height);
309 
310         var orthoMatrix = new cc.kmMat4();
311         cc.kmMat4OrthographicProjection(orthoMatrix, -1.0 / widthRatio, 1.0 / widthRatio,
312             -1.0 / heightRatio, 1.0 / heightRatio, -1, 1);
313         cc.kmGLMultMatrix(orthoMatrix);
314 
315         this._oldFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING);
316         gl.bindFramebuffer(gl.FRAMEBUFFER, this._fBO);//Will direct drawing to the frame buffer created above
317 
318         /*  Certain Qualcomm Andreno gpu's will retain data in memory after a frame buffer switch which corrupts the render to the texture.
319          *   The solution is to clear the frame buffer before rendering to the texture. However, calling glClear has the unintended result of clearing the current texture.
320          *   Create a temporary texture to overcome this. At the end of CCRenderTexture::begin(), switch the attached texture to the second one, call glClear,
321          *   and then switch back to the original texture. This solution is unnecessary for other devices as they don't have the same issue with switching frame buffers.
322          */
323         if (cc.Configuration.getInstance().checkForGLExtension("GL_QCOM")) {
324             // -- bind a temporary texture so we can clear the render buffer without losing our texture
325             gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._textureCopy._webTextureObj, 0);
326             //cc.CHECK_GL_ERROR_DEBUG();
327             gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
328             gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._texture._webTextureObj, 0);
329         }
330     },
331 
332     /**
333      * starts rendering to the texture while clearing the texture first.<br/>
334      * This is more efficient then calling -clear first and then -begin
335      * @param {Number} r red 0-1
336      * @param {Number} g green 0-1
337      * @param {Number} b blue 0-1
338      * @param {Number} a alpha 0-1 0 is transparent
339      * @param {Number} [depthValue=]
340      * @param {Number} [stencilValue=]
341      */
342     beginWithClear:function (r, g, b, a, depthValue, stencilValue) {
343         var gl = cc.renderContext;
344         depthValue = depthValue || gl.COLOR_BUFFER_BIT;
345         stencilValue = stencilValue || (gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
346 
347         this._beginWithClear(r, g, b, a, depthValue, stencilValue, (gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT));
348     },
349 
350     _beginWithClear: null,
351 
352     _beginWithClearForCanvas: function (r, g, b, a, depthValue, stencilValue, flags) {
353         this.begin();
354 
355         r = r || 0;
356         g = g || 0;
357         b = b || 0;
358         a = isNaN(a) ? 1 : a;
359 
360         //var context = cc.renderContext;
361         var context = this._cacheContext;
362         var locCanvas = this._cacheCanvas;
363         context.save();
364         context.fillStyle = "rgba(" + (0 | (r * 255)) + "," + (0 | (g * 255)) + "," + (0 | (b * 255)) + "," + a + ")";
365         context.clearRect(0, 0, locCanvas.width, -locCanvas.height);
366         context.fillRect(0, 0, locCanvas.width, -locCanvas.height);
367         context.restore();
368     },
369 
370     _beginWithClearForWebGL: function (r, g, b, a, depthValue, stencilValue, flags) {
371         this.begin();
372 
373         var gl = cc.renderContext;
374 
375         // save clear color
376         var clearColor = [0.0, 0.0, 0.0, 0.0];
377         var depthClearValue = 0.0;
378         var stencilClearValue = 0;
379 
380         if (flags & gl.COLOR_BUFFER_BIT) {
381             clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
382             gl.clearColor(r, g, b, a);
383         }
384 
385         if (flags & gl.DEPTH_BUFFER_BIT) {
386             depthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
387             gl.clearDepth(depthValue);
388         }
389 
390         if (flags & gl.STENCIL_BUFFER_BIT) {
391             stencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE);
392             gl.clearStencil(stencilValue);
393         }
394 
395         gl.clear(flags);
396 
397         // restore
398         if (flags & gl.COLOR_BUFFER_BIT)
399             gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
400 
401         if (flags & gl.DEPTH_BUFFER_BIT)
402             gl.clearDepth(depthClearValue);
403 
404         if (flags & gl.STENCIL_BUFFER_BIT)
405             gl.clearStencil(stencilClearValue);
406     },
407 
408     /**
409      * ends grabbing
410      */
411     end: null,
412 
413     _endForCanvas: function () {
414         cc.renderContext = cc.mainRenderContextBackup;
415         cc.EGLView.getInstance()._resetScale();
416 
417         //TODO
418         /*//restore viewport
419          director.setViewport();
420          cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
421          cc.kmGLPopMatrix();
422          cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
423          cc.kmGLPopMatrix();*/
424     },
425 
426     _endForWebGL: function () {
427         var gl = cc.renderContext;
428         var director = cc.Director.getInstance();
429         gl.bindFramebuffer(gl.FRAMEBUFFER, this._oldFBO);
430 
431         //restore viewport
432         director.setViewport();
433         cc.kmGLMatrixMode(cc.KM_GL_PROJECTION);
434         cc.kmGLPopMatrix();
435         cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW);
436         cc.kmGLPopMatrix();
437 
438         /* var size = director.getWinSizeInPixels();
439 
440          // restore viewport
441          gl.viewport(0, 0, size.width * cc.CONTENT_SCALE_FACTOR(), size.height * cc.CONTENT_SCALE_FACTOR());
442 
443          // special viewport for 3d projection + retina display
444          if (director.getProjection() == cc.DIRECTOR_PROJECTION_3D && cc.CONTENT_SCALE_FACTOR() != 1) {
445          gl.viewport((-size.width / 2), (-size.height / 2), (size.width * cc.CONTENT_SCALE_FACTOR()), (size.height * cc.CONTENT_SCALE_FACTOR()));
446          }
447 
448          director.setProjection(director.getProjection());*/
449     },
450 
451     /**
452      * clears the texture with a color
453      * @param {Number|cc.Rect} r red 0-1
454      * @param {Number} g green 0-1
455      * @param {Number} b blue 0-1
456      * @param {Number} a alpha 0-1
457      */
458     clear:function (r, g, b, a) {
459         this.beginWithClear(r, g, b, a);
460         this.end();
461     },
462 
463     clearRect:null,
464 
465     _clearRectForCanvas:function(x, y, width, height){
466         this._cacheContext.clearRect(x, y, width, -height);
467     },
468 
469     _clearRectForWebGL:function(x, y, width, height){
470         //TODO need to implement
471     },
472 
473     /**
474      * clears the texture with a specified depth value
475      * @param {Number} depthValue
476      */
477     clearDepth:null,
478 
479     _clearDepthForCanvas:function (depthValue) {
480         cc.log("clearDepth isn't supported on Cocos2d-Html5");
481     },
482 
483     _clearDepthForWebGL:function (depthValue) {
484         this.begin();
485 
486         var gl = cc.renderContext;
487         //! save old depth value
488         var depthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
489 
490         gl.clearDepth(depthValue);
491         gl.clear(gl.DEPTH_BUFFER_BIT);
492 
493         // restore clear color
494         gl.clearDepth(depthClearValue);
495         this.end();
496     },
497 
498     /**
499      * clears the texture with a specified stencil value
500      * @param {Number} stencilValue
501      */
502     clearStencil:null,
503 
504     _clearStencilForCanvas:function (stencilValue) {
505         cc.log("clearDepth isn't supported on Cocos2d-Html5");
506     },
507 
508     _clearStencilForWebGL:function (stencilValue) {
509         var gl = cc.renderContext;
510         // save old stencil value
511         var stencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE);
512 
513         gl.clearStencil(stencilValue);
514         gl.clear(gl.STENCIL_BUFFER_BIT);
515 
516         // restore clear color
517         gl.clearStencil(stencilClearValue);
518     },
519 
520     visit:null,
521 
522     _visitForCanvas:function (ctx) {
523         // override visit.
524         // Don't call visit on its children
525         if (!this._visible)
526             return;
527 
528         ctx = ctx || cc.renderContext;
529         ctx.save();
530 
531         this.draw(ctx);                                                   // update children of RenderTexture before
532         this.transform(ctx);
533         this._sprite.visit();                                             // draw the RenderTexture
534 
535         ctx.restore();
536 
537         this._orderOfArrival = 0;
538     },
539 
540     _visitForWebGL:function (ctx) {
541         // override visit.
542         // Don't call visit on its children
543         if (!this._visible)
544             return;
545 
546         cc.kmGLPushMatrix();
547 
548         var locGrid = this._grid;
549         if (locGrid && locGrid.isActive()) {
550             locGrid.beforeDraw();
551             this.transformAncestors();
552         }
553 
554         this.transform(ctx);
555         this._sprite.visit();
556         this.draw(ctx);
557 
558         if (locGrid && locGrid.isActive())
559             locGrid.afterDraw(this);
560 
561         cc.kmGLPopMatrix();
562 
563         this._orderOfArrival = 0;
564     },
565 
566     draw:null,
567 
568     _drawForCanvas: function (ctx) {
569         ctx = ctx || cc.renderContext;
570         if (this._autoDraw) {
571             this.begin();
572 
573             if (this._clearFlags) {
574                 var locCanvas = this._cacheCanvas;
575                 ctx.save();
576                 ctx.fillStyle = this._clearColorStr;
577                 ctx.clearRect(0, 0, locCanvas.width, -locCanvas.height);
578                 ctx.fillRect(0, 0, locCanvas.width, -locCanvas.height);
579                 ctx.restore();
580             }
581 
582             //! make sure all children are drawn
583             this.sortAllChildren();
584             var locChildren = this._children;
585             var childrenLen = locChildren.length;
586             var selfSprite = this._sprite;
587             for (var i = 0; i < childrenLen; i++) {
588                 var getChild = locChildren[i];
589                 if (getChild != selfSprite)
590                     getChild.visit();
591             }
592 
593             this.end();
594         }
595     },
596 
597     _drawForWebGL: function (ctx) {
598         var gl = cc.renderContext;
599         if (this._autoDraw) {
600             this.begin();
601 
602             var locClearFlags = this._clearFlags;
603             if (locClearFlags) {
604                 var oldClearColor = [0.0, 0.0, 0.0, 0.0];
605                 var oldDepthClearValue = 0.0;
606                 var oldStencilClearValue = 0;
607 
608                 // backup and set
609                 if (locClearFlags & gl.COLOR_BUFFER_BIT) {
610                     oldClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
611                     gl.clearColor(this._clearColor.r, this._clearColor.g, this._clearColor.b, this._clearColor.a);
612                 }
613 
614                 if (locClearFlags & gl.DEPTH_BUFFER_BIT) {
615                     oldDepthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE);
616                     gl.clearDepth(this._clearDepth);
617                 }
618 
619                 if (locClearFlags & gl.STENCIL_BUFFER_BIT) {
620                     oldStencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE);
621                     gl.clearStencil(this._clearStencil);
622                 }
623 
624                 // clear
625                 gl.clear(locClearFlags);
626 
627                 // restore
628                 if (locClearFlags & gl.COLOR_BUFFER_BIT)
629                     gl.clearColor(oldClearColor[0], oldClearColor[1], oldClearColor[2], oldClearColor[3]);
630 
631                 if (locClearFlags & gl.DEPTH_BUFFER_BIT)
632                     gl.clearDepth(oldDepthClearValue);
633 
634                 if (locClearFlags & gl.STENCIL_BUFFER_BIT)
635                     gl.clearStencil(oldStencilClearValue);
636             }
637 
638             //! make sure all children are drawn
639             this.sortAllChildren();
640             var locChildren = this._children;
641             for (var i = 0; i < locChildren.length; i++) {
642                 var getChild = locChildren[i];
643                 if (getChild != this._sprite)
644                     getChild.visit();
645             }
646 
647             this.end();
648         }
649     },
650 
651     /**
652      * creates a new CCImage from with the texture's data. Caller is responsible for releasing it by calling delete.
653      * @return {cc.Image}
654      */
655     newCCImage:null,
656 
657     _newCCImageForCanvas:function (flipImage) {
658         cc.log("saveToFile isn't supported on Cocos2d-Html5");
659         return null;
660     },
661 
662     _newCCImageForWebGL:function (flipImage) {
663         cc.log("saveToFile isn't supported on Cocos2d-Html5");
664 
665         if(flipImage === null)
666             flipImage = true;
667         cc.Assert(this._pixelFormat == cc.TEXTURE_2D_PIXEL_FORMAT_RGBA8888, "only RGBA8888 can be saved as image");
668 
669         if (!this._texture)
670             return null;
671 
672         var size = this._texture.getContentSizeInPixels();
673 
674         // to get the image size to save
675         //        if the saving image domain exeeds the buffer texture domain,
676         //        it should be cut
677         var nSavedBufferWidth = size.width;
678         var nSavedBufferHeight = size.height;
679 
680         var pImage = new cc.Image();
681         var gl = cc.renderContext;
682 
683         var pBuffer = new Uint8Array(nSavedBufferWidth * nSavedBufferHeight * 4);
684         if (!(pBuffer))
685             return pImage;
686 
687         var pTempData = new Uint8Array(nSavedBufferWidth * nSavedBufferHeight * 4);
688         if (!(pTempData))
689             return null;
690 
691         this.begin();
692         gl.pixelStorei(gl.PACK_ALIGNMENT, 1);
693         gl.readPixels(0, 0, nSavedBufferWidth, nSavedBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pTempData);
694         this.end();
695 
696         // to get the actual texture data
697         // #640 the image read from rendertexture is upseted
698         for (var i = 0; i < nSavedBufferHeight; ++i) {
699             this._memcpy(pBuffer, i * nSavedBufferWidth * 4,
700                 pTempData, (nSavedBufferHeight - i - 1) * nSavedBufferWidth * 4,
701                 nSavedBufferWidth * 4);
702         }
703         pImage.initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, cc.FMT_RAWDATA, nSavedBufferWidth, nSavedBufferHeight, 8);
704 
705         pBuffer = null;
706         pTempData = null;
707         return pImage;
708     },
709 
710     _memcpy:function (destArr, destIndex, srcArr, srcIndex, size) {
711         for (var i = 0; i < size; i++) {
712             destArr[destIndex + i] = srcArr[srcIndex + i];
713         }
714     },
715 
716     /**
717      * saves the texture into a file using JPEG format. The file will be saved in the Documents folder.
718      * Returns YES if the operation is successful.
719      * (doesn't support in HTML5)
720      * @param {Number} filePath
721      * @param {Number} format
722      */
723     saveToFile:function (filePath, format) {
724         cc.log("saveToFile isn't supported on Cocos2d-Html5");
725     },
726 
727     /**
728      * Listen "come to background" message, and save render texture. It only has effect on Android.
729      * @param {cc.Class} obj
730      */
731     listenToBackground:function (obj) {
732         cc.log("listenToBackground isn't supported on Cocos2d-Html5");
733     },
734 
735     /**
736      * Listen "come to foreground" message and restore the frame buffer object. It only has effect on Android.
737      * @param {cc.Class} obj
738      */
739     listenToForeground:function (obj) {
740         cc.log("listenToForeground isn't supported on Cocos2d-Html5");
741     },
742 
743     /**
744      * Valid flags: GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT. They can be OR'ed. Valid when "autoDraw is YES.
745      * @return {Number}
746      */
747     getClearFlags:function () {
748         return this._clearFlags;
749     },
750 
751     setClearFlags:function (clearFlags) {
752         this._clearFlags = clearFlags;
753     },
754 
755     /**
756      * Clear color value. Valid only when "autoDraw" is true.
757      * @return {cc.Color4F}
758      */
759     getClearColor:function () {
760         return this._clearColor;
761     },
762 
763     setClearColor:null,
764 
765     _setClearColorForCanvas:function (clearColor) {
766         var locClearColor = this._clearColor;
767         locClearColor.r = clearColor.r;
768         locClearColor.g = clearColor.g;
769         locClearColor.b = clearColor.b;
770         locClearColor.a = clearColor.a;
771 
772         this._clearColorStr = "rgba(" + (0 | (clearColor.r * 255)) + "," + (0 | (clearColor.g * 255)) + "," + (0 | (clearColor.b * 255)) + "," + clearColor.a + ")";
773     },
774 
775     _setClearColorForWebGL:function (clearColor) {
776         var locClearColor = this._clearColor;
777         locClearColor.r = clearColor.r;
778         locClearColor.g = clearColor.g;
779         locClearColor.b = clearColor.b;
780         locClearColor.a = clearColor.a;
781     },
782 
783     /**
784      * Value for clearDepth. Valid only when autoDraw is true.
785      * @return {Number}
786      */
787     getClearDepth:function () {
788         return this._clearDepth;
789     },
790 
791     setClearDepth:function (clearDepth) {
792         this._clearDepth = clearDepth;
793     },
794 
795     /**
796      * Value for clear Stencil. Valid only when autoDraw is true
797      * @return {Number}
798      */
799     getClearStencil:function () {
800         return this._clearStencil;
801     },
802 
803     setClearStencil:function (clearStencil) {
804         this._clearStencil = clearStencil;
805     },
806 
807     /**
808      * When enabled, it will render its children into the texture automatically. Disabled by default for compatiblity reasons. <br/>
809      * Will be enabled in the future.
810      * @return {Boolean}
811      */
812     isAutoDraw:function () {
813         return this._autoDraw;
814     },
815 
816     setAutoDraw:function (autoDraw) {
817         this._autoDraw = autoDraw;
818     }
819 });
820 
821 if(cc.Browser.supportWebGL){
822     cc.RenderTexture.prototype.ctor = cc.RenderTexture.prototype._ctorForWebGL;
823     cc.RenderTexture.prototype.cleanup = cc.RenderTexture.prototype._cleanupForWebGL;
824     cc.RenderTexture.prototype.initWithWidthAndHeight = cc.RenderTexture.prototype._initWithWidthAndHeightForWebGL;
825     cc.RenderTexture.prototype.begin = cc.RenderTexture.prototype._beginForWebGL;
826     cc.RenderTexture.prototype._beginWithClear = cc.RenderTexture.prototype._beginWithClearForWebGL;
827     cc.RenderTexture.prototype.end = cc.RenderTexture.prototype._endForWebGL;
828     cc.RenderTexture.prototype.clearRect = cc.RenderTexture.prototype._clearRectForWebGL;
829     cc.RenderTexture.prototype.clearDepth = cc.RenderTexture.prototype._clearDepthForWebGL;
830     cc.RenderTexture.prototype.clearStencil = cc.RenderTexture.prototype._clearStencilForWebGL;
831     cc.RenderTexture.prototype.visit = cc.RenderTexture.prototype._visitForWebGL;
832     cc.RenderTexture.prototype.draw = cc.RenderTexture.prototype._drawForWebGL;
833     cc.RenderTexture.prototype.newCCImage = cc.RenderTexture.prototype._newCCImageForWebGL;
834     cc.RenderTexture.prototype.setClearColor = cc.RenderTexture.prototype._setClearColorForWebGL;
835 } else {
836     cc.RenderTexture.prototype.ctor = cc.RenderTexture.prototype._ctorForCanvas;
837     cc.RenderTexture.prototype.cleanup = cc.RenderTexture.prototype._cleanupForCanvas;
838     cc.RenderTexture.prototype.initWithWidthAndHeight = cc.RenderTexture.prototype._initWithWidthAndHeightForCanvas;
839     cc.RenderTexture.prototype.begin = cc.RenderTexture.prototype._beginForCanvas;
840     cc.RenderTexture.prototype._beginWithClear = cc.RenderTexture.prototype._beginWithClearForCanvas;
841     cc.RenderTexture.prototype.end = cc.RenderTexture.prototype._endForCanvas;
842     cc.RenderTexture.prototype.clearRect = cc.RenderTexture.prototype._clearRectForCanvas;
843     cc.RenderTexture.prototype.clearDepth = cc.RenderTexture.prototype._clearDepthForCanvas;
844     cc.RenderTexture.prototype.clearStencil = cc.RenderTexture.prototype._clearStencilForCanvas;
845     cc.RenderTexture.prototype.visit = cc.RenderTexture.prototype._visitForCanvas;
846     cc.RenderTexture.prototype.draw = cc.RenderTexture.prototype._drawForCanvas;
847     cc.RenderTexture.prototype.newCCImage = cc.RenderTexture.prototype._newCCImageForCanvas;
848     cc.RenderTexture.prototype.setClearColor = cc.RenderTexture.prototype._setClearColorForCanvas;
849 }
850 
851 /**
852  * creates a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid
853  * @param {Number} width
854  * @param {Number} height
855  * @param {cc.IMAGE_FORMAT_JPEG|cc.IMAGE_FORMAT_PNG|cc.IMAGE_FORMAT_RAWDATA} format
856  * @param {Number} depthStencilFormat
857  * @return {cc.RenderTexture}
858  * @example
859  * // Example
860  * var rt = cc.RenderTexture.create()
861  */
862 cc.RenderTexture.create = function (width, height, format, depthStencilFormat) {
863     format = format || cc.TEXTURE_2D_PIXEL_FORMAT_RGBA8888;
864     depthStencilFormat = depthStencilFormat || 0;
865 
866     var ret = new cc.RenderTexture();
867     if (ret && ret.initWithWidthAndHeight(width, height, format, depthStencilFormat))
868         return ret;
869     return null;
870 };
871