#version 330 core

// inputz
in vec2 UV;

uniform vec2 iResolution;
uniform float iTime;

// outputz
out vec4 fragColor;

// The MIT License
// Copyright © 2017 Inigo Quilez
// remixed by noby
vec3 tri( in vec3 x )
{
    return 1.0-abs(2.0*fract(x/2.0)-1.0);
}

float anim;
float checkersTextureGrad( in vec3 p, in vec3 ddx, in vec3 ddy )
{
    if(length(floor(p)) > pow(smoothstep(-0.075,0.85,anim),1.25)*100.0 && anim < 0.3)
        return 1.0;
    vec3 w = max(abs(ddx), abs(ddy)) + 0.0001; // filter kernel
    vec3 i = (tri(p+0.5*w)-tri(p-0.5*w))/w;    // analytical integral (box filter)
    return 0.5 - 0.5*(i.x*i.y*i.z);            // xor pattern
}

float intersect( vec3 ro, vec3 rd, out vec3 pos, out vec3 nor, out float occ, out float matid )
{
    // raytrace
    float tmin = 1000.0;
    nor = vec3(0.0);
    occ = 1.0;
    pos = vec3(0.0);
    
    // raytrace-plane
    float h = (0.001-ro.y)/rd.y;
    if(h > 0.0) 
    { 
        tmin = h;
        pos = ro + h*rd;
        nor = vec3(0, 1, 0);
        /*
        vec3 T = texture(iChannel1, pos.xz*0.0639).rgb*0.5;
        T += texture(iChannel1, pos.xz*0.121).rgb*0.25;
        T += texture(iChannel1, pos.xz*0.27).rgb*0.125;
        nor = normalize( vec3(T.x,15.0,T.z) );
        */
    }
    
    return tmin;
}

vec3 texCoords( in vec3 p )
{
    return 2.0*p;
}

void calcCamera( out vec3 ro, out vec3 ta )
{
    float an = mix(1.0,0.05,pow(anim, 1.0/6.0));
    ro = vec3( 5.5*cos(an), mix(12.0,0.5,pow(anim,0.15)), 5.5*sin(an) );
    ta = vec3( 0.0, 0.1, 0.0 );
}

void calcRayForPixel( vec2 pix, out vec3 resRo, out vec3 resRd )
{
    vec2 p = (-iResolution.xy + 2.0*pix) / iResolution.y;
    
     // camera movement 
    vec3 ro, ta;
    calcCamera( ro, ta );
    // camera matrix
    vec3 ww = normalize( ta - ro );
    vec3 uu = normalize( cross(ww,vec3(0.0,1.0,0.0) ) );
    vec3 vv = normalize( cross(uu,ww));
    // create view ray
    vec3 rd = normalize( p.x*uu + p.y*vv + mix(7.5,3.5,pow(anim,0.15))*ww );
    
    resRo = ro;
    resRd = rd;
}


void main()
{
    vec2  p  = (-iResolution.xy + 2.0*UV*iResolution) / iResolution.y;
    anim = smoothstep(-0.1, 1.75,mod(iTime/3.0,1.0));
    vec3 ro, rd, ddx_ro, ddx_rd, ddy_ro, ddy_rd;
    calcRayForPixel( UV * iResolution + vec2(0.0,0.0), ro, rd );
    calcRayForPixel( UV * iResolution + vec2(1.0,0.0), ddx_ro, ddx_rd );
    calcRayForPixel( UV * iResolution + vec2(0.0,1.0), ddy_ro, ddy_rd );
    
    // trace
    vec3 pos, nor;
    float occ, mid;
    float t = intersect( ro, rd, pos, nor, occ, mid );

    const float fc = 0.5;
    vec3 col = vec3(fc);
    if( t<100.0 )
    {
        // computer ray differentials
        vec3 ddx_pos = ddx_ro - ddx_rd*dot(ddx_ro-pos,nor)/dot(ddx_rd,nor);
        vec3 ddy_pos = ddy_ro - ddy_rd*dot(ddy_ro-pos,nor)/dot(ddy_rd,nor);

        float df = mix(1.0,4.0,pow(smoothstep(15.0,50.0,t),2.0));
        vec3 uvw = texCoords( pos );    
        vec3 ddx_uvw = dFdx( uvw )*df;
        vec3 ddy_uvw = dFdy( uvw )*df;
        
        // shading      
        vec3 mate = vec3(1.0)*checkersTextureGrad( uvw, ddx_uvw, ddy_uvw ); 
        col = mate;
        
        /*
        vec3 r = reflect(rd, nor);
        float ndot = max(0.0, dot(nor, r));
        float F = pow((1.0 - ndot), 5.0);
        //col += pow(1.0-col,vec3(4))*texture(iChannel0, reflect(rd, normalize(mix(nor,vec3(0,1,0),F)) ).zyx).rgb*F;
        col += vec3(0.5)*smoothstep(-0.90,-0.915,r.x)*F;
        */
        col = mix( col, vec3(fc), 1.0-exp(-0.0005*t*t ) );
    }
    
    // gamma correction 
    col = pow( col, vec3(0.4545) );
    fragColor = vec4( col, 1.0 );
}
