Compare commits
11 commits
efdedb23b8
...
e974170ff0
| Author | SHA1 | Date | |
|---|---|---|---|
| e974170ff0 | |||
| 7defe8ae50 | |||
| 53a62f639e | |||
| 1683d2bbe9 | |||
| 618a3aec23 | |||
| 3f28498ad4 | |||
| 1d06470ccd | |||
| 935cc44f66 | |||
| ffad884915 | |||
| b03962ec0a | |||
| 345c1b592e |
27 changed files with 1391 additions and 427 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
bake/
|
||||
.sass-cache/
|
||||
sandbox/
|
||||
|
|
|
|||
1
CREDITS.md
Normal file
1
CREDITS.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
1. [github:rose-pine/tailwind-css](https://github.com/rose-pine/tailwind-css): I modified their css palettes
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
<!-- integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ==" -->
|
||||
<!-- crossorigin="anonymous" -->
|
||||
<!-- defer></script> -->
|
||||
<script src="js/webgl-demo.js" type="module"></script>
|
||||
<script src="js/main.js" type="module"></script>
|
||||
<link rel="stylesheet" href="css/shader-style.css">
|
||||
<link rel="stylesheet" href="css/typing-merge.css">
|
||||
<link rel="stylesheet" href="css/typing.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
<!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>
|
||||
|
|
@ -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 };
|
||||
|
||||
|
|
@ -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 };
|
||||
|
||||
32
www/js/main.js
Normal file
32
www/js/main.js
Normal file
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
4
www/js/smc/README.md
Normal file
4
www/js/smc/README.md
Normal file
|
|
@ -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.
|
||||
10
www/js/smc/errors.js
Normal file
10
www/js/smc/errors.js
Normal file
|
|
@ -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,
|
||||
}
|
||||
4
www/js/smc/lib.js
Normal file
4
www/js/smc/lib.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { Smc } from "./smc.js";
|
||||
import { SmcErr } from "./errors.js";
|
||||
|
||||
export { Smc, SmcErr };
|
||||
133
www/js/smc/progbuilder.js
Normal file
133
www/js/smc/progbuilder.js
Normal file
|
|
@ -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 ""
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
293
www/js/smc/smc.js
Normal file
293
www/js/smc/smc.js
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
24
www/js/smc/util.js
Normal file
24
www/js/smc/util.js
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<!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>
|
||||
96
www/shaders/fbm.glsl
Normal file
96
www/shaders/fbm.glsl
Normal file
|
|
@ -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.);
|
||||
}
|
||||
|
||||
323
www/shaders/optimised.glsl
Normal file
323
www/shaders/optimised.glsl
Normal file
|
|
@ -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.);
|
||||
}
|
||||
|
||||
23
www/shaders/sample.glsl
Normal file
23
www/shaders/sample.glsl
Normal file
|
|
@ -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.);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
50
www/shaders/squares.glsl
Normal file
50
www/shaders/squares.glsl
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -5,13 +5,13 @@
|
|||
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);
|
||||
}
|
||||
|
|
|
|||
368
www/shaders/working.glsl
Normal file
368
www/shaders/working.glsl
Normal file
|
|
@ -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<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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue