/**
 *
 * Diplomova prace
 * Stinove techniky na dnesnim hardware a jejich porovnani
 *
 * Michal Toth
 *
 * Fakulta informacnich technologii
 * Vysoke uceni technicke v Brne
 *
 * 2013/2014
 *
 */

/*
 * Fragment shader pro stinove mapy s cubemapou
 * s PCF filtraci pro mekke stiny
 */

#version 420

layout(early_fragment_tests) in;
in vec3 position;
in vec3 normal;
in vec2 tc;

uniform sampler2D KaTex;
uniform vec3 Ka;
uniform vec3 La;
uniform vec3 Ld;
uniform vec3 Ls;
uniform vec3 lightPos;
uniform vec3 cameraPos;

uniform samplerCubeShadow  shadowTexture;
uniform float far;
uniform float near;
uniform float offset;
uniform int filterSize=3;
uniform float dt=1.0/1024;

out vec4 fragColor;

uniform float shininess=32;



float depth(vec3 dir)
{
    vec3 absDir = abs(dir);
    float z = max(absDir.x, max(absDir.y, absDir.z));
    float c = (far+near) / (far-near) - (2*far*near)/(far-near)/z;
    return (c + 1.0) * 0.5;
}

float getShadow(){
    vec3 dir = position-lightPos;
    vec3 ndir ;//= normalize(dir);
    vec3 absDir = abs(dir);

    float sum=0;
    int d=filterSize/2;

    // vypocitavani smseru pro ziskani offsetu,
    // u cubemapy nejde jednoduse textureOffset +1 na ziskani vedlejsiho pixelu
    bool xo = absDir.x>=absDir.y && absDir.x>=absDir.z;
    bool yo = absDir.y>=absDir.x && absDir.y>=absDir.z;
    bool zo = absDir.z>=absDir.x && absDir.z>=absDir.y;
    if(xo){
	ndir = dir/absDir.x;
    }
    if(yo){
	ndir = dir/absDir.y;
    }
    if(zo){
	ndir = dir/absDir.z;
    }

    for(int x=-d;x<=d;x+=1){
	for(int y=-d;y<=d;y+=1){
	    vec3 d=vec3(0,0,0);
	    if(xo){
		d = vec3(0,x*dt,y*dt);
	    }
	    if(yo){
		d = vec3(x*dt,0,y*dt);
	    }
	    if(zo){
		d = vec3(x*dt,y*dt,0);
	    }
	    sum+=texture(shadowTexture,vec4(ndir+d*3,depth(dir)-offset)).x;
	}
    }
    return sum/(filterSize*filterSize);
}


void main() {
    float sh = getShadow();

    vec3 col = Ka+texture(KaTex,tc).rgb;

    vec3 N = normalize(normal);
    vec3 L = normalize(lightPos-position);
    vec3 A = La*col;
    vec3 D = Ld*max(dot(L,N),0)*col;
    vec3 S = vec3(0,0,0);
    if(shininess>0){
	vec3 V = normalize(cameraPos-position);
	vec3 R = reflect(-L,N);
	float spec = pow(max(0,dot(R,V)),shininess);
	S = spec*Ls;
    }

    fragColor = vec4(A+(D+S)*sh,1);
}
