#define time iTime

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

float sdBoxFrame( vec3 p, vec3 b, float e )
{
  p = abs(p  )-b;
  vec3 q = abs(p+e)-e;
  return min(min(
      length(max(vec3(p.x,q.y,q.z),0.0))+min(max(p.x,max(q.y,q.z)),0.0),
      length(max(vec3(q.x,p.y,q.z),0.0))+min(max(q.x,max(p.y,q.z)),0.0)),
      length(max(vec3(q.x,q.y,p.z),0.0))+min(max(q.x,max(q.y,p.z)),0.0));
}

// All components are in the range [0…1], including hue.
vec3 rgb2hsv(vec3 c)
{
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
 

// All components are in the range [0…1], including hue.
vec3 hsv2rgb(vec3 c)
{
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

vec4 map(vec3 p) {
    
    p.z -= 5.;
    //p.z += time*20.; 
    //p.xy -= (sin(time)*3);
    //p.yz *= r2d(-02);
    vec3 o = p;
    float d = 1000.;
    p = o;
    float lxz = (length(p.xz));
    //vec2 pc = p.xz;
    vec2 pc = vec2(log(lxz),atan(p.x,p.z));
    //p.y += (sin(pc.x*10.-time*30)+sin(pc.y*1.+lxz+time*10.)*3)*0.01*lxz;
    //pc.y += time*0.01;
    //pc = vec2(log(length(pc)),atan(pc.x,pc.y));
    
    float ns = 1.;
    //pc.y *= 3./3.141;
    //pc.y = (fract(pc.y-0.5));
    //pc.y *= 2./3.141;
    
    pc.x -= time*0.3;


    vec3 bp = p;
    float fy = 0.;
    float bps = 0.6;
    vec2 fpc = pc;
    //fpc.y *= .;
    //fpc.x *= 16./3.14159; 
    fpc = floor(fpc/bps)*bps;
   
    //fpc.y = floor(fpc.y/bps)*bps;
    //fpc.y += sin(time);
    for (int i=0;i<4;i++) {
        ns += 1.0;
        //p.y += (sin(pc.x*10*ns*0.1*pc.y*0.00)*0.4)*lxz*0.1;
        p.y += (sin(pc.y*6.*ns*0.5+pc.x*sin(ns*0.5)*10.)*0.04)*lxz;
        p.y += (sin(pc.y*2.*ns*0.5+pc.x*sin(ns*20.)*20.)*0.04)*lxz;
        fy += (sin(fpc.y*6.*ns*0.5+fpc.x*sin(ns*0.5)*10.)*0.04)*lxz;
        fy += (sin(fpc.y*2.*ns*0.5+fpc.x*sin(ns*20.)*20.)*0.04)*lxz;
        //p.y += (sin(pc.x*sin(ns)*20.03)+sin(pc.y*sin(ns)*40.+pc.x*0.1))*0.01*lxz;
        //p.y += (sin(pc.x*ns-time*3*ns+pc.y)+sin(pc.y*ns+pc.x))*0.04*lxz;
        
    }
    bp.zx = pc;
    //bp.z *= 1;
    bp.y += 1.; 
    bp.x /= 1./bps;
    bp.x *= 8./3.14159;
    bp.x += sin(bp.z*.1)*5.;
    bp.xz = (fract(bp.xz/bps)-0.5)*bps;
    //bp.y /= lxz;
    //bp.y += -0.05;
    
    bp.y += (fy*sin(log(lxz)*2.+time));
    bp.y -= 0.2;
    bp.y /= lxz;
    bp.xz *= r2d(pc.y*0.1);
    bp.xy *= r2d(pc.y*0.4);
    //bp.y *= 0.3;
    float db = sdBoxFrame(bp,vec3(0.03),0.004)*(lxz+0.1)*0.5;
    //db *= lxz;
    //db *= 0.99;
    //db -= 0.001;
    //d = min(d,//);
    //pc.y *= 3./3.141;
    //pc.y = (fract(pc.y-0.5));
    //pc.y += 1./3.14;
    
    //pc.y *= 10./3.14;
    //p.y += sin(pc.y*10.+pc.x*20.+time*4.)*0.2;
    //p.y += lxz;
    if (p.y+1. > db) {
        pc.y -= 2.;
    }
    d = db-0.;
    d = min(d,length(p.y+1.)*0.3);
    //d += 0.01;
    //float d = length(p)-1.;
    return vec4(pc.x,lxz,pc.y,d);
}

vec2 RM(vec3 ro, vec3 rd) {
    float dO = 0.;
    float ii = 0.;
    for (int i=0;i<64;i++) {
        vec3 p = ro+rd*dO;
        float dS = map(p).w;
        dO += dS;
        ii += 0.02;
        if (dO > 24.2 || dS < 0.0005) {break;}
    }
    return vec2(dO,ii);
}


vec3 calcNormal( in vec3 p ) // for function f(p)
{
    const float eps = 0.00003; // or some other value
    const vec2 h = vec2(eps,0.);
    return normalize( vec3(map(p+h.xyy).w - map(p-h.xyy).w,
                           map(p+h.yxy).w - map(p-h.yxy).w,
                           map(p+h.yyx).w - map(p-h.yyx).w ) );
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = -1. + 2. * (fragCoord/iResolution.xy);
    //vec2 uv = -1. + 2. * inData.v_texcoord;
    vec2 R = iResolution.xy;
    float ar = R.x/R.y;
    uv.x*=ar;
    float c = length(uv);
    //uv.y -= 0.3;
    vec3 col = vec3(0.);
    vec3 ro = vec3(0.,0.,2.);
    vec3 rd = normalize(vec3(uv,.75+c*0.75));
    vec2 ra = vec2(cos(time),sin(time))*0.3;

    //ro.z += sin(uv.x*4.*uv.y+time*2.)-c*2.;
    //ro.z *= 0.2;
    //ra.z += sin(time+sin(uv.x));
    //ra.x += floor(sin((uv.x*1.)*150.*(sin(uv.x*0.01+time*0.1)*0.5+0.5)))*0.1;
    //ra.y += floor(sin((uv.y*1.)*150.*(sin(uv.y*0.01+time*0.08)*0.5+0.5)))*0.1;
    //ra.x += sin(uv.y*1.+time)*0.2;
    //ro.xz *= r2d(ra.x);
    //rd.xz *= r2d(ra.x);
    //ro.yz *= r2d(ra.y);
    rd.yz *= r2d(-.25);
    vec2 d = RM(ro,rd);
    vec3 p = ro+rd*d.x;
    
    vec3 mp = map(p).xyz;
    //p.xy *= r2d(time);
    vec3 norm = calcNormal(p);
    p.z -= 5.;
    float lz = length(p.xz);
    
    //col = 1.-d.xxx*.1;
    col = hsv2rgb(vec3(floor(mp.z/3.14/2.*5.+mp.x*0.4)/5.,floor(sin(mp.x*10.1+mp.z*2.)*2.)/2.,(1.15-d.x*0.2)));
    
    //col = hsv2rgb(vec3(floor(mp.z/3.14/2*5.+mp.x*0.4)/5.,floor(sin(mp.x*10.1+mp.z*2.)*2.)/2,clamp(1.-d.x*0.1,0.,1.)));
    col += (clamp(sin(mp.z*30.)+sin(mp.x*90.),-0.,0.1)*5.-0.5)+d.y*0.08;
    norm.xz *= r2d(mp.x*0.2);
    col += (norm.x*2.)*0.4;
    //col.rg += (d.y*0.05-0.5);
    fragColor = vec4(col,1.);
    // Output to screen
    fragColor = vec4(col,1.0);
}
