#version 450

/*
    print-resolution-text-generate-and-cache.slang

    Text code is from the Shadertoy "96-bit 8x12" Font by Flyguy
    Some adjustments by HyperspaceMadness to simplify usage, and create this slang version

    This pass reuses the output from the last frame until the resolution info changes so
    that we reduce calculation if nothing has changed
    The text image will be written into the alpha of the pass
    The print-resolution-text-apply.slang pass which goes along with this will take the alpha channel 
    and print it on top of the game image in the next pass

    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 3 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, see <https://www.gnu.org/licenses/>.
*/

#pragma format R16G16B16A16_SFLOAT

#pragma name TextGeneratePass

layout(push_constant) uniform Push
{
	vec4 OriginalSize;
	vec4 SourceSize;
	vec4 OutputSize;
	vec4 FinalViewportSize;
	uint FrameCount;
} params;

layout(std140, set = 0, binding = 0) uniform UBO
{
	mat4 MVP;
} global;

#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;

void main()
{
   gl_Position = global.MVP * Position;
   vTexCoord = TexCoord * 1.00001;
}

#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;

layout(set = 0, binding = 1) uniform sampler2D Source;
layout(set = 0, binding = 2) uniform sampler2D TextGeneratePassFeedback;
#define PassFeedback TextGeneratePassFeedback


#define MAX_INT_DIGITS 4

#define CHAR_SIZE vec2(6, 7)
#define CHAR_SPACING vec2(6, 11)

#define STRWIDTH(c) (c * CHAR_SPACING.x)
#define STRHEIGHT(c) (c * CHAR_SPACING.y)

#define DOWN_SCALE 2.0

/*
Top left pixel is the most significant bit.
Bottom right pixel is the least significant bit.

 â–ˆâ–ˆâ–ˆ  |
â–ˆ   â–ˆ |
â–ˆ   â–ˆ |  
â–ˆ   â–ˆ |
â–ˆâ–ˆâ–ˆâ–ˆâ–ˆ |
â–ˆ   â–ˆ |
â–ˆ   â–ˆ |

011100 
100010
100010  
100010
111110
100010
100010

011100 (upper 21 bits)
100010 -> 011100 100010 100010 100 -> 935188
100010  
100
   010 (lower 21 bits)
111110 -> 010 111110 100010 100010 -> 780450
100010
100010

vec2(935188.0,780450.0)
*/

//Automatically generated from the sprite sheet here: http://uzebox.org/wiki/index.php?title=File:Font6x8.png
vec2 ch_spc = vec2(0.0,0.0);
vec2 ch_exc = vec2(276705.0,32776.0);
vec2 ch_quo = vec2(1797408.0,0.0);
vec2 ch_hsh = vec2(10738.0,1134484.0);
vec2 ch_dol = vec2(538883.0,19976.0);
vec2 ch_pct = vec2(1664033.0,68006.0);
vec2 ch_amp = vec2(545090.0,174362.0);
vec2 ch_apo = vec2(798848.0,0.0);
vec2 ch_lbr = vec2(270466.0,66568.0);
vec2 ch_rbr = vec2(528449.0,33296.0);
vec2 ch_ast = vec2(10471.0,1688832.0);
vec2 ch_crs = vec2(4167.0,1606144.0);
vec2 ch_per = vec2(0.0,1560.0);
vec2 ch_dsh = vec2(7.0,1572864.0);
vec2 ch_com = vec2(0.0,1544.0);
vec2 ch_lsl = vec2(1057.0,67584.0);
vec2 ch_0 = vec2(935221.0,731292.0);
vec2 ch_1 = vec2(274497.0,33308.0);
vec2 ch_2 = vec2(934929.0,1116222.0);
vec2 ch_3 = vec2(934931.0,1058972.0);
vec2 ch_4 = vec2(137380.0,1302788.0);
vec2 ch_5 = vec2(2048263.0,1058972.0);
vec2 ch_6 = vec2(401671.0,1190044.0);
vec2 ch_7 = vec2(2032673.0,66576.0);
vec2 ch_8 = vec2(935187.0,1190044.0);
vec2 ch_9 = vec2(935187.0,1581336.0);
vec2 ch_col = vec2(195.0,1560.0);
vec2 ch_scl = vec2(195.0,1544.0);
vec2 ch_les = vec2(135300.0,66052.0);
vec2 ch_equ = vec2(496.0,3968.0);
vec2 ch_grt = vec2(528416.0,541200.0);
vec2 ch_que = vec2(934929.0,1081352.0);
vec2 ch_ats = vec2(935285.0,714780.0);
vec2 ch_A = vec2(935188.0,780450.0);
vec2 ch_B = vec2(1983767.0,1190076.0);
vec2 ch_C = vec2(935172.0,133276.0);
vec2 ch_D = vec2(1983764.0,665788.0);
vec2 ch_E = vec2(2048263.0,1181758.0);
vec2 ch_F = vec2(2048263.0,1181728.0);
vec2 ch_G = vec2(935173.0,1714334.0);
vec2 ch_H = vec2(1131799.0,1714338.0);
vec2 ch_I = vec2(921665.0,33308.0);
vec2 ch_J = vec2(66576.0,665756.0);
vec2 ch_K = vec2(1132870.0,166178.0);
vec2 ch_L = vec2(1065220.0,133182.0);
vec2 ch_M = vec2(1142100.0,665762.0);
vec2 ch_N = vec2(1140052.0,1714338.0);
vec2 ch_O = vec2(935188.0,665756.0);
vec2 ch_P = vec2(1983767.0,1181728.0);
vec2 ch_Q = vec2(935188.0,698650.0);
vec2 ch_R = vec2(1983767.0,1198242.0);
vec2 ch_S = vec2(935171.0,1058972.0);
vec2 ch_T = vec2(2035777.0,33288.0);
vec2 ch_U = vec2(1131796.0,665756.0);
vec2 ch_V = vec2(1131796.0,664840.0);
vec2 ch_W = vec2(1131861.0,699028.0);
vec2 ch_X = vec2(1131681.0,84130.0);
vec2 ch_Y = vec2(1131794.0,1081864.0);
vec2 ch_Z = vec2(1968194.0,133180.0);
vec2 ch_lsb = vec2(925826.0,66588.0);
vec2 ch_rsl = vec2(16513.0,16512.0);
vec2 ch_rsb = vec2(919584.0,1065244.0);
vec2 ch_pow = vec2(272656.0,0.0);
vec2 ch_usc = vec2(0.0,62.0);
vec2 ch_a = vec2(224.0,649374.0);
vec2 ch_b = vec2(1065444.0,665788.0);
vec2 ch_c = vec2(228.0,657564.0);
vec2 ch_d = vec2(66804.0,665758.0);
vec2 ch_e = vec2(228.0,772124.0);
vec2 ch_f = vec2(401543.0,1115152.0);
vec2 ch_g = vec2(244.0,665474.0);
vec2 ch_h = vec2(1065444.0,665762.0);
vec2 ch_i = vec2(262209.0,33292.0);
vec2 ch_j = vec2(131168.0,1066252.0);
vec2 ch_k = vec2(1065253.0,199204.0);
vec2 ch_l = vec2(266305.0,33292.0);
vec2 ch_m = vec2(421.0,698530.0);
vec2 ch_n = vec2(452.0,1198372.0);
vec2 ch_o = vec2(228.0,665756.0);
vec2 ch_p = vec2(484.0,667424.0);
vec2 ch_q = vec2(244.0,665474.0);
vec2 ch_r = vec2(354.0,590904.0);
vec2 ch_s = vec2(228.0,114844.0);
vec2 ch_t = vec2(8674.0,66824.0);
vec2 ch_u = vec2(292.0,1198868.0);
vec2 ch_v = vec2(276.0,664840.0);
vec2 ch_w = vec2(276.0,700308.0);
vec2 ch_x = vec2(292.0,1149220.0);
vec2 ch_y = vec2(292.0,1163824.0);
vec2 ch_z = vec2(480.0,1148988.0);
vec2 ch_lpa = vec2(401542.0,66572.0);
vec2 ch_bar = vec2(266304.0,33288.0);
vec2 ch_rpa = vec2(788512.0,1589528.0);
vec2 ch_tid = vec2(675840.0,0.0);
vec2 ch_lar = vec2(8387.0,1147904.0);

float TEXT_MASK = 0;
vec2 CUR_UV = vec2(0);

#define _spc TEXT_MASK += char_px(ch_spc, CUR_UV);
#define _exc TEXT_MASK += char_px(ch_exc, CUR_UV);
#define _quo TEXT_MASK += char_px(ch_quo, CUR_UV);
#define _hsh TEXT_MASK += char_px(ch_hsh, CUR_UV);
#define _dol TEXT_MASK += char_px(ch_dol, CUR_UV);
#define _pct TEXT_MASK += char_px(ch_pct, CUR_UV);
#define _amp TEXT_MASK += char_px(ch_amp, CUR_UV);
#define _apo TEXT_MASK += char_px(ch_apo, CUR_UV);
#define _lbr TEXT_MASK += char_px(ch_lbr, CUR_UV);
#define _rbr TEXT_MASK += char_px(ch_rbr, CUR_UV);
#define _ast TEXT_MASK += char_px(ch_ast, CUR_UV);
#define _crs TEXT_MASK += char_px(ch_crs, CUR_UV);
#define _per TEXT_MASK += char_px(ch_per, CUR_UV);
#define _dsh TEXT_MASK += char_px(ch_dsh, CUR_UV);
#define _com TEXT_MASK += char_px(ch_com, CUR_UV);
#define _lsl TEXT_MASK += char_px(ch_lsl, CUR_UV);
#define _0 TEXT_MASK += char_px(ch_0, CUR_UV);
#define _1 TEXT_MASK += char_px(ch_1, CUR_UV);
#define _2 TEXT_MASK += char_px(ch_2, CUR_UV);
#define _3 TEXT_MASK += char_px(ch_3, CUR_UV);
#define _4 TEXT_MASK += char_px(ch_4, CUR_UV);
#define _5 TEXT_MASK += char_px(ch_5, CUR_UV);
#define _6 TEXT_MASK += char_px(ch_6, CUR_UV);
#define _7 TEXT_MASK += char_px(ch_7, CUR_UV);
#define _8 TEXT_MASK += char_px(ch_8, CUR_UV);
#define _9 TEXT_MASK += char_px(ch_9, CUR_UV);
#define _col TEXT_MASK += char_px(ch_col, CUR_UV);
#define _scl TEXT_MASK += char_px(ch_scl, CUR_UV);
#define _les TEXT_MASK += char_px(ch_les, CUR_UV);
#define _equ TEXT_MASK += char_px(ch_equ, CUR_UV);
#define _grt TEXT_MASK += char_px(ch_grt, CUR_UV);
#define _que TEXT_MASK += char_px(ch_que, CUR_UV);
#define _ats TEXT_MASK += char_px(ch_ats, CUR_UV);
#define _A TEXT_MASK += char_px(ch_A, CUR_UV);
#define _B TEXT_MASK += char_px(ch_B, CUR_UV);
#define _C TEXT_MASK += char_px(ch_C, CUR_UV);
#define _D TEXT_MASK += char_px(ch_D, CUR_UV);
#define _E TEXT_MASK += char_px(ch_E, CUR_UV);
#define _F TEXT_MASK += char_px(ch_F, CUR_UV);
#define _G TEXT_MASK += char_px(ch_G, CUR_UV);
#define _H TEXT_MASK += char_px(ch_H, CUR_UV);
#define _I TEXT_MASK += char_px(ch_I, CUR_UV);
#define _J TEXT_MASK += char_px(ch_J, CUR_UV);
#define _K TEXT_MASK += char_px(ch_K, CUR_UV);
#define _L TEXT_MASK += char_px(ch_L, CUR_UV);
#define _M TEXT_MASK += char_px(ch_M, CUR_UV);
#define _N TEXT_MASK += char_px(ch_N, CUR_UV);
#define _O TEXT_MASK += char_px(ch_O, CUR_UV);
#define _P TEXT_MASK += char_px(ch_P, CUR_UV);
#define _Q TEXT_MASK += char_px(ch_Q, CUR_UV);
#define _R TEXT_MASK += char_px(ch_R, CUR_UV);
#define _S TEXT_MASK += char_px(ch_S, CUR_UV);
#define _T TEXT_MASK += char_px(ch_T, CUR_UV);
#define _U TEXT_MASK += char_px(ch_U, CUR_UV);
#define _V TEXT_MASK += char_px(ch_V, CUR_UV);
#define _W TEXT_MASK += char_px(ch_W, CUR_UV);
#define _X TEXT_MASK += char_px(ch_X, CUR_UV);
#define _Y TEXT_MASK += char_px(ch_Y, CUR_UV);
#define _Z TEXT_MASK += char_px(ch_Z, CUR_UV);
#define _lsb TEXT_MASK += char_px(ch_lsb, CUR_UV);
#define _rsl TEXT_MASK += char_px(ch_rsl, CUR_UV);
#define _rsb TEXT_MASK += char_px(ch_rsb, CUR_UV);
#define _pow TEXT_MASK += char_px(ch_pow, CUR_UV);
#define _usc TEXT_MASK += char_px(ch_usc, CUR_UV);
#define _a TEXT_MASK += char_px(ch_a, CUR_UV);
#define _b TEXT_MASK += char_px(ch_b, CUR_UV);
#define _c TEXT_MASK += char_px(ch_c, CUR_UV);
#define _d TEXT_MASK += char_px(ch_d, CUR_UV);
#define _e TEXT_MASK += char_px(ch_e, CUR_UV);
#define _f TEXT_MASK += char_px(ch_f, CUR_UV);
#define _g TEXT_MASK += char_px(ch_g, CUR_UV);
#define _h TEXT_MASK += char_px(ch_h, CUR_UV);
#define _i TEXT_MASK += char_px(ch_i, CUR_UV);
#define _j TEXT_MASK += char_px(ch_j, CUR_UV);
#define _k TEXT_MASK += char_px(ch_k, CUR_UV);
#define _l TEXT_MASK += char_px(ch_l, CUR_UV);
#define _m TEXT_MASK += char_px(ch_m, CUR_UV);
#define _n TEXT_MASK += char_px(ch_n, CUR_UV);
#define _o TEXT_MASK += char_px(ch_o, CUR_UV);
#define _p TEXT_MASK += char_px(ch_p, CUR_UV);
#define _q TEXT_MASK += char_px(ch_q, CUR_UV);
#define _r TEXT_MASK += char_px(ch_r, CUR_UV);
#define _s TEXT_MASK += char_px(ch_s, CUR_UV);
#define _t TEXT_MASK += char_px(ch_t, CUR_UV);
#define _u TEXT_MASK += char_px(ch_u, CUR_UV);
#define _v TEXT_MASK += char_px(ch_v, CUR_UV);
#define _w TEXT_MASK += char_px(ch_w, CUR_UV);
#define _x TEXT_MASK += char_px(ch_x, CUR_UV);
#define _y TEXT_MASK += char_px(ch_y, CUR_UV);
#define _z TEXT_MASK += char_px(ch_z, CUR_UV);
#define _lpa TEXT_MASK += char_px(ch_lpa, CUR_UV);
#define _bar TEXT_MASK += char_px(ch_bar, CUR_UV);
#define _rpa TEXT_MASK += char_px(ch_rpa, CUR_UV);
#define _tid TEXT_MASK += char_px(ch_tid, CUR_UV);
#define _lar TEXT_MASK += char_px(ch_lar, CUR_UV);

vec2 res;
vec2 print_pos = vec2(0);

//Extracts bit b from the given number.
//Shifts bits right (num / 2^bit) then ANDs the result with 1 (mod(result,2.0)).
float extract_bit(float n, float b)
{
    b = clamp(b,-1.0,22.0); //Fixes small artefacts on my nexus 7
	return floor(mod(floor(n / pow(2.0,floor(b))),2.0));   
}

//Returns the pixel at uv in the given bit-packed sprite.
float sprite(vec2 spr, vec2 size, vec2 uv)
{
    uv = floor(uv);
    //Calculate the bit to extract (x + y * width) (flipped on x-axis)
    float bit = (size.x-uv.x-1.0) + uv.y * size.x;
    
    //Clipping bound to remove garbage outside the sprite's boundaries.
    bool bounds = all(greaterThanEqual(uv,vec2(0)));
    bounds = bounds && all(lessThan(uv,size));
    
    return bounds ? extract_bit(spr.x, bit - 21.0)+extract_bit(spr.y, bit) : 0.0;

}

//Prints a character and moves the print position forward by 1 character width.
float char_px(vec2 ch, vec2 uv)
{
    float px = sprite(ch, CHAR_SIZE, uv - print_pos);
    print_pos.x += CHAR_SPACING.x;
    return px;
}

//Returns the digit sprite for the given number.
vec2 get_digit(float d)
{
    d = floor(d);
    
    if(d == 0.0) return ch_0;
    if(d == 1.0) return ch_1;
    if(d == 2.0) return ch_2;
    if(d == 3.0) return ch_3;
    if(d == 4.0) return ch_4;
    if(d == 5.0) return ch_5;
    if(d == 6.0) return ch_6;
    if(d == 7.0) return ch_7;
    if(d == 8.0) return ch_8;
    if(d == 9.0) return ch_9;
    return vec2(0.0);
}

//Prints out the given number starting at pos.
float print_number(float number,vec2 pos, vec2 uv)
{
	vec2 dec_pos = pos;
    float result = 0.0;
    
	for(int i = 3; i >= -2; i--)
    {
        float clip = float(abs(number) > pow(10.0, float(i)) || i == 0); //Clip off leading zeros.
        
        float digit = mod(number / pow(10.0, float(i)),10.0);
        
        if(i == -1)
        {
            result += sprite(ch_per,CHAR_SIZE, uv - dec_pos) * clip;
            dec_pos.x += CHAR_SPACING.x * clip;
        }
        result += sprite(get_digit(digit),CHAR_SIZE, uv - dec_pos) * clip;
        
        
        dec_pos.x += CHAR_SPACING.x * clip;
    }
    
    return result;
}

float print_integer(float number, int zeros, vec2 uv)
{
    float result = 0.0;

	for(int i = MAX_INT_DIGITS; i >= 0; i--)
    {
        float digit = mod( number / pow(10.0, float(i)) , 10.0);

        if(abs(number) > pow(10.0, float(i)) || zeros > i  || i == 0) //Clip off leading zeros.
        {
        	result += char_px(get_digit(digit), uv);
        }
    }   
    return result;
}

#define eps 1e-3

vec2 GetIntegerScaleMult()
{
	float epsilon = 0.01;
	vec2 integer_scale = params.FinalViewportSize.xy / params.OriginalSize.xy;
	integer_scale = vec2(abs(integer_scale.x - round(integer_scale.x)) < epsilon ? round(integer_scale.x) : integer_scale.x,
						 abs(integer_scale.y - round(integer_scale.y)) < epsilon ? round(integer_scale.y) : integer_scale.y);
	return integer_scale;
}

float DrawResolutions(vec2 uv)
{
    float col = 0.0;
    
    float current_line_index = 0;
    float margin = STRHEIGHT(1);

    // Resolution Text
    print_pos = vec2(margin, 0);

    // Viewport Resolution ----------------------------------------------------
    TEXT_MASK = 0;
    CUR_UV = uv;

    // Int Scale Vertical ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);

    _I _n _t _spc _S _c _l _spc _V _e _r _t _spc _dsh _dsh _dsh _dsh _dsh _dsh _spc

    vec2 int_mult = GetIntegerScaleMult();

    if (fract(int_mult.y) < 0.01)
        TEXT_MASK += print_integer(int_mult.y, 0, uv);
    else
        TEXT_MASK += print_number(int_mult.y, print_pos, uv);


    // Int Scale Horizontal ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);
    
    _I _n _t _spc _S _c _l _spc _H _o _r _z _spc _dsh _dsh _dsh _dsh _dsh _dsh _spc

    if (fract(int_mult.x) < 0.01)
        TEXT_MASK += print_integer(int_mult.x, 0, uv);
    else
        TEXT_MASK += print_number(int_mult.x, print_pos, uv);


    // Final Aspect Ratio ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);
    
    _F _i _n _a _l _spc _A _s _p _e _c _t _spc _dsh _dsh _dsh _dsh _dsh _dsh _spc
    TEXT_MASK += print_number(params.FinalViewportSize.x / params.FinalViewportSize.y > 1 ? params.FinalViewportSize.x / params.FinalViewportSize.y : params.FinalViewportSize.y / params.FinalViewportSize.x, print_pos, uv);


    // Final Viewport ResS ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);
    
    _F _i _n _a _l _spc _V _i _e _w _p _o _r _t _spc _dsh _dsh _dsh _dsh _spc 
    TEXT_MASK += print_integer(params.FinalViewportSize.x, 0, uv); 
    _spc _x _spc
    TEXT_MASK += print_integer(params.FinalViewportSize.y, 0, uv); 


    // Pass Output Resolution ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);
        
    _T _e _x _t _spc _O _u _t _p _u _t _spc _R _e _s _spc _dsh _dsh _dsh _spc

    TEXT_MASK += print_integer(params.OutputSize.x, 0, uv);
    _spc _x _spc
    TEXT_MASK += print_integer(params.OutputSize.y, 0, uv);


    // Source Resolution ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);
        
    _S _o _u _r _c _e _spc _amp  _spc _T _e _x _t _spc _R _e _s _spc _dsh _spc

    TEXT_MASK += print_integer(params.SourceSize.x, 0, uv);
    _spc _x _spc
    TEXT_MASK += print_integer(params.SourceSize.y, 0, uv);


    // CORE Resolution ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);

     _O _r _i _g _i _n _a _l _spc _R _e _s _spc _dsh _dsh _dsh _dsh _dsh _dsh _spc

    TEXT_MASK += print_integer(params.OriginalSize.x, 0, uv);
    _spc _x _spc
    TEXT_MASK += print_integer(params.OriginalSize.y, 0, uv);

    // Empty Line ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);

    // Resolution Debugging ----------------------------------------------------------
    print_pos.x = margin;
    print_pos.y += STRHEIGHT(1);

     _P _r _i _n _t _spc _R _e _s _o _l _u _t _i _o _n _spc  _T _e _x _t _spc

    return TEXT_MASK;
}

float GetText(vec2 in_coord)
{
    vec2 canvas_size = params.OutputSize.xy;

    in_coord = (in_coord - 0.5) * vec2(1, -1) + 0.5;
    float downscale = 1;
    if (canvas_size.y > 460) downscale = 2;
    if (canvas_size.y > 1000) downscale = 3;

    vec2 uv = params.OutputSize.xy * in_coord;
    vec2 downscaled_uv = floor(params.OutputSize.xy * in_coord / downscale);

    float pixel = DrawResolutions(downscaled_uv);

    vec3 col = vec3(1);
    pixel *= (1 - distance(mod(uv, vec2(1.0)), vec2(0.65))) * 1.2;
    col *= mix(vec3(0), vec3(1, 1, 1), pixel);

    return col.r;
}

float GetTestValue()
{
	float out_val = params.OriginalSize.x +
                    params.OriginalSize.y +
                    params.SourceSize.x +
                    params.SourceSize.y +
                    params.OutputSize.x +
                    params.OutputSize.y +
                    params.FinalViewportSize.x +
                    params.FinalViewportSize.y;

    return out_val;
}

void main()
{
    float current_test_value = GetTestValue();
    float feedback_test_value = texture(PassFeedback, vec2(0,0)).a;

    if (feedback_test_value == current_test_value)
    {
        FragColor = texture(PassFeedback, vTexCoord);
        return;
    }

    FragColor = FragColor = texture(Source, vTexCoord);
    FragColor.a = GetText(vTexCoord);

    if (vTexCoord.x < params.OutputSize.z * 2 && vTexCoord.y < params.OutputSize.w * 2)
        FragColor.a = current_test_value;

    // // Bit to have a moving image to test if the cache is working
    // if (vTexCoord.x > 0.8 && vTexCoord.y > 0.8)
    //     FragColor.a = sin(mod(params.FrameCount, 60) / 60);

    return;
}