#define SHOW_POINTS 1
#define SHOW_SEGMENTS 1

// segment.x is distance to closest point
// segment.y is barycentric coefficient for closest point
// segment.z is length of closest point on curve, on the curve, starting from A
// segment.a is approximate length of curve
vec4 segment( vec2 p, vec2 a, vec2 b )
{
  a -= p;
  b -= p;
  vec3 k = vec3( dot(a,a) , dot(b,b) , dot(a,b) );
  float t = (k.x - k.z)/( k.x + k.y - 2.*k.z );
  float len = length(b-a);

  if( t < 0. ){
      return vec4( sqrt(k.x) , 0. , 0. , len );
  } else if( t > 1. ){
      return vec4( sqrt(k.y) , 1. , len , len );
  } else {
  	return vec4( length(a*(1.-t) + b*t) , t , t*len , len );
  }
}

// https://www.shadertoy.com/view/4djSRW
#define ITERATIONS 4


// *** Change these to suit your range of random numbers..

// *** Use this for integer stepped ranges, ie Value-Noise/Perlin noise functions.
#define HASHSCALE1 .1031
#define HASHSCALE3 vec3(.1031, .1030, .0973)
#define HASHSCALE4 vec4(1031, .1030, .0973, .1099)
//----------------------------------------------------------------------------------------
///  3 out, 2 in...
vec3 hash32(vec2 p)
{
	vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3);
    p3 += dot(p3, p3.yxz+19.19);
    return fract((p3.xxy+p3.yzz)*p3.zyx);
}

#define PRECISION 0.2

vec3 hash3point(vec2 p)
{
    //vec3 col = hash32(p);
    vec3 col =
            hash32(p*1.25672+vec2(.2,.8))
          * hash32(vec2(p.y,p.x)/3.42464-vec2(.5,.0))
          - hash32(vec2(3.0+p.y,1.2))
    ;

    return clamp(pow(
        abs(col)
        , vec3(.6,.5,.4)
      ),0.0,1.0
    );
    /*ivec2 ip = ivec2(
        round(p.x / PRECISION) ,
        round(p.y / PRECISION)
    );

    return hash32(vec2(ip));*/
}

void mixColorPoint(vec2 uv,inout vec3 col,vec2 colPoint,float scale)
{
    col = mix(
        col ,
        hash3point(colPoint) ,
        1.0 - smoothstep(0.0,1.0,sqrt(sqrt( length(uv - colPoint)* scale )))
    );
}


void mixColorLine(vec2 uv,inout vec3 col,vec2 lineA,vec2 lineB,float scale)
{
    col = mix(
        col ,
        hash3point(lineA+lineB) ,
        1.0 - smoothstep(0.0,1.0,sqrt(sqrt( segment(uv,lineA,lineB).x * scale )))
    );
}

bool pointsOnSameSideOfLine(vec2 pointA,vec2 pointB,vec2 lineA, vec2 lineB)
{
    vec2 n = lineB - lineA;
    n = vec2(n.y,-n.x);
    return  dot(pointA-lineA,n)
          * dot(pointB-lineA,n)
    > 0.0;
}

float viewportMagnify = 1.0;
vec2 screenToViewport(vec2 uv)
{
    return (uv - iResolution.xy/2.0 ) / min(iResolution.x,iResolution.y) * viewportMagnify;
}

float uhash( uint n )
{
    // integer hash copied from Hugo Elias
	n = (n << 13U) ^ n;
    n = n * (n * n * 15731U + 789221U) + 1376312589U;


    //return 1.0 - float(n&0x7fffffffU)/float(0x7fffffff);

    // floating point conversion from https://iquilezles.org/articles/sfrand
    return uintBitsToFloat( (n>>9U) | 0x3f800000U ) - 1.0;
}

float hash( float n )
{
    return ( tanh(uhash(uint(n))) + 1.0 ) / 2.0;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    fragColor = vec4(0.0);

    int nbIterations = 4 + int(floor((cos(iTime*3.14/5.0)+1.1)*3.5));

	int EquerreVersion = 1;
    vec2 base = vec2(sqrt(3.0),1.0);
    base *= 50000.0;


	vec2 uv = screenToViewport(fragCoord.xy );

    viewportMagnify = base.x / 4.1;
    uv *= viewportMagnify;
    uv += base/3.5;

    // Base Triangle
    vec2 A = vec2(0.0);
    vec2 B = A + vec2(base.x,0.0);
    vec2 C = A + vec2(0.0,base.y);

    vec2 D,E,F;
    #define SWAP(X,Y) F = X; X = Y; Y = F;

    #ifdef REPEAT_TILING
   		// Upper Triangle
        if( !pointsOnSameSideOfLine(uv,
                         A,B,C) )
        {
            A += vec2(base.x,base.y);
            SWAP(B,C)
        }
    #endif

    float TriangleID = 1.0;

    for(int i = 0 ; i < nbIterations ; i++)
    {
        D = (2.0 * A + B)/3.0;
        E = (B + C)/2.0;

        if( pointsOnSameSideOfLine(uv,
                                A,D,C) )
        {
            B = D;
            SWAP(B,C)
        }
        else if( pointsOnSameSideOfLine(uv,
                                B,D,E) )
        {
            A = E;
            C = D;
            TriangleID++;
        }
        else
        {
            A = E;
            B = C;
            C = D;
            TriangleID++;
            TriangleID++;
        }

        TriangleID *= 3.0;
    }

    TriangleID /= 3.0;

    /*fragColor.rgb = vec3(
        hash(mod(TriangleID,2.0)),
        hash(mod(TriangleID,2.0)),
        hash(mod(TriangleID,2.0))
    );*/

    fragColor.r = mod(TriangleID,3.0)/2.0;
    fragColor.g = mod(TriangleID,3.0)/2.0;
    fragColor.b = mod(TriangleID,3.0)/2.0;

    float scale = float(nbIterations);
    scale = pow(2.0,scale)/viewportMagnify/scale;

    #if SHOW_SEGMENTS==1
        mixColorLine(uv,fragColor.rgb,A,B,scale);
        mixColorLine(uv,fragColor.rgb,B,C,scale);
        mixColorLine(uv,fragColor.rgb,C,A,scale);
    #endif

    //scale /= float(nbIterations);

    #if SHOW_POINTS==1
        mixColorPoint(uv,fragColor.rgb,A,scale);
        mixColorPoint(uv,fragColor.rgb,B,scale);
        mixColorPoint(uv,fragColor.rgb,C,scale);
    #endif


	fragColor.rgb = pow(fragColor.rgb,vec3(0.5,.6,.7));
}



/*
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    uvec2 p = uvec2(fragCoord);

	float f = hash( p.x + 1920U*p.y + (1920U*1080U)*uint(iFrame) );

	fragColor = vec4(f,f,f,1.0);
}

*/
