//============================================================================//
// 🌟 COLORED GLOW RAYTRACING для VXGI System
// Объёмное цветное свечение с использованием voxel grid
//============================================================================//

#ifndef COLORED_GLOW_TRACING_GLSL
#define COLORED_GLOW_TRACING_GLSL

//============================================================================//
// НАСТРОЙКИ
//============================================================================//

#define GLOW_TRACING_ENABLED 1       // [0 1] Включить эффект
#define GLOW_TRACE_STEPS 24          // [8 16 24 32] Ray marching шаги
#define GLOW_TRACE_RADIUS 12.0       // [6.0 8.0 12.0 16.0] Радиус в блоках
#define GLOW_INTENSITY 3.0           // [1.0 2.0 3.0 4.0 6.0] Яркость
#define GLOW_BLOOM_SIZE 4.0          // [2.0 3.0 4.0 6.0] Размер bloom
#define GLOW_NOISE_AMOUNT 0.2        // [0.0 0.1 0.2 0.3] Grain overlay

//============================================================================//
// BLOCK COLOR DATABASE
//============================================================================//

vec3 GetBlockEmissionColor(vec3 blockColor) {
    float brightness = maxOf(blockColor);
    
    // Copper Lanterns (медный оттенок)
    if (length(blockColor - vec3(1.0, 0.7, 0.4)) < 0.15) {
        return vec3(1.0, 0.75, 0.45) * 1.5;
    }
    // Weathered Copper (зеленоватый)
    if (length(blockColor - vec3(0.6, 0.7, 0.5)) < 0.15) {
        return vec3(0.6, 0.85, 0.6) * 1.3;
    }
    // Oxidized Copper (бирюзовый)
    if (length(blockColor - vec3(0.3, 0.6, 0.5)) < 0.15) {
        return vec3(0.4, 0.8, 0.7) * 1.4;
    }
    
    // Colored Concrete
    if (length(blockColor - vec3(0.95, 0.85, 0.3)) < 0.15) { // Yellow
        return vec3(1.0, 0.95, 0.4) * 1.8;
    }
    if (length(blockColor - vec3(0.9, 0.2, 0.2)) < 0.15) { // Red
        return vec3(1.0, 0.2, 0.15) * 1.6;
    }
    if (length(blockColor - vec3(0.7, 0.2, 0.9)) < 0.15) { // Purple
        return vec3(0.85, 0.3, 1.0) * 1.5;
    }
    if (length(blockColor - vec3(0.2, 0.3, 0.85)) < 0.15) { // Blue
        return vec3(0.3, 0.4, 1.0) * 1.5;
    }
    if (length(blockColor - vec3(0.1, 0.7, 0.85)) < 0.15) { // Cyan
        return vec3(0.2, 0.9, 1.0) * 1.4;
    }
    if (length(blockColor - vec3(1.0, 0.4, 0.8)) < 0.15) { // Pink
        return vec3(1.0, 0.5, 0.9) * 1.6;
    }
    
    // Standard glowing blocks
    if (length(blockColor - vec3(1.0, 0.9, 0.6)) < 0.15) { // Glowstone
        return vec3(1.0, 0.95, 0.7) * 1.5;
    }
    if (length(blockColor - vec3(0.8, 1.0, 0.9)) < 0.15) { // Sea Lantern
        return vec3(0.7, 1.0, 0.95) * 1.4;
    }
    if (length(blockColor - vec3(1.0, 0.0, 0.0)) < 0.15) { // Redstone
        return vec3(1.0, 0.1, 0.0) * 1.8;
    }
    if (length(blockColor - vec3(0.3, 0.8, 1.0)) < 0.15) { // Soul
        return vec3(0.3, 0.7, 1.0) * 1.6;
    }
    if (length(blockColor - vec3(1.0, 0.8, 0.4)) < 0.15) { // Torch
        return vec3(1.0, 0.85, 0.5) * 1.3;
    }
    
    // Fallback: если блок яркий, усиливаем
    if (brightness > 0.7) {
        return blockColor * 1.5;
    } else if (brightness > 0.5) {
        return blockColor * 1.2;
    }
    
    return vec3(0.0);
}

bool IsEmissiveBlock(vec3 blockColor) {
    float brightness = maxOf(blockColor);
    float saturation = brightness - minOf(blockColor);
    
    // Светящиеся блоки обычно яркие и насыщенные
    return brightness > 0.5 && (saturation > 0.2 || brightness > 0.75);
}

//============================================================================//
// VOLUMETRIC NOISE
//============================================================================//

// Hash для 3D noise
float Hash13(vec3 p3) {
    p3 = fract(p3 * 0.1031);
    p3 += dot(p3, p3.zyx + 31.32);
    return fract((p3.x + p3.y) * p3.z);
}

// Multi-octave noise
float VolumetricNoise(vec3 pos, int frame) {
    vec3 p = pos * 0.4 + vec3(float(frame) * 0.01);
    
    float n = 0.0;
    float amplitude = 1.0;
    float frequency = 1.0;
    
    for (int i = 0; i < 3; i++) {
        vec3 ip = floor(p * frequency);
        vec3 fp = fract(p * frequency);
        fp = fp * fp * (3.0 - 2.0 * fp);
        
        float n000 = Hash13(ip);
        float n100 = Hash13(ip + vec3(1, 0, 0));
        float n010 = Hash13(ip + vec3(0, 1, 0));
        float n110 = Hash13(ip + vec3(1, 1, 0));
        float n001 = Hash13(ip + vec3(0, 0, 1));
        float n101 = Hash13(ip + vec3(1, 0, 1));
        float n011 = Hash13(ip + vec3(0, 1, 1));
        float n111 = Hash13(ip + vec3(1, 1, 1));
        
        float nx00 = mix(n000, n100, fp.x);
        float nx10 = mix(n010, n110, fp.x);
        float nx01 = mix(n001, n101, fp.x);
        float nx11 = mix(n011, n111, fp.x);
        
        float nxy0 = mix(nx00, nx10, fp.y);
        float nxy1 = mix(nx01, nx11, fp.y);
        
        n += mix(nxy0, nxy1, fp.z) * amplitude;
        
        frequency *= 2.0;
        amplitude *= 0.5;
    }
    
    return n;
}

//============================================================================//
// MAIN VOLUMETRIC GLOW TRACING
//============================================================================//

vec3 TraceColoredGlow(
    vec3 worldPos,
    vec3 viewDir,
    vec3 worldNormal,
    vec2 screenCoord,
    int frameCounter,
    sampler3D voxelAlbedoTex
) {
    #if GLOW_TRACING_ENABLED == 0
        return vec3(0.0);
    #endif
    
    vec3 glowAccum = vec3(0.0);
    float weightSum = 0.0;
    
    // Omnidirectional sampling (8 направлений)
    const vec3 directions[8] = vec3[8](
        vec3(1, 0, 0), vec3(-1, 0, 0),
        vec3(0, 1, 0), vec3(0, -1, 0),
        vec3(0, 0, 1), vec3(0, 0, -1),
        normalize(vec3(1, 1, 0)),
        normalize(vec3(1, 0, 1))
    );
    
    // Temporal dithering
    float dither = InterleavedGradientNoise(screenCoord * vec2(viewWidth, viewHeight));
    dither = fract(dither + float(frameCounter) * 0.618);
    
    float stepSize = GLOW_TRACE_RADIUS / float(GLOW_TRACE_STEPS);
    
    //========================================================================//
    // RAY MARCHING В РАЗНЫХ НАПРАВЛЕНИЯХ
    //========================================================================//
    
    for (int dir = 0; dir < 8; dir++) {
        vec3 rayDir = directions[dir];
        
        // Skip rays pointing away from surface
        float rayDotNormal = dot(rayDir, worldNormal);
        if (rayDotNormal < -0.1) continue;
        
        // Bias ray towards normal for better coverage
        float normalBias = max(0.0, rayDotNormal) * 0.5;
        
        for (int step = 0; step < GLOW_TRACE_STEPS; step++) {
            // Dithered step position
            float t = (float(step) + dither) * stepSize;
            vec3 samplePos = worldPos + rayDir * t;
            
            // Sample voxel
            ivec3 voxel = WorldToVoxel(samplePos);
            if (!IsVoxelInBounds(voxel)) continue;
            
            vec3 texCoord = VoxelToTexCoord(voxel);
            vec4 voxelData = texture(voxelAlbedoTex, texCoord);
            
            // Skip empty voxels
            if (voxelData.a < 0.1) continue;
            
            vec3 blockColor = voxelData.rgb;
            
            // Check if emissive
            if (!IsEmissiveBlock(blockColor)) continue;
            
            // Get emission color
            vec3 emissionColor = GetBlockEmissionColor(blockColor);
            if (length(emissionColor) < 0.01) {
                emissionColor = blockColor * 1.5;
            }
            
            //================================================================//
            // VOLUMETRIC SCATTERING CALCULATION
            //================================================================//
            
            float distance = t;
            
            // Volumetric noise (creates light rays effect)
            float volumeNoise = VolumetricNoise(samplePos, frameCounter);
            float noiseMod = mix(0.4, 1.0, volumeNoise);
            
            // Distance falloff (exponential)
            float falloff = exp(-distance / GLOW_BLOOM_SIZE);
            falloff *= noiseMod;
            
            // Directional weight (stronger when facing surface)
            vec3 toGlow = normalize(samplePos - worldPos);
            float dirWeight = max(0.2, dot(worldNormal, toGlow) * 0.5 + 0.5);
            dirWeight *= (0.5 + normalBias);
            
            // Density (как в volumetric fog)
            float density = falloff * dirWeight * voxelData.a * 0.4;
            
            // Accumulate
            glowAccum += emissionColor * density;
            weightSum += density;
            
            // Early exit при насыщении
            if (weightSum > 4.0) break;
        }
    }
    
    //========================================================================//
    // NORMALIZATION AND POST-PROCESSING
    //========================================================================//
    
    // Normalize by accumulated weight
    if (weightSum > 0.001) {
        glowAccum /= max(weightSum, 0.3);
    }
    
    // Screen-space grain (PTGI signature)
    float grain = InterleavedGradientNoise(screenCoord * vec2(1920, 1080) + float(frameCounter));
    grain = mix(1.0, grain, GLOW_NOISE_AMOUNT);
    glowAccum *= grain;
    
    // Apply intensity
    glowAccum *= GLOW_INTENSITY;
    
    // Soft clamp (preserves color while preventing clipping)
    glowAccum = glowAccum / (1.0 + glowAccum * 0.3);
    
    return max(glowAccum, vec3(0.0));
}

//============================================================================//
// SIMPLIFIED VERSION (for testing)
//============================================================================//

vec3 TraceColoredGlowSimple(
    vec3 worldPos,
    vec3 worldNormal,
    sampler3D voxelAlbedoTex
) {
    vec3 glow = vec3(0.0);
    float radius = 6.0;
    
    // Simple sphere sampling
    for (int i = 0; i < 12; i++) {
        float angle = float(i) / 12.0 * TAU;
        vec3 offset = vec3(cos(angle), 0.5, sin(angle)) * radius;
        
        vec3 samplePos = worldPos + offset;
        ivec3 voxel = WorldToVoxel(samplePos);
        
        if (!IsVoxelInBounds(voxel)) continue;
        
        vec3 texCoord = VoxelToTexCoord(voxel);
        vec4 voxelData = texture(voxelAlbedoTex, texCoord);
        
        if (voxelData.a > 0.1 && IsEmissiveBlock(voxelData.rgb)) {
            vec3 emission = GetBlockEmissionColor(voxelData.rgb);
            float dist = length(offset);
            glow += emission / (1.0 + dist * dist * 0.1);
        }
    }
    
    return glow * 0.5;
}

#endif // COLORED_GLOW_TRACING_GLSL
