const bool shadowcolor0Nearest = true;
const bool shadowcolor1Nearest = true;
const bool shadowtex0Nearest = true;
const bool shadowtex1Nearest = true;
const float shadowDistanceRenderMul = 1.0f;
const bool 	shadowHardwareFiltering0 = true;
const bool 	shadowHardwareFiltering1 = true;

float Depth = texture2D(depthtex0, texcoord).r;
vec3 viewNormal = normalize(texture2D(colortex1, texcoord).stp * 2.0f - 1.0f);

float Diffuse = max(0.0, dot(viewNormal, normalize(shadowLightPosition))); //Diffuse shading

vec2 DistortPosition(in vec2 pos)
{
	vec2 signedPos = pos * 2.0f - 1.0f;

	float dist = sqrt(signedPos.x * signedPos.x + signedPos.y * signedPos.y);
	float distortFactor = (1.0f - SHADOW_MAP_BIAS) + dist * SHADOW_MAP_BIAS;
	signedPos.xy *= 0.95 / distortFactor;

	pos = signedPos * 0.5f + 0.5f;

	return pos;
}

float blueNoise(){
  return fract(texelFetch2D(noisetex, ivec2(gl_FragCoord.xy)%512, 0).a);
}
vec4 ShadowSpace() {
	vec3 ClipSpace = vec3(texcoord, Depth) * 2.0f - 1.0f;
	vec4 ViewW = gbufferProjectionInverse * vec4(ClipSpace, 1.0f);
	vec3 View = ViewW.xyz / ViewW.w;
	vec4 World = gbufferModelViewInverse * vec4(View, 1.0f);
	vec4 ShadowSpace = shadowProjection * shadowModelView * World;
	return ShadowSpace;
}

float Visibility(in sampler2D ShadowMap, in vec3 SampleCoords) {
    return step(SampleCoords.z - 0.001f, texture2D(ShadowMap, SampleCoords.xy).r);
    return clamp(1.0 - max(SampleCoords.z - 0.001f - texture2D(ShadowMap, SampleCoords.xy).x, 0.0) * 4096, 0.0, 1.0);
}

float random(vec3 seed, int i){
	vec4 seed4 = vec4(seed,i);
	float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
	return fract(sin(dot_product) * 43758.5453);
}

vec3 TransparentShadow(in vec3 SampleCoords){
    //float ShadowVisibility0 = Visibility(shadowtex0, SampleCoords);
    float ShadowVisibility = Visibility(shadowtex1, SampleCoords);

    vec4 ShadowColor0 = texture2D(shadowcolor0, SampleCoords.xy);
    vec3 TransmittedColor = ShadowColor0.rgb * (1.0f - ShadowColor0.a);
    return mix(TransmittedColor * ShadowVisibility, sunlightCol, ShadowVisibility);
}

float cloudNoise(float noise, vec3 worldPos){
    return texture2D(noisetex, 0.000015 * (vec2(noise) + frameTimeCounter*1.0 + (worldPos.xz + cameraPosition.xz))).r;
}

float fakeCloudShadow(vec3 worldPos) {
    float shadow = cloudNoise(0.0, worldPos) + cloudNoise(1000.0, worldPos);
	return clamp(pow(shadow, 4.0), 0.0, 1.0);
}

float bayer2(vec2 a){
    a = floor(a);
    return fract( dot(a, vec2(.5, a.y * .75)) );
}

#define bayer4(a)   (bayer2( .5*(a))*.25+bayer2(a))
#define bayer8(a)   (bayer4( .5*(a))*.25+bayer2(a))
#define bayer16(a)  (bayer8( .5*(a))*.25+bayer2(a))
#define bayer32(a)  (bayer16(.5*(a))*.25+bayer2(a))
#define bayer64(a)  (bayer32(.5*(a))*.25+bayer2(a))

float dither64 = bayer64(gl_FragCoord.xy);

#ifdef BlinnPhong
//Phong Reflection https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model#Code_samples
vec3 blinnPhong(float shininess, float strength) {
	vec3 ClipSpace = vec3(texcoord, Depth) * 2.0f - 1.0f;
	vec4 ViewW = gbufferProjectionInverse * vec4(ClipSpace, 1.0f);
	vec3 View = ViewW.xyz / ViewW.w;

	vec3 eyeNormal = normalize(View.xyz);
	vec3 sunNormal = normalize(shadowLightPosition);
    float cosTheta = max(0.0, dot(viewNormal, sunNormal));

    vec3 specular = vec3(0.0);

    if(cosTheta > 0.0) {

       //Normal Phong//
       //vec3 reflectionDirection = reflect(-sunNormal, viewNormal);  
       //specular = sunReflectionCol * pow(max(0.0, dot(reflectionDirection, -eyeNormal)), shininess) * strength * (1 - rainStrength);
        
        //Blinn Phong//
        vec3 halfDir = normalize(sunNormal + eyeNormal*0.8); //multiply eyeNormal to fix a bug that I cant be bothered to find the source of
        float specAngle = max(dot(halfDir, viewNormal), 0.0);
        vec3 reflectionDirection = reflect(-halfDir, viewNormal);  

        specular = vec3(1.0) * clamp(pow(max(0.0, dot(reflectionDirection, -eyeNormal)), shininess) * (1 - rainStrength * 0.3), 0.0, 1.0);
    } 

	return vec3(1.0) - exp(-specular * strength*0.4);;
}
#else
vec3 blinnPhong(float shininess, float strength) {
return vec3(0.0);
}
#endif

////Bounce Light////
#ifdef BounceLight
vec3 backLight(vec3 bounceColor){
	vec3 worldNormal = normalize(texture2D(colortex1, texcoord).stp  * 2.0f - 1.0f);
	vec3 backLight = bounceColor * (-worldNormal.g * BounceAmbient*1.0 + BounceLightFill*6) * (1 - rainStrength * 0.3); //Adds the sunlight and flux colour to backfaces emulating bounce light
		 //backLight *= skyMap;

	return backLight;
}
#else
vec3 backLight(vec3 bounceColor) {
	return vec3(82.0);
}
#endif


////BlinnPhong////
float phongShininess = pshininess;
float phongStrength = pstrength; //(1 + tim2e[5] * 12.0)