// GUN SHINNY & SSR
#version 450

struct gbuffer_t
{
    vec3 world_pos;
    vec3 view;
    vec3 normal;
    vec3 specular;
    vec3 reflection;
    float smoothness;
    float depth;
    vec3 phongEnvBRDF;
};

layout(set = 0, binding = 0, std140) uniform freqHigh_fragmentUniforms_ubo
{
    vec4 renderpositiontoviewtexture;
    vec4 ssrsmoothnessthreshold;
    vec4 ssrparms;
    vec4 prevglobalpostowindowx;
    vec4 prevglobalpostowindowy;
    vec4 prevglobalpostowindowz;
    vec4 prevglobalpostowindoww;
    vec4 ssrscale;
} freqHigh_fragmentUniforms;

layout(set = 0, binding = 1, std140) uniform freqLow_fragmentUniforms_ubo
{
    vec4 inverseviewmatrixx;
    vec4 inverseviewmatrixy;
    vec4 inverseviewmatrixz;
    vec4 projectionmatrixz;
    vec4 resolutionscale;
    vec4 packedinverseprojection0;
    vec4 packedinverseprojection1;
    vec4 packedprojection;
    vec4 windowpostoglobalx;
    vec4 windowpostoglobaly;
    vec4 windowpostoglobalz;
    vec4 windowpostoglobalw;
    vec4 prevresolutionscale;
} freqLow_fragmentUniforms;

// 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 = 2) uniform sampler2D samp_tex0;
layout(set = 0, binding = 3) uniform sampler2D samp_tex4;
layout(set = 0, binding = 4) uniform sampler2D samp_tex1;
layout(set = 0, binding = 5) uniform sampler2D samp_tex3;
layout(set = 0, binding = 6) uniform sampler2D samp_tex5;

layout(location = 0) out vec4 out_FragColor0;
layout(location = 1) out vec4 out_FragColor1;

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);
}

vec2 OctWrap(vec2 v)
{
    float _394;
    if (v.x >= 0.0)
    {
        _394 = 1.0;
    }
    else
    {
        _394 = -1.0;
    }
    float _403;
    if (v.y >= 0.0)
    {
        _403 = 1.0;
    }
    else
    {
        _403 = -1.0;
    }
    return (vec2(1.0) - abs(v.yx)) * vec2(_394, _403);
}

vec3 NormalOctDecode(inout vec2 encN, bool expand_range)
{
    if (expand_range)
    {
        encN = (encN * 2.0) - vec2(1.0);
    }
    vec3 n;
    n.z = (1.0 - abs(encN.x)) - abs(encN.y);
    vec2 _433;
    if (n.z >= 0.0)
    {
        _433 = encN;
    }
    else
    {
        vec2 param = encN;
        _433 = OctWrap(param);
    }
    n = vec3(_433.x, _433.y, n.z);
    n = normalize(n);
    return n;
}

vec3 MatrixMul(mat3 m, vec3 v)
{
    return m * v;
}

float sqr(float x)
{
    return x * x;
}

vec2 SmoothnessDecode(float s)
{
    float expanded_s = (s * 2.0) - 1.0;
    float param = expanded_s;
    float _459;
    if (expanded_s > 0.0)
    {
        _459 = 1.0;
    }
    else
    {
        _459 = 0.0;
    }
    return vec2(sqr(param), _459);
}

vec3 sqr(vec3 x)
{
    return x * x;
}

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

vec3 GetViewPos(vec3 winPos, vec4 inverseProjection0, vec4 inverseProjection1)
{
    return vec3((inverseProjection0.xy * winPos.xy) + inverseProjection0.zw, inverseProjection1.z) / vec3((inverseProjection1.x * winPos.z) + inverseProjection1.y);
}

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

float asfloat(uint x)
{
    return uintBitsToFloat(x);
}

float ApproxExp2(float f)
{
    uint param = uint((f + 127.0) * 8388608.0);
    return asfloat(param);
}

vec3 environmentBRDF(float NdotV, float smoothness, vec3 f0)
{
    float t1 = 0.0949999988079071044921875 + (smoothness * (0.60000002384185791015625 + (4.190000057220458984375 * smoothness)));
    float t2 = NdotV + 0.02500000037252902984619140625;
    float t3 = (9.5 * smoothness) * NdotV;
    float param = 1.0 - (14.0 * NdotV);
    float a0 = (t1 * t2) * ApproxExp2(param);
    float param_1 = -t3;
    float a1 = 0.4000000059604644775390625 + (0.60000002384185791015625 * (1.0 - ApproxExp2(param_1)));
    return mix(vec3(a0), vec3(a1), f0);
}

vec3 GetWindowPosZ(vec3 viewPos, vec4 projection)
{
    return vec3(vec2(0.5) + (projection.xy * (viewPos.xy / vec2(viewPos.z))), (projection.w / viewPos.z) + projection.z);
}

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

int firstBitLow(uint value)
{
    return findLSB(value);
}

vec4 MatrixMul(vec3 pos, vec4 matX, vec4 matY, vec4 matZ, vec4 matW)
{
    return vec4((pos.x * matX.x) + ((pos.y * matX.y) + ((pos.z * matX.z) + matX.w)), (pos.x * matY.x) + ((pos.y * matY.y) + ((pos.z * matY.z) + matY.w)), (pos.x * matZ.x) + ((pos.y * matZ.y) + ((pos.z * matZ.z) + matZ.w)), (pos.x * matW.x) + ((pos.y * matW.y) + ((pos.z * matW.z) + matW.w)));
}

void main()
{
    vec2 param = gl_FragCoord.xy;
    vec4 param_1 = freqHigh_fragmentUniforms.renderpositiontoviewtexture;
    vec2 tc = screenPosToTexcoord(param, param_1);
    out_FragColor0 = vec4(0.0);
    out_FragColor1 = vec4(0.0);
    ivec2 param_2 = ivec2(gl_FragCoord.xy);
    int param_3 = 0;
    vec2 param_4 = tex2DFetch(samp_tex0, param_2, param_3).xy;
    bool param_5 = false;
    vec3 _500 = NormalOctDecode(param_4, param_5);
    vec3 normal = _500;
    ivec2 param_6 = ivec2(gl_FragCoord.xy);
    int param_7 = 0;
    vec4 spec = tex2DFetch(samp_tex4, param_6, param_7);
    gbuffer_t scene;
    scene.normal = normal;
    mat3 invProjT = mat3(vec3(freqLow_fragmentUniforms.inverseviewmatrixx.xyz), vec3(freqLow_fragmentUniforms.inverseviewmatrixy.xyz), vec3(freqLow_fragmentUniforms.inverseviewmatrixz.xyz));
    mat3 param_8 = invProjT;
    vec3 param_9 = scene.normal;
    scene.normal = normalize(MatrixMul(param_8, param_9));
    float param_10 = spec.w;
    vec2 decodedSmoothness = SmoothnessDecode(param_10);
    float _556;
    if (decodedSmoothness.y > 0.0)
    {
        _556 = decodedSmoothness.x;
    }
    else
    {
        _556 = 0.0;
    }
    scene.smoothness = _556;
    ivec2 param_11 = ivec2(gl_FragCoord.xy);
    int param_12 = 0;
    vec3 param_13 = tex2DFetch(samp_tex4, param_11, param_12).xyz;
    scene.specular = sqr(param_13);
    ivec2 param_14 = ivec2(gl_FragCoord.xy);
    int param_15 = 0;
    scene.depth = tex2DFetch(samp_tex1, param_14, param_15).x;
    float param_16 = scene.depth;
    vec4 param_17 = freqLow_fragmentUniforms.projectionmatrixz;
    float param_18 = 1.0;
    bool param_19 = true;
    float zLinear = GetLinearDepth(param_16, param_17, param_18, param_19);
    
    // Correction, but incorrect
    //tc.x -= vk3d_params.stereo.x;
    
    vec3 param_20 = vec3(tc * freqLow_fragmentUniforms.resolutionscale.zw, scene.depth);
    vec4 param_21 = freqLow_fragmentUniforms.packedinverseprojection0;
    vec4 param_22 = freqLow_fragmentUniforms.packedinverseprojection1;
    scene.world_pos = GetViewPos(param_20, param_21, param_22);
    
    // DISABLE UGL Y SSR
    scene.world_pos = vec3(0);
    
    scene.view = normalize(-scene.world_pos);
    scene.reflection = reflect(-scene.view, scene.normal);
    float param_23 = dot(scene.view, scene.normal);
    float NdotV = saturate(param_23);
    float param_24 = NdotV;
    float param_25 = scene.smoothness;
    vec3 param_26 = scene.specular;
    scene.phongEnvBRDF = environmentBRDF(param_24, param_25, param_26);
    float smoothness_threshold = freqHigh_fragmentUniforms.ssrsmoothnessthreshold.x;
    float VdovR_threshold = 0.0;
    bool _658 = scene.smoothness > smoothness_threshold;
    bool _668;
    if (_658)
    {
        _668 = dot(scene.view, scene.reflection) <= VdovR_threshold;
    }
    else
    {
        _668 = _658;
    }
    bool _674;
    if (_668)
    {
        _674 = scene.depth < 1.0;
    }
    else
    {
        _674 = _668;
    }
    if (_674)
    {
        uvec2 idxPix = uvec2(ivec2(gl_FragCoord.xy)) & uvec2(3u);
        float jitter = float(((((2068378560u * (1u - (idxPix.x >> uint(1)))) + (1500172770u * (idxPix.x >> uint(1)))) >> ((idxPix.y + ((idxPix.x & 1u) << uint(2))) << uint(2))) + uint(int(freqHigh_fragmentUniforms.ssrparms.w))) & 15u) / 15.0;
        jitter -= 1.0;
        int max_steps = 16;
        float stride = 1.0;
        vec3 ray_start_vs = scene.world_pos;
        float param_27 = scene.depth;
        vec4 param_28 = freqLow_fragmentUniforms.projectionmatrixz;
        float param_29 = 1.0;
        bool param_30 = true;
        vec3 ray_end_vs = ray_start_vs + (scene.reflection * GetLinearDepth(param_27, param_28, param_29, param_30));
        vec4 hit_color = vec4(0.0);
        vec3 param_31 = ray_start_vs;
        vec4 param_32 = freqLow_fragmentUniforms.packedprojection;
        vec3 ray_start = GetWindowPosZ(param_31, param_32) * vec3(freqLow_fragmentUniforms.resolutionscale.xy, 1.0);
        vec3 param_33 = ray_end_vs;
        vec4 param_34 = freqLow_fragmentUniforms.packedprojection;
        vec3 ray_end = GetWindowPosZ(param_33, param_34) * vec3(freqLow_fragmentUniforms.resolutionscale.xy, 1.0);
        vec3 ray_step = ((ray_end - ray_start) * (stride / float(max_steps))) / vec3(length(ray_end.xy - ray_start.xy));
        vec3 ray_pos = ray_start + (ray_step * jitter);
        float z_thickness = abs(ray_step.z);
        int hit = 0;
        vec3 best_hit = ray_pos;
        float prev_scene_z = ray_start.z;
        float _932;
        for (int curr_step = 0; curr_step < max_steps; curr_step += 4)
        {
            vec4 param_35 = vec4(ray_pos.xy + (ray_step.xy * float(curr_step + 1)), 0.0, 0.0);
            vec4 param_36 = vec4(ray_pos.xy + (ray_step.xy * float(curr_step + 2)), 0.0, 0.0);
            vec4 param_37 = vec4(ray_pos.xy + (ray_step.xy * float(curr_step + 3)), 0.0, 0.0);
            vec4 param_38 = vec4(ray_pos.xy + (ray_step.xy * float(curr_step + 4)), 0.0, 0.0);
            vec4 scene_z4 = vec4(1.0) - vec4(tex2Dlod(samp_tex3, param_35).x, tex2Dlod(samp_tex3, param_36).x, tex2Dlod(samp_tex3, param_37).x, tex2Dlod(samp_tex3, param_38).x);
            vec4 curr_step4 = vec4(1.0, 2.0, 3.0, 4.0) + vec4(float(curr_step));
            uvec4 z_test = mix(uvec4(0u), uvec4(1u), lessThan(abs(((ray_pos.zzzz + (ray_step.zzzz * curr_step4)) - scene_z4) - vec4(z_thickness)), vec4(z_thickness)));
            uint z_mask = (((z_test.x << uint(0)) | (z_test.y << uint(1))) | (z_test.z << uint(2))) | (z_test.w << uint(3));
            if (z_mask > 0u)
            {
                uint param_39 = z_mask;
                int first_hit = firstBitLow(param_39);
                if (first_hit > 0)
                {
                    _932 = scene_z4[max(0, (first_hit - 1))];
                }
                else
                {
                    _932 = prev_scene_z;
                }
                prev_scene_z = _932;
                best_hit = ray_pos + (ray_step * float((curr_step + first_hit) + 1));
                float z_after = scene_z4[first_hit] - best_hit.z;
                float z_before = (prev_scene_z - best_hit.z) + ray_step.z;
                float param_40 = z_after / (z_after - z_before);
                float w = saturate(param_40);
                vec3 prev_ray_pos = best_hit - ray_step;
                best_hit = (prev_ray_pos * w) + (best_hit * (1.0 - w));
                hit = curr_step + first_hit;
                break;
            }
            prev_scene_z = scene_z4.w;
        }
        if (hit > 0)
        {
            vec3 param_41 = vec3(best_hit.xy * freqLow_fragmentUniforms.resolutionscale.zw, best_hit.z);
            vec4 param_42 = freqLow_fragmentUniforms.windowpostoglobalx;
            vec4 param_43 = freqLow_fragmentUniforms.windowpostoglobaly;
            vec4 param_44 = freqLow_fragmentUniforms.windowpostoglobalz;
            vec4 param_45 = freqLow_fragmentUniforms.windowpostoglobalw;
            vec4 worldPosM = MatrixMul(param_41, param_42, param_43, param_44, param_45);
            worldPosM /= vec4(worldPosM.w);
            vec3 param_46 = worldPosM.xyz;
            vec4 param_47 = freqHigh_fragmentUniforms.prevglobalpostowindowx;
            vec4 param_48 = freqHigh_fragmentUniforms.prevglobalpostowindowy;
            vec4 param_49 = freqHigh_fragmentUniforms.prevglobalpostowindowz;
            vec4 param_50 = freqHigh_fragmentUniforms.prevglobalpostowindoww;
            vec4 tc_reproj = MatrixMul(param_46, param_47, param_48, param_49, param_50);
            vec2 _1058 = tc_reproj.xy / vec2(tc_reproj.w);
            tc_reproj = vec4(_1058.x, _1058.y, tc_reproj.z, tc_reproj.w);
            vec2 _1065 = (tc_reproj.xy * 0.5) + vec2(0.5);
            tc_reproj = vec4(_1065.x, _1065.y, tc_reproj.z, tc_reproj.w);
            vec2 _1074 = tc_reproj.xy * freqLow_fragmentUniforms.prevresolutionscale.xy;
            tc_reproj = vec4(_1074.x, _1074.y, tc_reproj.z, tc_reproj.w);
            vec4 param_51 = vec4(tc_reproj.xy, 0.0, 0.0);
            vec4 finalRefl = vec4(tex2Dlod(samp_tex5, param_51).xyz, 1.0);
            vec2 dist = ((tc_reproj.xy * freqLow_fragmentUniforms.prevresolutionscale.zw) * 2.0) - vec2(1.0);
            float param_52 = 1.0 - dot(dist, dist);
            float edge_atten = smoothstep(0.0, 0.5, saturate(param_52));
            float param_53 = (1.0 - (float(hit) / 16.0)) * 4.0;
            edge_atten *= saturate(param_53);
            hit_color = vec4(finalRefl.xyz, edge_atten);
        }
        float param_54 = 1.0 - ((1.0 - scene.smoothness) / (1.0 - smoothness_threshold));
        float param_55 = saturate(param_54);
        float smoothness_mask = saturate(param_55);
        float param_56 = (hit_color.w * smoothness_mask) * freqHigh_fragmentUniforms.ssrscale.x;
        hit_color.w = saturate(param_56);
        vec3 _1157 = max(vec3(0.0), (hit_color.xyz * hit_color.w) * scene.phongEnvBRDF);
        out_FragColor0 = vec4(_1157.x, _1157.y, _1157.z, out_FragColor0.w);
        float param_57 = hit_color.w;
        out_FragColor1.x = saturate(param_57);
    }
}




