// 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_tempsize; // temp texture size w h 1/h 1/w float4 vd_temp2size; // temp2 texture size w h 1/h 1/w float4 vd_vpcorrect2; // target screenspace xscale yscale yadd xadd float4 vd_tvpcorrect2; // temp screenspace xscale yscale yadd xadd float4 vd_t2vpcorrect2; // temp2 screenspace xscale yscale yadd xadd ////////////////////////////////////////////////////////////////////////// texture vd_srctexture; texture vd_temptexture; texture vd_temptexture2; sampler src = sampler_state { texture = ; addressu = clamp; addressv = clamp; minfilter = linear; magfilter = linear; mipfilter = none; }; sampler srcp = sampler_state { texture = ; addressu = clamp; addressv = clamp; minfilter = point; magfilter = point; mipfilter = none; }; sampler temp = sampler_state { texture = ; addressu = clamp; addressv = clamp; minfilter = linear; magfilter = linear; mipfilter = none; }; sampler temppoint = sampler_state { texture = ; addressu = clamp; addressv = clamp; minfilter = point; magfilter = point; mipfilter = none; }; sampler temp2 = sampler_state { texture = ; addressu = clamp; addressv = clamp; minfilter = linear; magfilter = linear; mipfilter = none; }; ////////////////////////////////////////////////////////////////////////// texture cubicoffsettex < string function = "genoffset"; int width = 32; int height = 32; >; texture cubicweighttex < string function = "genweights"; int width = 32; int height = 32; >; texture cubicbiastex < string function = "genbias"; int width = 32; int height = 32; >; sampler cubicoffsets = sampler_state { texture = ; addressu = wrap; addressv = wrap; minfilter = point; magfilter = point; mipfilter = none; }; sampler cubicweights = sampler_state { texture = ; addressu = wrap; addressv = wrap; minfilter = point; magfilter = point; mipfilter = none; }; sampler cubicbiases = sampler_state { texture = ; addressu = wrap; addressv = wrap; minfilter = point; magfilter = point; mipfilter = none; }; static const float A = -0.75; float4 genoffset(float2 texcoord : POSITION, float2 texelSize : PSIZE) : color0 { float2 fuv = texcoord; float4 coeff = { 1-fuv.x, 1-fuv.y, fuv.x, fuv.y }; float4 r0 = ((A+2)*coeff - (A+3))*coeff*coeff + float4(1,1,1,1); float4 r1 = -(A + (-2*A + A*coeff)*coeff)*coeff; // z1 z0 x0 x1 //w1 //w0 //y0 //y1 float x0 = r0.x; float y0 = r0.y; float z0 = r0.z; float w0 = r0.w; float x1 = r1.x; float y1 = r1.y; float z1 = r1.z; float w1 = r1.w; static const float fudge = 1e-5f; return float4(z0/((z1+z0)+fudge), w0/((w1+w0)+fudge), y1/((y1+y0)+fudge), x1/((x1+x0)+fudge)); } float4 genweights(float2 texcoord : POSITION, float2 texelSize : PSIZE) : color0 { float2 fuv = texcoord; float4 coeff = { 1-fuv.x, 1-fuv.y, fuv.x, fuv.y }; float4 r0 = ((A+2)*coeff - (A+3))*coeff*coeff + float4(1,1,1,1); float4 r1 = -(A + (-2*A + A*coeff)*coeff)*coeff; // z1 z0 x0 x1 //w1 //w0 //y0 //y1 float x0 = r0.x; float y0 = r0.y; float z0 = r0.z; float w0 = r0.w; float x1 = r1.x; float y1 = r1.y; float z1 = r1.z; float w1 = r1.w; float t0 = (w0+w1)*(z0+z1); float t1 = (w0+w1)*(x0+x1); float t2 = (y0+y1)*(z0+z1); float t3 = (y0+y1)*(x0+x1); return float4(t0, t1, t2, t3) * 0.5; } float4 genbias(float2 texcoord : POSITION, float2 texelSize : PSIZE) : color0 { float2 fuv = texcoord; float4 coeff = { 1-fuv.x, 1-fuv.y, fuv.x, fuv.y }; // 1,1,0,0 at home pos float4 r0 = ((A+2)*coeff - (A+3))*coeff*coeff + float4(1,1,1,1); // 0,0,1,1 at home pos float4 r1 = -(A + (-2*A + A*coeff)*coeff)*coeff; // 0,0,0,0 at home pos // z1 z0 x0 x1 //w1 //w0 //y0 //y1 float x0 = r0.x; // 0 at home pos float y0 = r0.y; // 0 at home pos float z0 = r0.z; // 1 at home pos float w0 = r0.w; // 1 at home pos float x1 = r1.x; // 0 at home pos float y1 = r1.y; // 0 at home pos float z1 = r1.z; // 0 at home pos float w1 = r1.w; // 0 at home pos float bias = (w1-y0)*(z0-x1) + (w0-y1)*(z1-x0); // 0 at home pos return bias*0.5 + 0.5; } float4 tex2Dbicubic(uniform sampler samp_linear, uniform sampler samp_point, float2 uvtexels, float4 texturesize) { uvtexels -= 0.5; float2 uvtexelsi = floor(uvtexels); float4 cubicoffsetvals = (uvtexelsi.xyyx + tex2D(cubicoffsets, uvtexels) + float4(-0.5,-0.5,1.5,1.5)) * texturesize.wzzw; float4 cubicbiasvals = tex2D(cubicbiases, uvtexels) - 0.5; float4 cubicweightvals = tex2D(cubicweights, uvtexels); float4 px0 = tex2D(samp_linear, cubicoffsetvals.xy); float4 px1 = tex2D(samp_linear, cubicoffsetvals.wy); float4 px2 = tex2D(samp_linear, cubicoffsetvals.xz); float4 px3 = tex2D(samp_linear, cubicoffsetvals.wz); float4 px = px0*cubicweightvals.x - px1*cubicweightvals.y - px2*cubicweightvals.z + px3*cubicweightvals.w - cubicbiasvals.x; if (frac(dot(uvtexelsi, float2(0.5, 0.5)) + 0.25) < 0.5) px = (0.5-px); px *= 2; return px; } ////////////////////////////////////////////////////////////////////////// struct VertexInput { float4 pos : POSITION; float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1; }; struct VertexGrad { float4 pos : POSITION; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; float2 uv8 : TEXCOORD7; }; static float4 offset32 = { vd_texsize.w, vd_texsize.z, vd_texsize.z, 0 }; static float4 offset10 = { -vd_texsize.w, vd_texsize.z, 0, vd_texsize.w }; VertexGrad VSgrad(VertexInput IN) { VertexGrad OUT; OUT.pos.xy = IN.uv2 * vd_vpsize.xy * -vd_tvpcorrect2.yx - vd_tvpcorrect2.zw; OUT.pos.zw = float2(0, 1); OUT.uv0 = IN.uv - offset32.xy; OUT.uv1 = IN.uv - offset32.wz; OUT.uv2 = IN.uv - offset10.xy; OUT.uv3 = IN.uv - offset10.wz; OUT.uv5 = IN.uv + offset10.wz; OUT.uv6 = IN.uv + offset10.xy; OUT.uv7 = IN.uv + offset32.wz; OUT.uv8 = IN.uv + offset32.xy; return OUT; } static const float4 lumacoeff = { 0.30f, 0.59f, 0.11f, 0 }; float4 PSgrad(VertexGrad IN) : COLOR0 { float4 p0 = tex2D(src, IN.uv0); float4 p1 = tex2D(src, IN.uv1); float4 p2 = tex2D(src, IN.uv2); float4 p3 = tex2D(src, IN.uv3); float4 p4 = tex2D(src, 0.5f * (IN.uv3 + IN.uv5)); float4 p5 = tex2D(src, IN.uv5); float4 p6 = tex2D(src, IN.uv6); float4 p7 = tex2D(src, IN.uv7); float4 p8 = tex2D(src, IN.uv8); float4 a = p8-p0; float4 b = p6-p2; float gy = dot(a + b + 2*(p7 - p1), lumacoeff); float gx = dot(a - b + 2*(p5 - p3), lumacoeff); return length(float2(gx, gy)) * 0.25f; } /////////////////////////////////////////////////////////////////////////// struct VertexBlur { float4 pos : POSITION; float2 uv1 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; }; VertexBlur VSblur(VertexInput IN) { VertexBlur OUT; OUT.pos.xy = IN.uv2 * vd_vpsize.xy * -vd_tvpcorrect2.yx - vd_tvpcorrect2.zw; OUT.pos.zw = float2(0, 1); float2 uv = IN.uv2 * vd_vpsize.xy * vd_tempsize.wz; OUT.uv1 = uv + 0.5f*float2(-vd_tempsize.w, -vd_tempsize.z); OUT.uv2 = uv + 0.5f*float2(-vd_tempsize.w, +vd_tempsize.z); OUT.uv3 = uv + 0.5f*float2(+vd_tempsize.w, -vd_tempsize.z); OUT.uv4 = uv + 0.5f*float2(+vd_tempsize.w, +vd_tempsize.z); return OUT; } float4 PSblur(VertexBlur IN) : COLOR0 { float4 p1 = tex2D(temp, IN.uv1); float4 p2 = tex2D(temp, IN.uv2); float4 p3 = tex2D(temp, IN.uv3); float4 p4 = tex2D(temp, IN.uv4); return 0.25f * (p1+p2+p3+p4); } /////////////////////////////////////////////////////////////////////////// struct VertexCubicPrep { float4 pos : POSITION; float2 uv : TEXCOORD0; float sum : TEXCOORD1; }; VertexCubicPrep VScubicprep(VertexInput IN) { VertexCubicPrep OUT; float2 pixelpos = IN.uv2 * (vd_srcsize.xy + float2(4,4)) - float2(2,2); OUT.pos.xy = pixelpos * -vd_tvpcorrect2.yx - vd_tvpcorrect2.zw; OUT.pos.zw = float2(0, 1); OUT.uv = pixelpos * vd_texsize.wz; OUT.sum = dot(pixelpos.xyxy + 0.25, float4(0.25, 0.25, 0.25, 0.25)); return OUT; } float4 PScubicprep(VertexCubicPrep IN) : color0 { float4 px = tex2D(src, IN.uv); return frac(IN.sum) < 0.5 ? px : float4(1,1,1,1) - px; } /////////////////////////////////////////////////////////////////////////// struct VertexFinal { float4 pos : POSITION; float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uvg_l : TEXCOORD2; float2 uvg_t : TEXCOORD3; float2 uvg_r : TEXCOORD4; float2 uvg_b : TEXCOORD5; }; VertexFinal VSfinal(VertexInput IN) { VertexFinal OUT; OUT.pos.xy = IN.uv2 * vd_vpsize.xy * vd_vpcorrect2.xy + vd_vpcorrect2.wz; OUT.pos.z = 0; OUT.pos.w = 1; OUT.uv = IN.uv; OUT.uv2 = (IN.uv2 * vd_srcsize.xy); float2 uv2 = IN.uv2 * vd_vpsize.xy * vd_temp2size.wz; OUT.uvg_l = uv2 + float2(-vd_temp2size.w, 0); OUT.uvg_r = uv2 + float2(vd_temp2size.w, 0); OUT.uvg_t = uv2 + float2(0, -vd_temp2size.z); OUT.uvg_b = uv2 + float2(0, vd_temp2size.z); return OUT; } float4 PSfinal(VertexFinal IN) : COLOR0 { float pT = tex2D(temp2, IN.uvg_t).x; float pB = tex2D(temp2, IN.uvg_b).x; float pL = tex2D(temp2, IN.uvg_l).x; float pR = tex2D(temp2, IN.uvg_r).x; float2 disp = { pR - pL, pB - pT + 1e-7f }; disp *= 10.0; disp *= saturate(1.0/length(disp)); float2 uv = IN.uv2 + disp * -0.25; float4 px = tex2Dbicubic(temp, temppoint, uv, vd_tempsize); float4 o = tex2Dbicubic(temp, temppoint, IN.uv2, vd_tempsize); return px + (px - o)*1.0f; } /////////////////////////////////////////////////////////////////////////// struct VertexBicubic { float4 pos : POSITION; float2 uv : TEXCOORD0; }; VertexBicubic VSbicubic(VertexInput IN) { VertexBicubic OUT; OUT.pos.xy = IN.uv2 * vd_vpsize.xy * vd_vpcorrect2.xy + vd_vpcorrect2.wz; OUT.pos.z = 0; OUT.pos.w = 1; OUT.uv = IN.uv2 * vd_srcsize.xy; return OUT; } float4 PSbicubic(VertexBicubic IN) : COLOR0 { return tex2Dbicubic(temp, temppoint, IN.uv, vd_tempsize); } /////////////////////////////////////////////////////////////////////////// technique point { pass p0 { VertexShader = asm { vs_2_0 dcl_position v0 dcl_texcoord v1 mov oPos, v0 mov oT0.xy, v1 }; PixelShader = asm { ps_2_0 dcl t0.xy dcl_2d s0 texld r0, t0, s0 mov oC0, r0 }; Texture[0] = ; AddressU[0] = clamp; AddressV[0] = clamp; MinFilter[0] = linear; MagFilter[0] = linear; } } technique bilinear { pass cubicprep < string vd_target = "temp"; > { VertexShader = compile vs_2_0 VScubicprep(); PixelShader = compile ps_2_0 PScubicprep(); } pass p0 { VertexShader = compile vs_2_0 VSbicubic(); PixelShader = compile ps_2_0 PSbicubic(); } } technique bicubic { pass grad < string vd_target = "temp"; > { VertexShader = compile vs_2_0 VSgrad(); PixelShader = compile ps_2_0 PSgrad(); } pass blur < string vd_target = "temp2"; > { VertexShader = compile vs_2_0 VSblur(); PixelShader = compile ps_2_0 PSblur(); } pass cubicprep < string vd_target = "temp"; > { VertexShader = compile vs_2_0 VScubicprep(); PixelShader = compile ps_2_0 PScubicprep(); } pass final < string vd_target = ""; > { VertexShader = compile vs_2_0 VSfinal(); PixelShader = compile ps_2_0 PSfinal(); } }