2022-06-04 04:58:05 +00:00
#ifdef SHADER_MODEL // make safe to include in resource file to enforce dependency
#ifndef PS_SCALE_FACTOR
#define PS_SCALE_FACTOR 1
#endif
struct VS_INPUT
{
float4 p : POSITION ;
float2 t : TEXCOORD0 ;
float4 c : COLOR ;
} ;
struct VS_OUTPUT
{
float4 p : SV_Position ;
float2 t : TEXCOORD0 ;
float4 c : COLOR ;
} ;
cbuffer cb0 : register ( b0 )
{
float4 u_source_rect ;
float4 u_target_rect ;
float2 u_source_size ;
float2 u_target_size ;
float2 u_target_resolution ;
float2 u_rcp_target_resolution ; // 1 / u_target_resolution
float2 u_source_resolution ;
float2 u_rcp_source_resolution ; // 1 / u_source_resolution
float u_time ;
} ;
Texture2D Texture ;
SamplerState TextureSampler ;
float4 sample_c ( float2 uv )
{
return Texture . Sample ( TextureSampler , uv ) ;
}
struct PS_INPUT
{
float4 p : SV_Position ;
float2 t : TEXCOORD0 ;
float4 c : COLOR ;
} ;
struct PS_OUTPUT
{
float4 c : SV_Target0 ;
} ;
VS_OUTPUT vs_main ( VS_INPUT input )
{
VS_OUTPUT output ;
output . p = input . p ;
output . t = input . t ;
output . c = input . c ;
return output ;
}
PS_OUTPUT ps_copy ( PS_INPUT input )
{
PS_OUTPUT output ;
2022-06-06 13:33:28 +00:00
2022-06-04 04:58:05 +00:00
output . c = sample_c ( input . t ) ;
return output ;
}
float4 ps_crt ( PS_INPUT input , int i )
{
2022-06-06 13:33:28 +00:00
float4 mask [ 4 ] =
{
float4 ( 1 , 0 , 0 , 0 ) ,
float4 ( 0 , 1 , 0 , 0 ) ,
float4 ( 0 , 0 , 1 , 0 ) ,
float4 ( 1 , 1 , 1 , 0 )
} ;
2022-06-04 04:58:05 +00:00
return sample_c ( input . t ) * saturate ( mask [ i ] + 0.5f ) ;
}
float4 ps_scanlines ( PS_INPUT input , int i )
{
float4 mask [ 2 ] =
2022-06-06 13:33:28 +00:00
{
float4 ( 1 , 1 , 1 , 0 ) ,
float4 ( 0 , 0 , 0 , 0 )
} ;
2022-06-04 04:58:05 +00:00
return sample_c ( input . t ) * saturate ( mask [ i ] + 0.5f ) ;
}
PS_OUTPUT ps_filter_scanlines ( PS_INPUT input )
{
PS_OUTPUT output ;
2022-06-06 13:33:28 +00:00
2022-06-04 04:58:05 +00:00
uint4 p = ( uint4 ) input . p ;
output . c = ps_scanlines ( input , p . y % 2 ) ;
return output ;
}
PS_OUTPUT ps_filter_diagonal ( PS_INPUT input )
{
PS_OUTPUT output ;
uint4 p = ( uint4 ) input . p ;
output . c = ps_crt ( input , ( p . x + ( p . y % 3 ) ) % 3 ) ;
return output ;
}
PS_OUTPUT ps_filter_triangular ( PS_INPUT input )
{
PS_OUTPUT output ;
uint4 p = ( uint4 ) input . p ;
2022-06-06 13:33:28 +00:00
// output.c = ps_crt(input, ((p.x + (p.y & 1) * 3) >> 1) % 3);
2022-06-04 04:58:05 +00:00
output . c = ps_crt ( input , ( ( p . x + ( ( p . y >> 1 ) & 1 ) * 3 ) >> 1 ) % 3 ) ;
return output ;
}
static const float PI = 3.14159265359f ;
PS_OUTPUT ps_filter_complex ( PS_INPUT input ) // triangular
{
PS_OUTPUT output ;
2022-06-10 13:23:58 +00:00
float2 texdim ;
Texture . GetDimensions ( texdim . x , texdim . y ) ;
output . c = ( 0.9 - 0.4 * cos ( 2 * PI * input . t . y * texdim . y ) ) * sample_c ( float2 ( input . t . x , ( floor ( input . t . y * texdim . y ) + 0.5 ) / texdim . y ) ) ;
2022-06-04 04:58:05 +00:00
return output ;
}
2022-06-06 13:33:28 +00:00
//Lottes CRT
#define MaskingType 4 //[1|2|3|4] The type of CRT shadow masking used. 1: compressed TV style, 2: Aperture-grille, 3: Stretched VGA style, 4: VGA style.
#define ScanBrightness -8.00 //[-16.0 to 1.0] The overall brightness of the scanline effect. Lower for darker, higher for brighter.
#define FilterCRTAmount -1.00 //[-4.0 to 1.0] The amount of filtering used, to replicate the TV CRT look. Lower for less, higher for more.
#define HorizontalWarp 0.00 //[0.0 to 0.1] The distortion warping effect for the horizontal (x) axis of the screen. Use small increments.
#define VerticalWarp 0.00 //[0.0 to 0.1] The distortion warping effect for the verticle (y) axis of the screen. Use small increments.
#define MaskAmountDark 0.80 //[0.0 to 1.0] The value of the dark masking line effect used. Lower for darker lower end masking, higher for brighter.
#define MaskAmountLight 1.50 //[0.0 to 2.0] The value of the light masking line effect used. Lower for darker higher end masking, higher for brighter.
#define ResolutionScale 2.00 //[0.1 to 4.0] The scale of the image resolution. Lowering this can give off a nice retro TV look. Raising it can clear up the image.
#define MaskResolutionScale 0.80 //[0.1 to 2.0] The scale of the CRT mask resolution. Use this for balancing the scanline mask scale for difference resolution scaling.
#define UseShadowMask 1 //[0 or 1] Enables, or disables the use of the CRT shadow mask. 0 is disabled, 1 is enabled.
float ToLinear1 ( float c )
{
c = saturate ( c ) ;
return c <= 0.04045 ? c / 12.92 : pow ( ( c + 0.055 ) / 1.055 , 2.4 ) ;
}
float3 ToLinear ( float3 c )
{
return float3 ( ToLinear1 ( c . r ) , ToLinear1 ( c . g ) , ToLinear1 ( c . b ) ) ;
}
float ToSrgb1 ( float c )
{
c = saturate ( c ) ;
return c < 0.0031308 ? c * 12.92 : 1.055 * pow ( c , 0.41666 ) - 0.055 ;
}
float3 ToSrgb ( float3 c )
{
return float3 ( ToSrgb1 ( c . r ) , ToSrgb1 ( c . g ) , ToSrgb1 ( c . b ) ) ;
}
float3 Fetch ( float2 pos , float2 off )
{
float2 screenSize = u_source_resolution ;
float2 res = ( screenSize * ResolutionScale ) ;
pos = round ( pos * res + off ) / res ;
if ( max ( abs ( pos . x - 0.5 ) , abs ( pos . y - 0.5 ) ) > 0.5 )
{
return float3 ( 0.0 , 0.0 , 0.0 ) ;
}
else
{
return ToLinear ( Texture . Sample ( TextureSampler , pos . xy ) . rgb ) ;
}
}
float2 Dist ( float2 pos )
{
float2 crtRes = u_rcp_target_resolution ;
float2 res = ( crtRes * MaskResolutionScale ) ;
pos = ( pos * res ) ;
return - ( ( pos - floor ( pos ) ) - float2 ( 0.5 , 0.5 ) ) ;
}
float Gaus ( float pos , float scale )
{
return exp2 ( scale * pos * pos ) ;
}
float3 Horz3 ( float2 pos , float off )
{
float3 b = Fetch ( pos , float2 ( - 1.0 , off ) ) ;
float3 c = Fetch ( pos , float2 ( 0.0 , off ) ) ;
float3 d = Fetch ( pos , float2 ( 1.0 , off ) ) ;
float dst = Dist ( pos ) . x ;
// Convert distance to weight.
float scale = FilterCRTAmount ;
float wb = Gaus ( dst - 1.0 , scale ) ;
float wc = Gaus ( dst + 0.0 , scale ) ;
float wd = Gaus ( dst + 1.0 , scale ) ;
return ( b * wb ) + ( c * wc ) + ( d * wd ) / ( wb + wc + wd ) ;
}
float3 Horz5 ( float2 pos , float off )
{
float3 a = Fetch ( pos , float2 ( - 2.0 , off ) ) ;
float3 b = Fetch ( pos , float2 ( - 1.0 , off ) ) ;
float3 c = Fetch ( pos , float2 ( 0.0 , off ) ) ;
float3 d = Fetch ( pos , float2 ( 1.0 , off ) ) ;
float3 e = Fetch ( pos , float2 ( 2.0 , off ) ) ;
float dst = Dist ( pos ) . x ;
// Convert distance to weight.
float scale = FilterCRTAmount ;
float wa = Gaus ( dst - 2.0 , scale ) ;
float wb = Gaus ( dst - 1.0 , scale ) ;
float wc = Gaus ( dst + 0.0 , scale ) ;
float wd = Gaus ( dst + 1.0 , scale ) ;
float we = Gaus ( dst + 2.0 , scale ) ;
return ( a * wa ) + ( b * wb ) + ( c * wc ) + ( d * wd ) + ( e * we ) / ( wa + wb + wc + wd + we ) ;
}
// Return scanline weight.
float Scan ( float2 pos , float off )
{
float dst = Dist ( pos ) . y ;
return Gaus ( dst + off , ScanBrightness ) ;
}
float3 Tri ( float2 pos )
{
float3 a = Horz3 ( pos , - 1.0 ) ;
float3 b = Horz5 ( pos , 0.0 ) ;
float3 c = Horz3 ( pos , 1.0 ) ;
float wa = Scan ( pos , - 1.0 ) ;
float wb = Scan ( pos , 0.0 ) ;
float wc = Scan ( pos , 1.0 ) ;
return ( a * wa ) + ( b * wb ) + ( c * wc ) ;
}
float2 Warp ( float2 pos )
{
pos = pos * 2.0 - 1.0 ;
pos * = float2 ( 1.0 + ( pos . y * pos . y ) * HorizontalWarp , 1.0 + ( pos . x * pos . x ) * VerticalWarp ) ;
return pos * 0.5 + 0.5 ;
}
float3 Mask ( float2 pos )
{
#if MaskingType == 1
// Very compressed TV style shadow mask.
float lines = MaskAmountLight ;
float odd = 0.0 ;
if ( frac ( pos . x / 6.0 ) < 0.5 )
{
odd = 1.0 ;
}
if ( frac ( ( pos . y + odd ) / 2.0 ) < 0.5 )
{
lines = MaskAmountDark ;
}
pos . x = frac ( pos . x / 3.0 ) ;
float3 mask = float3 ( MaskAmountDark , MaskAmountDark , MaskAmountDark ) ;
if ( pos . x < 0.333 )
{
mask . r = MaskAmountLight ;
}
else if ( pos . x < 0.666 )
{
mask . g = MaskAmountLight ;
}
else
{
mask . b = MaskAmountLight ;
}
mask * = lines ;
return mask ;
#elif MaskingType == 2
// Aperture-grille.
pos . x = frac ( pos . x / 3.0 ) ;
float3 mask = float3 ( MaskAmountDark , MaskAmountDark , MaskAmountDark ) ;
if ( pos . x < 0.333 )
{
mask . r = MaskAmountLight ;
}
else if ( pos . x < 0.666 )
{
mask . g = MaskAmountLight ;
}
else
{
mask . b = MaskAmountLight ;
}
return mask ;
#elif MaskingType == 3
// Stretched VGA style shadow mask (same as prior shaders).
pos . x + = pos . y * 3.0 ;
float3 mask = float3 ( MaskAmountDark , MaskAmountDark , MaskAmountDark ) ;
pos . x = frac ( pos . x / 6.0 ) ;
if ( pos . x < 0.333 )
{
mask . r = MaskAmountLight ;
}
else if ( pos . x < 0.666 )
{
mask . g = MaskAmountLight ;
}
else
{
mask . b = MaskAmountLight ;
}
return mask ;
#else
// VGA style shadow mask.
pos . xy = floor ( pos . xy * float2 ( 1.0 , 0.5 ) ) ;
pos . x + = pos . y * 3.0 ;
float3 mask = float3 ( MaskAmountDark , MaskAmountDark , MaskAmountDark ) ;
pos . x = frac ( pos . x / 6.0 ) ;
if ( pos . x < 0.333 )
{
mask . r = MaskAmountLight ;
}
else if ( pos . x < 0.666 )
{
mask . g = MaskAmountLight ;
}
else
{
mask . b = MaskAmountLight ;
}
return mask ;
#endif
}
float4 LottesCRTPass ( float4 fragcoord )
{
fragcoord - = u_target_rect ;
float2 inSize = u_target_resolution - ( 2 * u_target_rect . xy ) ;
float4 color ;
float2 pos = Warp ( fragcoord . xy / inSize ) ;
#if UseShadowMask == 0
color . rgb = Tri ( pos ) ;
#else
color . rgb = Tri ( pos ) * Mask ( fragcoord . xy ) ;
#endif
color . rgb = ToSrgb ( color . rgb ) ;
color . a = 1.0 ;
return color ;
}
PS_OUTPUT ps_filter_lottes ( PS_INPUT input )
{
PS_OUTPUT output ;
output . c = LottesCRTPass ( input . p ) ;
return output ;
}
2022-06-04 04:58:05 +00:00
#endif