Compare commits

..

No commits in common. "e974170ff04f92bf803b55049b04f88d446d5b86" and "efdedb23b8becfdaf7b43b431007fc369bae318d" have entirely different histories.

27 changed files with 427 additions and 1391 deletions

1
.gitignore vendored
View file

@ -1,3 +1,2 @@
bake/
.sass-cache/
sandbox/

View file

@ -1 +0,0 @@
1. [github:rose-pine/tailwind-css](https://github.com/rose-pine/tailwind-css): I modified their css palettes

110
www/css/typing-merge.css Normal file
View file

@ -0,0 +1,110 @@
.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;
}
}

View file

@ -1,3 +1,9 @@
html, body {
height: 100%;
margin: 0;
background-color: #0e0d14;
}
.centered {
position: absolute;
inset: 0 0 0 0;
@ -24,7 +30,6 @@
text-align: start;
border: 0.5ch solid #ffc0cb; /* #ac4aed */
background-color: #0e0d14;
padding: 20px;
display: flex;
@ -79,9 +84,6 @@
width: 11ch; /* ignore prompt width */
visibility: visible;
}
25% {
width: 11ch;
}
to {
visibility: visible;
}
@ -110,4 +112,3 @@
visibility: visible;
}
}

View file

@ -9,9 +9,9 @@
<!-- integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ==" -->
<!-- crossorigin="anonymous" -->
<!-- defer></script> -->
<script src="js/main.js" type="module"></script>
<script src="js/webgl-demo.js" type="module"></script>
<link rel="stylesheet" href="css/shader-style.css">
<link rel="stylesheet" href="css/typing.css">
<link rel="stylesheet" href="css/typing-merge.css">
</head>
<body>

38
www/index.html.bak Normal file
View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/typing.css">
</head>
<body>
<div class="centered heading">
<div id="typing-wrapper">
<div id="typing-prompt">
<span style="color: #9ccfd8;">grub></span> <span style="color: #c4a7e7;">boot</span>
</div>
<div id="typing-result" style="color: #f6c177;">
ERROR: Root device mounted successfully, but /sbin/init does not exist.<br/><br/>
<i style="color: #eb6f92;">Bailing out, you are on your own.</i><br/>
<i style="color: #eb6f92;">Good luck</i><br/><br/>
sh: can't access tty; job control turned off<br/><br/>
</div>
<div id="typing-prompt-segfault">
<span style="color: #9ccfd8;">[rootfs ]#</span>
<span style="color: #c4a7e7;">do butterflies cry when they're sad?</span>
</div>
<div id="typing-result-segfault">
<i style="color: #eb6f92;">Segmentation fault (core dumped)</i>
</div>
</div>
</div>
</body>
</html>

60
www/js/draw-scene.js Normal file
View file

@ -0,0 +1,60 @@
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 };

34
www/js/init-buffers.js Normal file
View file

@ -0,0 +1,34 @@
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 };

View file

@ -1,32 +0,0 @@
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()
);
}

View file

@ -1,4 +0,0 @@
# 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.

View file

@ -1,10 +0,0 @@
export { SmcErr };
const SmcErr = {
UNSUPPORTED: 0, // unused
SHADER_COMPILATION: 1,
PROGRAM_INIT: 2,
ATTRIBUTE_MISSING: 3,
UNIFORM_MISSING: 4,
FETCH_SHADER: 5,
}

View file

@ -1,4 +0,0 @@
import { Smc } from "./smc.js";
import { SmcErr } from "./errors.js";
export { Smc, SmcErr };

View file

@ -1,133 +0,0 @@
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 ""
// }
}

View file

@ -1,293 +0,0 @@
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);
}
}

View file

@ -1,24 +0,0 @@
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;
}

136
www/js/webgl-demo.js Normal file
View file

@ -0,0 +1,136 @@
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);
});
}

19
www/shader.html Normal file
View file

@ -0,0 +1,19 @@
<!doctype html>
<!-- Ref: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context -->
<html lang="en">
<head>
<meta charset="utf-8" />
<title>WebGL Demo</title>
<!-- <script -->
<!-- src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js" -->
<!-- integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ==" -->
<!-- crossorigin="anonymous" -->
<!-- defer></script> -->
<script src="js/webgl-demo.js" type="module"></script>
<link rel="stylesheet" href="css/shader-style.css">
</head>
<body>
<canvas class="gl-canvas-bg" id="gl-canvas"></canvas>
</body>
</html>

View file

@ -1,96 +0,0 @@
// 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.);
}

View file

@ -1,323 +0,0 @@
/* 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.);
}

View file

@ -1,23 +0,0 @@
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.);
}

View file

@ -11,13 +11,13 @@
precision mediump float;
#endif
uniform float uTime;
uniform vec2 uResolution;
uniform float u_time;
uniform vec2 u_resolution;
/* ==== Text Colouring ==== */
#define PHOSPHOR_COL vec4(196./255., 167./255., 231./255., 1.)
#define PHOSPHOR_COL vec4(1, 1., 1., 1.)
// #define BG_COL vec4(0.2, 0.0, 0.2, 0.5)
#define BG_COL vec4(14./255., 13./255., 20./255., 1.)
#define BG_COL vec4(0.0, 0.0, 0.0, 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 (uResolution.y < 320.) // attempt to get rid of aliasing on small resolution
if (u_resolution.y < 320.) // attempt to get rid of aliasing on small resolution
return smoothstep(1.0, 0.9, f);
else if (uResolution.y < 720.)
else if (u_resolution.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. * (uTime + 0.5*sin(uTime*1.4) + 0.2*sin(uTime*2.9)); // wobbly time
float wt = 5. * (u_time + 0.5*sin(u_time*1.4) + 0.2*sin(u_time*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, 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 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 uvNoise = gl_FragCoord.xy / uResolution.xy;
vec2 uvNoise = gl_FragCoord.xy / u_resolution.xy;
uvNoise = ceil(uvNoise * ROWCOLS) / ROWCOLS;
float val;
if (uTime < 2.0)
if (u_time < 2.0)
val = textLines(uvG);
else if (uTime < 2.3)
val = rand(uvG * uTime) * 17.;
else if (u_time < 2.3)
val = rand(uvG * u_time) * 17.;
else {
float noise = smokeNoise(vec3(uvNoise * noiseScale, uTime * noiseTimeScale));
float noise = smokeNoise(vec3(uvNoise * noiseScale, u_time * 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;

View file

@ -1,50 +0,0 @@
// 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);
}

View file

@ -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 uTime;
uniform vec2 uResolution;
uniform float u_time;
uniform vec2 u_resolution;
void main() {
vec2 uv = gl_FragCoord.xy / uResolution;
vec2 uv = gl_FragCoord.xy / u_resolution;
vec3 col = 0.5 + 0.5 * cos(uTime + uv.xyx + vec3(0, 2, 4));
vec3 col = 0.5 + 0.5 * cos(u_time + uv.xyx + vec3(0, 2, 4));
gl_FragColor = vec4(col,1.0);
}

View file

@ -1,368 +0,0 @@
// 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<noiseSwirlSteps; i++) {
v.xy += vec2(fbm3(v), fbm3(vec3(v.xy, v.z + 1000.))) * noiseSwirlStepValue;
}
// normalize
return fbm5(v) / 2. + 0.5;
}
void main() {
vec2 uv = vec2(gl_FragCoord.x, resolution.y - gl_FragCoord.y);
vec2 uvT = ROWCOLS * FONT_SIZE * uv / resolution.xy;
vec2 uvG = floor(ROWCOLS * uv / resolution.xy);
vec2 uvC = gl_FragCoord.xy / resolution;
vec2 uvNoise = uvC;
uvNoise = ceil(uvNoise * ROWCOLS) / ROWCOLS;
float val;
if (time < 2.0)
val = textLines(uvG);
else if (time < 2.3)
val = rand(uvG * time) * 17.;
else {
float noise = smokeNoise(vec3(uvNoise * noiseScale, time * 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;
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 :)
}
gl_FragColor = vt220Font(uvT - uvG * FONT_SIZE, val) * PHOSPHOR_COL + BG_COL;
}