#include "world.inc"
#include "material.inc"
#if OIT
#include "oit.inc"
#endif


struct VS_INPUT
{
	float4 Pos : POSITION;
	float4 Col : COLOR0;
};

struct GS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 ViewPos : TEXCOORD0;
	float4 WorldPos : TEXCOORD1;
	float4 Col : COLOR0;
};

struct GS_OUTPUT
{
	float4 Pos : SV_POSITION;
	float4 WorldPos : TEXCOORD0;
	float4 Col : COLOR0;
};

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 WorldPos : TEXCOORD0;
	float4 Col : COLOR0;
#if MSAA
	uint Coverage : SV_COVERAGE;
#endif
};

#include "oit_store.inc"


GS_INPUT VS(const VS_INPUT In)
{
	GS_INPUT Out;
	Out.Pos = mul(In.Pos, WorldViewProj);
	Out.ViewPos = mul(In.Pos, WorldView);
	Out.WorldPos = In.Pos;
	Out.Col = In.Col;
	return Out;
}

// Geometry shader for a line with a width
[maxvertexcount(4)]
void GS(line GS_INPUT input[2], inout TriangleStream<GS_OUTPUT> stream)
{
	GS_OUTPUT output;

	float4 pos1 = input[0].Pos;
	float4 pos2 = input[1].Pos;
	if(pos1.z >= 0 && pos2.z >= 0){
		// normal display
	}else if(pos1.z >= 0 && pos2.z < 0){
		float t = (ClipPlane.x - input[0].ViewPos.z) / (input[1].ViewPos.z - input[0].ViewPos.z);
		float4 viewpos = (1-t)*input[0].ViewPos + t*input[1].ViewPos;
		pos2 = mul(viewpos, Proj);
	}else if(pos1.z < 0 && pos2.z >= 0){
		float t = (ClipPlane.x-input[1].ViewPos.z) / (input[0].ViewPos.z-input[1].ViewPos.z);
		float4 viewpos = (1-t)*input[1].ViewPos + t*input[0].ViewPos;
		pos1 = mul(viewpos, Proj);
	}else{
		return;
	}

	float2 vec = normalize(pos1.yx / pos1.w - pos2.yx / pos2.w);
	vec.x *= -LineWidth / Resolution.x;
	vec.y *= LineWidth / Resolution.y;

	output.Col = input[0].Col;

	output.Pos = pos1;
	output.Pos.xy -= pos1.w * vec.xy;
	output.WorldPos = input[0].WorldPos;
	stream.Append(output);

	output.Pos = pos1;
	output.Pos.xy += pos1.w * vec.xy;
	output.WorldPos = input[0].WorldPos;
	stream.Append(output);

	output.Col = input[1].Col;

	output.Pos = pos2;
	output.Pos.xy -= pos2.w * vec.xy;
	output.WorldPos = input[1].WorldPos;
	stream.Append(output);

	output.Pos = pos2;
	output.Pos.xy += pos2.w * vec.xy;
	output.WorldPos = input[1].WorldPos;
	stream.Append(output);

	stream.RestartStrip();
}

#if OIT
[earlydepthstencil]
#endif
float4 PS(PS_INPUT In) : SV_Target
{
	if(IsArbClipped(In.WorldPos.xyz))
		discard;
#if OIT
	StoreOIT(In, In.Col);
	return float4(0, 0, 0, 0);	// This does not affect anything because RenderTargetWriteMask is 0.
#else
	return In.Col;
#endif
}

