// Warpedge video shader for VirtualDub, ps_2_0 version
// Copyright (C) 2005 Avery Lee.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

			// desc			x	y	z	w
float4 vd_vpsize;	// viewport		w	h	1/h	1/w
float4 vd_srcsize;	// source size		w	h	1/h	1/w
float4 vd_texsize;	// source texture size	w	h	1/h	1/w
float4 vd_vpcorrect2;	// target screenspace	xscale	yscale	yadd	xadd

//////////////////////////////////////////////////////////////////////////

texture vd_srctexture;

texture vd_temptexture : RENDERCOLORTARGET <
	string Format = "A8R8G8B8";
	float2 ViewportRatio = {1.0, 1.0};
>;

texture vd_temptexture2 : RENDERCOLORTARGET <
	string Format = "A8R8G8B8";
	float2 ViewportRatio = {1.0, 1.0};
>;

float4 vd_temptexture_size;
float4 vd_temptexture2_size;

sampler src = sampler_state {
	texture = <vd_srctexture>;
	addressu = clamp;
	addressv = clamp;
	minfilter = linear;
	magfilter = linear;
	mipfilter = none;
};

sampler srcp = sampler_state {
	texture = <vd_srctexture>;
	addressu = clamp;
	addressv = clamp;
	minfilter = point;
	magfilter = point;
	mipfilter = none;
};

sampler temp = sampler_state {
	texture = <vd_temptexture>;
	addressu = clamp;
	addressv = clamp;
	minfilter = linear;
	magfilter = linear;
	mipfilter = none;
};

sampler temppoint = sampler_state {
	texture = <vd_temptexture>;
	addressu = clamp;
	addressv = clamp;
	minfilter = point;
	magfilter = point;
	mipfilter = none;
};

sampler temp2 = sampler_state {
	texture = <vd_temptexture2>;
	addressu = clamp;
	addressv = clamp;
	minfilter = linear;
	magfilter = linear;
	mipfilter = none;
};

extern sampler samp : register(s0);
extern sampler samp1 : register(s1);

texture bloomtex1 : RENDERCOLORTARGET <
	float2 ViewportRatio = { 1, 1 };
>;

float4 bloomtex1_size;

texture bloomtex2 : RENDERCOLORTARGET <
	float2 ViewportRatio = { 1, 1 };
>;

float4 bloomtex2_size;

sampler bloom1 = sampler_state {
	Texture = <bloomtex1>;
	AddressU = CLAMP;
	AddressV = CLAMP;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
};

sampler bloom2 = sampler_state {
	Texture = <bloomtex2>;
	AddressU = CLAMP;
	AddressV = CLAMP;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
};

// 1 15 105 455 1365 3003 5005 6435
#if 1
static const half tap0 = 1.0f/32768.0f;
static const half tap1 = 15.0f/32768.0f;
static const half tap2 = 105.0f/32768.0f;
static const half tap3 = 455.0f/32768.0f;
static const half tap4 = 1365.0f/32768.0f;
static const half tap5 = 3003.0f/32768.0f;
static const half tap6 = 5005.0f/32768.0f;
static const half tap7 = 6435.0f/32768.0f;
static const half w0 = tap0+tap1;
static const half w1 = tap2+tap3;
static const half w2 = tap4+tap5;
static const half w3 = tap6+tap7;
static const half w4 = tap7+tap6;
static const half w5 = tap5+tap4;
static const half w6 = tap3+tap2;
static const half w7 = tap1+tap0;
static const half du0 = tap1 / w0 - 7.0;
static const half du1 = tap3 / w1 - 5.0;
static const half du2 = tap5 / w2 - 3.0;
static const half du3 = tap7 / w3 - 1.0;
static const half du4 = tap6 / w4 + 1.0;
static const half du5 = tap4 / w5 + 3.0;
static const half du6 = tap2 / w6 + 5.0;
static const half du7 = tap0 / w7 + 7.0;
#else
static const half w0 = 0.25;
static const half w1 = 0.50;
static const half w2 = 0.75;
static const half w3 = 1.00;
static const half w4 = 1.00;
static const half w5 = 0.75;
static const half w6 = 0.50;
static const half w7 = 0.25;
static const half du0 = -7.0;
static const half du1 = -5.0;
static const half du2 = -3.0;
static const half du3 = -1.0;
static const half du4 = +1.0;
static const half du5 = +3.0;
static const half du6 = +5.0;
static const half du7 = +7.0;
#endif

void VS_Bloom(	uniform float2 srcpixsize,
		uniform float4 srctexsize,
		uniform float2 dstpixsize,
		uniform float4 dsttexsize,
		uniform float2 direction,
		float4 pos: POSITION,
		float2 uv1: TEXCOORD1,
		out float4 oPos : POSITION0,
		out float2 oT0 : TEXCOORD0,
		out float2 oT1 : TEXCOORD1,
		out float2 oT2 : TEXCOORD2,
		out float2 oT3 : TEXCOORD3,
		out float2 oT4 : TEXCOORD4,
		out float2 oT5 : TEXCOORD5,
		out float2 oT6 : TEXCOORD6,
		out float2 oT7 : TEXCOORD7)
{
	oPos.xy = (uv1 * dstpixsize.xy - float2(0.5, 0.5)) * 2.0 * dsttexsize.wz;
	oPos.x = oPos.x - 1.0f;
	oPos.y = 1.0f - oPos.y;
	oPos.z = 0.0f;
	oPos.w = 1.0f;

	float2 uv = uv1*srcpixsize.xy*srctexsize.wz;
	float2 delta = direction*srctexsize.wz;
	oT0 = uv + du0*delta;
	oT1 = uv + du1*delta;
	oT2 = uv + du2*delta;
	oT3 = uv + du3*delta;
	oT4 = uv + du4*delta;
	oT5 = uv + du5*delta;
	oT6 = uv + du6*delta;
	oT7 = uv + du7*delta;
}

float maxcomp(float3 v) { return max(v.x, max(v.y, v.z)); }

#if 1
static const float base = 100.0;

float map(float l) {
	return (pow(base, l) - 1.0) / (base - 1.0);
}

float unmap(float l) {
	return log((base-1.0)*l + 1.0) / log(base);
}
#elif 1
float map(float l) {
	return (exp(l) - 1.0) / 1.7;
}

float unmap(float l) {
	return log(1.7*l + 1.0);
}
#else
float map(float l) {
	return l;
}

float unmap(float l) {
	return l;
}
#endif

float4 PS_Bloom1(uniform sampler src,
		float2 uv0 : TEXCOORD0,
		float2 uv1 : TEXCOORD1,
		float2 uv2 : TEXCOORD2,
		float2 uv3 : TEXCOORD3,
		float2 uv4 : TEXCOORD4,
		float2 uv5 : TEXCOORD5,
		float2 uv6 : TEXCOORD6,
		float2 uv7 : TEXCOORD7) : COLOR0
{
	static const float3 lumacoeff = {0.30, 0.59, 0.11};
	float l0 = map(dot(tex2D(src, uv0).xyz, lumacoeff));
	float l1 = map(dot(tex2D(src, uv1).xyz, lumacoeff));
	float l2 = map(dot(tex2D(src, uv2).xyz, lumacoeff));
	float l3 = map(dot(tex2D(src, uv3).xyz, lumacoeff));
	float l4 = map(dot(tex2D(src, uv4).xyz, lumacoeff));
	float l5 = map(dot(tex2D(src, uv5).xyz, lumacoeff));
	float l6 = map(dot(tex2D(src, uv6).xyz, lumacoeff));
	float l7 = map(dot(tex2D(src, uv7).xyz, lumacoeff));

	float l = l0*w0
		+ l1*w1
		+ l2*w2
		+ l3*w3
		+ l4*w4
		+ l5*w5
		+ l6*w6
		+ l7*w7;

	return l;
}

float4 PS_Bloom2(uniform sampler src,
		float2 uv0 : TEXCOORD0,
		float2 uv1 : TEXCOORD1,
		float2 uv2 : TEXCOORD2,
		float2 uv3 : TEXCOORD3,
		float2 uv4 : TEXCOORD4,
		float2 uv5 : TEXCOORD5,
		float2 uv6 : TEXCOORD6,
		float2 uv7 : TEXCOORD7) : COLOR0
{
	static const float3 lumacoeff = {0.30, 0.59, 0.11};
	float l0 = tex2D(src, uv0).g;
	float l1 = tex2D(src, uv1).g;
	float l2 = tex2D(src, uv2).g;
	float l3 = tex2D(src, uv3).g;
	float l4 = tex2D(src, uv4).g;
	float l5 = tex2D(src, uv5).g;
	float l6 = tex2D(src, uv6).g;
	float l7 = tex2D(src, uv7).g;

	float l = l0*w0
		+ l1*w1
		+ l2*w2
		+ l3*w3
		+ l4*w4
		+ l5*w5
		+ l6*w6
		+ l7*w7;

	return unmap(l);
}

void VS_Final(	uniform float4 srcpixsize,
		uniform float4 srctexsize,
		uniform float4 bloompixsize,
		uniform float4 bloomtexsize,
		uniform float4 dstpixsize,
		uniform float4 dsttexsize,
		float4 pos: POSITION0,
		float2 uv1: TEXCOORD1,
		out float4 oPos : POSITION0,
		out float2 oT0 : TEXCOORD0,
		out float2 oT1 : TEXCOORD1)
{
	oPos.xy = (uv1 * dstpixsize.xy - float2(0.5, 0.5)) * 2.0 * dsttexsize.wz;
	oPos.x = oPos.x - 1.0f;
	oPos.y = 1.0f - oPos.y;
	oPos.z = 0.0f;
	oPos.w = 1.0f;

	oT0 = uv1*srcpixsize.xy*srctexsize.wz;
	oT1 = uv1*bloompixsize.xy*bloomtexsize.wz;
}

float3 tonemap(float3 px) {
	float mx = dot(px, float3(0.30, 0.59, 0.11));

	if (mx > 0.5) {
		float r = 2.0;
		float v = mx / (mx + r) * (0.5+r);

		px *= v/mx;
	}

	mx = max(px.r, max(px.g, px.b));
	if (mx > 1.0) {
		float l = dot(px, float3(0.30, 0.59, 0.11));
		if (l < 1.0)
			px = l + (px - l) / (mx - l) * (1.0 - l);
	}

	return px;
}

float4 PS_Final(uniform sampler src, uniform float srcfac, uniform sampler bloom, uniform float bloomfac, float2 uv0: TEXCOORD0, float2 uv1: TEXCOORD1) : COLOR0 {
#if 0
	half3 px = tex2D(src, uv0).rgb;
	half y = dot(px.rgb, half3(0.30, 0.59, 0.11));

	half l = y * srcfac + (half3)tex2D(bloom, uv1).rgb * bloomfac;

	static const float midlevel = 0.1;

	static const float clamp1 = 3.0f;
	static const float clamp2 = (midlevel + clamp1);

	if (l > midlevel)
		l = saturate(l / (l + clamp1) * clamp2);

	return half4((px-y)/(y+1e-9f)*l*0.75+l, 0);
#elif 0
	static const float3 lumacoeff = {0.30, 0.59, 0.11};
	static const float f = 2.0;
	float3 px = tex2D(src, uv0).rgb * f;
	float bl = tex2D(bloom, uv1).g;

	bl *= f;

	px = px / max(1.0, bl);

	float mx = max(max(px.r, px.g), px.b);
	float l = dot(lumacoeff, px);
	if (mx > 1.0)
		px = l + (px - l) * saturate((1.0 - l) / (mx - l));

	return float4(px, 0);
#elif 0
	static const float3 lumacoeff = {0.30, 0.59, 0.11};
	static const float f = 2.0;
	float3 px = tex2D(src, uv0).rgb * f;
	float bl = tex2D(bloom, uv1).g;

	bl *= f;

	px = px / max(1.0, bl);

	px = tonemap(px);

	return float4(px, 0);
#else
	float3 px = tex2D(src, uv0).rgb;
	float bl = tex2D(bloom, uv1).g;

	px *= 1.0 + saturate(0.8 - bl)*1.4;

	return float4(px, 0);
	
#endif
}

technique point_ {
	pass p0
	<
		string vd_target = "bloomtex1";
	>
	{
		VertexShader = compile vs_3_0 VS_Bloom(vd_srcsize.xy, vd_texsize, vd_srcsize.xy, bloomtex1_size, float2(1, 0));
		PixelShader = compile ps_3_0 PS_Bloom1(src);
	}

	pass p1
	<
		string vd_target = "bloomtex2";
	>
	{
		VertexShader = compile vs_3_0 VS_Bloom(vd_srcsize.xy, bloomtex1_size, vd_srcsize.xy, bloomtex2_size, float2(0, 1));
		PixelShader = compile ps_3_0 PS_Bloom2(bloom1);
	}

	pass p2
	<
		string vd_target = "";
	>
	{
		VertexShader = compile vs_3_0 VS_Final(vd_srcsize, vd_texsize, vd_srcsize, bloomtex2_size, vd_srcsize, vd_temptexture_size);
		PixelShader = compile ps_3_0 PS_Final(src, 1.4f, bloom2, 0.2f);
	}
}
