@thi.ng/webgl-shadertoy
Version:
Basic WebGL scaffolding for running interactive fragment shaders via @thi.ng/shader-ast
104 lines (103 loc) • 2.77 kB
JavaScript
import { F, I, V2, V4 } from "@thi.ng/shader-ast/api/types";
import { assign } from "@thi.ng/shader-ast/ast/assign";
import { defMain, defn } from "@thi.ng/shader-ast/ast/function";
import { FLOAT0, FLOAT1, vec4 } from "@thi.ng/shader-ast/ast/lit";
import { compileModel } from "@thi.ng/webgl/buffer";
import { draw } from "@thi.ng/webgl/draw";
import { defQuadModel } from "@thi.ng/webgl/geo/quad";
import { defShader } from "@thi.ng/webgl/shader";
const shaderToy = (opts) => {
const gl = opts.gl;
const model = defQuadModel({ uv: false });
model.textures = opts.textures || [];
compileModel(gl, model);
opts.canvas.addEventListener("mousemove", (e) => {
const rect = opts.canvas.getBoundingClientRect();
const dpr = window.devicePixelRatio;
model.uniforms.mouse = [
(e.clientX - rect.left) * dpr,
(rect.height - (e.clientY - rect.top)) * dpr
];
});
opts.canvas.addEventListener("mousedown", (e) => {
model.uniforms.mouseButtons = e.buttons;
});
opts.canvas.addEventListener("mouseup", (e) => {
model.uniforms.mouseButtons = e.buttons;
});
let active;
let t0;
const update = (time) => {
const w = gl.drawingBufferWidth;
const h = gl.drawingBufferHeight;
model.uniforms.time = time;
model.uniforms.resolution = [w, h];
gl.viewport(0, 0, w, h);
draw(model);
};
const updateRAF = () => {
update((Date.now() - t0) * 1e-3);
active && requestAnimationFrame(updateRAF);
};
const instance = {
start() {
t0 = Date.now();
active = true;
requestAnimationFrame(updateRAF);
},
stop() {
active = false;
},
update(time) {
update(time);
},
recompile(main, shaderOpts) {
if (model.shader) {
model.shader.release();
}
model.shader = defShader(
gl,
{
vs: (gl2, _, ins) => [
defMain(() => [
assign(
gl2.gl_Position,
vec4(ins.position, FLOAT0, FLOAT1)
)
])
],
fs: (gl2, unis, _, outputs) => [
defMain(() => [
assign(
outputs.fragColor,
defn(
V4,
"mainImage",
[],
() => main(gl2, unis)
)()
)
])
],
attribs: {
position: V2
},
uniforms: {
resolution: V2,
mouse: [V2, [0, 0]],
mouseButtons: [I, 0],
time: F,
...opts.uniforms
}
},
shaderOpts || opts.opts
);
},
model
};
instance.recompile(opts.main);
return instance;
};
export {
shaderToy
};