float MIN_DIST = 0.001;
float MAX_DIST = 1.0;
int MAX_ITER = 64;
float IOR = 1.25;
float ABB = 0.025;
float DENSITY = .05;

#define pi 3.1415926535
#define rot(a) mat2(cos(a),sin(a),-sin(a),cos(a))
#define sat(a) clamp(a,0.0,1.0)
#define h13(n) fract((n)*vec3(12.9898,78.233,45.6114)*43758.5453123)

vec2 vor(vec2 v, vec3 p, vec3 s){
    p = abs(fract(p-s)-0.5);
    float a = max(p.x,max(p.y,p.z));
    float b = min(v.x,a);
    float c = max(v.x,min(v.y,a));
    return vec2(b,c);
}

float vorMap(vec3 p){
    vec2 v = vec2(5.0);
    v = vor(v,p,h13(0.96));
    p.xy*=rot(1.2);
    v = vor(v,p,h13(0.55));
    p.yz*=rot(2.);
    v = vor(v,p,h13(0.718));
    p.zx*=rot(2.7);
    v = vor(v,p,h13(0.3));
    return v.y-v.x;
}

float sd_box(vec3 p){
    p=abs(p)-.2;
    return length(max(p,0.)) + min(max(p.x,max(p.y,p.z)),0.);
}

vec3 cameraDir(vec2 uv, float ratio, vec3 p, vec3 dir){
    uv -= .5;
    uv.x *= ratio;
    vec3 r = cross(vec3(0., 1., 0.), dir);
    vec3 u = cross(dir, r);
    float zoom = 1.;
    vec3 c = p + dir * zoom;
    vec3 i = c+uv.x*r + uv.y*u;
    vec3 rd = i - p;
    return rd;
}

float map(in vec3 p)
{
    //GEM
    float cracks = -vorMap(p*3.)-0.05;
    float gem = length(p)-.25;
    float cracked_gem = mix(gem,cracks,.05);

    return cracked_gem;
}

float raymarch(vec3 ro, vec3 rd, float s, out int i)
{
    float t = .0;

    for(i = 0; i < MAX_ITER; i++){
        vec3 pos = ro + t*rd;
        float d = map(pos)*s;
        if(abs(d) < MIN_DIST)
            break;
        t += d;
        if(t > MAX_DIST) break;
    }

    if(t > MAX_DIST)
        t = -1.;
    return t;
}

vec3 calcNormal(in vec3 pos)
{
    vec2 e = vec2(MIN_DIST, 0.);
    float d = map(pos);
    return normalize(d - vec3(map(pos-e.xyy),
                          map(pos-e.yxy),
                          map(pos-e.yyx)));
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    float t = iTime;
    vec2 uv = fragCoord.xy/iResolution.xy;
    float ratio = iResolution.x/iResolution.y;
    vec3 ro = vec3(.8*sin(t*.2), .01*cos(t*0.25), -.8*cos(t*.2));
    vec3 f = normalize(-ro);
    vec3 truePos = ro + f*(sin(t*15.)+1.0);
    vec3 rd = cameraDir(uv, ratio, truePos, f);

    vec3 col = vec3(0.0);
    int steps;
    float d = raymarch(ro,rd, 1., steps);

    if(d > 0.)
    {
        int internal_steps;
        vec3 p = ro + rd*d;
        vec3 n = calcNormal(p);
        float fresnel = pow(1.+dot(rd,n), 5.);
        vec3 refl = reflect(rd,n);
        vec3 reflTex = texture(iChannel0, refl).rgb;
        rd = refract(rd,n,1./IOR);
        p += -n * MIN_DIST * 3.;
        d = raymarch(p,rd,-1., internal_steps);
        p += rd*d;
        n = -calcNormal(p);
        vec3 _rd = rd;

        //red
        vec3 refr= refract(_rd,n, IOR-ABB);
        if(dot(refr,refr) == 0.)
            rd = reflect(_rd,n);
        else
            rd = refr;
        col.r = texture(iChannel0, rd).r;
        //green
        refr= refract(_rd,n,IOR);
        if(dot(refr,refr) == 0.)
            rd = reflect(_rd,n);
        else
            rd = refr;

        col.g = texture(iChannel0, rd+ABB).g;

        //blue
        refr= refract(_rd,n,IOR);
        if(dot(refr,refr) == 0.)
            rd = reflect(_rd,n);
        else
            rd = refr;
        col.b = texture(iChannel0, rd).b;

        float optDist = exp(DENSITY * -d);

        col*=optDist;
        col+= reflTex * (1.-fresnel);
        col+= float(internal_steps)/200.*(1.-fresnel);
    }
    else col = texture(iChannel0, rd).rgb;
    col += float(steps)/200.;
    fragColor = vec4(col, 1.0);
}
