summaryrefslogtreecommitdiff
path: root/fractiform.js
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-06-14 13:24:48 +0100
committerpommicket <pommicket@gmail.com>2023-06-14 13:24:48 +0100
commit5d84ef35cef2959ef4901b85f3469735d51c9555 (patch)
tree73b752263af5517a0d1357a9959c7155e2a9c9c1 /fractiform.js
parenta6df8658309f82c62e4507894e409b65a6470950 (diff)
framebuffers
Diffstat (limited to 'fractiform.js')
-rw-r--r--fractiform.js122
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);