// Code by Flopine
// Thanks to wsmind, leon, XT95, lsdlive, lamogui, Coyhot, Alkama and YX for teaching me
// Thanks LJ for giving me the love of shadercoding :3

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

#define PI 3.141592

mat2 rot (float a)
{return mat2(cos(a),sin(a),-sin(a),cos(a));}

float cyl (vec3 p, float r, float h)
{return max(length(p.xy)-r, abs(p.z)-h);}

float box (vec3 p, vec3 c)
{
    return length(max(abs(p)-c,0.));
}

void moda(inout vec2 p, float rep)
{
    float a = atan(p.y,p.x);
    float per = 2.*PI/rep;
    float l = length(p);
    a = mod(a-per*0.5, per)-per*0.5;
    p = vec2(cos(a),sin(a))*l;
}

void mo (inout vec2 p, vec2 d)
{
    p = abs(p)-d;
    if (p.y>p.x) p = p.yx;
}

float tunnel (vec3 p)
{
    p.x += texture(iChannel0, p.yz*0.01).r*0.4;
    p.y += texture(iChannel0, p.xz*0.008).r*0.5;
    return -cyl(p, 5., 1e10);
}

float ribs (vec3 p)
{    
    float per = .5;
    p.z = mod(p.z-per*0.5, per)-per*0.5;
    p.y += p.x*p.x*0.6;
    return cyl(p.yzx, .2-abs(p.x)*0.2, 5.);
}

float g1 = 0.;
float skeleton (vec3 p)
{
    p.z += iTime;
    p.xy *= rot(p.z*0.1);
    mo(p.xy, vec2(1., 1.8));
    p.x -= 2.5;
    p.y += sin(p.z*0.6);
    p.x += cos(p.z)*0.2;
    p.xy *= rot(p.z*0.1);
    float spine = cyl(p, 0.25,1e10);
    float d =  min(spine, ribs(p));
    g1 += 0.1/(0.1+d*d);
    return d;
}

float g2 = 0.;
float flower(vec3 p)
{
    p.z -= 2.+iTime;
    p.xz *= rot(iTime);
    p.xz *= rot(p.y*0.5);
    mo(p.xy, vec2(0.5));
    mo(p.xz, vec2(1.));
    moda(p.xz, 3.);
    p.x -= 0.5;
    float d = box(p, vec3(.05-sin(p.y-.5),1.5,0.05));
    g2 += 0.1/(0.1+d*d);
    return d;
}

float SDF (vec3 p)
{
    return min(flower(p),min(tunnel(p), skeleton(p)));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = 2.*(fragCoord/iResolution.xy)-1.;
	uv.x *= iResolution.x/iResolution.y;
    float dither = texture(iChannel0, uv).r;
    
    vec3 ro = vec3(0.001,0.001, -3.+iTime); vec3 p = ro;
    vec3 rd = normalize(vec3(uv,1.));
    vec3 col = vec3(0.);
    
    float shad = 0.;
    
    for (float i=0.; i<64.; i++)
    {
        float d = SDF(p);
        if (d<0.01)
        {
            shad = i/64.;
            break;
        }
        d *= 0.6+dither*0.1;
        p+=d*rd;
    }
    
    col = vec3(shad);
    col += g1*vec3(0.08,0.12,0.08)*exp(-fract(iTime))*0.25;
    col += g2 * vec3(0.5,0.1,0.2)*0.2;

    // Output to screen
    fragColor = vec4(col,1.0);
}
