#version 330 core

layout(location=0) out vec4 vFragColor;	//wyjście shadera fragmentów

//uniformy
uniform mat4 MV;				//macierz modelu i widoku
uniform sampler2D  shadowMap;		//tekstura mapy cienia
uniform vec3 light_position;	//położenie światła w przestrzeni obiektu
uniform vec3 diffuse_color;		//kolor światła rozpraszanego
									 
//dane wejściowe z shadera wierzchołków
smooth in vec3 vEyeSpaceNormal;	        //interpolowany wektor normalny w przestrzeni oka      
smooth in vec3 vEyeSpacePosition;	//interpolowane położenie wierzchołka w przestrzeni oka
smooth in vec4 vShadowCoords;		//interpolowane współrzędne cienia

//stałe shadera
const float k0 = 1.0;	//wygaszanie stałe
const float k1 = 0.0;	//wygaszanie liniowe
const float k2 = 0.0;	//wygaszanie kwadratowe

void main() {   

	//wyznaczanie położenia swiatła w przestrzeni oka
	vec4 vEyeSpaceLightPosition = (MV*vec4(light_position,1));
	
	//wyznaczanie wektora światła
	vec3 L = (vEyeSpaceLightPosition.xyz-vEyeSpacePosition);
	
	//Wyznaczanie odległości do źródła światła
	float d = length(L);

	//normalizacja wektora światła
 	L = normalize(L);

	//obliczanie składowej rozproszenia i wprowadzenie wygaszania
	float attenuationAmount = 1.0/(k0 + (k1*d) + (k2*d*d));
	float diffuse = max(0, dot(vEyeSpaceNormal, L)) * attenuationAmount;	
	  
	//jeśli współrzędna w jest > 1, jesteśmy w połówce przedniej
	//i należy wygenerować cień. Jeśli usuniesz ten warunek, zobaczysz 
	//cienie po obu stronach źródła światła, gdy będzie ono blisko podłoża  
	//Spróbuj to zrobić, a zobaczysz, co mam na myśli.
	if(vShadowCoords.w>1) {
		
		//dzielenie współrzędnych cienia przez współrzędną w
		vec3 uv = vShadowCoords.xyz/vShadowCoords.w;
		
		//pobieranie wartości głębi
		float depth = uv.z;
		
		//odczytywanie momentów z tekstury mapy cienia
		vec4 moments = texture(shadowMap, uv.xy); 

		//wyznaczanie wariancji z momentów
		float E_x2 = moments.y;
		float Ex_2 = moments.x*moments.x;
		float var = E_x2-Ex_2;

		//obcięcie wariancji
		var = max(var, 0.00002);

		//odejmowanie pierwszego momentu od głębokości fragmentu
		//i dzielenie wariancji przez kwadrat różnicy
		//w celu obliczenia maksymalnego prawdopodobieństwa, że fragment jest w cieniu
		float mD = depth-moments.x;
		float mD_2 = mD*mD; 
		float p_max = var/(var+ mD_2); 

		//przyciemnianie składowej rozproszenia, jeśli bieżąca głębokość jest mniejsza lub równa
		// pierwszemu momentowi i zwracana wielkość jest mniejsza niż 
		//wyliczone maksymalne prawdopodobieństwo
		diffuse *= max(p_max, (depth<=moments.x)?1.0:0.2); 
	}
	//wyprowadzenie iloczynu składowej rozproszenia i koloru rozproszenia 
	//jako kolor bieżącego fragmentu
	vFragColor = diffuse*vec4(diffuse_color, 1);	 
}