// Copyright 2019 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_MESH_MESH_UTILS_H_
#define DRACO_MESH_MESH_UTILS_H_

#include "draco/draco_features.h"

#ifdef DRACO_TRANSCODER_SUPPORTED
#include "Eigen/Geometry"
#include "draco/core/status_or.h"
#include "draco/mesh/mesh.h"

namespace draco {

// Helper class containing various utilities operating on draco::Mesh.
// TODO(ostava): Move scattered functions in this folder here (e.g. corner table
// construction).
class MeshUtils {
 public:
  // Transforms |mesh| using the |transform| matrix. The mesh is transformed
  // in-place.
  static void TransformMesh(const Eigen::Matrix4d &transform, Mesh *mesh);

  // Merges metadata from |src_mesh| to |dst_mesh|. Any metadata with the same
  // names are left unchanged.
  static void MergeMetadata(const Mesh &src_mesh, Mesh *dst_mesh);

  // Removes unused MeshFeatures from |mesh|. If the |mesh| contains any mesh
  // feature textures, the textures must be owned by the |mesh| otherwise an
  // error is returned.
  static Status RemoveUnusedMeshFeatures(Mesh *mesh);

  // Flips the UV values of |att|.
  static bool FlipTextureUvValues(bool flip_u, bool flip_v,
                                  PointAttribute *att);

  // Counts the number of degenerate faces in |mesh| for attribute |att_id|.
  // Returns < 0 if counting of degenerate faces is not supported for |att_id|.
  static int CountDegenerateFaces(const Mesh &mesh, int att_id);

  // Searches for the lowest texture quantization bits for |tex_att| that does
  // not introduce any new texture coordinate degenerate faces. The range for
  // the search is |tex_target_quantization_bits| - 29, inclusive. The function
  // does not count texture coordinate degenerate faces already in the source.
  // Nor does it count any new texture coordinate degenerate faces that are a
  // subset of new position degenerate faces created from the quantization of
  // |pos_att| using |pos_quantization_bits|. Returns the lowest quantization
  // bits within the specified range or zero signifying that it could not find a
  // quantization that did not cause any new degenerate faces.
  static StatusOr<int> FindLowestTextureQuantization(
      const Mesh &mesh, const PointAttribute &pos_att,
      int pos_quantization_bits, const PointAttribute &tex_att,
      int tex_target_quantization_bits);

  // Helper function that checks whether a mesh has auto-generated tangents.
  // See go/tangents_and_draco_simplifier.
  static bool HasAutoGeneratedTangents(const Mesh &mesh);

 private:
  static void TransformNormalizedAttribute(const Eigen::Matrix3d &transform,
                                           PointAttribute *att);

  template <typename att_components_t>
  static int CountDegenerateFaces(const Mesh &mesh, const PointAttribute &att);

  // Returns a sorted list of degenerate faces for |att|. |att| must use |mesh|
  // for its connectivity. |range| and |max_quantized_value| are the values
  // passed into the quantizer. |quantized_degenerate_only|, is true will only
  // include degenerate faces caused by the quantization. Otherwise all
  // degenerate faces will be included, those made by the quantization and those
  // already in the source.
  static std::vector<FaceIndex> ListDegenerateQuantizedFaces(
      const Mesh &mesh, const PointAttribute &att, float range,
      uint32_t max_quantized_value, bool quantized_degenerate_only);

  // Returns a sorted list of degenerate faces for |att|. |att_components_t| is
  // the component count for |att| as a VectorD. E.g. Vector2f, Vector3f, or
  // Vector4f. |quantized_components_t| is the quantized component count for
  // |att| as a VectorD. E.g. VectorD<int32_t, 2>, VectorD<int32_t, 3>, or
  // VectorD<int32_t, 4>.
  template <typename att_components_t, typename quantized_components_t>
  static std::vector<FaceIndex> ListDegenerateQuantizedFaces(
      const Mesh &mesh, const PointAttribute &att, float range,
      uint32_t max_quantized_value, bool quantized_degenerate_only);
};

}  // namespace draco

#endif  // DRACO_TRANSCODER_SUPPORTED
#endif  // DRACO_MESH_MESH_UTILS_H_
