#version 330 core
out vec4 FragColor;
in vec2 TexCoord;

uniform sampler2D InputTexture;
uniform float exposureValue; // Expecting value in stops, e.g., -5.0 to 5.0

// Calculate perceptual luminance
float luminance(vec3 color) {
    return dot(color, vec3(0.2126, 0.7152, 0.0722));
}

// Apply exposure by adjusting luminance while preserving color relationships
vec3 applyExposure(vec3 color, float exposureStops) {
    // Get original luminance
    float lum = luminance(color);
    
    // Skip processing for very dark pixels to avoid division by zero
    if (lum < 0.0001) return color;
    
    // Calculate exposure factor
    float exposureFactor = pow(2.0, exposureStops);
    
    // Apply highlight compression when increasing exposure
    float newLum = lum * exposureFactor;
    if (exposureStops > 0.0 && newLum > 0.8) {
        // Soft highlight roll-off to prevent harsh clipping
        float excess = newLum - 0.8;
        newLum = 0.8 + 0.2 * (1.0 - exp(-excess * 5.0));
    }
    
    // Scale RGB proportionally to maintain color relationships
    return color * (newLum / lum);
}

void main() {
    vec4 color = texture(InputTexture, TexCoord);
    
    // Apply exposure adjustment
    color.rgb = applyExposure(color.rgb, exposureValue);
    
    // Ensure output is in valid range
    FragColor = vec4(clamp(color.rgb, vec3(0.0), vec3(1.0)), color.a);
}