@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
151 lines • 14 kB
JavaScript
import { TgdDataset } from "./../../dataset/dataset.js";
import { TgdFilterVerbatim } from "./../../filter/index.js";
import { TgdPainter } from "./../painter.js";
import { TgdProgram } from "./../../program/index.js";
import { TgdShaderFragment } from "./../../shader/fragment.js";
import { TgdShaderVertex } from "./../../shader/vertex.js";
import { TgdVertexArray } from "./../../vao/index.js";
import { TgdPainterState } from "../state/index.js";
import { Framebuffers } from "./framebuffers.js";
import { tgdTextureRecordToUniforms } from "./../../utils/index.js";
export class TgdPainterFilter extends TgdPainter {
constructor(context, options) {
super();
this.context = context;
this.z = 0;
this.texturesArray = [];
this.paintOneFilter = (filterIndex, time, delta, flip = +1) => {
const { framebuffers } = this;
const textureInput = framebuffers.texture;
const filter = this.filters[filterIndex];
const program = this.programs[filterIndex];
const vao = this.vaos[filterIndex];
const { context } = this;
const { gl } = context;
program.use();
program.uniform1f("uniZ", this.z);
program.uniform1f("uniFlipY", flip);
const textures = this.texturesArray[filterIndex];
if (textures) {
let unit = 1;
for (const uniformName of Object.keys(textures)) {
const texture = textures[uniformName];
texture.activate(unit++, program, uniformName);
}
}
filter.setUniforms({ context, program, time, delta });
textureInput.activate(0, program, "uniTexture");
vao.bind();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
vao.unbind();
};
const { texture } = options;
if (!texture) {
throw new Error(`[TgdPainterFilter] A texture must be given for "${this.name}"!`);
}
this.framebuffers = new Framebuffers(context, texture);
this.z = options.z ?? 0.999999;
this.flipY = options.flipY ?? false;
const filters = [...(options.filters ?? [])];
if (filters.length === 0) {
filters.push(new TgdFilterVerbatim());
}
const programs = filters.map((filter) => {
const vert = new TgdShaderVertex({
attributes: {
attPoint: "vec2",
attUV: "vec2",
},
varying: {
varUV: "vec2",
varPixel: "vec2",
},
uniforms: {
uniZ: "float",
uniFlipY: "float",
uniTexture: "sampler2D",
},
mainCode: [
"varUV = attUV;",
"ivec2 size = textureSize(uniTexture, 0);",
"varPixel = vec2(1.0 / float(size.x), 1.0 / float(size.y));",
"gl_Position = vec4(",
["attPoint * vec2(1.0, uniFlipY),", "uniZ,", "1.0"],
");",
],
}).code;
const { textures } = filter;
this.texturesArray.push(textures);
const uniformsForTextures = tgdTextureRecordToUniforms(textures);
console.log("🐞 [filter@77] filter =", filter); // @FIXME: Remove this line written on 2026-05-18 at 20:37
const frag = new TgdShaderFragment({
uniforms: {
...uniformsForTextures,
uniTexture: "sampler2D",
...filter.uniforms,
},
varying: {
varUV: "vec2",
varPixel: "vec2",
},
mainCode: filter.fragmentShaderCode ?? [
"vec4 color = texture(uniTexture, varUV);",
"FragColor = color;",
],
functions: filter.extraFunctions,
}).code;
const prg = new TgdProgram(context.gl, { vert, frag });
prg.use();
const samplerNames = Object.keys(textures);
for (let unit = 1; unit <= samplerNames.length; unit++) {
const uniformName = samplerNames[unit - 1];
const texture = textures[uniformName];
texture.activate(unit, prg, uniformName);
}
return prg;
});
const vaos = programs.map((program) => createVAO(context, program));
this.programs = programs;
this.filters = filters;
this.vaos = vaos;
this.name = options.name ?? `Filter/${this.name}`;
}
delete() {
const { programs, vaos, framebuffers } = this;
framebuffers.delete();
for (const prg of programs)
prg.delete();
for (const vao of vaos)
vao.delete();
}
paint(time, delta) {
const { framebuffers, filters } = this;
TgdPainterState.do(this.context, {
depth: "off",
blend: "off",
cull: "off",
action: () => {
for (let index = 0; index < filters.length - 1; index++) {
framebuffers.paint(() => this.paintOneFilter(index, time, delta));
}
},
});
this.paintOneFilter(filters.length - 1, time, delta, (filters.length & 1) === (this.flipY ? 0 : 1) ? +1 : -1);
if (filters.length % 2 === 0)
framebuffers.swap();
}
}
function createVAO(context, program) {
const dataset = new TgdDataset({
attPoint: "vec2",
attUV: "vec2",
});
// prettier-ignore
dataset.set("attPoint", new Float32Array([-1, +1, +1, +1, -1, -1, +1, -1]));
dataset.set("attUV", new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]));
const vao = new TgdVertexArray(context.gl, program, [dataset]);
if (!vao)
throw new Error("Unable to create WebGL VAO!");
return vao;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3BhaW50ZXIvZmlsdGVyL2ZpbHRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDakQsT0FBTyxFQUFrQixpQkFBaUIsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUMvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDakQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUN6QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUN4RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFFcEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzFDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFXdkQsTUFBTSxPQUFPLGdCQUFpQixTQUFRLFVBQVU7SUFVNUMsWUFDb0IsT0FBbUIsRUFDbkMsT0FBZ0M7UUFFaEMsS0FBSyxFQUFFLENBQUE7UUFIUyxZQUFPLEdBQVAsT0FBTyxDQUFZO1FBVmhDLE1BQUMsR0FBRyxDQUFDLENBQUE7UUFPSyxrQkFBYSxHQUFvRCxFQUFFLENBQUE7UUF1R25FLG1CQUFjLEdBQUcsQ0FBQyxXQUFtQixFQUFFLElBQVksRUFBRSxLQUFhLEVBQUUsSUFBSSxHQUFHLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDOUYsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLElBQUksQ0FBQTtZQUM3QixNQUFNLFlBQVksR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFBO1lBRXpDLE1BQU0sTUFBTSxHQUFHLElB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