#define iChannel0 inputImageTexture
#define texture(a,b) texture2D(a,fract(b))
#define fragColor gl_FragColor
precision highp float;

varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;

uniform highp float iTime;

uniform highp vec2 iResolution;


float MAXD=1000.0;
int rm_Iterations =100;
float perspective=1.25;
float zoom=1.2;
highp vec3 cameraLocation=vec3(0.0, -12.5, -24.6);
highp vec3 light=vec3(-0.1,-0.1, -1.);
float rotX=1.5;
float dist=.95;
highp vec3 center=vec3(0.0,0.0,0.0);
highp vec3 shift=vec3(64./2.,0.,36./1.5);

highp vec3 rotateX( const in highp vec3 p, const in float angle ){
    float s = sin(angle);
    float c = cos(angle);
    return vec3( p.x, c * p.y + s * p.z, -s * p.y + c * p.z);
}

float map( highp vec3 p ){
    p=rotateX(p,rotX);//a little tilted for mo' 3d effect
    p +=shift;
    if (p.x>-0.5 && p.x<64. && p.z>0. && p.z<48.){
        highp vec4 tex=texture(iChannel0,p.xz/vec2(64.0,48.0).xy);

        float tl=max(.3,tex.r*1.5);//small size vs. big size
        float div=2.;
        p.x = mod( p.x + dist/div, dist ) - dist/div;
        //float dist2=2.75;
        //p.y = (mod( p.y + dist2/div, dist2 ) - dist2/div)-1.5;
        p.z = mod( p.z + dist/div, dist ) - dist/div;

        return length( center - p ) - tl;
    }
    else return 1.0;
}


highp vec3 calc_normal(highp vec3 v){
    float e=0.0001;
    highp vec3 n=vec3(
    map(vec3(v.x+e,v.y,v.z))-map(vec3(v.x-e,v.y,v.z)),
    map(vec3(v.x,v.y+e,v.z))-map(vec3(v.x,v.y-e,v.z)),
    map(vec3(v.x,v.y,v.z+e))-map(vec3(v.x,v.y,v.z-e)));
    return normalize(n);
}

float ao(highp vec3 p, highp vec3 n, float d){
    float o=1.0;
    float ii=5.0;
    for(int i=0;i<5;i++){
        highp vec3 tmpV=p+n*(ii*d);
        float tmp=map(tmpV);
        if(tmp<0.0) tmp=0.0;
        o-=(ii*d-tmp)/pow(2.0,ii);
        ii=ii-1.0;
    }
    return o;
}

void main() {
    highp vec2 uv = textureCoordinate;
    float x = 0.0;
    float y = 0.0;
    float off = 0.0;
    highp vec4 col;
    float rx;
    float ry;
    float d;
    int steps = 0;
    highp vec3 ray;
    highp vec3 direction;

    highp vec2 p = 2.0 * uv * vec2(1.0,iResolution.y / iResolution.x);
    p-=1.0;
    p.y=-p.y;
    p=p/zoom;
    ray=vec3(p.x,p.y,0);
    ray=ray+cameraLocation;
    direction=vec3(p.x*perspective,p.y*perspective,1.0);
    direction=normalize(direction);
    col=vec4(0.25+(p.y+0.5)/3.0,0.25+(p.y+0.5)/3.0,0.33+(p.y+0.5)/3.0,1.0);

    for(int i=0;i<100;i++){
        d=map(ray);
        if(d>=MAXD){
            // Infinite distance
            break;
        }
        if(d<0.00001){
            highp vec3 n=calc_normal(ray);
            //float normlight=0.25*dot(light,n);
            float normlight=0.25*max(0.,dot(light,n));//thx @ las
            float aolight=ao(ray,n,0.25);//float aolight=ao(ray,n,0.25);
            if(normlight<0.0) normlight=0.0;
            float ambient=0.75;
            float c=(normlight+ambient)*aolight;
            col=vec4(c,c,c,1.0);
            highp vec3 p2=rotateX(ray,rotX);
            p2 +=shift;
            highp vec4 tex=texture(iChannel0,p2.xz/vec2(64.0,48.0).xy);
            col *=tex /(1.+map(ray));//col +=vec3(1.,0.1,0.1) /(1.+map(ray));//thanks @ XT95
            break;
        }
        ray+=direction*d;
    }

    fragColor = col;
}