/*================================================================================
	MeshPaintPixelShader.usf: Mesh texture paint pixel shader
	Copyright 1998-2010 Epic Games, Inc. All Rights Reserved.
================================================================================*/

#include "Common.usf"

/** Texture containing a clone of the texture we're currently rendering to. */
sampler2D s_CloneTexture;

float4x4 c_WorldToBrushMatrix;

/** Brush metrics: x = radius, y = falloff range, z = depth, w = depth falloff range */
float4 c_BrushMetrics;

float c_BrushStrength;
float4 c_BrushColor;

// @todo MeshPaint: Remove this?
float c_Gamma;






void Main( float2 InCloneTextureCoordinates : TEXCOORD0,
		   float3 InWorldSpaceVertexPosition : TEXCOORD1,
		   out float4 OutColor : COLOR0 )
{
	// First sample the source values from the clone texture
	float4 OldColor = tex2D( s_CloneTexture, InCloneTextureCoordinates );


	// Brush metrics: x = radius, y = falloff range, z = depth, w = depth falloff range
	float BrushRadius = c_BrushMetrics.x;
	float BrushRadialFalloffRange = c_BrushMetrics.y;
	float BrushDepth = c_BrushMetrics.z;
	float BrushDepthFalloffRange = c_BrushMetrics.w;



	float4x4 WorldToBrushMatrix = c_WorldToBrushMatrix;
//  	WorldToBrushMatrix._m30 = c_WorldToBrushMatrix._m03;
//  	WorldToBrushMatrix._m31 = -c_WorldToBrushMatrix._m13;
//  	WorldToBrushMatrix._m32 = c_WorldToBrushMatrix._m23;
//  	WorldToBrushMatrix._m03 = c_WorldToBrushMatrix._m30;
//  	WorldToBrushMatrix._m13 = -c_WorldToBrushMatrix._m31;
//  	WorldToBrushMatrix._m23 = c_WorldToBrushMatrix._m32;

//	float3 WorldSpaceBrushPosition = float3( WorldToBrushMatrix._m03, WorldToBrushMatrix._m13, WorldToBrushMatrix._m23 );
//	float3 BrushSpaceVertexPosition = WorldSpaceVertexPosition - WorldSpaceBrushPosition;

	// Project the pixel into the plane of the brush
	float3 WorldSpaceVertexPosition = InWorldSpaceVertexPosition;
	float3 BrushSpaceVertexPosition = MulMatrix( WorldToBrushMatrix, float4( WorldSpaceVertexPosition, 1.0f ) );
	float2 BrushSpaceVertexPosition2D = BrushSpaceVertexPosition.xy;


	// Start by using the old color
	float4 NewColor = OldColor;


	// Is the brush close enough to the vertex to paint?
 	float DistanceToVertex2D = length( BrushSpaceVertexPosition2D );
 	if( DistanceToVertex2D <= BrushRadius )
	{
		// OK the vertex is overlapping the brush in 2D space, but is it too close or
		// two far (depth wise) to be influenced?
 		float VertexDepthToBrush = abs( BrushSpaceVertexPosition.z );
 		if( VertexDepthToBrush <= BrushDepth )
		{
			// Compute amount of paint to apply
			float PaintAmount = 1.0f;

			// Apply radial-based falloff
			{
				// Compute the actual distance
				float InnerBrushRadius = BrushRadius - BrushRadialFalloffRange;
				if( DistanceToVertex2D > InnerBrushRadius )
				{
					float RadialBasedFalloff = ( DistanceToVertex2D - InnerBrushRadius ) / BrushRadialFalloffRange;
					PaintAmount *= 1.0f - RadialBasedFalloff;
				}
			}

			// Apply depth-based falloff
			{
				float InnerBrushDepth = BrushDepth - BrushDepthFalloffRange;
				if( VertexDepthToBrush > InnerBrushDepth )
				{
					float DepthBasedFalloff = ( VertexDepthToBrush - InnerBrushDepth ) / BrushDepthFalloffRange;
					PaintAmount *= 1.0f - DepthBasedFalloff;
				}
			}

			PaintAmount *= c_BrushStrength;

			float4 BrushColor = c_BrushColor;

//			if( c_bWriteRed )
			{
				if( OldColor.x < BrushColor.x )
				{
					NewColor.x = min( BrushColor.x, OldColor.x + PaintAmount );
				}
				else
				{
					NewColor.x = max( BrushColor.x, OldColor.x - PaintAmount );
				}
			}

//			if( c_bWriteGreen )
			{
				if( OldColor.y < BrushColor.y )
				{
					NewColor.y = min( BrushColor.y, OldColor.y + PaintAmount );
				}
				else
				{
					NewColor.y = max( BrushColor.y, OldColor.y - PaintAmount );
				}
			}

//			if( c_bWriteBlue )
			{
				if( OldColor.z < BrushColor.z )
				{
					NewColor.z = min( BrushColor.z, OldColor.z + PaintAmount );
				}
				else
				{
					NewColor.z = max( BrushColor.z, OldColor.z - PaintAmount );
				}
			}

//			if( c_bWriteAlpha )
			{
				if( OldColor.w < BrushColor.w )
				{
					NewColor.w = min( BrushColor.w, OldColor.w + PaintAmount );
				}
				else
				{
					NewColor.w = max( BrushColor.w, OldColor.w - PaintAmount );
				}
			}

//			NewColor = float4( PaintAmount, PaintAmount, PaintAmount, PaintAmount );
		}
	}

//	OutColor = OldColor;
	OutColor = NewColor;


	// Gamma correct the output color.
	if( c_Gamma != 1.0 )
	{
		OutColor.rgb = pow( saturate( OutColor.rgb ), c_Gamma );	
	}


//	float3 WorldSpaceBrushPosition = float3( WorldToBrushMatrix._m03, WorldToBrushMatrix._m13, WorldToBrushMatrix._m23 );
// 
// 	float Dist = length( WorldSpaceBrushPosition - WorldSpaceVertexPosition ) / 1000;
// 
// 	OutColor = float4( abs( WorldSpaceBrushPosition - WorldSpaceVertexPosition ) / 1000, 1.0f );
// 	OutColor = float4( WorldSpaceVertexPosition / 4000, 1.0f );
//	OutColor = float4( WorldSpaceBrushPosition / 1000, 1.0f );
//	OutColor = float4( Dist, Dist, Dist, 1.0f );
//	OutColor = float4( abs( BrushSpaceVertexPosition ) / 100, 1.0f );
	
//	OutColor = float4( abs( c_WorldToBrushMatrix._m03 - WorldSpaceVertexPosition.x ) / 1000, abs( c_WorldToBrushMatrix._m13 - WorldSpaceVertexPosition.y )/ 1000, abs( c_WorldToBrushMatrix._m23 - WorldSpaceVertexPosition.z )/ 1000, 1.0f );
}
