#version 110

// Standard inputs
uniform vec2 ove_resolution;
varying vec2 ove_texcoord;
uniform int ove_iteration;

// Node parameter inputs
uniform sampler2D tex_in;
uniform float sigma_in;
uniform bool horiz_in;
uniform bool vert_in;

// Gaussian function uses PI
#define M_PI 3.1415926535897932384626433832795

// Single gaussian formula (unused, mainly here for documentation/just in case)
//float gaussian(float x, float sigma) {
//    return (1.0/(sigma*sqrt(2.0*M_PI)))*exp(-0.5*pow(x/sigma, 2.0));
//}

// Double gaussian formula, actually used in the code below
// Should be faster than the single gaussian above since it doesn't need sqrt()
float gaussian2(float x, float y, float sigma) {
    return (1.0/(pow(sigma, 2.0)*2.0*M_PI))*exp(-0.5*((pow(x, 2.0) + pow(y, 2.0))/pow(sigma, 2.0)));
}

void main(void) {
    // Determine this iteration should process anything or not
    if (sigma_in == 0.0                          // If the radius is zero
        || (ove_iteration == 0 && !horiz_in)     // Or this iteration (horizontal) is disabled
        || (ove_iteration == 1 && !vert_in)) {   // Or this iteration (vertical) is disabled
        // No-op, do nothing
        gl_FragColor = texture2D(tex_in, ove_texcoord);
        return;
    }

    // Using (3 * sigma) because 3 standard deviations covers 97% of the blur according to this document:
    // http://chemaguerra.com/gaussian-filter-radius/
    float radius = ceil(3.0 * sigma_in);

    // Use gaussian formula to calculate the weight of all pixels
    float sum = 0.0;
    for (float i=-radius+0.5;i<=radius;i+=2.0) {
        sum += gaussian2(i, 0.0, sigma_in);
    }

    // We can take advantage of OpenGL's linear interpolation by sampling between pixels. This produces a mathematically
    // identical result while allowing us to sample the texture half as many times.
    vec4 composite = vec4(0.0);
    for (float i=-radius+0.5;i<=radius;i+=2.0) {
        // Calculate weight of this pixel using gaussian
        float weight = (gaussian2(i, 0.0, sigma_in)/sum);

        // Determine pixel coordinate based on iteration
        // We use two iterations horizontally and vertically since that produces a mathematically identical result and
        // (2*radius) is much faster than (radius^2)
        vec2 pixel_coord = ove_texcoord;
        if (ove_iteration == 0) {
            pixel_coord.x += i/ove_resolution.x;
        } else if (ove_iteration == 1) {
            pixel_coord.y += i/ove_resolution.y;
        }

        composite += texture2D(tex_in, pixel_coord) * weight;
    }
    gl_FragColor = composite;
}
