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/
|
bake/
|
||||||
.sass-cache/
|
.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 {
|
.centered {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0 0 0 0;
|
inset: 0 0 0 0;
|
||||||
|
|
@ -30,6 +24,7 @@ html, body {
|
||||||
text-align: start;
|
text-align: start;
|
||||||
|
|
||||||
border: 0.5ch solid #ffc0cb; /* #ac4aed */
|
border: 0.5ch solid #ffc0cb; /* #ac4aed */
|
||||||
|
background-color: #0e0d14;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -84,6 +79,9 @@ html, body {
|
||||||
width: 11ch; /* ignore prompt width */
|
width: 11ch; /* ignore prompt width */
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
25% {
|
||||||
|
width: 11ch;
|
||||||
|
}
|
||||||
to {
|
to {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
@ -112,3 +110,4 @@ html, body {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@
|
||||||
<!-- integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ==" -->
|
<!-- integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ==" -->
|
||||||
<!-- crossorigin="anonymous" -->
|
<!-- crossorigin="anonymous" -->
|
||||||
<!-- defer></script> -->
|
<!-- 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/shader-style.css">
|
||||||
<link rel="stylesheet" href="css/typing-merge.css">
|
<link rel="stylesheet" href="css/typing.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<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;
|
precision mediump float;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform float u_time;
|
uniform float uTime;
|
||||||
uniform vec2 u_resolution;
|
uniform vec2 uResolution;
|
||||||
|
|
||||||
/* ==== Text Colouring ==== */
|
/* ==== 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.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 ======= */
|
/* ======= Text Size ======= */
|
||||||
#define FONT_SIZE vec2(10.,20.)
|
#define FONT_SIZE vec2(10.,20.)
|
||||||
#define ROWCOLS vec2(80., 24.)
|
#define ROWCOLS vec2(80., 24.)
|
||||||
|
|
@ -155,9 +155,9 @@ float roundLine(vec2 p, vec2 a, vec2 b) {
|
||||||
b -= a + vec2(1.0,0.);
|
b -= a + vec2(1.0,0.);
|
||||||
p -= a;
|
p -= a;
|
||||||
float f = length(p-clamp(dot(p,b)/dot(b,b),0.0,1.0)*b);
|
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);
|
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);
|
return smoothstep(0.75, 0.5, f);
|
||||||
else
|
else
|
||||||
return smoothstep(1., 0., f);
|
return smoothstep(1., 0., f);
|
||||||
|
|
@ -305,7 +305,7 @@ float vt220Font(vec2 p, float c) {
|
||||||
// https://www.shadertoy.com/view/MsdGWn
|
// https://www.shadertoy.com/view/MsdGWn
|
||||||
//
|
//
|
||||||
float textLines(vec2 uvG) {
|
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));
|
vec2 uvGt = uvG + vec2(0., floor(wt));
|
||||||
float ll = rand(vec2(uvGt.y, - 1.)) * ROWCOLS.x; // line length
|
float ll = rand(vec2(uvGt.y, - 1.)) * ROWCOLS.x; // line length
|
||||||
|
|
||||||
|
|
@ -351,21 +351,21 @@ float smokeNoise(vec3 v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 uv = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y);
|
vec2 uv = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y);
|
||||||
vec2 uvT = ROWCOLS * FONT_SIZE * uv / u_resolution.xy;
|
vec2 uvT = ROWCOLS * FONT_SIZE * uv / uResolution.xy;
|
||||||
vec2 uvG = floor(ROWCOLS * uv / u_resolution.xy);
|
vec2 uvG = floor(ROWCOLS * uv / uResolution.xy);
|
||||||
vec2 uvC = gl_FragCoord.xy / u_resolution.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;
|
uvNoise = ceil(uvNoise * ROWCOLS) / ROWCOLS;
|
||||||
|
|
||||||
float val;
|
float val;
|
||||||
if (u_time < 2.0)
|
if (uTime < 2.0)
|
||||||
val = textLines(uvG);
|
val = textLines(uvG);
|
||||||
else if (u_time < 2.3)
|
else if (uTime < 2.3)
|
||||||
val = rand(uvG * u_time) * 17.;
|
val = rand(uvG * uTime) * 17.;
|
||||||
else {
|
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
|
// 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 = (exp(noise) / 2.71828); // increase contrast (normalised 0.0 - 1.0)
|
||||||
val = 1.0 / val;
|
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);
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
// is highp wasteful for this shader?
|
// is highp wasteful for this shader?
|
||||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||||
precision highp float;
|
precision highp float;
|
||||||
#else
|
#else
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform float u_time;
|
uniform float uTime;
|
||||||
uniform vec2 u_resolution;
|
uniform vec2 uResolution;
|
||||||
|
|
||||||
void main() {
|
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);
|
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