////////////////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "../../../types.txt"
#include "../common.ps.txt"

#include "types.txt"
#include "common.ps.txt"

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main Function : ColorModel
////////////////////////////////////////////////////////////////////////////////////////////////////

PS_COLOR_OUTPUT mainColorModel( PS_COLOR_INPUT input )
{
	PS_COLOR_OUTPUT output = ( PS_COLOR_OUTPUT )0;

	////////////////////////////////////////////////////////////
	// Initialize
	////////////////////////////////////////////////////////////

#if ENABLE_PROJ_TEX
	float2 projTex = 0.5 + ( input.projPos.xy / input.projPos.w ) * float2( 0.5, -0.5 );
#endif //ENABLE_PROJ_TEX

	// Refract clip ( RGB=SurfaceZ A=Mask ) Only transparency
#if ENABLE_REFRACT_CLIP
	clip( ( input.projPos.z / input.projPos.w ) - TEX_REFRACT_2D( projTex ).r );
#endif //ENABLE_REFRACT_CLIP

	float depth = saturate( input.projPos.z * INV_FAR_Z );

	// Eye parameater
#if ( ENABLE_LIGHTING || ( ENABLE_FOG && ENABLE_ATMOSPHERE ) )
	float3 eyeVec = EYE_POS - input.worldPos.xyz;
	float3 eyeDir = normalize( eyeVec );
#endif //( ENABLE_LIGHTING || ( ENABLE_FOG && ENABLE_ATMOSPHERE ) )

#if ENABLE_LIGHTING
	#if ENABLE_BUMP
		#if ENABLE_PARALLAX_MAPPING
			float3 localBumpNormal = ComputeLocalBumpNormal( input.tex, input.tangent, input.binormal, input.normal, eyeVec, eyeDir );
			float3 bumpNormal = TransformBumpNormal( localBumpNormal, input.tangent, input.binormal, input.normal );
		#else //ENABLE_PARALLAX_MAPPING
			float3 localBumpNormal = ComputeLocalBumpNormal( input.tex );
			float3 bumpNormal = TransformBumpNormal( localBumpNormal, input.tangent, input.binormal, input.normal );
		#endif //ENABLE_PARALLAX_MAPPING
	#else //ENABLE_BUMP
		float3 bumpNormal = input.normal;
	#endif //ENABLE_BUMP
#endif //ENABLE_LIGHTING

#if ENABLE_N_DOT_L
	float NdotL = dot( bumpNormal, -SUN_DIR );
#endif //ENABLE_N_DOT_L

#if ENABLE_N_DOT_E
	float NdotE = dot( bumpNormal, eyeDir );
#endif //ENABLE_N_DOT_E

#if ENABLE_N_DOT_E_PLANE
	float planeNdotE = dot( input.normal, eyeDir );
#endif //ENABLE_N_DOT_E_PLANE

#if ENABLE_FRESNEL
	float fresnelFacing = 1.0 - abs( planeNdotE );
//	float fresnelFacing = 1.0 - abs( NdotE );
#endif //ENABLE_FRESNEL

#if ENABLE_LIGHTING
	float3 ambientColor;
#endif //ENABLE_LIGHTING

	float4 diffuseColor;

#if ENABLE_SPECULAR
	float4 specularColor;
#endif //ENABLE_SPECULAR

#if ENABLE_REFLECT_MAPPING
	float reflectGloss;
	float reflectRatio;
#endif //ENABLE_REFLECT_MAPPING

	float4 emissiveColor;

#if ENABLE_LIGHTING
	LIGHT_INFO lightInfo = ( LIGHT_INFO )0;
#endif //ENABLE_LIGHTING

#if ENABLE_FOG
	float fogRatio = ComputeFogRatio( input.projPos.w );
	#if ENABLE_ATMOSPHERE
		float eyeDist = length( eyeVec );
	#endif //ENABLE_ATMOSPHERE
#endif //ENABLE_FOG

	////////////////////////////////////////////////////////////
	// Base
	////////////////////////////////////////////////////////////

	// Ambient
#if ENABLE_LIGHTING
	ambientColor = GLOBAL_AMBIENT_COLOR * M_AMBIENT_COLOR;
#endif //ENABLE_LIGHTING
	
#if ENABLE_WATER

	// Diffuse
	if( planeNdotE >= 0.0 )
	{
		diffuseColor = input.color * M_DIFFUSE_COLOR;
	}
	else
	{
		diffuseColor = float4( 0.0, 0.0, 0.0, 0.0 );
	}

	// Specular
	#if ENABLE_SPECULAR
		specularColor = M_SPECULAR_COLOR;
	#endif //ENABLE_SPECULAR

	// Reflect
	#if ENABLE_REFLECT_MAPPING
		reflectGloss = 1.0;
	#endif //ENABLE_REFLECT_MAPPING

	// Emissive
	emissiveColor = M_EMISSIVE_COLOR;

#else //ENABLE_WATER

	// Diffuse
	#if ENABLE_DIFFUSE_MAPPING
		diffuseColor = input.color * M_DIFFUSE_COLOR;
		#if ENABLE_PARALLAX_MAPPING
			diffuseColor *= TEX_DIFFUSE_2D_GRAD( gradTex, dx, dy );
		#else //ENABLE_PARALLAX_MAPPING
			diffuseColor *= TEX_DIFFUSE_2D( input.tex );
		#endif //ENABLE_PARALLAX_MAPPING
	#else //ENABLE_DIFFUSE_MAPPING
		diffuseColor = input.color * M_DIFFUSE_COLOR;
	#endif //ENABLE_DIFFUSE_MAPPING
		
	// Specular
	#if ENABLE_SPECULAR
		#if ENABLE_SPECULAR_MAPPING
			
			#if ENABLE_PARALLAX_MAPPING
				float4 texSpecularColor = TEX_SPECULAR_2D_GRAD( gradTex, dx, dy );
			#else //ENABLE_PARALLAX_MAPPING
				float4 texSpecularColor = TEX_SPECULAR_2D( input.tex );
			#endif //ENABLE_PARALLAX_MAPPING

			specularColor = M_SPECULAR_COLOR;
			specularColor.rgb *= texSpecularColor.rgb;
			specularColor *= texSpecularColor.a;

			#if ENABLE_REFLECT_MAPPING
				reflectGloss = texSpecularColor.a;
			#endif //ENABLE_REFLECT_MAPPING

		#else //ENABLE_SPECULAR_MAPPING

			specularColor = M_SPECULAR_COLOR;

			#if ENABLE_REFLECT_MAPPING
				reflectGloss = 1.0;
			#endif //ENABLE_REFLECT_MAPPING

		#endif //ENABLE_SPECULAR_MAPPING
	#endif //ENABLE_SPECULAR

	// Emissive
	#if ENABLE_EMISSIVE_MAPPING
		#if ENABLE_PARALLAX_MAPPING
			float4 texEmissiveColor = TEX_EMISSIVE_2D_GRAD( gradTex, dx, dy );
		#else //ENABLE_PARALLAX_MAPPING
			float4 texEmissiveColor = TEX_EMISSIVE_2D( input.tex );
		#endif //ENABLE_PARALLAX_MAPPING
		emissiveColor = M_EMISSIVE_COLOR * texEmissiveColor;
	#else //ENABLE_EMISSIVE_MAPPING
		emissiveColor = M_EMISSIVE_COLOR;
	#endif //ENABLE_EMISSIVE_MAPPING

#endif //ENABLE_WATER

	// Diffuse ( Fresnel )
#if ENABLE_DIFFUSE_FRESNEL
	diffuseColor = ComputeDiffuseFresnel( diffuseColor, fresnelFacing );
#endif //ENABLE_DIFFUSE_FRESNEL

	// Diffuse ( Reflect )
#if ENABLE_REFLECT_MAPPING
	#if ENABLE_REFLECT_FRESNEL
		reflectRatio = ComputeReflectRatio( reflectGloss, fresnelFacing );
	#else //ENABLE_REFLECT_FRESNEL
		reflectRatio = ComputeReflectRatio( reflectGloss );
	#endif //ENABLE_REFLECT_FRESNEL
	diffuseColor = ComputeReflect( diffuseColor, eyeDir, input.normal, bumpNormal, reflectRatio );
#endif //ENABLE_REFLECT_MAPPING

	////////////////////////////////////////////////////////////
	// Lighting
	////////////////////////////////////////////////////////////

#if ENABLE_LIGHTING

	// Hemisphere lighting
	lightInfo = ComputeHemisphereLight( lightInfo, bumpNormal );

	// Directional lighting
#if ENABLE_N_DOT_E
	lightInfo = ComputeDirectionalLight( lightInfo, NdotL, NdotE, eyeDir, bumpNormal );
#else //ENABLE_N_DOT_E
	lightInfo = ComputeDirectionalLight( lightInfo, NdotL, eyeDir, bumpNormal );
#endif //ENABLE_N_DOT_E

	// Local lighting
#if ENABLE_N_DOT_E
	lightInfo = ComputeLocalLight( lightInfo, NdotE, eyeDir, input.worldPos.xyz, bumpNormal );
#else //ENABLE_N_DOT_E
	lightInfo = ComputeLocalLight( lightInfo, eyeDir, input.worldPos.xyz, bumpNormal );
#endif //ENABLE_N_DOT_E

	// Apply ambient
	ambientColor *= max( 0.0, 1.0 - lightInfo.diffuseColor );

	// Apply diffuse
	diffuseColor.rgb *= lightInfo.diffuseColor;

	// Apply specular
#if ENABLE_SPECULAR
	specularColor *= lightInfo.specularFactor;
#endif //ENABLE_SPECULAR

#endif //ENABLE_LIGHTING

	////////////////////////////////////////////////////////////
	// Out : Color
	////////////////////////////////////////////////////////////

	// Ambient
#if ENABLE_LIGHTING
	output.color.rgb += ambientColor;
#endif //ENABLE_LIGHTING

	// Diffuse
	output.color += diffuseColor;

	// Specular
#if ENABLE_SPECULAR
	output.color += specularColor * M_SPECULAR_SCALE;
#endif //ENABLE_SPECULAR

	// Emissive
	output.color += emissiveColor * M_EMISSIVE_SCALE;

	// Fog
#if ENABLE_FOG
	#if ENABLE_ATMOSPHERE
		output.color.rgb = ApplyFog( output.color.rgb, -eyeDir, eyeDist, fogRatio );
	#else //ENABLE_ATMOSPHERE
		output.color.rgb = ApplyFog( output.color.rgb, fogRatio );
	#endif //ENABLE_ATMOSPHERE
#endif //ENABLE_FOG

	// Only Transparency ( SoftEdge or Refraction )
#if ENABLE_REFRACT_MAPPING
	//RGB=BackgroundColor A=Mask
	#if ENABLE_SOFTPARTICLE
		output.color = ComputeRefract( output.color, localBumpNormal, input.projPos, projTex, depth );
	#else //ENABLE_SOFTPARTICLE
		output.color = ComputeRefract( output.color, localBumpNormal, input.projPos, projTex );
	#endif //ENABLE_SOFTPARTICLE
#else //ENABLE_REFRACT_MAPPING
	#if ENABLE_SOFTPARTICLE
		output.color.a *= ComputeSoftEdge( depth, projTex );
	#endif //ENABLE_SOFTPARTICLE
#endif //ENABLE_REFRACT_MAPPING

	// Clip transparency
#if ENABLE_TRANSPARENCY_CLIP
	clip( output.color.a - TRANSPARENCY_THRESHOLD );
#endif //ENABLE_TRANSPARENCY_CLIP

	////////////////////////////////////////////////////////////
	// Out : Depth
	////////////////////////////////////////////////////////////

	output.depth.rgb = depth;
	output.depth.a = 1.0;

	////////////////////////////////////////////////////////////
	// Out : Data
	////////////////////////////////////////////////////////////
	
#if ( ENABLE_SSAO || ENABLE_SHADOW )
	#if ENABLE_LIGHTING
		#if ENABLE_REFRACT_MAPPING
			output.data = 0.0;
		#else //ENABLE_REFRACT_MAPPING
			output.data.xyz = input.viewNormal.xyz * 0.5 + 0.5;
			output.data.a = output.color.a;
		#endif //ENABLE_REFRACT_MAPPING
	#else //ENABLE_LIGHTING
		output.data = float4( 0.0, 0.0, 0.0, output.color.a );
	#endif //ENABLE_LIGHTING
#else //( ENABLE_SSAO || ENABLE_SHADOW )
	output.data = float4( 0.0, 0.0, 0.0, output.color.a );
#endif //( ENABLE_SSAO || ENABLE_SHADOW )

	////////////////////////////////////////////////////////////
	// Out : Shadow
	////////////////////////////////////////////////////////////

#if ENABLE_SHADOW
	#if ENABLE_SHADOW_RECEIVE
		output.shadow = ComputeShadow( input.shadowTex, input.shadowDepth, NdotL );
	#else //ENABLE_SHADOW_RECEIVE
		#if ENABLE_REFRACT_MAPPING
			output.shadow = float4( 1.0, 0.0, 0.0, 1.0 );
		#else //ENABLE_REFRACT_MAPPING
			output.shadow.rgb = float3( 1.0, 0.0, 0.0 );
			output.shadow.a = ( ( output.color.a - TRANSPARENCY_THRESHOLD ) > 0.0 )? output.color.a : 0.0;
		#endif //ENABLE_REFRACT_MAPPING
	#endif //ENABLE_SHADOW_RECEIVE
#endif //ENABLE_SHADOW

	////////////////////////////////////////////////////////////

	return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main Function : MaskModel
////////////////////////////////////////////////////////////////////////////////////////////////////

float4 mainMaskModel( PS_MASK_MODEL_INPUT input ) : MSV_TARGET0
{
	float4 output;

	output.rgb = input.projPos.z / input.projPos.w;
	output.a = 1.0;

	return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main Function : ShadowModel
////////////////////////////////////////////////////////////////////////////////////////////////////

float4 mainShadowModel( PS_SHADOW_MODEL_INPUT input ) : MSV_TARGET0
{
	float4 color = input.color * M_DIFFUSE_COLOR;
	float4 output = 0.0;

#if ENABLE_DIFFUSE_MAPPING
	color *= TEX_DIFFUSE_2D( input.tex );
#endif // ENABLE_DIFFUSE_MAPPING

#if 1

	output.r = input.depth.z / input.depth.w;
	output.g = 0.0;
	output.b = 0.0;
	output.a = color.a;

#else

	float depth = input.depth.z / input.depth.w;
	float dx = ddx( depth );
	float dy = ddy( depth );

	output.r = depth;
	output.g = depth * depth + 0.25 * ( dx * dx + dy * dy );
	output.b = 0.0;
	output.a = color.a;

#endif

	return output;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main Function : SelectModel
////////////////////////////////////////////////////////////////////////////////////////////////////

float4 mainSelectModel( float4 pos : SV_POSITION ) : MSV_TARGET0
{
	return M_DIFFUSE_COLOR;
}
