/* * Hq2x scaler pixel shader version by Mitja Gros (Mitja.Gros@gmail.com) * * Port of OpenGL-HQ Copyright (C) 2004-2005 Jörg Walter * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "scaling.inc" string name : NAME = "hq2x"; float scaling : SCALING = 1.01; float staticTreshold : HQ2XSTATICTRESHOLD = 10.0 / 255.0; float dynamicTreshold : HQ2XDYNAMICTRESHOLD = 33.0 / 100.0; // combineTechnique: Final combine steps. Outputs to destination frame buffer string combineTechique : COMBINETECHNIQUE = "Combine_hq2x"; // sourcetexture -> workingtexture string preprocessTechique : PREPROCESSTECHNIQUE = "Preprocess0_hq2x"; // workingtexture -> workingtexture1 string preprocessTechique1 : PREPROCESSTECHNIQUE1 = "Preprocess1_hq2x"; texture Hq2xLookupTexture : HQ2XLOOKUPTEXTURE; sampler Hq2xLookupSampler = sampler_state { Texture = (Hq2xLookupTexture); MinFilter = POINT; MagFilter = POINT; MipFilter = NONE; AddressU = Clamp; AddressV = Clamp; AddressW = Clamp; SRGBTEXTURE = FALSE; }; struct VS_OUTPUT_PRODUCT0 { float4 Position : POSITION; float2 pixel0 : TEXCOORD0; float2 pixel1 : TEXCOORD1; float2 pixel2 : TEXCOORD2; float2 pixel3 : TEXCOORD3; }; struct VS_OUTPUT_PRODUCT1 { float4 Position : POSITION; float2 pixel0 : TEXCOORD0; float2 pixel1 : TEXCOORD1; float2 pixel2 : TEXCOORD2; float2 pixel3 : TEXCOORD3; }; struct VS_OUTPUT_PRODUCT2 { float4 Position : POSITION; float2 pixel0 : TEXCOORD0; }; // vertex shaders VS_OUTPUT_PRODUCT0 VS_Product0( float3 Position : POSITION, float2 TexCoord : TEXCOORD0) { VS_OUTPUT_PRODUCT0 Out = (VS_OUTPUT_PRODUCT0)0; const float4 coordmask = { 1, 0, 1, 0 }; Out.Position = mul(half4(Position, 1), WorldViewProjection); // Matrix multipliy Out.pixel0 = TexCoord; Out.pixel1 = TexelSize * coordmask + Out.pixel0; Out.pixel2 = TexelSize * coordmask.gbra + Out.pixel0; Out.pixel3 = TexelSize + Out.pixel0; return Out; } VS_OUTPUT_PRODUCT1 VS_Product1( float3 Position : POSITION, float2 TexCoord : TEXCOORD0) { VS_OUTPUT_PRODUCT1 Out = (VS_OUTPUT_PRODUCT1)0; const float4 coordmask = { 0, -1, 0, 0.0625 }; Out.Position = mul(half4(Position, 1), WorldViewProjection); // Matrix multipliy Out.pixel3 = TexCoord; Out.pixel0 = Out.pixel3 - TexelSize; Out.pixel1 = TexelSize.x * coordmask + Out.pixel3; Out.pixel2 = TexelSize.x * coordmask.gbra + Out.pixel3; return Out; } VS_OUTPUT_PRODUCT2 VS_Product2( float3 Position : POSITION, float2 TexCoord : TEXCOORD0) { VS_OUTPUT_PRODUCT2 Out = (VS_OUTPUT_PRODUCT2)0; Out.Position = mul(half4(Position, 1), WorldViewProjection); // Matrix multipliy Out.pixel0 = TexCoord; return Out; } // pixel shaders half PS_Product0_Diff(half4 pixel1, half4 pixel2) { const half4 weight = { 1.884313725490196078431372549, 3.768627450980392156862745098, 2.822790287990196078431372548, 0 }; const half4 mask = { 0.4710784313725490196078431372, 0, -0.4710784313725490196078431372, 0 }; half4 diff = 0, rmean = 0; diff.rgb = pixel1 - pixel2; rmean.a = pixel1.r + pixel2.r; rmean.rgb = rmean.a * mask + weight; diff.rgb = diff * diff; return clamp(dot(rmean, diff), 0 , 1); } half4 PS_Product0 ( in VS_OUTPUT_PRODUCT0 input ) : COLOR { half4 pixel0 = tex2D(SourceSampler, input.pixel0); half4 pixel1 = tex2D(SourceSampler, input.pixel1); half4 pixel2 = tex2D(SourceSampler, input.pixel2); half4 pixel3 = tex2D(SourceSampler, input.pixel3); half4 result = 0; result.b = PS_Product0_Diff(pixel0, pixel3); result.r = PS_Product0_Diff(pixel0, pixel1); result.g = PS_Product0_Diff(pixel0, pixel2); result.a = PS_Product0_Diff(pixel1, pixel2); return result; } half4 PS_Product1 ( in VS_OUTPUT_PRODUCT1 input ) : COLOR { const half4 constant = { 65536, 0.1666666666666666, 1, 0 }; const half4 factors = { 0.0627450980392157, 0.125490196078431, 0.250980392156863, 0.501960784313725 }; const half4 oneSixteenth = { 0, -1, 0, 0.0625 }; half4 pixel0 = tex2D(WorkingSampler, input.pixel0); half4 pixel1 = tex2D(WorkingSampler, input.pixel1); half4 pixel2 = tex2D(WorkingSampler, input.pixel2); half4 pixel3 = tex2D(WorkingSampler, input.pixel3); half4 minimum = 0, currentTrigger = 0, result = 0; pixel1.r = pixel0.b; pixel2.g = pixel0.a; minimum = pixel1 + pixel2 + pixel3; currentTrigger.a = dot(minimum, constant.g); currentTrigger.a = clamp(currentTrigger.a * dynamicTreshold, 0, 1); currentTrigger.a = max(currentTrigger.a, staticTreshold); currentTrigger.a = currentTrigger.a * constant.r; pixel1 = clamp(pixel1 * constant.r - currentTrigger.a, 0, 1); pixel2 = clamp(pixel2 * constant.r - currentTrigger.a, 0, 1); pixel3 = clamp(pixel3 * constant.r - currentTrigger.a, 0, 1); result.a = dot(pixel3, factors); pixel2 = pixel2 * oneSixteenth.a + pixel1; result.rgb = dot(pixel2, factors); return result; } half4 PS_Product2 ( in VS_OUTPUT_PRODUCT2 input ) : COLOR { const half4 cap = { 1.142857142857142857127368540393064222371, -0.07142857142857143002735720305196309709572, 0.83825, 0.080875 }; const half4 constant = { 0.0625, 0.5, 0.99609375, 0.001953125 }; half2 coord1 = 0.0f; half2 coord2 = 0.0f; half2 coord3 = 0.0f; half3 centerOffset = 0.0f; half4 diff = tex2D(WorkingSampler1, input.pixel0); centerOffset.xy = input.pixel0.xy * SourceDims.xy; centerOffset.xy = frac(centerOffset.xy); coord3.xy = centerOffset.xy - constant.g; coord3 = (coord3 < 0) ? -TexelSize : TexelSize; coord3.xy = input.pixel0 + coord3; coord1.x = coord3.x; coord1.y = input.pixel0.y; coord2.x = input.pixel0.x; coord2.y = coord3.y; centerOffset.xy = clamp(centerOffset.xy * cap.r + cap.g, 0, 1); centerOffset.xy = centerOffset.xy * cap.b + cap.a; centerOffset.x = centerOffset.x * constant.x + diff.a; centerOffset.z = diff.z * constant.b + constant.a; half4 pixel0 = tex2D(SourceSampler, input.pixel0); half4 pixel1 = tex2D(SourceSampler, coord1); half4 pixel2 = tex2D(SourceSampler, coord2); half4 pixel3 = tex2D(SourceSampler, coord3); half4 factors = tex3D(Hq2xLookupSampler, centerOffset); pixel0 = pixel0 * factors.b; pixel0 = pixel1 * factors.g + pixel0; pixel0 = pixel2 * factors.r + pixel0; half4 result = pixel3 * factors.a + pixel0; return result; } technique Preprocess0_hq2x { pass P0 { // shaders VertexShader = compile vs_2_0 VS_Product0(); PixelShader = compile ps_2_0 PS_Product0(); AlphaBlendEnable = FALSE; ColorWriteEnable = RED|GREEN|BLUE|ALPHA; SRGBWRITEENABLE = FALSE; } } technique Preprocess1_hq2x { pass P0 { // shaders VertexShader = compile vs_2_0 VS_Product1(); PixelShader = compile ps_2_0 PS_Product1(); AlphaBlendEnable = FALSE; ColorWriteEnable = RED|GREEN|BLUE|ALPHA; SRGBWRITEENABLE = FALSE; } } technique Combine_hq2x { pass P0 { // shaders VertexShader = compile vs_2_0 VS_Product2(); PixelShader = compile ps_2_0 PS_Product2(); AlphaBlendEnable = FALSE; ColorWriteEnable = RED|GREEN|BLUE|ALPHA; SRGBWRITEENABLE = FALSE; } }