#pragma parameter InputGamma "Input gamma" 2.4 0.0 5.0 0.1
#pragma parameter OutputGamma "Output Gamma" 2.2 0.0 5.0 0.1
#pragma parameter DILATION_STRENGTH "Dilation Strength" 0.9 0.0 1.0 0.05
#pragma parameter SHARPNESS "Sharpness" 2.0 0.0 5.0 0.1
#pragma parameter RED_BOOST "Red Boost" 1.0 1.0 2.0 0.01
#pragma parameter GREEN_BOOST "Green Boost" 1.0 1.0 2.0 0.01
#pragma parameter SCANLINES_STRENGTH "Scanline Strength" 0.7 0.0 1.0 0.01
#pragma parameter BEAM_MIN_WIDTH "Min. Beam Width" 0.1 0.0 1.0 0.01
#pragma parameter BEAM_MAX_WIDTH "Max Beam Width" 0.7 0.0 1.0 0.01
#pragma parameter COLOR_BOOST "Color Boost" 1.2 1.0 2.0 0.05
#pragma parameter BEAM_WIDTH_SENSITIVITY "Beam Width Sensitivity" 0.5 0.0 1.0 0.01
#pragma parameter CRT_TV_BLUE_TINT "CRT TV Blue Tint" 1.05 1.0 2.0 0.01
#ifdef PARAMETER_UNIFORM
uniform float InputGamma;
uniform float OutputGamma;
uniform float DILATION_STRENGTH;
uniform float SHARPNESS;
uniform float RED_BOOST;
uniform float GREEN_BOOST;
uniform float SCANLINES_STRENGTH;
uniform float BEAM_MIN_WIDTH;
uniform float BEAM_MAX_WIDTH;
uniform float COLOR_BOOST;
uniform float BEAM_WIDTH_SENSITIVITY;
uniform float CRT_TV_BLUE_TINT;
#else
#define InputGamma 2.4
#define OutputGamma 2.2
#define DILATION_STRENGTH 0.9
#define SHARPNESS 2.0
#define RED_BOOST 1.0
#define GREEN_BOOST 1.0
#define SCANLINES_STRENGTH 0.7
#define BEAM_MIN_WIDTH 0.1
#define BEAM_MAX_WIDTH 0.7
#define COLOR_BOOST 1.2
#define BEAM_WIDTH_SENSITIVITY 0.5
#define CRT_TV_BLUE_TINT 1.05
#endif
// END PARAMETERS //

/* COMPATIBILITY
   - HLSL compilers
   - Cg   compilers
*/

/*
   Hyllian's CRT Shader
  
   Copyright (C) 2011-2014 Hyllian/Jararaca - sergiogdb@gmail.com

   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.

*/

// Uncomment to enable anti-ringing to horizontal filter.
#define ANTI_RINGING

// Uncomment to dilate bright pixels horizontally.
#define DILATION

// Uncomment to increase the sharpness of the scanlines.
//#define SHARPER

// Comment next line if you don't desire the phosphor effect.
#define PHOSPHOR

// Uncomment to enable adjustment of red and green saturation.
//#define RED_GREEN_CONTROL

#define GAMMA_IN(color)     pow(color, float3(InputGamma, InputGamma, InputGamma))
#define GAMMA_OUT(color)    pow(color, float3(1.0 / OutputGamma, 1.0 / OutputGamma, 1.0 / OutputGamma))


// Horizontal cubic filter.

// Some known filters use these values:

//    B = 0.0, C = 0.0  =>  Hermite cubic filter.
//    B = 1.0, C = 0.0  =>  Cubic B-Spline filter.
//    B = 0.0, C = 0.5  =>  Catmull-Rom Spline filter. This is the default used in this shader.
//    B = C = 1.0/3.0   =>  Mitchell-Netravali cubic filter.
//    B = 0.3782, C = 0.3109  =>  Robidoux filter.
//    B = 0.2620, C = 0.3690  =>  Robidoux Sharp filter.
//    B = 0.36, C = 0.28  =>  My best config for ringing elimination in pixel art (Hyllian).


// For more info, see: http://www.imagemagick.org/Usage/img_diagrams/cubic_survey.gif

// Change these params to configure the horizontal filter.
const static float  B =  0.0; 
const static float  C =  0.5;  

const static float4x4 invX = float4x4(            (-B - 6.0*C)/6.0,         (3.0*B + 12.0*C)/6.0,     (-3.0*B - 6.0*C)/6.0,             B/6.0,
                                        (12.0 - 9.0*B - 6.0*C)/6.0, (-18.0 + 12.0*B + 6.0*C)/6.0,                      0.0, (6.0 - 2.0*B)/6.0,
                                       -(12.0 - 9.0*B - 6.0*C)/6.0, (18.0 - 15.0*B - 12.0*C)/6.0,      (3.0*B + 6.0*C)/6.0,             B/6.0,

                                                   (B + 6.0*C)/6.0,                           -C,                      0.0,               0.0);


struct input
{
    float2 video_size;
    float2 texture_size;
    float2 output_size;
    float  frame_count;
    float  frame_direction;
    float  frame_rotation;
};


struct out_vertex {
    float2 texCoord : TEXCOORD0;
};

/*    VERTEX_SHADER    */
out_vertex main_vertex
(
    float4 position      : POSITION,
    out float4 oPosition : POSITION,
    float2 texCoord      : TEXCOORD0,

    uniform float4x4 modelViewProj,
    uniform input IN
)
{
    oPosition = mul(modelViewProj, position);

    out_vertex OUT = {
        texCoord
    };

    return OUT;
}


float4 main_fragment(in out_vertex VAR, uniform sampler2D s_p : TEXUNIT0, uniform input IN) : COLOR
{
#ifdef SHARPER
    float2 TextureSize = float2(SHARPNESS*IN.texture_size.x, IN.texture_size.y);
#else
    float2 TextureSize = IN.texture_size;
#endif

    float2 dx = float2(1.0/TextureSize.x, 0.0);
    float2 dy = float2(0.0, 1.0/TextureSize.y);
    float2 pix_coord = VAR.texCoord*TextureSize-float2(0.5,0.0);

    float2 tc = (floor(pix_coord)+float2(0.5,0.5))/TextureSize;

    float2 fp = frac(pix_coord);

    float3 c10 = tex2D(s_p, tc     - dx).xyz;
    float3 c11 = tex2D(s_p, tc         ).xyz;
    float3 c12 = tex2D(s_p, tc     + dx).xyz;
    float3 c13 = tex2D(s_p, tc + 2.0*dx).xyz;

#ifdef ANTI_RINGING
    //  Get min/max samples
    float3 min_sample = min(c11, c12);
    float3 max_sample = max(c11, c12);
#endif

    float4x3 color_matrix = float4x3(c10, c11, c12, c13);

    float4 invX_Px = mul(invX, float4(fp.x*fp.x*fp.x, fp.x*fp.x, fp.x, 1.0));
    float3 color   = mul(invX_Px, color_matrix);

#ifdef DILATION
    float dz = DILATION_STRENGTH*IN.video_size.x/(IN.output_size.x);

    float2 fpf = float2(fp.x + dz, fp.y);
    float2 fpd = float2(fp.x - dz, fp.y);

    invX_Px = mul(invX, float4(fpf.x*fpf.x*fpf.x, fpf.x*fpf.x, fpf.x, 1.0));
    float3 colorf   = mul(invX_Px, color_matrix);

    invX_Px = mul(invX, float4(fpd.x*fpd.x*fpd.x, fpd.x*fpd.x, fpd.x, 1.0));
    float3 colord   = mul(invX_Px, color_matrix);

    color = max(color, max(colorf, colord));
#endif

#ifdef ANTI_RINGING
    // Anti-ringing
    color = clamp(color, min_sample, max_sample);
#endif

    float pos = abs(fp.y - 0.5);

    float3 lum = lerp(float3(BEAM_MIN_WIDTH), float3(BEAM_MAX_WIDTH), color);
    lum = pow(lum,float3(BEAM_WIDTH_SENSITIVITY));

    float3 d = clamp(pos/lum, 0.0, 1.0);

    d = smoothstep(0.0, 1.0, 1.0-d);

    d = SCANLINES_STRENGTH*(d-1.0)+1.0;

#ifdef RED_GREEN_CONTROL
    color.rgb *= float3(RED_BOOST, GREEN_BOOST, CRT_TV_BLUE_TINT);
#else
    color.b *= CRT_TV_BLUE_TINT;
#endif

    color = clamp(color*d, 0.0, 1.0);            
 
    color = GAMMA_IN(color);

#ifdef PHOSPHOR
    float mod_factor = VAR.texCoord.x * IN.output_size.x * IN.texture_size.x / IN.video_size.x;

    float3 dotMaskWeights = lerp(
                                 float3(1.0, 0.7, 1.0),
                                 float3(0.7, 1.0, 0.7),
                                 floor(fmod(mod_factor, 2.0))
                                  );

    color.rgb *= dotMaskWeights;
#endif                   

    color *= COLOR_BOOST;
    color  = GAMMA_OUT(color);

    return float4(color, 1.0);
}

