#define PI 3.1415926
#define T( s ) fract( iTime * s ) * PI * 4.


mat2 rotation(float a) {
    float s = sin(a), c = cos(a);
    return mat2(c, s, -s, c);
}

float map(vec3 pos)
{
    float t = iTime;
    
    float d = 5.;
    
    pos.xy *= -1.;
    
    pos.yz *= rotation(  -PI * .2 - sin( T( .05 ) ) * -.2 + .3 );
    
    pos.xz *= rotation( cos( T( .05 ) ) * .2 );

    pos.y += cos( pos.x ) * .15;
    pos.y += cos( pos.y ) * .15;
    
    d = length( pos ) - 2.5;

    float r = length(pos.xy) * 1.;
    float a = atan(pos.y, pos.x);
    
    float b = cos( (a-cos( r + T( .05 ) )*15.0)*1.0 - T( .05 ) ) * .7 + .2;

    d += b * .15;
    
    return d;
}

// https://iquilezles.org/articles/normalsSDF
vec3 calcNormal( in vec3 pos) {
    vec2 e = vec2(1.0, -1.0) * 0.5773;
    const float eps = 0.0005;
    return normalize(e.xyy * map(pos + e.xyy * eps) +
        e.yyx * map(pos + e.yyx * eps) +
        e.yxy * map(pos + e.yxy * eps) +
        e.xxx * map(pos + e.xxx * eps));
}

vec3 raymarching( vec3 ro, vec3 rd ){
    
    float t = 0.,
          dist = 0.;
          
    vec3 lig = normalize(vec3(.57703));
    lig.xz *= rotation( T( .05 ) );
    vec3 hal = normalize(lig - rd);
    vec3 bg = vec3( 0.7 + 0.3*cos( T(.2) +rd+vec3(0,2,4)) );
    
    vec3 pos = vec3( 0. );
    
    for( int i = 0; i < 32; i++ ){
        
        pos = ro + rd * t;
        dist = map( pos );
        
        if( t > 1e3 ){
            break ;
        }
        
        t += dist * .666667;
    }
    
    
    if( dist < 1. ){
    
        vec3 nor = calcNormal(pos);

        float dif = clamp(dot(nor, vec3(.4, 1., -.5)), 0.0, 1.0);

        float spe = pow(clamp(dot(nor, hal), 0.0, 1.0), 50.0) * .6;
        spe *= dif;

        float amb = dot(nor, vec3(0.0, 1.0, 0.0));

        return spe + .1 * dif + 0.3 * sin( T( .1 ) + nor.xyz + vec3(0,2,4) + t * .1 ) * dif + texture( iChannel0, nor ).rgb * 1.1 * dif;
    }
    
    bg = sqrt( bg );
    bg *= .3;
    
    return bg;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;
    
    uv = (uv - .5) * 2.;

    uv.x *= iResolution.x / iResolution.y;

    // Time varying pixel color
    
    vec3 ro = vec3( 0., 0., -4. );
    vec3 rd = vec3( uv, 1. );
    
    vec3 col = raymarching( ro, rd );

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