#if defined OVERWORLD||defined END
#include "/lib/lighting/shadows.glsl"

vec3 DistortShadow(inout vec3 worldPos,float distortFactor){
    worldPos.xy/=distortFactor;
    worldPos.z*=.2;
    return worldPos*.5+.5;
}
#endif

    vec3 toLinear(vec3 color) {
	return mix(color / 12.92, pow((color + 0.055) / 1.055, vec3(2.4)), vec3(greaterThan(color, vec3(0.04045))));
}

vec3 BlackBody(float Temperature)
{
    float t = pow(Temperature, -1.5);
    float lt = log(Temperature);

    vec3 col = vec3(0.0);
         col.x = 220000.0 * t + 0.58039215686;
         col.y = 0.39231372549 * lt - 2.44549019608;
         col.y = Temperature > 6500. ? 138039.215686 * t + 0.72156862745 : col.y;
         col.z = 0.76078431372 * lt - 5.68078431373;
         col = clamp01(col);
         col = Temperature < 1000. ? col * Temperature * 0.001 : col;

    return toLinear(col);
}

float CurveBlockLight(float blockLight)
{
    float decode=pow(blockLight,1./.25);
    #ifdef LIGHT_JITTER
    const float speed=JITTER_SPEED;
    float jitter1=1.-sin(frameTimeCounter*1.4*speed+cos(frameTimeCounter*6.9*speed)-sin(frameTimeCounter*9.5*speed))*JITTER_STRENGHT1;
    float jitter2=1.-sin(frameTimeCounter*1.4*speed+cos(frameTimeCounter*3.*speed)-sin(frameTimeCounter*4.5*speed))*JITTER_STRENGHT2;
    float jitter3=1.-sin(frameTimeCounter*1.4*speed+cos(frameTimeCounter*1.5*speed)-sin(frameTimeCounter*2.5*speed))*JITTER_STRENGHT3;
    #endif
    
    #ifdef LIGHT_JITTER
    decode*=jitter1*jitter2*jitter3;
    #endif
     
    return decode;
}

void GetLighting(inout vec3 albedo, out vec3 shadow, vec3 viewPos, float lViewPos, vec3 worldPos,
                 vec2 lightmap, float smoothLighting, float NoL, float vanillaDiffuse,
                 float parallaxShadow, float emissive, float foliage,float dither) {

    lightmap.x = max(lightmap.x * 1.15 - 0.15, 0.0);

    vec3 fullShadow = vec3(0.0);

    #if defined OVERWORLD || defined END
    vec3 shadowPos = ToShadow(worldPos);

    float distb = sqrt(shadowPos.x * shadowPos.x + shadowPos.y * shadowPos.y);
    float distortFactor = distb * shadowMapBias + (1.0 - shadowMapBias);
    shadowPos = DistortShadow(shadowPos, distortFactor);

    float doShadow = float(
        shadowPos.x > 0.0 && shadowPos.x < 1.0 &&
        shadowPos.y > 0.0 && shadowPos.y < 1.0
    );

    #ifdef OVERWORLD
    doShadow *= float(lightmap.y > 0.001);
    #endif
    
    if ((NoL > 0.0 || foliage > 0.9)) {
        if (doShadow > 0.5) {
            float NoLm = NoL * 0.99 + 0.01;
            
            float biasFactor = sqrt(1.0 - NoLm * NoLm) / NoLm;
            float distortBias = distortFactor * shadowDistance / 256.0;
            distortBias *= 8.0 * distortBias;
            float distanceBias = sqrt(dot(worldPos.xyz, worldPos.xyz)) * 0.005;
            
            float bias = (distortBias * biasFactor + distanceBias) / shadowMapResolution;
            float offset = 1.0 / shadowMapResolution;

            #ifdef ShadowCloseDithering
            if (AA > 1) dither = fract(frameTimeCounter * (1.0 / 16.0) + dither);
            shadowPos.xyz -= .0025*(dither)/shadowMapResolution*40;
            
            #endif
            
            if (foliage > 0.5) {
                bias = 0.0002;
                offset = 0.0009765625;
            }
            
            shadow=GetShadow(shadowPos,bias,offset);
            
        }else shadow=vec3(lightmap.y);
    }
    shadow*=parallaxShadow;
    
    fullShadow = shadow * max(NoL, foliage);
    
    #ifdef OVERWORLD
    float shadowMult = (1.0 - 0.9 * rainStrength) * shadowFade;

	float shadowTime = worldTime;
	shadowTime -= floor(shadowTime / 24000) * 24000;
	if (shadowTime < 12800) {
		shadowTime = clamp((12800 - shadowTime) / 400, 0.0, 1.0);
	} else if (shadowTime < 23200) {
		if (shadowTime < 18000) shadowTime = clamp((shadowTime - 12800) / 400, 0.0, 1.0);
		if (shadowTime > 18000) shadowTime = clamp((23200 - shadowTime) / 400, 0.0, 1.0);
	} else {
		shadowTime = clamp((shadowTime - 23200) / 400, 0.0, 1.0);
	}
	shadowMult *= clamp(shadowTime*shadowTime, 0.0, 1.0);


    vec3 lightingCol = pow(lightCol, vec3(1.0 + sunVisibility));
	vec3 sceneLighting = mix(ambientCol, lightingCol, fullShadow * shadowMult);
         sceneLighting *= pow(lightmap.y, 2.5);

#endif

    #ifdef END
    vec3 sceneLighting = endCol.rgb * (0.1 * fullShadow + 0.07);
    #endif
    
    if (foliage > 0.5) {
        float VoL = clamp(dot(normalize(viewPos.xyz), lightVec), 0.0, 1.0);
        float subsurface = pow(VoL, 25.0) * (1.0 - rainStrength);
        sceneLighting *= 3.0 * fullShadow * subsurface + 1.0;
    }
    #else
    #ifdef NETHER
	#if MC_VERSION <= 11600
	#else
    if (vanillaDiffuse < 0.5625) vanillaDiffuse = 0.5625 + (0.4 - vanillaDiffuse * 0.7111111111111111);
    #endif
    
    vec3 sceneLighting = netherCol.rgb * (1 - pow(length(fogColor / 3), 0.25)) * (screenBrightness*0.5 + 0.5);
    #else
	vec3 sceneLighting = vec3(0.0);
   
    #endif
    #endif
    
    float torchDist=length(worldPos);
    float handTorchLightmap=0.;
    vec3 handLightCol=vec3(0.1);
    
    #ifdef DYNAMIC_HAND_LIGHT
		float handLight = min(float(heldBlockLightValue2 + heldBlockLightValue), 15.0) / 15.0;
		float handLightFactor = 1.0 - min(14.0, lViewPos) * 0.07142857;
		lightmap.x = max(handLight * handLightFactor * 0.95, lightmap.x);
	#endif

    #ifdef DYNAMIC_HAND_LIGHT
    if (heldItemId==13001||heldItemId2==13001||
        heldItemId==13002||heldItemId2==13002||
        heldItemId==13003||heldItemId2==13003||
        heldItemId==13004||heldItemId2==13004||
        heldItemId==13005||heldItemId2==13005||
        heldItemId==13006||heldItemId2==13006||
        heldItemId==13007||heldItemId2==13007){

        handTorchLightmap=clamp(1.-((torchDist-DIST_MAX_LIGHT)/(DIST_DECLINE-DIST_MAX_LIGHT)),0.,1.)*MAX_LIGHT;
        
        #ifdef COLORED_DYNAMIC_HAND_LIGHT
        
        if(heldItemId==13002||heldItemId2==13002)
        {
            handLightCol=vec3(.4863,.7686,.9882);
        }
        else if(heldItemId==13003||heldItemId2==13003)
        {
            handLightCol=vec3(0.8863, 0.0235, 0.0235);
        }
        else if(heldItemId==13004||heldItemId2==13004)
        {
            handLightCol=vec3(0.0, 0.1843, 1.0);
        }
        else if(heldItemId==13005||heldItemId2==13005)
        {
            handLightCol=vec3(0.0, 0.8549, 0.6667);
        }
        else if(heldItemId==13006||heldItemId2==13006)
        {
            handLightCol=vec3(0.9765, 0.3412, 1.0);
        }
        else if(heldItemId==13007||heldItemId2==13007)
        {
            handLightCol=vec3(0.0, 0.5255, 0.2824);
        }
        else if(heldItemId==13001||heldItemId2==13001)
        {
            handLightCol=vec3(1.,.3686,0.);
        }
        #endif
    }
    #endif
    #if CONCENTRATE_BLOCK_LIGHT == 1
    float newLightmap  = pow(lightmap.x, 120.0 / LIGHTING_POWER) * BLOCKLIGHT_LUMA + max(lightmap.x - 0.01, 0.0) * (screenBrightness*0.25 + 0.9);
    #endif
    #if CONCENTRATE_BLOCK_LIGHT == 2
    float newLightmap  = sqrt(pow(lightmap.x, 120.0 / LIGHTING_POWER) * BLOCKLIGHT_I + max(lightmap.x - 0.01, 0.0) * (screenBrightness*0.25 + 0.9));
    #endif

    #ifndef HAND
    #ifdef BLOCKLIGHT_BY_TEMP
    blocklightCol=BlackBody(BLOCKLIGHT_TEMP) * 2.0 * BLOCKLIGHT_LUMA;
    #endif
    #endif
    
    handTorchLightmap=CurveBlockLight(handTorchLightmap);
    newLightmap=CurveBlockLight(newLightmap);
    
    #ifdef OVERWORLD
    #if SHINE_BLOCKLIGHTINGLIMITER == 0
    float newLightMap = newLightmap;
    #endif
    #if SHINE_BLOCKLIGHTINGLIMITER == 1
    float newLightMap = newLightmap * newLightmap;
    #endif

    vec3 blockLighting=max(blocklightCol*(newLightMap),handLightCol * (handTorchLightmap));
    #else
    vec3 blockLighting=max(blocklightCol*(newLightmap),handLightCol * (handTorchLightmap));
    #endif

    vec3 emissiveColor = sqrt(albedo * length(albedo) + vec3(0.00001));
    vec3 emissiveLighting = emissiveColor * (emissive * 4.0 / vanillaDiffuse);
    
    float nightVisionLighting=nightVision*.25;
    float minLighting = 0.000000000001 + (MIN_LIGHT * 0.0035 * (screenBrightness*0.08 + 0.01)) * (1.0 - eBS);
    albedo *= sceneLighting + blockLighting + emissiveLighting + nightVisionLighting + minLighting;
    albedo *=pow(vanillaDiffuse,SHADING_STRENGTH)*smoothLighting;
    
    #ifdef DESATURATION
    #ifdef OVERWORLD
    float desatAmount=sqrt(max(sqrt(length(fullShadow/3.))*lightmap.y,lightmap.y))*
    sunVisibility*(1.-rainStrength*.4)+sqrt(lightmap.x+emissive);
    
    vec3 desatNight=lightNight/LIGHT_NI;
    vec3 desatWeather=weatherCol.rgb/weatherCol.a*.5;
    
    desatNight*=desatNight;desatWeather*=desatWeather;
    
    float desatNWMix=(1.-sunVisibility)*(1.-rainStrength);
    
    vec3 desatColor=mix(desatWeather,desatNight,desatNWMix);
    desatColor=mix(vec3(.1),desatColor,sqrt(lightmap.y))*10.;
    #endif
    
    #ifdef NETHER
    float desatAmount=sqrt(lightmap.x+emissive);
    
    vec3 desatColor=netherColSqrt.rgb/netherColSqrt.a;
    #endif
    
    #ifdef END
    float desatAmount=sqrt(lightmap.x+emissive);
    
    vec3 desatColor=endCol.rgb*1.25;
    #endif
    
    desatAmount=clamp(desatAmount,DESATURATION_FACTOR*.4,1.);
    desatColor*=1.-desatAmount;
    
    albedo=mix(GetLuminance(albedo)*desatColor,albedo,desatAmount);
    #endif
}