codepens/colorful-distance-field-sha.../dist/script.js

152 lines
4.6 KiB
JavaScript
Raw Normal View History

2023-10-06 23:12:53 +02:00
console.clear();
class DigitalArt extends HTMLElement {
constructor() {
super();
this.canvas = null;
this.gl = null;
this.onResize = this.onResize.bind(this);
this.loop = this.loop.bind(this);
}
static register() {
customElements.define("digital-art", DigitalArt);
}
connectedCallback() {
if (! this.gl) {
this.setup();
}
}
disconnectedCallback() {
this.dispose();
}
get devicePixelRatio() {
return parseFloat(this.getAttribute('dpr')) || window.devicePixelRatio;
}
onResize() {
const { canvas, gl, program } = this;
const width = this.clientWidth;
const height = this.clientHeight;
const dpr = this.devicePixelRatio;
canvas.width = width * dpr;
canvas.height = height * dpr;
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
const uResolution = gl.getUniformLocation(program, "resolution");
gl.uniform2fv(uResolution, [gl.drawingBufferWidth, gl.drawingBufferHeight]);
}
createShader(type, code) {
const { gl } = this;
const sh = gl.createShader(type, code);
gl.shaderSource(sh, code);
gl.compileShader(sh);
if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
throw gl.getShaderInfoLog(sh);
}
return sh;
}
createBuffers() {
const { gl, program } = this;
const bufferScripts = [...this.querySelectorAll('[type=buffer]')];
this.buffers = {};
let count = -1;
bufferScripts.forEach(container => {
const name = container.getAttribute('name') || 'position';
const recordSize = parseInt(container.getAttribute('data-size'), 10) || 1;
const data = new Float32Array(JSON.parse(container.textContent.trim()));
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
data,
gl.STATIC_DRAW
);
const attribLoc = gl.getAttribLocation(program, name);
this.buffers[name] = { buffer, data, attribLoc, recordSize };
count = Math.max(count, (data.length / recordSize)|0);
gl.enableVertexAttribArray(attribLoc);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(attribLoc, recordSize, gl.FLOAT, false, 0, 0);
});
this.count = count;
}
loop(time = 0) {
const { gl, program } = this;
const uTime = gl.getUniformLocation(program, "time");
gl.uniform1f(uTime, time);
gl.drawArrays(gl.TRIANGLES, 0, this.count);
this.frame = requestAnimationFrame(this.loop);
}
createPrograms() {
const { gl } = this;
const fragScript = this.querySelector('[type=frag]');
const vertScript = this.querySelector('[type=vert]');
const HEADER = 'precision highp float;';
const DEFAULT_VERT = HEADER + 'attribute vec4 position;void main(){gl_Position=position;}';
const DEFAULT_FRAG = HEADER + 'void main(){gl_FragColor=vec4(1.,0,0,1.);}';
this.fragCode = fragScript?.textContent || DEFAULT_FRAG;
this.vertCode = vertScript?.textContent || DEFAULT_VERT;
const program = gl.createProgram();
this.program = program;
this.gl = gl;
this.fragShader = this.createShader(gl.FRAGMENT_SHADER, this.fragCode);
this.vertShader = this.createShader(gl.VERTEX_SHADER, this.vertCode);
gl.attachShader(program, this.fragShader);
gl.attachShader(program, this.vertShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw gl.getProgramInfoLog(program);
}
}
setup() {
this.canvas = document.createElement('canvas');
this.dpr = window.devicePixelRatio;
this.appendChild(this.canvas);
this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl');
this.createPrograms();
const { program, gl } = this;
gl.useProgram(program);
this.createBuffers();
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
this.onResize();
window.addEventListener('resize', this.onResize, false);
this.frame = requestAnimationFrame(this.loop);
}
dispose() {
cancelAnimationFrame(this.loop);
this.frame = -1;
window.removeEventListener('resize', this.onResize, false);
Object.entries(this.buffers).forEach(([name, buf]) => {
this.gl.deleteBuffer(buf.buffer);
});
this.gl.deleteProgram(this.program);
const loseCtx = this.gl.getExtension('WEBGL_lose_context');
if (loseCtx && typeof loseCtx.loseContext === 'function') {
loseCtx.loseContext();
}
this.removeChild(this.canvas);
this.gl = null;
this.canvas = null;
this.buffers = {}
}
}
DigitalArt.register();