
// This shader works like M_DiffuseBumpReflection_3Tex but without the reflection map and vertex color is multiplied to the diffuse color.
// tex_0 contain a diffuse RGB map.
// tex_1 contain a bumpmap in the red channel where darker is lower and brighter is higher.
// tex_1 contain a specular map in the green channel. Specular is the maximum maximum specular light response.
// tex_1 contain a gloss map in the blue channel. Gloss is how sharp the shine is on an exponential scale from 1 to 100.

// If there is no light then make sure that the vertices have a tangent space in the A and B vectors.

// You may modify this to move more data from the vertex shader to the pixel shader.
// It needs at least the position to work.
struct VS_to_PS {
	float4 Pos : SV_POSITION;
	float3 Color : COLOR;
	float3 Normal_WorldSpace : NORMAL;
	float4 Tex : TEXCOORD0;
	float3 UAxis_WorldSpace : TEXCOORD1;
	float3 VAxis_WorldSpace : TEXCOORD2;
	float4 Pos_WorldSpace : TEXCOORD3;
	float4 Pos_CameraSpace : TEXCOORD4;
};

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_to_PS VS( VS_structure input ) {
	VS_to_PS output = (VS_to_PS)0;
	
	// Convert vertice positions from object space to world space
	output.Pos_WorldSpace = mul( input.Pos, ObjectToWorld );
	// Convert vertice positions from world space to camera space
	output.Pos_CameraSpace = mul( output.Pos_WorldSpace, WorldToCamera );
	// Convert vertice positions from camera space to 2D projection
	output.Pos = mul( output.Pos_CameraSpace, CameraToImage );
	
	// Transform normals and tangent space to world space
	output.Normal_WorldSpace = mul(input.Normal,(float3x3)ObjectToWorld);
	output.UAxis_WorldSpace = mul(input.A.xyz,(float3x3)ObjectToWorld);
	output.VAxis_WorldSpace = mul(input.B.xyz,(float3x3)ObjectToWorld);	
	
	// Give the texture coordinates to the pixel shader
	output.Tex = input.Tex;
	
	// Give the vertex color multiplied with the instance color to the pixel shader
	output.Color = lerp(input.Color.rgb * InstanceColor.rgb, float3(0.0f,0.0f,1.0f), input.Selected);
	
	return output;
}

#define DiffuseMap tex_0
#define BumpSpecularGloss tex_1

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( VS_to_PS input) : SV_Target {
	// If the camera has a world space cutting plane, clip on the negative side.
	UseCuttingPlane(input.Pos_WorldSpace)
	
	// Sample the diffuse map
	float4 DiffuseOriginal = DiffuseMap.Sample( samAnisotropicMipmap, input.Tex.xy );
	
	// Show the color from the vertex shader where alpha is low on the image
	float3 DiffuseColor = DiffuseMap.Sample( samAnisotropicMipmap, input.Tex.xy ) * input.Color;
	
	// Get the texture dimensions for bump mapping
	uint BumpWidth; uint BumpHeight; uint BumpLevels;
	BumpSpecularGloss.GetDimensions(0,BumpWidth,BumpHeight,BumpLevels);
	
	// Sample the bump, specular and gloss map
	float4 BumpSpecularGloss_Center = BumpSpecularGloss.Sample( samSharp, input.Tex.xy );
		float Specularity = BumpSpecularGloss_Center.g;
		float Glossyness = pow(100.0f,BumpSpecularGloss_Center.b);
	float4 BumpSpecularGloss_Left = BumpSpecularGloss.Sample( samSharp, input.Tex.xy - float2(0.5f / BumpWidth, 0.0f) );
	float4 BumpSpecularGloss_Right = BumpSpecularGloss.Sample( samSharp, input.Tex.xy + float2(0.5f / BumpWidth, 0.0f) );
	float4 BumpSpecularGloss_Up = BumpSpecularGloss.Sample( samSharp, input.Tex.xy - float2(0.0f, 0.5f / BumpHeight) );
	float4 BumpSpecularGloss_Down = BumpSpecularGloss.Sample( samSharp, input.Tex.xy + float2(0.0f, 0.5f / BumpHeight) );
	
	// Get the normalized normal and tangent space
	float3x3 TangentSpace = float3x3(normalize(input.UAxis_WorldSpace),normalize(input.VAxis_WorldSpace),normalize(input.Normal_WorldSpace));
	
	// Derive the bump map to get the tangent space normal
	float3 Normal_TangentSpace = float3(BumpSpecularGloss_Left.r - BumpSpecularGloss_Right.r,BumpSpecularGloss_Up.r - BumpSpecularGloss_Down.r,0.2f);
	
	// Convert to world space and normalize
	float3 Normal_WorldSpace = normalize(mul(Normal_TangentSpace,TangentSpace));
	
	// Get the global light
	float3 DiffuseLight;
	float3 SpecularLight;
	Engine_GetDiffuseAndSpecularLight(input.Pos_WorldSpace.xyz,Normal_WorldSpace,Glossyness,DiffuseLight,SpecularLight);
	
	// Mix paint and light
	float4 finalColor = float4((DiffuseColor * DiffuseLight) + (SpecularLight * Specularity),1.0f);
	
	// Show the final color with fog on R,G,B channels
	return float4((lerp(finalColor,FogColor,saturate(length(input.Pos_CameraSpace) / FogDistance) * MaxFogIntensity)).xyz,finalColor.w);
}
