//SSAO. Ambient occlusion.
#version 450
#extension GL_EXT_nonuniform_qualifier : require

struct HbaoInput
{
    vec2 uv0;
    vec2 dynamicResolutionFactor;
};

struct FlrInput
{
    vec2 uv0;
    vec2 dynamicResolutionFactor;
};

struct FlrOutput
{
    vec4 aoColor;
};

// 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 = 0, std140) uniform PerView
{
    mat4 invProjMatrix;
    vec4 haltonSample;
    vec4 hbaoParameters0;
    mat4 viewMatrix;
    vec4 dynamicResolutionParameters;
} _145;

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

layout(set = 0, binding = 1) uniform sampler2D depthBufferTex;
layout(set = 0, binding = 2) uniform sampler2D hbaoNoiseTex;
layout(set = 0, binding = 3) uniform sampler2D normalsTex;
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(location = 0) in vec2 inUV0;
layout(location = 0) out vec4 outColor;

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 _108 = (vec2(1.0) - abs(v.yx)) * signNotZero(param);
        v = vec3(_108.x, _108.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;
}

vec3 fetchPosVS(vec2 uv)
{
    vec2 param = uv;
    float param_1 = textureLod(depthBufferTex, uv, 0.0).x;
    mat4 param_2 = _145.invProjMatrix;
    
    //param.x -= vk3d_params.stereo.x *(5-vk3d_params.stereo.y*param_1*0.2)*0.5;
    
    vec3 res = unproject(param, param_1, param_2);
    return res;
}

vec2 rotateDirection(vec2 dir, vec2 cosSin)
{
    return vec2((dir.x * cosSin.x) - (dir.y * cosSin.y), (dir.x * cosSin.y) + (dir.y * cosSin.x));
}

float falloff(float dist2)
{
    float radius2Inv = (-1.0) / ((_145.hbaoParameters0.x * 1.0) * (_145.hbaoParameters0.x * 1.0));
    return (dist2 * radius2Inv) + 1.0;
}

float computeAO(vec3 P, vec3 N, vec3 S)
{
    vec3 V = S - P;
    float VdV = dot(V, V);
    float NdV = (dot(N, V) * 1.0) / sqrt(VdV);
    float param = VdV;
    return clamp(NdV - _145.hbaoParameters0.z, 0.0, 1.0) * clamp(falloff(param), 0.0, 1.0);
}

vec4 hbao(HbaoInput hbaoInput)
{
    ivec2 size = textureSize(depthBufferTex, 0);
    uvec2 wh;
    wh.x = uint(size.x);
    wh.y = uint(size.y);
    vec4 res = vec4(vec2(wh), 0.0, 0.0);
    vec2 _258 = vec2(1.0) / res.xy;
    res = vec4(res.x, res.y, _258.x, _258.y);
    ivec2 size_1 = textureSize(hbaoNoiseTex, 0);
    uvec2 nwh;
    nwh.x = uint(size_1.x);
    nwh.y = uint(size_1.y);
    vec2 noiseScale = vec2(nwh) / res.xy;
    
    vec2 inp2 = hbaoInput.uv0;
    inp2.x -= vk3d_params.stereo.x *(1)*-1;
    
    vec2 rand = textureLod(hbaoNoiseTex, (hbaoInput.uv0 + _145.haltonSample.xy) / noiseScale, 0.0).yz;
    vec4 normals = textureLod(normalsTex, hbaoInput.uv0 * hbaoInput.dynamicResolutionFactor, 0.0);
    vec2 param = normals.zw;
    
    //param.x -= vk3d_params.stereo.x *(1)*12;
    
    vec3 normalVS = (_145.viewMatrix * vec4(decodeNormal(param), 0.0)).xyz;
    vec2 param_1 = hbaoInput.uv0;
    
    //hbaoInput.uv0.x -= vk3d_params.stereo.x *(1)*-1;
    
    //param_1.x -= vk3d_params.stereo.x *1;
    
    vec3 posVS = fetchPosVS(param_1);
    float ao = 0.0;
    float toScreen = res.y / 1.67999994754791259765625;
    float radiusPixels = (toScreen * (_145.hbaoParameters0.x * 1.0)) / (-posVS.z);
    float randAngle = 6.283185482025146484375 * rand.x;
    vec2 randDir = vec2(cos(randAngle), sin(randAngle));
    
    
    //for (float di = 0.0; di < 2.0; di += 1.0)
    for (float di = 0.0; di < 2.0; di += 1.0)
    {
        float angle = 3.1415927410125732421875 * di;
        vec2 param_2 = vec2(cos(angle), sin(angle));
        vec2 param_3 = randDir;
        vec2 dir = rotateDirection(param_2, param_3);
        float rayPixels = (rand.y * radiusPixels) + 1.0;
        vec2 snappedUV = (round(dir * rayPixels) * res.zw) + hbaoInput.uv0;
        vec2 param_4 = snappedUV;
        vec3 S = fetchPosVS(param_4);
        vec3 param_5 = posVS;
        vec3 param_6 = normalVS;
        vec3 param_7 = S;
        ao += computeAO(param_5, param_6, param_7);
    }
    ao *= ((_145.hbaoParameters0.y * 1.5) / 2.0);
    ao = clamp(1.0 - (ao * 2.0), 0.0, 1.0);
    return vec4(ao);
}

void flrMain(FlrInput flrInput, inout FlrOutput flrOutput)
{
    HbaoInput hbaoInput;
    
    //flrInput.uv0.x -= vk3d_params.stereo.x *(1)*-0.5;
    
    hbaoInput.uv0 = flrInput.uv0;
    hbaoInput.dynamicResolutionFactor = flrInput.dynamicResolutionFactor;
    HbaoInput param = hbaoInput;
    flrOutput.aoColor = hbao(param);
}

void main()
{
    FlrInput flrInput;
    flrInput.uv0 = inUV0;
    
    //flrInput.uv0.x -= vk3d_params.stereo.x *(1-vk3d_params.stereo.y*depth*0.2)*0.5;
    
    
    flrInput.dynamicResolutionFactor = _145.dynamicResolutionParameters.xy;
    FlrInput param = flrInput;
    FlrOutput param_1;
    flrMain(param, param_1);
    FlrOutput flrOutput = param_1;
    outColor = flrOutput.aoColor;
}




