//Volumetric lighting CS 3.
#version 450
#extension GL_EXT_nonuniform_qualifier : require
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;

struct FlrInput
{
    uvec2 cellCoord;
};

// Vk3DVision (http://3dsurroundgaming.com/) - Stereo Injection
layout(set = 0, binding = 110, std140) uniform Vk3DParams
{
    vec4 stereo;
    vec4 custom_params;
} vk3d_params;

layout(set = 0, binding = 2, std140) uniform PerInstance
{
    mat4 invViewProjMatrix;
    vec4 camPosWS;
    vec4 volumetricsParameters0;
    vec4 volumetricsParameters2;
    vec4 nearFar;
} _95;

layout(set = 0, binding = 102, std430) buffer DebugBuffer
{
    uint debugBuffer[];
} _281;

layout(set = 0, binding = 0) uniform sampler3D inputTex;
layout(set = 0, binding = 1, r11f_g11f_b10f) uniform writeonly image3D outputTex;
layout(set = 2, binding = 0) uniform texture2D globalTextures[];
layout(set = 2, binding = 0) uniform textureCube globalCubeTextures[];
layout(set = 2, binding = 0) uniform texture3D global3DTextures[];
layout(set = 1, binding = 0) uniform sampler linearClampSampler;
layout(set = 1, binding = 1) uniform sampler linearRepeatSampler;
layout(set = 1, binding = 2) uniform sampler nearestClampSampler;
layout(set = 1, binding = 3) uniform sampler nearestRepeatSampler;
layout(set = 1, binding = 4) uniform sampler shadowSampler;

vec3 cellCenterToNDC(vec3 cellCenter, vec4 volumetricsParams0)
{
    return (cellCenter * volumetricsParams0.xyz) + vec3(-1.0, -1.0, 0.0);
}

float linearDepthToDevice(float depthLinear, float near, float far)
{
    return -(((depthLinear + far) * near) / (depthLinear * (far - near)));
}

float volumeZToNativeDepth(float z, float depthExp, float depthRange, vec2 nearFar)
{
    float depthLinear = -((pow(abs(z), depthExp) * depthRange) + nearFar.x);
    float param = depthLinear;
    float param_1 = nearFar.x;
    float param_2 = nearFar.y;
    return linearDepthToDevice(param, param_1, param_2);
}

void flrMain(FlrInput flrInput)
{
    vec4 accumLightingAndTransm = vec4(0.0, 0.0, 0.0, 1.0);
    vec3 previousCellCenterWS = _95.camPosWS.xyz;
    for (uint z = 0u; z < uint(_95.volumetricsParameters0.w); z++)
    {
        ivec3 cellCoord = ivec3(ivec2(flrInput.cellCoord), int(z));
        vec3 cellCenter = vec3(cellCoord) + vec3(0.5);
        vec3 param = cellCenter;
        vec4 param_1 = _95.volumetricsParameters0;
        vec3 cellCenterSS = cellCenterToNDC(param, param_1);
        float cellCenterVolumeZ = cellCenterSS.z;
        float param_2 = cellCenterVolumeZ;
        float param_3 = _95.volumetricsParameters2.x;
        float param_4 = _95.volumetricsParameters2.z;
        vec2 param_5 = _95.nearFar.xy;
        cellCenterSS.z = volumeZToNativeDepth(param_2, param_3, param_4, param_5);
        vec4 cellCenterWS = _95.invViewProjMatrix * vec4(cellCenterSS, 1.0);
        
        //cellCenterWS.x -= vk3d_params.stereo.x *(1)*0.5;
        
        vec3 _180 = cellCenterWS.xyz / vec3(cellCenterWS.w);
        cellCenterWS = vec4(_180.x, _180.y, _180.z, cellCenterWS.w);
        float cellSize = length(cellCenterWS.xyz - previousCellCenterWS);
        previousCellCenterWS = cellCenterWS.xyz;
        
        
        
        vec4 lightingAndExtinction = texelFetch(inputTex, cellCoord, 0);
        float transmittance = exp((-lightingAndExtinction.w) * cellSize);
        vec3 scattering = (lightingAndExtinction.xyz - (lightingAndExtinction.xyz * transmittance)) / vec3(max(lightingAndExtinction.w, 9.9999999392252902907785028219223e-09));
        vec3 _227 = accumLightingAndTransm.xyz + (scattering * accumLightingAndTransm.w);
        accumLightingAndTransm = vec4(_227.x, _227.y, _227.z, accumLightingAndTransm.w);
        accumLightingAndTransm.w *= transmittance;
        imageStore(outputTex, cellCoord, vec4(accumLightingAndTransm));
    }
}

void main()
{
    FlrInput flrInput;
    flrInput.cellCoord = gl_GlobalInvocationID.xy;
    FlrInput param = flrInput;
    flrMain(param);
}



