// ====================================================================
// ToneMapping_Extended.glsl - РАСШИРЕННАЯ КОЛЛЕКЦИЯ ТОНМАППИНГ ОПЕРАТОРОВ
// ====================================================================

// === Конфигурация для всех операторов ===
const float SHOULDER_STRENGTH = 0.22;
const float WHITE_POINT       = 4.0;
const float EXPOSURE          = 1.0;
const float GAMMA             = 2.2;

const float oneMinusShoulder = 1.0 - SHOULDER_STRENGTH;
const float shoulderFactor = oneMinusShoulder * 3.0;
const float shoulderWhitePointFactor = oneMinusShoulder / (WHITE_POINT * WHITE_POINT);

// === Вспомогательные функции ===
#ifndef GetLuminance
float GetLuminance(in vec3 col) {
    return dot(col, vec3(0.2126, 0.7152, 0.0722));
}
#endif

vec3 saturate(in vec3 x) { return clamp(x, 0.0, 1.0); }
vec3 max0(in vec3 x) { return max(x, vec3(0.0)); }
float oneMinus(float x) { return 1.0 - x; }
float sumOf(in vec3 v) { return v.r + v.g + v.b; }
float curve(float x) { return x * x * (3.0 - 2.0 * x); }
vec3 curve(vec3 x) { return x * x * (3.0 - 2.0 * x); }

// === Матрицы перекрытия конусов ===
const float overlap = 0.2;
const float rgOverlap = 0.1 * overlap;
const float rbOverlap = 0.01 * overlap;
const float gbOverlap = 0.04 * overlap;

const mat3 coneOverlap = mat3(
    1.0,        rgOverlap, rbOverlap,
    rgOverlap,  1.0,       gbOverlap,
    rbOverlap,  rgOverlap, 1.0
);

const mat3 coneOverlapInverse = mat3(
    1.0 + rgOverlap + rbOverlap, -rgOverlap,                  -rbOverlap,
    -rgOverlap,                  1.0 + rgOverlap + gbOverlap, -gbOverlap,
    -rbOverlap,                  -rgOverlap,                  1.0 + rbOverlap + rgOverlap
);

// ====================================================================
// ОРИГИНАЛЬНЫЕ ОПЕРАТОРЫ (НЕ ТРОГАЕМ)
// ====================================================================

// 1. SEUS
vec3 SEUSTonemap(in vec3 color) {
    color *= 1.1;
    color *= coneOverlap;

    const float p = 1.5;
    color = pow(color, vec3(p));
    color = color / (1.0 + color);
    color = pow(color, vec3((1.0 / GAMMA) / p));

    color *= coneOverlapInverse;

    {
        const float a = 0.3;
        float l = curve(a);
        vec3 c = color * oneMinus(a) + a;
        color = curve(c);
        color -= l;
        color /= oneMinus(l);
        color = max0(color);
    }

    {
        vec3 c = color;
        color = mix(color, curve(c), vec3(0.2));
    }

    return color;
}

// 2. HABLE (Original)
vec3 HableTonemap(in vec3 x) {
    const float p = 3.0;
    x = x * coneOverlap;
    x *= 1.3;

    const float A = 0.15, B = 0.50, C = 0.10, D = 0.20, E = 0.00, F = 0.30;

    x = pow(x, vec3(p));
    vec3 result = pow((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F), vec3(1.0 / p)) - E/F;
    result = saturate(result);
    result = result * coneOverlapInverse;

    return result;
}

// 3. UCHIMURA
vec3 UchimuraTonemap(in vec3 color) {
    const float maxDisplayBrightness = 1.2;
    const float contrast             = 0.75;
    const float linearStart          = 0.15;
    const float linearLength         = 0.02;
    const float black                = 1.4;
    const float pedestal             = 0.0;

    float l0 = ((maxDisplayBrightness - linearStart) * linearLength) / contrast;
    float L0 = linearStart - linearStart / contrast;
    float L1 = linearStart + oneMinus(linearStart) / contrast;
    float S0 = linearStart + l0;
    float S1 = linearStart + contrast * l0;
    float C2 = (contrast * maxDisplayBrightness) / (maxDisplayBrightness - S1);
    float CP = -C2 / maxDisplayBrightness;

    vec3 w0 = 1.0 - smoothstep(0.0, linearStart, color);
    vec3 w2 = step(linearStart + l0, color);
    vec3 w1 = 1.0 - w0 - w2;

    vec3 T = linearStart * pow(color / vec3(linearStart), vec3(black)) + vec3(pedestal);
    vec3 S = maxDisplayBrightness - (maxDisplayBrightness - S1) * exp(CP * (color - S0));
    vec3 L = linearStart + contrast * (color - linearStart);

    color *= coneOverlap;
    color = T * w0 + L * w1 + S * w2;
    color *= coneOverlapInverse;

    return color;
}

// 4. ACES Fit
vec3 RRTAndODTFit(in vec3 v) {
    vec3 a = v * (v + 0.0245786) - 0.000090537;
    vec3 b = v * (0.4329510 * v + 0.238081);
    return a / b;
}

vec3 ACESTonemap2(in vec3 color) {
    color *= coneOverlap;
    color = RRTAndODTFit(color);
    color *= coneOverlapInverse;
    return saturate(color);
}

// 5. LOTTES
vec3 LottesTonemap(in vec3 color) {
    color *= 5.0;
    float peak = GetLuminance(color);
    vec3 ratio = color / peak;

    const float contrast = 1.0;
    const float shoulder = 1.0;
    const float b = 1.0;
    const float c = 3.0;

    peak = pow(peak, 1.6);
    float x = peak;
    float z = pow(x, contrast);
    peak = z / (pow(z, shoulder) * b + c);
    peak = pow(peak, 1.0 / 1.6);

    vec3 tonemapped = peak * ratio;
    float tonemappedMaximum = GetLuminance(tonemapped);

    vec3 crosstalk = vec3(5.0, 0.5, 5.0) * 2.0;
    float saturation = 0.9;
    float crossSaturation = 1280.0;

    ratio = pow(ratio, vec3(saturation / crossSaturation));
    ratio = mix(ratio, vec3(1.0), pow(vec3(tonemappedMaximum), crosstalk));
    ratio = pow(ratio, vec3(crossSaturation));

    return peak * ratio;
}

// 6. ACES
vec3 ACESTonemap(in vec3 color) {
    color *= 0.4;
    vec3 crosstalk = vec3(0.05, 0.2, 0.05) * 2.9;
    float avgColor = GetLuminance(color);
    const float p = 1.0;
    color = pow(color, vec3(p));
    color = (color * (2.51 * color + 0.03)) / (color * (2.43 * color + 0.59) + 0.14);
    color = pow(color, vec3(1.0 / p));
    color = saturate(color);
    color = pow(color, vec3(0.85));
    return color;
}

// 7. Modified Reinhard Extended
vec3 ModifiedReinhardExtended(in vec3 color) {
    color *= EXPOSURE;  
    color *= coneOverlap;

    float sumCol = sumOf(color);
    vec3 tonemapped = color * ((3.0 + sumCol * shoulderWhitePointFactor) / (shoulderFactor + sumCol));

    tonemapped *= coneOverlapInverse;
    return saturate(tonemapped);
}

// 8. Modified Reinhard Jodie Extended
vec3 ModifiedReinhardJodieExtended(in vec3 color) {
    color *= EXPOSURE;
    color *= coneOverlap;

    float sumCol = sumOf(color);

    vec3 reinhardColorFactor = color * ((1.0 + color * shoulderWhitePointFactor) / (oneMinusShoulder + color));
    vec3 reinhardLumaFactor  = color * ((3.0 + sumCol * shoulderWhitePointFactor) / (shoulderFactor + sumCol));

    vec3 result = (reinhardColorFactor - reinhardLumaFactor) * reinhardColorFactor + reinhardLumaFactor;

    result *= coneOverlapInverse;
    return saturate(result);
}

// 9. None
vec3 None(in vec3 color) {
    return color;
}

// ====================================================================
// НОВЫЕ ТОНМАППИНГ ОПЕРАТОРЫ
// ====================================================================

// 10. REINHARD SIMPLE - Базовый оператор Reinhard
vec3 ReinhardSimple(in vec3 color) {
    color *= EXPOSURE * 1.2;
    
    // Простая формула Reinhard: color / (1 + color)
    vec3 result = color / (1.0 + color);
    
    return saturate(result);
}

// 11. EXTENDED REINHARD - Улучшенный Reinhard с настраиваемой белой точкой
vec3 ExtendedReinhard(in vec3 color) {
    color *= EXPOSURE * 1.15;
    
    float luminance = GetLuminance(color);
    
    // Extended Reinhard formula
    float whitePoint = 2.5;
    float numerator = luminance * (1.0 + (luminance / (whitePoint * whitePoint)));
    float denominator = 1.0 + luminance;
    
    vec3 result = color * (numerator / denominator);
    
    return saturate(result);
}

// 12. FILMIC - Классический кинематографический тонмаппинг
vec3 FilmicTonemap(in vec3 color) {
    color *= EXPOSURE * 1.5;
    color *= coneOverlap;
    
    // Параметры кривой
    const float A = 0.22;  // Shoulder Strength
    const float B = 0.30;  // Linear Strength
    const float C = 0.10;  // Linear Angle
    const float D = 0.20;  // Toe Strength
    const float E = 0.01;  // Toe Numerator
    const float F = 0.30;  // Toe Denominator
    
    vec3 result = ((color * (A * color + C * B) + D * E) / 
                   (color * (A * color + B) + D * F)) - E / F;
    
    result *= coneOverlapInverse;
    return saturate(result);
}

// 13. HABLE FILMIC (UNCHARTED 2) - Полная версия с нормализацией
vec3 HableFilmic(in vec3 color) {
    color *= EXPOSURE * 2.0;
    
    // Параметры из Uncharted 2
    const float A = 0.15;  // Shoulder Strength
    const float B = 0.50;  // Linear Strength
    const float C = 0.10;  // Linear Angle
    const float D = 0.20;  // Toe Strength
    const float E = 0.02;  // Toe Numerator
    const float F = 0.30;  // Toe Denominator
    
    // Функция тонмаппинга
    vec3 x = color;
    vec3 curr = ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
    
    // Нормализация по белой точке
    float W = 11.2;
    vec3 whiteScale = 1.0 / (((vec3(W) * (A * W + C * B) + D * E) / 
                              (vec3(W) * (A * W + B) + D * F)) - E / F);
    
    return saturate(curr * whiteScale);
}

// 14. HEJL-DAWSON - Быстрый аппроксимированный тонмаппинг
vec3 HejlDawson(in vec3 color) {
    color *= EXPOSURE * 1.3;
    
    // Простая и быстрая аппроксимация
    vec3 x = max(vec3(0.0), color - 0.004);
    vec3 result = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
    
    return result;
}

// 15. JODIE REINHARD - Улучшенный Reinhard с лучшим сохранением цветов
vec3 JodieReinhard(in vec3 color) {
    color *= EXPOSURE * 1.1;
    
    float luminance = GetLuminance(color);
    
    // Jodie's improved formula
    vec3 tc = color / (1.0 + color);
    float tl = luminance / (1.0 + luminance);
    
    return mix(color / (1.0 + luminance), tc, tc);
}

// ====================================================================
// КАСТОМНЫЙ ТОНМАППИНГ - BLUE SHADOW (СИНЕВАТЫЕ ТЕНИ)
// ====================================================================

// 16. BLUE SHADOW CUSTOM - Добавляет синеватый оттенок в темные области
vec3 BlueShadowCustom(in vec3 color) {
    color *= EXPOSURE * 1.15;
    
    // Определяем яркость для маски теней
    float luminance = GetLuminance(color);
    
    // Создаем маску для темных областей (тени)
    // Значения близкие к 1 = тени, значения близкие к 0 = света
    float shadowMask = 1.0 - smoothstep(0.0, 0.3, luminance);
    shadowMask = pow(shadowMask, 2.2); // Делаем переход более плавным
    
    // Синий оттенок для теней (холодный тон)
    vec3 blueTint = vec3(0.4, 0.5, 0.9);  // RGB оттенок синего
    float tintStrength = 0.35;  // Интенсивность подкраски (0.0 - 1.0)
    
    // Применяем синий оттенок только к темным областям
    vec3 colorWithBlueShadows = mix(color, color * blueTint, shadowMask * tintStrength);
    
    // Применяем стандартный тонмаппинг поверх
    vec3 result = colorWithBlueShadows / (1.0 + colorWithBlueShadows);
    
    // Дополнительное усиление синего в самых темных участках
    float deepShadowMask = pow(shadowMask, 3.0);
    result = mix(result, result * vec3(0.5, 0.6, 1.2), deepShadowMask * 0.2);
    
    return saturate(result);
}

// ====================================================================
// ДОПОЛНИТЕЛЬНЫЕ ВАРИАНТЫ BLUE SHADOW (ОПЦИОНАЛЬНО)
// ====================================================================

// Вариант 2: Более интенсивная синева
vec3 BlueShadowIntense(in vec3 color) {
    color *= EXPOSURE * 1.15;
    
    float luminance = GetLuminance(color);
    float shadowMask = 1.0 - smoothstep(0.0, 0.35, luminance);
    shadowMask = pow(shadowMask, 1.8);
    
    vec3 blueTint = vec3(0.3, 0.45, 1.1);  // Более насыщенный синий
    float tintStrength = 0.5;  // Сильнее эффект
    
    vec3 colorWithBlueShadows = mix(color, color * blueTint, shadowMask * tintStrength);
    vec3 result = colorWithBlueShadows / (1.0 + colorWithBlueShadows);
    
    float deepShadowMask = pow(shadowMask, 2.5);
    result = mix(result, result * vec3(0.4, 0.55, 1.3), deepShadowMask * 0.3);
    
    return saturate(result);
}

// Вариант 3: Тонкий намек синего (субтильный эффект)
vec3 BlueShadowSubtle(in vec3 color) {
    color *= EXPOSURE * 1.15;
    
    float luminance = GetLuminance(color);
    float shadowMask = 1.0 - smoothstep(0.0, 0.25, luminance);
    shadowMask = pow(shadowMask, 2.8);
    
    vec3 blueTint = vec3(0.55, 0.65, 0.95);  // Мягкий синий
    float tintStrength = 0.2;  // Слабый эффект
    
    vec3 colorWithBlueShadows = mix(color, color * blueTint, shadowMask * tintStrength);
    vec3 result = colorWithBlueShadows / (1.0 + colorWithBlueShadows);
    
    return saturate(result);
}

// ====================================================================
// ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ДЛЯ ИНТЕГРАЦИИ
// ====================================================================

// Универсальная функция выбора тонмаппинга
// Используй эту функцию в Grade.glsl, добавив соответствующие #define
vec3 ApplyTonemap(in vec3 color, int tonemapType) {
    switch (tonemapType) {
        case 0:  return SEUSTonemap(color);
        case 1:  return HableTonemap(color);
        case 2:  return UchimuraTonemap(color);
        case 3:  return ACESTonemap2(color);
        case 4:  return LottesTonemap(color);
        case 5:  return ACESTonemap(color);
        case 6:  return ModifiedReinhardExtended(color);
        case 7:  return ModifiedReinhardJodieExtended(color);
        case 8:  return None(color);
        
        // НОВЫЕ ОПЕРАТОРЫ
        case 9:  return ReinhardSimple(color);
        case 10: return ExtendedReinhard(color);
        case 11: return FilmicTonemap(color);
        case 12: return HableFilmic(color);
        case 13: return HejlDawson(color);
        case 14: return JodieReinhard(color);
        
        // КАСТОМНЫЕ
        case 15: return BlueShadowCustom(color);
        case 16: return BlueShadowIntense(color);
        case 17: return BlueShadowSubtle(color);
        
        default: return color;
    }
}


