// composite_voxel_propagate.csh (composite11.csh)
// Пропагація світла по воксельній сітці

#version 430 compatibility

/* RENDERTARGETS: 6 */
layout(location = 0) out vec4 voxelEmissionOut;

#include "/lib/Head/Common.inc"

uniform sampler3D colortex6; // Воксельна емісія (поточна)

#define VOXEL_VOLUME_SIZE 128
#define PROPAGATION_ITERATIONS 4 // Кількість ітерацій поширення

in vec2 texcoord;

// Поширення світла у 3D сітці
vec4 PropagateLight(vec3 voxelCoord) {
    vec4 currentData = texture(colortex6, voxelCoord);
    vec3 currentEmission = currentData.rgb;
    float currentDensity = currentData.a;
    
    // Якщо це джерело світла - не змінюємо
    if (length(currentEmission) > 5.0) {
        return currentData;
    }
    
    vec3 propagatedLight = vec3(0.0);
    float totalWeight = 0.0;
    
    // 6 основних напрямків + 12 діагональних
    const vec3 directions[18] = vec3[18](
        // Основні 6
        vec3( 1.0,  0.0,  0.0),
        vec3(-1.0,  0.0,  0.0),
        vec3( 0.0,  1.0,  0.0),
        vec3( 0.0, -1.0,  0.0),
        vec3( 0.0,  0.0,  1.0),
        vec3( 0.0,  0.0, -1.0),
        // Діагональні на площинах
        vec3( 1.0,  1.0,  0.0),
        vec3( 1.0, -1.0,  0.0),
        vec3(-1.0,  1.0,  0.0),
        vec3(-1.0, -1.0,  0.0),
        vec3( 1.0,  0.0,  1.0),
        vec3( 1.0,  0.0, -1.0),
        vec3(-1.0,  0.0,  1.0),
        vec3(-1.0,  0.0, -1.0),
        vec3( 0.0,  1.0,  1.0),
        vec3( 0.0,  1.0, -1.0),
        vec3( 0.0, -1.0,  1.0),
        vec3( 0.0, -1.0, -1.0)
    );
    
    const float weights[18] = float[18](
        1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
        0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7
    );
    
    float stepSize = 1.0 / VOXEL_VOLUME_SIZE;
    
    for (int i = 0; i < 18; i++) {
        vec3 dir = normalize(directions[i]);
        vec3 sampleCoord = voxelCoord + dir * stepSize;
        
        // Перевірка меж
        if (all(greaterThan(sampleCoord, vec3(0.001))) && 
            all(lessThan(sampleCoord, vec3(0.999)))) {
            
            vec4 neighborData = texture(colortex6, sampleCoord);
            vec3 neighborLight = neighborData.rgb;
            float neighborDensity = neighborData.a;
            
            // Затухання через щільність та відстань
            float distance = length(directions[i]);
            float transmission = exp(-neighborDensity * 1.5);
            float distanceFalloff = 1.0 / (1.0 + distance * distance);
            
            float weight = transmission * distanceFalloff * weights[i];
            
            propagatedLight += neighborLight * weight;
            totalWeight += weight;
        }
    }
    
    // Затухання світла з часом
    const float lightDecay = 0.92;
    
    if (totalWeight > 0.001) {
        propagatedLight = (propagatedLight / totalWeight) * lightDecay;
    } else {
        propagatedLight = currentEmission * lightDecay;
    }
    
    // Змішування для плавності
    vec3 finalEmission = mix(currentEmission, propagatedLight, 0.5);
    
    return vec4(finalEmission, currentDensity);
}

void main() {
    // Розгортаємо 2D координату у 3D воксельну координату
    ivec2 screenPos = ivec2(gl_FragCoord.xy);
    int voxelIndex = screenPos.y * int(viewWidth) + screenPos.x;
    
    if (voxelIndex >= VOXEL_VOLUME_SIZE * VOXEL_VOLUME_SIZE * VOXEL_VOLUME_SIZE) {
        voxelEmissionOut = vec4(0.0);
        return;
    }
    
    // Розпаковуємо у 3D
    int z = voxelIndex / (VOXEL_VOLUME_SIZE * VOXEL_VOLUME_SIZE);
    int remainder = voxelIndex % (VOXEL_VOLUME_SIZE * VOXEL_VOLUME_SIZE);
    int y = remainder / VOXEL_VOLUME_SIZE;
    int x = remainder % VOXEL_VOLUME_SIZE;
    
    vec3 voxelCoord = (vec3(x, y, z) + 0.5) / VOXEL_VOLUME_SIZE;
    
    // Виконуємо пропагацію
    voxelEmissionOut = PropagateLight(voxelCoord);
}