diff options
Diffstat (limited to 'fractiform.js')
-rw-r--r-- | fractiform.js | 122 |
1 files changed, 94 insertions, 28 deletions
diff --git a/fractiform.js b/fractiform.js index 9575802..c63751d 100644 --- a/fractiform.js +++ b/fractiform.js @@ -1,10 +1,13 @@ 'use strict'; let gl; -let program; -let vertex_buffer; -let prev_frame_time = 0.0; +let program_main; +let program_post; +let vertex_buffer_rect; let canvas; +let framebuffer; +let framebuffer_color_texture; +let prev_width = -1, prev_height = -1; window.addEventListener('load', startup); @@ -12,14 +15,13 @@ function startup() { canvas = document.getElementById('canvas'); gl = canvas.getContext('webgl'); - program = gl.createProgram(); - let vertex_shader = compile_shader('main vertex', gl.VERTEX_SHADER, ` + program_main = compile_program('main', ` attribute vec2 v_pos; +uniform vec2 u_scale; void main() { - gl_Position = vec4(v_pos, 0.0, 1.0); + gl_Position = vec4(v_pos * u_scale, 0.0, 1.0); } -`); - let fragment_shader = compile_shader('main fragment', gl.FRAGMENT_SHADER, ` +`, ` #ifdef GL_ES precision highp float; #endif @@ -30,54 +32,118 @@ void main() { gl_FragColor = u_color; } `); - if (vertex_shader == null || fragment_shader == null) { + if (program_main === null) { return; } - gl.attachShader(program, vertex_shader); - gl.attachShader(program, fragment_shader); - gl.linkProgram(program); - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - show_error('Error linking shader program:\n' + gl.getProgramInfoLog(program)); + program_post = compile_program('main', ` +attribute vec2 v_pos; +varying vec2 uv; +void main() { + uv = v_pos * 0.5 + 0.5; + gl_Position = vec4(v_pos, 0.0, 1.0); +} +`, ` +#ifdef GL_ES +precision highp float; +#endif +uniform sampler2D u_texture; +varying vec2 uv; +void main() { + gl_FragColor = texture2D(u_texture, uv); +} +`); + if (program_post === null) { return; } - vertex_buffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); + vertex_buffer_rect = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer_rect); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ - -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, + -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, + -1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ]), gl.STATIC_DRAW); + frame(0.0); } -function frame(delta) { +function frame(time) { + time *= 1e-3; + let width = canvas.offsetWidth; let height = canvas.offsetHeight; canvas.width = width; canvas.height = height; + + if (width !== prev_width || height !== prev_height) { + console.log('new framebuffer'); + prev_width = width; + prev_height = height; + framebuffer = gl.createFramebuffer(); + framebuffer_color_texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, framebuffer_color_texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, + gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, framebuffer_color_texture, 0); + let status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); + if (status !== gl.FRAMEBUFFER_COMPLETE) { + show_error('Error: framebuffer incomplete (status ' + status + ')'); + return; + } + } + + gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); gl.viewport(0, 0, width, height); - gl.clearColor(0.8, 0.9, 1.0, 1.0); + gl.clearColor(Math.sin(time) ** 2, 0.9, 1.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); - gl.useProgram(program); + gl.useProgram(program_main); - gl.uniform4fv(gl.getUniformLocation(program, 'u_color'), [0.1, 0.7, 0.2, 1.0]); + gl.uniform4fv(gl.getUniformLocation(program_main, 'u_color'), [0.1, 0.7, 0.2, 1.0]); + gl.uniform2fv(gl.getUniformLocation(program_main, 'u_scale'), [0.5, 0.5]); - gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); + gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer_rect); + + let v_pos = gl.getAttribLocation(program_main, 'v_pos'); + gl.enableVertexAttribArray(v_pos); + gl.vertexAttribPointer(v_pos, 2, gl.FLOAT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, 6); - let v_pos = gl.getAttribLocation(program, 'v_pos'); + gl.useProgram(program_post); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, framebuffer_color_texture); + gl.uniform1i(gl.getUniformLocation(program_post, 'u_texture'), 0); + v_pos = gl.getAttribLocation(program_post, 'v_pos'); gl.enableVertexAttribArray(v_pos); gl.vertexAttribPointer(v_pos, 2, gl.FLOAT, false, 0, 0); gl.drawArrays(gl.TRIANGLES, 0, 6); - requestAnimationFrame((t) => { - let delta = t - prev_frame_time; - prev_frame_time = t; - frame(delta); - }); + requestAnimationFrame(frame); } +function compile_program(name, vertex_source, fragment_source) { + let vshader = compile_shader(name + ' (vertex)', gl.VERTEX_SHADER, vertex_source); + let fshader = compile_shader(name + ' (fragment)', gl.FRAGMENT_SHADER, fragment_source); + if (vshader === null || fshader === null) { + return null; + } + let program = gl.createProgram(); + gl.attachShader(program, vshader); + gl.attachShader(program, fshader); + gl.linkProgram(program); + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + show_error('Error linking shader program:\n' + gl.getProgramInfoLog(program)); + return null; + } + return program; +} function compile_shader(name, type, source) { let shader = gl.createShader(type); |