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


struct VS_INPUT
{
	float4 Pos : POSITION;
	float4 Col : COLOR0;
	uint NumVert : NUMVERTEX;
};

struct GS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 ViewPos : TEXCOORD0;
	float4 Col : COLOR0;
	uint NumVert : COLOR1;
};

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

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	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.Col = In.Col;
	Out.NumVert = In.NumVert;
	return Out;
}

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

	float2 sv0 = input[0].Pos.xy / input[0].Pos.w;
	float2 sv1 = input[1].Pos.xy / input[1].Pos.w;
	float2 sv2 = input[2].Pos.xy / input[2].Pos.w;
	float2 sv3 = input[3].Pos.xy / input[3].Pos.w;
	float inprod1, inprod2;
	if(input[0].NumVert >= 3){
		inprod1 = (sv1.x-sv0.x) * (sv2.y-sv1.y)
	            - (sv1.y-sv0.y) * (sv2.x-sv1.x);
	}else{
		inprod1 = 1.0;
	}
	if(input[0].NumVert >= 4){
		inprod2 = (sv2.x-sv0.x) * (sv3.y-sv2.y)
	            - (sv2.y-sv0.y) * (sv3.x-sv2.x);
	}else{
		inprod2 = -1.0;
	}

	float a = (inprod1 > 0 || inprod2 > 0) ? 1.0 : BackLineAlpha * BackLineAlpha;
	if(a > 0.0){
#if OIT
		if(OITRenderMode == 1 && a*input[0].Col.a < 1.0) return; // opaque only
		if(OITRenderMode == 2 && a*input[0].Col.a == 1.0) return;// transparent only
#endif
		for(uint i=0; i<4; i++){
			if(input[i].Col.a > 0.0){
				uint i2 = (i+1)%4;

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

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

				output.Col = input[i].Col;
				output.Col.a *= a;

				output.Pos = pos1;
				output.Pos.xy -= pos1.w * vec.xy;
				stream.Append(output);

				output.Pos = pos1;
				output.Pos.xy += pos1.w * vec.xy;
				stream.Append(output);

				output.Pos = pos2;
				output.Pos.xy -= pos2.w * vec.xy;
				stream.Append(output);

				output.Pos = pos2;
				output.Pos.xy += pos2.w * vec.xy;
				stream.Append(output);

				stream.RestartStrip();
			}
		}
	}
}

#if OIT
[earlydepthstencil]
#endif
float4 PS(PS_INPUT In) : SV_Target
{
#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
}

