// Copyright 2013 The Flutter 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 "impeller/display_list/display_list_vertices_geometry.h"

#include "impeller/core/device_buffer.h"
#include "impeller/entity/contents/content_context.h"
#include "impeller/entity/entity.h"
#include "impeller/entity/position_color.vert.h"
#include "impeller/entity/texture_fill.vert.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/point.h"
#include "impeller/renderer/render_pass.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkRect.h"

namespace impeller {

static Rect ToRect(const SkRect& rect) {
  return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
}

// Fan mode isn't natively supported. Unroll into triangle mode by
// manipulating the index array.
//
// In Triangle fan, the first vertex is shared across all triangles, and then
// each sliding window of two vertices plus that first vertex defines a
// triangle.
static std::vector<uint16_t> fromFanIndices(
    const flutter::DlVertices* vertices) {
  FML_DCHECK(vertices->vertex_count() >= 3);
  FML_DCHECK(vertices->mode() == flutter::DlVertexMode::kTriangleFan);

  std::vector<uint16_t> indices;

  // Un-fan index buffer if provided.
  if (vertices->index_count() > 0) {
    auto* dl_indices = vertices->indices();
    auto center_point = dl_indices[0];
    for (int i = 1; i < vertices->index_count() - 1; i++) {
      indices.push_back(center_point);
      indices.push_back(dl_indices[i]);
      indices.push_back(dl_indices[i + 1]);
    }
  } else {
    // If indices were not provided, create an index buffer that unfans
    // triangles instead of re-writing points, colors, et cetera.
    for (int i = 1; i < vertices->vertex_count() - 1; i++) {
      indices.push_back(0);
      indices.push_back(i);
      indices.push_back(i + 1);
    }
  }
  return indices;
}

/////// Vertices Geometry ///////

// static
std::shared_ptr<VerticesGeometry> DLVerticesGeometry::MakeVertices(
    const flutter::DlVertices* vertices) {
  return std::make_shared<DLVerticesGeometry>(vertices);
}

DLVerticesGeometry::DLVerticesGeometry(const flutter::DlVertices* vertices)
    : vertices_(vertices) {
  NormalizeIndices();
}

DLVerticesGeometry::~DLVerticesGeometry() = default;

void DLVerticesGeometry::NormalizeIndices() {
  // Convert triangle fan if present.
  if (vertices_->mode() == flutter::DlVertexMode::kTriangleFan) {
    normalized_indices_ = fromFanIndices(vertices_);
    return;
  }

  auto index_count = vertices_->index_count();
  auto vertex_count = vertices_->vertex_count();
  if (index_count != 0 || vertex_count == 0) {
    return;
  }
  normalized_indices_.reserve(vertex_count);
  for (auto i = 0; i < vertex_count; i++) {
    normalized_indices_.push_back(i);
  }
}

static PrimitiveType GetPrimitiveType(const flutter::DlVertices* vertices) {
  switch (vertices->mode()) {
    case flutter::DlVertexMode::kTriangles:
      return PrimitiveType::kTriangle;
    case flutter::DlVertexMode::kTriangleStrip:
      return PrimitiveType::kTriangleStrip;
    case flutter::DlVertexMode::kTriangleFan:
      // Unrolled into triangle mode.
      return PrimitiveType::kTriangle;
  }
}

std::optional<Rect> DLVerticesGeometry::GetTextureCoordinateCoverge() const {
  if (!HasTextureCoordinates()) {
    return std::nullopt;
  }
  auto vertex_count = vertices_->vertex_count();
  auto* dl_texture_coordinates = vertices_->texture_coordinates();
  if (vertex_count == 0) {
    return std::nullopt;
  }

  auto left = dl_texture_coordinates[0].x();
  auto top = dl_texture_coordinates[0].y();
  auto right = dl_texture_coordinates[0].x();
  auto bottom = dl_texture_coordinates[0].y();

  for (auto i = 0; i < vertex_count; i++) {
    left = std::min(left, dl_texture_coordinates[i].x());
    top = std::min(top, dl_texture_coordinates[i].y());
    right = std::max(right, dl_texture_coordinates[i].x());
    bottom = std::max(bottom, dl_texture_coordinates[i].y());
  }
  return Rect::MakeLTRB(left, top, right, bottom);
}

bool DLVerticesGeometry::HasVertexColors() const {
  return vertices_->colors() != nullptr;
}

bool DLVerticesGeometry::HasTextureCoordinates() const {
  return vertices_->texture_coordinates() != nullptr;
}

GeometryResult DLVerticesGeometry::GetPositionBuffer(
    const ContentContext& renderer,
    const Entity& entity,
    RenderPass& pass) {
  auto index_count = normalized_indices_.size() == 0
                         ? vertices_->index_count()
                         : normalized_indices_.size();
  auto vertex_count = vertices_->vertex_count();
  auto* dl_indices = normalized_indices_.size() == 0
                         ? vertices_->indices()
                         : normalized_indices_.data();
  auto* dl_vertices = vertices_->vertices();

  size_t total_vtx_bytes = vertex_count * sizeof(float) * 2;
  size_t total_idx_bytes = index_count * sizeof(uint16_t);

  DeviceBufferDescriptor buffer_desc;
  buffer_desc.size = total_vtx_bytes + total_idx_bytes;
  buffer_desc.storage_mode = StorageMode::kHostVisible;

  auto buffer =
      renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);

  if (!buffer->CopyHostBuffer(reinterpret_cast<const uint8_t*>(dl_vertices),
                              Range{0, total_vtx_bytes}, 0)) {
    return {};
  }
  if (!buffer->CopyHostBuffer(
          reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
          Range{0, total_idx_bytes}, total_vtx_bytes)) {
    return {};
  }

  return GeometryResult{
      .type = GetPrimitiveType(vertices_),
      .vertex_buffer =
          {
              .vertex_buffer = {.buffer = buffer,
                                .range = Range{0, total_vtx_bytes}},
              .index_buffer = {.buffer = buffer,
                               .range =
                                   Range{total_vtx_bytes, total_idx_bytes}},
              .index_count = index_count,
              .index_type = IndexType::k16bit,
          },
      .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
                   entity.GetTransformation(),
      .prevent_overdraw = false,
  };
}

GeometryResult DLVerticesGeometry::GetPositionColorBuffer(
    const ContentContext& renderer,
    const Entity& entity,
    RenderPass& pass) {
  using VS = GeometryColorPipeline::VertexShader;

  auto index_count = normalized_indices_.size() == 0
                         ? vertices_->index_count()
                         : normalized_indices_.size();
  auto vertex_count = vertices_->vertex_count();
  auto* dl_indices = normalized_indices_.size() == 0
                         ? vertices_->indices()
                         : normalized_indices_.data();
  auto* dl_vertices = vertices_->vertices();
  auto* dl_colors = vertices_->colors();

  std::vector<VS::PerVertexData> vertex_data(vertex_count);
  {
    for (auto i = 0; i < vertex_count; i++) {
      auto dl_color = dl_colors[i];
      auto color = Color(dl_color.getRedF(), dl_color.getGreenF(),
                         dl_color.getBlueF(), dl_color.getAlphaF())
                       .Premultiply();
      auto sk_point = dl_vertices[i];
      vertex_data[i] = {
          .position = Point(sk_point.x(), sk_point.y()),
          .color = color,
      };
    }
  }

  size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
  size_t total_idx_bytes = index_count * sizeof(uint16_t);

  DeviceBufferDescriptor buffer_desc;
  buffer_desc.size = total_vtx_bytes + total_idx_bytes;
  buffer_desc.storage_mode = StorageMode::kHostVisible;

  auto buffer =
      renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);

  if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
                              Range{0, total_vtx_bytes}, 0)) {
    return {};
  }
  if (!buffer->CopyHostBuffer(
          reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
          Range{0, total_idx_bytes}, total_vtx_bytes)) {
    return {};
  }

  return GeometryResult{
      .type = GetPrimitiveType(vertices_),
      .vertex_buffer =
          {
              .vertex_buffer = {.buffer = buffer,
                                .range = Range{0, total_vtx_bytes}},
              .index_buffer = {.buffer = buffer,
                               .range =
                                   Range{total_vtx_bytes, total_idx_bytes}},
              .index_count = index_count,
              .index_type = IndexType::k16bit,
          },
      .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
                   entity.GetTransformation(),
      .prevent_overdraw = false,
  };
}

GeometryResult DLVerticesGeometry::GetPositionUVBuffer(
    Rect texture_coverage,
    Matrix effect_transform,
    const ContentContext& renderer,
    const Entity& entity,
    RenderPass& pass) {
  using VS = TexturePipeline::VertexShader;

  auto index_count = normalized_indices_.size() == 0
                         ? vertices_->index_count()
                         : normalized_indices_.size();
  auto vertex_count = vertices_->vertex_count();
  auto* dl_indices = normalized_indices_.size() == 0
                         ? vertices_->indices()
                         : normalized_indices_.data();
  auto* dl_vertices = vertices_->vertices();
  auto* dl_texture_coordinates = vertices_->texture_coordinates();

  auto size = texture_coverage.size;
  auto origin = texture_coverage.origin;
  std::vector<VS::PerVertexData> vertex_data(vertex_count);
  {
    for (auto i = 0; i < vertex_count; i++) {
      auto sk_point = dl_vertices[i];
      auto texture_coord = dl_texture_coordinates[i];
      auto uv = effect_transform *
                Point((texture_coord.x() - origin.x) / size.width,
                      (texture_coord.y() - origin.y) / size.height);
      // From experimentation we need to clamp these values to < 1.0 or else
      // there can be flickering.
      vertex_data[i] = {
          .position = Point(sk_point.x(), sk_point.y()),
          .texture_coords =
              Point(std::clamp(uv.x, 0.0f, 1.0f - kEhCloseEnough),
                    std::clamp(uv.y, 0.0f, 1.0f - kEhCloseEnough)),
      };
    }
  }

  size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData);
  size_t total_idx_bytes = index_count * sizeof(uint16_t);

  DeviceBufferDescriptor buffer_desc;
  buffer_desc.size = total_vtx_bytes + total_idx_bytes;
  buffer_desc.storage_mode = StorageMode::kHostVisible;

  auto buffer =
      renderer.GetContext()->GetResourceAllocator()->CreateBuffer(buffer_desc);

  if (!buffer->CopyHostBuffer(reinterpret_cast<uint8_t*>(vertex_data.data()),
                              Range{0, total_vtx_bytes}, 0)) {
    return {};
  }
  if (!buffer->CopyHostBuffer(
          reinterpret_cast<uint8_t*>(const_cast<uint16_t*>(dl_indices)),
          Range{0, total_idx_bytes}, total_vtx_bytes)) {
    return {};
  }

  return GeometryResult{
      .type = GetPrimitiveType(vertices_),
      .vertex_buffer =
          {
              .vertex_buffer = {.buffer = buffer,
                                .range = Range{0, total_vtx_bytes}},
              .index_buffer = {.buffer = buffer,
                               .range =
                                   Range{total_vtx_bytes, total_idx_bytes}},
              .index_count = index_count,
              .index_type = IndexType::k16bit,
          },
      .transform = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
                   entity.GetTransformation(),
      .prevent_overdraw = false,
  };
}

GeometryVertexType DLVerticesGeometry::GetVertexType() const {
  auto* dl_colors = vertices_->colors();
  if (dl_colors != nullptr) {
    return GeometryVertexType::kColor;
  }
  auto* dl_texture_coordinates = vertices_->texture_coordinates();
  if (dl_texture_coordinates != nullptr) {
    return GeometryVertexType::kUV;
  }

  return GeometryVertexType::kPosition;
}

std::optional<Rect> DLVerticesGeometry::GetCoverage(
    const Matrix& transform) const {
  return ToRect(vertices_->bounds()).TransformBounds(transform);
}

}  // namespace impeller
