#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 sampler2DRect u_texture_gv;         // v-gradient

uniform float u_rez;
uniform int   dbg_without_derivatives;

/*
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); }
vec4 sample_gv(vec2 coord) { return texture2DRect(u_texture_gv, coord); }

void main() {
    vec2 coord = gl_FragCoord.xy;
    vec2 dx = vec2(1.0, 0.0);
    vec2 dy = vec2(0.0, 1.0);
    
    vec4 f_00  = sample_f (coord);
    
    if (f_00.w == 1.0) {
        gl_FragColor = f_00;
        return;
    }
    
    if (dbg_without_derivatives) {
        gl_FragColor =
            0.25 * sample_f(coord - dx) +
            0.25 * sample_f(coord + dx) +
            0.25 * sample_f(coord - dy) +
            0.25 * sample_f(coord + dy);
        gl_FragColor.w = 0.0;
        return;
    }
    vec4 f_m0 = coord.x == 0.5         ? f_00 : (sample_f(coord - dx) + sample_gu(coord - dx));
    vec4 f_p0 = coord.x == u_rez - 0.5 ? f_00 : (sample_f(coord + dx) - sample_gu(coord     ));
    vec4 f_0m = coord.y == 0.5         ? f_00 : (sample_f(coord - dy) + sample_gv(coord - dy));
    vec4 f_0p = coord.y == u_rez - 0.5 ? f_00 : (sample_f(coord + dy) - sample_gv(coord     ));
    gl_FragColor =
        0.5   * f_00 +
        0.125 * f_m0 +
        0.125 * f_p0 +
        0.125 * f_0m +
        0.125 * f_0p;
    gl_FragColor.w = 0.0;
}
