// composite6.csh
// Розмісти: shaders/composite/composite6.csh
// Також створи копії: composite7.csh, composite8.csh, composite9.csh з ОДНАКОВИМ кодом
// Пропагація світла по воксельній сітці

#version 430 compatibility

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

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

uniform float viewWidth;
uniform float viewHeight;
uniform int frameCounter;

// ========================
// НАЛАШТУВАННЯ
// ========================
#ifndef VOXEL_VOLUME_SIZE
    #define VOXEL_VOLUME_SIZE 128
#endif

// ========================
// ДОПОМІЖНІ ФУНКЦІЇ
// ========================
#define saturate(x) clamp(x, 0.0, 1.0)

// ========================
// ОСНОВНИЙ КОД
// ========================

in vec2 texcoord;

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;
    
    // 26-напрямний семплінг
    const vec3 directions[26] = vec3[26](
        // Основні 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),
        // 12 діагональних
        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),
        // 8 кутових
        vec3( 1.0,  1.0,  1.0), vec3( 1.0,  1.0, -1.0),
        vec3( 1.0, -1.0,  1.0), vec3( 1.0, -1.0, -1.0),
        vec3(-1.0,  1.0,  1.0), vec3(-1.0,  1.0, -1.0),
        vec3(-1.0, -1.0,  1.0), vec3(-1.0, -1.0, -1.0)
    );
    
    const float weights[26] = float[26](
        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,
        0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5
    );
    
    float stepSize = 1.0 / VOXEL_VOLUME_SIZE;
    
    for (int i = 0; i < 26; 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 transmission = exp(-neighborDensity * 1.2);
            float distance = length(directions[i]);
            float distanceFalloff = 1.0 / (1.0 + distance * distance * 0.5);
            
            float weight = transmission * distanceFalloff * weights[i];
            
            propagatedLight += neighborLight * weight;
            totalWeight += weight;
        }
    }
    
    const float lightDecay = 0.94;
    
    if (totalWeight > 0.001) {
        propagatedLight = (propagatedLight / totalWeight) * lightDecay;
    } else {
        propagatedLight = currentEmission * lightDecay;
    }
    
    float mixFactor = 0.5;
    vec3 finalEmission = mix(currentEmission, propagatedLight, mixFactor);
    
    return vec4(finalEmission, currentDensity);
}

void main() {
    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);
}