//vec2 V;
//#define rot(a) mat2( V= sin(vec2(1.57, 0) + a), -V.y, V.x)
#define rot(a) mat2( sin ( a+1.57*vec4(1,0,2,1) ) );

vec3 getNormal(vec3 p) {
    vec3 sub = (fract(p)-.5)*2.;
    sub= abs(sub);
    float y = min(step(0.,sub.y-sub.z),step(0.,sub.y-sub.x));
    float x = min(1.-y,step(0.,sub.x-sub.z));
    float z = min(1.-y,1.-x);
    return vec3(x,y,z)*sign((fract(p)-.5)*2.); //fixed for backfaces
}

float dist(vec3 p,vec3 dir) {
    if(p.y>6.5) return p.y-6.5; //bail!
    vec3 f = fract(p);
    vec3 d = step(0.,dir); //backface
    float d1 = dot( (d-f), vec3(0,1,0))/dot(dir,vec3(0,1,0));
    float d2 = dot( (d-f), vec3(1,0,0))/dot(dir,vec3(1,0,0));
    float d3 = dot( (d-f), vec3(0,0,-1))/dot(dir,vec3(0,0,-1));
    return abs(min(d1,min(d2,d3))) ;
}

float getPillars(vec3 block, inout vec3 col) {
    float cy = 1.-step(texture(iChannel0,block.xz/256.).r*12.,block.y+6.);
    col = mix(col,vec3(.5,.5,.5),cy);
    return cy;
}

float getVoxel(vec3 p,out vec3 col) {
    vec3 block = trunc(p);
    float fl = 1.-step(texture(iChannel0,block.xz/512.).r*6.,block.y); //works with Textures!
    col = mix(vec3(0.6,0.5,0.3),vec3(0.4,0.6,0.2),step(4.,block.y));
    return max(fl,getPillars(block,col));
}

//now with shadows!
float shadow(vec3 pos, vec3 l) {
    vec3 col = vec3(0.1);
 	int maxsteps = 25;
    vec3 p = pos;
    float d = .01;
    for(int steps = 0; steps<maxsteps;steps++) {
        p = (pos+l*d);
        float v = getVoxel(p,col);
        if(v>.9) {
            return 1.0;
        }
        d+= max(0.0001,dist(p,l));
    }
    return 0.0;
}



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

    vec3 dir = normalize(vec3(1.,-.5,1.));
	dir.xz*=rot(sin(iTime*.025)*3.14);
    vec3 ndx = cross(dir,vec3(0.,-1.,0.));
    vec3 ndy = cross(dir,ndx);

    vec3 o = ndx*(uv.x*30.)+ndy*(uv.y*30.+3.)+dir*(0.);
    o+=vec3(20.,5.,150.); //bias - things get glitchy in negative space
    o+=vec3(iTime*4.,sin(iTime*0.2),sin(iTime*.2)*5.);

    //raymarch!
    vec3 col = vec3(0.1);
    float steplength = .01;
    float steps = 0.; float maxsteps = 100.;
    vec3 p = o;
    float d = steplength;
    for(steps = 0.; steps<maxsteps;steps+=1.) {
        p = (o+dir*d);
        float v = getVoxel(p,col);
        if(v>.9) {
            break;
        }
        steplength = max(0.0001,dist(p,dir));
        d+=steplength;
    }

    vec3 light = vec3(.8,1.,0.5);
    light.xz*=rot(iTime*0.2);

    //shading
    float shad = shadow(p,light);
    float shading = dot(getNormal(p),light);
    col =col*shading*(1.-shad)+col*shading*.5*shad;

    //fake water
    float depth = (1.-smoothstep(0.,4.,p.y));
    col*=(1.-depth);
    col += vec3(0.,.5,1.)*(1.-step(2.7,p.y+sin(p.x*2.-iTime*3.)*0.1+cos(p.z*3.-iTime*2.)*0.1))*depth;
    col*=0.6+(1.-depth)*0.4;

    //col *=vec3(1.-(steps/maxsteps));
    fragColor = vec4(col,1.0);
}
