The 80s On ASCIID

This is a piece that brings me back to the amazing aesthetics of my childhood, by using simple mathematical patterns that were widely explored back in the demoscene days.

Created by marcogomez on Thu, 27 May 2021 21:35:57 GMT.


// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm3Texture;
uniform vec2 resolution;
uniform float time;

const float PI = acos(-1.0); //         π or acos(-1.0) or 180°
const float HALFPI = PI / 2.0; //       π / 2 [ rad(deg(π/2)) ] or 90°
const float ttp = 1.0 / 3.0; //         33%
const float ssp = 1.0 / 6.0; //         66%

const vec2 hashV = vec2(12.9898, 78.233);
const float hashF = 43758.5453123;

const vec2 vignetteSize = vec2(0.34, 0.34);
const float vignetteRoundness = 0.0;
const float vignetteSmoothness = 0.17;
const float vignetteMix = 0.8;
const float h = 0.0001;
const float v = 0.001;
const float g = 0.12;

vec2 curve(vec2 uv) {
  uv = (uv - 0.5) * 2.0;
  uv *= 1.1;
  uv.x *= 1.0 + pow((abs(uv.y) / 8.0), 2.0);
  uv.y *= 1.0 + pow((abs(uv.x) / 8.0), 2.0);
  uv = (uv / 2.0) + 0.5;
  uv = uv * 0.92 + 0.04;
  return uv;
}

float stepm(float a, float b, float c) {
  return step(c, sin(time + a * cos(time * b)));
}

float gaussian(float z, float u, float o) {
  return (
    (1.0 / (o * sqrt(2.0 * PI))) *
    (exp(-(((z - u) * (z - u)) / (2.0 * (o * o)))))
  );
}

vec3 gaussgrain(float t) {
  vec2 ps = vec2(1.0) / resolution.xy;
  vec2 uv = gl_FragCoord.xy * ps;
  float seed = dot(uv, hashV);
  float noise = fract(sin(seed) * hashF + t);
  noise = gaussian(noise, 0.0, 0.5);
  return vec3(noise);
}

float sdSquare(vec2 point, float width) {
  vec2 d = abs(point) - width;
  return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}

float vignette(vec2 uv, vec2 size, float roundness, float smoothness) {
  uv -= 0.5;
  float minWidth = min(size.x, size.y);
  uv.x = sign(uv.x) * clamp(abs(uv.x) - abs(minWidth - size.x), 0.0, 1.0);
  uv.y = sign(uv.y) * clamp(abs(uv.y) - abs(minWidth - size.y), 0.0, 1.0);
  float boxSize = minWidth * (1.0 - roundness);
  float dist = sdSquare(uv, boxSize) - (minWidth * roundness);
  return 1.0 - smoothstep(0.0, smoothness, dist);
}

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  uv = curve(uv);
  vec4 prgm3 = texture2D(prgm3Texture, uv);
  float frameScale = 29.97;
  float frameTime = floor(time * frameScale) / frameScale;
  vec3 grain = gaussgrain(frameTime);
  prgm3.xyz += grain * 0.05;
  float v = vignette(uv, vignetteSize, vignetteRoundness, vignetteSmoothness);
  prgm3.xyz = mix(prgm3.xyz, prgm3.xyz * v, vignetteMix);
  if (uv.x < 0.0 || uv.x > 1.0) { prgm3 *= 0.0; }
  if (uv.y < 0.0 || uv.y > 1.0) { prgm3 *= 0.0; }
  gl_FragColor = vec4(prgm3.xyz, 1.0);
}

// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform vec2 resolution;
uniform float time, fft, alpha;

const float PI = acos(-1.0); //         π or acos(-1.0) or 180°
const float HALFPI = PI / 2.0; //       π / 2 [ rad(deg(π/2)) ] or 90°
const float ttp = 1.0 / 3.0; //         33%
const float ssp = 1.0 / 6.0; //         66%

const vec2 hashV = vec2(12.9898, 78.233);
const float hashF = 43758.5453123;

float osc(float s, float e, float t, float ts) {
  return (e - s) / 2.0 + s + sin(t * ts) * (e - s) * 0.5;
}

vec2 rotate(vec2 uv, float a) {
  return vec2(uv.x * cos(a) - uv.y * sin(a), uv.x * sin(a) + uv.y * cos(a));
}

float hash(vec2 uv) {
  return fract(sin(dot(uv.xy, hashV)) * hashF);
}

float noise(vec2 uv) {
  const vec2 O = vec2(0.0, 1.0);
  vec2 b = floor(uv);
  return mix(mix(hash(b), hash(b + O.yx), 0.5), mix(hash(b + O), hash(b + O.yy), 0.5), 0.5);
}

float waves(vec2 uv, float frac) {
  float t2 = time * -0.5;
  uv.y += t2;
  float w = sin(uv.y - frac * 2.0 * PI + 1.5 * PI) * 0.5 + 0.5;
  w += sin(uv.x * 10.0 - uv.y * 4.0 - time * 2.0) * ttp * 0.1;
  return clamp(w * w, 0.0, 1.0);
}

float atanStar(vec2 uv) {
  vec2 cp = normalize(vec3(uv.xy, 4.0 - fft * 1.0)).xy * 2.0;
  cp = mix(uv, cp, 0.7);
  float pAtan = atan(cp.x, cp.y) + cp.x;
  float star = sin(9.0 * fft + pAtan * 8.0 - time * 7.45) * 0.4 + 0.1 * fft + 0.4;
  return clamp(star, 0.0, 1.0);
}

vec2 truchetPattern(vec2 uv, float index) {
  index = fract(((index - 0.5) * 2.0));
  if (index > 0.75) { uv = vec2(1.0) - uv; }
  else if (index > 0.50) { uv = vec2(1.0 - uv.x, uv.y); }
  else if (index > 0.25) { uv = 1.0 - vec2(1.0 - uv.x, uv.y); }
  return uv;
}

float curvedTruchet(vec2 uv) {
  vec2 ouv = uv;
  uv *= 2.1;
  uv.x -= time * 1.2;
  vec2 ipos = floor(uv);
  vec2 fpos = fract(uv);
  vec2 tile = truchetPattern(fpos, hash(ipos));
  float a = (
    (step(length(tile), 0.6) - step(length(tile), 0.4)) +
    (step(length(tile - vec2(1.0)), 0.6) - step(length(tile - vec2(1.0)), 0.4))
  );
  float curves = a / length(ouv * 0.8) * 0.5;
  return clamp(curves, 0.0, 1.0);
}

float pacman(vec2 uv, float frac) {
  float value = 0.0;
  uv *= 4.0;
  vec2 pacmanCenter = vec2(6.7 - frac * 12.0, 0.0), delta = uv - pacmanCenter;
  float theta = abs(atan(delta.y, -delta.x));
  float mouth = step(max(0.0, sin(time * 10.0) * 0.4 + 0.35), theta);
  float dist = distance(uv, pacmanCenter);
  value += sqrt(max(0.0, 20.0 - dist * 20.0) * mouth);
  if (uv.x > pacmanCenter.x + 0.5) { return value; }
  uv.y += sin((5.0 * time) + uv.x * 0.5) * 0.15;
  vec2 center = vec2(floor(uv.x) + 0.5, 0.0);
  if (uv.x < pacmanCenter.x - 0.95) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 1.5 - distance(pacmanCenter , center);
  }
  if (uv.x < pacmanCenter.x - 0.9) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.60;
  } else if (uv.x < pacmanCenter.x - 0.6) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.30;
  } else if (uv.x < pacmanCenter.x - 0.3) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.15;
  } else if (uv.x < pacmanCenter.x + 0.25) {
    value += max(0.0, 6.0 - distance(uv , center) * 30.0) * 0.07;
  }
  return clamp(value, 0.0, 1.0);
}

float truchet(vec2 uv) {
  float shade = abs(uv.y);
  uv *= 4.0;
  uv.x -= time * 1.7;
  uv = rotate(uv, PI * 0.25);
  vec2 gv = fract(uv) - 0.5;
  vec2 id = floor(uv);
  float n = hash(id);
  float w = 0.21;
  if (n < 0.5) { gv.x *= -1.0; }
  float dist = abs(abs(gv.x + gv.y) - 0.5);
  float mask = smoothstep(0.01, -0.01, dist - w);
  return clamp(mask - shade * 0.5, 0.0, 1.0);
}

float plasma(vec2 uv) {
  vec2 ouv = uv;
  uv *= 0.7 + osc(-0.2, 0.2, time, 0.12);
  uv = rotate(uv, time * 0.12);
  uv.y *= max(resolution.x, resolution.y) / min(resolution.x, resolution.y);
  float t1 = time * 0.12, t2 = time * 0.21;
  uv *= vec2(40.0, 12.0), uv = floor(uv), uv /= vec2(80.0, 24.0);
  float color = 0.0;
  color += 0.7 * sin(00.5 * uv.x + t1);
  color += 3.0 * sin(01.6 * uv.y + t1);
  color += 1.0 * sin(10.0 * (uv.y * sin(t2) + uv.x * cos(t1)) + t2);
  float cx = uv.x + 0.5 * sin(t2);
  float cy = uv.y + 0.5 * cos(t2 * 0.5);
  color += +0.4 * sin(sqrt(100.0 * cx *cx + 100.0 *cy * cy + 1.0) + time);
  color += +0.9 * sin(sqrt(075.0 * cx *cx + 025.0 *cy * cy + 1.0) + time);
  color += -1.4 * sin(sqrt(256.0 * cx *cx + 025.0 *cy * cy + 1.0) + time);
  color += +0.3 * sin(0.5 * uv.y + uv.x + sin(time));
  float plasma = (3.0 * (0.5 + 0.499 * sin(color))) * ttp;
  plasma = plasma / length(ouv * 0.8) * 0.5;
  return clamp(plasma * plasma * 2.0, 0.0, 1.0);
}

float irisColor(vec3 norm, float frac, float theta) {
  float color = 1.0;
  float sTheta = sin(theta * 2.0) * 0.3 + 0.7;
  float zDist = distance(0.98, norm.z);
  float sstzDist = 1.0 - smoothstep(0.0, 0.1, zDist);
  if (norm.z > 0.99 + smoothstep(0.0, 0.7, frac) * 0.009) { color = 0.0; }
  else if (norm.z > 0.9) { color = 0.7 * sstzDist * sTheta; }
  return color;
}

float eye(vec2 uv, float frac) {
  uv *= 1.5;
  float r = length(uv);
  if (r > 1.0) { return 0.0; }
  else {
    vec3 l = normalize(vec3(1.0, 1.0, 2.0));
    vec3 p = vec3(uv, sqrt(1.0 - r * r));
    float angle = cos(time * 0.02914) * 15.115;
    float angle2 = sin(time * 0.447) * 0.117;
    l.xy = rotate(l.xy, angle);
    p.xy = rotate(p.xy, angle2);
    l.xz = rotate(l.xz, angle2);
    p.xz = rotate(p.xz, angle2);
    float d = dot(l, p), theta = atan(p.x, p.y) - angle;
    return (d * 0.5 + d * d * 0.3 + 0.3) * irisColor(p, frac, theta);
  }
}

float stars(vec2 uv) {
  vec2 ouv = uv;
  uv.y += 1.5;
  float stars = 0.0, fl, s;
  for (int layer = 3; layer < 8; layer++) {
    fl = float(layer);
    s = (100.0 - fl * 16.0);
    float d = pow(abs(noise(mod(vec2(uv.x * s + (time + 7.0) * -12.0 - fl * 16.0, uv.y * s), resolution.x))), 16.0);
    stars += step(0.15, d);
  }
  stars = stars / length(ouv * 0.5) * 0.5;
  return clamp(stars, 0.0, 1.0);
}

float spiral(vec2 uv) {
  vec2 ouv = uv;
  uv *= 0.42;
  uv = vec2(atan(uv.x, uv.y) / PI * 4.0, log(length(uv) + 1.0) * 8.0);
  uv.x += (time + 10.0) * 0.5;
  uv.y -= uv.x * 0.5 + time * 1.0;
  vec2 f = fract(uv) * 1.5 - 0.5;
  float spiral = max(f.x - uv.x, uv.y);
  spiral = spiral / length(ouv * 0.5) * 0.5;
  return clamp(spiral, 0.0, 1.0);
}

float pong(vec2 uv) {
  uv *= 0.4;
  uv.x *= 1.5;
  uv.x += 0.5;
  uv.y *= 1.2;
  float t = time;
  vec2 b;
  b.x = mod(t / 1.7, 1.88) + 0.03;
  b.y = mod(t / 2.5, 1.08) - 0.27;
  b = min(b, vec2(1.94, 0.54) - b);
  float c = smoothstep(1.0, 0.9, 70.0 * distance(uv, b));
  float l = mix(b.y, sin(t * 3.1) * 0.2, b.x);
  float r = mix(cos(t * 3.7) / 4.5, b.y * 0.9, b.x);
  if (
    (uv.x < 0.040 && uv.x > 0.01 && abs(l - uv.y) < 0.06) ||
    (uv.x > 0.955 && uv.x < 0.99 && abs(r - uv.y) < 0.06)
  ) { c = 1.0; }
  if (uv.x < +0.001 || uv.x > 0.999 || uv.y < -0.27 || uv.y > 0.27) { c = 1.0; }
  if (uv.x < -0.020 || uv.x > 1.020 || uv.y < -0.29 || uv.y > 0.29) { c = 0.0; }
  return c;
}

float corridor(vec2 uv) {
  uv.y = abs(uv.y);
  uv.y = max(0.08, uv.y);
  uv.x /= uv.y;
  uv.x += time;
  float c = mod(floor(uv.x) + floor(uv.y * 2.0), 2.0) + 0.5;
  float dist = sqrt(uv.y);
  c = c * max(0.1, min(1.0, dist * 1.3));
  return c;
}

float rings(vec2 uv) {
  float scale = resolution.y / 50.0;
  float ring = 64.0;
  float radius = resolution.x;
  float gap = scale * 0.25;
  float d = length(uv);
  d += scale - time * 0.1;
  float v = mod(d + radius / (ring * 2.0), radius / ring);
  v = abs(v - radius / (ring * 2.0));
  v = clamp(v - gap, 0.0, 1.0);
  d += v;
  float m = fract((d - 1.0) * (ring * -0.5, -ring, ring * 0.25) * 0.25);
  return m;
}

float wave(vec2 uv) {
  vec2 ouv = uv;
  uv.x += time * 0.2 + (3.0 + sin(time) * 0.25);
  float w = sin(uv.x * 14.0 + time * 1.2) / 4.0;
  float d = abs(uv.y - w) * 4.0;
  w += cos(uv.x * 18.0 + time) / 8.0;
  d *= (abs(uv.y - w) * 18.0) * 0.25;
  float wave = 0.25 / d;
  wave = 1.0 - wave;
  wave = wave / length(ouv * 0.7) * 0.5;
  return clamp(sqrt(wave) * 12.0 * wave * wave * wave * wave, 0.0, 1.0);
}

float flippingSquares(vec2 uv) {
  vec2 ouv = uv;
  uv = rotate(uv, time * -0.5);
  uv *= 2.5;
  uv.y += time * 0.5;
  float size = 20.0 + abs(sin(time * 0.5)) * 150.0;
  float hsm = 1.5 / resolution.y * size * 0.5;
  vec2 id = floor(uv);
  uv = fract(uv) - 0.5;
  float a = time;
  float phase = mod(floor(a / HALFPI), 2.0);
  float mask = 0.0;
  for (float y =- 1.0; y <= 1.0; y++) {
    for (float x =- 1.0; x <= 1.0; x++) {
      vec2 ruv = uv + vec2(x, y);
      vec2 rid = id + vec2(x, y);
      ruv *= mat2(cos(a + vec4(0.0, 33.0, 11.0, 0.0)));
      vec2 maskXY = smoothstep(0.5 + hsm, 0.5 - hsm, abs(ruv));
      float maskI = maskXY.x * maskXY.y;
      vec2 idm = mod(rid, 2.0);
      float draw = abs(idm.x * idm.y + (1.0 - idm.x) * (1.0 - idm.y) - phase);
      mask += maskI * draw;
    }
  }
  float squares = abs(mask - phase);
  squares = squares / length(ouv * 0.6) * 0.5;
  return squares;
}

bool detect(vec2 cir, vec2 curr, float size ) {
  return (distance(cir, curr) < size);
}

float snake(vec2 uv) {
  uv *= 0.5;
  uv += 0.5;
  float s = 0.0;
  for (int k = 0; k < 60; k++) {
    float x = float(k);
    float shift = time + x / 9.0 * 1.1416;
    if (detect(uv, vec2((sin(shift) * x / 100.0 * 0.9), (cos(shift) * 0.1)) + 0.5, x / 768.0)) {
      s = 0.01 * x;
    }
  }
  return s * s * 4.0;
}

float getEffect(int fx, vec2 uv, float frac) {
  float effects = 17.0;
  int idx = int(effects) - 1;
  fx = int(fract(float(fx) * 1.61456) * effects);
  int temp = int(float(fx) / float(idx));
  fx -= temp * idx;
  float value = 0.0;
  uv *= 1.0 - fft * 0.42;
  if (fx == 0) { value = waves(uv, frac); }
  else if (fx == 1) { value = atanStar(uv); }
  else if (fx == 2) { value = curvedTruchet(uv); }
  else if (fx == 3) { value = pacman(uv, frac); }
  else if (fx == 4) { value = truchet(uv); }
  else if (fx == 5) { value = eye(uv, frac); }
  else if (fx == 6) { value = plasma(uv); }
  else if (fx == 7) { value = corridor(uv); }
  else if (fx == 8) { value = spiral(uv); }
  else if (fx == 9) { value = stars(uv); }
  else if (fx == 10) { value = pong(uv); }
  else if (fx == 11) { value = rings(uv); }
  else if (fx == 12) { value = wave(uv); }
  else if (fx == 13) { value = flippingSquares(uv); }
  else if (fx == 14) { value = snake(uv); }
  else { value = truchet( uv ); }
  return value;
}

float transition(vec2 uv, float effectLength) {
  int fx = int(time / effectLength);
  float frac = mod(time, effectLength) / effectLength;
  float valueA = getEffect(fx, uv, 0.0);
  float valueB = getEffect(fx - 1, uv, frac);
  return mix(valueB, valueA, smoothstep(ssp, 1.0, frac));
}

float draw(vec2 frag, float effectLength, float ledSize, float cellSize ) {
  float size = ledSize * cellSize;
  vec2 cell = floor((frag + 2.0) / size) * size * 1.0 - resolution.xy;
  cell /= resolution.y;
  float brightness = transition(cell, effectLength);
  return brightness;
}

void main(void) {
  const vec3 CA = vec3(0.02, 0.07, 0.04);
  vec3 CB = vec3(0.3, 1.0, 0.9);
  const float EFFECT_LENGTH = 9.1;
  const float LED_SIZE = 2.0;
  const float CELL_SIZE = 3.0;
  const float SIZE = LED_SIZE * CELL_SIZE;
  float d = draw(gl_FragCoord.xy * 2.0, EFFECT_LENGTH, LED_SIZE, CELL_SIZE);
  vec3 col = sqrt(d * CB) + (CA * 1.25) + 0.06;
  gl_FragColor = vec4(col * col, 1.0);
}

// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm1Texture;
uniform vec2 resolution;

const float zoom = 1.0;
const float amount = 1.0;
const bool bypass = false;
const float chx = 12.0;
const float chy = 18.0;

float gray(vec3 c) {
  return c.x * 0.299 + c.y * 0.587 + c.z * 0.114;
}

void P(
  in int id,
  in int a, in int b, in int c, in int d,
  in int e, in int f, in int g, in int h,
  inout ivec2 p, inout float cha
) {
  if (id == int(p.y)) {
    int pa = (a + 2 * (b + 2 * (c + 2 * (d + 2 * (e + 2 * (f + 2 * (g + 2 * h)))))));
    cha = floor(mod(float(pa) / pow(abs(2.0), float(p.x) -1.0), 2.0));
  }
}

void main(void) {
  float z = zoom;
  vec2 uv = vec2(
    floor(gl_FragCoord.x / chx / z) * chx * z,
    floor(gl_FragCoord.y / chy / z) * chy * z
  ) / resolution.xy;
  ivec2 p = ivec2(mod(gl_FragCoord.x / z, chx), mod(gl_FragCoord.y / z, chy));
  vec4 prgm1 = texture2D(prgm1Texture, uv);
  float cha = 0.0;
  float g = gray(prgm1.xyz);
  if ( g < 0.125 ) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,0,0,0,0,0,0,0,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,0,0,0,0,0, p, cha);
    P( 3,0,0,0,0,0,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.25) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,0,0,0,0,0,0,0,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,1,1,0,0,0, p, cha);
    P( 3,0,0,0,1,1,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.375) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,0,0,0,0,0,0,0,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,1,1,0,0,0, p, cha);
    P( 3,0,0,0,1,1,0,0,0, p, cha);
    P( 2,0,0,0,0,1,0,0,0, p, cha);
    P( 1,0,0,0,1,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.5) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,0,0,0,0,0, p, cha);
    P( 8,0,0,0,0,0,0,0,0, p, cha);
    P( 7,0,0,0,0,0,0,0,0, p, cha);
    P( 6,1,1,1,1,1,1,1,0, p, cha);
    P( 5,0,0,0,0,0,0,0,0, p, cha);
    P( 4,0,0,0,0,0,0,0,0, p, cha);
    P( 3,0,0,0,0,0,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.625) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,0,0,0,0,0, p, cha);
    P( 9,0,0,0,1,0,0,0,0, p, cha);
    P( 8,0,0,0,1,0,0,0,0, p, cha);
    P( 7,0,0,0,1,0,0,0,0, p, cha);
    P( 6,1,1,1,1,1,1,1,0, p, cha);
    P( 5,0,0,0,1,0,0,0,0, p, cha);
    P( 4,0,0,0,1,0,0,0,0, p, cha);
    P( 3,0,0,0,1,0,0,0,0, p, cha);
    P( 2,0,0,0,0,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.75) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,0,1,0,0,0,0, p, cha);
    P( 9,1,0,0,1,0,0,1,0, p, cha);
    P( 8,0,1,0,1,0,1,0,0, p, cha);
    P( 7,0,0,1,1,1,0,0,0, p, cha);
    P( 6,0,0,0,1,0,0,0,0, p, cha);
    P( 5,0,0,1,1,1,0,0,0, p, cha);
    P( 4,0,1,0,1,0,1,0,0, p, cha);
    P( 3,1,0,0,1,0,0,1,0, p, cha);
    P( 2,0,0,0,1,0,0,0,0, p, cha);
    P( 1,0,0,0,0,0,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else if (g < 0.875) {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,1,0,0,1,0,0, p, cha);
    P( 9,0,0,1,0,0,1,0,0, p, cha);
    P( 8,1,1,1,1,1,1,1,0, p, cha);
    P( 7,0,0,1,0,0,1,0,0, p, cha);
    P( 6,0,0,1,0,0,1,0,0, p, cha);
    P( 5,0,1,0,0,1,0,0,0, p, cha);
    P( 4,0,1,0,0,1,0,0,0, p, cha);
    P( 3,1,1,1,1,1,1,1,0, p, cha);
    P( 2,0,1,0,0,1,0,0,0, p, cha);
    P( 1,0,1,0,0,1,0,0,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  } else {
    P(11,0,0,0,0,0,0,0,0, p, cha);
    P(10,0,0,1,1,1,1,0,0, p, cha);
    P( 9,0,1,0,0,0,0,1,0, p, cha);
    P( 8,1,0,0,0,1,1,1,0, p, cha);
    P( 7,1,0,0,1,0,0,1,0, p, cha);
    P( 6,1,0,0,1,0,0,1,0, p, cha);
    P( 5,1,0,0,1,0,0,1,0, p, cha);
    P( 4,1,0,0,1,0,0,1,0, p, cha);
    P( 3,1,0,0,1,1,1,1,0, p, cha);
    P( 2,0,1,0,0,0,0,0,0, p, cha);
    P( 1,0,0,1,1,1,1,1,0, p, cha);
    P( 0,0,0,0,0,0,0,0,0, p, cha);
  }
  vec3 col = prgm1.xyz / max(prgm1.x, max(prgm1.y, prgm1.z));
  vec4 charColor = vec4(cha * col, 1.0);
  if (bypass) {
    vec4 color = vec4(texture2D(prgm1Texture, uv).xyz, 1.0);
    gl_FragColor = color;
  } else {
    vec4 color = vec4(mix(prgm1, charColor, amount).xyz, 1.0);
    gl_FragColor = color;
  }
}

// ╔═════════════╦═════════════════╦════════════════╗
// ║ Marco Gomez ║ @TheCodeTherapy ║ https://mgz.me ║
// ╚═════════════╩═════════════════╩════════════════╝
precision highp float;

uniform sampler2D prgm2Texture;
uniform vec2 resolution;

vec3 samplef(vec2 uv, sampler2D tex) {
  return pow(texture2D(tex, uv).xyz, vec3(2.2, 2.2, 2.2));
}

vec3 highlights(vec3 pixel, float threshold) {
  float val = (pixel.x + pixel.y + pixel.z) / 3.0;
  return pixel * smoothstep(threshold - 0.1, threshold + 0.1, val);
}

vec3 hsample(vec2 uv, sampler2D tex) {
  return highlights(samplef(uv, tex), 0.17);
}

vec3 blur(vec2 uv, float offs, sampler2D tex) {
  vec4 xoffs = offs * vec4(-2.0, -1.0, 1.0, 2.0) / resolution.x;
  vec4 yoffs = offs * vec4(-2.0, -1.0, 1.0, 2.0) / resolution.y;
  vec3 color = vec3(0.0);
  color += hsample(uv + vec2(xoffs.x, yoffs.x), tex) * 0.00366;
  color += hsample(uv + vec2(xoffs.y, yoffs.x), tex) * 0.01465;
  color += hsample(uv + vec2(    0.0, yoffs.x), tex) * 0.02564;
  color += hsample(uv + vec2(xoffs.z, yoffs.x), tex) * 0.01465;
  color += hsample(uv + vec2(xoffs.w, yoffs.x), tex) * 0.00366;
  color += hsample(uv + vec2(xoffs.x, yoffs.y), tex) * 0.01465;
  color += hsample(uv + vec2(xoffs.y, yoffs.y), tex) * 0.05861;
  color += hsample(uv + vec2(    0.0, yoffs.y), tex) * 0.09524;
  color += hsample(uv + vec2(xoffs.z, yoffs.y), tex) * 0.05861;
  color += hsample(uv + vec2(xoffs.w, yoffs.y), tex) * 0.01465;
  color += hsample(uv + vec2(xoffs.x, 0.0), tex) * 0.02564;
  color += hsample(uv + vec2(xoffs.y, 0.0), tex) * 0.09524;
  color += hsample(uv + vec2(    0.0, 0.0), tex) * 0.15018;
  color += hsample(uv + vec2(xoffs.z, 0.0), tex) * 0.09524;
  color += hsample(uv + vec2(xoffs.w, 0.0), tex) * 0.02564;
  color += hsample(uv + vec2(xoffs.x, yoffs.z), tex) * 0.01465;
  color += hsample(uv + vec2(xoffs.y, yoffs.z), tex) * 0.05861;
  color += hsample(uv + vec2(    0.0, yoffs.z), tex) * 0.09524;
  color += hsample(uv + vec2(xoffs.z, yoffs.z), tex) * 0.05861;
  color += hsample(uv + vec2(xoffs.w, yoffs.z), tex) * 0.01465;
  color += hsample(uv + vec2(xoffs.x, yoffs.w), tex) * 0.00366;
  color += hsample(uv + vec2(xoffs.y, yoffs.w), tex) * 0.01465;
  color += hsample(uv + vec2(    0.0, yoffs.w), tex) * 0.02564;
  color += hsample(uv + vec2(xoffs.z, yoffs.w), tex) * 0.01465;
  color += hsample(uv + vec2(xoffs.w, yoffs.w), tex) * 0.00366;
  return color;
}

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;
  vec3 prgm2 = texture2D(prgm2Texture, uv).xyz;
  vec3 color = blur(uv, 2.0, prgm2Texture);
  color += blur(uv, 3.0, prgm2Texture);
  color += blur(uv, 5.0, prgm2Texture);
  color += blur(uv, 7.0, prgm2Texture);
  color /= 3.0;
  color += samplef(uv, prgm2Texture);
  color = mix(prgm2, color, 0.9);
  gl_FragColor = vec4(color, 1.0);
}