//https://www.shadertoy.com/view/MtlcWX
vec2 rotate(vec2 v, float angle)
{
    float cosA = cos(angle), sinA = sin(angle);
    return v.x * vec2(cosA, sinA) + v.y * vec2(-sinA, cosA);
}

vec2 ortho(vec2 v)
{
    return vec2(v.y, -v.x);
}

void stroke(float dist, vec3 color, inout vec3 fragColor, float thickness, float aa)
{
    float alpha = smoothstep(0.5 * (thickness + aa), 0.5 * (thickness - aa), abs(dist));
    fragColor = mix(fragColor, color, alpha);
}

void fill(float dist, vec3 color, inout vec3 fragColor, float aa)
{
    float alpha = smoothstep(0.5*aa, -0.5*aa, dist);
    fragColor = mix(fragColor, color, alpha);
}

void renderGrid(vec2 pos, out vec3 fragColor)
{
    vec3 background = vec3(1.0);
    vec3 axes = vec3(0.4);
    vec3 lines = vec3(0.7);
    vec3 sublines = vec3(0.95);
    float subdiv = 8.0;

    float thickness = 0.003;
    float aa = length(fwidth(pos));

    fragColor = background;

    vec2 toSubGrid = pos - round(pos*subdiv)/subdiv;
    stroke(min(abs(toSubGrid.x), abs(toSubGrid.y)), sublines, fragColor, thickness, aa);

    vec2 toGrid = pos - round(pos);
    stroke(min(abs(toGrid.x), abs(toGrid.y)), lines, fragColor, thickness, aa);

    stroke(min(abs(pos.x), abs(pos.y)), axes, fragColor, thickness, aa);
}

float distLineSeg(vec2 a, vec2 b, vec2 pos)
{
    float proj = dot(pos - a, b - a) / dot(b - a, b - a);
    vec2 posNearest = mix(a, b, clamp(proj, 0.0, 1.0));
    return length(pos - posNearest);
}

void renderLineSeg(vec2 a, vec2 b, vec3 color, float thickness, vec2 pos, inout vec3 fragColor)
{
    stroke(distLineSeg(a, b, pos), color, fragColor, thickness, length(fwidth(pos)));
}

float sdistLine(vec2 a, vec2 b, vec2 pos)
{
    return dot(pos - a, normalize(ortho(b - a)));
}

float sdistTri(vec2 a, vec2 b, vec2 c, vec2 pos)
{
    return max( sdistLine(a, b, pos),
            max(sdistLine(b, c, pos),
                sdistLine(c, a, pos)));
}

float sdistQuadConvex(vec2 a, vec2 b, vec2 c, vec2 d, vec2 pos)
{
    return max(  sdistLine(a, b, pos),
            max( sdistLine(b, c, pos),
             max(sdistLine(c, d, pos),
                 sdistLine(d, a, pos))));
}

void renderATriangle(vec2 pos, inout vec3 fragColor)
{
    float dist = sdistTri(vec2(0.6, 0.4),
                          vec2(1.1, 0.9),
                          vec2(0.75, 0.95), pos);
    stroke(dist, vec3(0, 0, 1), fragColor, 0.005, length(fwidth(pos)));
}

void renderAxes(vec2 origin, vec2 pos, inout vec3 fragColor)
{
    float len = 0.1;
    float thickness = 0.0075;
    float aa = length(fwidth(pos));

    float xshaft = sdistQuadConvex(origin + vec2(0.5*thickness),
                                   origin - vec2(0.5*thickness),
                                   origin + vec2(len, -0.5*thickness),
                                   origin + vec2(len, 0.5*thickness), pos);
    float xhead = sdistTri(origin + vec2(len, -2.0*thickness),
                           origin + vec2(len + 6.0*thickness, 0),
                           origin + vec2(len, 2.0*thickness), pos);

    fill(min(xshaft, xhead), vec3(1, 0, 0), fragColor, aa);

    float yshaft = sdistQuadConvex(origin - vec2(0.5*thickness),
                                   origin + vec2(0.5*thickness),
                                   origin + vec2(0.5*thickness, len),
                                   origin + vec2(-0.5*thickness, len), pos);
    float yhead = sdistTri(origin + vec2(2.0*thickness, len),
                           origin + vec2(0, len + 6.0*thickness),
                           origin + vec2(-2.0*thickness, len), pos);

    fill(min(yshaft, yhead), vec3(0, 0.75, 0), fragColor, aa);

}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    float aspect = iResolution.x / iResolution.y;
	vec2 pos = (fragCoord / iResolution.y) * 1.3 - vec2((1.3*aspect - 1.0)/2.0, 0.15);

    // animate the grid a bit to test antialiasing
    pos = vec2(0.5) + rotate(pos - vec2(0.5), cos(iTime) * 0.1 - 0.05) *
        				(sin(iTime) * 0.1 + 1.0);
    pos.y -= 0.1 * sin(iTime);

    fragColor.a = 1.0;
	renderGrid(pos, fragColor.rgb);

    renderATriangle(pos, fragColor.rgb);

    renderAxes(vec2(0), pos, fragColor.rgb);
    renderAxes(vec2(1, 0), pos, fragColor.rgb);
}
