//commom===================common
const float e = 2.718281828459045;
const float pi = 3.14159265359;

vec3 rotate(vec3 v, vec2 cam_yp){
    float yaw = cam_yp.x;
    float pitch = cam_yp.y;
    
    v = vec3(v.x, v.z*sin(pitch) + v.y*cos(pitch), v.z*cos(pitch) - v.y*sin(pitch) );
    v = vec3(v.x*cos(yaw) + v.z*sin(yaw), v.y, -v.x*sin(yaw) + v.z*cos(yaw) );
    return v;
}

float hash11(float p)
{
    p = fract(p * .1031);
    p *= p + 33.33;
    p *= p + p;
    return fract(p);
}

float hash(vec2 seed){
    return hash11(seed.x + hash11(seed.y));
}

vec2 rot(vec2 i,float w){
    float a = hash(vec2(i))*2.*3.14159 + w;
    return vec2(cos(a),sin(a));
}

float noise(vec2 uv,float w){

    uv *= 5.;
    vec2 i = floor(uv);
    
    vec2 f = fract(uv);
    vec2 u = f * f * (3.0 - 2.0 * f);

    float dot_a = dot(rot( i + vec2(0.,0.),w) , f - vec2(0.,0.));
    float dot_b = dot(rot( i + vec2(1.,0.),w) , f - vec2(1.,0.));
    float dot_c = dot(rot( i + vec2(0.,1.),w) , f - vec2(0.,1.));
    float dot_d = dot(rot( i + vec2(1.,1.),w) , f - vec2(1.,1.));

    float mix_ = mix(mix(dot_a, dot_b, u.x), mix(dot_c, dot_d, u.x), u.y);
    mix_ = (mix_ +1.)/2.;

    return mix_;
}


float multi(vec2 uv, float w){
    float n = 0.;
    float scale = 0.5;
    const int iter = 10;
    for (int i = 0; i < iter; i++){
        n += noise(uv/scale,float(i)+w) * scale;
        scale /= 2.;
    }
    return n;
}

//wood=======================wood

float simple_w(vec2 p){
    p.y *= 5.;
    p = vec2(noise(p-20.,0.),noise(p,0.));
    p = vec2(noise(p-20.,0.),noise(p,0.));
    p = vec2(noise(p-20.,0.),noise(p,0.));
    float value = noise(p,0.);
    return value;
}

vec3 wood_normal(vec2 pos){
    float e = 0.0001;
    vec3 vec_1 = vec3(pos,simple_w(pos))-vec3( pos-vec2(e,0.),simple_w(pos-vec2(e,0.)) );
    vec3 vec_2 = vec3(pos,simple_w(pos))-vec3( pos-vec2(0.,e),simple_w(pos-vec2(0.,e)) );
    vec_1=normalize(vec_1);
    vec_2=normalize(vec_2);
    vec3 n = cross(vec_1,vec_2);
    return normalize(n);  
}

vec3 wood(vec2 p,vec3 li){
    vec2 p0 = p;

    p.y *= 5.;
    p = vec2(noise(p-20.,0.),noise(p,0.));
    p = vec2(noise(p-20.,0.),noise(p,0.));
    p = vec2(noise(p-20.,0.),noise(p,0.));


    float value = noise(p,0.);
    
    vec3 W_C_1 = vec3(0.49, 0.325, 0.106);
    vec3 W_C_2 = vec3(0.678, 0.518, 0.302);
    vec3 col = mix(W_C_1,W_C_2,value)*0.8;
    
    vec3 n = wood_normal(p0);
    float albedo = dot(n,li);
    albedo = albedo/2.+0.5;
    
    col *= mix(1.,albedo,0.05);
    
    return col;

}



//tape=======================tape
float tape(vec2 uv, vec2 pos, float rot, float w){
 
    uv -= pos;
    uv = vec2(uv.x*sin(rot) + uv.y*cos(rot), uv.x*cos(rot) - uv.y*sin(rot) );

    vec2 uv0 = uv;
    
    float NS = 5.;
    uv = mix( vec2(noise(uv*NS-20.,w)-0.5,noise(uv*NS,w)-0.5),uv , 0.99 );
    
    float TS = 0.015; 
    uv.y += abs(mod(uv.x-TS/2.,TS)-TS/2.);

    float size = 0.035;
    float width_scale = 0.3;
    float sq_sdf = max(abs(uv.x),abs(uv.y*width_scale));
    
    float mask = 0.;
    
    if(sq_sdf < size){mask = 1.;}
    
    mask *= noise(uv0*3.,0.);
    
    return mask;
}


//sky=======================sky

float Preetham(vec3 dr, vec3 sunDir){
    float T = 1.9;

    float A =  0.1787*T - 1.4630;
    float B = -0.3554*T + 0.4275;
    float C = -0.0227*T + 5.3251;
    float D =  0.1206*T - 2.5771;
    float E = -0.0670*T + 0.3703;

    float theta = acos(clamp(dr.y, -1.0, 1.0));
    float gamma = acos(clamp(dot(dr, sunDir), -1.0, 1.0));

    float term1 = 1.0 + A * exp(B / max(0.1, cos(theta)));
    float term2 = 1.0 + C * exp(D * gamma) + E * pow(cos(gamma),2.0);

    return term1 * term2;
}

vec3 Sky(vec3 dr, vec3 sunDir){
    float sky = Preetham(dr,sunDir);
    
    vec3 col = mix(vec3(0.004, 0.048, 0.253),
               vec3(0.8, 0.9, 1.0),
               sky); 
   
    float height_dr = (dr.y+1.)/2.;
    float height_sunDirr = (sunDir.y+1.)/2.;
           
    
    col = mix(vec3(1.0,0.85,0.53)/4.,col * 1.2,height_dr) * height_sunDirr;
    col = (col-0.5)*1.2+0.5;
    float light_size = 0.10;
    float sun_disk = max( (dot(dr, sunDir) - 1.)/(1. - cos(light_size)) + 1., 0.0);
    sun_disk *= pow(height_dr,10.);
               
    return col/2. + sun_disk*10.;
}





//main=======================main

float cube(vec3 p,vec3 size, vec2 rot){
    p = rotate(p,rot/180. * pi);
    vec3 d = abs(p) - size;
    vec3 md = min(d, vec3(0));

    return length(max(d, vec3(0))) + max(max(md.x, md.y), md.z);
}

float PC(vec3 p){
    float c1 = cube(p,vec3(0.5,0.55,0.5),vec2(0.,6.));
    float c2 = cube(p-vec3(0.,-0.1,0.),vec3(0.5,0.55,0.45),vec2(0.,0.0));
    float c3 = cube(p-vec3(0.,-0.52,-0.55),vec3(2.,0.04,0.08),vec2(0.,50));
    float sdf = min(c1,c2);
    sdf = max(sdf,-c3)-0.01;
    
    return sdf;
}

float de1( vec3 p0 ){
	vec4 p = vec4(p0, 1.);
	float sdf = 0.;
    float col = 0.;
	for(int i = 0; i < 10; i++){
    

        float x = 2.;
        float y = 2.;
        float z = 2.;

        float c1 = floor(p.y/y+y/4.)*sin(iTime/10.);
        p.x += c1;
        
        p.x = mod(p.x-x/2.,x)-x/2.;
        p.y = mod(p.y-y/2.,y)-y/2.;
        p.z = mod(p.z-z/2.,z)-z/2.;
        
        
		p*=(1.333333)/dot(p.xyz,p.xyz);

		sdf = (length(p.xyz/p.w)*0.25);
        col += sdf;
	}
    return sdf;
}

float dunes_f(vec3 p){
    vec3 p0 = p;

    float dunes = p.y + noise(p.xz/10.,0.)-0.6; 
    dunes -= noise(p.xz/2.,0.)/50.;

    return dunes;
}

vec2 Map(vec3 p){
    float sdf;
    float id = 0.;
    
    vec3 frac_p = vec3(0.1,0.,1.); 
    
    sdf = max(de1(p/10.)*10.,length(p)-25.);
    
    float dunes = dunes_f(p);
    if (sdf>dunes){id=1.;}
    sdf = min(sdf,dunes);
    
    return vec2(sdf,id);
}

//Ray marching
vec3 Ray(vec3 dr, vec3 rp, float min_dis, int iter){
    float min_ = min_dis;
    float max_ = 0.01;

    vec3 cam_pos = rp;

    for (int i = 0; i < iter; i++){
        float o = Map(rp).x;
        rp += dr * o;
        
        float dis = dot(rp-cam_pos,rp-cam_pos);
        
        float lod = mix(min_,max_,dis/500.);
        
        if (o < lod) break;
        if (o > 100.) break;
    }
    return rp;
}

//Normal calculation
vec3 Normal(vec3 pos){
    float e = 0.00005;
    vec3 n = 
    vec3( Map(pos+vec3(e, 0.0, 0.0) ).x - Map(pos-vec3(e, 0.0, 0.0) ).x,
          Map(pos+vec3(0.0, e, 0.0) ).x - Map(pos-vec3(0.0, e, 0.0) ).x,
          Map(pos+vec3(0.0, 0.0, e) ).x - Map(pos-vec3(0.0, 0.0, e) ).x );
    return normalize(n);          
}


vec3 sun_lamp(vec3 n, vec3 rp, vec3 li){
    rp += n*0.01;
    vec3 dr = li;
    

    vec3 new_rp = Ray(dr, rp, 0.003, 40);
    


    float final_light;

    float value = dot(n,dr);

    if (length(new_rp - rp)>99.){
        final_light = clamp( value ,0.,1.);
    }else{
        final_light = 0.;
    }
   
    //ambient oclusion
    float sample_length = 0.05;
    vec3 test_point = rp + n*sample_length;
    float oc = Map(test_point).x/sample_length;
    oc = clamp(oc,0.,1.);
    oc *= 1.-clamp(-value,0.,1.);
    oc/=10.;


    vec3 final_col = mix(vec3(oc),vec3(1.),final_light);

    final_col = final_col * vec3(1.);



    return final_col;
}


vec3 Render_C(vec2 xy, vec3 rp,vec2 cam_yp){

    vec3 li = normalize(vec3(1.,1.,0.6));

    vec3 cam_dr = rotate( normalize(vec3(xy, 1.0)), cam_yp ) ;
    vec3 cam_pos = rp;
    
    
    //------Ray-----
    vec3 dr = cam_dr;
    rp = Ray(dr, rp, 0.0008, 150);
    
    vec3 n = Normal(rp);
    
    vec3 sun = sun_lamp(n,rp, li );
    //-----------------
    
    
    
    //------Color-----
    int ID = int(Map(rp).y);
    
    vec3 obj_col = vec3(0.5);
    
    vec3 dune_col1 = vec3(1, 0.627, 0.337);
    vec3 dune_col2 = vec3(0.71, 0.412, 0.184);
    vec3 dune_col = mix(dune_col1,dune_col2,noise(rp.xz/2.,0.));
    
    obj_col = mix(obj_col,dune_col,max(dot(n,vec3(0.,1.,0.)),0.) );  
    
    if (ID == 1){obj_col = dune_col;}
    //-----------------
    
    
    
    //------effects-----
    vec3 col = sun*obj_col;
    
    float depth = length(rp-cam_pos);
    if (depth>99.){col = Sky(cam_dr,li);}
    
    float fog = exp(-depth*0.08)* noise(xy/2. + depth*0.3 ,0.);
    vec3 fog_col = vec3(0.831, 0.675, 0.439);
    
    
    col = mix(col, (mix(fog_col,col,fog)) ,0.25 );
    
    float dust = 0.;
    float step_length = 1.;
    vec3 step_pos = cam_pos;
    for (int i = 0; i < 5; i++){
        step_pos += cam_dr*step_length;
        float full_length = float(i)*step_length+1.;
        
        vec2 step_uv = xy+cam_yp/3.*full_length;
        
        float noise_ = multi(step_uv*full_length,iTime*5.) * noise(step_uv,iTime*1.);
        
        if(full_length<depth){
            float mask = Map(step_pos).x;
            mask = clamp(0.3-mask,0.,1.);
            dust += noise_ * mask * 3.;
        }  
    }
    vec3 dust_col = vec3(0.949, 0.663, 0.404);
    col = mix(col, mix(col,dust_col,clamp(dust,0.,1.)) ,1. );
 
    //-----------------
    
    return col;

}


vec3 Render_P(vec2 uv){
    //Camera rotation
    vec2 cam_yp = vec2(-0.9,0.2);
    
    float scale = 0.3;
    cam_yp += vec2(sin(iTime*2.)/20.,cos(iTime)/20.)*scale;
    cam_yp += vec2(sin(iTime*3.)/30.,cos(iTime*2.)/30.)*scale;
    cam_yp += vec2(sin(iTime*6.)/100.,cos(iTime*10.)/100.)*scale;
    
    vec3 cam_pos = vec3(10.,0.15,1.8);
    //vec2 cam_yp = vec2(float(iMouse.x)/100.+0.5 ,float(iMouse.y)/100.0)-0.4;
    //vec3 cam_pos = rotate(vec3(0.,0.,-1.), cam_yp) * 2.;
    
    //Rendering
    vec3 col;
    col = Render_C(uv, cam_pos,cam_yp);
    
    col = mix( pow( col, vec3(1.0/2.2)), col,0.5);

    return col;
}


vec3 Render_F(vec2 uv){
    vec3 col = vec3(0.);
    
    
    float h_scale = 1.6;
    float scale = 0.5;
    
    float frame_scale = 0.01;
    
    vec3 li = vec3(1.,1.,1.);
    
    float sq_sdf = max(abs(uv.x),abs(uv.y*h_scale));
    
    if (sq_sdf < scale){
        col = Render_P(uv/scale);
    }else{
    
        col = wood(uv,li);
        
        col *= clamp(sq_sdf*2.75 - scale,0.,1.);
        
        if (max(abs(uv.x),abs(uv.y*h_scale)-frame_scale/2.) < scale+frame_scale){
            col = vec3(1.)*clamp(multi(uv,2.)+0.4,0.,1.);
        }
    }

    float tape1 = tape(uv,vec2(0.5,0.29),1.,0.);
    float tape2 = tape(uv,vec2(-0.5,-0.29),0.8,20.);

    vec3 tape_col = mix(col,vec3(1.),0.7);
    col = mix(col,tape_col,  tape1);
    col = mix(col,tape_col,  tape2);

    return col;
}


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

    //xy to uv  
    vec2 uv_o = fragCoord/iResolution.xy;
    vec2 uv = vec2((uv_o.x - 0.5)*(iResolution.x / iResolution.y ), uv_o.y -0.5);
    
    
    vec3 col = Render_F(uv);

    
    fragColor = vec4(col,1.);
}