layout(std140) uniform param {
  float type;
  float prev_type;
  float transition;

  float bounds_fog;
  vec4  bounds_pos;  /* xy: chunk, zw: fract */
  vec2  bounds_size;
} p;

in vec2 v_pos;
in vec2 v_uv;

out vec4 o_color;

const float EPSILON = 1e-4;

/* ---- UTILITY FUNCTIONS ---- */
vec3 get_ray_direction(in vec2 p, in vec2 s, float fov) {
  return normalize(vec3(p*s/2., s.y/tan(radians(fov)/2.)));
}
float rand(in vec2 p) {
  /* https://qiita.com/shimacpyon/items/d15dee44a0b8b3883f76 */
  return fract(sin(dot(p ,vec2(12.9898,78.233))) * 43758.5453);
}
float noise(in vec3 p) {
  /* https://www.shadertoy.com/view/4dS3Wd */
  const vec3 step = vec3(110, 241, 171);

  vec3 i = floor(p);
  vec3 f = fract(p);

  float n = dot(i, step);

  vec3 u = f * f * (3.0 - 2.0 * f);

  const vec3 e1 = vec3(1., 0., 0.);
  const vec3 e2 = vec3(0., 1., 0.);
  const vec3 e3 = vec3(0., 0., 1.);
  return mix(mix(mix(rand(dot(step, vec3(0.))+vec2(n)), rand(dot(step, e1      )+vec2(n)), u.x),
                 mix(rand(dot(step,       e2)+vec2(n)), rand(dot(step, e1+e2   )+vec2(n)), u.x), u.y),
             mix(mix(rand(dot(step,       e3)+vec2(n)), rand(dot(step, e1+e3   )+vec2(n)), u.x),
                 mix(rand(dot(step,    e2+e3)+vec2(n)), rand(dot(step, e1+e2+e3)+vec2(n)), u.x), u.y), u.z);
}
float fbm15(in vec3 p) {
  float v = 0., a = .5, f = 0.;

  for (int i = 0; i < 15; ++i) {
    v += a*noise(p);
    p *= 2.;
    a *= .5;
  }
  return v;
}

/* ---- SCENE: white cloud ---- */
vec4 white_cloud(void) {
  vec3 dir = get_ray_direction(v_uv, uni.resolution, 60.);
  vec3 eye = vec3(0.);

  eye.xy += uni.pos.xy + uni.pos.zw;

  float a = 0.;
  for (float i = 1.; i <= 5.; ++i) {
    a += fbm15(eye + dir*i/3.) / pow(i, 2.);
  }
  return vec4(.6, .6, .5, clamp(pow(a, 8.), 0., .8));
}

/* ---- SCENE: bounds fog ---- */
vec4 bounds_fog(void) {
  float aa = uni.aa * 100;

  vec2 pos;
  pos.x = (p.bounds_pos.x - uni.pos.x) + (p.bounds_pos.z - uni.pos.z);
  pos.y = (p.bounds_pos.y - uni.pos.y) + (p.bounds_pos.w - uni.pos.w);
  pos   = (uni.proj * uni.cam * vec4(pos, 0., 1.)).xy;

  vec2 size = (uni.proj * uni.cam * vec4(p.bounds_size, 0., 0.)).xy;

  vec2 area_pos = v_uv - pos;

  float r =
      smoothstep(size.x-aa, size.x+aa, abs(area_pos.x)) +
      smoothstep(size.y-aa, size.y+aa, abs(area_pos.y));

  float a = fbm15(vec3(area_pos, abs(fract(uni.time/60.)*2.-1.)));

  return vec4(1.) * a * r * p.bounds_fog;
}

vec4 scene(in float type) {
  return
      type == 1.? white_cloud():
      vec4(0.);
}
void main(void) {
  vec4 prev = vec4(0.), next = vec4(0.);
  if (p.transition > 0.) next = clamp(scene(p.type), 0., 1.);
  if (p.transition < 1.) prev = clamp(scene(p.prev_type), 0., 1.);
  o_color = mix(prev, next, p.transition);

  o_color += bounds_fog();
}