float4x4 g_matView;
float4x4 g_matInvProj;
float4x4 g_matProj;

float2 g_RTSize;

float g_Radius = 1;

float3 g_SamplePoints[32];

texture g_texDepth;
sampler2D g_sDepth = sampler_state
{
    Texture = <g_texDepth>;
    AddressU = Clamp;
    AddressV = Clamp;
    MipFilter = NONE;
    MagFilter = POINT;
    MinFilter = POINT;
};

texture g_texWorld;
sampler2D g_sWorld = sampler_state
{
    Texture = <g_texWorld>;
    AddressU = Clamp;
    AddressV = Clamp;
    MipFilter = NONE;
    MagFilter = POINT;
    MinFilter = POINT;
};

texture g_texNoiseNormal;
sampler2D g_sNoiseNormal = sampler_state
{
    Texture = <g_texNoiseNormal>;
    AddressU = Wrap;
    AddressV = Wrap;
    MipFilter = NONE;
    MagFilter = LINEAR;
    MinFilter = LINEAR;
};

#define WPT_DEPTH 0
#define WPT_LINEARDEPTH 1
#define WPT_WORLDPOS 2

float4 BuildSSAO(float2 ScreenCoord:TEXCOORD0, uniform int wpt) : COLOR
{
	//get position in eyespace

	float3 eyepoint;

	if (wpt == WPT_LINEARDEPTH)
	{
		float depth = tex2D(g_sDepth, ScreenCoord).r;
		//if (depth == 2000)
		//	return 1;
		float2 v = mul(ScreenCoord * float2(2, -2) - float2(1, -1) + float2(-1, 1) / g_RTSize, g_matInvProj);
		eyepoint = depth * float3(v , 1);
	}
	else if (wpt == WPT_DEPTH)
	{
		float depth = tex2D(g_sDepth, ScreenCoord).r;
		float4 vp = float4(ScreenCoord * float2(2, -2) - float2(1, -1) + float2(-1, 1) / g_RTSize, depth, 1);
		float4 v = mul(vp, g_matInvProj);
		eyepoint = v.xyz/v.w;
	}
	else if (wpt == WPT_WORLDPOS)
	{
		float4 vp = mul(float4(tex2D(g_sWorld, ScreenCoord).rgb, 1), g_matView);
		eyepoint = vp.xyz;
	}

	//return eyepoint.z / 2000;

	float bl = 0;

	float4 reflvec = float4(tex2D(g_sNoiseNormal,  ScreenCoord * g_RTSize / 128).rgb, 0);
	//return float4(reflvec, 1);
	reflvec = reflvec * 2 - 1;
    
	int i = 0;
	for (; i < 32; i++)
    {
		//sample point in sphere
		float3 spherepoint = eyepoint + g_Radius * reflect(g_SamplePoints[i], reflvec) * 0.3;
		//float3 spherepoint = eyepoint + g_Radius * g_SamplePoints[i];

		float4 vs = mul(spherepoint, g_matProj);
		float2 ss = vs.xy / vs.w;
       	//project into clip space and lookup its z value

		//float2 ss = spherepoint.xy / spherepoint.z * float2(g_matProj[0][0], g_matProj[1][1]);
		float2 sn = float2(ss.x, -ss.y) * 0.5f + 0.5f;
		float sz;

		if (wpt == WPT_LINEARDEPTH)
		{
			sz = tex2D(g_sDepth, sn).r;
		}
		else if (wpt == WPT_DEPTH)
		{
			sz = tex2D(g_sDepth, sn).r; //todo
		}
		else if (wpt == WPT_WORLDPOS)
		{
			float4 swpos = mul(float4(tex2D(g_sWorld, sn).rgb, 1), g_matView);
			sz = swpos.z;
		}
		
		float zd = 30 * max(spherepoint.z - sz, 0.0);
		bl += 1.0 / (1.0 + zd * zd); 
   }

	return bl / i;
}

stateblock RSSSAO = stateblock_state
{
	CullMode = NONE;
    ZEnable = false;
	AlphaBlendEnable = false;
    AlphaTestEnable = false;
};

technique RenderSSAO_Depth
{
    pass P0
    {      
		StateBlock = (RSSSAO);

        VertexShader = null;
        PixelShader  = compile ps_3_0 BuildSSAO(WPT_DEPTH);
    }
}

technique RenderSSAO_LinearDepth
{
    pass P0
    {      
		StateBlock = (RSSSAO);

        VertexShader = null;
        PixelShader  = compile ps_3_0 BuildSSAO(WPT_LINEARDEPTH);
    }
}

technique RenderSSAO_World
{
    pass P0
    {      
		StateBlock = (RSSSAO);

        VertexShader = null;
        PixelShader  = compile ps_3_0 BuildSSAO(WPT_WORLDPOS);
    }
}