#include "color.effect"

uniform float4x4 ViewProj;
uniform texture2d image;
uniform float multiplier;
uniform texture2d mask;
uniform texture2d blurred;

sampler_state texSampler {
	Filter    = Linear;
	AddressU  = Clamp;
	AddressV  = Clamp;
};

struct VertData {
	float4 pos : POSITION;
	float2 uv  : TEXCOORD0;
};

struct VertInOut {
	float2 uv  : TEXCOORD0;
	float4 pos : POSITION;
};

struct FragData {
	float2 uv  : TEXCOORD0;
};

struct FragPos {
	float4 pos : POSITION;
};

VertInOut VSDefault(VertData v_in)
{
	VertInOut v_out;
	v_out.uv = v_in.uv;
	v_out.pos = mul(float4(v_in.pos.xyz, 1.), ViewProj);
	return v_out;
}

FragPos VSConvertUnorm(uint id : VERTEXID)
{
	float idHigh = float(id >> 1);
	float idLow = float(id & uint(1));

	float x = idHigh * 4.0 - 1.0;
	float y = idLow * 4.0 - 1.0;

	FragPos vert_out;
	vert_out.pos = float4(x, y, 0.0, 1.0);
	return vert_out;
}

float4 Mask(FragData f_in)
{
	float4 rgba = image.Sample(texSampler, f_in.uv);
	float3 blur = srgb_nonlinear_to_linear(blurred.Sample(texSampler, f_in.uv).rgb);
	// Between blurred and unblurred area we interpolate to have a smooth transition.
	float m = smoothstep(0.85, 0.95, mask.Sample(texSampler, f_in.uv).a);
	float3 out_lin = lerp(blur, rgba.rgb, m);
	return float4(out_lin, rgba.a);
}

float4 PSMaskMultiply(FragData f_in) : TARGET
{
	float4 rgba = Mask(f_in);
	rgba.rgb *= multiplier;
	return rgba;
}

float4 PSMaskTonemap(FragData f_in) : TARGET
{
	float4 rgba = Mask(f_in);
	rgba.rgb = rec709_to_rec2020(rgba.rgb);
	rgba.rgb = reinhard(rgba.rgb);
	rgba.rgb = rec2020_to_rec709(rgba.rgb);
	return rgba;
}

float4 PSMaskMultiplyTonemap(FragData f_in) : TARGET
{
	float4 rgba = Mask(f_in);
	rgba.rgb *= multiplier;
	rgba.rgb = rec709_to_rec2020(rgba.rgb);
	rgba.rgb = reinhard(rgba.rgb);
	rgba.rgb = rec2020_to_rec709(rgba.rgb);
	return rgba;
}

float4 PSMask(FragData f_in) : TARGET
{
	return Mask(f_in);
}

float4 PSDefault(FragPos f_in) : TARGET
{
	float4 rgba = image.Load(int3(f_in.pos.xy, 0));
	return rgba;
}

float4 PSConvertUnorm(FragPos f_in) : TARGET
{
	float4 rgba = image.Load(int3(f_in.pos.xy, 0));
	rgba.rgb = srgb_linear_to_nonlinear(rgba.rgb);
	return rgba;
}

float4 PSConvertUnormTonemap(FragPos f_in) : TARGET
{
	float4 rgba = image.Load(int3(f_in.pos.xy, 0));
	rgba.rgb = rec709_to_rec2020(rgba.rgb);
	rgba.rgb = reinhard(rgba.rgb);
	rgba.rgb = rec2020_to_rec709(rgba.rgb);
	rgba.rgb = srgb_linear_to_nonlinear(rgba.rgb);
	return rgba;
}

float4 PSConvertUnormMultiplyTonemap(FragPos f_in) : TARGET
{
	float4 rgba = image.Load(int3(f_in.pos.xy, 0));
	rgba.rgb *= multiplier;
	rgba.rgb = rec709_to_rec2020(rgba.rgb);
	rgba.rgb = reinhard(rgba.rgb);
	rgba.rgb = rec2020_to_rec709(rgba.rgb);
	rgba.rgb = srgb_linear_to_nonlinear(rgba.rgb);
	return rgba;
}

technique Draw
{
	pass
	{
		vertex_shader = VSDefault(v_in);
		pixel_shader  = PSMask(f_in);
	}
}

technique DrawMultiply
{
	pass
	{
		vertex_shader = VSDefault(v_in);
		pixel_shader  = PSMaskMultiply(f_in);
	}
}

technique DrawTonemap
{
	pass
	{
		vertex_shader = VSDefault(v_in);
		pixel_shader  = PSMaskTonemap(f_in);
	}
}

technique DrawMultiplyTonemap
{
	pass
	{
		vertex_shader = VSDefault(v_in);
		pixel_shader  = PSMaskMultiplyTonemap(f_in);
	}
}

technique ConvertUnorm
{
	pass
	{
		vertex_shader = VSConvertUnorm(id);
		pixel_shader  = PSConvertUnorm(f_in);
	}
}

technique ConvertUnormTonemap
{
	pass
	{
		vertex_shader = VSConvertUnorm(id);
		pixel_shader  = PSConvertUnormTonemap(f_in);
	}
}

technique ConvertUnormMultiplyTonemap
{
	pass
	{
		vertex_shader = VSConvertUnorm(id);
		pixel_shader  = PSConvertUnormMultiplyTonemap(f_in);
	}
}
