#pragma language glsl3
#ifdef VERTEX
 vec4 position(mat4 transform_projection, vec4 vertex_position) {return transform_projection * vertex_position; }
#endif

#ifdef PIXEL
#define SAMPLE_COUNT 32
uniform vec3 samples[SAMPLE_COUNT];
uniform vec3 eyePosition;
uniform vec3 volumePosition = vec3(0);
uniform vec3 volumeScale;

uniform sampler2D gbuffer_diffuse;
uniform sampler2D gbuffer_normal;
uniform sampler2D gbuffer_position;

uniform sampler2D gbuffer_depth;
uniform sampler2D gbuffer_traced;

uniform float ambientLight;
uniform vec3 ambientColor;

mat4 bias = mat4(0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0,
                 0.5, 0.5, 0.5, 1.0);
vec4 voxelJitterNoise(vec4 p4) {
  p4 = fract(p4 * vec4(443.897, 441.423, 437.195, 444.129));
  p4 += dot(p4, p4.wzxy + vec4(19.19));
  return fract((p4.xxyz + p4.yzzw) * p4.zywx);
}
vec3 getDirectionWeights(vec3 direction) { return direction * direction; }
vec4 samp(sampler3D tex,vec3 point){
  return (textureLod(tex,point,0)*11 +
          textureLod(tex,point,1)*1 )/12;
}

uniform float zNear = 0.0001;
uniform float zFar = 4.0;
float linearDepth(float depthSample)
{
    depthSample = 2.0 * depthSample - 1.0;
    float zLinear = 2.0 * zNear * zFar / (zFar + zNear - depthSample * (zFar - zNear));
    return zLinear;
}
float depthSample(float linearDepth)
{
    float nonLinearDepth = (zFar + zNear - 2.0 * zNear * zFar / linearDepth) / (zFar - zNear);
    nonLinearDepth = (nonLinearDepth + 1.0) / 2.0;
    return nonLinearDepth;
}

vec4 effect(vec4 color, sampler2D tex, vec2 textureCoords, vec2 screen_coords) {

  vec2 coord = screen_coords / love_ScreenSize.xy;
  vec4 direct = Texel(tex, textureCoords);
  vec3 position = Texel(gbuffer_position, textureCoords).xyz;
  vec4 diffuse = Texel(gbuffer_diffuse, textureCoords);
  vec4 normal = Texel(gbuffer_normal, textureCoords);
  vec4 traced= Texel(gbuffer_traced,   textureCoords);
  float depth= Texel(gbuffer_depth,   textureCoords).r;

  vec3 voxelPosition = (position-volumePosition)/(volumeScale*2)+0.5;
  vec4 noise = voxelJitterNoise(vec4(position + (vec3(gl_FragCoord.xyz) * 1.0), fract(coord.x * 0.01) * 100.0));
  vec3 direction = normalize(eyePosition-position);
  vec3  directionWeights = getDirectionWeights(direction);
  bvec3 negativeDirection = lessThan(direction, vec3(0.0));
  vec3 samplePoint=voxelPosition;//+noise.xyz/128;

  if (diffuse.a == 0) {
    discard;
  }

  vec4 result = vec4(
    ambientLight * ambientColor * diffuse.rgb+ 
    diffuse.rgb* direct.rgb 
  ,1)+ traced ;

  float sum = 0.0;
  
  for (int i = 0; i < SAMPLE_COUNT; i++) {
    float sampleDepth = Texel(gbuffer_depth, textureCoords + samples[i].xy / depth).r;
    
    float diff = depth - sampleDepth;
    float rangeCheck = smoothstep(0.0, 1.0, 16 / abs(depth - sampleDepth));
    diff *=200;
    if (diff<0.01){
      sum += (clamp(diff, -1.0, 1.0) * samples[i].z / (abs(diff)+0.05));
    }

    // occlusion       += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck;  
  }

  
  sum = clamp(1.0 - sum * 12.0, 0.0, 1.0);
  vec4 ssao = vec4(vec3(sum),1);
  return traced*ssao;//;//vec4(pow(result.rgb / (result.rgb + vec3(1.0)), vec3(2.2)),result.a);
}

#endif
