#version 330 core
/*
 * Advanced Texture Control Shader
 * -------------------------------
 * This shader emulates Adobe Lightroom/Photoshop's Texture slider by:
 * 
 * 1. Using frequency separation techniques to isolate medium-frequency details
 * 2. Employing multi-scale edge detection for more natural enhancement
 * 3. Adding tone-aware processing to protect highlights and shadows
 * 4. Implementing perceptual weighting to preserve color relationships
 * 5. Using non-linear response curves similar to Lightroom's implementation
 * 
 * Negative values: Smooth medium-frequency texture details (skin smoothing)
 * Positive values: Enhance medium-frequency texture details (fabric, hair, etc.)
 * 
 * Unlike Clarity (which affects larger contrast structures) or Sharpening (which 
 * affects fine details), Texture specifically targets medium-frequency details
 * that represent surface textures while avoiding edges.
 */

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

// Improved blur function with Gaussian weights for better quality
vec3 gaussianBlur(sampler2D tex, vec2 uv, vec2 texelSize, float radius) {
    vec3 blurred = vec3(0.0);
    float weightSum = 0.0;
    float sigma = radius / 2.0;
    float sigma2 = 2.0 * sigma * sigma;
    int kernelSize = int(ceil(radius * 2.0));
    
    for (int x = -kernelSize; x <= kernelSize; ++x) {
        for (int y = -kernelSize; y <= kernelSize; ++y) {
            float dist2 = float(x*x + y*y);
            float weight = exp(-dist2 / sigma2);
            vec3 sample = texture(tex, uv + vec2(x, y) * texelSize).rgb;
            blurred += sample * weight;
            weightSum += weight;
        }
    }
    
    return blurred / max(weightSum, 0.0001);
}

// Edge-aware weight function to prevent halos
float edgeWeight(float lumaDiff, float threshold) {
    return 1.0 - smoothstep(0.0, threshold, abs(lumaDiff));
}

// Sigmoid function for smoother transitions
float sigmoid(float x, float strength) {
    return x * (1.0 + strength) / (1.0 + strength * abs(x));
}

out vec4 FragColor;
in vec2 TexCoord;

uniform sampler2D InputTexture;
uniform float textureValue; // -100 (smooth) to 100 (enhance)

vec3 applyTexture(vec3 originalColor, vec2 uv, float textureAdj) {
    if (abs(textureAdj) < 0.01) return originalColor;

    vec2 texelSize = 1.0 / textureSize(InputTexture, 0);
    float origLuma = luminance(originalColor);
    
    // Multi-scale approach for medium frequency targeting
    // For texture, we want medium frequencies (not too small, not too large)
    float smallRadius = 2.0;   // For high frequency details
    float mediumRadius = 4.0;  // For medium frequency details (texture)
    float largeRadius = 8.0;   // For low frequency details
    
    vec3 smallBlur = gaussianBlur(InputTexture, uv, texelSize, smallRadius);
    vec3 mediumBlur = gaussianBlur(InputTexture, uv, texelSize, mediumRadius);
    vec3 largeBlur = gaussianBlur(InputTexture, uv, texelSize, largeRadius);
    
    // Extract medium frequencies (texture details)
    vec3 highFreq = smallBlur - mediumBlur;
    vec3 mediumFreq = mediumBlur - largeBlur;
    
    // Calculate local contrast for edge-aware processing
    float smallLuma = luminance(smallBlur);
    float mediumLuma = luminance(mediumBlur);
    float largeLuma = luminance(largeBlur);
    
    // Edge detection weights
    float edgeMask = edgeWeight(smallLuma - mediumLuma, 0.1);
    
    // Highlight & shadow protection
    float highlightProtect = 1.0 - smoothstep(0.75, 0.95, origLuma);
    float shadowProtect = smoothstep(0.05, 0.25, origLuma);
    float tonalWeight = highlightProtect * shadowProtect;
    
    // Map texture value to a perceptually balanced strength
    // Use non-linear mapping to match Lightroom's response curve
    float strength = sign(textureAdj) * pow(abs(textureAdj / 100.0), 0.8);
    
    // Apply different processing for positive vs negative values
    vec3 result = originalColor;
    if (strength > 0.0) {
        // Enhance texture (positive values)
        float enhanceFactor = strength * 1.5 * tonalWeight * edgeMask;
        result = originalColor + mediumFreq * enhanceFactor;
    } else {
        // Smooth texture (negative values)
        float smoothFactor = -strength * tonalWeight;
        result = mix(originalColor, mediumBlur, smoothFactor);
    }
    
    // Apply sigmoid function for more natural transitions
    result = mix(originalColor, result, sigmoid(abs(strength), 0.5));
    
    return result;
}

void main() {
    vec4 color = texture(InputTexture, TexCoord);
    color.rgb = applyTexture(color.rgb, TexCoord, textureValue);
    FragColor = vec4(max(color.rgb, vec3(0.0)), color.a);
}