uniform sampler2D tex;
uniform float red;
uniform float green;
uniform float blue;
uniform float blend;
uniform int mode;

const int NORMAL = 0;
const int MULTIPLY = 1;
const int SCREEN = 2;
const int OVERLAY = 3;
const int DARKEN = 4;
const int LIGHTEN = 5;
const int PLUS_DARKER = 6;
const int PLUS_LIGHTER = 7;
const int COLOR_DODGE = 8;
const int COLOR_BURN = 9;
const int HARD_LIGHT = 10;
const int SOFT_LIGHT = 11;
const int DIFFERENCE = 12;
const int EXCLUSION = 13;
const int HUE = 14;
const int SATURATION = 15;
const int COLOR = 16;
const int LUMINOSITY = 17;

vec3 rgb_to_hsl(vec3 c) {
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

vec3 hsl_to_rgb(vec3 c) {
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}

float soft_light_channel(float base, float _blend) {
    if (_blend < 0.5) {
        return base - (1.0 - 2.0 * _blend) * base * (1.0 - base);
    } else {
        float d = (base < 0.25)
        ? ((16.0 * base - 12.0) * base + 4.0) * base
        : sqrt(base);
        return base + (2.0 * _blend - 1.0) * (d - base);
    }
}

vec3 get_blend(vec3 base, vec3 _blend) {
    if (mode == MULTIPLY) return base * _blend;
    if (mode == SCREEN) return 1 - (1 - base) * (1 - _blend);
    if (mode == OVERLAY) {
        vec3 result;
        result.r = base.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r));
        result.g = base.g < 0.5 ? (2.0 * base.g * _blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - _blend.g));
        result.b = base.b < 0.5 ? (2.0 * base.b * _blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - _blend.b));
        return result;
    }
    if (mode == DARKEN) return min(base, _blend);
    if (mode == LIGHTEN) return max(base, _blend);
    if (mode == PLUS_DARKER) return base + _blend - 1;
    if (mode == PLUS_LIGHTER) return base + _blend;
    if (mode == COLOR_DODGE) return base / (1 - _blend);
    if (mode == COLOR_BURN) return 1 - (1 - base) / _blend;
    if (mode == HARD_LIGHT) {
        vec3 result;
        result.r = _blend.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r));
        result.g = _blend.g < 0.5 ? (2.0 * base.g * _blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - _blend.g));
        result.b = _blend.b < 0.5 ? (2.0 * base.b * _blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - _blend.b));
        return result;
    }
    if (mode == SOFT_LIGHT) {
        return vec3(soft_light_channel(base.r, _blend.r), soft_light_channel(base.g, _blend.g), soft_light_channel(base.b, _blend.b));
    }
    if (mode == DIFFERENCE) return abs(base - _blend);
    if (mode == EXCLUSION) return 0.5 - 2 * (base - 0.5) * (_blend - 0.5);
    if (mode == HUE) {
        vec3 base_hsl = rgb_to_hsl(base);
        vec3 blend_hsl = rgb_to_hsl(_blend);
        return hsl_to_rgb(vec3(blend_hsl.x, base_hsl.y, base_hsl.z));
    }
    if (mode == SATURATION) {
        vec3 base_hsl = rgb_to_hsl(base);
        vec3 blend_hsl = rgb_to_hsl(_blend);
        return hsl_to_rgb(vec3(base_hsl.x, blend_hsl.y, base_hsl.z));
    }
    if (mode == COLOR) {
        vec3 base_hsl = rgb_to_hsl(base);
        vec3 blend_hsl = rgb_to_hsl(_blend);
        return hsl_to_rgb(vec3(blend_hsl.x, blend_hsl.y, base_hsl.z));
    }
    if (mode == LUMINOSITY) {
        vec3 base_hsl = rgb_to_hsl(base);
        vec3 blend_hsl = rgb_to_hsl(_blend);
        return hsl_to_rgb(vec3(base_hsl.x, base_hsl.y, blend_hsl.z));
    }
    return _blend; // For NORMAL
}

void main() {
    vec4 c = texture2D(tex, cogl_tex_coord_in[0].st);
    vec3 pix_color = c.xyz;
    vec3 color = get_blend(pix_color, vec3(red, green, blue));

    cogl_color_out = vec4(mix(pix_color, color, blend), 1.);
}