/*
"Swiss SBB Clock" by Emmanuel Keller aka Tambako - March 2016
License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
Contact: tamby@tambako.ch
*/

// Much code adapted from https://www.shadertoy.com/view/Xds3zN, thanks iq to let us use it! :)

#define pi 3.14159265359

// Switches, you can play with them!
#define specular
//#define shadow
#define reflections
#define ambocc
#define show_glass

struct Lamp
{
  	vec3 position;
  	vec3 color;
  	float intensity;
  	float attenuation;
};

struct RenderData
{
  	vec3 col;
  	vec3 pos;
  	vec3 norm;
  	int objnr;
};

struct ClockHand
{
	vec2 size;
    float angle;
    float ypos;
    float frontLength;
    float backLength;
    vec2 cap;
    int capShape;    // 0: no cap, 1: disk, 2: square, 3: arrow, 4: inverse arrow
    float timeFactor;
    float rotationFactor;
    bool continuous;
    vec2 tickMovement;
    vec3 color;
    bool metallic;
    int object;
    bool visible;
};

struct FaceTicks
{
    float outPos;
    vec2 size;
    float tstep;
    vec3 color;
    int type;    // 0: not visible, 1: line, 2: circle
};

struct Clock
{
    float diameter;
    float height;
    float caseThickness;
    float facePos;
    float glassTickness;
    vec2 axisSize;
    vec3 caseColor;
    vec3 faceColor;
    vec3 glassColor;
    vec3 axisColor;
    ClockHand secondsHand;
    ClockHand minutesHand;
    ClockHand hoursHand;
    FaceTicks minuteTicks;
    FaceTicks hourTicks;
};

// Every object of the scene has its ID
#define SKY_OBJ         0
#define CASE_OBJ        1
#define FACE_OBJ        2
#define SHAND_OBJ       3
#define MHAND_OBJ       4
#define HHAND_OBJ       5
#define AXIS_OBJ        6
#define GLASS_OBJ       7

Clock SBBClock;
Clock DesignClock;
Clock LuxuryClock;
Clock cClock;
void initClock()
{
    ClockHand secondsHand = ClockHand(vec2(0.025, 0.02), 0., 0.06, 0.615, 0.25, vec2(0.615, 0.09), 1, 1., 60./58., true, vec2(80., 250.), vec3(1., 0.08, 0.08), false, SHAND_OBJ, true);
    ClockHand minutesHand = ClockHand(vec2(0.085, 0.02), 0.55, 0.04, 0.88, 0.19, vec2(0.0, 0.0), 0, 60., 1., false, vec2(75., 200.), vec3(0.03, 0.03, 0.03), false, MHAND_OBJ, true);
    ClockHand hoursHand = ClockHand(vec2(0.115, 0.02), 0.55, 0.02, 0.647, 0.19, vec2(0.0, 0.0), 0, 60.*12., 1., true, vec2(75., 150.), vec3(0.03, 0.03, 0.03), false, HHAND_OBJ, true);

    FaceTicks minuteTicks = FaceTicks(0.93, vec2(0.07, 1.4), 6., vec3(0., 0., 0.), 1);
    FaceTicks hourTicks = FaceTicks(0.93, vec2(0.22, 4.), 30., vec3(0., 0., 0.), 1);

    SBBClock = Clock(3., 1., 0.06, 0.8, 0.08, vec2(0.04, 0.1), vec3(0.85, 0.83, 0.81), vec3(0.98, 0.98, 0.98), vec3(0.96, 0.99, 0.96), vec3(0.83, 0.03, 0.03), secondsHand, minutesHand, hoursHand, minuteTicks, hourTicks);

    secondsHand = ClockHand(vec2(0.035, 0.02), 0., 0.07, 0.6, 0.25, vec2(0.6, 0.09), 3, 1., 1., false, vec2(50., 100.), vec3(0.3, 0.6, 0.87), false, SHAND_OBJ, true);
    minutesHand = ClockHand(vec2(0.08, 0.02), 0., 0.045, 0.7, 0.15, vec2(0.0, 0.0), 0, 60., 1., true, vec2(50., 100.), vec3(0.8, 0.85, 0.93), false, MHAND_OBJ, true);
    hoursHand = ClockHand(vec2(0.08, 0.02), 0., 0.02, 0.55, 0.15, vec2(0.0, 0.0), 0, 60.*12., 1., true, vec2(50., 100.), vec3(0.6, 0.72, 0.91), false, HHAND_OBJ, true);

    minuteTicks = FaceTicks(0.9, vec2(0.1, 1.), 6., vec3(1., 1., 1.), 1);
    hourTicks = FaceTicks(0.94, vec2(0.2, 1.), 30., vec3(1., 1., 1.), 1);

    DesignClock = Clock(3., .8, 0.03, 0.9, 0., vec2(0.06, 0.13), vec3(0.5, 0.7, 1.0), vec3(0.05, 0.05, 0.09), vec3(0.96, 0.99, 0.96), vec3(0.96, 0.96, 0.96), secondsHand, minutesHand, hoursHand, minuteTicks, hourTicks);

    secondsHand = ClockHand(vec2(0.025, 0.025), 0., 0.09, 0.82, 0.25, vec2(0., 0.), 0, 1., 1., false, vec2(75., 150.), vec3(0.8, 0.82, 0.84), true, SHAND_OBJ, true);
    minutesHand = ClockHand(vec2(0.04, 0.025), -4.5, 0.055, 0.7, 0.05, vec2(0.742, 0.085), 3, 60., 1., true, vec2(50., 100.), vec3(0.8, 0.67, 0.3), true, MHAND_OBJ, true);
    hoursHand = ClockHand(vec2(0.06, 0.025), -7., 0.02, 0.5, 0.05, vec2(0.55, 0.1), 3, 60.*12., 1., true, vec2(50., 100.), vec3(0.8, 0.67, 0.3), true, HHAND_OBJ, true);

    minuteTicks = FaceTicks(0.91, vec2(0.06, 1.3), 6., vec3(0., 0., 0.), 2);
    hourTicks = FaceTicks(0.91, vec2(0.1, 3.4), 30., vec3(0.8, 0.67, 0.3), 2);

    LuxuryClock = Clock(3., 0.55, 0.02, 0.7, 0.05, vec2(0.04, 0.18), vec3(0.81, 0.83, 0.86), vec3(0.8, 0.8, 0.8), vec3(0.96, 0.99, 0.96), vec3(0.8, 0.67, 0.3), secondsHand, minutesHand, hoursHand, minuteTicks, hourTicks);

    cClock = SBBClock; // You can choose one of the three defined watches: SBBClock, DesignClock or LuxuryClock
}

Lamp lamps[3];

// Campera options
vec3 campos = vec3(0., 0., 9.);
vec3 camdir = vec3(0., 0., -1.);
float fov = 5.2;
float angle;
float angle2;

// Ambient light
const vec3 ambientColor = vec3(0.3);
const float ambientint = 0.05;

// Shading options
const float specint = 0.22;
const float specshin = 70.;
const float aoint = 0.55;
const float shi = 2.85;
const float shf = 1.4;

// Tracing options
const float normdelta = 0.0001;
const float maxdist = 40.;
const int nbref = 2;
const int nbrefr = 2;
const float glass_ior = 1.5;

// Antialias. Change from 1 to 2 or more AT YOUR OWN RISK! It may CRASH your browser while compiling!
const float aawidth = 0.8;
const int aasamples = 1;

// 1D hash function
float hash(float n){
	return fract(sin(n)*3538.5453);
}

// 2D hash function
vec2 hash2(vec2 n){
	return fract(vec2(sin(n.x)*3538.5453, sin(n.y)*2753.8256));
}

// Union operation from iq
vec2 opU(vec2 d1, vec2 d2)
{
	return (d1.x<d2.x) ? d1 : d2;
}

// Difference operation from iq
float opS(float d1, float d2)
{
    return max(-d2,d1);
}

vec2 rotateVec(vec2 vect, float angle)
{
    vec2 rv;
    rv.x = vect.x*cos(angle) - vect.y*sin(angle);
    rv.y = vect.x*sin(angle) + vect.y*cos(angle);
    return rv;
}

vec3 rotateVec2(vec3 posr)
{
    posr = vec3(posr.x, posr.y*cos(angle2) + posr.z*sin(angle2), posr.y*sin(angle2) - posr.z*cos(angle2));
    posr = vec3(posr.x*cos(angle) + posr.z*sin(angle), posr.y, posr.x*sin(angle) - posr.z*cos(angle));

    return posr;
}

// From https://www.shadertoy.com/view/Xds3zN
float sdCylinder(vec3 p, vec2 h)
{
    vec2 d = abs(vec2(length(p.xz),p.y)) - h;
    return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}

// From https://www.shadertoy.com/view/Xds3zN
float sdBox(vec3 p, vec3 b)
{
  vec3 d = abs(p) - b;
  return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}

// From https://www.shadertoy.com/view/Xds3zN
float sdTriPrism(vec3 p, vec2 h)
{
    vec3 q = abs(p);
    float d1 = q.z-h.y;
    float d2 = max(q.x*0.866025+p.y*0.5,-p.y)-h.x*0.5;
    return length(max(vec2(d1,d2),0.0)) + min(max(d1,d2), 0.);
}

float getStepImpulse(float t, float a, float s, float f)
{
    return a*cos(t*f)*exp(-s*t);
}

vec2 map_hand(vec3 pos, float angle, ClockHand hand)
{
    if (!hand.visible)
        return vec2(maxdist*2., hand.object);
    pos.xz = rotateVec(pos.xz, radians(angle));
    pos.y/= cClock.height;
    pos.y-= hand.ypos + cClock.facePos - 0.25;
    pos.xz/= cClock.diameter/2. - cClock.caseThickness;
    float handd = max(max(abs(pos.x) + tan(radians(hand.angle))*pos.z - hand.size.x/2.,
                      max(pos.y - hand.size.y, -pos.y)),
                      max(pos.z - hand.frontLength, -pos.z + -hand.backLength));
    //0: no cap, 1: disk, 2: square, 3: arrow, 4: inverse arrow
    if (hand.cap.x!=0. && hand.cap.x!=0. && hand.capShape>0)
    {
        float cap;
        if (hand.capShape==1)
            cap = sdCylinder(pos - vec3(0., hand.size.y/2., hand.cap.x), vec2(hand.cap.y, hand.size.y/2.));
        if (hand.capShape==2)
            cap = sdBox(pos - vec3(0., hand.size.y/2., hand.cap.x), vec3(hand.cap.y, hand.size.y/2., hand.cap.y));
        if (hand.capShape==3)
            cap = sdTriPrism((pos - vec3(0., hand.size.y/2., hand.cap.x)).xzy, vec2(hand.cap.y, hand.size.y/2.));
        if (hand.capShape==4)
            cap = sdTriPrism((pos - vec3(0., hand.size.y/2., hand.cap.x)).xzy*vec3(1., -1., 1.), vec2(hand.cap.y, hand.size.y/2.));
        handd = min(handd, cap);
    }
    return vec2(handd, hand.object);
}

vec2 map(vec3 pos)
{
    pos = pos.xzy;
    pos = rotateVec2(pos);

    float secondsAngle = clamp(mod(iDate.w*6./cClock.secondsHand.timeFactor, 360.)*cClock.secondsHand.rotationFactor, 0., 360.);
    float minutesAngle = clamp(mod(iDate.w*6./cClock.minutesHand.timeFactor, 360.)*cClock.minutesHand.rotationFactor, 0., 360.);
    float hoursAngle = clamp(mod(iDate.w*6./cClock.hoursHand.timeFactor, 360.)*cClock.hoursHand.rotationFactor, 0., 360.);

    if (!cClock.secondsHand.continuous)
        secondsAngle = 6.*floor(secondsAngle/6.) - getStepImpulse(fract(secondsAngle/6.), 6., cClock.secondsHand.tickMovement.x*cClock.secondsHand.timeFactor, cClock.secondsHand.tickMovement.y);
    if (!cClock.minutesHand.continuous)
        minutesAngle = 6.*floor(minutesAngle/6.) - getStepImpulse(fract(minutesAngle/6.), 6., cClock.secondsHand.tickMovement.x*cClock.minutesHand.timeFactor, cClock.secondsHand.tickMovement.y*cClock.secondsHand.timeFactor);
    if (!cClock.hoursHand.continuous)
        hoursAngle = 30.*floor(hoursAngle/30.) - getStepImpulse(fract(hoursAngle/6.), 6., cClock.secondsHand.tickMovement.x*cClock.hoursHand.timeFactor, cClock.secondsHand.tickMovement.y*pow(cClock.secondsHand.timeFactor, 2.));

    vec2 dSecondsHand = map_hand(pos, -secondsAngle, cClock.secondsHand);
    vec2 dMinutesHand = map_hand(pos, -minutesAngle, cClock.minutesHand);
    vec2 dHoursHand = map_hand(pos, -hoursAngle, cClock.hoursHand);
    vec2 hands = opU(opU(dSecondsHand, dMinutesHand), dHoursHand);

    float ccase = opS(sdCylinder(pos - vec3(0., cClock.height/4., 0), vec2(cClock.diameter/2., cClock.height/2.)),
                     sdCylinder(pos - vec3(0., cClock.height/4. + cClock.caseThickness, 0.), vec2(cClock.diameter/2. - cClock.caseThickness, cClock.height/2.)));
    vec2 clockd = opU(vec2(ccase, CASE_OBJ), hands);

    float face = sdCylinder(pos + vec3(0., cClock.height*(1./4. - cClock.facePos/2.), 0), vec2(cClock.diameter/2. - 0.01, cClock.height*cClock.facePos/2. - 0.01));
    clockd = opU(vec2(face, FACE_OBJ), clockd);

    float axis = sdCylinder(pos - vec3(0., cClock.height*cClock.facePos + cClock.axisSize.y*0.5 - 0.25, 0), cClock.axisSize*vec2(1, 0.5));
    clockd = opU(vec2(axis, AXIS_OBJ), clockd);

    #ifdef show_glass
    if (cClock.glassTickness>0.)
    {
       float glass = sdCylinder(pos - vec3(0., cClock.height*0.75 - cClock.glassTickness*0.5 - 0.002, 0), vec2(cClock.diameter/2. - 0.01, cClock.glassTickness*0.5));
       clockd = opU(vec2(glass, GLASS_OBJ), clockd);
    }
    #endif

    return clockd;
}

// Main tracing function
vec2 trace(vec3 cam, vec3 ray, float maxdist, bool inside)
{
    float t = 0.02;
    float objnr = 0.;
    vec3 pos;
    float dist;
    float dist2;

  	for (int i = 0; i < 128; ++i)
    {
    	pos = ray*t + cam;
        vec2 res = map(pos);
        dist = inside?-res.x:res.x;
        if (dist>maxdist || abs(dist)<0.000005)
            break;
        t+= dist*0.5;
        objnr = abs(res.y);
  	}
  	return vec2(t, objnr);
}

// From https://www.shadertoy.com/view/MstGDM
// Here the texture maping is only used for the normal, not the raymarching, so it's a kind of bump mapping. Much faster
vec3 getNormal(vec3 pos, float e, bool inside)
{
    vec2 q = vec2(0, e);
    return (inside?-1.:1.)*normalize(vec3(map(pos + q.yxx).x - map(pos - q.yxx).x,
                          map(pos + q.xyx).x - map(pos - q.xyx).x,
                          map(pos + q.xxy).x - map(pos - q.xxy).x));
}

// Gets the color of the sky
vec3 sky_color(vec3 ray)
{
	vec3 rc = 1.5*texture(iChannel0, ray).rgb;
    return rc;
}

// Gets the color of the sky
vec3 sky_color_s(vec3 ray)
{
	vec3 rc = 0.2 + vec3(4.5, 4.9, 4.5)*texture(iChannel1, ray).rgb;
    return rc;
}

bool isInTick(vec3 pos, FaceTicks ticks)
{
    if (ticks.type==0)
        return false;
    else if (ticks.type==1)
    {
        float l = length(pos.xz)/(cClock.diameter/2. - cClock.caseThickness);
        float angle = mod(atan(pos.x, pos.z) - 0.259, radians(ticks.tstep));
        return (2.*abs(angle - radians(ticks.tstep)/2.)<radians(ticks.size.y)*(1. + (1./l - 1.)) && l<ticks.outPos && l>ticks.outPos-ticks.size.x);
    }
    else
    {
        float angle = mod(atan(pos.x, pos.z) + radians(ticks.tstep)/2., radians(ticks.tstep)) - radians(ticks.tstep)/2.;
        //ticks.outPos*(cClock.diameter/2. - cClock.caseThickness)
        vec2 pos2 = length(pos.xz)*vec2(cos(angle), sin(angle));
        return distance(pos2, vec2(ticks.outPos*(cClock.diameter/2. - cClock.caseThickness), 0.))*60.<ticks.size.y;
    }
}

vec3 getTicksColor(vec3 pos, Clock clock)
{
    return isInTick(pos, clock.hourTicks)?clock.hourTicks.color:(isInTick(pos, clock.minuteTicks)?clock.minuteTicks.color:clock.faceColor);
    //return isInTick(pos, clock.hourTicks)?vec3(0.1):vec3(0.9);
}

// Combines the colors
vec3 getColor(vec3 norm, vec3 pos, int objnr)
{
    pos = pos.xzy;
    pos = rotateVec2(pos);

    vec3 col = objnr==CASE_OBJ?cClock.caseColor:(
               objnr==FACE_OBJ?getTicksColor(pos, cClock):(
               objnr==AXIS_OBJ?cClock.axisColor:(
               objnr==SHAND_OBJ?cClock.secondsHand.color:(
               objnr==MHAND_OBJ?cClock.minutesHand.color:(
               objnr==HHAND_OBJ?cClock.hoursHand.color:vec3(0.))))));
    return col;
}

// Gets the flares of the lamps (kind of non-reflective specular...)
vec3 getFlares(vec3 ray)
{
	vec3 rc = vec3(0.);
    #ifdef bulb
    rc+= 1.6*clamp(normalize(lamps[1].color)*lamps[1].intensity*specint*pow(max(0.0, dot(ray, normalize(lamps[1].position - campos))), 150.), 0., 1.);
    #endif
    return rc;
}

// From https://www.shadertoy.com/view/Xds3zN, but I changed the code
float softshadow(vec3 ro, vec3 rd, float mint, float tmax)
{
	float res = 1.0;
    float t = mint;
    for(int i=0; i<50; i++)
    {
    	float h = map(ro + rd*t).x;
        res = min(res, 10.0*h/t + 0.02*float(i));
        t += 0.8*clamp(h, 0.01, 0.35);
        if( h<0.001 || t>tmax ) break;
    }
    return clamp( res, 0.0, 1.0 );
}

// From https://www.shadertoy.com/view/Xds3zN
float calcAO(in vec3 pos, in vec3 nor)
{
	float occ = 0.0;
    float sca = 1.0;
    for(int i=0; i<6; i++)
    {
        float hr = 0.01 + 0.12*float(i)/9.0;
        vec3 aopos =  nor*hr + pos;
        float dd = map(aopos).x;
        occ+= -(dd - hr)*sca;
        sca*= 0.85;
    }
    occ = 2.*smoothstep(0.06, 0.5, occ);
    return clamp( 1.0 - 3.0*occ, 0.0, 1.0 );
}

// Fresnel reflectance factor through Schlick's approximation: https://en.wikipedia.org/wiki/Schlick's_approximation
float fresnel(vec3 ray, vec3 norm, float n2)
{
   float n1 = 1.; // air
   float angle = acos(-dot(ray, norm));
   float r0 = dot((n1-n2)/(n1+n2), (n1-n2)/(n1+n2));
   float r = r0 + (1. - r0)*pow(1. - cos(angle), 5.);
   return r;
}

// Shading of the objects pro lamp
vec3 lampShading(Lamp lamp, vec3 norm, vec3 pos, vec3 ocol, int objnr, int lampnr)
{
	vec3 pl = normalize(lamp.position - pos);
    float dlp = distance(lamp.position, pos);
    vec3 pli = pl/pow(1. + lamp.attenuation*dlp, 2.);

    // Diffuse shading
    vec3 col = ocol*lamp.color*lamp.intensity*smoothstep(-0.1, 1., dot(norm, pli));

    // Specular shading
    #ifdef specular
    if (dot(norm, lamp.position - pos) > 0.0)
        col+= lamp.color*lamp.intensity*specint*pow(max(0.0, dot(reflect(pl, norm), normalize(pos - campos))), specshin);
    #endif

    // Softshadow
    #ifdef shadow
    col*= shi*softshadow(pos, normalize(vec3(lamp.position.x, 4.9, lamp.position.z) - pos), shf, 100.) + 1. - shi;
    #endif

    return col;
}

// Shading of the objects over all lamps
vec3 lampsShading(vec3 norm, vec3 pos, vec3 ocol, int objnr)
{
    vec3 col = vec3(0.);
    for (int l=0; l<3; l++) // lamps.length()
        col+= lampShading(lamps[l], norm, pos, ocol, objnr, l);

    return col;
}

// From https://www.shadertoy.com/view/lsSXzD, modified
vec3 GetCameraRayDir(vec2 vWindow, vec3 vCameraDir, float fov)
{
	vec3 vForward = normalize(vCameraDir);
	vec3 vRight = normalize(cross(vec3(0.0, 1.0, 0.0), vForward));
	vec3 vUp = normalize(cross(vForward, vRight));

	vec3 vDir = normalize(vWindow.x * vRight + vWindow.y * vUp + vForward * fov);

	return vDir;
}

// Tracing and rendering a ray
RenderData trace0(vec3 tpos, vec3 ray, float maxdist, bool inside, bool reflect)
{
    vec2 tr = trace(tpos, ray, maxdist, inside);
    float tx = tr.x;
    int objnr = int(tr.y);
    vec3 col;
    vec3 pos = tpos + tx*ray;
    vec3 norm;

    lamps[0] = Lamp(vec3(-2., 5., 20.), vec3(1., 1., 1.), 1.8, 0.01);
    lamps[1] = Lamp(vec3(-5., 3, -12.), vec3(1., .95, .75), 0.9, 0.01);
    lamps[2] = Lamp(vec3(16., 5., -8.), vec3(1., .6, .5), 0.7, 0.01);

    if (tx<maxdist)
    {
        norm = getNormal(pos, normdelta, inside);
        col = getColor(norm, pos, objnr);

        // Shading
        col = ambientColor*ambientint + lampsShading(norm, pos, col, objnr);

        // Ambient occlusion
        #ifdef ambocc
        col*= 1. - aoint + aoint*vec3(calcAO(pos, norm));
        //col = vec3(calcAO(pos, norm));
        #endif
    }
    else
    {
        objnr = SKY_OBJ;
        if (reflect)
        	col = sky_color_s(ray);
        else
            col = sky_color(ray);
    }
    return RenderData(col, pos, norm, objnr);
}

// Main render function with reflections
vec4 render(vec2 fragCoord)
{
  vec2 uv = fragCoord.xy / iResolution.xy;
  uv = uv*2.0 - 1.0;
  uv.x*= iResolution.x / iResolution.y;

  vec3 ray = GetCameraRayDir(uv, camdir, fov);

  RenderData traceinf = trace0(campos, ray, maxdist, false, false);
  vec3 col = traceinf.col; // + getFlares(ray);
  #ifdef reflections
  for (int i=0; i<nbref; i++)
  {
      vec3 refray = reflect(ray, traceinf.norm);
  	  if (traceinf.objnr==CASE_OBJ || (traceinf.objnr==SHAND_OBJ && cClock.secondsHand.metallic) || (traceinf.objnr==MHAND_OBJ && cClock.minutesHand.metallic) || (traceinf.objnr==HHAND_OBJ && cClock.hoursHand.metallic))
      {
          RenderData traceinf_ref = trace0(traceinf.pos, refray, 20., false, traceinf.objnr==CASE_OBJ);
          float r = 0.5;
          col = mix(col, col*traceinf_ref.col, r);

          ray = refray;
          traceinf = traceinf_ref;
      }
  }
  #endif
  #ifdef show_glass
  bool inside = true;
  float cior = glass_ior;
  vec3 glassf = vec3(1.);
  if (traceinf.objnr==GLASS_OBJ)
  {
  		vec3 norm = traceinf.norm;
        vec3 ray_r = refract(ray, traceinf.norm, 1./glass_ior);
        vec3 ray_r2;

        int n2;
        for (int n=0; n<nbrefr; n++)
        {
            vec3 posr = traceinf.pos;
        	traceinf = trace0(posr, ray_r, 20., inside, false);

            if (inside)
                glassf*= cClock.glassColor;
            else
                traceinf.col+= getFlares(ray_r);

            col+= traceinf.col*glassf;
            col = clamp(col, 0., 1.);

            if (traceinf.objnr==GLASS_OBJ)
            {
      		    ray_r2 = refract(ray_r, traceinf.norm, cior);
        	    if (length(ray_r2)!=0.)
                {
                    inside = !inside;
                    cior = 1./cior;
                }
                else
                    ray_r2 = reflect(ray_r, traceinf.norm);
            }
            else
            {
                col = traceinf.col*glassf;
                break;
            }
            ray_r = ray_r2;
            n2 = n;
        }

        if ((traceinf.objnr==SHAND_OBJ && cClock.secondsHand.metallic) || (traceinf.objnr==MHAND_OBJ && cClock.minutesHand.metallic) || (traceinf.objnr==HHAND_OBJ && cClock.hoursHand.metallic))
        {
           vec3 refray = reflect(ray_r, traceinf.norm);
           float r = 0.5;
           col = mix(col, col*sky_color(refray), r);
        }
        // Outer reflection
        float r = fresnel(ray, norm, glass_ior);
        col = mix(col, sky_color(reflect(ray, norm)), r);
  }
  #endif

  return vec4(col, 1.0);
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    initClock();

    vec2 iMouse2;
    if (iMouse.x==0. && iMouse.y==0.)
       iMouse2 = iResolution.xy*vec2(0.5, 0.5);
    else
       iMouse2 = iMouse.xy;
    angle = 2.*pi*(iMouse2.x/iResolution.x - 0.5);
    angle2 = -2.*pi*(iMouse2.y/iResolution.y - 0.5);

    // Antialiasing.
    vec4 vs = vec4(0.);
    for (int j=0;j<aasamples ;j++)
    {
       float oy = float(j)*aawidth/max(float(aasamples-1), 1.);
       for (int i=0;i<aasamples ;i++)
       {
          float ox = float(i)*aawidth/max(float(aasamples-1), 1.);
          vs+= render(fragCoord + vec2(ox, oy));
       }
    }
    vec2 uv = fragCoord.xy / iResolution.xy;

    fragColor = vs/vec4(aasamples*aasamples);
}
