@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
316 lines • 30.7 kB
JavaScript
import { webglCreateFramebuffer, webglLookup, webglRenderbufferStorageMultisample } from "./../utils/index.js";
import { TgdPainterGroup } from "./group.js";
export class TgdPainterFramebuffer extends TgdPainterGroup {
constructor(context, options) {
super({
children: options.children,
});
this.context = context;
this.options = options;
this.colorRenderbuffersMSAA = [];
this._depthBufferMSAA = null;
this._framebufferMSAA = null;
/**
* The framebuffer becomes dirty as soon as the width or height changes.
*/
this.dirty = true;
this._lastWidth = 0;
this._lastHeight = 0;
this._framebuffer = null;
this._depthBuffer = null;
this._stencilBuffer = null;
this._antiAliasing = options.antiAliasing ?? false;
if (options.name)
this.name = options.name;
else
this.name = `Framebuffer/${this.name}`;
const { textureColor0, textureColor1, textureColor2, textureColor3 } = options;
if (!(textureColor0 || textureColor1 || textureColor2 || textureColor3)) {
this.context.console.warn("[TgdPainterFramebuffer] You gave no color texture in the constructor: nothing will be rendered!", options);
this.debugHierarchy();
}
this.textureColor0 = nameTexture(textureColor0, "textureColor0");
this.textureColor1 = nameTexture(textureColor1, "textureColor1");
this.textureColor2 = nameTexture(textureColor2, "textureColor2");
this.textureColor3 = nameTexture(textureColor3, "textureColor3");
this.onEnter = options.onEnter;
this.onExit = options.onExit;
const { gl } = this.context;
this.samples = Math.min(4, gl.getParameter(gl.MAX_SAMPLES));
this.drawBuffers = [
this.textureColor0 ? gl.COLOR_ATTACHMENT0 : gl.NONE,
this.textureColor1 ? gl.COLOR_ATTACHMENT1 : gl.NONE,
this.textureColor2 ? gl.COLOR_ATTACHMENT2 : gl.NONE,
this.textureColor3 ? gl.COLOR_ATTACHMENT3 : gl.NONE,
];
this.isFixedSize = !!options.fixedSize;
if (options.fixedSize) {
const texture = this.textureColor0 ?? this.textureColor1 ?? this.textureColor2 ?? this.textureColor3;
if (!texture)
throw new Error("[TgdPainterFramebuffer] Impossible error! Should be caugth before.");
const { width, height } = texture;
if (width < 1 || height < 1) {
throw new Error('[TgdPainterFramebuffer] If you chose "fixedSize", you must provide at least one texture with a size!');
}
}
}
get antiAliasing() {
return this._antiAliasing;
}
set antiAliasing(antiAliasing) {
if (this._antiAliasing === antiAliasing)
return;
this._antiAliasing = antiAliasing;
this.dirty = true;
}
get textureColor0() {
return this._textureColor0;
}
set textureColor0(textureColor0) {
if (this._textureColor0 === textureColor0)
return;
this._textureColor0 = textureColor0;
this.dirty = true;
}
get textureColor1() {
return this._textureColor1;
}
set textureColor1(textureColor1) {
if (this._textureColor1 === textureColor1)
return;
this._textureColor1 = textureColor1;
this.dirty = true;
}
get textureColor2() {
return this._textureColor2;
}
set textureColor2(textureColor2) {
if (this._textureColor2 === textureColor2)
return;
this._textureColor2 = textureColor2;
this.dirty = true;
}
get textureColor3() {
return this._textureColor3;
}
set textureColor3(textureColor3) {
if (this._textureColor3 === textureColor3)
return;
this._textureColor3 = textureColor3;
this.dirty = true;
}
get textureWidth() {
const texture = this.textureColor0 ?? this.textureColor1 ?? this.textureColor2 ?? this.textureColor3;
if (!texture)
throw new Error("[TgdPainterFramebuffer] You must provide at least one texture: textureColor0, textureColor1, textureColor2 or textureColor3!");
return texture.width;
}
get textureHeight() {
const texture = this.textureColor0 ?? this.textureColor1 ?? this.textureColor2 ?? this.textureColor3;
if (!texture)
throw new Error("[TgdPainterFramebuffer] You must provide at least one texture: textureColor0, textureColor1, textureColor2 or textureColor3!");
return texture.height;
}
get width() {
if (this.isFixedSize)
return this.textureWidth;
const { context } = this;
const { viewportMatchingScale = 1 } = this.options;
return Math.round(context.width * viewportMatchingScale);
}
get height() {
if (this.isFixedSize)
return this.textureHeight;
const { context } = this;
const { viewportMatchingScale = 1 } = this.options;
return Math.round(context.height * viewportMatchingScale);
}
updateTextureForColor(tgdTexture, attachment, width, height) {
if (!tgdTexture)
return;
const { context } = this;
const { gl } = context;
tgdTexture.resize(width, height);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + attachment, gl.TEXTURE_2D, tgdTexture.glTexture, 0);
}
updateTextureForDepth(gl, width, height) {
if (this.options.depthBuffer === false)
return;
// Create a Depth Buffer, because the default
// framebuffer has none.
const depthBuffer = gl.createRenderbuffer();
if (!depthBuffer)
throw new Error("Unable to create WebGLRenderBuffer for depth!");
this._depthBuffer = depthBuffer;
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT24, width, height);
this.context.checkError("updateTextureForDepth");
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
}
createDepthBufferMSAA(gl, width, height) {
if (this.options.depthBuffer === false)
return;
// Create a Depth Buffer, because the default
// framebuffer has none.
const depthBuffer = gl.createRenderbuffer();
if (!depthBuffer)
throw new Error("Unable to create WebGLRenderBuffer for depth!");
this._depthBufferMSAA = depthBuffer;
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
webglRenderbufferStorageMultisample(gl, this.samples, gl.DEPTH_COMPONENT24, width, height);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
}
createStencilBuffer(gl, width, height) {
if (!this.options.stencilBuffer)
return;
const stencilBuffer = gl.createRenderbuffer();
if (!stencilBuffer)
throw new Error("Unable to create WebGLRenderBuffer for stencil!");
this._stencilBuffer = stencilBuffer;
gl.bindRenderbuffer(gl.RENDERBUFFER, stencilBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width, height);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, stencilBuffer);
}
createFramebufferMSAA(width, height) {
const { context } = this;
const { gl } = context;
this.createRenderbuffersMSAA(width, height);
this.createDepthBufferMSAA(gl, width, height);
this._framebufferMSAA = webglCreateFramebuffer(gl);
gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebufferMSAA);
this.colorRenderbuffersMSAA.map((renderbuffer, index) => {
if (renderbuffer) {
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + index, gl.RENDERBUFFER, renderbuffer);
}
});
if (this._depthBufferMSAA) {
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this._depthBufferMSAA);
}
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status !== gl.FRAMEBUFFER_COMPLETE) {
this.context.console.error(`[TgdPainterFramebuffer] Your Framebuffer is incomplete: ${webglLookup(status)}!`);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
createFramebufferIfNeeded(width, height) {
if (width < 1 || height < 1)
return;
if (!this.dirty && width === this._lastWidth && height === this._lastHeight)
return;
const { context, antiAliasing } = this;
this._lastWidth = width;
this._lastHeight = height;
this.delete();
const { gl } = context;
if (antiAliasing)
this.createFramebufferMSAA(width, height);
this._framebuffer = webglCreateFramebuffer(gl);
gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebuffer);
this.updateTextureForColor(this.textureColor0, 0, width, height);
this.updateTextureForColor(this.textureColor1, 1, width, height);
this.updateTextureForColor(this.textureColor2, 2, width, height);
this.updateTextureForColor(this.textureColor3, 3, width, height);
if (!antiAliasing)
this.updateTextureForDepth(gl, width, height);
this.createStencilBuffer(gl, width, height);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status !== gl.FRAMEBUFFER_COMPLETE) {
this.context.console.error(`[TgdPainterFramebuffer] Your Framebuffer is incomplete: ${webglLookup(status)}!`);
}
this.dirty = false;
}
blitFramebuffers(width, height) {
const { context } = this;
const { gl } = context;
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this._framebufferMSAA);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this._framebuffer);
this.colorRenderbuffersMSAA.map((rd, index) => {
if (!rd)
return;
gl.readBuffer(gl.COLOR_ATTACHMENT0 + index);
const buffers = [gl.NONE, gl.NONE, gl.NONE, gl.NONE];
buffers[index] = gl.COLOR_ATTACHMENT0 + index;
gl.drawBuffers(buffers);
gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
});
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
}
paint(time, delta) {
const { context, width, height, antiAliasing } = this;
const { gl } = context;
const paint = () => {
const currentFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
this.createFramebufferIfNeeded(width, height);
gl.bindFramebuffer(gl.FRAMEBUFFER, antiAliasing ? this._framebufferMSAA : this._framebuffer);
gl.drawBuffers(this.drawBuffers);
super.paint(time, delta);
if (this.antiAliasing) {
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
this.blitFramebuffers(width, height);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, currentFramebuffer);
};
context.paintInCustomSize(width, height, paint);
}
delete() {
const { context, _framebuffer, _depthBuffer, _stencilBuffer } = this;
const { gl } = context;
if (_framebuffer) {
gl.deleteFramebuffer(_framebuffer);
this._framebuffer = null;
}
if (_depthBuffer) {
gl.deleteRenderbuffer(_depthBuffer);
this._depthBuffer = null;
}
if (_stencilBuffer) {
gl.deleteRenderbuffer(_stencilBuffer);
this._stencilBuffer = null;
}
if (this._depthBufferMSAA) {
gl.deleteRenderbuffer(this._depthBufferMSAA);
this._depthBufferMSAA = null;
}
if (this._framebufferMSAA) {
gl.deleteFramebuffer(this._framebufferMSAA);
this._framebufferMSAA = null;
}
this.deleteRenderbuffersMSAA();
}
deleteRenderbuffersMSAA() {
const { gl } = this.context;
for (let i = 0; i < this.colorRenderbuffersMSAA.length; i++) {
const colorRenderbuffer = this.colorRenderbuffersMSAA[i];
if (colorRenderbuffer) {
gl.deleteRenderbuffer(colorRenderbuffer);
}
}
this.colorRenderbuffersMSAA.splice(0);
}
createRenderbuffersMSAA(width, height) {
const { context, textureColor0, textureColor1, textureColor2, textureColor3 } = this;
const { gl } = context;
this.deleteRenderbuffersMSAA();
this.colorRenderbuffersMSAA = [textureColor0, textureColor1, textureColor2, textureColor3].map((texture) => {
if (!texture)
return;
const colorRenderBuffer = gl.createRenderbuffer();
if (!colorRenderBuffer)
throw new Error("Unable to create RenderBuffer!");
gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderBuffer);
webglRenderbufferStorageMultisample(gl, this.samples, texture.internalFormat, width, height);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
return colorRenderBuffer;
});
}
}
function nameTexture(texture, name) {
if (texture) {
texture.name += `/${name}`;
}
return texture;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWVidWZmZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcGFpbnRlci9mcmFtZWJ1ZmZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFHQSxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsV0FBVyxFQUFFLG1DQUFtQyxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBQ3JHLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFxRHpDLE1BQU0sT0FBTyxxQkFBc0IsU0FBUSxlQUFlO0lBeUJ0RCxZQUNvQixPQUFtQixFQUNsQixPQUE4QztRQUUvRCxLQUFLLENBQUM7WUFDRixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7U0FDN0IsQ0FBQyxDQUFBO1FBTGMsWUFBTyxHQUFQLE9BQU8sQ0FBWTtRQUNsQixZQUFPLEdBQVAsT0FBTyxDQUF1QztRQWxCM0QsMkJBQXNCLEdBQXNDLEVBQUUsQ0FBQTtRQUM5RCxxQkFBZ0IsR0FBNkIsSUFBSSxDQUFBO1FBQ2pELHFCQUFnQixHQUE0QixJQUFJLENBQUE7UUFDeEQ7O1dBRUc7UUFDSyxVQUFLLEdBQUcsSUFBSSxDQUFBO1FBQ1osZUFBVSxHQUFHLENBQUMsQ0FBQTtRQUNkLGdCQUFXLEdBQUcsQ0FBQyxDQUFBO1FBQ2YsaUJBQVksR0FBNEIsSUFBSSxDQUFBO1FBQzVDLGlCQUFZLEdBQTZCLElBQUksQ0FBQTtRQUM3QyxtQkFBYyxHQUE2QixJQUFJLENBQUE7UUFZbkQsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsWUFBWSxJQUFJLEtBQUssQ0FBQTtRQUNsRCxJQUFJLE9BQU8sQ0FBQyxJQUFJO1lBQUUsSUFBSSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFBOztZQUNyQyxJQUFJLENBQUMsSUFBSSxHQUFHLGVBQWUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFBO1FBQzNDLE1BQU0sRUFBRSxhQUFhLEVBQUUsYUFBYSxFQUFFLGFBQWEsRUFBRSxhQUFh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