text: // Copyright 2018 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 <memory>
  
  #include "lib/ui/scenic/cpp/commands.h"
  #include "lib/ui/scenic/cpp/resources.h"
  
  namespace scenic {
  namespace mesh_utils {
  
  std::unique_ptr<Mesh> NewMeshWithVertices(Session* session, const std::vector<float>& vertices,
                                            const std::vector<uint32_t>& indices) {
    auto mesh = std::make_unique<Mesh>(session);
  
    ZX_DEBUG_ASSERT(vertices.size() % 3 == 0);
    const uint64_t num_vertices = vertices.size() / 3;
  
    ZX_DEBUG_ASSERT(*std::max_element(indices.begin(), indices.end()) < num_vertices);
  
    // TODO(SCN-558) vertex_elements should be 3.
    uint64_t vertex_elements = 5;
  
    uint64_t vertex_size = vertex_elements * sizeof(float);
    uint64_t vertex_buffer_size = num_vertices * vertex_size;
    uint64_t index_buffer_size = indices.size() * sizeof(uint32_t);
  
    // TODO(SCN-558) This whole block is a workaround and should be removed.
    std::vector<float> vertices_scn_558;
    vertices_scn_558.reserve(vertex_buffer_size / sizeof(float));
    for (uint64_t i = 0; i < num_vertices; i++) {
      const float* vertex_in = vertices.data() + i * 3;
      float* vertex_out = vertices_scn_558.data() + i * vertex_elements;
      vertex_out[0] = vertex_in[0];
      vertex_out[1] = vertex_in[1];
      vertex_out[2] = vertex_in[2];
      vertex_out[3] = 0;
      vertex_out[4] = 0;
    }
    // END TODO(SCN-558)
  
    // Copy data to VMO and create buffers
    uint64_t vmo_size = vertex_buffer_size + index_buffer_size;
    zx::vmo vmo;
    zx_status_t status;
    status = zx::vmo::create(vmo_size, 0u, &vmo);
  
    // TODO(SCN-558) uses vertices.data()
    status = vmo.write(vertices_scn_558.data(), 0, vertex_buffer_size);
    ZX_DEBUG_ASSERT(status == ZX_OK);
    status = vmo.write(indices.data(), vertex_buffer_size, index_buffer_size);
    ZX_DEBUG_ASSERT(status == ZX_OK);
  
    Memory mem(session, std::move(vmo), vmo_size, fuchsia::images::MemoryType::VK_DEVICE_MEMORY);
    Buffer vertex_buffer(mem, 0, vertex_buffer_size);
    Buffer index_buffer(mem, vertex_buffer_size, index_buffer_size);
  
    auto vertex_format =
        NewMeshVertexFormat(fuchsia::ui::gfx::ValueType::kVector3, fuchsia::ui::gfx::ValueType::kNone,
                            fuchsia::ui::gfx::ValueType::kVector2);
  
    // Compute bounding box.
    std::vector<float> bounding_box_min;
    std::vector<float> bounding_box_max;
    for (int i = 0; i < 3; i++) {
      bounding_box_min.push_back(std::numeric_limits<float>::max());
      bounding_box_max.push_back(std::numeric_limits<float>::min());
    }
  
    for (uint64_t i = 0; i < num_vertices; i++) {
      const float* vertex = vertices.data() + i * 3;
      bounding_box_min[0] = std::min(bounding_box_min[0], vertex[0]);
      bounding_box_min[1] = std::min(bounding_box_min[1], vertex[1]);
      bounding_box_min[2] = std::min(bounding_box_min[2], vertex[2]);
  
      bounding_box_max[0] = std::max(bounding_box_max[0], vertex[0]);
      bounding_box_max[1] = std::max(bounding_box_max[1], vertex[1]);
      bounding_box_max[2] = std::max(bounding_box_max[2], vertex[2]);
    }
  
    // Bind buffers.
    mesh->BindBuffers(index_buffer, fuchsia::ui::gfx::MeshIndexFormat::kUint32, 0, indices.size(),
                      vertex_buffer, std::move(vertex_format), 0, num_vertices,
                      bounding_box_min.data(), bounding_box_max.data());
    return mesh;
  }
  
  }  // namespace mesh_utils
  }  // namespace scenic
  