dosbox-x/shaders/HQ2x.fx

268 lines
7.5 KiB
HLSL

/*
* Hq2x scaler pixel shader version by Mitja Gros (Mitja.Gros@gmail.com)
*
* Port of OpenGL-HQ Copyright (C) 2004-2005 Jörg Walter <jwalt@garni.ch>
*
* 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.00;
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;
}
}