
uniform sampler2D g_color;
uniform sampler2D g_normal;
uniform sampler2D g_position;

#if defined shadows_enabled
    uniform sampler2DShadow shadow_map;
    uniform mat4 shadow_projection;
    uniform mat4 shadow_matrix;
    uniform mat4 view_matrix_inv;
#endif
#if defined ssao_enabled
    uniform sampler2D g_ssao;
#endif
uniform sampler2D g_highlight;
uniform sampler2D g_highlight_blur;

layout (location = 0) out vec4 frag_color;

const vec3 light_dir = normalize(vec3(-1.0, 3.0, 1.0));

#if defined shadows_enabled
    float get_shadow_factor(vec4 shadow_pos) {
        vec3 projected_coords = shadow_pos.xyz / shadow_pos.w;
        vec3 uvcoords = projected_coords.xyz * 0.5 + 0.5;
        if (uvcoords.z > 1.0) {
            return 1.0;
        }
        float result = 0.0;
        vec2 tsize = textureSize(shadow_map, 0).xy;
        float bias = 0.0007 * (4096.0 / tsize.x);
        vec2 size = 1.0 / vec2(tsize);
        for (int x = -1; x <= 1; x++) {
            for (int y = -1; y <= 1; y++) {
                vec2 offset = vec2(x, y) * size;
                float depth = texture(shadow_map, vec3(uvcoords.xy + offset, uvcoords.z + bias));
                result += depth;
            }
        }
        return (result/9.0) * 0.7 + 0.3;
    }
#endif

void main() {
    frag_color = vec4(
        texelFetch(g_color, ivec2(gl_FragCoord.xy), 0).rgb,
        1.0
    );
    vec3 normal = texelFetch(g_normal, ivec2(gl_FragCoord.xy), 0).rgb * 2.0 - 1.0;
    vec3 diffuse = max(dot(normal, light_dir), 0.0) * vec3(0.85);
    frag_color.rgb *= 0.15 + diffuse;

    #if defined shadows_enabled
        vec3 pos = texelFetch(g_position, ivec2(gl_FragCoord.xy), 0).xyz;
        vec4 shadow_pos = shadow_projection
                    * shadow_matrix
                    * (view_matrix_inv * vec4(pos, 1.0));
        frag_color.rgb *= get_shadow_factor(shadow_pos);
    #endif

    vec2 screen_size = vec2(textureSize(g_color, 0).xy);

    // Gamma correction
    frag_color.rgb = pow(frag_color.rgb, vec3(1.0 / 2.6));

    #if defined ssao_enabled
    float ssao = texture(g_ssao, vec2(gl_FragCoord.xy) / screen_size, 0).r;
    frag_color.rgb *= ssao;
    #endif

    vec3 highlight = texture(g_highlight, vec2(gl_FragCoord.xy) / screen_size).rgb;
    vec3 highlight_blur = texture(g_highlight_blur, vec2(gl_FragCoord.xy) / screen_size).rgb;
    frag_color.rgb += max(vec3(0.0), highlight_blur - highlight) * 3.0;
}
