#version 150 compatibility

// fragment shader for map rendering

// https://learnopengl.com/Lighting/Basic-Lighting

// TODO: light parameters.

uniform vec2 u_resolution;  // Canvas size (width,height)
uniform vec2 u_mouse;       // mouse position in screen pixels
uniform float u_time;       // Time in seconds since load

uniform int ShadowsPass;
uniform float AmbientLighting; // minimum ambient brightness 0..1, even in shadows
uniform float ShadowSharpness; // adjusting this gives more blurred shadows.. this value is in relation to how big shadow is (dimensions of world).

uniform sampler2D ShadowMap;
varying vec4 ShadowCoord_LightSpace;

//uniform mat4 view_matrix;

uniform sampler2D Texture1; // need
uniform vec3 PlayerPosition;
uniform vec3 CameraVector;
varying vec3 Playercheckcoords; // need

varying vec3 normcoords;
varying vec3 vPos;

// Passed in from the vertex shader.
varying vec2 v_texcoord;
varying vec4 VertexColor;
varying vec3 vertexcoords; // need

uniform int UndergroundMode;
uniform float UndergroundIntensity;

void main() {
	
	// Get fragment color
	vec4 color = texture2D(Texture1, gl_TexCoord[0].st);
	
	// Produce cone shaped holes in ground, to see thru ceilings
	if (UndergroundIntensity > 0.0) {
		
		vec3 comparison = vertexcoords.xyz;
		float maxdist = 3.0;
		vec3 checkpcoords = Playercheckcoords;
		checkpcoords.z += maxdist;
		
		float Dist2D = distance(checkpcoords.xy, comparison.xy);
		float dist3d = distance(checkpcoords.xyz, comparison.xyz);
		
		// discard based on sort of cone shape, 0.4 is minimum height at which the effect starts.
		
		float offset = 0.0;
		
		if (UndergroundMode > 1) // /* + 0.4 USE THIS WHEN STANDING ON angled surfaces. */
			offset = 0.4;
		
		if ( (Dist2D < maxdist) && (comparison.z > (Playercheckcoords.z + offset) + (Dist2D * 0.25)) ) {
			
			maxdist = exp2(dist3d);
			
			float how_much_alpha = (Dist2D * 0.35 /*(1.0 /maxdist)*/);
			
			color.a = color.a * (how_much_alpha + (1.0 - UndergroundIntensity) );
			
		}
		
	}
	
	float shadow = 1.0;
	
	if (ShadowsPass != 0) {
		
		vec4 shadowCoordinateWdivide = ShadowCoord_LightSpace; // dividing - / ShadowCoord_LightSpace.w  is needed only for projected lights?
		
		float bias = 0.001 * 0.4;
		
		// Debugging if shadow mapping projection is correct.
		// gl_FragColor = texture2D(ShadowMap, shadowCoordinateWdivide.st); //  + (color * 0.5)
		
		/*
		
		// primitive technique:
		// Used to lower moiré pattern and self-shadowing
		// shadowCoordinateWdivide.z -= bias;
		float distanceFromLight = texture2D(ShadowMap, shadowCoordinateWdivide.st).r; // was .z
		
	 	if (ShadowCoord_LightSpace.w > 0.0) // This is when we try to sample value behind the light's view frustrum.
	 		shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.5 : 1.0;
		
		*/
		
		// poisson disk, small:
		/*
		vec2 poissonDisk[4] = vec2[](
			vec2( -0.94201624, -0.39906216 ),
			vec2( 0.94558609, -0.76890725 ),
			vec2( -0.094184101, -0.92938870 ),
			vec2( 0.34495938, 0.29387760 )
		);
		*/
		
		// poisson disk, large:
		int num_samples = 16;
		
		vec2 poissonDisk[16] = vec2[]( 
		   vec2( -0.94201624, -0.39906216 ), 
		   vec2( 0.94558609, -0.76890725 ), 
		   vec2( -0.094184101, -0.92938870 ), 
		   vec2( 0.34495938, 0.29387760 ), 
		   vec2( -0.91588581, 0.45771432 ), 
		   vec2( -0.81544232, -0.87912464 ), 
		   vec2( -0.38277543, 0.27676845 ), 
		   vec2( 0.97484398, 0.75648379 ), 
		   vec2( 0.44323325, -0.97511554 ), 
		   vec2( 0.53742981, -0.47373420 ), 
		   vec2( -0.26496911, -0.41893023 ), 
		   vec2( 0.79197514, 0.19090188 ), 
		   vec2( -0.24188840, 0.99706507 ), 
		   vec2( -0.81409955, 0.91437590 ), 
		   vec2( 0.19984126, 0.78641367 ), 
		   vec2( 0.14383161, -0.14100790 ) 
		);
		
		float poisson_divider = 700.0 * ShadowSharpness; // adjusting this gives more blurred shadows.. this value is in relation to how big shadow is (dimensions of world).
		
		for (int i = 0; i < num_samples; i++) {
			if ( texture( ShadowMap, shadowCoordinateWdivide.st + poissonDisk[i] / poisson_divider ).r  < shadowCoordinateWdivide.z - bias ){
				shadow -= (1.0 / num_samples);
			}
		}
		
		// Take ambient brightness into account
	  	shadow = AmbientLighting + (shadow * (1.0 - AmbientLighting));
	}
  	
	gl_FragColor = vec4(color.r * shadow, color.g * shadow, color.b * shadow, color.a);
	
	//gl_FragColor = shadow * color; // todo: *VertexColor* todo: lighting
	
}
