UNPKG

@thi.ng/webgl

Version:

WebGL & GLSL abstraction layer

106 lines (105 loc) 3.04 kB
import { assert } from "@thi.ng/errors/assert"; import { TEX_FORMATS } from "./api/texture.js"; import { isGL2Context } from "./checks.js"; import { error } from "./error.js"; import { RBO } from "./rbo.js"; const GL_COLOR_ATTACHMENT0_WEBGL = 36064; const GL_MAX_COLOR_ATTACHMENTS_WEBGL = 36063; class FBO { gl; fbo; ext; maxAttachments; constructor(gl, opts) { this.gl = gl; this.fbo = gl.createFramebuffer() || error("error creating FBO"); this.ext = !isGL2Context(gl) && opts?.tex && opts.tex.length > 1 ? gl.getExtension("WEBGL_draw_buffers") || error("missing WEBGL_draw_buffers ext") : void 0; this.maxAttachments = gl.getParameter(GL_MAX_COLOR_ATTACHMENTS_WEBGL); opts && this.configure(opts); } bind() { this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.fbo); return true; } unbind() { this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null); return true; } release() { this.gl.deleteFramebuffer(this.fbo); delete this.fbo; delete this.ext; return true; } configure(opts, unbind = true) { const gl = this.gl; this.bind(); if (opts.tex) { assert( opts.tex.length < this.maxAttachments, `too many attachments (max. ${this.maxAttachments})` ); const attachments = []; for (let i = 0; i < opts.tex.length; i++) { const tex = opts.tex[i]; assert( !!(TEX_FORMATS[tex.format].render || TEX_FORMATS[tex.format].renderExt), `texture #${i} has non-renderable format` ); const attach = GL_COLOR_ATTACHMENT0_WEBGL + i; gl.framebufferTexture2D( gl.FRAMEBUFFER, attach, gl.TEXTURE_2D, tex.tex, 0 ); attachments[i] = attach; } if (this.ext) { this.ext.drawBuffersWEBGL(attachments); } else if (isGL2Context(gl)) { gl.drawBuffers(attachments); } } if (opts.depth) { opts.depth instanceof RBO ? gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, opts.depth.buffer ) : gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, opts.depth.tex, 0 ); } this.validate(); return unbind ? this.unbind() : true; } validate() { const gl = this.gl; const err = gl.checkFramebufferStatus(gl.FRAMEBUFFER); switch (err) { case gl.FRAMEBUFFER_COMPLETE: return true; case gl.FRAMEBUFFER_UNSUPPORTED: error("FBO unsupported"); case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error("FBO incomplete attachment"); case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: error("FBO incomplete dimensions"); case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error("FBO incomplete missing attachment"); default: return error(`FBO error: ${err}`); } } } const defFBO = (gl, opts) => new FBO(gl, opts); export { FBO, defFBO };