Texture2D colorIn : register( t0 );
SamplerState samLinear : register( s0 );

cbuffer cbChangeOnRenderTarget : register( b0 )
{
    matrix view;
    matrix iView;
	matrix proj;
}

cbuffer cbChangesEveryLight : register( b1 )
{
	float4 lightPos;
}

cbuffer cbChangesEveryResize : register ( b2 )
{
	float2 size;
}

static const float3 g_positions[4] =
{
    float3( -1,  1, 0 ),
    float3(  1,  1, 0 ),
    float3( -1, -1, 0 ),
    float3(  1, -1, 0 )
};

static const float2 g_texcoords[4] = 
{ 
    float2(0,1),
    float2(1,1),
    float2(0,0),
    float2(1,0)
};


//--------------------------------------------------------------------------------------
struct VS_INPUT
{
    float3 Pos : POSITION0;
    float  Alpha : POSITION1;
    float  Size : PSIZE;
    float  Del : POSITION2;
    float  Mov : POSITION3;
};

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float2 Tex : TEXCOORD0;
    float  Alpha : TEXCOORD1;
};


//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_INPUT VS(VS_INPUT input)
{
	return input;
}

//--------------------------------------------------------------------------------------
// Geometry Shader for Lens Flare Effect
//--------------------------------------------------------------------------------------
[maxvertexcount(4)]
void GS_LENSFLARE(point VS_INPUT input[1], inout TriangleStream<PS_INPUT> outputStream)
{
	PS_INPUT output = (PS_INPUT)0;
		
	for(int i = 0; i < 4; i++)
	{
		float lightLength = length(lightPos.xy);
		float3 position = g_positions[i];
		position.x *= size.x;
		position.y *= size.y;
		position *= input[0].Size;
		position.xy *= (1.0f - input[0].Mov * length(lightPos.xy));
		position.xy = position.xy + lightPos.xy * input[0].Del;
		position.z = lightPos.z;
		
		output.Pos = float4(position, 1.0f);
		output.Tex = g_texcoords[i];
		
		output.Alpha = input[0].Alpha;
		if(lightLength > 1.0f)
			output.Alpha *= 1.0f - 3.0f*(lightLength - 1.0f);
		
		outputStream.Append(output);
	}
	
	outputStream.RestartStrip();
}

[maxvertexcount(4)]
void GS(point VS_INPUT input[1], inout TriangleStream<PS_INPUT> outputStream)
{
	PS_INPUT output = (PS_INPUT)0;
		
	for(int i = 0; i < 4; i++)
	{
		float3 position = g_positions[i] * input[0].Size;
		position = mul( (float3x3)iView, position );
		position = position + input[0].Pos;
		
		output.Pos = float4(position, 1.0f);
		output.Pos = mul( view, output.Pos );
		output.Pos = mul( proj, output.Pos );
		
		output.Tex = g_texcoords[i];
		
		outputStream.Append(output);
	}
	
	outputStream.RestartStrip();
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS(PS_INPUT input): SV_TARGET
{
	return colorIn.Sample(samLinear, input.Tex) * float4(1.0f, 1.0f, 1.0f, input.Alpha);
}