#extension GL_ARB_texture_rectangle : enable

uniform sampler2DRect u_texture_f;          // value ('fixed' flag at w-component)
uniform sampler2DRect u_texture_gu;         // u-gradient

uniform float u_rez;

/*
p: plus 1
m: minus 1
0: no plus/minus
(exmaples)
f_00 means f(i, j)
f_p0 means f(i+1, j)
*/
vec4 sample_f (vec2 coord) { return texture2DRect(u_texture_f , coord); }
vec4 sample_gu(vec2 coord) { return texture2DRect(u_texture_gu, coord); }

void main() {
    vec2 coord = gl_FragCoord.xy;
    vec2 dx  = vec2(1.0, 0.0);
    vec2 dy  = vec2(0.0, 1.0);
    vec2 dx2 = vec2(2.0, 0.0);
    
    vec4 gu_00 = sample_gu(coord);
    vec4 gu_m0 = sample_gu(coord - dx);
    vec4 gu_p0 = sample_gu(coord + dx);
    vec4 gu_0m = sample_gu(coord - dy);
    vec4 gu_0p = sample_gu(coord + dy);
    
    if (gu_00.w == 1.0) {
        gl_FragColor = gu_00;
        return;
    }
    
    vec4 hu_00 = sample_f(coord + dx) - sample_f(coord);
    vec4 hu_m0 = coord.x == 0.5         ? hu_00 : gu_m0.w == 1.0 ? gu_m0 : (sample_f(coord          ) - sample_f(coord - dx));
    vec4 hu_p0 = coord.x == u_rez - 1.5 ? hu_00 : gu_p0.w == 1.0 ? gu_p0 : (sample_f(coord + dx2    ) - sample_f(coord + dx));
    vec4 hu_0m = coord.y == 0.5         ? hu_00 : gu_0m.w == 1.0 ? gu_0m : (sample_f(coord + dx - dy) - sample_f(coord - dy));
    vec4 hu_0p = coord.y == u_rez - 0.5 ? hu_00 : gu_0p.w == 1.0 ? gu_0p : (sample_f(coord + dx + dy) - sample_f(coord + dy));
    gl_FragColor =
        0.5   * hu_00 +
        0.125 * hu_m0 +
        0.125 * hu_p0 +
        0.125 * hu_0m +
        0.125 * hu_0p;
    gl_FragColor.w = 0.0;
}
