
vec3 conv(in sampler2D tex, in vec2 uv, in mat3 ker);

vec3 edges(in sampler2D tex, in vec2 uv)
{
    mat3 ker = mat3(
        vec3(-1, -2, -1),
        vec3(-2, 12, -2),
        vec3(-1, -2, -1)
    );
    
    return conv(tex, uv, ker)+.5;
}

// can be used to remove high frequency noise
vec3 median(in sampler2D tex, in vec2 uv)
{
    float k = 1./8.;
    mat3 ker = mat3(
        vec3(k, k, k),
        vec3(k, 0, k),
        vec3(k, k, k)
    );
    
    return conv(tex, uv, ker);
}

// sharpen filter including diagonals
vec3 laplace(in sampler2D tex, in vec2 uv, in float strength)
{
    float k = -strength;
    mat3 ker = mat3(
        vec3(k, k, k),
        vec3(k, 8.*strength+1., k),
        vec3(k, k, k)
    );
    
    return conv(tex, uv, ker);
}

// subtracts high frequency edges from the source image
vec3 unsharp(in sampler2D tex, in vec2 uv)
{
    float k = 1./9.;
    mat3 ker = mat3(
        vec3(k, k, k),
        vec3(k, k, k),
        vec3(k, k, k)
    );
    
    vec3 blurred = conv(tex, uv, ker);
    
    return texture(iChannel0, uv).rgb - (texture(iChannel0, uv).rgb - blurred);
}

vec3 emboss(in sampler2D tex, in vec2 uv, in float theta)
{
    // init kernel
    mat3 ker = mat3(
        vec3(0),
        vec3(0),
        vec3(0)
    );
    
    // direction of edge detection
    vec2 dir = vec2(sin(theta), cos(theta));
    
    // fill kernel with values
    for (int x = -1; x < 2; x++)
    for (int y = -1; y < 2; y++)
        ker[x+1][y+1] = dot(dir, vec2(x,y));
    
    return conv(tex, uv, ker)+.5;
}

vec3 sobelFeldmann(in sampler2D tex, in vec2 uv)
{
    // init horizontal kernel
    mat3 ker0 = mat3(
        vec3(1, 0, -1),
        vec3(2, 0, -2),
        vec3(1, 0, -1)
    );
    
    // init vertical kernel
    mat3 ker1 = mat3(
        vec3(1, 2, 1),
        vec3(0, 0, 0),
        vec3(-1, -2, -1)
    );
    
    vec3 c0 = conv(tex, uv, ker0);// convolute horizontal
    vec3 c1 = conv(tex, uv, ker1);// convolute vertical
    
    // pythagoras
    return sqrt(c0*c0+c1*c1);
}

vec3 conv(in sampler2D tex, in vec2 uv, in mat3 ker)
{
    vec3 sum = vec3(0);
    
    for (int x = 0; x < 3; x++)
    for (int y = 0; y < 3; y++)
    {
        vec2 off = (vec2(x,y)*.3333-.5)/iResolution.xy;
        sum += texture(tex, uv + off).rgb * ker[x][y];
    }
    
    return sum;
}

bool sector(in vec2 uv, in vec2 hor, in vec2 ver)
{
    vec2 delta = 1./vec2(hor[1], ver[1]);

    vec2 low = delta * vec2(hor[0], ver[0]);
    vec2 high = low + delta;
    
    return low.x < uv.x && low.y < uv.y && high.x > uv.x && high.y > uv.y;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord/iResolution.xy;

    vec3 col = texture(iChannel0, uv).rgb;
    
    if (sector(uv, vec2(0,4), vec2(1,2))) col = unsharp(iChannel0, uv);
    if (sector(uv, vec2(1,4), vec2(0,2))) col = laplace(iChannel0, uv, 2.0);
    if (sector(uv, vec2(1,2), vec2(0,2))) col = emboss(iChannel0, uv, iTime);
    if (sector(uv, vec2(1,2), vec2(1,2))) col = sobelFeldmann(iChannel0, uv);
    if (sector(uv, vec2(1,4), vec2(1,2))) col = median(iChannel0, uv);
    if (sector(uv, vec2(1,4), vec2(1,2))) col = edges(iChannel0, uv);
    
    fragColor = vec4(col,1.0);
}