#version 330 core
out vec4 fragColor;
in vec2 uv;
uniform vec3 iResolution;
uniform float iTime;
uniform int uPrimCount;
uniform vec4 uPrimsA[128];
uniform vec4 uPrimsB[128];
uniform float uScale;
uniform float uThickness;
uniform vec3 uTextColor;
uniform vec3 uBorderColor;
uniform float uBorderIntensity;
uniform float uAlpha;
uniform float uOffset;
uniform vec4 uBorderRect; // minX, minY, maxX, maxY in glyph space

float pi = atan(1.0)*4.0;
float tau = atan(1.0)*8.0;

float epsilon = 1e-3;
float infinity = 1e6;

#define USE_CHEAP_ARCS

#define BRIGHTNESS 0.008

bool ApproxEqual(float a, float b)
{
    return abs(a - b) <= epsilon;
}

float dfLine(vec2 start, vec2 end, vec2 uv)
{
    start *= uScale;
    end *= uScale;
    vec2 line = end - start;
    float frac = dot(uv - start,line) / dot(line,line);
    return distance(start + line * clamp(frac, 0.0, 1.0), uv);
}

float dfArc(vec2 origin, float startAng, float sweep, float radius, vec2 uv)
{
    origin *= uScale;
    radius *= uScale;
    uv -= origin;
    uv *= mat2(cos(startAng), sin(startAng), -sin(startAng), cos(startAng));
    #ifdef USE_CHEAP_ARCS
        if(ApproxEqual(sweep, pi))
        {
            float d = abs(length(uv) - radius) + step(uv.y, 0.0) * infinity;
            d = min(d, min(length(uv - vec2(radius, 0)), length(uv + vec2(radius, 0))));
            return d;
        }
        else if(ApproxEqual(sweep, pi/2.0))
        {
            float d = abs(length(uv) - radius) + step(min(uv.x, uv.y), 0.0) * infinity;
            d = min(d, min(length(uv - vec2(0, radius)), length(uv - vec2(radius, 0))));
            return d;
        }
        else
        {
            float offs = (sweep / 2.0 - pi);
            float ang = mod(atan(uv.y, uv.x) - offs, tau) + offs;
            ang = clamp(ang, min(0.0, sweep), max(0.0, sweep));
            return distance(radius * vec2(cos(ang), sin(ang)), uv);
        }
    #else
        float offs = (sweep / 2.0 - pi);
        float ang = mod(atan(uv.y, uv.x) - offs, tau) + offs;
        ang = clamp(ang, min(0.0, sweep), max(0.0, sweep));
        return distance(radius * vec2(cos(ang), sin(ang)), uv);
    #endif
}

float dfLogo(vec2 uv)
{
    float dist = infinity;
    for (int i = 0; i < uPrimCount; ++i)
    {
        vec4 a = uPrimsA[i];
        vec4 b = uPrimsB[i];
        float typ = a.x;
        if (typ < 0.5)
        {
            vec2 s = vec2(a.y, a.z);
            vec2 e = vec2(a.w, b.x);
            dist = min(dist, dfLine(s, e, uv));
        }
        else
        {
            vec2 origin = vec2(a.y, a.z);
            float startAng = b.y;
            float sweep = b.z;
            float radius = b.w;
            dist = min(dist, dfArc(origin, startAng, sweep, radius, uv));
        }
    }
    return dist;
}

float dfRectBorder(vec2 uv, vec4 rect)
{
    float dist = infinity;
    vec2 p0 = vec2(rect.x, rect.y);
    vec2 p1 = vec2(rect.z, rect.y);
    vec2 p2 = vec2(rect.z, rect.w);
    vec2 p3 = vec2(rect.x, rect.w);
    dist = min(dist, dfLine(p0, p1, uv));
    dist = min(dist, dfLine(p1, p2, uv));
    dist = min(dist, dfLine(p2, p3, uv));
    dist = min(dist, dfLine(p3, p0, uv));
    return dist;
}

void main(){
    vec2 aspect = iResolution.xy / iResolution.y;
    vec2 fragCoord = uv * iResolution.xy;
    vec2 fuv = fragCoord.xy / iResolution.y - aspect/2.0;
    vec2 offs = vec2(uOffset, 1.5) * uScale;

    float dist = 0.0;
    vec3 color = vec3(0);

    float fade_text = clamp((iTime - 0.6) / 0.5, 0.0, 1.0);
    float bright_text = BRIGHTNESS * fade_text;

    float fade_bord = clamp((iTime - 0.5) / 0.5, 0.0, 1.0);
    float bright_bord = BRIGHTNESS * fade_bord;

    float distText = dfLogo(fuv + offs);
    float shadeText = bright_text / max(epsilon, distText - uThickness);
    color += uTextColor * shadeText;

    float distFrame = dfRectBorder(fuv + offs, uBorderRect);
    float frameThickness = uThickness * 3.0;
    float shadeBorder = bright_bord * uBorderIntensity / max(epsilon, distFrame - frameThickness);
    color += uBorderColor * shadeBorder;

    vec3 mapped = color * uAlpha * 1.8;
    mapped = mapped / (mapped + vec3(0.6));
    float glowMask = clamp(max(max(mapped.r, mapped.g), mapped.b), 0.0, 1.0);
    fragColor = vec4(clamp(mapped, 0.0, 1.0), glowMask * uAlpha);
}
