// CC0: Cracked heirloom
//  Tinkering with distored toruses and a favorite shader
//  Trippy Triangle by Tater: https://www.shadertoy.com/view/fslcDS

#define GLOW

#define TIME            iTime
#define RESOLUTION      iResolution

#define PI              3.141592654
#define PI_2            (0.5*PI)
#define TAU             (2.0*PI)

#define TOLERANCE       0.0001
#define MAX_RAY_LENGTH  12.0
#define MAX_RAY_MARCHES 60
#define MAX_SHADOW_MARCHES 30
#define NORM_OFF        0.001
#define ROT(a)          mat2(cos(a), sin(a), -sin(a), cos(a))
#define H13(n) fract((n)*vec3(12.9898,78.233,45.6114)*43758.5453123)

// License: WTFPL, author: sam hocevar, found: https://stackoverflow.com/a/17897228/418488
const vec4 hsv2rgb_K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 hsv2rgb(vec3 c) {
  vec3 p = abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www);
  return c.z * mix(hsv2rgb_K.xxx, clamp(p - hsv2rgb_K.xxx, 0.0, 1.0), c.y);
}
// License: WTFPL, author: sam hocevar, found: https://stackoverflow.com/a/17897228/418488
//  Macro version of above to enable compile-time constants
#define HSV2RGB(c)  (c.z * mix(hsv2rgb_K.xxx, clamp(abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www) - hsv2rgb_K.xxx, 0.0, 1.0), c.y))

// License: Unknown, author: nmz (twitter: @stormoid), found: https://www.shadertoy.com/view/NdfyRM
vec3 sRGB(vec3 t) {
  return mix(1.055*pow(t, vec3(1./2.4)) - 0.055, 12.92*t, step(t, vec3(0.0031308)));
}

// License: Unknown, author: Matt Taylor (https://github.com/64), found: https://64.github.io/tonemapping/
vec3 aces_approx(vec3 v) {
  v = max(v, 0.0);
  v *= 0.6f;
  float a = 2.51f;
  float b = 0.03f;
  float c = 2.43f;
  float d = 0.59f;
  float e = 0.14f;
  return clamp((v*(a*v+b))/(v*(c*v+d)+e), 0.0f, 1.0f);
}

// License: MIT, author: Pascal Gilcher, found: https://www.shadertoy.com/view/flSXRV
float atan_approx(float y, float x) {
  float cosatan2 = x / (abs(x) + abs(y));
  float t = PI_2 - cosatan2 * PI_2;
  return y < 0.0 ? -t : t;
}

// License: MIT, author: Inigo Quilez, found: https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
float hex(vec2 p, float r) {
  const vec3 k = vec3(-0.866025404,0.5,0.577350269);
  p = abs(p);
  p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
  p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
  return length(p)*sign(p.y);
}

// License: MIT, author: Inigo Quilez, found: https://www.iquilezles.org/www/articles/smin/smin.htm
float pmin(float a, float b, float k) {
  float h = clamp(0.5+0.5*(b-a)/k, 0.0, 1.0);
  return mix(b, a, h) - k*h*(1.0-h);
}

// License: MIT, author: Inigo Quilez, found: https://www.iquilezles.org/www/articles/smin/smin.htm
float pmax(float a, float b, float k) {
  return -pmin(-a, -b, k);
}


// License: CC0, author: Mårten Rånge, found: https://github.com/mrange/glsl-snippets
float pabs(float a, float k) {
  return -pmin(a, -a, k);
}

// License: MIT, author: Inigo Quilez, found: https://iquilezles.org/articles/distfunctions/
float hexTorus(vec3 p, vec3 d) {
  vec2 q = vec2(length(p.xz) - d.x, p.y);
  float a = atan_approx(p.x, p.z);
  const float off = PI*0.875;
  a = abs(a);
  float b = a;
  b -= off;
  b = -pabs(b, 1.0);
  b += off;
  a *= b;
  mat2 r = ROT(-4.0*a/6.0);
  return hex(r*q, d.y)-d.z;
}

// License: MIT, author: Inigo Quilez, found: https://iquilezles.org/articles/spherefunctions/
float sphered(vec3 ro, vec3 rd, vec4 sph, float dbuffer) {
    float ndbuffer = dbuffer/sph.w;
    vec3  rc = (ro - sph.xyz)/sph.w;

    float b = dot(rd,rc);
    float c = dot(rc,rc) - 1.0;
    float h = b*b - c;
    if( h<0.0 ) return 0.0;
    h = sqrt( h );
    float t1 = -b - h;
    float t2 = -b + h;

    if( t2<0.0 || t1>ndbuffer ) return 0.0;
    t1 = max( t1, 0.0 );
    t2 = min( t2, ndbuffer );

    float i1 = -(c*t1 + b*t1*t1 + t1*t1*t1/3.0);
    float i2 = -(c*t2 + b*t2*t2 + t2*t2*t2/3.0);
    return (i2-i1)*(3.0/4.0);
}

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

// https://www.shadertoy.com/view/7sByWR
float vorMap(vec3 p){
  const vec3 v0 = H13(0.96);
  const vec3 v1 = H13(0.55);
  const vec3 v2 = H13(0.718);
  const vec3 v3 = H13(0.3);
  const mat2 r0 = ROT(1.2);
  const mat2 r1 = ROT(2.0);
  const mat2 r2 = ROT(2.7);
  vec2 v = vec2(5.0);
  v = vor(v,p,v0);
  p.xy*=r0;
  v = vor(v,p,v1);
  p.yz*=r1;
  v = vor(v,p,v2);
  p.zx*=r2;
  v = vor(v,p,v3);
  return v.y-v.x;
}

float df(vec3 p) {
  vec3 p0 = p.zxy;
  float d0 = hexTorus(p0, vec3(2.0, 0.65, 0.025));
  float d1 = p.x+1.0;
  vec2 pp = p.yz;
  pp.y = -abs(pp.y);
  const vec2 nn = normalize(vec2(1.5, 1.));
  float vf = 0.025*dot(pp, nn);
  float d2 = vorMap(p)-vf;
  float d = d0;
  d = pmax(d, -d2, 0.0125);
  d = min(d, d1);

  return d;
}

vec3 normal(vec3 pos) {
  vec2  eps = vec2(NORM_OFF,0.0);
  vec3 nor;
  nor.x = df(pos+eps.xyy) - df(pos-eps.xyy);
  nor.y = df(pos+eps.yxy) - df(pos-eps.yxy);
  nor.z = df(pos+eps.yyx) - df(pos-eps.yyx);
  return normalize(nor);
}

float rayMarch(vec3 ro, vec3 rd) {
  float t = 0.0;
  const float tol = TOLERANCE;
  vec2 dti = vec2(1e10,0.0);
  int i = 0;
  for (i = 0; i < MAX_RAY_MARCHES; ++i) {
    float d = df(ro + rd*t);
    if (d<dti.x) { dti=vec2(d,t); }
    if (d < TOLERANCE || t > MAX_RAY_LENGTH) {
      break;
    }
    t += d;
  }
  if(i==MAX_RAY_MARCHES) { t=dti.y; };
  return t;
}


float softShadow(vec3 ps, vec3 ld, float mint, float k) {
  float res = 0.0;
  float t = mint*7.0;
  for (int i=0; i<MAX_SHADOW_MARCHES; ++i) {
    vec3 p = ps + ld*t;
    float d = df(p);
    if (d < 0.0) return 0.0;
    res += 0.05*inversesqrt((d));
    if (res > 1.0) {
      return 0.0;
    };
    t += max(d, mint);
  }
  return clamp(1.0-res, 0.0, 1.0);
}

vec3 render(vec3 ro, vec3 rd) {
  const vec3 lightPos = vec3(5.0, 3.0, 1.0)*2.;
  const float i = 100.0;
  const float h = 0.55;
  const vec3 dcol = HSV2RGB(vec3(h, 0.25, i));
  const vec3 scol = HSV2RGB(vec3(h, 0.25, i));

  float t = rayMarch(ro, rd);
  vec3 col = vec3(0.0);

#ifdef GLOW
  float gf = 0.5+0.5*cos(TAU*TIME/10.0);
  float gr = mix(0.62, 0.57, gf);
  float gd = sphered(ro, rd, vec4(vec3(0.19, 2.0-0.025, 0.0), gr), t);
  vec3 gcol = hsv2rgb(vec3(h, mix(0.75, 0.9, gf), mix(60.0, 2.0, gf)));
#endif

  vec3 p = ro+rd*t;
  vec3 n = normal(p);
  vec3 r = reflect(rd, n);
  vec3 ld = normalize(lightPos - p);
  float ll2 = dot(lightPos - p, lightPos - p);
  float sd = softShadow(p, ld, 0.025, 2.0);
  float dif = max(dot(ld, n), 0.0);
  float spe = pow(max(dot(ld, r), 0.0), 10.0);
  if (t < MAX_RAY_LENGTH) {
    col = dcol;
    col *= mix(0.1, 1.0, dif);
    col *= mix(0.2, 1.0, sd);
    col += spe*sd*scol;
    col /= ll2;
  }
#ifdef GLOW
  col += gcol*gd;
#endif

  return col;
}

vec3 effect(vec2 p) {
  const vec3 ro = vec3(5.0, 0.0, 0.01);
  const vec3 la = vec3(0.0, 0.0, 0.0);
  const vec3 up = normalize(vec3(0.0, 1.0, 0.0));

  vec3 ww = normalize(la - ro);
  vec3 uu = normalize(cross(up, ww ));
  vec3 vv = (cross(ww,uu));
  const float fov = tan(TAU/6.);
  vec3 rd = normalize(-p.x*uu + p.y*vv + fov*ww);

  vec3 col = render(ro, rd);

  return col;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
  vec2 q = fragCoord/RESOLUTION.xy;
  vec2 p = -1. + 2. * q;
  vec2 pp = p;
  p.x *= RESOLUTION.x/RESOLUTION.y;
  vec3 col = vec3(0.0);
  col = effect(p);
  col *= smoothstep(1.75, 1.0-0.5, length(pp));
  col = aces_approx(col);
  col = sRGB(col);
  fragColor = vec4(col, 1.0);
}
