#pragma language glsl4
#ifdef VERTEX
 vec4 position(mat4 transformProjection, vec4 vertexPosition) {return transformProjection * vertexPosition; }
#endif
#ifdef PIXEL
#define NUM_CONES 5
#define NUM_LIGHTS 1

uniform float z;

uniform vec3 lightPosition[NUM_LIGHTS];
uniform vec3 lightColor[NUM_LIGHTS];
uniform float lightPower[NUM_LIGHTS];
uniform float lightRange[NUM_LIGHTS];

uniform vec3 volumePosition = vec3(0);
uniform vec3 volumeScale;

uniform sampler3D occlusion;
uniform sampler3D diffuse;
uniform sampler3D normal;

// uniform sampler3D emissive1;
// uniform sampler3D emissive2;
// uniform sampler3D emissive3;
// uniform sampler3D emissive4;
// uniform sampler3D emissive5;
// uniform sampler3D emissive6;

const int voxelVolumeBits = 7;
uniform int voxelVolumeSize = 128;
uniform float voxelVolumeInverseSize; // Size of a voxel

vec2 tc;

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

float traceShadowCone(vec3 normal, vec3 from, vec3 to) {
  const float aperture = tan(radians(3.0));
  const float s = 0.33333;
  float doubledAperture = max(voxelVolumeInverseSize, 2.0 * aperture);
  from += normal * voxelVolumeInverseSize * 1.0;
  vec3 direction = to - from;
  float maxDistance = length(direction), 
        dist = 0.5 * voxelVolumeInverseSize,
        accumulator = 0.0;
  direction /= maxDistance;
  maxDistance = min(maxDistance, 1.41421356237);
  dist += voxelJitterNoise(vec4(from.xyz + to.xyz + normal.xyz, tc.x)).x * s * voxelVolumeInverseSize;
  vec3 position = from + (direction * dist);
  while ((accumulator < 1.0) && (dist < maxDistance)) {
    float diameter = max(voxelVolumeInverseSize * 0.5, doubledAperture * dist);
    float mipMapLevel = max(0.0, log2((diameter * float(voxelVolumeSize)) + 0.0));
    accumulator += (1.0 - accumulator) * clamp(textureLod(occlusion, position, mipMapLevel).r , 0.0, 1.0);
    dist += max(diameter, voxelVolumeInverseSize) * s*0.5;
    position = from + (direction * dist);
  }
  return clamp(1.0 - accumulator, 0.0, 1.0);
}

float att (float dist, float radius) {
  return clamp(1.0 - (dist*dist)/(radius*radius), 0.0, 1.0);
}

vec4 effect(vec4 color, sampler2D tex, vec2 textureCoords, vec2 screen_coords) {
  vec2 coord    = screen_coords / love_ScreenSize.xy;
  tc = coord;

  vec3 position = vec3(textureCoords,z);
  vec3 worldPosition = (position.xyz-0.5)*volumeScale*2+volumePosition;
  vec4 d  = Texel(diffuse, position);

  vec4 nn = Texel(normal, position);
  vec3 n = nn.xyz*2-1;

  vec4 result=vec4(0);

  for (int i = 0; i < NUM_LIGHTS; i++) {
    vec3 lightPositionVoxel = (lightPosition[i]-volumePosition)/(volumeScale*2)+0.5;
    vec3 l = normalize(lightPositionVoxel - position);
    float dist = distance( lightPosition[i] , worldPosition );
    float cosTheta = dot(n,  l);
    vec3 col = vec3(1);
    vec3 light =  lightColor[i]*lightPower[i] * cosTheta * att(dist,lightRange[i]/2);
    // if (dist<lightRange[i]) {
      vec3 shadow = vec3(traceShadowCone(n,position,lightPositionVoxel));
      // -vec3(max(0,dot(l,-normalize(vec3(1)))))
      // result+=vec4(vec3(cosTheta),1);
      result+=d*vec4(light*shadow,1);
    // }

  }
  return result;
}

#endif
