// SSAO
#version 450

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

layout(set = 0, binding = 0, std140) uniform freqHigh_fragmentUniforms_ubo
{
    vec4 renderpositiontoviewtexture;
    vec4 prevviewprojectionmatrixw;
    vec4 prevviewprojectionmatrixx;
    vec4 prevviewprojectionmatrixy;
    vec4 prevtexsize;
    vec4 texsize;
} freqHigh_fragmentUniforms;

layout(set = 0, binding = 1, std140) uniform freqLow_fragmentUniforms_ubo
{
    vec4 resolutionscale;
    vec4 projectionmatrixz;
    vec4 frustumvectl;
    vec4 frustumvectr;
    vec4 frustumvecbl;
    vec4 frustumvecbr;
    vec4 globalvieworigin;
} freqLow_fragmentUniforms;

layout(set = 0, binding = 2) uniform sampler2D samp_tex2;
layout(set = 0, binding = 3) uniform sampler2D samp_tex3;
layout(set = 0, binding = 4) uniform sampler2D samp_tex0;
layout(set = 0, binding = 5) uniform sampler2D samp_tex1;

layout(location = 0) out vec4 out_FragColor0;

vec2 screenPosToTexcoord(vec2 pos, vec4 bias_scale)
{
    return (pos * bias_scale.zw) + bias_scale.xy;
}

vec4 tex2DFetch(sampler2D image, ivec2 texcoord, int mip)
{
    return texelFetch(image, texcoord, mip);
}

float fmax3(float f1, float f2, float f3)
{
    return max(f1, max(f2, f3));
}

float fmin3(float f1, float f2, float f3)
{
    return min(f1, min(f2, f3));
}

vec4 saturate(vec4 v)
{
    return clamp(v, vec4(0.0), vec4(1.0));
}

vec4 tex2Dlod(sampler2D image, vec4 texcoord)
{
    return textureLod(image, texcoord.xy, texcoord.w);
}

float GetLinearDepth(float ndcZ, vec4 projectionMatrixZ, float rcpFarZ, bool bFirstPersonArmsRescale)
{
    float linearZ = projectionMatrixZ.w / (ndcZ + projectionMatrixZ.z);
    if (bFirstPersonArmsRescale)
    {
        float _123;
        if (linearZ < 1.0)
        {
            _123 = 10.0;
        }
        else
        {
            _123 = 1.0;
        }
        linearZ *= _123;
    }
    return linearZ * rcpFarZ;
}

vec2 computeVelocity(ivec2 pixCoords)
{
    vec2 param = vec2(pixCoords);
    vec4 param_1 = freqHigh_fragmentUniforms.renderpositiontoviewtexture;
    vec2 winPos = screenPosToTexcoord(param, param_1);
    vec2 resScale = freqLow_fragmentUniforms.resolutionscale.zw;
    vec4 param_2 = vec4(winPos, 0.0, 0.0);
    float ndcZ = tex2Dlod(samp_tex2, param_2).x;
    float param_3 = ndcZ;
    vec4 param_4 = freqLow_fragmentUniforms.projectionmatrixz;
    float param_5 = 1.0;
    bool param_6 = true;
    float linearZ = GetLinearDepth(param_3, param_4, param_5, param_6);
    vec4 param_7 = vec4(winPos, 0.0, 0.0);
    vec2 objV = tex2Dlod(samp_tex3, param_7).xy;
    vec3 frustumVecX0 = mix(freqLow_fragmentUniforms.frustumvectl.xyz, freqLow_fragmentUniforms.frustumvectr.xyz, vec3(winPos.x * freqLow_fragmentUniforms.resolutionscale.z));
    vec3 frustumVecX1 = mix(freqLow_fragmentUniforms.frustumvecbl.xyz, freqLow_fragmentUniforms.frustumvecbr.xyz, vec3(winPos.x * freqLow_fragmentUniforms.resolutionscale.z));
    vec3 frustumVec = mix(frustumVecX1, frustumVecX0, vec3(1.0 - (winPos.y * freqLow_fragmentUniforms.resolutionscale.w)));
    vec3 world_pos = freqLow_fragmentUniforms.globalvieworigin.xyz + (frustumVec * linearZ);

	// Frustum corners appear to be in _fa_freqLow[0,1,3,4], let's use 0 & 1 as the top two corners:
vec3 camera_horizontal_world = freqLow_fragmentUniforms.frustumvectr.xyz - freqLow_fragmentUniforms.frustumvectl.xyz;

// In this case I think that the frustum is already a unit distance from the 
// camera, otherwise it would need to be rescaled.

// Find the width of the frustum using Pythagorus:
float frustum_width = sqrt(dot(camera_horizontal_world.xyz, camera_horizontal_world.xyz));

// Calculate the horizontal unit vector:
vec3 camera_horizontal_world_normalized = camera_horizontal_world / frustum_width;

// Calculate the stereo adjustment magnitude, using frustum_width/2 in place of
// tan(fov_horizontal / 2) normally obtained from the inverse projection matrix:
float adjustment_magnitude = vk3d_params.stereo.x * (linearZ - vk3d_params.stereo.y) * frustum_width / 2;

// World space adjustment is just the magitude * horizontal:
world_pos.xyz -= adjustment_magnitude * camera_horizontal_world_normalized;

    
    float rcpHW = 1.0 / ((world_pos.x * freqHigh_fragmentUniforms.prevviewprojectionmatrixw.x) + ((world_pos.y * freqHigh_fragmentUniforms.prevviewprojectionmatrixw.y) + ((world_pos.z * freqHigh_fragmentUniforms.prevviewprojectionmatrixw.z) + freqHigh_fragmentUniforms.prevviewprojectionmatrixw.w)));
    vec2 winPosPrev = vec2((world_pos.x * freqHigh_fragmentUniforms.prevviewprojectionmatrixx.x) + ((world_pos.y * freqHigh_fragmentUniforms.prevviewprojectionmatrixx.y) + ((world_pos.z * freqHigh_fragmentUniforms.prevviewprojectionmatrixx.z) + freqHigh_fragmentUniforms.prevviewprojectionmatrixx.w)), (world_pos.x * freqHigh_fragmentUniforms.prevviewprojectionmatrixy.x) + ((world_pos.y * freqHigh_fragmentUniforms.prevviewprojectionmatrixy.y) + ((world_pos.z * freqHigh_fragmentUniforms.prevviewprojectionmatrixy.z) + freqHigh_fragmentUniforms.prevviewprojectionmatrixy.w))) * rcpHW;
    vec2 _310;
    if (objV.x < 1.0)
    {
        _310 = objV;
    }
    else
    {
        _310 = winPos - (winPosPrev * freqLow_fragmentUniforms.resolutionscale.xy);
    }
    return _310;
}

void main()
{
    vec2 param = gl_FragCoord.xy;
    vec4 param_1 = freqHigh_fragmentUniforms.renderpositiontoviewtexture;
    vec2 texcoord = screenPosToTexcoord(param, param_1);
    ivec2 pixelLocation = ivec2(gl_FragCoord.xy);
    vec4 curr_frame = vec4(0.0);
    vec4 curr_frame_lowpass = vec4(0.0);
    vec4 cMax = vec4(0.0);
    vec4 cMin = vec4(0.0);
    ivec2 param_2 = pixelLocation;
    int param_3 = 0;
    vec4 M = tex2DFetch(samp_tex0, param_2, param_3);
    ivec2 param_4 = pixelLocation + ivec2(-1, 0);
    int param_5 = 0;
    vec4 ML = tex2DFetch(samp_tex0, param_4, param_5);
    ivec2 param_6 = pixelLocation + ivec2(1, 0);
    int param_7 = 0;
    vec4 MR = tex2DFetch(samp_tex0, param_6, param_7);
    ivec2 param_8 = pixelLocation + ivec2(0, -1);
    int param_9 = 0;
    vec4 T = tex2DFetch(samp_tex0, param_8, param_9);
    ivec2 param_10 = pixelLocation + ivec2(0, 1);
    int param_11 = 0;
    vec4 B = tex2DFetch(samp_tex0, param_10, param_11);
    float param_12 = T.x;
    float param_13 = M.x;
    float param_14 = B.x;
    float param_15 = fmax3(param_12, param_13, param_14);
    float param_16 = ML.x;
    float param_17 = MR.x;
    float param_18 = T.y;
    float param_19 = M.y;
    float param_20 = B.y;
    float param_21 = fmax3(param_18, param_19, param_20);
    float param_22 = ML.y;
    float param_23 = MR.y;
    float param_24 = T.z;
    float param_25 = M.z;
    float param_26 = B.z;
    float param_27 = fmax3(param_24, param_25, param_26);
    float param_28 = ML.z;
    float param_29 = MR.z;
    vec3 _436 = vec3(fmax3(param_15, param_16, param_17), fmax3(param_21, param_22, param_23), fmax3(param_27, param_28, param_29));
    cMax = vec4(_436.x, _436.y, _436.z, cMax.w);
    float param_30 = T.x;
    float param_31 = M.x;
    float param_32 = B.x;
    float param_33 = fmin3(param_30, param_31, param_32);
    float param_34 = ML.x;
    float param_35 = MR.x;
    float param_36 = T.y;
    float param_37 = M.y;
    float param_38 = B.y;
    float param_39 = fmin3(param_36, param_37, param_38);
    float param_40 = ML.y;
    float param_41 = MR.y;
    float param_42 = T.z;
    float param_43 = M.z;
    float param_44 = B.z;
    float param_45 = fmin3(param_42, param_43, param_44);
    float param_46 = ML.z;
    float param_47 = MR.z;
    vec3 _493 = vec3(fmin3(param_33, param_34, param_35), fmin3(param_39, param_40, param_41), fmin3(param_45, param_46, param_47));
    cMin = vec4(_493.x, _493.y, _493.z, cMin.w);
    float param_48 = T.w;
    float param_49 = M.w;
    float param_50 = B.w;
    float param_51 = fmax3(param_48, param_49, param_50);
    float param_52 = ML.w;
    float param_53 = MR.w;
    cMax.w = fmax3(param_51, param_52, param_53);
    float param_54 = T.w;
    float param_55 = M.w;
    float param_56 = B.w;
    float param_57 = fmin3(param_54, param_55, param_56);
    float param_58 = ML.w;
    float param_59 = MR.w;
    cMin.w = fmin3(param_57, param_58, param_59);
    ivec2 param_60 = pixelLocation + ivec2(-1);
    int param_61 = 0;
    vec4 TL = tex2DFetch(samp_tex0, param_60, param_61);
    ivec2 param_62 = pixelLocation + ivec2(1, -1);
    int param_63 = 0;
    vec4 TR = tex2DFetch(samp_tex0, param_62, param_63);
    ivec2 param_64 = pixelLocation + ivec2(-1, 1);
    int param_65 = 0;
    vec4 BL = tex2DFetch(samp_tex0, param_64, param_65);
    ivec2 param_66 = pixelLocation + ivec2(1);
    int param_67 = 0;
    vec4 BR = tex2DFetch(samp_tex0, param_66, param_67);
    float param_68 = TL.x;
    float param_69 = TR.x;
    float param_70 = BL.x;
    float param_71 = fmax3(param_68, param_69, param_70);
    float param_72 = BR.x;
    float param_73 = cMax.x;
    float param_74 = TL.y;
    float param_75 = TR.y;
    float param_76 = BL.y;
    float param_77 = fmax3(param_74, param_75, param_76);
    float param_78 = BR.y;
    float param_79 = cMax.y;
    float param_80 = TL.z;
    float param_81 = TR.z;
    float param_82 = BL.z;
    float param_83 = fmax3(param_80, param_81, param_82);
    float param_84 = BR.z;
    float param_85 = cMax.z;
    vec3 _621 = (vec3(fmax3(param_71, param_72, param_73), fmax3(param_77, param_78, param_79), fmax3(param_83, param_84, param_85)) + cMax.xyz) * 0.5;
    cMax = vec4(_621.x, _621.y, _621.z, cMax.w);
    float param_86 = TL.x;
    float param_87 = TR.x;
    float param_88 = BL.x;
    float param_89 = fmin3(param_86, param_87, param_88);
    float param_90 = BR.x;
    float param_91 = cMin.x;
    float param_92 = TL.y;
    float param_93 = TR.y;
    float param_94 = BL.y;
    float param_95 = fmin3(param_92, param_93, param_94);
    float param_96 = BR.y;
    float param_97 = cMin.y;
    float param_98 = TL.z;
    float param_99 = TR.z;
    float param_100 = BL.z;
    float param_101 = fmin3(param_98, param_99, param_100);
    float param_102 = BR.z;
    float param_103 = cMin.z;
    vec3 _682 = (vec3(fmin3(param_89, param_90, param_91), fmin3(param_95, param_96, param_97), fmin3(param_101, param_102, param_103)) + cMin.xyz) * 0.5;
    cMin = vec4(_682.x, _682.y, _682.z, cMin.w);
    float param_104 = TL.w;
    float param_105 = TR.w;
    float param_106 = BL.w;
    float param_107 = fmax3(param_104, param_105, param_106);
    float param_108 = BR.w;
    float param_109 = cMax.w;
    cMax.w = (fmax3(param_107, param_108, param_109) + cMax.w) * 0.5;
    float param_110 = TL.w;
    float param_111 = TR.w;
    float param_112 = BL.w;
    float param_113 = fmin3(param_110, param_111, param_112);
    float param_114 = BR.w;
    float param_115 = cMin.w;
    cMin.w = (fmin3(param_113, param_114, param_115) + cMin.w) * 0.5;
    vec4 param_116 = M;
    curr_frame = saturate(param_116);
    ivec2 param_117 = ivec2(gl_FragCoord.xy);
    vec2 velocity = computeVelocity(param_117);
    vec4 param_118 = vec4((texcoord * freqHigh_fragmentUniforms.prevtexsize.xy) - velocity, 0.0, 0.0);
    vec4 prev_frame = tex2Dlod(samp_tex1, param_118);
    vec4 param_119 = (cMax - prev_frame) / (cMax - cMin);
    vec4 cubeBlendRatios = saturate(param_119);
    prev_frame = mix(cMax, cMin, cubeBlendRatios);
    out_FragColor0 = max(vec4(0.0), mix(prev_frame, curr_frame, vec4(freqHigh_fragmentUniforms.texsize.x)));
}


