// Shadow mapping utility functions

float inShadow(vec3 lightclip, float bias)
{	

	vec2 add = vec2(
	noise(vec3(lightclip.x, lightclip.y, p_beat)), 
	noise(vec3(p_beat, lightclip.x, p_beat))
	);
	
	lightclip.xy += add * 0.001;

	float val = 0.0f;
	val += (textureOffset(shadowbuffer, lightclip.xy, ivec2(-1, 0)).x - lightclip.z - bias) > 0.0 ? 1.0 : 0.0;
	val += (textureOffset(shadowbuffer, lightclip.xy, ivec2( 1, 0)).x - lightclip.z - bias) > 0.0 ? 1.0 : 0.0;
	val += (textureOffset(shadowbuffer, lightclip.xy, ivec2( 0, 1)).x - lightclip.z - bias) > 0.0 ? 1.0 : 0.0;
	val += (textureOffset(shadowbuffer, lightclip.xy, ivec2( 0,-1)).x - lightclip.z - bias) > 0.0 ? 1.0 : 0.0;
	
	return val / 4.0;
}

vec3 accumulate_light(Camera cam, vec4 worldpos, vec3 lightclip, vec3 normal, float specularExponent, float specularMult, 
float particle)
{
	vec3 accum = vec3(0.0);

	for (int i=0;i<MAX_LIGHTS;i++) {
		if (!lights.spot[i].enabled)
			continue;
		
		vec3 point_to_cam = cam.pos - worldpos.xyz;
		vec3 point_to_lamp = lights.spot[i].pos - worldpos.xyz;
		vec3 halfway = normalize(point_to_lamp + point_to_cam);
		
		vec3 light_dir = normalize(point_to_lamp);
		float cone = max(0.0, pow((dot(-light_dir, normalize(lights.spot[i].dir)) - 0.87)*10.0, 1.0));
		float reach = (1.0/pow(length(point_to_lamp), 2.0)) * lights.spot[i].falloff;
		vec3 raito = vec3(0.0);
		vec3 color = lights.spot[i].intensity;
		//color = vec3(1.0, 0.0, 1.0);
		if (particle == 1.0) {
			raito += cone * color;
			raito *= reach;
		} else {
			float diffuse = max(0.0, dot(normal, light_dir));
			float specular = cone * pow(max(0.0, dot(normal, halfway)), specularExponent);
			vec3 specular_color = color;
			
			raito = color * diffuse * cone;
			
			raito *= reach;
			raito += specular * specular_color * 8.0 * specularMult;
		}
		
		if (i == SHADOW_SPOT_INDEX && !(lightclip.x > 1 || lightclip.x < 0 || lightclip.y < 0 || lightclip.y > 1)) {
			raito *= inShadow(lightclip, -0.0002);	
		}

		accum += raito;
	}

	return accum; 
}

vec3 lightViewToClip(vec4 lightview)
{
	vec3 lightclip = (lightview / lightview.w).xyz; // perform w division, now we've got clip space stuff
	lightclip.xyz = lightclip.xyz * 0.5 + vec3(0.5); // map from [-1,1] range to [0,1]
	return lightclip;
}