float get_luminance(vec3 x) {
    return dot(x, vec3(0.2126, 0.7152, 0.0722));
}

vec3 reinhard_inv(vec3 x) {
    return x / (1 - x);
}
#include "tonemap/Reinhard_Jodie.glsl"
#include "tonemap/ACES.glsl"
#include "tonemap/Uncharted2.glsl"
#include "tonemap/agx_minimal.glsl"

vec3 apply_tonemap(vec3 x) {
    #if TONEMAP_OPERATOR == 0
    return reinhard_jodie(x);
    #elif TONEMAP_OPERATOR == 1
    return ACESFitted(x);
    #elif TONEMAP_OPERATOR == 2
    return uncharted2_filmic(x);
    #elif TONEMAP_OPERATOR == 3
    return agx_tonemapping(x);
    #else
    return x;
    #endif
}

vec3 apply_saturation(vec3 Color, float Sat) {
    float luminance = get_luminance(Color);
    return mix(vec3(luminance), Color, Sat);
}

vec3 apply_vibrance(vec3 color, float intensity) {
    float mn = min(color.r, min(color.g, color.b));
    float mx = max(color.r, max(color.g, color.b));
    float sat = (1.0 - clamp(mx - mn, 0, 1)) * clamp(1.0 - mx, 0, 1) * get_luminance(color) * 5.0;
    vec3 lightness = vec3((mn + mx) * 0.5);

    return mix(color, mix(lightness, color, intensity), sat);
}

vec3 apply_contrast(vec3 color, float contrast) {
    return (color - 0.5) * contrast + 0.5;
}

vec3 purkinje_effect(vec3 Color) {
    vec3 ColorXYZ = rgb_to_xyz(Color);
    float ScotopicLuminance = ColorXYZ.y * (1.33 * (1.0 + (ColorXYZ.y + ColorXYZ.z) / max(ColorXYZ.x, 0.01)) - 1.68);
    vec3 NightColor = ScotopicLuminance * PurkinjeTint;

    float BlendFactor = 1 - smoothstep(0.0, 0.05, get_luminance(Color));
    vec3 FinalColor = Color * mix(vec3(1), NightColor, BlendFactor * PURKINJE_EFFECT_STRENGTH);
    return FinalColor;
}

vec3 film_grain(vec3 Color, vec2 Pos) {
    float framemod60 = floor(frameTimeCounter * 60); // Grain becomes less apparent at high fps without this
    Pos.x += fract(framemod60 / 4.14159) * 445;
    Pos.y -= fract(framemod60 / 5.49382) * 567;
    vec3 GrainColor = (texture2D(noisetex, Pos.xy / 512).rgb - 0.5) * FILM_GRAIN_STRENGTH * 0.1;
    float BlendFactor = 1 - smoothstep(0.0, 0.3, get_luminance(Color));
    return Color + GrainColor * BlendFactor;
}