//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
Texture2D txDiffuse : register( t0 );
Texture2D txAttribute : register( t1 );
Texture2D txNormal : register( t2 );

SamplerState samLinear : register( s0 );
SamplerState samPoint : register( s1 );

cbuffer cbNeverChanges : register( b0 )
{
    float generalAlpha;
};

cbuffer cbChangeOnRenderTarget : register( b1 )
{
    matrix view[6];
	matrix proj;
	matrix reflectM;
	float4 cameraPos;
};

cbuffer cbChangesEveryObject : register( b2 )
{
    matrix world;
    float4 meshColor;
	float4 material;
};

//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    float4 Pos : POSITION;
	float3 Normal : NORMAL0;
    float2 Tex : TEXCOORD0;
	float3 Tangent : TANGENT0;
	float3 Binormal : BINORMAL0;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
	float3 Normal : NORMAL0;
	float2 Tex : TEXCOORD0;
	float4 Worldpos : TEXCOORD1;
	float  Length : TEXCOORD2;
	float3 Tangent : TANGENT0;
	float3 Binormal : BINORMAL0;
};

struct PS_CM_INPUT
{
    float4 Pos : SV_POSITION;
	float3 Normal : NORMAL0;
	float2 Tex : TEXCOORD0;
	float4 Worldpos : TEXCOORD1;
	float  Length : TEXCOORD2;
	float3 Tangent : TANGENT0;
	float3 Binormal : BINORMAL0;
	uint Rt : SV_RenderTargetArrayIndex;
};

struct PS_OUT
{
	float4 color : SV_Target0;
	float4 normal : SV_Target1;
	float4 pos : SV_Target2;
	float4 material : SV_Target3;
};


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;

	output.Pos = mul( world, input.Pos );
	output.Pos = mul( reflectM, output.Pos );
    output.Pos = mul( view[0], output.Pos );
    output.Pos = mul( proj, output.Pos );
	output.Normal = mul( (float3x3)world, input.Normal);
	output.Tangent = mul( (float3x3)world, input.Tangent);
	output.Binormal = mul( (float3x3)world, input.Binormal);
	output.Worldpos = mul( world, input.Pos );
	output.Length = length( output.Worldpos - cameraPos );
    output.Tex = input.Tex;
    
    return output;
}

PS_INPUT VS_CM( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;

    output.Pos = mul( world, input.Pos );

	output.Normal = mul( (float3x3)world, input.Normal);
	output.Tangent = mul( (float3x3)world, input.Tangent);
	output.Binormal = mul( (float3x3)world, input.Binormal);
	output.Worldpos = mul( world, input.Pos );
	output.Length = length( output.Worldpos - cameraPos );
    output.Tex = input.Tex;
    
    return output;
}

//--------------------------------------------------------------------------------------
// Geometry Shader
//--------------------------------------------------------------------------------------

[maxvertexcount(18)]
void GS_CM( triangle PS_INPUT input[3], inout TriangleStream<PS_CM_INPUT> outstream )
{
    for( uint i = 0; i < 6; i++ )
    {
		PS_CM_INPUT output;
		output.Rt = i;

        for( uint v = 0; v < 3; v++ )
        {
            output.Pos = mul( view[i], input[v].Pos );
            output.Pos = mul( proj, output.Pos );

			output.Normal = input[v].Normal;
			output.Tangent = input[v].Tangent;
			output.Binormal = input[v].Binormal;
			output.Tex = input[v].Tex;
			output.Worldpos = input[v].Worldpos;
			output.Length = input[v].Length;

            outstream.Append( output );
        }
        outstream.RestartStrip();
    }
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
PS_OUT PS( PS_INPUT input)
{
	PS_OUT ret = (PS_OUT)0;

	ret.color = txDiffuse.Sample( samLinear, input.Tex );

	float3x3 tangentM = float3x3( input.Tangent, input.Binormal, input.Normal );
	float3 normal = txNormal.Sample( samLinear, input.Tex );
	normal = normalize((normal - 0.5f) * 2.0f);
	ret.normal.xyz = mul( normal, tangentM); ret.normal.w = 0.0f;

	ret.pos = input.Worldpos; ret.pos.w = input.Length;
	ret.material = material;
	ret.material.x = 0.0f;

	float4 att = txAttribute.Sample( samLinear, input.Tex );

	ret.material.x = att.x;
	ret.color = meshColor * att.y + ret.color * (1.0f - att.y);

    return ret;
}

PS_OUT PS_CM( PS_CM_INPUT input)
{
	PS_OUT ret = (PS_OUT)0;

	ret.color = txDiffuse.Sample( samLinear, input.Tex );

	float3x3 tangentM = float3x3( input.Tangent, input.Binormal, input.Normal );
	float3 normal = txNormal.Sample( samLinear, input.Tex );
	normal = normalize((normal - 0.5f) * 2.0f);
	ret.normal.xyz = mul( normal, tangentM); ret.normal.w = 0.0f;

	ret.pos = input.Worldpos; ret.pos.w = input.Length;
	ret.material = material;
	ret.material.x = 0.0f;

	float4 att = txAttribute.Sample( samLinear, input.Tex );

	ret.material.x = att.x;
	ret.color = meshColor * att.y + ret.color * (1.0f - att.y);

    return ret;
}
