diff --git a/.gitignore b/.gitignore
index 30c9307..c341ed4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
bake/
.sass-cache/
+sandbox/
diff --git a/CREDITS.md b/CREDITS.md
new file mode 100644
index 0000000..4896e1d
--- /dev/null
+++ b/CREDITS.md
@@ -0,0 +1 @@
+1. [github:rose-pine/tailwind-css](https://github.com/rose-pine/tailwind-css): I modified their css palettes
diff --git a/palette.theme b/docs/palette.theme
similarity index 100%
rename from palette.theme
rename to docs/palette.theme
diff --git a/bakeimgs b/scripts/bakeimgs
similarity index 100%
rename from bakeimgs
rename to scripts/bakeimgs
diff --git a/serve b/scripts/serve
similarity index 100%
rename from serve
rename to scripts/serve
diff --git a/www/css/typing-merge.css b/www/css/typing-merge.css
deleted file mode 100644
index 4e54f42..0000000
--- a/www/css/typing-merge.css
+++ /dev/null
@@ -1,110 +0,0 @@
-.centered {
- position: absolute;
- inset: 0 0 0 0;
- margin: auto;
-
- display: flex;
-}
-
-.heading {
- font-family: monospace;
- font-size: 2em;
- font-weight: bold;
- color: #ffc0cb; /* #ac4aed */
-}
-
-/* =========================================================== *
- * Type Writer Effect *
-/* =========================================================== */
-
-#typing-wrapper {
- margin: auto auto;
- width: 71ch; /* prompt + command + cursor length */
- height: 21ch;
- text-align: start;
-
- border: 0.5ch solid #ffc0cb; /* #ac4aed */
- background-color: #0e0d14;
- padding: 20px;
-
- display: flex;
- flex-direction: column;
- justify-content: start;
- align-content: center;
- align-items: start;
-}
-
-#typing-prompt {
- width: 10ch; /* prompt + command length */
- animation: kfs-typing 0.5s steps(4), kfs-cursor-blink 1.2s steps(1, start) 0.6s forwards;
- white-space: nowrap;
- overflow: hidden;
- border-right: 1ch solid;
- margin-bottom: 0.5ch;
-}
-
-#typing-result {
- /* "4.8s" means the result is shown 1.8s after typing ends */
- animation: unhide 1s 1.8s forwards;
- visibility: hidden;
- white-space: nowrap; /* preserve linebreaks */
-}
-
-#typing-prompt-segfault {
- width: 47ch; /* prompt + command length */
- /* animation: kfs-typing-segfault 3s steps(36) 2.6s, cursor-blink 0.6s steps(1, start) 3s infinite alternate; */
- animation: kfs-typing-segfault 3s steps(36) 4s forwards, cursor-blink-segfault 0.6s steps(1, start) 7.1s infinite alternate;
- white-space: nowrap;
- overflow: hidden;
- border-right: 1ch solid;
- margin-bottom: 0.5ch;
- visibility: hidden;
-}
-
-#typing-result-segfault {
- /* "4.8s" means the result is shown 1.8s after typing ends */
- animation: unhide 1s 8.3s forwards;
- visibility: hidden;
- white-space: nowrap; /* preserve linebreaks */
-}
-
-@keyframes kfs-typing {
- from {
- width: 6ch; /* ignore prompt width */
- }
-}
-
-@keyframes kfs-typing-segfault {
- from {
- width: 11ch; /* ignore prompt width */
- visibility: visible;
- }
- to {
- visibility: visible;
- }
-}
-
-@keyframes kfs-cursor-blink {
- from {
- border-color: transparent;
- }
- 50% {
- border-color: currentColor;
- }
- to {
- border-color: transparent;
- }
-}
-
-@keyframes cursor-blink-segfault {
- 50% {
- border-color: transparent;
- }
-}
-
-@keyframes unhide {
- to {
- visibility: visible;
- }
-}
-
diff --git a/www/css/typing.css b/www/css/typing.css
index 723506b..34226b2 100644
--- a/www/css/typing.css
+++ b/www/css/typing.css
@@ -1,9 +1,3 @@
-html, body {
- height: 100%;
- margin: 0;
- background-color: #0e0d14;
-}
-
.centered {
position: absolute;
inset: 0 0 0 0;
@@ -30,6 +24,7 @@ html, body {
text-align: start;
border: 0.5ch solid #ffc0cb; /* #ac4aed */
+ background-color: #0e0d14;
padding: 20px;
display: flex;
@@ -84,6 +79,9 @@ html, body {
width: 11ch; /* ignore prompt width */
visibility: visible;
}
+ 25% {
+ width: 11ch;
+ }
to {
visibility: visible;
}
@@ -112,3 +110,4 @@ html, body {
visibility: visible;
}
}
+
diff --git a/www/index.html b/www/index.html
index 700e299..f8308c9 100644
--- a/www/index.html
+++ b/www/index.html
@@ -9,9 +9,9 @@
-
+
-
+
diff --git a/www/index.html.bak b/www/index.html.bak
deleted file mode 100644
index a8d3f1c..0000000
--- a/www/index.html.bak
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- grub> boot
-
-
-
- ERROR: Root device mounted successfully, but /sbin/init does not exist.
-
- Bailing out, you are on your own.
- Good luck
-
- sh: can't access tty; job control turned off
-
-
-
-
- [rootfs ]#
- do butterflies cry when they're sad?
-
-
-
- Segmentation fault (core dumped)
-
-
-
-
-
-
diff --git a/www/js/draw-scene.js b/www/js/draw-scene.js
deleted file mode 100644
index 0df76cc..0000000
--- a/www/js/draw-scene.js
+++ /dev/null
@@ -1,60 +0,0 @@
-function drawScene(gl, programInfo, buffers, time) {
- // Tell WebGL how to convert from clip space to pixels
- gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
-
- gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
- gl.clearDepth(1.0); // Clear everything
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-
- // NOTE: this is how width/height is taken
- // const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
-
- // Tell WebGL how to pull out the positions from the position
- // buffer into the vertexPosition attribute.
- setPositionAttribute(gl, buffers, programInfo);
-
- gl.useProgram(programInfo.program);
-
- /* --- Set Uniform Variables --- */
- // Time since page loaded in seconds
- gl.uniform1f(
- programInfo.uniformLocations.time,
- time,
- );
- // Viewport resolution in pixels
- gl.uniform2f(
- programInfo.uniformLocations.resolution,
- gl.canvas.width,
- gl.canvas.height,
- );
-
- {
- const offset = 0;
- const vertexCount = 4;
- gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
- }
-}
-
-// Tell WebGL how to pull out the positions from the position
-// buffer into the vertexPosition attribute.
-function setPositionAttribute(gl, buffers, programInfo) {
- const numComponents = 2; // pull out 2 values per iteration
- const type = gl.FLOAT; // the data in the buffer is 32bit floats
- const normalize = false; // don't normalize
- const stride = 0; // how many bytes to get from one set of values to the next
- // 0 = use type and numComponents above
- const offset = 0; // how many bytes inside the buffer to start from
- gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
- gl.vertexAttribPointer(
- programInfo.attribLocations.vertexPosition,
- numComponents,
- type,
- normalize,
- stride,
- offset,
- );
- gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
-}
-
-export { drawScene };
-
diff --git a/www/js/init-buffers.js b/www/js/init-buffers.js
deleted file mode 100644
index bf12c1a..0000000
--- a/www/js/init-buffers.js
+++ /dev/null
@@ -1,34 +0,0 @@
-function initBuffers(gl) {
- const positionBuffer = initPositionBuffer(gl);
-
- return {
- position: positionBuffer,
- };
-}
-
-function initPositionBuffer(gl) {
- // Position array of a "full-screen" quad (encoded as TRIANGLE_STRIP)
- // Ref: https://en.wikipedia.org/wiki/Triangle_strip
- // NOTE: +x,+y is top-right & -x,-y is bottom-left
- const positions = [
- -1.0, 1.0,
- -1.0, -1.0,
- 1.0, 1.0,
- 1.0, -1.0,
- ];
-
- // Create a buffer for the square's positions.
- const positionBuffer = gl.createBuffer();
- // Select the positionBuffer as the one to apply buffer
- // operations to from here out.
- gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
- // Now pass the list of positions into WebGL to build the
- // shape. We do this by creating a Float32Array from the
- // JavaScript array, then use it to fill the current buffer.
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
-
- return positionBuffer;
-}
-
-export { initBuffers };
-
diff --git a/www/js/main.js b/www/js/main.js
new file mode 100644
index 0000000..a5ca67b
--- /dev/null
+++ b/www/js/main.js
@@ -0,0 +1,32 @@
+import { Smc } from "./smc/smc.js"
+
+main();
+
+async function fetchShader(uri, delegate) {
+ const res = await fetch(uri);
+ if (res.ok)
+ return await res.text();
+ this.raiseError(
+ SmcErr.FETCH_SHADER,
+ `Failed to load shader source ${url}: ${res.status} ${res.json()}`);
+ return ""
+}
+
+
+function main() {
+ const canvas = document.querySelector("#gl-canvas");
+ canvas.setAttribute('width', window.innerWidth);
+ canvas.setAttribute('height', window.innerHeight);
+
+
+ fetchShader("../shaders/segfault.glsl")
+ .then(frag =>
+ new Smc(canvas)
+ .setMaxFps(30)
+ .setProgram(builder =>
+ builder
+ .addFragmentShader(frag))
+ .run()
+ );
+}
+
diff --git a/www/js/smc/README.md b/www/js/smc/README.md
new file mode 100644
index 0000000..c013131
--- /dev/null
+++ b/www/js/smc/README.md
@@ -0,0 +1,4 @@
+# Shade My Canvas
+An easy to use and purely declarative wrapper for WebGL written in Javascript.
+The main idea is to remove all the boilerplate required to render shader
+programs, so you can focus on writing GLSL and not debugging WebGL.
diff --git a/www/js/smc/errors.js b/www/js/smc/errors.js
new file mode 100644
index 0000000..3900885
--- /dev/null
+++ b/www/js/smc/errors.js
@@ -0,0 +1,10 @@
+export { SmcErr };
+
+const SmcErr = {
+ UNSUPPORTED: 0, // unused
+ SHADER_COMPILATION: 1,
+ PROGRAM_INIT: 2,
+ ATTRIBUTE_MISSING: 3,
+ UNIFORM_MISSING: 4,
+ FETCH_SHADER: 5,
+}
diff --git a/www/js/smc/lib.js b/www/js/smc/lib.js
new file mode 100644
index 0000000..cbff55e
--- /dev/null
+++ b/www/js/smc/lib.js
@@ -0,0 +1,4 @@
+import { Smc } from "./smc.js";
+import { SmcErr } from "./errors.js";
+
+export { Smc, SmcErr };
diff --git a/www/js/smc/progbuilder.js b/www/js/smc/progbuilder.js
new file mode 100644
index 0000000..6084410
--- /dev/null
+++ b/www/js/smc/progbuilder.js
@@ -0,0 +1,133 @@
+import { SmcErr } from './errors.js';
+
+export { SmcProgramBuilder };
+
+class SmcProgramBuilder {
+ #gl;
+ #program;
+
+ #isBuilt = false;
+ #hasVertexShader = false;
+ #hasFragmentShader = false;
+
+ #defaultVertexShader = `
+ attribute vec4 aVertex;
+
+ void main() {
+ gl_Position = aVertex;
+ }
+ `;
+
+ // TODO: reset the sample fragment shader back to the rainbow
+ #sampleFragmentShader = `
+ precision mediump float;
+
+ // uniform float uTime;
+ uniform vec2 uResolution;
+
+ void main() {
+ vec2 uv = gl_FragCoord.xy / uResolution.xy;
+ // vec3 col = 0.5 + 0.5 * cos(uTime + uv.xyx + vec3(0, 2, 4));
+ // gl_FragColor = vec4(col, 1.0);
+ // gl_FragColor = vec4(216., 43., 72., 255.) / 255.;
+
+
+ // float maxfc = max(gl_FragCoord.x, gl_FragCoord.y);
+ // gl_FragColor = vec4(gl_FragCoord.xy, maxfc, maxfc) / maxfc;
+
+ float maxuv = max(uv.x, uv.y);
+ gl_FragColor = vec4(216. * maxuv, 43., 72., 255.) / 255.;
+
+
+ // vec3 col = 0.5 + 0.5*cos(uv.xyx+vec3(0,2,4));
+ // gl_FragColor = vec4(col, 1.);
+ }
+ `;
+
+
+ constructor(gl, raiseError) {
+ this.#gl = gl;
+ this.#program = this.#gl.createProgram();
+ this.raiseError = raiseError;
+ }
+
+ addVertexShader(source) {
+ this.#gl.attachShader(
+ this.#program,
+ this.#newShader(
+ this.#gl.VERTEX_SHADER,
+ source
+ )
+ )
+ this.#hasVertexShader = true;
+ return this;
+ }
+
+ addFragmentShader(source) {
+ this.#gl.attachShader(
+ this.#program,
+ this.#newShader(
+ this.#gl.FRAGMENT_SHADER,
+ source
+ )
+ )
+ console.log(source)
+ this.#hasFragmentShader = true;
+ return this;
+ }
+
+ // fetchVertexShader(uri) {
+ // (async () => this.#fetchShader(uri, (source) => this.addVertexShader(source)))();
+ // return this;
+ // }
+
+ // async fetchFragmentShader(uri) {
+ // var delegate = (source) => this.addFragmentShader(source);
+ // var source = await this.#fetchShader(uri);
+ // return this;
+ // }
+
+ build() {
+ // avoid user accidental calls to build()
+ if (!this.#isBuilt) {
+ if (!this.#hasVertexShader)
+ this.addVertexShader(this.#defaultVertexShader)
+ if (!this.#hasFragmentShader)
+ this.addFragmentShader(this.#sampleFragmentShader);
+
+ this.#gl.linkProgram(this.#program);
+ this.#gl.useProgram(this.#program);
+ }
+ return this.#program;
+ }
+
+ // Creates a shader of the given type, uploads the source and compiles
+ #newShader(type, source) {
+ const shader = this.#gl.createShader(type);
+ this.#gl.shaderSource(shader, source);
+ this.#gl.compileShader(shader);
+
+ if (!this.#gl.getShaderParameter(shader, this.#gl.COMPILE_STATUS)) {
+ this.#gl.deleteShader(shader);
+ const infoLog = this.#gl.getShaderInfoLog(shader);
+ this.raiseError(
+ SmcErr.SHADER_COMPILATION,
+ new Error(`An error occurred while compiling the shader: ${infoLog}`)
+ );
+ }
+
+ return shader;
+ }
+
+ // async #fetchShader(uri, delegate) {
+ // const res = await fetch(uri);
+ // if (res.ok)
+ // return await res.text();
+ // this.raiseError(
+ // SmcErr.FETCH_SHADER,
+ // `Failed to load shader source ${url}: ${res.status} ${res.json()}`);
+ // return ""
+ // }
+
+}
+
diff --git a/www/js/smc/smc.js b/www/js/smc/smc.js
new file mode 100644
index 0000000..9829921
--- /dev/null
+++ b/www/js/smc/smc.js
@@ -0,0 +1,293 @@
+import { SmcErr } from "./errors.js";
+import { SmcProgramBuilder } from "./progbuilder.js";
+import { hexToRgba } from "./util.js";
+
+export { Smc, UniformType };
+
+const UniformType = {
+ Float1: 0,
+ Float2: 1,
+ Float3: 2,
+ Float4: 3,
+ Int1: 4,
+ Int2: 5,
+ Int3: 6,
+ Int4: 7,
+};
+
+class Smc {
+ #canvas;
+ #gl;
+
+ // Position array of a "full-screen" quad (encoded as TRIANGLE_STRIP)
+ // Ref: https://en.wikipedia.org/wiki/Triangle_strip
+ // NOTE: +x,+y is top-right & -x,-y is bottom-left
+ #verticesFullscreen = [
+ -1.0, 1.0,
+ -1.0, -1.0,
+ 1.0, 1.0,
+ 1.0, -1.0,
+ ];
+ #vertices = this.#verticesFullscreen;
+ #attributes = new Map();
+ #uniforms = new Map();
+ #program = null;
+ #clearBitFlags;
+
+ #maxFps;
+ #minDeltaTimeMs; // in milliseconds
+ #prevTimeMs = 0;
+
+ #errorDelegate = (_, error) => { throw error };
+ #initDelegate = (_) => { };
+ #resizeDelegate = (_) => { };
+
+ constructor(canvas) {
+ this.raiseError = this.raiseError.bind(this);
+ this.render = this.render.bind(this);
+ this.renderLoop = this.renderLoop.bind(this);
+ // DEBUG: is this necessary
+ this.setAttribute = this.setAttribute.bind(this);
+ this.setUniform = this.setUniform.bind(this);
+
+ this.#canvas = canvas;
+ this.#gl = Smc.#getWebGlContext(canvas);
+ // NOTE: smc.isWebGlSupported() should be queried prior
+ if (this.#gl == null)
+ throw new Error("Unable to initialize WebGL. Your browser or machine may not support it.");
+
+ // clear the entire depth buffer when this.#gl.clear is called
+ this.#gl.clearDepth(1.0);
+ this.#clearBitFlags = this.#gl.COLOR_BUFFER_BIT | this.#gl.DEPTH_BUFFER_BIT;
+ // set WebGL's render context (number of pixels to draw)
+ this.#gl.viewport(0, 0, this.#gl.canvas.width, this.#gl.canvas.height);
+
+ // set defaults
+ this.setMaxFps(30);
+ this.setClearColor(0., 0., 0., 255.);
+ }
+
+ static #getWebGlContext(canvas) {
+ try {
+ return canvas.getContext("webgl") ?? canvas.getContext("experimental-webgl");
+ } catch {
+ return null;
+ };
+ }
+
+ static isWebGlSupported() {
+ try {
+ const canvas = document.createElement('canvas');
+ return !!window.WebGLRenderingContext && Smc.#getWebGlContext(canvas) != null;
+ } catch (e) {
+ return false;
+ }
+ }
+
+ onError(delegate) {
+ this.#errorDelegate = delegate;
+ return this;
+ }
+
+ onInit(delegate) {
+ this.#initDelegate = delegate;
+ return this;
+ }
+
+ onResize(delegate) {
+ this.#resizeDelegate = delegate;
+ return this;
+ }
+
+ setClearColorHex(color) {
+ color = hexToRgba(color);
+ if (color == null) {
+ // this.raiseError isn't needed because this should
+ // be treated as a "compilation" error not a "runtime" error
+ throw new Error(`setClearColorHex expects an RGB/RGBA hex value, got "${color}"`);
+ }
+ return this.setClearColor(color.r, color.g, color.b, color.a);
+ }
+
+ setClearColor(r, g, b, a) {
+ this.#gl.clearColor(r / 255., g / 255., b / 255., a / 255.);
+ return this;
+ }
+
+ setVertices(positions) {
+ this.#vertices = positions;
+ return this;
+ }
+
+ setMaxFps(fps) {
+ this.#maxFps = fps;
+ this.#minDeltaTimeMs = fps ? 1000 / fps : null;
+ return this;
+ }
+
+ setProgram(delegate) {
+ const builder = new SmcProgramBuilder(this.#gl, this.raiseError);
+ var result = delegate(builder);
+
+ this.#program = result.build();
+ if (!this.#gl.getProgramParameter(this.#program, this.#gl.LINK_STATUS)) {
+ const infoLog = this.#gl.getProgramInfoLog(this.#program);
+ this.raiseError(
+ SmcErr.PROGRAM_INIT,
+ new Error(`Unable to initialize the shader program: ${infoLog}`)
+ )
+ }
+
+ this.#addAttribute("aVertex", this.#setVerticesAttribute.bind(this));
+ // DEBUG: uncomment afterwards
+ this.#addUniform("uResolution", UniformType.Float2, false, (_) => new Float32Array([this.#gl.canvas.width, this.#gl.canvas.height]));
+ this.#addUniform("uTime", UniformType.Float1);
+ this.#addUniform("uDelta", UniformType.Float1);
+ return this;
+ }
+
+ run() {
+ this.#initDelegate()
+ this.setAttribute("aVertex", this.#vertices);
+ this.setUniform("uResolution", this.#gl.canvas.width, this.#gl.canvas.height);
+
+ if (this.#maxFps == 0)
+ requestAnimationFrame(this.render)
+ else
+ requestAnimationFrame(this.renderLoop);
+ }
+
+ // requestAnimationFrame requests the browser to call the renderLoop
+ // callback function before the next repaint.
+ // `time` is the milliseconds elapsed since the page loaded.
+ renderLoop(time) {
+ var delta = time - this.#prevTimeMs;
+ this.render(time, delta);
+
+ setTimeout(
+ () => requestAnimationFrame(this.renderLoop),
+ Math.max(0, delta - this.#minDeltaTimeMs)
+ );
+ this.#prevTimeMs = time;
+ }
+
+ render(time, delta) {
+ this.setUniform("uTime", time * 0.001);
+ this.setUniform("uDelta", delta);
+ this.#gl.clear(this.#gl.COLOR_BUFFER_BIT | this.#gl.DEPTH_BUFFER_BIT);
+ this.#gl.drawArrays(this.#gl.TRIANGLE_STRIP, 0, this.#vertices.length / 2);
+ }
+
+ #addAttribute(name, setDelegate, required = false) {
+ var location = this.#gl.getAttribLocation(this.#program, name);
+ if (location == -1) {
+ if (required) {
+ this.raiseError(
+ SmcErr.ATTRIBUTE_MISSING,
+ `Linked program missing required attribute: "${name}"`
+ );
+ }
+ location = null;
+ }
+ this.#attributes.set(
+ name,
+ {
+ setDelegate: setDelegate,
+ location: location,
+ });
+
+ }
+
+ #addUniform(name, type, setEachFrame, setCallback, required = false) {
+ const location = this.#gl.getUniformLocation(this.#program, name);
+ if (location == -1) {
+ if (required) {
+ this.raiseError(
+ SmcErr.UNIFORM_MISSING,
+ `Linked program missing required uniform: "${name}"`
+ )
+ }
+ location = null;
+ }
+
+ if (type == UniformType.Float1)
+ var uniformfv = (...values) => this.#gl.uniform1f(location, ...values);
+ else if (type == UniformType.Float2)
+ var uniformfv = (...values) => this.#gl.uniform2f(location, ...values);
+ else if (type == UniformType.Float3)
+ var uniformfv = (...values) => this.#gl.uniform3f(location, ...values);
+ else if (type == UniformType.Float4)
+ var uniformfv = (...values) => this.#gl.uniform4f(location, ...values);
+ else if (type == UniformType.Int1)
+ var uniformfv = (...values) => this.#gl.uniform1i(location, ...values);
+ else if (type == UniformType.Int2)
+ var uniformfv = (...values) => this.#gl.uniform2i(location, ...values);
+ else if (type == UniformType.Int3)
+ var uniformfv = (...values) => this.#gl.uniform3i(location, ...values);
+ else if (type == UniformType.Int4)
+ var uniformfv = (...values) => this.#gl.uniform4i(location, ...values);
+ else {
+ // this.raiseError isn't needed because this should
+ // be treated as a "compilation" error not a "runtime" error
+ throw new Error(`Expected type from enum UniformType, but got "${type}"`);
+ }
+
+ // simplify function call to a single argument
+ this.#uniforms.set(
+ name,
+ {
+ setDelegate: uniformfv,
+ location: location,
+ setEachFrame: setEachFrame,
+ setCallback: setCallback,
+ }
+ );
+ }
+
+ #getAttributeLocation(name) {
+ return this.#attributes.get(name).location;
+ }
+
+ #getUniformLocation(name) {
+ return this.#uniforms.get(name).location;
+ }
+
+ setAttribute(name, ...args) {
+ if (this.#getAttributeLocation(name) != null)
+ this.#attributes.get(name).setDelegate(...args);
+ }
+
+ setUniform(name, ...args) {
+ if (this.#getUniformLocation(name) != null) {
+ this.#uniforms.get(name).setDelegate(...args);
+ }
+ }
+
+ #setVerticesAttribute(vertices) {
+ this.#vertices = vertices;
+
+ const buffer = this.#gl.createBuffer();
+ this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, buffer);
+ this.#gl.bufferData(
+ this.#gl.ARRAY_BUFFER,
+ new Float32Array(vertices),
+ this.#gl.STATIC_DRAW
+ );
+
+ this.#gl.vertexAttribPointer(
+ this.#getAttributeLocation("aVertex"),
+ 2, // (size) one vertex == 2 floats
+ this.#gl.FLOAT, // (type) vertex positions given as 32bit floats
+ false, // (normalized) don't normalize
+ 0, // (stride) buffer offset pointer BETWEEN elements (0 => packed)
+ 0, // (offset) buffer offset pointer from START to first element
+ )
+ this.#gl.enableVertexAttribArray(this.#getAttributeLocation("aVertex"));
+
+ return buffer;
+ }
+
+ raiseError(type, error) {
+ this.#errorDelegate(type, error);
+ }
+}
diff --git a/www/js/smc/util.js b/www/js/smc/util.js
new file mode 100644
index 0000000..a786d02
--- /dev/null
+++ b/www/js/smc/util.js
@@ -0,0 +1,24 @@
+export { hexToRgba, hexToRgbaNormal };
+
+/* Converts a string of the form "#XXXXXX"
+ *
+*/
+function hexToRgba(hex) {
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex.toLowerCase());
+ return result ? {
+ r: parseInt(result[1], 16),
+ g: parseInt(result[2], 16),
+ b: parseInt(result[3], 16),
+ a: result.length == 4 ? parseInt(result[4], 16) : 255.,
+ } : null;
+}
+
+function hexToRgbaNormal(hex) {
+ var result = hexToRgba(hex);
+ return result ? {
+ r: result.r / 255.,
+ g: result.g / 255.,
+ b: result.b / 255.,
+ a: result.a / 255.,
+ } : null;
+}
diff --git a/www/js/webgl-demo.js b/www/js/webgl-demo.js
deleted file mode 100644
index 5e58854..0000000
--- a/www/js/webgl-demo.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import { initBuffers } from "./init-buffers.js";
-import { drawScene } from "./draw-scene.js";
-
-main();
-
-// Initialize a shader program, so WebGL knows how to draw our data
-function initShaderProgram(gl, vsSource, fsSource) {
- const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
- const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
-
- // Create the shader program
- const program = gl.createProgram();
- gl.attachShader(program, vertexShader);
- gl.attachShader(program, fragmentShader);
- gl.linkProgram(program);
-
- // If creating the shader program failed, alert
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
- alert(
- `Unable to initialize the shader program: ${gl.getProgramInfoLog(
- program,
- )}`,
- );
- return null;
- }
-
- return program;
-}
-
-// Creates a shader of the given type, uploads the source and compiles
-function loadShader(gl, type, source) {
- const shader = gl.createShader(type);
-
- // Send the source to the shader object
- gl.shaderSource(shader, source);
-
- // Compile the shader program
- gl.compileShader(shader);
-
- // See if it compiled successfully
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
- gl.deleteShader(shader);
- throw new Error(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`);
- }
-
- return shader;
-}
-
-function renderShader(gl, vsSource, fsSource) {
- const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
-
- // Collect all the info needed to use the shader program.
- // Look up which attribute our shader program is using
- // for aVertexPosition and look up uniform locations.
- const programInfo = {
- program: shaderProgram,
- attribLocations: {
- vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
- },
- uniformLocations: {
- resolution: gl.getUniformLocation(shaderProgram, "u_resolution"),
- time: gl.getUniformLocation(shaderProgram, "u_time"),
- },
- };
-
- // Here's where we call the routine that builds all the
- // objects we'll be drawing.
- const buffers = initBuffers(gl);
-
- // Draw the scene
- // drawScene(gl, programInfo, buffers, 0);
-
- const fpsLimit = 30;
- const fpsDelta = 1000 / 30;
- // let timePrev = 0;
- // requestAnimationFrame asks the browser to call render,
- // providing the time in milliseconds since the page loaded
- function render(time) {
- time *= 0.001; // convert to seconds
- // delta = time - timePrev;
-
- drawScene(gl, programInfo, buffers, time);
-
- setTimeout(() => requestAnimationFrame(render), fpsDelta);
- }
- function update() {
- requestAnimationFrame(render);
- }
-
- // XXX: TODO: read this guide it's great! https://stackoverflow.com/questions/56998225/why-is-rendering-blurred-in-webgl
- // window.addEventListener('resize', render);
-
- requestAnimationFrame(render);
- // update();
- // setInterval(update, 1000 / fpsLimit);
-}
-
-function fetchShader(name) {
- return fetch(`../shaders/${name}`)
- .then(res => {
- if (!res.ok) throw new Error(`Failed to load fragment shader source ${url}: ${res.status}`);
- return res.text();
- });
-
-}
-
-function main() {
- const canvas = document.querySelector("#gl-canvas");
- // Initialize the GL context
- const gl = canvas.getContext("webgl");
-
- // XXX: TODO: use `window.addEventListener('resize', ...);`
- canvas.setAttribute('width', window.innerWidth);
- canvas.setAttribute('height', window.innerHeight);
-
- // Only continue if WebGL is available and working
- if (gl === null) {
- throw new Error("Unable to initialize WebGL. Your browser or machine may not support it.");
- }
-
- // Vertex shader program
- const vsSource = `
- attribute vec4 aVertexPosition;
-
- void main() {
- gl_Position = aVertexPosition;
- }
- `;
-
- // Fetch fragment shader program
- fetchShader("segfault.glsl")
- .then(fsSource => {
- renderShader(gl, vsSource, fsSource);
- });
-}
-
diff --git a/www/shader.html b/www/shader.html
deleted file mode 100644
index fd65714..0000000
--- a/www/shader.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- WebGL Demo
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/www/shaders/fbm.glsl b/www/shaders/fbm.glsl
new file mode 100644
index 0000000..dcb1f4d
--- /dev/null
+++ b/www/shaders/fbm.glsl
@@ -0,0 +1,96 @@
+// Author @patriciogv - 2015
+// http://patriciogonzalezvivo.com
+
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+uniform vec2 uResolution;
+uniform float uTime;
+
+float random (in vec2 _st) {
+ return fract(sin(dot(_st.xy,
+ vec2(12.9898,78.233)))*
+ 43758.5453123);
+}
+
+// Based on Morgan McGuire @morgan3d
+// https://www.shadertoy.com/view/4dS3Wd
+float noise (in vec2 _st) {
+ vec2 i = floor(_st);
+ vec2 f = fract(_st);
+
+ // Four corners in 2D of a tile
+ float a = random(i);
+ float b = random(i + vec2(1.0, 0.0));
+ float c = random(i + vec2(0.0, 1.0));
+ float d = random(i + vec2(1.0, 1.0));
+
+ vec2 u = f * f * (3.0 - 2.0 * f);
+
+ return mix(a, b, u.x) +
+ (c - a)* u.y * (1.0 - u.x) +
+ (d - b) * u.x * u.y;
+}
+
+#define NUM_OCTAVES 100
+// Brightness (0.0 - 1.0)
+#define BRIGHTNESS 0.55
+#define LACUNARITY 2.0
+#define GAIN 0.5
+#define SHIFT 100.0
+
+// VAR_THETA defines whether to compute
+// sin/cos values at runtime or
+#define VAR_THETA 0
+#define THETA 0.5
+#if (VAR_THETA == 1)
+#endif
+
+float fbm ( in vec2 _st) {
+ float v = 0.0;
+ float a = BRIGHTNESS;
+ // Rotate to reduce axial bias
+ mat2 T = LACUNARITY * mat2(cos(THETA), sin(THETA),
+ -sin(THETA), cos(THETA));
+ for (int i = 0; i < NUM_OCTAVES; ++i) {
+ _st = T * _st + SHIFT;
+ v += noise(_st) * a;
+ a *= GAIN;
+ }
+ return v;
+}
+
+#define SCALE 3.
+
+void main() {
+ vec2 st = gl_FragCoord.xy/uResolution.xy*SCALE;
+ // st += st * abs(sin(uTime*0.1)*3.0);
+
+ vec2 q = vec2(
+ fbm( st + 0.*uTime),
+ fbm( st + vec2(1.0))
+ );
+
+ vec2 r = vec2(
+ fbm( st + 1.0*q + vec2(1.7,9.2)+ 0.15*uTime ),
+ fbm( st + 1.0*q + vec2(8.3,2.8)+ 0.126*uTime)
+ );
+
+ float f = fbm(st+r);
+
+ vec3 color = mix(vec3(0.101961,0.619608,0.666667),
+ vec3(0.666667,0.666667,0.498039),
+ clamp((f*f)*4.0,0.0,1.0));
+
+ color = mix(color,
+ vec3(0,0,0.164706),
+ clamp(length(q),0.0,1.0));
+
+ color = mix(color,
+ vec3(0.666667,1,1),
+ clamp(length(r.x),0.0,1.0));
+
+ gl_FragColor = vec4((f*f*f+.6*f*f+.5*f)*color,1.);
+}
+
diff --git a/www/shaders/optimised.glsl b/www/shaders/optimised.glsl
new file mode 100644
index 0000000..8fd8d1b
--- /dev/null
+++ b/www/shaders/optimised.glsl
@@ -0,0 +1,323 @@
+/* BTW: You can use ANY function as the noise/plasma function
+ * It just needs to return a float in the range 0.0 - 17.0
+ * But shouldn't return 0.0 or 17.0 (they're exclusive bounds).
+ * View this shader on shadertoy: https://www.shadertoy.com/view/t3tSRj#
+ */
+
+// is highp wasteful for this shader?
+#ifdef GL_ES
+# ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+# else
+precision mediump float;
+# endif
+#endif
+
+uniform float uTime;
+uniform vec2 uResolution;
+
+/* ==== Text Colouring ==== */
+#define PHOSPHOR_COL vec4(196./255., 167./255., 231./255., 1.)
+// #define BG_COL vec4(0.2, 0.0, 0.2, 0.5)
+#define BG_COL vec4(14./255., 13./255., 20./255., 1.)
+/* ======= Text Size ======= */
+#define FONT_SIZE vec2(10.,20.)
+#define ROWCOLS vec2(80., 24.)
+
+// ===================================================================
+// Library Functions
+//
+float rand (in vec2 _st) {
+ return fract(sin(dot(_st.xy, vec2(12.9898,78.233))) * 43758.5453123);
+}
+
+float quantise(float val, float n) {
+ return clamp(floor(val * n), 0.0, n) / n;
+}
+
+float roundSquare(vec2 p, vec2 b, float r) {
+ return length(max(abs(p)-b,0.0))-r;
+}
+
+
+// ===================================================================
+// VT220 Font Rendering
+// Author/Source : https://www.shadertoy.com/view/llSXDV
+//
+#define l(y,a,b) roundLine(p, vec2(float(a), float(y)), vec2(float(b), float(y)))
+float roundLine(vec2 p, vec2 a, vec2 b) {
+ b -= a + vec2(1.0,0.);
+ p -= a;
+ float f = length(p-clamp(dot(p,b)/dot(b,b),0.0,1.0)*b);
+ if (uResolution.y < 320.) // attempt to get rid of aliasing on small resolution
+ return smoothstep(1.0, 0.9, f);
+ else if (uResolution.y < 720.)
+ return smoothstep(0.75, 0.5, f);
+ else
+ return smoothstep(1., 0., f);
+}
+
+float vt220Font(vec2 p, float c) {
+ if (c < 1.) return 0.;
+ if (p.y > 16.) {
+ if (c > 2.) return 0.0;
+ if (c > 1.) return l(17,1,9);
+ }
+ if (p.y > 14.) {
+ if (c > 16.) return l(15,3,8);
+ if (c > 15.) return l(15,1,8);
+ if (c > 14.) return l(15,1,3)+ l(15,7,9);
+ if (c > 13.) return l(15,2,8);
+ if (c > 12.) return l(15,1,9);
+ if (c > 11.) return l(15,2,8);
+ if (c > 10.) return l(15,1,3)+ l(15,6,8);
+ if (c > 9.) return l(15,4,6);
+ if (c > 8.) return l(15,2,4)+ l(15,5,7);
+ if (c > 7.) return l(15,2,8);
+ if (c > 6.) return l(15,2,8);
+ if (c > 5.) return l(15,2,8);
+ if (c > 4.) return l(15,2,9);
+ if (c > 3.) return l(15,1,8);
+ if (c > 2.) return l(15,2,9);
+ }
+ if (p.y > 12.) {
+ if (c > 16.) return l(13,2,4)+ l(13,7,9);
+ if (c > 15.) return l(13,2,4)+ l(13,7,9);
+ if (c > 14.) return l(13,1,3)+ l(13,7,9);
+ if (c > 13.) return l(13,1,3)+ l(13,7,9);
+ if (c > 12.) return l(13,1,3);
+ if (c > 11.) return l(13,4,6);
+ if (c > 10.) return l(13,2,4)+ l(13,5,9);
+ if (c > 9.) return l(13,2,8);
+ if (c > 8.) return l(13,2,4)+ l(13,5,7);
+ if (c > 7.) return l(13,1,3)+ l(13,7,9);
+ if (c > 6.) return l(13,1,3)+ l(13,7,9);
+ if (c > 5.) return l(13,1,3)+ l(13,7,9);
+ if (c > 4.) return l(13,1,3)+ l(15,2,9);
+ if (c > 3.) return l(13,1,4)+ l(13,7,9);
+ if (c > 2.) return l(13,1,3)+ l(13,6,9);
+ }
+ if (p.y > 10.) {
+ if (c > 16.) return l(11,1,3);
+ if (c > 15.) return l(11,2,4)+ l(11,7,9);
+ if (c > 14.) return l(11,1,9);
+ if (c > 13.) return l(11,7,9);
+ if (c > 12.) return l(11,2,5);
+ if (c > 11.) return l(11,4,6);
+ if (c > 10.) return l(11,3,5)+ l(11,6,8);
+ if (c > 9.) return l(11,4,6)+ l(11,7,9);
+ if (c > 8.) return l(11,1,8);
+ if (c > 7.) return l(11,1,3)+ l(11,7,9);
+ if (c > 6.) return l(11,1,3)+ l(11,7,9);
+ if (c > 5.) return l(11,1,3)+ l(11,7,9);
+ if (c > 4.) return l(11,1,3);
+ if (c > 3.) return l(11,1,3)+ l(11,7,9);
+ if (c > 2.) return l(11,2,9);
+ }
+ if (p.y > 8.) {
+ if (c > 16.) return l(9,1,3);
+ if (c > 15.) return l(9,2,8);
+ if (c > 14.) return l(9,1,3)+ l(9,7,9);
+ if (c > 13.) return l(9,4,8);
+ if (c > 12.) return l(9,4,8);
+ if (c > 11.) return l(9,4,6);
+ if (c > 10.) return l(9,4,6);
+ if (c > 9.) return l(9,2,8);
+ if (c > 8.) return l(9,2,4)+ l(9,5,7);
+ if (c > 7.) return l(9,1,3)+ l(9,7,9);
+ if (c > 6.) return l(9,1,3)+ l(9,7,9);
+ if (c > 5.) return l(9,1,3)+ l(9,7,9);
+ if (c > 4.) return l(9,1,3)+ l(9,7,9);
+ if (c > 3.) return l(9,1,4)+ l(9,7,9);
+ if (c > 2.) return l(9,7,9);
+ }
+ if (p.y > 6.) {
+ if (c > 16.) return l(7,1,3);
+ if (c > 15.) return l(7,2,4)+ l(7,7,9);
+ if (c > 14.) return l(7,2,4)+ l(7,6,8);
+ if (c > 13.) return l(7,5,7);
+ if (c > 12.) return l(7,7,9);
+ if (c > 11.) return l(7,2,6);
+ if (c > 10.) return l(7,2,4)+ l(7,5,7);
+ if (c > 9.) return l(7,1,3)+ l(7,4,6);
+ if (c > 8.) return l(7,1,8);
+ if (c > 7.) return l(7,2,8);
+ if (c > 6.) return l(7,2,8);
+ if (c > 5.) return l(7,2,8);
+ if (c > 4.) return l(7,2,8);
+ if (c > 3.) return l(7,1,8);
+ if (c > 2.) return l(7,2,8);
+ }
+ if (p.y > 4.) {
+ if (c > 16.) return l(5,2,4)+ l(5,7,9);
+ if (c > 15.) return l(5,2,4)+ l(5,7,9);
+ if (c > 14.) return l(5,3,7);
+ if (c > 13.) return l(5,6,8);
+ if (c > 12.) return l(5,1,3)+ l(5,7,9);
+ if (c > 11.) return l(5,3,6);
+ if (c > 10.) return l(5,1,5)+ l(5,6,8);
+ if (c > 9.) return l(5,2,8);
+ if (c > 8.) return l(5,2,4)+ l(5,5,7);
+ if (c > 7.) return 0.;
+ if (c > 6.) return 0.;
+ if (c > 5.) return 0.;
+ if (c > 4.) return 0.;
+ if (c > 3.) return l(5,1,3);
+ if (c > 2.) return 0.;
+ }
+ if (p.y > 2.) {
+ if (c > 16.) return l(3,3,8);
+ if (c > 15.) return l(3,1,8);
+ if (c > 14.) return l(3,4,6);
+ if (c > 13.) return l(3,1,9);
+ if (c > 12.) return l(3,2,8);
+ if (c > 11.) return l(3,4,6);
+ if (c > 10.) return l(3,2,4)+ l(3,7,9);
+ if (c > 9.) return l(3,4,6);
+ if (c > 8.) return l(3,2,4)+ l(3,5,7);
+ if (c > 7.) return l(3,2,4)+ l(3,6,8);
+ if (c > 6.) return l(3,1,3)+ l(3,4,7);
+ if (c > 5.) return l(3,2,4)+ l(3,6,8);
+ if (c > 4.) return 0.;
+ if (c > 3.) return l(3,1,3);
+ if (c > 2.) return 0.;
+ }
+ else {
+ if (c > 7.) return 0.;
+ if (c > 6.) return l(1,2,5)+ l(1,6,8);
+ }
+ return 0.0;
+}
+
+
+// ===================================================================
+// Text Effects
+// textLines(...) is for simulating the writing of random characters in line formats
+// https://www.shadertoy.com/view/llSXDV (same author as VT220 font rendering)
+//
+float textLines(vec2 uvG) {
+ float wt = 5. * (uTime + 0.5*sin(uTime*1.4) + 0.2*sin(uTime*2.9)); // wobbly time
+ vec2 uvGt = uvG + vec2(0., floor(wt));
+ float ll = rand(vec2(uvGt.y, - 1.)) * ROWCOLS.x; // line length
+
+ if (uvG.y > ROWCOLS.y - 2.){
+ if (ceil(uvG.x) == floor(min(ll, fract(wt)*ROWCOLS.x)))
+ return 2.;
+ if (ceil(uvG.x) > floor(min(ll, fract(wt)*ROWCOLS.x)))
+ return 0.;
+ }
+ if (uvGt.x > 5. && rand(uvGt) < .075)
+ return 0.;
+ if (max(5., uvGt.x) > ll)
+ return 0.;
+
+ return rand(uvGt)*15. + 2.;
+}
+
+
+// ===================================================================
+// Noise Generation Algorithms
+// noise(...) is for the main noise generation algorithm (very tunable)
+// https://www.shadertoy.com/view/MsdGWn
+//
+
+// Based on Morgan McGuire @morgan3d
+// https://www.shadertoy.com/view/4dS3Wd
+float noise (in vec2 _st) {
+ vec2 i = floor(_st);
+ vec2 f = fract(_st);
+
+ // Four corners in 2D of a tile
+ float a = rand(i);
+ float b = rand(i + vec2(1.0, 0.0));
+ float c = rand(i + vec2(0.0, 1.0));
+ float d = rand(i + vec2(1.0, 1.0));
+
+ vec2 u = f * f * (3.0 - 2.0 * f);
+
+ return mix(a, b, u.x) +
+ (c - a)* u.y * (1.0 - u.x) +
+ (d - b) * u.x * u.y;
+}
+
+#define NUM_OCTAVES 100
+// Brightness (0.0 - 1.0)
+#define BRIGHTNESS 0.55
+#define LACUNARITY 2.0
+#define GAIN 0.5
+#define SHIFT 100.0
+
+// VAR_THETA defines whether to compute
+// sin/cos values at runtime or
+#define VAR_THETA 0
+#define THETA 0.5
+#if (VAR_THETA == 1)
+#endif
+
+float fbm( in vec2 _st) {
+ float v = 0.0;
+ float a = BRIGHTNESS;
+ // Rotate to reduce axial bias
+ mat2 T = LACUNARITY * mat2(cos(THETA), sin(THETA),
+ -sin(THETA), cos(THETA));
+ for (int i = 0; i < NUM_OCTAVES; ++i) {
+ _st = T * _st + SHIFT;
+ v += noise(_st) * a;
+ a *= GAIN;
+ }
+ return v;
+}
+
+
+#define SCALE_UV 3.
+#define SCALE_TIME 1.
+
+// XXX: TODO: use two shaders, the first on a MUCH lower resolution (one pixel for each text character)
+// XXX: TODO: then the second should map those pixel values to higher resolution text characters
+void main() {
+ vec2 uv = gl_FragCoord.xy / uResolution;
+ vec2 st = uv * SCALE;
+
+ // // uvNoise = ceil(uvNoise * ROWCOLS) / ROWCOLS;
+ // float val = noise(st);
+ // // Noise is fed through a sigmoid function, then quantised to integer range 0-17
+ // val = (exp(val) / 2.71828); // increase contrast (normalised 0.0 - 1.0)
+ // val = 1.0 / val;
+ // val *= 1.0 / (1.0 + exp(-val)) - 0.5; // subtraction value is tunable (range 0.0 - 0.5)
+ // val *= quantise(val, 17.0); // quantise by 17 then normalise back to 0.0 - 1.0
+ // val = pow(18.0, val) - 1.0; // TODO: try changing 18.0 to 200.0 and you'll notice some pretty changes :)
+
+ // // VT220 Font Rendering
+ // vec2 base = uv;
+ // base.y = 1 - base.y;
+ // vec2 uvT = ROWCOLS * FONT_SIZE * base;
+ // vec2 uvG = floor(ROWCOLS * base;
+ // gl_FragColor = vt220Font(uvT - uvG * FONT_SIZE, val) * PHOSPHOR_COL + BG_COL;
+
+ vec2 q = vec2(
+ fbm( st + 0.*uTime),
+ fbm( st + vec2(1.0))
+ );
+
+ vec2 r = vec2(
+ fbm( st + 1.0*q + vec2(1.7,9.2)+ 0.15*uTime ),
+ fbm( st + 1.0*q + vec2(8.3,2.8)+ 0.126*uTime)
+ );
+
+ float f = fbm(st+r);
+
+ vec3 color = mix(vec3(0.101961,0.619608,0.666667),
+ vec3(0.666667,0.666667,0.498039),
+ clamp((f*f)*4.0,0.0,1.0));
+
+ color = mix(color,
+ vec3(0,0,0.164706),
+ clamp(length(q),0.0,1.0));
+
+ color = mix(color,
+ vec3(0.666667,1,1),
+ clamp(length(r.x),0.0,1.0));
+
+ gl_FragColor = vec4((f*f*f+.6*f*f+.5*f)*color,1.);
+}
+
diff --git a/www/shaders/sample.glsl b/www/shaders/sample.glsl
new file mode 100644
index 0000000..9b54b8f
--- /dev/null
+++ b/www/shaders/sample.glsl
@@ -0,0 +1,23 @@
+precision mediump float;
+
+// uniform float uTime;
+uniform vec2 uResolution;
+
+void main() {
+ vec2 uv = gl_FragCoord.xy / uResolution.xy;
+ // vec3 col = 0.5 + 0.5 * cos(uTime + uv.xyx + vec3(0, 2, 4));
+ // gl_FragColor = vec4(col, 1.0);
+ // gl_FragColor = vec4(216., 43., 72., 255.) / 255.;
+
+
+ // float maxfc = max(gl_FragCoord.x, gl_FragCoord.y);
+ // gl_FragColor = vec4(gl_FragCoord.xy, maxfc, maxfc) / maxfc;
+
+ float maxuv = max(uv.x, uv.y);
+ gl_FragColor = vec4(34., 43., 192.*maxuv, 255.) / 255.;
+
+
+ // vec3 col = 0.5 + 0.5*cos(uv.xyx+vec3(0,2,4));
+ // gl_FragColor = vec4(col, 1.);
+}
+
diff --git a/www/shaders/segfault.glsl b/www/shaders/segfault.glsl
index a3d73a8..a96bb19 100644
--- a/www/shaders/segfault.glsl
+++ b/www/shaders/segfault.glsl
@@ -11,13 +11,13 @@
precision mediump float;
#endif
-uniform float u_time;
-uniform vec2 u_resolution;
+uniform float uTime;
+uniform vec2 uResolution;
/* ==== Text Colouring ==== */
-#define PHOSPHOR_COL vec4(1, 1., 1., 1.)
+#define PHOSPHOR_COL vec4(196./255., 167./255., 231./255., 1.)
// #define BG_COL vec4(0.2, 0.0, 0.2, 0.5)
-#define BG_COL vec4(0.0, 0.0, 0.0, 1.)
+#define BG_COL vec4(14./255., 13./255., 20./255., 1.)
/* ======= Text Size ======= */
#define FONT_SIZE vec2(10.,20.)
#define ROWCOLS vec2(80., 24.)
@@ -155,9 +155,9 @@ float roundLine(vec2 p, vec2 a, vec2 b) {
b -= a + vec2(1.0,0.);
p -= a;
float f = length(p-clamp(dot(p,b)/dot(b,b),0.0,1.0)*b);
- if (u_resolution.y < 320.) // attempt to get rid of aliasing on small resolution
+ if (uResolution.y < 320.) // attempt to get rid of aliasing on small resolution
return smoothstep(1.0, 0.9, f);
- else if (u_resolution.y < 720.)
+ else if (uResolution.y < 720.)
return smoothstep(0.75, 0.5, f);
else
return smoothstep(1., 0., f);
@@ -305,7 +305,7 @@ float vt220Font(vec2 p, float c) {
// https://www.shadertoy.com/view/MsdGWn
//
float textLines(vec2 uvG) {
- float wt = 5. * (u_time + 0.5*sin(u_time*1.4) + 0.2*sin(u_time*2.9)); // wobbly time
+ float wt = 5. * (uTime + 0.5*sin(uTime*1.4) + 0.2*sin(uTime*2.9)); // wobbly time
vec2 uvGt = uvG + vec2(0., floor(wt));
float ll = rand(vec2(uvGt.y, - 1.)) * ROWCOLS.x; // line length
@@ -351,21 +351,21 @@ float smokeNoise(vec3 v) {
}
void main() {
- vec2 uv = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y);
- vec2 uvT = ROWCOLS * FONT_SIZE * uv / u_resolution.xy;
- vec2 uvG = floor(ROWCOLS * uv / u_resolution.xy);
- vec2 uvC = gl_FragCoord.xy / u_resolution.xy;
+ vec2 uv = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
+ vec2 uvT = ROWCOLS * FONT_SIZE * uv / uResolution.xy;
+ vec2 uvG = floor(ROWCOLS * uv / uResolution.xy);
+ vec2 uvC = gl_FragCoord.xy / uResolution.xy;
- vec2 uvNoise = gl_FragCoord.xy / u_resolution.xy;
+ vec2 uvNoise = gl_FragCoord.xy / uResolution.xy;
uvNoise = ceil(uvNoise * ROWCOLS) / ROWCOLS;
float val;
- if (u_time < 2.0)
+ if (uTime < 2.0)
val = textLines(uvG);
- else if (u_time < 2.3)
- val = rand(uvG * u_time) * 17.;
+ else if (uTime < 2.3)
+ val = rand(uvG * uTime) * 17.;
else {
- float noise = smokeNoise(vec3(uvNoise * noiseScale, u_time * noiseTimeScale));
+ float noise = smokeNoise(vec3(uvNoise * noiseScale, uTime * noiseTimeScale));
// Noise is fed through a sigmoid function, then quantised to integer range 0-17
val = (exp(noise) / 2.71828); // increase contrast (normalised 0.0 - 1.0)
val = 1.0 / val;
diff --git a/www/shaders/squares.glsl b/www/shaders/squares.glsl
new file mode 100644
index 0000000..3520ecc
--- /dev/null
+++ b/www/shaders/squares.glsl
@@ -0,0 +1,50 @@
+// is highp wasteful for this shader?
+#ifdef GL_FRAGMENT_PRECISION_HIGH
+precision highp float;
+#else
+precision mediump float;
+#endif
+
+uniform float uTime;
+uniform vec2 uResolution;
+
+#define ROWS 10.
+
+float rand(in vec2 _st) {
+ return fract(sin(dot(_st.xy, vec2(12.9898,78.233))) * 43758.5453123);
+}
+
+// #define STEPS 10.
+
+void main() {
+ // float ROWS = mod(uTime, 2. * STEPS);
+
+ float aspect = uResolution.x / uResolution.y;
+ float cols = floor(ROWS * aspect);
+
+ vec2 uv = vec2(
+ ceil(gl_FragCoord.x / uResolution.x * cols) / cols,
+ ceil(gl_FragCoord.y / uResolution.y * ROWS) / ROWS
+ );
+ // vec2 uv = ceil(gl_FragCoord.xy / uResolution * vec2(ROWS, COLS)) / vec2(ROWS, COLS);
+
+ float offset = rand(uv) + rand(vec2(uTime, uTime));
+ float id = mod(abs(uv.y * ROWS + uv.x * cols + offset), 4.); // project f(t) = (1, 1)t + uv against the y-axis
+ vec3 col = vec3(255., 0., 0.) / 255.;
+ if (id < 1.) {
+ col = vec3(156., 207., 216.) / 255.;
+ } else if (id < 2.) {
+ col = vec3(246., 193., 119.) / 255.;
+ } else if (id < 3.) {
+ col = vec3(196., 167., 231.) / 255.;
+ } else if (id < 4.) {
+ col = vec3(235., 111., 146.) / 255.;
+ }
+ // vec3 col = vec3(id, id, id);
+
+ // float val1 = rand(uv);
+ // float val2 = rand(val1 + uv);
+ // float val3 = rand(val2 + uv);
+ // vec3 col = vec3(val1, val2, val3);
+ gl_FragColor = vec4(col,1.0);
+}
diff --git a/www/shaders/trivial.glsl b/www/shaders/trivial.glsl
index 22464ae..9935c91 100644
--- a/www/shaders/trivial.glsl
+++ b/www/shaders/trivial.glsl
@@ -1,17 +1,17 @@
// is highp wasteful for this shader?
#ifdef GL_FRAGMENT_PRECISION_HIGH
- precision highp float;
+precision highp float;
#else
- precision mediump float;
+precision mediump float;
#endif
-uniform float u_time;
-uniform vec2 u_resolution;
+uniform float uTime;
+uniform vec2 uResolution;
void main() {
- vec2 uv = gl_FragCoord.xy / u_resolution;
+ vec2 uv = gl_FragCoord.xy / uResolution;
- vec3 col = 0.5 + 0.5 * cos(u_time + uv.xyx + vec3(0, 2, 4));
+ vec3 col = 0.5 + 0.5 * cos(uTime + uv.xyx + vec3(0, 2, 4));
gl_FragColor = vec4(col,1.0);
}
diff --git a/www/shaders/working.glsl b/www/shaders/working.glsl
new file mode 100644
index 0000000..71a0872
--- /dev/null
+++ b/www/shaders/working.glsl
@@ -0,0 +1,368 @@
+// WARNING: NOTE: this works on https://glslsandbox.com/e
+precision highp float;
+
+uniform float time;
+uniform vec2 resolution;
+
+/* ==== Text Colouring ==== */
+#define PHOSPHOR_COL vec4(1, 1., 1., 1.)
+#define BG_COL vec4(0.2, 0.0, 0.2, 0.)
+/* ======= Text Size ======= */
+#define FONT_SIZE vec2(10.,20.)
+#define ROWCOLS vec2(80., 24.)
+/* === Text Bloom Effect === */
+#define WIDTH 1.2
+#define HEIGHT 0.7
+#define SMOOTH 0.004
+/* ====== Smoke Noise ====== */
+const int noiseSwirlSteps = 0;
+const float noiseSwirlValue = 1.;
+const float noiseSwirlStepValue = noiseSwirlValue / float(noiseSwirlSteps);
+const float noiseScale = 1.0;
+const float noiseTimeScale = 0.1;
+
+// ===================================================================
+// Library Functions
+//
+float rand(vec2 co) {
+ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
+}
+
+float quantise(float val, float n) {
+ return clamp(floor(val * n), 0.0, n) / n;
+}
+
+float roundSquare(vec2 p, vec2 b, float r) {
+ return length(max(abs(p)-b,0.0))-r;
+}
+
+// standard roundSquare
+float stdRS(vec2 uv, float r) {
+ return roundSquare(uv - 0.5, vec2(WIDTH, HEIGHT) + r, 0.05);
+}
+
+// ===================================================================
+// Description : Array and textureless GLSL 2D/3D/4D simplex
+// noise functions.
+// Author : Ian McEwan, Ashima Arts.
+// Maintainer : ijm
+// Lastmod : 20110822 (ijm)
+// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
+// Distributed under the MIT License. See LICENSE file.
+// https://github.com/ashima/webgl-noise
+//
+vec3 mod289(vec3 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 mod289(vec4 x) {
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
+}
+
+vec4 permute(vec4 x) {
+ return mod289(((x*34.0)+1.0)*x);
+}
+
+vec4 taylorInvSqrt(vec4 r) {
+ return 1.79284291400159 - 0.85373472095314 * r;
+}
+
+float simplex(vec3 v) {
+ const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
+ const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
+
+ // First corner
+ vec3 i = floor(v + dot(v, C.yyy) );
+ vec3 x0 = v - i + dot(i, C.xxx) ;
+
+ // Other corners
+ vec3 g = step(x0.yzx, x0.xyz);
+ vec3 l = 1.0 - g;
+ vec3 i1 = min( g.xyz, l.zxy );
+ vec3 i2 = max( g.xyz, l.zxy );
+
+ vec3 x1 = x0 - i1 + C.xxx;
+ vec3 x2 = x0 - i2 + C.yyy;
+ vec3 x3 = x0 - D.yyy;
+
+ // Permutations
+ i = mod289(i);
+ vec4 p = permute( permute( permute(
+ i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
+
+ // Gradients: 7x7 points over a square, mapped onto an octahedron.
+ // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
+ float n_ = 0.142857142857; // 1.0/7.0
+ vec3 ns = n_ * D.wyz - D.xzx;
+
+ vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
+
+ vec4 x_ = floor(j * ns.z);
+ vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
+
+ vec4 x = x_ *ns.x + ns.yyyy;
+ vec4 y = y_ *ns.x + ns.yyyy;
+ vec4 h = 1.0 - abs(x) - abs(y);
+
+ vec4 b0 = vec4( x.xy, y.xy );
+ vec4 b1 = vec4( x.zw, y.zw );
+
+ vec4 s0 = floor(b0)*2.0 + 1.0;
+ vec4 s1 = floor(b1)*2.0 + 1.0;
+ vec4 sh = -step(h, vec4(0.0));
+
+ vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
+ vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
+
+ vec3 p0 = vec3(a0.xy,h.x);
+ vec3 p1 = vec3(a0.zw,h.y);
+ vec3 p2 = vec3(a1.xy,h.z);
+ vec3 p3 = vec3(a1.zw,h.w);
+
+ //Normalise gradients
+ vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
+ p0 *= norm.x;
+ p1 *= norm.y;
+ p2 *= norm.z;
+ p3 *= norm.w;
+
+ // Mix final noise value
+ vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
+ m = m * m;
+ return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) );
+}
+
+
+// ===================================================================
+// VT220 Font Rendering
+// Author/Source : https://www.shadertoy.com/view/llSXDV
+//
+#define l(y,a,b) roundLine(p, vec2(float(a), float(y)), vec2(float(b), float(y)))
+float roundLine(vec2 p, vec2 a, vec2 b) {
+ b -= a + vec2(1.0,0.);
+ p -= a;
+ float f = length(p-clamp(dot(p,b)/dot(b,b),0.0,1.0)*b);
+ if (resolution.y < 320.) // attempt to get rid of aliasing on small resolution
+ return smoothstep(1.0, 0.9, f);
+ else if (resolution.y < 720.)
+ return smoothstep(0.75, 0.5, f);
+ else
+ return smoothstep(1., 0., f);
+}
+
+float vt220Font(vec2 p, float c) {
+ if (c < 1.) return 0.;
+ if (p.y > 16.) {
+ if (c > 2.) return 0.0;
+ if (c > 1.) return l(17,1,9);
+ }
+ if (p.y > 14.) {
+ if (c > 16.) return l(15,3,8);
+ if (c > 15.) return l(15,1,8);
+ if (c > 14.) return l(15,1,3)+ l(15,7,9);
+ if (c > 13.) return l(15,2,8);
+ if (c > 12.) return l(15,1,9);
+ if (c > 11.) return l(15,2,8);
+ if (c > 10.) return l(15,1,3)+ l(15,6,8);
+ if (c > 9.) return l(15,4,6);
+ if (c > 8.) return l(15,2,4)+ l(15,5,7);
+ if (c > 7.) return l(15,2,8);
+ if (c > 6.) return l(15,2,8);
+ if (c > 5.) return l(15,2,8);
+ if (c > 4.) return l(15,2,9);
+ if (c > 3.) return l(15,1,8);
+ if (c > 2.) return l(15,2,9);
+ }
+ if (p.y > 12.) {
+ if (c > 16.) return l(13,2,4)+ l(13,7,9);
+ if (c > 15.) return l(13,2,4)+ l(13,7,9);
+ if (c > 14.) return l(13,1,3)+ l(13,7,9);
+ if (c > 13.) return l(13,1,3)+ l(13,7,9);
+ if (c > 12.) return l(13,1,3);
+ if (c > 11.) return l(13,4,6);
+ if (c > 10.) return l(13,2,4)+ l(13,5,9);
+ if (c > 9.) return l(13,2,8);
+ if (c > 8.) return l(13,2,4)+ l(13,5,7);
+ if (c > 7.) return l(13,1,3)+ l(13,7,9);
+ if (c > 6.) return l(13,1,3)+ l(13,7,9);
+ if (c > 5.) return l(13,1,3)+ l(13,7,9);
+ if (c > 4.) return l(13,1,3)+ l(15,2,9);
+ if (c > 3.) return l(13,1,4)+ l(13,7,9);
+ if (c > 2.) return l(13,1,3)+ l(13,6,9);
+ }
+ if (p.y > 10.) {
+ if (c > 16.) return l(11,1,3);
+ if (c > 15.) return l(11,2,4)+ l(11,7,9);
+ if (c > 14.) return l(11,1,9);
+ if (c > 13.) return l(11,7,9);
+ if (c > 12.) return l(11,2,5);
+ if (c > 11.) return l(11,4,6);
+ if (c > 10.) return l(11,3,5)+ l(11,6,8);
+ if (c > 9.) return l(11,4,6)+ l(11,7,9);
+ if (c > 8.) return l(11,1,8);
+ if (c > 7.) return l(11,1,3)+ l(11,7,9);
+ if (c > 6.) return l(11,1,3)+ l(11,7,9);
+ if (c > 5.) return l(11,1,3)+ l(11,7,9);
+ if (c > 4.) return l(11,1,3);
+ if (c > 3.) return l(11,1,3)+ l(11,7,9);
+ if (c > 2.) return l(11,2,9);
+ }
+ if (p.y > 8.) {
+ if (c > 16.) return l(9,1,3);
+ if (c > 15.) return l(9,2,8);
+ if (c > 14.) return l(9,1,3)+ l(9,7,9);
+ if (c > 13.) return l(9,4,8);
+ if (c > 12.) return l(9,4,8);
+ if (c > 11.) return l(9,4,6);
+ if (c > 10.) return l(9,4,6);
+ if (c > 9.) return l(9,2,8);
+ if (c > 8.) return l(9,2,4)+ l(9,5,7);
+ if (c > 7.) return l(9,1,3)+ l(9,7,9);
+ if (c > 6.) return l(9,1,3)+ l(9,7,9);
+ if (c > 5.) return l(9,1,3)+ l(9,7,9);
+ if (c > 4.) return l(9,1,3)+ l(9,7,9);
+ if (c > 3.) return l(9,1,4)+ l(9,7,9);
+ if (c > 2.) return l(9,7,9);
+ }
+ if (p.y > 6.) {
+ if (c > 16.) return l(7,1,3);
+ if (c > 15.) return l(7,2,4)+ l(7,7,9);
+ if (c > 14.) return l(7,2,4)+ l(7,6,8);
+ if (c > 13.) return l(7,5,7);
+ if (c > 12.) return l(7,7,9);
+ if (c > 11.) return l(7,2,6);
+ if (c > 10.) return l(7,2,4)+ l(7,5,7);
+ if (c > 9.) return l(7,1,3)+ l(7,4,6);
+ if (c > 8.) return l(7,1,8);
+ if (c > 7.) return l(7,2,8);
+ if (c > 6.) return l(7,2,8);
+ if (c > 5.) return l(7,2,8);
+ if (c > 4.) return l(7,2,8);
+ if (c > 3.) return l(7,1,8);
+ if (c > 2.) return l(7,2,8);
+ }
+ if (p.y > 4.) {
+ if (c > 16.) return l(5,2,4)+ l(5,7,9);
+ if (c > 15.) return l(5,2,4)+ l(5,7,9);
+ if (c > 14.) return l(5,3,7);
+ if (c > 13.) return l(5,6,8);
+ if (c > 12.) return l(5,1,3)+ l(5,7,9);
+ if (c > 11.) return l(5,3,6);
+ if (c > 10.) return l(5,1,5)+ l(5,6,8);
+ if (c > 9.) return l(5,2,8);
+ if (c > 8.) return l(5,2,4)+ l(5,5,7);
+ if (c > 7.) return 0.;
+ if (c > 6.) return 0.;
+ if (c > 5.) return 0.;
+ if (c > 4.) return 0.;
+ if (c > 3.) return l(5,1,3);
+ if (c > 2.) return 0.;
+ }
+ if (p.y > 2.) {
+ if (c > 16.) return l(3,3,8);
+ if (c > 15.) return l(3,1,8);
+ if (c > 14.) return l(3,4,6);
+ if (c > 13.) return l(3,1,9);
+ if (c > 12.) return l(3,2,8);
+ if (c > 11.) return l(3,4,6);
+ if (c > 10.) return l(3,2,4)+ l(3,7,9);
+ if (c > 9.) return l(3,4,6);
+ if (c > 8.) return l(3,2,4)+ l(3,5,7);
+ if (c > 7.) return l(3,2,4)+ l(3,6,8);
+ if (c > 6.) return l(3,1,3)+ l(3,4,7);
+ if (c > 5.) return l(3,2,4)+ l(3,6,8);
+ if (c > 4.) return 0.;
+ if (c > 3.) return l(3,1,3);
+ if (c > 2.) return 0.;
+ }
+ else {
+ if (c > 7.) return 0.;
+ if (c > 6.) return l(1,2,5)+ l(1,6,8);
+ }
+ return 0.0;
+}
+
+
+// ===================================================================
+// Noise Generation Algorithms
+// textLines(...) is for simulating the writing of random characters in line formats
+// https://www.shadertoy.com/view/llSXDV (same author as VT220 font rendering)
+//
+// smokeNoise(...) is for the main noise generation algorithm (very tunable)
+// https://www.shadertoy.com/view/MsdGWn
+//
+float textLines(vec2 uvG) {
+ float wt = 5. * (time + 0.5*sin(time*1.4) + 0.2*sin(time*2.9)); // wobbly time
+ vec2 uvGt = uvG + vec2(0., floor(wt));
+ float ll = rand(vec2(uvGt.y, - 1.)) * ROWCOLS.x; // line length
+
+ if (uvG.y > ROWCOLS.y - 2.){
+ if (ceil(uvG.x) == floor(min(ll, fract(wt)*ROWCOLS.x)))
+ return 2.;
+ if (ceil(uvG.x) > floor(min(ll, fract(wt)*ROWCOLS.x)))
+ return 0.;
+ }
+ if (uvGt.x > 5. && rand(uvGt) < .075)
+ return 0.;
+ if (max(5., uvGt.x) > ll)
+ return 0.;
+
+ return rand(uvGt)*15. + 2.;
+}
+
+float fbm3(vec3 v) {
+ float result = simplex(v);
+ result += simplex(v * 2.) / 2.;
+ result += simplex(v * 4.) / 4.;
+ result /= (1. + 1./2. + 1./4.);
+ return result;
+}
+
+float fbm5(vec3 v) {
+ float result = simplex(v);
+ result += simplex(v * 2.) / 2.;
+ result += simplex(v * 4.) / 4.;
+ result += simplex(v * 8.) / 8.;
+ result += simplex(v * 16.) / 16.;
+ result /= (1. + 1./2. + 1./4. + 1./8. + 1./16.);
+ return result;
+}
+
+float smokeNoise(vec3 v) {
+ // make it curl
+ for (int i=0; i