'use strict' var createTexture = require('gl-texture2d') module.exports = createFBO var colorAttachmentArrays = null var FRAMEBUFFER_UNSUPPORTED var FRAMEBUFFER_INCOMPLETE_ATTACHMENT var FRAMEBUFFER_INCOMPLETE_DIMENSIONS var FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT function saveFBOState(gl) { var fbo = gl.getParameter(gl.FRAMEBUFFER_BINDING) var rbo = gl.getParameter(gl.RENDERBUFFER_BINDING) var tex = gl.getParameter(gl.TEXTURE_BINDING_2D) return [fbo, rbo, tex] } function restoreFBOState(gl, data) { gl.bindFramebuffer(gl.FRAMEBUFFER, data[0]) gl.bindRenderbuffer(gl.RENDERBUFFER, data[1]) gl.bindTexture(gl.TEXTURE_2D, data[2]) } function lazyInitColorAttachments(gl, ext) { var maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL) colorAttachmentArrays = new Array(maxColorAttachments + 1) for(var i=0; i<=maxColorAttachments; ++i) { var x = new Array(maxColorAttachments) for(var j=0; j 1) { ext.drawBuffersWEBGL(colorAttachmentArrays[numColors]) } //Allocate depth/stencil buffers var WEBGL_depth_texture = gl.getExtension('WEBGL_depth_texture') if(WEBGL_depth_texture) { if(useStencil) { fbo.depth = initTexture(gl, width, height, WEBGL_depth_texture.UNSIGNED_INT_24_8_WEBGL, gl.DEPTH_STENCIL, gl.DEPTH_STENCIL_ATTACHMENT) } else if(useDepth) { fbo.depth = initTexture(gl, width, height, gl.UNSIGNED_SHORT, gl.DEPTH_COMPONENT, gl.DEPTH_ATTACHMENT) } } else { if(useDepth && useStencil) { fbo._depth_rb = initRenderBuffer(gl, width, height, gl.DEPTH_STENCIL, gl.DEPTH_STENCIL_ATTACHMENT) } else if(useDepth) { fbo._depth_rb = initRenderBuffer(gl, width, height, gl.DEPTH_COMPONENT16, gl.DEPTH_ATTACHMENT) } else if(useStencil) { fbo._depth_rb = initRenderBuffer(gl, width, height, gl.STENCIL_INDEX, gl.STENCIL_ATTACHMENT) } } //Check frame buffer state var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER) if(status !== gl.FRAMEBUFFER_COMPLETE) { //Release all partially allocated resources fbo._destroyed = true //Release all resources gl.bindFramebuffer(gl.FRAMEBUFFER, null) gl.deleteFramebuffer(fbo.handle) fbo.handle = null if(fbo.depth) { fbo.depth.dispose() fbo.depth = null } if(fbo._depth_rb) { gl.deleteRenderbuffer(fbo._depth_rb) fbo._depth_rb = null } for(var i=0; i maxFBOSize || h < 0 || h > maxFBOSize) { throw new Error('gl-fbo: Can\'t resize FBO, invalid dimensions') } //Update shape fbo._shape[0] = w fbo._shape[1] = h //Save framebuffer state var state = saveFBOState(gl) //Resize framebuffer attachments for(var i=0; i maxFBOSize || height < 0 || height > maxFBOSize) { throw new Error('gl-fbo: Parameters are too large for FBO') } //Handle each option type options = options || {} //Figure out number of color buffers to use var numColors = 1 if('color' in options) { numColors = Math.max(options.color|0, 0) if(numColors < 0) { throw new Error('gl-fbo: Must specify a nonnegative number of colors') } if(numColors > 1) { //Check if multiple render targets supported if(!WEBGL_draw_buffers) { throw new Error('gl-fbo: Multiple draw buffer extension not supported') } else if(numColors > gl.getParameter(WEBGL_draw_buffers.MAX_COLOR_ATTACHMENTS_WEBGL)) { throw new Error('gl-fbo: Context does not support ' + numColors + ' draw buffers') } } } //Determine whether to use floating point textures var colorType = gl.UNSIGNED_BYTE var OES_texture_float = gl.getExtension('OES_texture_float') if(options.float && numColors > 0) { if(!OES_texture_float) { throw new Error('gl-fbo: Context does not support floating point textures') } colorType = gl.FLOAT } else if(options.preferFloat && numColors > 0) { if(OES_texture_float) { colorType = gl.FLOAT } } //Check if we should use depth buffer var useDepth = true if('depth' in options) { useDepth = !!options.depth } //Check if we should use a stencil buffer var useStencil = false if('stencil' in options) { useStencil = !!options.stencil } return new Framebuffer( gl, width, height, colorType, numColors, useDepth, useStencil, WEBGL_draw_buffers) }