/**
    Quadtree Octahedrons
    @byt3_m3chanic | 08/09/21

    I dont know how to break space down and do the
    quad tree thing - so doing some brute force
    attempts.

*/


#define R iResolution
#define M iMouse
#define T iTime

#define PI  3.14159265359
#define PI2 6.28318530718

mat2 rot (float a) { return mat2(cos(a),sin(a),-sin(a),cos(a)); }
float hash21( vec2 p ) { return fract(sin(dot(p,vec2(23.43,84.21))) *4832.3234); }
//@iq
float octa( vec3 p, float s) {
  p = abs(p);
  return (p.x+p.y+p.z-s)*0.57735027;
}

mat2 r45,r22;
vec3 hit,hitPoint;
vec2 gid,sid;
float time,srnd,grnd;
vec2 sc = vec2(.0),ssc,gsc;

vec2 map(vec3 p) {
    p.y+=5.;
    p.x+=time;
    vec2 res = vec2(1e5,0);

    sc = vec2(.25);
    vec2 bsize = vec2(1.);

    vec2 id = floor(p.xz*sc) + .5;
    vec2 r = p.xz - id/(sc);
    vec3 q = vec3(r.x,p.y,r.y);

    float rnd = hash21(id);
    float tn=-1.;
    if(rnd>.5){
       sc*=2.;
       id = floor(q.xz*(sc)) + .5;
       r = q.xz - id/(sc);
       q = vec3(r.x,p.y,r.y);
       rnd = hash21(id+rnd);
       tn=0.;
       if(rnd>.5){
           sc*=2.;
           id = floor(q.xz*(sc)) + .5;
           r = q.xz - id/(sc);
           q = vec3(r.x,p.y,r.y);
           rnd = hash21(id+rnd);
           if(rnd>.5){
               sc*=2.;
               id = floor(q.xz*(sc)) + .5;
               r = q.xz - id/(sc);
               q = vec3(r.x,p.y,r.y);
               rnd = hash21(id+rnd);
               if(rnd>.5){
                   sc*=2.;
                   id = floor(q.xz*(sc)) + .5;
                   r = q.xz - id/(sc);
                   q = vec3(r.x,p.y,r.y);
                   rnd = hash21(id+rnd);
                   tn=1.;
               }
           }
       }
    }
    vec3 qs=q;
    q.xz*=rot(rnd*T*1.5);

    bsize = .375/sc.xx;
    float b1 = octa(q-vec3(0,bsize.y,0),bsize.x);

    if(tn==0.){
        q.xz*=r45;
        b1 = min(octa(q-vec3(0,bsize.y,0),bsize.x),b1);
    }
    if(tn==-1.){
        q.xz*=r22;
        b1 = min(octa(q-vec3(0,bsize.y,0),bsize.x),b1);
        q.xz*=r22;
        b1 = min(octa(q-vec3(0,bsize.y,0),bsize.x),b1);
    }

    if(b1<res.x) {
        res = vec2(b1,2.);
    	hit=q;
        gid=id;
        grnd=rnd;
        gsc=sc;
    }

    float d9 = p.y;
    if(d9<res.x) {
        res = vec2(d9,1.);
    	hit=qs;
        gid=id;
        grnd=rnd;
    }
    return res;
}

vec3 normal(vec3 p, float t, float mindist)
{
    float e = mindist*t;
    vec2 h = vec2(1.0,-1.0);
    return normalize( h.xyy*map( p + h.xyy*e).x +
					  h.yyx*map( p + h.yyx*e).x +
					  h.yxy*map( p + h.yxy*e).x +
					  h.xxx*map( p + h.xxx*e).x );
}

vec3 hue(float t)
{
    vec3 d = vec3(0.220,0.961,0.875);
    return .375 + .375*cos(PI2*t*(vec3(.985,.98,.95)+d));
}

vec3 render(vec3 p, vec3 rd, vec3 ro, float d, float m, inout vec3 n, inout float fresnel)
{
    n = normal(p,d,1.01);
    vec3 lpos =  vec3(5,4,1);
    vec3 l = normalize(lpos-p);

    float diff = clamp(dot(n,l),0.,1.);

    fresnel = pow(clamp(1.+dot(rd, n), 0., 1.), 3.);
    fresnel = mix(.01, .7, fresnel);

    float shdw = 1.;
    float t=.0;
    for(float i=.0;i<24.;i++)
    {
        float h = map(p + l*t).x;
        if( h<1e-4 ) { shdw = 0.; break; }
        shdw = min(shdw, 18.*h/t);
        t += h;
        if( shdw<.01 || t>64. ) break;
    }
    diff = mix(diff,diff*shdw,.4);

    vec3 h = vec3(0.914,0.984,0.973);
    if(m==1.) {
        float cir = length(hitPoint.xz)-(.15/ssc.x);
        float of =(.045/ssc.x);
        float ox =(.015/ssc.x);
        cir=abs(abs(abs(cir)-of)-of)-ox;
        cir = smoothstep(.001,.0011,cir);
        h=mix(vec3(0.561,0.639,0.627),h,1.-cir);
    }

    if(m==2.) {
        h=hue(((srnd+fresnel)+hitPoint.z*.05)*3.);
    }
    return diff*h;//mix(h,h*shdw,.6);
}

void mainImage( out vec4 O, in vec2 F )
{
    // precal
    time = T*.35;
    r45=rot(45.*PI/180.);
    r22=rot(30.*PI/180.);
    //

    vec2 uv = (2.*F.xy-R.xy)/max(R.x,R.y);

    float zoom = 3.;
    //orthographic camera
    vec3 ro = vec3(uv*zoom,-zoom);
    vec3 rd = vec3(0,0,1.);

    mat2 rx = rot(-0.58539816339);
    mat2 ry = rot(-0.78539816339);
    ro.yz *= rx;
    rd.yz *= rx;
    ro.xz *= ry;
    rd.xz *= ry;

    vec3 C = vec3(0);
    vec3  p = ro + rd;
    float atten = 1.;
    float k = 1.;
    float d = 0.;
    for(int i=0;i<125;i++)
    {
        vec2 ray = map(p);
        vec3 n=vec3(0);
        float m = ray.y;

        d = ray.x*.5;
        p += rd * d *k;

        if (d*d < 1e-6) {
            hitPoint = hit;
            sid = gid;
            ssc = gsc;
            srnd=grnd;
            float fresnel=0.;
            C+=render(p,rd,ro,d,ray.y,n,fresnel)*atten;
            if(m==1.)break;

            atten *= .65;
            p += rd*.025;
            k = sign(map(p).x);

            vec3 rr = vec3(0);
            if(int(F.x)%3 != int(F.y)%3) {
                rr = refract(rd,n,.45);
                rd=mix(rr,rd,.9-fresnel);
            }else{
                vec3 rr=reflect(-rd,n);
                rd=mix(rr,rd, vec3(.8)-fresnel);
                p+=n*.05;
            }

        }

        if(distance(p,rd)>75.) { break; }
    }

    C = pow(C, vec3(.4545));
    O = vec4(C,1.0);
}
