#version 330 core
in vec2 vUV;
out vec4 FragColor;
uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;
uniform float uWriteSpeed;
// font size controlled by uniform (default set from C#)
uniform float uFontSize;

uniform float uFontSpacing;
uniform float uLineSpacing;
uniform vec2 uTextOrigin;
uniform sampler2D iChannel0;

// MatrixText fragment shader adapted from provided source

vec2 coord;

// font sizing now controlled by uniforms: uFontSize, uLetterSpacing, uLineSpacing
vec2 caret_origin = vec2(2.4, 0.7);
vec2 caret;

#define STROKEWIDTH 0.05
#define PI 3.14159265359

#define A_ vec2(0.,0.)
#define B_ vec2(1.,0.)
#define C_ vec2(2.,0.)
#define E_ vec2(1.,1.)
#define G_ vec2(0.,2.)
#define H_ vec2(1.,2.)
#define I_ vec2(2.,2.)
#define J_ vec2(0.,3.)
#define K_ vec2(1.,3.)
#define L_ vec2(2.,3.)
#define M_ vec2(0.,4.)
#define N_ vec2(1.,4.)
#define O_ vec2(2.,4.)
#define S_ vec2(0.,6.)
#define T_ vec2(1.,6.)
#define U_ vec2(2.0,6.)

#define A(p) t(G_,I_,p) + t(I_,O_,p) + t(O_,M_, p) + t(M_,J_,p) + t(J_,L_,p);caret.x += 1.0;
#define B(p) t(A_,M_,p) + t(M_,O_,p) + t(O_,I_, p) + t(I_,G_,p);caret.x += 1.0;
#define C(p) t(I_,G_,p) + t(G_,M_,p) + t(M_,O_,p);caret.x += 1.0;
#define D(p) t(C_,O_,p) + t(O_,M_,p) + t(M_,G_,p) + t(G_,I_,p);caret.x += 1.0;
#define E(p) t(O_,M_,p) + t(M_,G_,p) + t(G_,I_,p) + t(I_,L_,p) + t(L_,J_,p);caret.x += 1.0;
#define F(p) t(C_,B_,p) + t(B_,N_,p) + t(G_,I_,p);caret.x += 1.0;
#define G(p) t(O_,M_,p) + t(M_,G_,p) + t(G_,I_,p) + t(I_,U_,p) + t(U_,S_,p);caret.x += 1.0;
#define H(p) t(A_,M_,p) + t(G_,I_,p) + t(I_,O_,p);caret.x += 1.0;
#define I(p) t(E_,E_,p) + t(H_,N_,p);caret.x += 1.0;
#define J(p) t(E_,E_,p) + t(H_,T_,p) + t(T_,S_,p);caret.x += 1.0;
#define K(p) t(A_,M_,p) + t(M_,I_,p) + t(K_,O_,p);caret.x += 1.0;
#define L(p) t(B_,N_,p);caret.x += 1.0;
#define M(p) t(M_,G_,p) + t(G_,I_,p) + t(H_,N_,p) + t(I_,O_,p);caret.x += 1.0;
#define N(p) t(M_,G_,p) + t(G_,I_,p) + t(I_,O_,p);caret.x += 1.0;
#define O(p) t(G_,I_,p) + t(I_,O_,p) + t(O_,M_, p) + t(M_,G_,p);caret.x += 1.0;
#define P(p) t(S_,G_,p) + t(G_,I_,p) + t(I_,O_,p) + t(O_,M_, p);caret.x += 1.0;
#define Q(p) t(U_,I_,p) + t(I_,G_,p) + t(G_,M_,p) + t(M_,O_, p);caret.x += 1.0;
#define R(p) t(M_,G_,p) + t(G_,I_,p);caret.x += 1.0;
#define S(p) t(I_,G_,p) + t(G_,J_,p) + t(J_,L_,p) + t(L_,O_,p) + t(O_,M_,p);caret.x += 1.0;
#define T(p) t(B_,N_,p) + t(N_,O_,p) + t(G_,I_,p);caret.x += 1.0;
#define U(p) t(G_,M_,p) + t(M_,O_,p) + t(O_,I_,p);caret.x += 1.0;
#define V(p) t(G_,J_,p) + t(J_,N_,p) + t(N_,L_,p) + t(L_,I_,p);caret.x += 1.0;
#define W(p) t(G_,M_,p) + t(M_,O_,p) + t(N_,H_,p) + t(O_,I_,p);caret.x += 1.0;
#define X(p) t(G_,O_,p) + t(I_,M_,p);caret.x += 1.0;
#define Y(p) t(G_,M_,p) + t(M_,O_,p) + t(I_,U_,p) + t(U_,S_,p);caret.x += 1.0;
#define Z(p) t(G_,I_,p) + t(I_,M_,p) + t(M_,O_,p);caret.x += 1.0;
#define STOP(p) t(N_,N_,p);caret.x += 1.0;

// Digit macros (approximate shapes using existing node segments)
// Ensure a tiny dot segment is included first so at least some ink appears early during the write animation
//#define ZERO(p) t(N_,N_,p) + t(G_,I_,p) + t(I_,O_,p) + t(O_,M_,p) + t(M_,G_,p);caret.x += 1.0;
#define ZERO(p) t(A_,C_,p) + t(C_,O_,p) + t(O_,M_,p) + t(M_,A_,p) + t(M_,C_,p);caret.x += 1.0;
#define ONE(p)  t(E_,C_,p) + t(C_,I_,p) + t(I_,O_,p);caret.x += 1.0;
#define TWO(p)  t(A_,C_,p) + t(C_,I_,p) + t(I_,G_,p) + t(G_,M_,p) + t(M_,O_,p);caret.x += 1.0;
#define THREE(p) t(A_,C_,p) + t(C_,I_,p) + t(I_,G_,p) + t(I_,O_,p) + t(O_,M_,p);caret.x += 1.0;
#define FOUR(p) t(A_,G_,p) + t(G_,I_,p) + t(C_,I_,p) + t(I_,O_,p);caret.x += 1.0;
#define FIVE(p) t(C_,A_,p) + t(A_,G_,p) + t(G_,I_,p) + t(I_,O_,p) + t(O_,M_,p) ;caret.x += 1.0;
#define SIX(p)  t(A_,G_,p) + t(G_,M_,p) + t(M_,O_,p) + t(O_,I_,p) + t(I_,G_,p) ;caret.x += 1.0;
#define SEVEN(p) t(A_,C_,p) + t(C_,I_,p) + t(I_,O_,p);caret.x += 1.0;
#define EIGHT(p) t(A_,C_,p) + t(C_,I_,p) + t(I_,O_,p) + t(O_,M_,p) + t(M_,G_,p) + t(G_,A_,p)+ t(G_,I_,p);caret.x += 1.0;
#define NINE(p)  t(O_,I_,p) + t(I_,C_,p) + t(C_,A_,p) + t(A_,G_,p) + t(G_,I_,p);caret.x += 1.0;

// At symbol approximation
#define AT(p) t(O_,M_,p) + t(M_,A_,p) + t(A_,C_,p) + t(C_,I_,p) + t(I_,H_,p) + t(H_,B_,p);caret.x += 1.0;


//-----------------------------------------------------------------------------------
float minimum_distance(vec2 v, vec2 w, vec2 p)
{    // Return minimum distance between line segment vw and point p
    
    float l2 = (v.x - w.x)*(v.x - w.x) + (v.y - w.y)*(v.y - w.y); //length_squared(v, w);  // i.e. |w-v|^2 -  avoid a sqrt
    if (l2 == 0.0) {
        return distance(p, v);   // v == w case
    }
    
    // Consider the line extending the segment, parameterized as v + t (w - v).
    // We find projection of point p onto the line.  It falls where t = [(p-v) . (w-v)] / |w-v|^2
    float t = dot(p - v, w - v) / l2;
    if(t < 0.0) {
        // Beyond the 'v' end of the segment
        return distance(p, v);
    } else if (t > 1.0) {
        return distance(p, w);  // Beyond the 'w' end of the segment
    }
    vec2 projection = v + t * (w - v);  // Projection falls on the segment
    return distance(p, projection);
}

//-----------------------------------------------------------------------------------
float textColor(vec2 from, vec2 to, vec2 p)
{
    p *= uFontSize;
    float inkNess = 0., nearLine, corner;
    nearLine = minimum_distance(from,to,p); // basic distance from segment, thanks http://glsl.heroku.com/e#6140.0
    inkNess += smoothstep(0., 1., 1.- 14.*(nearLine - STROKEWIDTH)); // ugly still
    inkNess += smoothstep(0., 2.5, 1.- (nearLine  + 5. * STROKEWIDTH)); // glow
    return inkNess;
}

//-----------------------------------------------------------------------------------
vec2 grid(vec2 letterspace) 
{
    return ( vec2( (letterspace.x / 2.) * .65 , 1.0-((letterspace.y / 2.) * .95) ));
}

//-----------------------------------------------------------------------------------
float count = 0.0;
float gtime;
float t(vec2 from, vec2 to, vec2 p) 
{
    count++;
    if (count > gtime*20.0) return 0.0;
    return textColor(grid(from), grid(to), p);
}

//-----------------------------------------------------------------------------------
vec2 r()
{
    // apply text origin (in pixels), then normalize to frag-space
    vec2 pos = (coord - uTextOrigin) / iResolution.xy;
    // apply caret offsets (in character-space)
    pos.y -= caret.y;
    pos.x -= uFontSpacing*caret.x;
    return pos;
}

//-----------------------------------------------------------------------------------
void _()
{
    caret.x += 1.5;
}

//-----------------------------------------------------------------------------------
void newline()
{
    caret.x = caret_origin.x;
    // line step scaled by uniform uLineSpacing (default ~1.4)
    caret.y -= (0.18 * uLineSpacing);
}

// @@MAINIMAGE@@
