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