@thi.ng/webgl
Version:
WebGL & GLSL abstraction layer
106 lines (105 loc) • 3.04 kB
JavaScript
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
};