matrix World;
matrix View;
matrix Projection;

struct vsInput
{
	float4 Pos 	: POSITION;
	float2 Tex 	: TEXCOORD;
};

struct psInput
{
	float4 Pos 		: SV_POSITION;
	float2 Tex 		: TEXCOORD0;
};

//=============================================================================

psInput vShader(vsInput input)
{
	psInput output;
	
	output.Pos = mul(input.Pos, World);
	output.Pos = mul(output.Pos, View);
	output.Pos = mul(output.Pos, Projection);	
	output.Tex = input.Tex;

	return output;
}

//=============================================================================

float2 pxsize = float2(1.f  / 1280.f, 1.f / 720.f);
float2 right = float2(1.f / 1280.f, 0.f);
float2 up = float2(0.f, 1.f / 720.f);

float single_step = 1.f / 255.f;

#define MAXIDX 4

SamplerState PointSampler
{
	Filter = MIN_MAG_MIP_POINT;
	AddressU = Clamp;
	AddressV = Clamp;
};

Texture2D BaseTexture;
Texture2D CurrentLen;

//=============================================================================

float2 propHorizontal(float2 coord)
{	
	float2 ret = 0.f;

	// Going Left
	float2 uv = coord;
	int i = 0;
	float last;
	for (; i<MAXIDX; i++, last = 0.f)
	{
		uv = coord - (i * right * 4);
		last = CurrentLen.SampleLevel(PointSampler, uv, 0).r;
		if (last < (4 * single_step))
			break;
	}
	ret.r = i * single_step * 4 + last;

	// Going right
	i = 0;
	uv = coord;
	for (; i<MAXIDX; i++, last = 0.f)
	{
		uv = coord + (i * right * 4);
		last = CurrentLen.SampleLevel(PointSampler, uv, 0).g;
		if (last < (4 * single_step))
			break;
	}
	ret.g = i * single_step * 4 + last;

	return ret;
}

float2 propVertical(float2 coord)
{
	float2 ret = 0.f;

	// Going Down
	float2 uv = coord;
	int i = 0;
	float last;
	for (; i<MAXIDX; i++, last = 0.f)
	{
		uv = coord + (i * up * 4);
		last = CurrentLen.SampleLevel(PointSampler, uv, 0).b;
		if (last < (4 * single_step))
			break;
	}
	ret.r = i * single_step * 4 + last;

	// Going Up
	i = 0;
	uv = coord;
	for (; i<MAXIDX; i++, last = 0.f)
	{
		uv = coord - (i * up * 4);
		last = CurrentLen.SampleLevel(PointSampler, uv, 0).a;
		if (last < (4 * single_step))
			break;
	}
	ret.g = i * single_step * 4 + last;

	return ret;
}

float4 pShader(psInput input) : SV_Target
{
	float4 ret = 0.f;
	float4 hpix[2];
	float4 vpix[2];

	hpix[0].r = BaseTexture.Sample(PointSampler, input.Tex - 1 * right).g;
	hpix[0].g = hpix[0].r ? BaseTexture.Sample(PointSampler, input.Tex - 2 * right).g : 0.f;
	hpix[0].b = hpix[0].g ? BaseTexture.Sample(PointSampler, input.Tex - 3 * right).g : 0.f;
	hpix[0].a = hpix[0].b ? BaseTexture.Sample(PointSampler, input.Tex - 4 * right).g : 0.f;

	hpix[1].r = BaseTexture.Sample(PointSampler, input.Tex + 1 * right).g;
	hpix[1].g = hpix[1].r ? BaseTexture.Sample(PointSampler, input.Tex + 2 * right).g : 0.f;
	hpix[1].b = hpix[1].g ? BaseTexture.Sample(PointSampler, input.Tex + 3 * right).g : 0.f;
	hpix[1].a = hpix[1].b ? BaseTexture.Sample(PointSampler, input.Tex + 4 * right).g : 0.f;
	
	ret.r = dot(hpix[0], float4(1.f, 1.f, 1.f, 1.f));
	ret.g = dot(hpix[1], float4(1.f, 1.f, 1.f, 1.f));

	vpix[0].r = BaseTexture.Sample(PointSampler, input.Tex + 1 * up).r;
	vpix[0].g = vpix[0].r ? BaseTexture.Sample(PointSampler, input.Tex + 2 * up).r : 0.f;
	vpix[0].b = vpix[0].g ? BaseTexture.Sample(PointSampler, input.Tex + 3 * up).r : 0.f;
	vpix[0].a = vpix[0].b ? BaseTexture.Sample(PointSampler, input.Tex + 4 * up).r : 0.f;

	vpix[1].r = BaseTexture.Sample(PointSampler, input.Tex - 1 * up).r;
	vpix[1].g = vpix[1].r ? BaseTexture.Sample(PointSampler, input.Tex - 2 * up).r : 0.f;
	vpix[1].b = vpix[1].g ? BaseTexture.Sample(PointSampler, input.Tex - 3 * up).r : 0.f;
	vpix[1].a = vpix[1].b ? BaseTexture.Sample(PointSampler, input.Tex - 4 * up).r : 0.f;
	
	ret.b = dot(vpix[0], float4(1.f, 1.f, 1.f, 1.f));
	ret.a = dot(vpix[1], float4(1.f, 1.f, 1.f, 1.f));

	return (ret * single_step) * BaseTexture.Sample(PointSampler, input.Tex).ggrr;
}

float4 PropLength(psInput input) : SV_Target
{
	float4 ret;
	ret.rg = propHorizontal(input.Tex);
	ret.ba = propVertical(input.Tex);
	return ret;
}
//=============================================================================
DepthStencilState NoDepthStencilTest
{
	DepthEnable = false;

	StencilEnable = true;
	StencilReadMask  = 0xFFFFFFFF;
	StencilWriteMask = 0;

    	BackFaceStencilFunc = Equal;
	BackFaceStencilPass = Keep;
};

technique10 Default
{
	pass P0
	{
		SetVertexShader(CompileShader(vs_4_0, vShader()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, pShader()));
		SetDepthStencilState(NoDepthStencilTest, 1);
	}
}

technique10 Propagate
{
	pass P0
	{
		SetVertexShader(CompileShader(vs_4_0, vShader()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, PropLength()));
		SetDepthStencilState(NoDepthStencilTest, 1);
	}
}
//=============================================================================