varying vec2 texcoord;

varying vec3 sunWorldDir, moonWorldDir, lightWorldDir;
varying vec3 sunViewDir, moonViewDir, lightViewDir;

varying float isNoon, isNight, sunRiseSet;
varying float isNoonS, isNightS, sunRiseSetS;

varying vec3 sunColor, skyColor;


#include "/lib/uniform.glsl"
#include "/lib/settings.glsl"
#include "/lib/common/utils.glsl"
#include "/lib/camera/colorToolkit.glsl"
#include "/lib/camera/filter.glsl"
#include "/lib/common/position.glsl"
#include "/lib/common/normal.glsl"
#include "/lib/common/noise.glsl"

#include "/lib/atmosphere/atmosphericScattering.glsl"

#ifdef FSH
const bool shadowtex1Mipmap = true;
const bool shadowtex1Nearest = false;

const bool shadowcolor0Mipmap = true;
const bool shadowcolor0Nearest = false;
const bool shadowcolor1Mipmap = true;
const bool shadowcolor1Nearest = false;



#include "/lib/common/gbufferData.glsl"

#include "/lib/common/materialIdMapper.glsl"
#include "/lib/lighting/lightmap.glsl"
#include "/lib/lighting/shadowMapping.glsl"
#include "/lib/lighting/screenSpaceShadow.glsl"
#include "/lib/lighting/RSM.glsl"
#include "/lib/lighting/SSAO.glsl"
#include "/lib/surface/PBR.glsl"

#include "/lib/atmosphere/fog.glsl"
#include "/lib/atmosphere/celestial.glsl"
#include "/lib/atmosphere/volumetricClouds.glsl"



void main() {
	vec4 color = texture(colortex0, texcoord);	// albedo
	vec3 texColor = color.rgb;
	vec3 albedo = toLinearR(texColor);
	vec3 diffuse = albedo / PI;

	vec3 normalV = normalize(normalDecode(normalEnc));
	vec3 normalW = normalize(viewPosToWorldPos(vec4(normalV, 0.0)).xyz);

	vec3 L2 = BLACK;
	vec3 ao = vec3(1.0);

	#ifdef DISTANT_HORIZONS
		bool isTerrain = skyB < 0.5 || dhTerrain > 0.5;

		float depth1;
		vec4 viewPos1;
		if(dhTerrain > 0.5){ 
			depth1 = texture(dhDepthTex0, texcoord).r;
			viewPos1 = screenPosToViewPosDH(vec4(texcoord, depth1, 1.0));
		}else{
			depth1 = texture(depthtex1, texcoord).r;
			viewPos1 = screenPosToViewPos(vec4(unTAAJitter(texcoord), depth1, 1.0));	
		}
	#else 
		bool isTerrain = skyB < 0.5;

		float depth1 = texture(depthtex1, texcoord).r;
		vec4 viewPos1 = screenPosToViewPos(vec4(unTAAJitter(texcoord), depth1, 1.0));	
	#endif

	vec3 viewDir = normalize(viewPos1.xyz);
	vec4 worldPos1 = viewPosToWorldPos(viewPos1);
	vec3 worldDir = normalize(worldPos1.xyz);
	vec3 shadowPos = getShadowPos(worldPos1).xyz;
	float worldDis1 = length(worldPos1);

	if(isTerrain){	
		vec2 lightmap = AdjustLightmap(mcLightmap);

		MaterialParams materialParams = MapMaterialParams(specularMap);
		#ifdef PBR_REFLECTIVITY
			mat2x3 PBR = CalculatePBR(viewDir, normalV, lightViewDir, albedo, materialParams);
			vec3 BRDF = PBR[0] + PBR[1];
			vec3 BRDF_D = BRDF_Diffuse(normalV, viewDir, albedo, materialParams);
		#else
			vec3 BRDF = albedo / PI;
			vec3 BRDF_D = BRDF;
		#endif



		float cos_theta_O = dot(normalW, lightWorldDir);
		float cos_theta = max(cos_theta_O, 0.0);

		// bzyzhang: 练习项目(十一)：次表面散射的近似实现
		// https://zhuanlan.zhihu.com/p/348106844
		float sssWrap = SSS_INTENSITY * materialParams.subsurfaceScattering;
		if(plants > 0.5) sssWrap = 20.0;
		cos_theta = saturate((cos_theta_O + sssWrap) / (1 + sssWrap));


		float noRSM = hand > 0.5 ? 1.0 : 0.0;
		float lightMask = pow(smoothstep(0.0, 0.1, lightmap.y), 0.45);
		float UoN = dot(normalW, upWorldDir);
		vec3 skyLight = lightmap.y * BRDF_D
					* mix(sunColor, skyColor, SUN_SKY_BLEND - 0.05 * noRSM * lightmap.y)
					* mix(1.0, UoN * 0.5 + 0.5, 0.75);
		

		vec4 gi = getGI(depth1, normalW);
		if(noRSM < 0.5) {
			L2 = sunColor * BRDF_D * gi.rgb;
			#ifdef AO_MULTI_BOUNCE
				ao = AOMultiBounce(albedo, saturate(1.0 - gi.a));
			#else 
				ao = vec3(saturate(1.0 - gi.a));
			#endif
		}



		float shadow = 1.0;
		vec3 colorShadow = vec3(0.0);
		if(texture(shadowtex1, shadowPos.xy).r <= 1.0 && !outScreen(shadowPos.xy) && cos_theta > 0.001){
			shadow = min(parallaxShadow, shadowMapping(worldPos1, normalW, sssWrap));
			colorShadow = getColorShadow(shadowPos, shadow);
		}
		if(worldDis1 > shadowDistance * 0.75){
			float mixFactor = smoothstep(shadowDistance * 0.75, shadowDistance * 0.90, worldDis1);
			mixFactor = saturate(mixFactor);
			float RTShadow = screenSpaceShadow(viewPos1.xyz, normalW, shadow);
			shadow = min(shadow, mix(1.0, RTShadow, mixFactor));
			shadow = saturate(shadow);
		}
		vec3 visibility = vec3(shadow + colorShadow * 1.0);
		vec3 direct = sunColor * BRDF * visibility * cos_theta;



		vec3 artificial = lightmap.x * artificial_color * (1. + GLOWING_BRIGHTNESS * glowingB) * diffuse;
		artificial += saturate(materialParams.emissiveness - lightmap.x) * diffuse * EMISSIVENESS_BRIGHTNESS;
		artificial += 1 * lightningBolt;

		

		
		
		
		#ifdef DISABLE_LEAKAGE_REPAIR
			lightMask = 1.0;
		#endif
		color.rgb = albedo * 0.005;
		color.rgb += skyLight * SKY_LIGHT_BRIGHTNESS;
		color.rgb += nightVision * diffuse * NIGHT_VISION_BRIGHTNESS;
		color.rgb += L2 * lightMask * RSM_BRIGHTNESS;
		color.rgb *= ao;
		color.rgb += direct * lightMask * DIRECT_LUMINANCE;

		if(isEyeInWater == 1){
			vec3 underWaterTransmit = saturate(fastExp(-(vec3(1.0) - waterFogColor) * (1.25 - lightmap.y) * 3));
			color.rgb *= underWaterTransmit * 1.0;
		}
		
		color.rgb += artificial;
		// color.rgb = gi.rgb;
		// color.rgb = vec3(1.0 - gi.a);




		#ifdef ATMOSPHERIC_SCATTERING_FOG
			float fogVis = fogVisibility(worldPos1);
			fogVis = (fogVis * min(shadowDistance, worldDis1) + max(worldDis1 - shadowDistance, 0.0)) / worldDis1;
			fogVis = saturate(fogVis * isNoon);

			color.rgb = Transmittance1(earthPos, earthPos + worldPos1.xyz * ATMOSPHERIC_SCATTERING_FOG_DENSITY, VOLUME_LIGHT_SAMPLES) * color.rgb;
			mat2x3 AtmosphericScattering_Land = AtmosphericScattering(worldPos1.xyz, normalize(worldPos1.xyz), sunWorldDir, IncomingLight, 1.0, int(VOLUME_LIGHT_SAMPLES));
			color.rgb += (AtmosphericScattering_Land[0] * fogVis * (1.0 + 3.0 * rainStrength) + AtmosphericScattering_Land[1]) * ATMOSPHERIC_SCATTERING_FOG_DENSITY;
		#endif
		
	}else{
		#include "/lib/atmosphere/skyColorMain.glsl"
	}
	
	color.rgb = max(BLACK, color.rgb);
	// color.rgb = vec3(texture(colortex1, texcoord * 0.5).rgb);
	
	
	CT4.rg = pack4x8To2x16(vec4(albedo, ao));

/* DRAWBUFFERS:04 */
	gl_FragData[0] = color;
	gl_FragData[1] = CT4;
}

#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef VSH

void main() {
	sunViewDir = normalize(sunPosition);
	moonViewDir = normalize(moonPosition);
	lightViewDir = normalize(shadowLightPosition);

	sunWorldDir = normalize(viewPosToWorldPos(vec4(sunPosition, 0.0)).xyz);
    moonWorldDir = normalize(viewPosToWorldPos(vec4(moonPosition, 0.0)).xyz);
    lightWorldDir = normalize(viewPosToWorldPos(vec4(shadowLightPosition, 0.0)).xyz);

	isNoon = saturate(dot(sunWorldDir, upWorldDir) * NOON_DURATION);
	isNight = saturate(dot(moonWorldDir, upWorldDir) * NIGHT_DURATION);
	sunRiseSet = saturate(1 - isNoon - isNight);

	isNoonS = saturate(dot(sunWorldDir, upWorldDir) * NOON_DURATION_SLOW);
	isNightS = saturate(dot(moonWorldDir, upWorldDir) * NIGHT_DURATION_SLOW);
	sunRiseSetS = saturate(1 - isNoonS - isNightS);

	sunColor = getSunColor();
	skyColor = getSkyColor();

	gl_Position = ftransform();
	texcoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;
}

#endif