#pragma language glsl3
#ifdef VERTEX

out vec3 direction;
out vec3 eyePos;

uniform vec3 eyePosition;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform vec3 volumePosition = vec3(0);
uniform vec3 volumeScale;

vec4 position(mat4 transform_projection, vec4 vertex_position) {
  // Translate the cube to center it at the origin.
  // volumePosition = vec3(0.5) - volumeScale * 0.5;

  // Compute eye position and ray directions in the unit cube space
  eyePos = (eyePosition - volumePosition) / volumeScale;
  direction = vertex_position.xyz - eyePos;

  return projectionMatrix * viewMatrix *
         vec4(vertex_position.xyz * volumeScale + volumePosition, 1);
}

#endif

#ifdef PIXEL
in vec3 direction;
in vec3 eyePos;
uniform float lod = 0;
uniform bool average = true;
uniform bool renderOcclusion;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform sampler3D occlusion;
uniform sampler3D volume0;
uniform sampler3D volume1;
uniform sampler3D volume2;
uniform sampler3D volume3;
uniform sampler3D volume4;
uniform sampler3D volume5;
uniform sampler3D volume6;

uniform float stepSize = 0.002f;
uniform float maxSamples = 1000;

struct Ray {
  vec3 Origin;
  vec3 Dir;
};

struct AABB {
  vec3 Min;
  vec3 Max;
};

bool IntersectBox(Ray r, AABB aabb, out float t0, out float t1) {
  vec3 invR = 1.0 / r.Dir;
  // these are equation 2 of the (2) article mentioned on top of page
  vec3 tbot = invR * (aabb.Min - r.Origin);
  vec3 ttop = invR * (aabb.Max - r.Origin);
  vec3 tmin = min(ttop, tbot);
  vec3 tmax = max(ttop, tbot);
  // find the minimum ray t value between x, y, and z
  vec2 t = max(tmin.xx, tmin.yz);
  t0 = max(t.x, t.y);
  // find maximum ray t value between x, y, and z
  t = min(tmax.xx, tmax.yz);
  t1 = min(t.x, t.y);

  return t0 <= t1;
}

vec4 cubeSample(vec3 dir,vec3 pos,float lod){
  vec4 sample;
  vec3 vAbs = abs(dir);

  if (vAbs.z >= vAbs.x && vAbs.z >= vAbs.y) {
    sample = dir.z < 0.0 ? textureLod(volume6,pos,lod) : textureLod(volume3,pos,lod);
    // return vec4(0);
  } else if (vAbs.y >= vAbs.x) {
    sample = dir.y < 0.0 ? textureLod(volume5,pos,lod) : textureLod(volume2,pos,lod);
    // if (dir.y > 0.0){
    // }
      // return vec4(0);
  } else {
    sample = dir.x < 0.0 ? textureLod(volume4,pos,lod) : textureLod(volume1,pos,lod);
    // return vec4(0);
  }

  return sample/sample.a;
}
vec3 getDirectionWeights(vec3 direction){
  return direction * direction;
}

vec4 effect(vec4 color, sampler2D texturee, vec2 textureCoords, vec2 screen_coords) {
  vec2 coord = screen_coords / love_ScreenSize.xy;
  vec4 result = vec4(0);

  Ray eye = Ray(eyePos, normalize(direction));
  AABB aabb = AABB(vec3(-1.0), vec3(+1.0));

  float tnear, tfar;
  if (IntersectBox(eye, aabb, tnear, tfar)) {
    if (tnear < 0.0)
    tnear = 0.0;

    vec3 rayStart = eye.Origin + eye.Dir * tnear;
    vec3 rayStop = eye.Origin + eye.Dir * tfar;

    rayStart = 0.5 * (rayStart + 1.0);
    rayStop = 0.5 * (rayStop + 1.0);

    vec3 pos = rayStart;
    vec3 step = normalize(rayStop - rayStart) * stepSize;
    float travel = distance(rayStop, rayStart);

    for (int i = 0; i < maxSamples && travel > 0.0; ++i, pos += step, travel -= stepSize) {
      vec3 samplePoint = pos;
      float occ = textureLod(occlusion,pos,lod).r;
      if (occ>0){
        if (renderOcclusion){
          return vec4(vec3(occ),1);
        }
        if (lod<1) {
          vec4 voxel = texture(volume0,pos);
          return voxel;
        }else{ 
          vec4 face;
          if (average==false){
            float size = 128/pow(2,int(lod));
            vec3 center = ((floor(pos*size)+0.5)/size)*2-1;
            IntersectBox(eye,AABB(center-vec3(1)/size,center+vec3(1)/size),tnear,tfar);
            vec3 intersectPos = eyePos+tnear*normalize(direction);
            face = cubeSample(center-intersectPos,pos, lod-1);
          }else{
            bvec3 negativeDirection = lessThan(direction, vec3(0.0));
            vec3 weight = getDirectionWeights(direction);
            face = (
              (negativeDirection.x ? textureLod(volume4, pos, lod-1) : textureLod(volume1, pos, lod-1)) *weight.x +
              (negativeDirection.y ? textureLod(volume5, pos, lod-1) : textureLod(volume2, pos, lod-1)) *weight.y +
              (negativeDirection.z ? textureLod(volume6, pos, lod-1) : textureLod(volume3, pos, lod-1)) *weight.z
            );
            face/=face.a;
          }
          if (face.a>0){
            face.a=1;
            return face;
          }
        }
      }
    }
  }
  return result;
}
#endif
