UNPKG

sigrist-svelte-mandelbrot-explorer

Version:

A svelte component that renders the mandelbrot set using WebGL. Try this [Demo](https://sigrist.dev/apps/mandelbrot).

112 lines (111 loc) 4.76 kB
import vertexShaderCode from './shaders/vertexShader'; import fragmentShaderCode from './shaders/fragmentShader'; /** * Renders the Mandelbrot set to the canvas Element * */ function mandelbrotAction(node, args) { /**Access to the WebGLRenderingContext interface. * @readonly * @type {WebGLRenderingContext}*/ const gl = node.getContext("webgl"); if (!gl) { console.error("MANDELBROT: Your browser does not support WebGL"); return; } let { center, magnificationMultiplier, width, height, numberOfIterations } = args; node.width = width; node.height = height; let program; let angleOffset = 0.0; let time = Date.now(); function updateAngleOffset() { const newTime = Date.now(); angleOffset += (newTime - time) / 250; time = newTime; } //Initialize and Bind Vertex Buffer for Quad const vertexBuffer = gl.createBuffer(); const indexBuffer = gl.createBuffer(); const vertices = [-1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0]; const indecies = [3, 2, 1, 3, 1, 0]; gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indecies), gl.STATIC_DRAW); /**Creates a WebGL Program and sets the program variable to it. * If Program is already set, it will delete it and create a new Program */ function configureProgram() { const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(vertexShader, vertexShaderCode); gl.compileShader(vertexShader); if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { console.error("Could not compile vertex shader", gl.getShaderInfoLog(vertexShader)); gl.deleteShader(vertexShader); } const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderCode); gl.compileShader(fragmentShader); if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { console.error("Could not compile fragment shader", gl.getShaderInfoLog(fragmentShader)); gl.deleteShader(fragmentShader); } if (program) { gl.deleteProgram(program); program = null; } program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.error("Could not link program"); gl.deleteProgram(program); } gl.useProgram(program); gl.deleteShader(fragmentShader); gl.deleteShader(vertexShader); } configureProgram(); /**Render the WebGL Context with the current program */ function render() { //Map vertex data to vertex shader attributes const positionAttributeLocation = gl.getAttribLocation(program, "position"); gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(positionAttributeLocation); //Set uniforms const translationMatrixPosition = gl.getUniformLocation(program, "translation_matrix"); gl.uniformMatrix3fv(translationMatrixPosition, false, [(width / height) * magnificationMultiplier, 0, 0, 0, 1 * magnificationMultiplier, 0, ...center, 1]); const angleOffsetPosition = gl.getUniformLocation(program, "angleOffset"); gl.uniform1f(angleOffsetPosition, angleOffset); const maximumIterationsPosition = gl.getUniformLocation(program, "maximumIterations"); gl.uniform1f(maximumIterationsPosition, numberOfIterations); gl.clearColor(0, 0, 1, 1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.viewport(0, 0, width, height); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); updateAngleOffset(); requestAnimationFrame(render); } requestAnimationFrame(render); return { update(newArgs) { if (!gl) return; center = newArgs.center; magnificationMultiplier = newArgs.magnificationMultiplier; width = newArgs.width; height = newArgs.height; numberOfIterations = newArgs.numberOfIterations; node.width = width; node.height = height; }, destroy() { gl.deleteBuffer(vertexBuffer); gl.deleteBuffer(indexBuffer); gl.deleteProgram(program); } }; } export default mandelbrotAction;