UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

316 lines 30.7 kB
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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