texture PosTexture;
texture NormalTexture;
texture DiffuseTexture;

uniform float4 g_freeLightPos;
uniform float4 g_freeLightColor;

sampler2D g_PosTexSampler = 
sampler_state{
	texture = <PosTexture>;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;   
	AddressU  = Clamp;
	AddressV  = Clamp;
};

sampler2D g_NormalTexSampler = 
sampler_state{
	texture = <NormalTexture>;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;   
	AddressU  = Clamp;
	AddressV  = Clamp;
};

sampler2D g_DiffuseTexSampler = 
sampler_state{
	texture = <DiffuseTexture>;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;   
	AddressU  = Clamp;
	AddressV  = Clamp;
};

void VS_Deferred(
	in float4 iPosition : POSITION,
	in float2 iUV : TEXCOORD0,
	out float4 oPosition : POSITION,
	out float2 oUV : TEXCOORD0
)
{
	oPosition = iPosition;
	oUV = iUV;
}

void PS_Deferred(
	in float2 iUV : TEXCOORD0,
	out float4 oColor : COLOR
)
{
	oColor = tex2D(g_DiffuseTexSampler, iUV);
}

void PS_Deferred_Shadow_DirLight_Ambient(
	in float2 iUV : TEXCOORD0,
	out float4 oColor : COLOR
)
{
	iUV += 1.0f / g_renderTargetSize * 0.5f;
	
	float4 modelColor = tex2D(g_DiffuseTexSampler, iUV);
	float4 normal = tex2D(g_NormalTexSampler, iUV);
	
	float shadowFactor = 1.0f;
	#if SHADOW_FEATURE_ENABLED
	float4 worldPos = tex2D(g_PosTexSampler, iUV);
	float depth = worldPos.w;
	
	int cascadeIndex = -1;
	// 根据像素在世界空间中的位置，挑选对应的阴影贴图
	float currentPixelDepth = -depth - 0;
	cascadeIndex = ChooseCascade(currentPixelDepth);
	// 计算阴影系数，消耗大量FPS
	if (cascadeIndex < MAX_CASCADE_SPLITS)
	{
		float4 shadowPos = GetShadowPos(worldPos, normal, cascadeIndex);
		// shadowPos /= shadowPos.w;
		
		shadowFactor = CalcShadowFactor(shadowPos);
		
		// 混合级联阴影贴图边界，消耗不少FPS
		#if ENABLE_BLEND_ACROSS_CASCADE
		shadowFactor = BlendCascade(currentPixelDepth, shadowFactor, worldPos, normal, cascadeIndex);
		#endif
	}
	else
	{
		// 超出有效阴影距离，不画阴影
		shadowFactor = 1.0f;
	}
	#endif // SHADOW_FEATURE_ENABLED
	
	float diff = GetDirLightDiffuse(normal);
	diff *= shadowFactor;
	float3 finalColor = diff * g_lightColor.rgb * modelColor.rgb;
	finalColor += g_ambientColor.rgb * modelColor.rgb;
	
	#if SHOW_DEBUG_CASCADED_SHADOWMAP
	if (cascadeIndex >= 0 && cascadeIndex < MAX_CASCADE_SPLITS)
	{
		finalColor = finalColor * g_shadowmapDebugColors[max(cascadeIndex, 0)];	
	}
	#endif
	
	oColor = float4(finalColor, 1.0f);
}

void VS_Deferred_FreeLight(
	in float3 iPosition : POSITION,
	in float2 iUV : TEXCOORD0,
	out float4 oUV : TEXCOORD0,
	out float4 oPosition : POSITION
)
{
	float4 pos = float4(iPosition ,1);
	oPosition = mul(pos, g_wvpMatrix);
	oUV = mul(oPosition, g_texSpaceMatrix);
}

void PS_Deferred_FreeLight(
	in float4 iUV : TEXCOORD0,
	out float4 oColor : COLOR
	)
{
	float2 uv = iUV.xy / iUV.w; // 透视修正
	float4 modelColor = tex2D(g_DiffuseTexSampler, uv.xy);
	float4 normal = tex2D(g_NormalTexSampler, uv.xy);
	float4 worldPos = tex2D(g_PosTexSampler, uv.xy);
	
	float3 lightDir;
	float diff;
	
	float4 lightPos = g_freeLightPos;
	float atten = lightPos.w;
	float3 lightVec = (worldPos.xyz - lightPos.xyz) * atten;
	float lightDist = length(lightVec);
	lightDir = lightVec / lightDist;
	#ifdef TRANSLUCENT
	diff = abs(dot(normal, -lightDir)) * tex2D(RampSampler, float2(lightDist, 0.0)).r;
	#else
	diff = saturate(dot(normal, -lightDir)) * tex2D(RampSampler, float2(lightDist, 0.0)).r;
	#endif
	
	
	float4 freeLightColor = g_freeLightColor;
	float3 lightAmbient = tex2D(RampSampler, float2(lightDist, 0.0)).r * freeLightColor.rgb;
	float3 finalColor = (lightAmbient + diff * freeLightColor.rgb) * modelColor.rgb;
	oColor = float4(finalColor, 1.0f);
}

technique Deferred
{
	// for test only
	pass p0
	{
		AlphaTestEnable = false;
		AlphaBlendEnable = false;
		ZEnable = false;
		ZWriteEnable = false;
		SrcBlend = One;
		DestBlend = One; 
		BlendOp = Add;
		VertexShader = compile vs_3_0 VS_Deferred();
		PixelShader = compile ps_3_0 PS_Deferred();
	}

	pass p1
	{
		AlphaTestEnable = false;
		AlphaBlendEnable = false;
		ZEnable = false;
		ZWriteEnable = false;
		SrcBlend = One;
		DestBlend = One; 
		BlendOp = Add;
		VertexShader = compile vs_3_0 VS_Deferred();
		PixelShader = compile ps_3_0 PS_Deferred_Shadow_DirLight_Ambient();
	}
	
	pass p2
	{
		AlphaTestEnable = false;
		AlphaBlendEnable = true;
		ZEnable = false;
		ZWriteEnable = false;
		SrcBlend = One;
		DestBlend = One; 
		BlendOp = Add;
		VertexShader = compile vs_3_0 VS_Deferred_FreeLight();
		PixelShader = compile ps_3_0 PS_Deferred_FreeLight();
	}
}
