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