precision highp float;
uniform vec2 resolution;
uniform vec2 mouse;
uniform float time;
uniform sampler2D backbuffer;

// ------------------------------------------------------------------------------------
// Original Character By MikkaBouzu : https://twitter.com/mikkabouzu777
// ------------------------------------------------------------------------------------

#define saturate(x) clamp(x, 0.0, 1.0)
#define MAX_MARCH 256
#define MAX_DIST 100.

const float EPS = 1e-3;
const float EPS_N = 1e-4;
const float OFFSET = EPS * 10.0;

#define M_PI 3.1415926
#define M_PI2 6.2831852
#define RAD90 (M_PI * 0.5)

struct surface {
       float dist;
   vec4 albedo;
   int count;
   bool isHit;
};

// Surface Data Define
#define SURF_NOHIT(d)   (surface(d, vec4(0),                    0, false))
#define SURF_BLACK(d)   (surface(d, vec4(0,0,0,1),      0, true))
#define SURF_FACE(d)    (surface(d, vec4(1,0.7,0.6,1),  0, true))
#define SURF_MOUSE(d)   (surface(d, vec4(1,0,0.1,1),    0, true))
#define SURF_CHEEP(d)   (surface(d, vec4(1,0.3,0.4,1),  0, true))

vec3 hsv2rgb( in vec3 c )
{
   vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );

       rgb = rgb*rgb*(3.0-2.0*rgb); // cubic smoothing

       return c.z * mix( vec3(1.0), rgb, c.y);
}

#define M_PI03 1.04719
#define M_PI06 2.09439
vec3 sinebow(float h) {
   vec3 r = sin((.5-h)*M_PI + vec3(0,M_PI03,M_PI06));
   return r*r;
}

//  1 out, 3 in...
float hash13(vec3 p3)
{
       p3  = fract(p3 * .1031);
   p3 += dot(p3, p3.zyx + 31.32);
   return fract((p3.x + p3.y) * p3.z);
}

float noise(vec3 st)
{
       vec3 ip = floor(st);
 vec3 fp = smoothstep(vec3(0.), vec3(1.), fract(st));

       vec4 a = vec4(hash13(ip+vec3(0.)),hash13(ip+vec3(1.,0.,0.)),hash13(ip+vec3(0.,1.,0.)),hash13(ip+vec3(1.,1.,0.)));
 vec4 b = vec4(hash13(ip+vec3(0.,0.,1.)),hash13(ip+vec3(1.,0.,1.)),hash13(ip+vec3(0.,1.,1.)),hash13(ip+vec3(1.,1.,1.)));

       a = mix(a, b, fp.z);
       a.xy = mix(a.xy, a.zw, fp.y);

       return mix(a.x, a.y, fp.x);
}

mat3 m = mat3( 0.00,  0.80,  0.60,
             -0.80,  0.36, -0.48,
             -0.60, -0.48,  0.64 );

float fbm( vec3 p )
{
   float f;
   f  = 0.5000*noise( p ); p = m*p*2.02;
   f += 0.2500*noise( p ); p = m*p*2.03;
   f += 0.1250*noise( p );
   return f;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Basic Distance function
/////////////////////////////////////////////////////////////////////////////////////////////////
float sdRoundBox(vec3 p, vec3 size, float r)
{
   return length(max(abs(p) - size * 0.5, 0.0)) - r;
}

float sdCapsule(vec3 p, vec3 a, vec3 b, float r)
{
       vec3 pa = p - a, ba = b - a;
       float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
       return length(pa - ba*h) - r;
}

float sdEllipsoid( vec3 p, vec3 r )
{
   float k0 = length(p/r);
   float k1 = length(p/(r*r));
   return k0*(k0-1.0)/k1;
}

float sdCappedTorus(in vec3 p, in vec2 sc, in float ra, in float rb)
{
 p.x = abs(p.x);
 float k = (sc.y*p.x>sc.x*p.y) ? dot(p.xy,sc) : length(p.xy);
 return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb;
}

float sdRoundedCylinder( vec3 p, float ra, float rb, float h )
{
 vec2 d = vec2( length(p.xz)-2.0*ra+rb, abs(p.y) - h );
 return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rb;
}

vec3 rotate(vec3 p, float angle, vec3 axis)
{
   vec3 a = normalize(axis);
   float s = sin(angle);
   float c = cos(angle);
   float r = 1.0 - c;
   mat3 m = mat3(
       a.x * a.x * r + c,
       a.y * a.x * r + a.z * s,
       a.z * a.x * r - a.y * s,
       a.x * a.y * r - a.z * s,
       a.y * a.y * r + c,
       a.z * a.y * r + a.x * s,
       a.x * a.z * r + a.y * s,
       a.y * a.z * r - a.x * s,
       a.z * a.z * r + c
   );
   return m * p;
}

// Union, Subtraction, SmoothUnion (distance, Material)
surface opU(surface d1, surface d2)
{
   if(d1.dist < d2.dist){
       return d1;
   } else {
       return d2;
   }
}

float opU( float d1, float d2 ) {  return min(d1,d2); }

surface opS( surface d1, surface d2 )
{
   if(-d1.dist > d2.dist){
       d1.dist = -d1.dist;
       return d1;
   } else {
       return d2;
   }
}

surface opSU( surface d1, surface d2, float k ) {
   float h = clamp( 0.5 + 0.5*(d2.dist - d1.dist)/k, 0.0, 1.0 );
   float d = mix( d2.dist, d1.dist, h ) - k*h*(1.0-h);
   vec4 albedo = mix( d2.albedo, d1.albedo, h );
   return surface(d, albedo, d1.count, true);
}

float smin( float d1, float d2, float k ) {
   float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
   return mix( d2, d1, h ) - k*h*(1.0-h);
}

//https://www.shadertoy.com/view/NdS3Dh
//SmoothSymmetricPolarMod aka smoothRot
//
//s repetitions
//m smoothness (0-1)
//c correction (0-1)
//d object displace from center
//
vec2 smoothRot(vec2 p,float s,float m,float c,float d){
 s*=0.5;
 float k=length(p);
 float x=asin(sin(atan(p.x,p.y)*s)*(1.0-m))*k;
 float ds=k*s;
 float y=mix(ds,2.0*ds-sqrt(x*x+ds*ds),c);
 return vec2(x/s,y/s-d);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// Mikka Boze Distance Function
/////////////////////////////////////////////////////////////////////////////////////////////////
float sdEar(vec3 p)
{
   p = rotate(p, RAD90+0.25, vec3(0,0,1));
   return sdCappedTorus(p + vec3(0.05, 0.175, 0), vec2(sin(0.7),cos(0.7)), 0.03, 0.01);
}

#define EYE_SPACE 0.04

vec3 opBendXY(vec3 p, float k)
{
   float c = cos(k*p.x);
   float s = sin(k*p.x);
   mat2  m = mat2(c,-s,s,c);
   return vec3(m*p.xy,p.z);
}

vec3 opBendXZ(vec3 p, float k)
{
   float c = cos(k*p.x);
   float s = sin(k*p.x);
   mat2  m = mat2(c,-s,s,c);
   vec2 xz = m*p.xz;
   return vec3(xz.x, p.y, xz.y);
}

float sdMouse(vec3 p, float ms)
{
   vec3 q = opBendXY(p, 2.0);
   ms += 0.00001;
   return sdEllipsoid(q - vec3(0,0,0.2), vec3(0.035, 0.01 * ms,0.05 * ms));
}

float sdCheep(vec3 p)
{
   const float x = 0.05;
   const float z = -0.175;
   const float r = 0.0045;
   const float rb1 = 100.;

   p = rotate(p, M_PI * -0.6 * (p.x - x), vec3(-0.2,0.8,0));

   float d = sdCapsule(opBendXY(p + vec3(x, -0.01, z), rb1), vec3(-0.005,0.0,0.0), vec3(0.005, 0., 0.001), r);
   float d1 = sdCapsule(opBendXY(p + vec3(x+0.01, -0.01, z), 200.0), vec3(-0.0026,0.0,0), vec3(0.0026, 0., 0), r);
   float d2 = sdCapsule(opBendXY(p + vec3(x+0.019, -0.015, z), -rb1), vec3(-0.01,0.0,-0.01), vec3(0.0045, 0., 0.0), r);

   return opU(opU(d, d1), d2);
}

float sdEyeBrow(vec3 p)
{
   const float x = 0.05;
   p = opBendXZ(p + vec3(0.02,0,-0.02), -6.5);
   return sdRoundBox(p + vec3(0.005, -0.14,-0.11), vec3(0.003,0.0025,0.05), 0.001);
}

surface sdBoze(vec3 p, vec3 sc, float ms)
{
   surface result = SURF_NOHIT(1e5);

   float minsc = min(sc.x, min(sc.y, sc.z));
   p /= sc;

   // head
         float d = sdCapsule(p, vec3(0,0.05,0), vec3(0, 0.11, 0), 0.125);

   float d1 = sdRoundedCylinder(p + vec3(0,0.025,0), 0.095, 0.05, 0.0);

   d = smin(d, d1, 0.1);

   vec3 mxp = vec3(-abs(p.x), p.yz);

   // ear
   float d2 = sdEar(mxp);
   d = opU(d, d2);

         surface head = SURF_FACE(d);

         // eye
   float d4 = sdCapsule(mxp, vec3(-EYE_SPACE, 0.06, 0.13), vec3(-EYE_SPACE, 0.08, 0.125), 0.0175);
   surface eye = SURF_BLACK(d4);

   // mouse
   float d6 = sdMouse(p, ms);
   surface mouse = SURF_MOUSE(d6);

   // cheep
   float d7 = sdCheep(mxp);
   surface cheep = SURF_CHEEP(d7);

   // eyebrows
   float d9 = sdEyeBrow(mxp);
   eye.dist = opU(eye.dist, d9);

   // integration
   mouse = opU(eye, mouse);
   result = opS(mouse, head);
   result = opU(cheep, result);

   result.dist *= minsc;

   return result;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// End of Mikka Boze
/////////////////////////////////////////////////////////////////////////////////////////////////

// https://iquilezles.org/articles/mandelbulb/
surface map(vec3 p)
{
         surface result = SURF_NOHIT(1e5);

   float ms = sin(time) * 0.5 + 0.5;

   vec3 z = p;
         float dz = 1.0;
   // square of the magnitude of z
   float m2 = dot(z,z);

   vec4 orbitTrap = vec4(abs(z), m2);

   //float deg = iTime*-0.5;
   float deg=-time*0.15;

   float d = 1.;
   float d2 = 0.;
   float repetitions=7.0;
   float smoothness=0.1;
   float correction=0.1;
   float displace= 0.5;

   p = rotate(p+vec3(0,0.1,0), RAD90+time*2.1, vec3(0.5, 0, 0.5));


         for(int i=0; i<4; i++)
   {
       // extract sperical coordinate
       float r = length(z);
       float phi = deg*acos(z.y/r);
       float theta = deg*atan(z.x, z.z);

       // z = z^p+c
       z = pow(r,deg) * vec3(sin(phi)*sin(theta), cos(phi), sin(phi)*cos(theta)) + p;

       vec3 z2 = z;
       z2.z = abs(z2.z);
       z2.xy = smoothRot(z.xy, repetitions, smoothness, correction, displace);
       surface boze = sdBoze((z2) - vec3(0,0.1,0), vec3(3.), ms);
       result = opU(result, boze);

   }
   return result;
}

vec3 norm(in vec3 position) {
   // https://www.shadertoy.com/view/XltyRf
   vec4 n = vec4(0);
   for (int i = 0 ; i < 4 ; i++) {
       vec4 s = vec4(position, 0);
       s[i] += 0.001;
       n[i] = map(s.xyz).dist;
   }
   return normalize(n.xyz-n.w);

}

surface traceRay(in vec3 origin, in vec3 direction, float dist, out vec3 pos) {
   float t = 0.0;

   pos = origin;

   int count = 0;
   surface hit;
   float d;

   for (int i = 0; i < MAX_MARCH; i++) {
       hit = map(pos);
       d = hit.dist;

       if (d <= EPS || d >= MAX_DIST) {
               break;
       }

       t += d;
       pos = origin + direction * t;
       count++;
   }

   hit.dist = t;
       hit.count = count;

   pos = origin + direction * t;

   if(hit.isHit)
   {
       // Lighting
       vec3 normal = norm(pos);

       vec3 lightDir = normalize(vec3(cos(time), 1, sin(time)));
                   vec3 lightColor = vec3(1.5);

       float NoL = saturate(dot(normal, lightDir));

       vec3 ambientColor = vec3(0.1);

       hit.albedo.rgb *= NoL * lightColor +  ambientColor;
   }

   if(d <= EPS){
       hit.isHit = true;
       return hit;
   }else{

       hit.isHit = false;
       return hit;
   }
}

vec3 render(vec3 p, vec3 ray, vec2 uv)
{
   vec3 pos;
   surface mat = traceRay(p, ray, 0., pos);

   vec3 col = vec3(0,0,0);
   //vec3 sky = vec3(0.3);
   vec3 sky = sinebow(fbm(vec3(uv * 0.01, 0))*5.5+(time * M_PI2 * 0.5)*0.25)*0.5+0.25;

   col = mat.isHit ? mat.albedo.rgb : sky;

   return col;

}

mat3 camera(vec3 ro, vec3 ta, float cr )
{
       vec3 cw = normalize(ta - ro);
       vec3 cp = vec3(sin(cr), cos(cr),0.);
       vec3 cu = normalize( cross(cw,cp) );
       vec3 cv = normalize( cross(cu,cw) );
   return mat3( cu, cv, cw );
}

void main()
{
 vec2 r=resolution,p=(gl_FragCoord.xy*2.-r)/min(r.x,r.y);
 const float l = 3.;
 float t = time + RAD90;

 vec3 ro = vec3(cos(t) * l, 0.05, sin(t) * l);
 //vec3 ro = vec3(0, 0.05, 0.8);
 vec3 ta = vec3(0, -0.25, 0);

 mat3 c = camera(ro, ta, 0.0);
 vec3 ray = c * normalize(vec3(p, 1.5));
 vec3 col = render(ro, ray, gl_FragCoord.xy);

 // Output to screen
 gl_FragColor = vec4(col,1.0);

}