#define rot(a) mat2(cos(a), sin(a), -sin(a), cos(a))

#define cubes 100

vec3 get_ro(void)
{
    return vec3(0.5+sin(iTime*0.02)*30.0,sin(iTime*0.24)*10.0-4.0,iTime);
}

float get_height(vec2 p)
{
    float s = sin(p.x)*2.0;
    float c = cos(p.y+iTime)*sin(iTime)*3.5;
    
    float h = s+c;
    
    vec3 ro = get_ro();
    
    vec2 p2 = p-ro.xz;
    
    float l = clamp(length(p2)*0.2-0.2, 0.0, 1.0);
    
    return mix(min(h,ro.y-2.0), h, l);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = (fragCoord.xy*2.0-iResolution.xy)/iResolution.y;
    vec4 muv = (iMouse.xyzw*2.0-iResolution.xyxy)/iResolution.y;
    
    vec3 ro = get_ro();
    vec3 rd = normalize(vec3(uv, 1.0));
    
    rd.zy *= rot(-muv.y);
    rd.xz *= rot(muv.x);
    
    vec3 ird = 1.0/rd;
    vec3 srd = sign(ird);
    vec2 fro = floor(ro.xz);
    vec2 lro = ro.xz-fro;
    
    vec2 dists = (step(0.0,ird.xz)-lro)*ird.xz;
    
    float oldl = 0.0;
    
    float height = 0.0;
    
    vec3 normal = vec3(0);
    
    int i;
    for (i = 0; i < cubes; i++)
    {
        vec2 mask = vec2(1, 0);
        if (dists.y < dists.x)
            mask = vec2(0, 1);
        
        float l = dot(dists, mask);
        
        vec3 p = ro+rd*oldl;
        
        height = get_height(fro);
    
        float hit1 = ird.y*(height-ro.y-0.5*srd.y);
        
        if ((hit1 > oldl && hit1 < l) || abs(p.y-height) < 0.5) break;
        
        fro += mask*srd.xz;
        dists += mask*ird.xz*srd.xz;
        
        oldl = l;
        normal.xz = mask;
    }
    
    float hit1 = ird.y*(height-ro.y-0.5*srd.y);
    
    if (hit1 < oldl)
    {
        normal *= -srd;
    }
    else
    {
        normal = vec3(0,-srd.y,0);
    }
    
    float d = max(hit1,oldl);
    
    vec3 p = ro+rd*d;
    
    // Time varying pixel color
    
    float sun1 = dot(normal, normalize(vec3(1.0, 0.5, 0.8)));
    float sun2 = dot(normal, normalize(vec3(-1.4, -0.7, -0.8)));
    
    vec3 suncol1 = sun1*vec3(0.8,1.0,0.7);
    vec3 suncol2 = sun2*vec3(0.5,0.3,0.2);
    
    vec3 col = max(suncol1, suncol2);
    
    vec3 heightcol = vec3(max(0.0, -height), max(0.0, height), 1.0);
    
    col *= heightcol;

    // Output to screen
    if (i < cubes)
        fragColor = vec4(col,1.0);
    else
    {
        fragColor = vec4(normalize(rd)*0.5+0.5,1.0);
    }
}
