#include "world.inc"
#include "material.inc"
#include "oit.inc"


Buffer<uint> StartOffsetBufferSRV : register(t4);
StructuredBuffer<OITLinkBufferElement> LinkBufferSRV : register(t5);
#if MSAA > 1
Texture2DMS<float4, MSAA> BackgroundTexture : register(t6);
#else
Texture2D BackgroundTexture : register(t6);
#endif


struct VS_INPUT
{
	float4 Pos : POSITION;
	float3 Normal : NORMAL;
	float2 TexCoord : TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 Pos : SV_POSITION;
	float2 TexCoord : TEXCOORD0;
};

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float2 TexCoord : TEXCOORD0;
#if MSAA > 1
	uint SampleIndex : SV_SAMPLEINDEX;
#endif
};


#define MAX_SORTED_FRAGMENTS 18

static uint2 SortedFragments[MAX_SORTED_FRAGMENTS+1];



VS_OUTPUT VS(const VS_INPUT In)
{
	VS_OUTPUT Out;
	Out.Pos = In.Pos;
	Out.TexCoord = In.TexCoord;
	return Out;
}


[earlydepthstencil]
float4 PS(PS_INPUT In) : SV_Target
{
	int2 ipos = floor(In.Pos.xy);// - TileRect.xy);
	uint start = uint(ipos.x + Resolution.x * ipos.y);
	uint offset = StartOffsetBufferSRV.Load(start);

	int num_elem = 0;
	while(offset != 0xFFFFFFFF)
	{
		OITLinkBufferElement elem = LinkBufferSRV[offset];

#if MSAA > 1
		uint coverage = UnpackCoverageIntoUint(elem.DepthAndCoverage);
		if(coverage & (1 << In.SampleIndex))
#endif
		{
			SortedFragments[num_elem] = uint2(elem.Color, UnpackDepthIntoUint(elem.DepthAndCoverage));

			// Sort elements in front to back
			if(num_elem > 0){
				int j = num_elem;
				[loop]
				while((j > 0) && (SortedFragments[max(j-1, 0)].y > SortedFragments[j].y))
				{
					int j1 = j-1;
					uint2 tmp           = SortedFragments[j];
					SortedFragments[j]  = SortedFragments[j1];
					SortedFragments[j1] = tmp;
					j--;
				}
			}
			num_elem = min(num_elem+1, MAX_SORTED_FRAGMENTS);
		}

		offset = elem.Next;
	}

	// Get the color by rendering opaque objects
#if MSAA > 1
	float4 col = BackgroundTexture.Load(int2(In.Pos.xy), In.SampleIndex);
#else
	float4 col = BackgroundTexture.Load(int3(In.Pos.xy, 0));
#endif

	// Blend elements
	for(int k=num_elem-1; k>=0; k--)
	{
		float4 fragment_col = UnpackUintIntoFloat4(SortedFragments[k].x);
		col.xyz = lerp(col.xyz, fragment_col.xyz, fragment_col.w);
	}

	return col;
}


