// Code by Flopine

// Thanks to wsmind, leon, XT95, lsdlive, lamogui,
// Coyhot, Alkama,YX, NuSan, slerpy, wwrighter
// BigWings, FabriceNeyret and Blackle for teaching me

// Thanks LJ for giving me the spark :3

// Thanks to the Cookie Collective, which build a cozy and safe environment for me
// and other to sprout :)
// https://twitter.com/CookieDemoparty



// Trying the clean domain repetition
// presenting by Blackle on Perfect Pistons <3
// https://youtu.be/I8fmkLK1OKg
// https://www.shadertoy.com/view/WtXcWB

#define PI acos(-1.)
#define rot(a) mat2(cos(a),sin(a),-sin(a),cos(a))

vec2 edge (vec2 p)
{
    vec2 p2 = abs(p);
    if (p2.x > p2.y) return vec2((p.x<0.)?-1.:1., 0.);
    else return vec2(0., (p.y<0.)?-1.:1.);
}

float box (vec3 p , vec3 c)
{
    vec3 q = abs(p)-c;
    return min(0.,max(q.x,max(q.y,q.z)))+length(max(q,0.));
}


float SDF (vec3 p)
{
    p.yz *= rot(-atan(1./sqrt(2.)));
    p.xz *= rot(PI/4.);

    vec2 center = floor(p.xz)+.5;
    vec2 neighbour = center + edge(p.xz-center);
    float py = sin(length(center)+iTime)*1.5;

    float me = box(p-vec3(center.x, 0., center.y), vec3(.4,2.+py,.4))-.05;
    float next = box(p-vec3(neighbour.x, 0., neighbour.y), vec3(.4, 3.5, .4))-.05;
    float set = min(me,next);

    return set;
}

vec3 getnorm (vec3 p)
{
    vec2 eps = vec2(0.001,0.);
    return normalize(SDF(p)-vec3(SDF(p-eps.xyy),SDF(p-eps.yxy),SDF(p-eps.yyx)));
}

float AO (float eps, vec3 p, vec3 n)
{return clamp(SDF(p+eps*n)/eps,0.,1.);}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (2.*fragCoord-iResolution.xy)/iResolution.y;
    vec3 ro = vec3(uv*3.,-30.), rd=vec3(0.,0.1,1.),p=ro,
    col=vec3(0.),l=normalize(vec3(1.,2.,-2.));

    bool hit=false;
    for (float i=0.; i<100.; i++)
    {
        float d= SDF(p);
        if (d<0.001)
        {hit=true;break;}
        p += d*rd;
    }

    if (hit)
    {
        vec3 n = getnorm(p);
        float light = dot(n,l)*.5+.5;
        float ao = AO(0.1,p,n)+AO(0.35,p,n)+AO(0.75,p,n);
        col = vec3(1.)*light*(ao/2.);
    }

    fragColor = vec4(sqrt(col),1.0);
}
