// Fork of "revision 2025 cursed tiling b" by jeyko. https://shadertoy.com/view/4ccSDM
// 2024-06-30 18:47:26

in vec2 uv;

out vec4 C;

uniform float u_t;
uniform float u_bpm;
uniform vec3 bg_col;
uniform vec3 main_col;
uniform vec3 hl_col;
uniform vec3 silent_col;

const float PI=acos(-1.);
const float TAU=PI*2.;
const float BEAT_DUR=60./u_bpm;
const int LEVWRIGHTIAN[] = int[](67,72,69, 77,85,71,65);

#include scene_nordlicht24/jy-sdf-font.glsl
#include scene_nordlicht24/rand.glsl

float Bayer2(vec2 a) {
    a = floor(a);
    return fract(a.x / 2. + a.y * a.y * .75);
}

#define Bayer4(a)   (Bayer2 (.5 *(a)) * .25 + Bayer2(a))
//float rand(vec2 p){return dot(fract(sin(p*849.163)*636.164),fract(sin(p*734.845)*936.368));}
const float t=u_t-Bayer4(gl_FragCoord.xy)/50.0;

float ease(float n){return smoothstep(0.,1.,smoothstep(0.,1.,n));}
float ease2(float n){return ease(ease(n));}
float sdSegment( in vec2 p, in vec2 a, in vec2 b )
{
    vec2 pa = p-a, ba = b-a;
    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
    return length( pa - ba*h );
}
float letter(vec2 p, int ascii, vec2 stretch)
{
    p*=3.;
    float accum=9999.;
    for(int j=0;j<SEGMENTS.length();j++){
        if((ascii_to_bitmask(ascii)&(1<<j))!=0){
            vec2 a=SEGMENTS[j][0];
            a+=sign(a)*stretch;
            vec2 b=SEGMENTS[j][1];
            b+=sign(b)*stretch;
            accum=min(accum,sdSegment(p,a,b));
        }
    }

    return accum;
}
vec3 hash32(vec2 p){
    p += 425.;
    vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
    p3 += dot(p3, p3.yxz+33.33);
    return fract((p3.xxy+p3.yzz)*p3.zyx);
}
struct Cell {
    int ax;
    float offs;
    vec3 r;
};

bool dbg = false;


Cell get_cell(ivec2 id){
    Cell c;

    c.r = hash32(vec2(id));
    c.ax = (id.x + id.y % 2) % 2;
    c.offs = c.r.x;

    float trep = 1.;

    float rr = float(id.x) + float(id.y);
    rr = sin(rr + float(id.y));
    c.r.y = fract(sin(rr));

    float t = t*(pow(c.r.y,0.5) + 0.4)*1.;

    float env = fract(t/trep);
    env = smoothstep(0.,1.0,env);
    env = pow(env,0.5 + c.r.z*0. + 2.);
    t = floor(t/trep)*trep + env;
    c.offs = 0.5 + 0.2*sin(t * 1.14);

    return c;
}

float made(vec2 p){
    float accum=1.;
    
    p*=5.;

    float i_t=floor(t*.25/BEAT_DUR),
          f_t=fract(t*.25/BEAT_DUR);
    
    vec3 r=hash32(vec2(i_t+50)); r*=2.; r-=1.;
    
    r.x=mix(.5,r.x,ease(min(1.,f_t*2.)));
    r.yz=mix(vec2(.5),r.yz,ease(max(0.,f_t*2.-1.)));
    
    accum=min(accum,letter(p-vec2(-.75, .75),77,vec2(r.x,r.y)));
    accum=min(accum,letter(p-vec2( .75, .75),65,vec2(1.-r.x,r.z)));
    accum=min(accum,letter(p-vec2(-.75,-.75),68,vec2(r.x,1.-r.y)));
    accum=min(accum,letter(p-vec2( .75,-.75),69,vec2(1.-r.x,1.-r.z)));
    return accum-.1;
}

float with(vec2 p){
    float accum=1.;

    p*=5.;

    float i_t=floor(t*.25/BEAT_DUR),
    f_t=fract(t*.25/BEAT_DUR);

    vec3 r=hash32(vec2(i_t+200)); r*=2.; r-=1.;

    r.x=mix(.5,r.x,ease(min(1.,f_t*2.)));
    r.yz=mix(vec2(.5),r.yz,ease(max(0.,f_t*2.-1.)));

    accum=min(accum,letter(p-vec2(-.75, .75),87,vec2(r.x,r.y)));
    accum=min(accum,letter(p-vec2( .75, .75),73,vec2(1.-r.x,r.z)));
    accum=min(accum,letter(p-vec2(-.75,-.75),84,vec2(r.x,1.-r.y)));
    accum=min(accum,letter(p-vec2( .75,-.75),72,vec2(1.-r.x,1.-r.z)));
    return accum-.1;
}

float levwrightian(vec2 p){
    float accum=1.;

    p*=15.;

//    float i_t=floor(u_t*.25/BEAT_DUR),
//    f_t=fract(u_t*.25/BEAT_DUR);
    for(int i=0; i<LEVWRIGHTIAN.length(); i++){
        float off=float(i%LEVWRIGHTIAN.length()) - float(LEVWRIGHTIAN.length()-1)/2.;

        accum=min(accum,letter(p-vec2(off*1.5,0),LEVWRIGHTIAN[i],vec2(.5,mix(3.,.3,pow(sin(t*4.7-i*.2)*.5+.5,20.)))));
    }

    
    return accum-.3;
}

vec2 rot_uv(vec2 p){
    float i_t=floor(t*.125/BEAT_DUR),
          f_t=fract(t*.125/BEAT_DUR);

    p*=rot(mix(hash32(vec2(i_t)).x,hash32(vec2(i_t+1)).x,ease2(f_t))*PI-PI/2.);
    return p;
}

void main(){
    const float PREV_END=128.;
    
    vec2 uv = (U - 0.5*R)/R.y;
    vec2 uv2 = uv;

    float i_t=floor(t/BEAT_DUR),
          f_t=fract(t/BEAT_DUR);

    uv=rot_uv(uv);


    {
        uv.y -= t*0.1;
        uv *= 6.;
        uv += 40.;
    }


    C -= C;

    float fw = fwidth(uv.y);

    vec2 fruv = fract(uv);

    ivec2 id = ivec2(uv);

    Cell c = get_cell(id);
    float c_sd = fruv[c.ax] - c.offs;

    ivec2 oc_offs = ivec2(0);
    oc_offs[c.ax] = int(sign(c_sd));

    Cell oc = get_cell(id + oc_offs);
    float oc_sd = fruv[1-c.ax] - oc.offs;

    int c_dir = int(sign(c_sd));
    int oc_dir = int(sign(oc_sd));

    ivec2 cid = id;
    cid[c.ax] += (c_dir + 1)/2 + 1;
    cid[1-c.ax] += (oc_dir + 1)/2 + 1;

    vec2 cuv;
    vec2 uvsc;
    {
        ivec2 cuv_offs = ivec2(0);
        cuv_offs[c.ax] = c_dir;
        cuv_offs[1-c.ax] = oc_dir;

        Cell cuv_oc = get_cell(id + cuv_offs);

        if(c_dir > 0){
            float range = 1. + cuv_oc.offs - c.offs;
            float u = fruv[c.ax] - c.offs;
            uvsc[c.ax] = range;
            u /= range;
            cuv[c.ax] = u;
        } else {
            float range = 1. + c.offs - cuv_oc.offs;
            float u = fruv[c.ax] + 1. - cuv_oc.offs;
            u /= range;
            uvsc[c.ax] = range;
            cuv[c.ax] = u;
        }
    }
    {
        ivec2 cuv_offs = ivec2(0);
        cuv_offs[1-c.ax] = oc_dir;

        Cell cuv_oc = get_cell(id + cuv_offs);

        if(oc_dir > 0){
            float range = 1. + cuv_oc.offs - oc.offs;
            float u = fruv[1-c.ax] - oc.offs;
            u /= range;
            uvsc[1-c.ax] = range;
            cuv[1-c.ax] = u;
        } else {
            float range = 1. + oc.offs - cuv_oc.offs;
            float u = fruv[1-c.ax] + 1. - cuv_oc.offs;
            u /= range;
            uvsc[1-c.ax] = range;
            cuv[1-c.ax] = u;
        }
    }

    vec3 cr = hash32(vec2(cid));
    
    float dist = letter(cuv.xy*1.-.5,65+int(cr.x*float(91-65)),vec2(0));
    vec3 back=mix(silent_col,bg_col,step(.3,dist));
    
    float title=mix(
    made(uv2),
    mix(
    with(uv2),
    levwrightian(uv2),
    step(PREV_END+8.,i_t)
    ),
    step(PREV_END+4.,i_t)
    );
    vec3 col=mix(main_col,back,step(0.,title));
    
    C=vec4(col,1);
}
