#version 450 core

#define PI 3.14159265358979323846

// inputs 
in vec2 texCoord;

// outputs
out vec4 fragColor;

// uniforms
uniform sampler2D   t_texture0;
uniform float 	    g_time;
uniform ivec3       g_resolution;

// ------------------------------------------

float rand(vec2 co){
    return 2*fract(sin(dot(co, vec2(12.9898, 16.4495))) * 43758.5453)-.5;
}

vec4 hash4(vec2 a) {
	return vec4(
		rand(a.xx), rand(a.xy), rand(a.yx), rand(a.yy)
	);
}

// base grid size for 320x200 is 8x8px, rescale for any other resolution
vec2  vRes      = vec2(640., 320.);
float vGridSize = 8.;
float gridSize  = (g_resolution.x / vRes.x) * vGridSize;

// interpolation stuff

struct uvColor {
    vec2 uv;
    vec3 color;
};

float t = g_time;

uvColor corners[4] = uvColor[4](uvColor(vec2(0.0), vec3(0.0)),
                                uvColor(vec2(0.0), vec3(0.0)),
                                uvColor(vec2(0.0), vec3(0.0)),
                                uvColor(vec2(0.0), vec3(0.0)));


mat2 rotate(float a) {return mat2(cos(a), -sin(a), sin(a), cos(a));}
vec3 rotateXYZ(vec3 o, vec3 a) {
	o.yz *= rotate(a.x);
	o.xz *= rotate(a.y);
	o.xy *= rotate(a.z);
	
	return o;
}

vec3 rotateZYX(vec3 o, vec3 a) {
	o.xy *= rotate(a.z);
	o.xz *= rotate(a.y);
	o.yz *= rotate(a.x);
	
	return o;
}

// uv means grid uv coordinates
void trace(vec2 uv, out uvColor rtn) {
   
#if 0
    float dist = 160;
    float planeDist = 30.;
    float lightStrength = 50.4;
    
    vec3 origin = vec3(5 * planeDist * sin(t*1.2), -1, (t*60.2));
    vec3 direction;
    direction.xy = uv * vGridSize * (1. / dist);
    direction.z  = 1;
    
    //direction = rotateXYZ(normalize(direction), vec3(-PI/2,0,0));
    direction = normalize(direction);
    
    float t = (planeDist) / abs(0.0*origin.y + (direction.y));
    vec3 p = origin + t*direction;
    
    rtn.uv = 0.005*p.xz;
    
    float att = (planeDist * lightStrength) / (t); 
    att = (att)/(att+.2);
    
    rtn.uv = (textureSize(t_texture0, 1) * rtn.uv);
    rtn.color = vec3(att);
    //rtn.color = vec3(1.0);
#endif

#if 1
    
    float a = 1.0;
    //uv = mod(uv, vec2(256.0));
    //uv -= vec2(sin(t*0.3), cos(t*0.7));
	uv *= 0.1*(.8+.5*sin(t*0.3))*rotate(t*0.5);
	uv *= rotate(t*0.2);
	float b = 1.*sin(t*1.6+cos(t*0.7)+uv.y*4.3*(0.2*sin(t*0.2+length(.08*uv*(.4+t*0.1))*4.3)));
	uv += 0.6*vec2(
		sin(t*0.52)*sin(t*0.64)*cos(t*0.437)+sin(t*0.33)*cos(t*0.42),
		cos(t*0.44)*sin(t*0.85)*sin(t*0.573)+sin(t*0.26)*sin(t*0.24)
	);

    rtn.uv = uv*(.4*b+.2);
    rtn.uv *= rotate(-t*1.3);
    rtn.uv += 1.0 * vec2(
    	sin(t*0.2)*sin(t*0.6)*cos(t*0.4)+sin(t*0.3)*cos(t*0.2),
		cos(t*0.4)*sin(t*0.8)*sin(t*0.5)+sin(t*0.2)*sin(t*0.1)
    );
    rtn.uv += 256.;
    rtn.uv = (textureSize(t_texture0, 1) * rtn.uv);
    rtn.color = 4.9*vec3(.5*b+.5);
    
#endif
}


vec3 interpolate(vec2 grid) {
    // vetical
    uvColor left  = uvColor(mix(corners[0].uv,    corners[2].uv,    fract(grid.y)),
                            mix(corners[0].color, corners[2].color, fract(grid.y)));
    uvColor right = uvColor(mix(corners[1].uv,    corners[3].uv,    fract(grid.y)),
                            mix(corners[1].color, corners[3].color, fract(grid.y)));
    // horizontal
    uvColor rtn   = uvColor(mix(left.uv,    right.uv,    fract(grid.x)),
                            mix(left.color, right.color, fract(grid.x)));
                            
    //return textureLod(t_texture0, rtn.uv / textureSize(t_texture0, 1), 1.).rgb * rtn.color;
    return texture(t_texture0, rtn.uv / textureSize(t_texture0, 1)).rgb * 
    (corners[0].color + corners[1].color + corners[2].color + corners[3].color)*0.25;
    //return vec3(mod(rtn.uv / textureSize(t_texture0, 1), 1.), 0.0);
}


void main(void) {  
    vec2 uv = (texCoord - .5) * g_resolution.xy;
    
    vec2 uvgrid = vec2(uv.x / gridSize,
                       uv.y / gridSize);
    
#if 0
    uvColor outGrid;
    trace((uvgrid), outGrid);
    //vec3 outColor = texture(t_texture0, outGrid.uv / textureSize(t_texture0, 1)).rgb;
    vec3 outColor = texture(t_texture0, outGrid.uv / textureSize(t_texture0, 1)).rgb;
  
#else
    // trace corners
    trace(floor(uvgrid + vec2(0, 0)), corners[0]);
    trace(floor(uvgrid + vec2(1, 0)), corners[1]);
    trace(floor(uvgrid + vec2(0, 1)), corners[2]);
    trace(floor(uvgrid + vec2(1, 1)), corners[3]);
       
    // interpolate
    //vec3 outColor = vec3(fract(uvgrid.x), fract(uvgrid.y), 0.0);
    //vec3 outColor = texture(t_texture0, corners[0].uv / textureSize(t_texture0, 1)).rgb;
    vec3 outColor = interpolate(uvgrid);
    
    /* 
    fragColor = mod(vec4(corners[0].uv.x / textureSize(t_texture0, 1).x,
                         corners[1].uv.x / textureSize(t_texture0, 1).x,
                         corners[2].uv.x / textureSize(t_texture0, 1).x,
                         corners[3].uv.x / textureSize(t_texture0, 1).x), vec4(1.0));
    */
    /*
    vec3 outColor = vec3(
                         mod(corners[0].uv.x / textureSize(t_texture0, 1).x, 1.),
                         mod(corners[2].uv.x / textureSize(t_texture0, 1).x, 1.),
                         mod(corners[0].uv.x / textureSize(t_texture0, 1).x, 1.)
                         );
                         */
#endif    
    
    //fragColor = vec4(outColor, 1.0);
    outColor *= vec3(0.9+0.1*texCoord.y*sin(texCoord.x*texCoord.y*62.0)*cos(texCoord.x+texCoord.y*25.0),
                     0.9+0.1*texCoord.y*sin(texCoord.x*texCoord.y*52.0)*cos(texCoord.x+texCoord.y*72.0),
                     0.9+0.1*texCoord.y*sin(texCoord.x*texCoord.y*37.0)*cos(texCoord.x+texCoord.y*85.0)
                    );
    fragColor = vec4(outColor, 1.0);
}















