// ============================================================================
// POST-PROCESSING AND TONEMAPPING
// ============================================================================
#ifndef TONEMAP_GLSL
#define TONEMAP_GLSL

#include "/lib/settings.glsl"
#include "/lib/renodx.glsl"

const vec3 luminance_weights = vec3(0.2126, 0.7152, 0.0722);

// ACES Tonemapping.
vec3 tonemapACES(vec3 rgb) {
    float a = 2.51;
    float b = 0.03;
    float c = 2.43; float d = 0.59; float e = 0.14;
    return clamp((rgb * (a * rgb + b)) / (rgb * (c * rgb + d) + e), 0.0, 1.0);
}

// Reinhard-Jodie Tonemapping.
vec3 tonemapReinhardJodie(vec3 rgb) {
    vec3 reinhard = rgb / (rgb + 1.0);
    return mix(rgb / (dot(rgb, luminance_weights) + 1.0), reinhard, reinhard); 
}

// Main Color Pipeline.
vec3 applyTonemap(vec3 color) {
    // Convert to linear color space.
    color = pow(color, vec3(2.2));

    // Apply user exposure.
    color *= float(EXPOSURE);
	
	// Apply selected tonemapping operator.
    #if HDR_ENABLED == 1
        color = ToneMapPass(color, vec3(0), vec2(0));
    #else
        #if TONEMAP_OPERATOR == 1
            color = tonemapACES(color);
        #elif TONEMAP_OPERATOR == 2
            color = tonemapReinhardJodie(color);
        #endif
    #endif
	
    // Calculate base luminance for adjustments.
    float luma = dot(color, luminance_weights);
	
    // Desaturate dark areas to mimic stylized flat shading in shadows.
    float dark_mask = 1.0 - smoothstep(0.0, 0.2, luma);
    color = mix(color, vec3(luma), dark_mask * float(DARKNESS_DESATURATION));
	
    // Apply saturation and vibrance adjustments.
    color = mix(vec3(luma), color, float(SATURATION));
	
	// Apply vibrance adjustment without breaking saturation.
    float max_color = max(color.r, max(color.g, color.b));
    float min_color = min(color.r, min(color.g, color.b));
    float current_saturation = max_color - min_color;
    float vibrance_amount = float(VIBRANCE) - 1.0;
    color = mix(vec3(luma), color, 1.0 + (vibrance_amount * (1.0 - current_saturation)));
    color = max(color, vec3(0.0));
	
	// Prevent negative colors.
    color = max(color, vec3(0.0));
	
    // Apply ambient color tint filter.
    #if TINT_INTENSITY > 0.0
        vec3 tintColor = vec3(TINT_R, TINT_G, TINT_B);
        color = mix(color, color * tintColor, float(TINT_INTENSITY));
    #endif

    #if HDR_ENABLED == 1
        color = RenderIntermediatePass(color);
    #endif

    // Apply gamma correction for screen space.
    #if HDR_ENABLED == 0
        color = pow(color, vec3(1.0 / (2.2 * float(GAMMA))));
    #endif
    
    return color;
}

#endif