// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/ui/lib/escher/acceleration/uniform_grid.h"

#include "src/ui/lib/escher/geometry/intersection.h"
#include "src/ui/lib/escher/renderer/batch_gpu_uploader.h"
#include "src/ui/lib/escher/vk/buffer.h"

namespace escher {

namespace {

inline float DistanceToPlane(float D, float O, float pos) {
  return D != 0.f ? (pos - O) / D : 100000000.f;
}

inline bool GridCellIsValid(glm::ivec3 coordinates, int32_t resolution) {
  if (coordinates.x < 0 || coordinates.x >= resolution)
    return false;
  if (coordinates.y < 0 || coordinates.y >= resolution)
    return false;
  if (coordinates.z < 0 || coordinates.z >= resolution)
    return false;
  return true;
}

inline BoundingBox GetTriangleBoundingBox(glm::vec3 v1, glm::vec3 v2, glm::vec3 v3) {
  float min_x = glm::min(glm::min(v1.x, v2.x), v3.x);
  float min_y = glm::min(glm::min(v1.y, v2.y), v3.y);
  float min_z = glm::min(glm::min(v1.z, v2.z), v3.z);

  float max_x = glm::max(glm::max(v1.x, v2.x), v3.x);
  float max_y = glm::max(glm::max(v1.y, v2.y), v3.y);
  float max_z = glm::max(glm::max(v1.z, v2.z), v3.z);

  return BoundingBox(glm::vec3(min_x, min_y, min_z), glm::vec3(max_x, max_y, max_z));
}

}  // anonymous namespace

void UniformGrid::Construct(const std::vector<glm::vec3>& positions,
                            const std::vector<uint32_t>& indices, const BoundingBox& bounding_box) {
  uint32_t num_indices = indices.size();
  uint32_t num_vertices = positions.size();
  uint32_t num_triangles = num_indices / 3;

  // Set resolution to (roughly) the cube root of (roughly) num_triangles, so that the
  // number of cells is proportional to the number of triangles. Using the cubed root of
  // the total number of triangles has been shown to be a good guideline for uniform grid
  // construction by various researchers:
  // https://pharr.org/matt/blog/images/pbr-2001.pdf
  resolution_ = static_cast<uint32_t>(glm::max(cbrtf(static_cast<float>(num_triangles)), 1.f));
  FXL_DCHECK(resolution_ > 0);

  // Save the vertex and bounding box information..
  vertices_ = std::vector<glm::vec3>(positions);
  bounds_ = bounding_box;

  // Calculate the extent for cells.
  glm::vec3 cell_extent = bounds_.extent() / static_cast<float>(resolution_) + glm::vec3(kEpsilon);
  FXL_DCHECK(glm::all(glm::greaterThan(cell_extent, glm::vec3(kEpsilon))));

  // Assign all of the triangles to cells that they overlap.
  for (uint32_t i = 0; i < num_indices; i += 3) {
    uint32_t index_1 = indices[i];
    uint32_t index_2 = indices[i + 1];
    uint32_t index_3 = indices[i + 2];

    glm::vec3 v1 = vertices_[index_1];
    glm::vec3 v2 = vertices_[index_2];
    glm::vec3 v3 = vertices_[index_3];

    BoundingBox triangle_bbox = GetTriangleBoundingBox(v1, v2, v3);
    FXL_DCHECK(!triangle_bbox.is_empty());

    glm::ivec3 cell_min = glm::floor(triangle_bbox.min() - bounds_.min()) / cell_extent;
    glm::ivec3 cell_max = glm::floor(triangle_bbox.max() - bounds_.min()) / cell_extent;
    for (int32_t x = cell_min.x; x <= cell_max.x; x++) {
      for (int32_t y = cell_min.y; y <= cell_max.y; y++) {
        for (int32_t z = cell_min.z; z <= cell_max.z; z++) {
          // Lazily create each cell once we find a triangle that intersects it.
          glm::ivec3 key(x, y, z);
          if (!cell_hash_.count(key)) {
            vec3 min = bounds_.min() + glm::vec3(key) * cell_extent;
            vec3 max = min + cell_extent;
            cell_hash_[key].set_bounds(BoundingBox(min, max));
          }

          cell_hash_[glm::ivec3(x, y, z)].AddTriangle(index_1, index_2, index_3);
        }
      }
    }
  }
}

bool UniformGrid::Intersect(const ray4& ray, float* out_distance) const {
  FXL_DCHECK(out_distance);

  // Get ray properties.
  const glm::vec4 O = ray.origin;
  const glm::vec4 D = ray.direction;

  // Check that the ray intersects the bounding box first.
  Interval interval;
  if (!IntersectRayBox(ray, bounds_, &interval)) {
    return false;
  }
  glm::vec4 hit = ray.At(interval.min());
  glm::vec3 cell_extent = bounds_.extent() / static_cast<float>(resolution_) + glm::vec3(kEpsilon);

  // Compute the coordinates of the current cell
  glm::vec3 min = bounds_.min();
  glm::ivec3 cell_coordinates = (vec3(hit) - min) / cell_extent;
  FXL_DCHECK(glm::all(glm::greaterThanEqual(cell_coordinates, glm::ivec3(0))));

  int px = glm::sign(D.x);
  int py = glm::sign(D.y);
  int pz = glm::sign(D.z);
  glm::ivec3 signs = glm::sign(D);
  glm::vec3 delta = glm::vec3(signs) * cell_extent / vec3(D + vec4(kEpsilon));

  float x_offset = (px > 0.f) ? px : 0.f;
  float y_offset = (py > 0.f) ? py : 0.f;
  float z_offset = (pz > 0.f) ? pz : 0.f;

  float next_x =
      DistanceToPlane(D.x, hit.x, min.x + (cell_coordinates.x + x_offset) * cell_extent.x);
  float next_y =
      DistanceToPlane(D.y, hit.y, min.y + (cell_coordinates.y + y_offset) * cell_extent.y);
  float next_z =
      DistanceToPlane(D.z, hit.z, min.z + (cell_coordinates.z + z_offset) * cell_extent.z);
  FXL_DCHECK(next_x >= 0.f) << next_x;
  FXL_DCHECK(next_y >= 0.f) << next_y;
  FXL_DCHECK(next_z >= 0.f) << next_z;

  // If we go beyond the extent of the uniform grid without finding a hit,
  // then stop looping.
  while (GridCellIsValid(cell_coordinates, resolution_)) {
    // The cell map is sparse, and so cells with no triangles that overlap
    // with them are not created.
    if (cell_hash_.count(cell_coordinates)) {
      const Cell& cell = cell_hash_.at(cell_coordinates);

      // Intersect the ray with the current cell, return true if there's a hit,
      // otherwise continue on to the next cell.
      if (cell.Intersect(ray, vertices_.data(), out_distance)) {
        return true;
      }
    }

    // Find the next cell to check.
    if (next_x < next_y && next_x < next_z) {
      cell_coordinates.x += signs.x;
      next_x += delta.x;
    } else if (next_y < next_x && next_y < next_z) {
      cell_coordinates.y += signs.y;
      next_y += delta.y;
    } else {
      cell_coordinates.z += signs.z;
      next_z += delta.z;
    }

    FXL_DCHECK(!std::isnan(next_x) && !std::isinf(next_x));
    FXL_DCHECK(!std::isnan(next_y) && !std::isinf(next_y));
    FXL_DCHECK(!std::isnan(next_z) && !std::isinf(next_z));
  }

  // No hit.
  return false;
}

// Iterates over all of the triangles that overlap the cell and performs intersection
// tests on each of them. Returns true if any of the triangles are intersected. The
// out distance will be the distance to the closest triangle hit. Note that we cannot
// simply return early as soon as any triangle hit is found, because it might not be
// the closest triangle.
bool UniformGrid::Cell::Intersect(const ray4& ray, const vec3* vertices,
                                  float* out_distance) const {
  FXL_DCHECK(vertices);
  FXL_DCHECK(out_distance);
  FXL_DCHECK(indices_.size() % 3 == 0);
  FXL_DCHECK(!bounds_.is_empty());

  *out_distance = FLT_MAX;
  for (uint32_t i = 0; i < indices_.size(); i += 3) {
    const vec3& v0 = vertices[indices_[i]];
    const vec3& v1 = vertices[indices_[i + 1]];
    const vec3& v2 = vertices[indices_[i + 2]];

    float distance;
    if (IntersectRayTriangle(ray, v0, v1, v2, &distance)) {
      // Intersection only counts if it occcurs _within_ the current cell. Since a triangle
      // can overlap multiple cells, it's necessary to do this check before considering it
      // officially hit.
      if (bounds_.Contains(ray.At(distance))) {
        if (distance < *out_distance) {
          *out_distance = distance;
        }
      }
    }
  }

  // If there is a hit, the out distance will be less than FLT_MAX.
  return *out_distance < FLT_MAX;
}

}  // namespace escher
