UNPKG

@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
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 };