/******************************************************************************
 * Copyright 2018 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/
/// \file
/// \brief Distributed subsets of irregular volume datasets.

#ifndef NVIDIA_INDEX_IIRREGULAR_VOLUME_SUBSET_H
#define NVIDIA_INDEX_IIRREGULAR_VOLUME_SUBSET_H

#include <mi/base/interface_declare.h>
#include <mi/dice.h>
#include <mi/math/vector.h>

#include <nv/index/idistributed_data_subset.h>

namespace nv
{
namespace index
{

/// @ingroup nv_index_data_storage
/// Distributed data storage class for irregular volume subsets.
///
/// An irregular volume dataset is defined as a set of cells (see the \c
/// IIrregular_volume_subset::Cell structure). The
/// cells are defined by a set of faces (see the \c IIrregular_volume_subset::Face structure). The
/// faces, finally, are
/// defined by a set of vertex positions in three dimensional space. The cell, face and vertex
/// information is handled in
/// three separate arrays (see \c IIrregular_volume_subset::Mesh_storage). In order to support
/// irregular volumes with
/// heterogeneous cell and face definitions, which allows for cells with varying numbers of faces
/// and faces with varying
/// numbers of vertices, the association of faces to cells and vertices to faces is handled by
/// shared cell-face and
/// face-vertex arrays. This further allows for sharing faces of connected cells in the irregular
/// volume mesh.
///
/// Attribute values can either be defined per vertex or per cell (see
/// IIrregular_volume_subset::Attribute_affiliation).
///
/// \note The current implementation of NVIDIA IndeX only allows for tetrahedral cells defining an
/// irregular volume.
///       While the interface allows to generate multiple attribute sets
///       associated with the irregular volume dataset only the first attribute set is regarded for
///       rendering.
///
class IIrregular_volume_subset
  : public mi::base::Interface_declare<0xe00304d7, 0x3f25, 0x4719, 0xb4, 0x7e, 0x3d, 0x10, 0xec,
      0xbd, 0x3c, 0x2f, IDistributed_data_subset>
{
public:
  /// Irregular volume cell definition.
  ///
  /// This structure holds the number of faces of the irregular volume cell and the starting
  /// index of the face index in the shared cell-face array (see \c Mesh_storage).The cell-face
  /// indices are
  /// stored consecutively in the shared cell-face array.
  ///
  struct Cell
  {
    mi::Uint32 nb_faces;         ///< Number of faces compounding this cell.
    mi::Uint32 start_face_index; ///< Starting index to the cell-face index array.
  };

  /// Irregular volume cell-face definition.
  ///
  /// This structure holds the number of vertices of the irregular volume cell face and the starting
  /// index of the face vertices in the shared face-vertex array (see \c Mesh_storage). The
  /// face-vertex indices are
  /// stored consecutively in the shared face-vertex array.
  ///
  struct Face
  {
    mi::Uint32 nb_vertices;        ///< Number of vertices in the face.
    mi::Uint32 start_vertex_index; ///< Starting index to the face-vertex index array.
  };

  /// Irregular volume mesh storage parameters.
  ///
  /// This structure defines the basic irregular volume dataset parameters such as the number of
  /// vertices, faces and
  /// cells in the underlying mesh structure as well as the size of the shared cell-face and
  /// face-vertex arrays.
  ///
  /// An additional global mesh maximum edge length is a required mesh parameter the rendering
  /// system strongly
  /// requires. This parameter cannot be determined in a straightforward way inside the rendering
  /// system as
  /// it only is presented with data sub-sets.
  ///
  struct Mesh_parameters
  {
    // mesh geometry and topology info
    mi::Uint32 nb_vertices;          ///< Size of the vertex array in number of vertices.
    mi::Uint32 nb_face_vtx_indices;  ///< Size of the face vertex index array in number of elements.
    mi::Uint32 nb_faces;             ///< Size of the face array in number of faces.
    mi::Uint32 nb_cell_face_indices; ///< Size of the cell face index array in number of elements.
    mi::Uint32 nb_cells;             ///< Size of the cell array in number of faces.

    // mesh geometry traits
    mi::Float32
      global_max_edge_length; ///< The length of the longest edge in the irregular volume mesh
  };

  /// Irregular volume mesh storage.
  ///
  /// The storage is generated by a call to \c generate_mesh_storage() passing an initialized
  /// instance of mesh parameters
  /// \c Mesh_parameters(). A valid mesh storage then contains initialized arrays for storing the
  /// irregular volume
  /// subset.
  ///
  struct Mesh_storage
  {
    mi::math::Vector_struct<mi::Float32, 3>* vertices; ///< The vertex array.
    mi::Uint32* face_vtx_indices;                      ///< The face-vertex index array.
    Face* faces;                                       ///< The face array.
    mi::Uint32* cell_face_indices;                     ///< The cell-face index array.
    Cell* cells;                                       ///< The cell array.
  };

  /// Types of attribute set affiliations.
  ///
  /// \note The currently only supported attribute affiliation allows for assigning attribute values
  /// to irregular
  ///       volume mesh vertices. Future affiliations will allow per cell attribute assignments.
  ///
  enum Attribute_affiliation
  {
    ATTRIB_AFFIL_PER_VERTEX = 0x00, ///< Per irregular volume mesh-vertex attribute.
    ATTRIB_AFFIL_PER_CELL = 0x01    ///< Per irregular volume mesh-cell attribute.
  };

  /// Types of attribute set values.
  ///
  /// The currently only supported attribute type is an 8bit unsigned integer type. Future types
  /// will encompass
  /// different single channel as well as multi-channel attribute values with higher precision base
  /// types.
  ///
  enum Attribute_type
  {
    ATTRIB_TYPE_UINT8 = 0x00, ///<  8bit unsigned integer scalar attribute type.
    ATTRIB_TYPE_UINT8_2 =
      0x01, ///<  8bit unsigned integer vector attribute type with two components.
    ATTRIB_TYPE_UINT8_3 =
      0x02, ///<  8bit unsigned integer vector attribute type with three components.
    ATTRIB_TYPE_UINT8_4 =
      0x03, ///<  8bit unsigned integer vector attribute type with four components.
    ATTRIB_TYPE_UINT16 = 0x04, ///< 16bit unsigned integer scalar attribute type.
    ATTRIB_TYPE_UINT16_2 =
      0x05, ///< 16bit unsigned integer vector attribute type with two components.
    ATTRIB_TYPE_UINT16_3 =
      0x06, ///< 16bit unsigned integer vector attribute type with three components.
    ATTRIB_TYPE_UINT16_4 =
      0x07, ///< 16bit unsigned integer vector attribute type with four components.
    ATTRIB_TYPE_FLOAT32 = 0x08, ///< 32bit floating point scalar attribute type.
    ATTRIB_TYPE_FLOAT32_2 =
      0x09, ///< 32bit floating point vector attribute type with two components.
    ATTRIB_TYPE_FLOAT32_3 =
      0x10, ///< 32bit floating point vector attribute type with three components.
    ATTRIB_TYPE_FLOAT32_4 =
      0x11 ///< 32bit floating point vector attribute type with four components.
  };

  /// Irregular volume attribute parameters.
  ///
  /// This structure defines the basic parameters of a single attribute set associated with the
  /// irregular volume dataset.
  ///
  struct Attribute_parameters
  {
    Attribute_affiliation affiliation; ///< Attribute affiliation. See \c Attribute_affiliation.
    Attribute_type type;               ///< Attribute type. See \c Attribute_type.
    mi::Uint32 nb_attrib_values;       ///< Number of attribute values in number of elements.
  };

  /// Attribute storage.
  ///
  /// The attribute storage is generated by a call to \c generate_mesh_storage() passing an
  /// initialized instance of
  /// attribute parameters \c Attribute_parameters. A valid attribute storage contains a raw pointer
  /// to an array of
  /// attribute values.
  ///
  struct Attribute_storage
  {
    void* attrib_values; ///< The attribute array.
  };

  /// Generate and initialize an instance of irregular volume mesh storage.
  ///
  /// This function initializes an instance of \c Mesh_storage according to the passed instance of
  /// \c Mesh_parameters.
  /// At any point during the lifetime of an \c IIrregular_volume_subset instance there can only be
  /// a single valid
  /// mesh storage. Multiple calls to this function will invalidate previous instances of the mesh
  /// storage and return
  /// a new valid instance according the newly passed mesh parameters.
  ///
  /// \param[in]  mesh_params     The irregular volume mesh parameters.
  /// \param[out] mesh_storage    Mesh_storage instance that contains valid references to the
  /// vertex,
  ///                             face, and cell arrays of the irregular volume mesh.
  ///
  /// \return                     True if a valid storage was generated, false otherwise.
  ///
  virtual bool generate_mesh_storage(
    const Mesh_parameters& mesh_params, Mesh_storage& mesh_storage) = 0;

  /// Generate and initialize an instance of irregular volume attribute set storage.
  ///
  /// This function initializes an instance of \c Attribute_storage according to the passed instance
  /// of \c Attribute_parameters.
  /// An irregular volume dataset can be associated with multiple attribute sets which are
  /// identified by an attribute
  /// index. At any point during the lifetime of an \c IIrregular_volume_subset instance there can
  /// only be a single valid
  /// attribute storage per attribute index. Multiple calls to this function will invalidate
  /// previous instances of the
  /// attribute storage associated with the passed index value and return a new valid instance
  /// according the newly
  /// passed attribute parameters.
  ///
  /// \param[in]  attrib_index    The storage index for this attribute set.
  /// \param[in]  attrib_params   The attribute parameters.
  /// \param[out] attrib_storage  Attribute storage instance that contains valid references to the
  /// attribute value array.
  ///
  /// \return                     True if a valid storage was generated, false otherwise.
  ///
  virtual bool generate_attribute_storage(mi::Uint32 attrib_index,
    const Attribute_parameters& attrib_params, Attribute_storage& attrib_storage) = 0;

  /// Get the irregular volume mesh parameters of the currently valid mesh storage.
  ///
  /// When this function is called before initializing a valid mesh storage (\c
  /// generate_mesh_storage()) the returned
  /// instance of \c Mesh_parameters will describe an empty irregular volume mesh (i.e. all values
  /// 0).
  ///
  /// \return     The irregular volume mesh parameters of the currently valid mesh storage.
  ///
  virtual Mesh_parameters get_mesh_parameters() const = 0;

  /// Get the current valid irregular volume mesh storage.
  ///
  /// When this function is called before initializing a valid mesh storage (\c
  /// generate_mesh_storage()) the returned
  /// instance of \c Mesh_storage will hold invalid pointers to the particular arrays (i.e. value
  /// 0).
  ///
  /// \return     A copy of the currently valid irregular volume mesh storage.
  ///
  virtual Mesh_storage get_mesh() const = 0;

  /// Get the current number of valid attribute sets.
  ///
  /// \return     The number of attribute sets.
  ///
  virtual mi::Uint32 get_nb_attributes() const = 0;

  /// Get the attribute parameters of an currently valid attribute set for a given index.
  ///
  /// \param[in]  attrib_index    The storage index of the attribute set.
  /// \param[out] attrib_params   The attribute set parameters for the given index.
  ///
  /// \return                     True when the attribute set according to the passed index could be
  /// found, false otherwise.
  ///
  virtual bool get_attribute_parameters(
    mi::Uint32 attrib_index, Attribute_parameters& attrib_params) const = 0;

  /// Get the currently valid attribute set storage for a given attribute index.
  ///
  /// \param[in]  attrib_index    The storage index of the attribute set.
  /// \param[out] attrib_storage  The attribute storage for the given index.
  ///
  /// \return                     True when the attribute storage according to the passed index
  /// could be found, false otherwise.
  //
  virtual bool get_attribute(mi::Uint32 attrib_index, Attribute_storage& attrib_storage) const = 0;
};

} // namespace index
} // namespace nv

#endif // NVIDIA_INDEX_IIRREGULAR_VOLUME_SUBSET_H
