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

struct SH9
{
    vec3 L[9];
};

struct FlrInput
{
    vec2 uv0;
};

struct FlrOutput
{
    vec4 hdrColor;
};

struct SH9Compressed
{
    uvec4 data0[2];
    uvec4 data1;
};

struct SH9Compressed_1
{
    uvec4 data0[2];
    uvec4 data1;
};

// 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 = 11, std140) uniform PerView
{
    mat4 invViewProjMatrix;
    mat4 invProjMatrix;
    vec4 nearFar;
    vec4 nearFarWidthHeight;
    vec4 cameraPositionWS;
    vec4 dirLightDirWS;
    vec4 dirLightColorAndIntens;
    uvec4 dirLightProjectorParams;
    vec4 dirLightProjectorTransform;
    mat4 dirLightProjectorViewProjMatrix;
    SH9Compressed skyModelSH;
    SH9Compressed globalBackgroundSH;
    mat4 pssmViewProjMatrices[5];
    mat4 localLightViewProjMatrices[16];
    vec4 shadowParameters0;
    vec4 playerWorldPosition;
    vec4 lightingWeights0;
    vec4 lightingWeights1;
    vec4 dynamicResolutionParameters;
    vec4 frameParameters0;
    vec4 frameParameters1;
    vec4 projectionOffsets;
    vec4 irradianceGridWorldPosition;
    vec4 irradianceGridHalfExtents;
    uvec4 irradianceGridResolution;
} _695;

layout(set = 0, binding = 6, std430) buffer irradianceGridBuffer
{
    SH9Compressed_1 _irradianceGridBuffer[];
} _712;

layout(set = 0, binding = 10, std140) uniform PerInstance
{
    vec4 ouput_dims;
} _1066;

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

layout(set = 0, binding = 2) uniform sampler2D depthBufferTex;
layout(set = 0, binding = 1) uniform sampler2D normalsTex;
layout(set = 0, binding = 0, rgba16f) uniform writeonly image2D 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;
layout(set = 0, binding = 3) uniform sampler2D depthBufferHalfTex;
layout(set = 0, binding = 4) uniform sampler2D depthBufferQuarterTex;

vec2 signNotZero(vec2 v)
{
    return vec2((v.x >= 0.0) ? 1.0 : (-1.0), (v.y >= 0.0) ? 1.0 : (-1.0));
}

vec3 decodeNormal(vec2 e)
{
    vec3 v = vec3(e, (1.0 - abs(e.x)) - abs(e.y));
    if (v.z < 0.0)
    {
        vec2 param = v.xy;
        vec2 _164 = (vec2(1.0) - abs(v.yx)) * signNotZero(param);
        v = vec3(_164.x, _164.y, v.z);
    }
    return normalize(v);
}

vec3 unproject(vec2 uv0, float depth, mat4 invProjMatrix)
{
    vec4 unprojPos = invProjMatrix * vec4((uv0 * 2.0) - vec2(1.0), depth, 1.0);
    return unprojPos.xyz / unprojPos.www;
}

vec4 unpackUNorm4x8(uint p_PackedValue)
{
    return vec4(float(p_PackedValue & 255u), float((p_PackedValue >> uint(8)) & 255u), float((p_PackedValue >> uint(16)) & 255u), float((p_PackedValue >> uint(24)) & 255u)) * 0.00392160005867481231689453125;
}

SH9 decodeSH9(vec4 data[7])
{
    SH9 result;
    result.L[0] = data[0].xyz;
    result.L[1] = vec3(data[0].w, data[1].xy);
    result.L[2] = vec3(data[1].zw, data[2].x);
    result.L[3] = data[2].yzw;
    result.L[4] = data[3].xyz;
    result.L[5] = vec3(data[3].w, data[4].xy);
    result.L[6] = vec3(data[4].zw, data[5].x);
    result.L[7] = data[5].yzw;
    result.L[8] = data[6].xyz;
    return result;
}

SH9 decodeSH9(uvec4 data0[2], uvec4 data1)
{
    uint param = data0[0].x;
    vec4 tempCoeff = (unpackUNorm4x8(param) * 2.0) - vec4(1.0);
    float tempCoeffLen = unpackHalf2x16(data1.x & 65535u).x;
    vec4 coeffs[7];
    coeffs[0] = tempCoeff * tempCoeffLen;
    uint param_1 = data0[0].y;
    tempCoeff = (unpackUNorm4x8(param_1) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16((data1.x >> uint(16)) & 65535u).x;
    coeffs[1] = tempCoeff * tempCoeffLen;
    uint param_2 = data0[0].z;
    tempCoeff = (unpackUNorm4x8(param_2) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16(data1.y & 65535u).x;
    coeffs[2] = tempCoeff * tempCoeffLen;
    uint param_3 = data0[0].w;
    tempCoeff = (unpackUNorm4x8(param_3) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16((data1.y >> uint(16)) & 65535u).x;
    coeffs[3] = tempCoeff * tempCoeffLen;
    uint param_4 = data0[1].x;
    tempCoeff = (unpackUNorm4x8(param_4) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16(data1.z & 65535u).x;
    coeffs[4] = tempCoeff * tempCoeffLen;
    uint param_5 = data0[1].y;
    tempCoeff = (unpackUNorm4x8(param_5) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16((data1.z >> uint(16)) & 65535u).x;
    coeffs[5] = tempCoeff * tempCoeffLen;
    uint param_6 = data0[1].z;
    tempCoeff = (unpackUNorm4x8(param_6) * 2.0) - vec4(1.0);
    tempCoeffLen = unpackHalf2x16(data1.w & 65535u).x;
    coeffs[6] = tempCoeff * tempCoeffLen;
    vec4 param_7[7] = coeffs;
    return decodeSH9(param_7);
}

SH9 projectOntoSH9(vec3 n)
{
    SH9 sh;
    sh.L[0] = vec3(0.88622760772705078125);
    vec3 a1 = n.yzx * 0.48860299587249755859375;
    sh.L[1] = vec3(2.094399929046630859375) * a1.x;
    sh.L[2] = vec3(2.094399929046630859375) * a1.y;
    sh.L[3] = vec3(2.094399929046630859375) * a1.z;
    sh.L[4] = vec3(0.785398006439208984375) * ((1.09254801273345947265625 * n.x) * n.y);
    sh.L[5] = vec3(0.785398006439208984375) * ((1.09254801273345947265625 * n.y) * n.z);
    sh.L[6] = vec3(0.785398006439208984375) * (0.3153919875621795654296875 * (((3.0 * n.z) * n.z) - 1.0));
    sh.L[7] = vec3(0.785398006439208984375) * ((1.09254801273345947265625 * n.x) * n.z);
    sh.L[8] = vec3(0.785398006439208984375) * (0.546274006366729736328125 * ((n.x * n.x) - (n.y * n.y)));
    return sh;
}

vec3 shDotProduct(SH9 a, SH9 b)
{
    vec3 result = a.L[0] * b.L[0];
    result += (a.L[1] * b.L[1]);
    result += (a.L[2] * b.L[2]);
    result += (a.L[3] * b.L[3]);
    result += (a.L[4] * b.L[4]);
    result += (a.L[5] * b.L[5]);
    result += (a.L[6] * b.L[6]);
    result += (a.L[7] * b.L[7]);
    result += (a.L[8] * b.L[8]);
    return result;
}

vec3 sampleSH(uvec4 data0[2], uvec4 data1, vec3 dir)
{
    uvec4 param[2] = data0;
    uvec4 param_1 = data1;
    SH9 sh = decodeSH9(param, param_1);
    vec3 param_2 = dir;
    SH9 dirSH = projectOntoSH9(param_2);
    SH9 param_3 = dirSH;
    SH9 param_4 = sh;
    return max(shDotProduct(param_3, param_4), vec3(0.0));
}

uint _mortonPart1By2(inout uint x)
{
    x &= 1023u;
    x = (x ^ (x << uint(16))) & 4278190335u;
    x = (x ^ (x << uint(8))) & 50393103u;
    x = (x ^ (x << uint(4))) & 51130563u;
    x = (x ^ (x << uint(2))) & 153391689u;
    return x;
}

uint mortonEncode(uvec3 x)
{
    uint param = x.z;
    uint _234 = _mortonPart1By2(param);
    uint param_1 = x.y;
    uint _239 = _mortonPart1By2(param_1);
    uint param_2 = x.x;
    uint _246 = _mortonPart1By2(param_2);
    return ((_234 << uint(2)) + (_239 << uint(1))) + _246;
}

uint calcIrradianceGridCellIdx(uvec3 p_CellCoord)
{
    uvec3 param = p_CellCoord;
    return mortonEncode(param);
}

uint _mortonCompact1By2(inout uint x)
{
    x &= 153391689u;
    x = (x ^ (x >> uint(2))) & 51130563u;
    x = (x ^ (x >> uint(4))) & 50393103u;
    x = (x ^ (x >> uint(8))) & 4278190335u;
    x = (x ^ (x >> uint(16))) & 1023u;
    return x;
}

uvec3 mortonDecode(uint x)
{
    uint param = x >> uint(0);
    uint _254 = _mortonCompact1By2(param);
    uint param_1 = x >> uint(1);
    uint _258 = _mortonCompact1By2(param_1);
    uint param_2 = x >> uint(2);
    uint _262 = _mortonCompact1By2(param_2);
    return uvec3(_254, _258, _262);
}

void evaluateCell(uint i, vec3 globalIrrad, vec3 NVtx, vec3 N, vec3 posWS, vec3 cellExtents, uint baseCellIdx, vec3 alpha, inout vec4 gridIrrad)
{
    ivec3 offset = ivec3(int(i), int(i >> uint(1)), int(i >> uint(2))) & ivec3(1);
    uint param = baseCellIdx;
    ivec3 offsetGridCoord = clamp(ivec3(mortonDecode(param)) + offset, ivec3(0), ivec3(_695.irradianceGridResolution.xyz) - ivec3(1));
    uvec3 param_1 = uvec3(offsetGridCoord);
    uint _716 = calcIrradianceGridCellIdx(param_1);
    SH9Compressed_1 sh;
    sh.data0[0] = _712._irradianceGridBuffer[_716].data0[0];
    sh.data0[1] = _712._irradianceGridBuffer[_716].data0[1];
    sh.data1 = _712._irradianceGridBuffer[_716].data1;
    bool empty = sh.data0[1].w == 0u;
    vec3 _736;
    if (!empty)
    {
        uint param_2 = sh.data0[1].w;
        _736 = (((unpackUNorm4x8(param_2).xyz * 2.0) - vec3(1.0)) * cellExtents) * 0.5;
    }
    else
    {
        _736 = vec3(0.0);
    }
    vec3 probeOffset = _736;
    vec3 tri = mix(vec3(1.0) - alpha, alpha, vec3(offset));
    vec3 cellWorldPos = (((_695.irradianceGridWorldPosition.xyz + (vec3(offsetGridCoord) * cellExtents)) - _695.irradianceGridHalfExtents.xyz) + cellExtents) + probeOffset;
    vec3 posToCellDir = -normalize(posWS - cellWorldPos);
    float weight = ((tri.x * tri.y) * tri.z) * max(dot(NVtx, posToCellDir), 0.100000001490116119384765625);
    uvec4 param_3[2] = sh.data0;
    uvec4 param_4 = sh.data1;
    vec3 param_5 = N;
    gridIrrad += vec4(mix(sampleSH(param_3, param_4, param_5) * weight, globalIrrad * weight, vec3(float(empty))), weight);
}

void calcIrradiance(vec3 posWS, vec3 NVtx, vec3 N, inout vec3 irrad)
{
    vec3 cellExtents = (_695.irradianceGridHalfExtents.xyz * 2.0) / vec3(_695.irradianceGridResolution.xyz);
    vec3 gridPos = clamp((((posWS - _695.irradianceGridWorldPosition.xyz) / _695.irradianceGridHalfExtents.xyz) * 0.5) + vec3(0.5), vec3(0.0), vec3(1.0));
    vec4 gridIrrad = vec4(0.0);
    uvec4 param[2];
    param[0] = _695.skyModelSH.data0[0];
    param[1] = _695.skyModelSH.data0[1];
    uvec4 param_1 = _695.skyModelSH.data1;
    vec3 param_2 = N;
    irrad = sampleSH(param, param_1, param_2);
    vec3 gridCoordFloat = (gridPos * vec3(_695.irradianceGridResolution.xyz)) - vec3(1.0, 0.5, 1.0);
    uvec3 param_3 = uvec3(gridCoordFloat);
    uint baseCellIdx = calcIrradianceGridCellIdx(param_3);
    vec3 alpha = fract(gridCoordFloat);
    for (uint i = 0u; i < 4u; i++)
    {
        uint param_4 = i;
        vec3 param_5 = irrad;
        vec3 param_6 = NVtx;
        vec3 param_7 = N;
        vec3 param_8 = posWS;
        vec3 param_9 = cellExtents;
        uint param_10 = baseCellIdx;
        vec3 param_11 = alpha;
        vec4 param_12 = gridIrrad;
        evaluateCell(param_4, param_5, param_6, param_7, param_8, param_9, param_10, param_11, param_12);
        gridIrrad = param_12;
        uint param_13 = i + 4u;
        vec3 param_14 = irrad;
        vec3 param_15 = NVtx;
        vec3 param_16 = N;
        vec3 param_17 = posWS;
        vec3 param_18 = cellExtents;
        uint param_19 = baseCellIdx;
        vec3 param_20 = alpha;
        vec4 param_21 = gridIrrad;
        evaluateCell(param_13, param_14, param_15, param_16, param_17, param_18, param_19, param_20, param_21);
        gridIrrad = param_21;
    }
    vec4 _942;
    if (gridIrrad.w > 9.9999999392252902907785028219223e-09)
    {
        _942 = gridIrrad / vec4(gridIrrad.w);
    }
    else
    {
        _942 = vec4(0.0);
    }
    gridIrrad = _942;
    vec3 fadeBox = vec3(1.0) - (clamp(abs((gridPos * 2.0) - vec3(1.0)) - vec3(0.949999988079071044921875), vec3(0.0), vec3(1.0)) * 20.0);
    float gridBlendWeight = min(fadeBox.x, min(fadeBox.y, fadeBox.z));
    irrad = mix(irrad, gridIrrad.xyz, vec3(gridBlendWeight)) * 1.39999997615814208984375;
}

void flrMain(FlrInput flrInput, inout FlrOutput flrOutput)
{
    vec2 sampleUv = flrInput.uv0;
    sampleUv *= _695.dynamicResolutionParameters.xy;
    float depth = textureLod(depthBufferTex, sampleUv, 0.0).x;
    if (depth == 0.0)
    {
        flrOutput.hdrColor = vec4(0.0, 0.0, 0.0, 1.0);
        return;
    }
    vec4 normals = textureLod(normalsTex, sampleUv, 0.0);
    vec2 param = normals.xy;
    vec3 normal = decodeNormal(param);
    vec2 param_1 = normals.zw;
    vec3 normalVtx = decodeNormal(param_1);
    vec2 param_2 = flrInput.uv0;
    float param_3 = depth;
    mat4 param_4 = _695.invViewProjMatrix;
    
    param_2.x -= vk3d_params.stereo.x *(1-vk3d_params.stereo.y*depth*0.2)*0.5;
    
    vec3 posWS = unproject(param_2, param_3, param_4);
    vec3 irrad = vec3(0.0);
    vec3 param_5 = posWS;
    vec3 param_6 = normalVtx;
    vec3 param_7 = normal;
    vec3 param_8;
    calcIrradiance(param_5, param_6, param_7, param_8);
    irrad = param_8;
    flrOutput.hdrColor = vec4(irrad, 1.0);
}

void main()
{
    uvec3 cellCoord = gl_GlobalInvocationID;
    vec3 cellCenter = vec3(cellCoord) + vec3(0.5);
    FlrInput flrInput;
    flrInput.uv0 = cellCenter.xy / vec2(_1066.ouput_dims.xy);
    FlrInput param = flrInput;
    FlrOutput flrOutput;
    FlrOutput param_1 = flrOutput;
    flrMain(param, param_1);
    flrOutput = param_1;
    imageStore(outputTex, ivec2(cellCoord.xy), vec4(flrOutput.hdrColor));
}




