/**

    License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License

    Inercia DemoParty Shader Jam!! Making my last Truchet for the year!!

    Year of Truchets #062
    12/01/2023  @byt3_m3chanic
    Truchet Core \M/->.<-\M/ 2023

*/


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

#define PI  3.14159265359
#define PI2 6.28318530718

#define MIN_DIST .001
#define MAX_DIST 90.
#define SCALE .775

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); }

float box(vec3 p, vec3 b, float r) {
  vec3 q = abs(p)-b;
  return length(max(q,0.))+min(max(q.x,max(q.y,q.z)),0.)-r;
}
float trs(vec3 p, vec2 t){
  vec2 q=vec2(length(p.xy)-t.x,p.z);
  return length(q)-t.y;
}

vec3 shp,fhp;
vec2 sip,bid;
float thsh;

const float sz = 1./SCALE;
const float hf = sz/2.;
const float bs = hf*.82;
const float cs = (hf*1.15);
vec2 map(vec3 p) {
    vec2 res = vec2(1e5,0);
  p.z += 4.;
  p.x -= T*.2;

  vec2 qid = floor((p.xy+hf)/sz);
  vec3 qm = vec3(mod(p.xy+hf,sz)-hf,p.z);

  float hs = hash21(qid);
  if(hs>.5) qm.x=-qm.x;

  vec2 q = length(qm.xy-hf)<length(qm.xy+hf)?qm.xy-hf:qm.xy+hf;
  vec3 q3 = vec3(q,qm.z);

  float thx = .125+.11*sin(3.5+p.y*.75);
  float t = trs(q3,vec2(hf,thx));

  sip = qid;
  thsh = hs;

  if(t<res.x) {
    res = vec2(t,1.);
    shp = qm;
  }

  float bx = box(qm+vec3(0,0,1.45),vec3(bs),.04);
  if(bx<res.x) {
    res = vec2(bx,2.);
  }

  float cx = box(qm,vec3(bs),.04);
  float sx = length(qm)-cs;
  float nx = max(cx,-sx);
  if(nx<res.x&&hs>.82) {
      res = vec2(nx,3.);
  }
  return res;
}

vec3 normal(vec3 p, float t)
{
    float e = MIN_DIST*t;
    vec2 h =vec2(1,-1)*.5773;
    vec3 n = 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;
    return normalize(n);
}
vec3 thp,ghp;
vec2 tip,fid;
float hsh;
vec4 FC = vec4(.30,.33,.35,0.);
vec3 hue(float a){
  return  .45 + .45 * cos(PI2* a * vec3(1.,.15,.25));
}
vec4 render(inout vec3 ro, inout vec3 rd, inout vec3 ref, bool last, inout float d) {

    vec3 C = vec3(0);
    float m = 0.;
    vec3 p = ro;

    for(int i=0;i<164;i++) {
        p = ro + rd * d;
        vec2 ray = map(p);
        if(ray.x<MIN_DIST*d||d>MAX_DIST)break;
        d += i<62? ray.x*.25: ray.x*.75;
        m  = ray.y;
    }

    thp = shp;
    tip = sip;
    hsh = thsh;
    if(d<MAX_DIST)
    {
        vec3 n = normal(p,d);
        vec3 lpos =  vec3(1,8,0);
        vec3 l = normalize(lpos-p);

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

        float shdw = 1.0;
        for( float t=.05; t < 18.; ) {
            float h = map(p + l*t).x;
            if( h<MIN_DIST ) { shdw = 0.; break; }
            shdw = min(shdw, 18.*h/t);
            t += h;
            if( shdw<MIN_DIST || t>32. ) break;
        }
        diff = mix(diff,diff*shdw,.75);

        vec3 view = normalize(p - ro);
        vec3 ret = reflect(normalize(lpos), n);
        float spec =  .75 * pow(max(dot(view, ret), 0.), 25.);
        vec3 h = vec3(.05);

        if(m==1.) {
            thp /= 1./SCALE;
            float dir = mod(tip.x + tip.y,2.) * 2. - 1.;
            vec2 uv = thp.xy-sign(thp.x+thp.y+.001)*.5;
            float angle = atan(uv.x, uv.y);
            float a = sin( dir * angle * 6. + T * 2.25);
            a = abs(abs(a)-.45)-.35;

            vec3 nz = hue((p.x*.5+(T*.12))*.25);
            h = mix(nz, vec3(1), smoothstep(.01, .02, a));

            ref= h==vec3(1)? vec3(0) : h ;
        }

        if(m==2.) {
            h=vec3(hsh*.5);
            ref=h;
        }

        if(m==3.) {
            h = hue((p.x*.5+(T*.12))*.25)*.3;
            ref=h;
        }

        C = h*diff+min(spec,shdw);
        C = mix(FC.rgb,C,  exp(-.00005*d*d*d));

        ro = p+n*.001;
        rd = reflect(rd,n);

    }else{
        C = FC.rgb;
    }
    return vec4(C,d);
}

void mainImage( out vec4 O, in vec2 F )
{

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

    float zoom = 6.;
    vec3 ro = vec3(uv*zoom,-(zoom+10.));
    vec3 rd = vec3(0,0,1.);

    mat2 rx = rot(.4), ry = rot(2.8);
    ro.yz *= rx,ro.xz *= ry;
    rd.yz *= rx,rd.xz *= ry;

    vec3 C = vec3(0),ref=vec3(0),fil=vec3(1);

    float d = 0.,a = 0.;
    float numBounces = 2.;

    for(float i=0.; i<numBounces; i++) {
        d =0.;
        vec4 pass = render(ro, rd, ref, i==numBounces-1., d);
        C += pass.rgb*fil;
        fil*=ref;
        if(i==0.) a = d;
    }

    float ff = hash21(uv);
    if(ff>.5) C = mix(C,clamp(C-.05,vec3(0),vec3(1)),ff);
    C = mix(FC.rgb,C,  exp(-.000001*a*a*a));

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

