#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 WorldPos : TEXCOORD0;
	float4 Col : COLOR0;
	uint NumVert : COLOR1;
};

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.Col = In.Col;
	Out.NumVert = In.NumVert;
	Out.WorldPos = In.Pos;
	return Out;
}

// Geometry shader for a line
[maxvertexcount(8)]
void GS(lineadj GS_INPUT input[4], inout LineStream<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;
	uint numvert = input[0].NumVert & 0x7;
	bool front_flag = input[0].NumVert & 0x40;
	bool edgecolor = input[0].NumVert & 0x20;
	float inprod1, inprod2;
	if(!front_flag && numvert >= 3){
		inprod1 = (sv1.x-sv0.x) * (sv2.y-sv1.y)
	            - (sv1.y-sv0.y) * (sv2.x-sv1.x);
	}else{
		inprod1 = 1.0;
	}
	if(!front_flag && 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){
		for(uint i=0; i<4; i++){
			if((input[i].NumVert & 0x80) != 0)
				continue;
			uint i2 = (i+1)%4;
			uint e2 = edgecolor ? i : i2;
			if(OITRenderMode == 1 && (a*input[i].Col.a < 1.0 || a*input[e2].Col.a < 1.0)) continue; // opaque only
#if OIT
			if(OITRenderMode == 2 && a*input[i].Col.a == 1.0 && a*input[e2].Col.a == 1.0) continue; // transparent only
#endif
			if(input[i].Col.a > 0.0 || input[e2].Col.a > 0.0){
				output.Pos = input[i].Pos;
				output.Col = input[i].Col;
				output.Col.a *= a;
				output.WorldPos = input[i].WorldPos;
				stream.Append(output);

				output.Pos = input[i2].Pos;
				output.Col = input[e2].Col;
				output.Col.a *= a;
				output.WorldPos = input[i2].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
}

