// composite_voxel.csh (composite10.csh)
// Побудова та пропагація воксельної сітки освітлення

#version 430 compatibility

/* RENDERTARGETS: 6,7 */
layout(location = 0) out vec4 voxelEmission;    // colortex6: Емісія + щільність
layout(location = 1) out vec4 voxelAlbedoNormal; // colortex7: Альбедо + нормаль

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

uniform sampler2D colortex0; // Основний колор
uniform sampler2D colortex1; // Матеріали
uniform sampler2D colortex2; // Світло
uniform sampler2D colortex3; // Нормалі

uniform sampler3D colortex6; // Попередня воксельна емісія
uniform sampler3D colortex7; // Попередні дані

uniform mat4 gbufferModelView;
uniform mat4 gbufferProjectionInverse;

#define VOXEL_VOLUME_SIZE 128
#define VOXEL_VOLUME_RADIUS (VOXEL_VOLUME_SIZE / 2)
#define VOXEL_SIZE 2.0

// ========================
// ВЛАСНИЙ VOXELIZATION PASS
// ========================

in vec2 texcoord;

void main() {
    // Обчислюємо 3D координату вокселя з 2D координати екрану
    ivec2 screenPos = ivec2(gl_FragCoord.xy);
    
    // Розгортаємо 2D у 3D для воксельної сітки
    // Припускаємо, що рендеримо в квадратну текстуру
    int voxelIndex = screenPos.y * int(viewWidth) + screenPos.x;
    
    if (voxelIndex >= VOXEL_VOLUME_SIZE * VOXEL_VOLUME_SIZE * VOXEL_VOLUME_SIZE) {
        discard;
    }
    
    // Розпаковуємо 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;
    
    // Конвертуємо у світову позицію
    vec3 relativePos = (voxelCoord * VOXEL_VOLUME_SIZE - VOXEL_VOLUME_RADIUS) * VOXEL_SIZE;
    vec3 worldPos = relativePos + cameraPosition;
    
    // Проектуємо світову позицію на екран
    vec3 viewPos = mat3(gbufferModelView) * (worldPos - cameraPosition);
    vec3 screenSpace = ViewToScreenSpace(viewPos);
    
    // Перевіряємо, чи в межах екрану
    if (any(lessThan(screenSpace.xy, vec2(0.0))) || 
        any(greaterThan(screenSpace.xy, vec2(1.0)))) {
        // Поза екраном - зберігаємо попередні дані або очищаємо
        vec4 prevEmission = texture(colortex6, voxelCoord);
        vec4 prevData = texture(colortex7, voxelCoord);
        
        // Затухання старих даних
        voxelEmission = prevEmission * 0.95;
        voxelAlbedoNormal = prevData * 0.95;
        return;
    }
    
    // Семплюємо дані з G-buffer
    ivec2 screenTexel = ivec2(screenSpace.xy * screenSize);
    
    vec4 albedo = texelFetch(colortex0, screenTexel, 0);
    vec4 materialData = texelFetch(colortex1, screenTexel, 0);
    vec4 lightData = texelFetch(colortex2, screenTexel, 0);
    vec3 normal = GetNormals(screenTexel);
    
    float depth = GetDepth(screenTexel);
    
    // Якщо немає геометрії - очищаємо воксель
    if (depth >= 0.9999) {
        voxelEmission = vec4(0.0);
        voxelAlbedoNormal = vec4(0.0);
        return;
    }
    
    // Отримуємо ID матеріалу
    int materialID = int(materialData.g * 255.0 + 0.5);
    
    // Обчислюємо емісію на основі ID матеріалу
    vec3 emission = vec3(0.0);
    float density = 0.5; // За замовчуванням
    
    // Імпортуємо логіку з BlockLighting.glsl
    vec3 albedoRaw = pow(albedo.rgb, vec3(2.2)); // sRGB to linear
    float albedoLuminance = length(albedoRaw);
    
    // Спрощена версія switch з BlockLighting.glsl
    switch (materialID) {
        // Факели
        case 21:
            float redGlow = float(albedoRaw.r > 0.8 || albedoRaw.r > albedoRaw.g * 1.4);
            float greenGlow = float(albedoRaw.g > 0.8 || albedoRaw.g > albedoRaw.r * 1.4 && albedoRaw.g > albedoRaw.b * 1.4);
            emission = 6.0 * vec3(1.0, 0.7, 0.3) * max(redGlow, greenGlow);
            density = 0.05;
            break;
        
        // Вогонь
        case 22:
        case 15:
            emission = 6.0 * vec3(1.0, 0.6, 0.2) * cube(albedoLuminance);
            density = 0.1;
            break;
        
        // Glowstone
        case 23:
            emission = 4.0 * vec3(1.0, 0.9, 0.6) * cube(albedoLuminance);
            density = 0.05;
            break;
        
        // Лампи
        case 80: case 81: case 82: case 83: 
        case 84: case 85: case 86: case 87:
            float pureYellow = float(albedoRaw.r > 0.76 && albedoRaw.g > 0.66);
            emission = 20.0 * vec3(1.0, 0.8, 0.4) * pureYellow;
            density = 0.008;
            break;
        
        // За замовчуванням - невелика емісія від яскравих блоків
        default:
            if (albedoLuminance > 0.8) {
                emission = albedoRaw * 0.5;
                density = 0.3;
            } else {
                density = 0.8; // Непрозорий блок
            }
            break;
    }
    
    // Записуємо результат
    voxelEmission = vec4(emission, density);
    voxelAlbedoNormal = vec4(albedoRaw, PackUnorm2x8(EncodeNormal(normal)));
}