/* SPDX-License-Identifier: GPL-2.0-or-later
 * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
#pragma once

/** \file
 * \ingroup bke
 */

#ifdef __cplusplus
extern "C" {
#endif

struct MEdge;
struct MLoop;
struct MLoopTri;
struct MLoopUV;
struct MPoly;
struct MVert;

/* map from uv vertex to face (for select linked, stitch, uv suburf) */

/* UvVertMap */
#define STD_UV_CONNECT_LIMIT 0.0001f

typedef struct UvVertMap {
  struct UvMapVert **vert;
  struct UvMapVert *buf;
} UvVertMap;

typedef struct UvMapVert {
  struct UvMapVert *next;
  unsigned int poly_index;
  unsigned short loop_of_poly_index;
  bool separate;
} UvMapVert;

/* UvElement stores per uv information so that we can quickly access information for a uv.
 * it is actually an improved UvMapVert, including an island and a direct pointer to the face
 * to avoid initializing face arrays */
typedef struct UvElement {
  /* Next UvElement corresponding to same vertex */
  struct UvElement *next;
  /* Face the element belongs to */
  struct BMLoop *l;
  /* index in loop. */
  unsigned short loop_of_poly_index;
  /* Whether this element is the first of coincident elements */
  bool separate;
  /* general use flag */
  unsigned char flag;
  /* If generating element map with island sorting, this stores the island index */
  unsigned int island;
} UvElement;

/* UvElementMap is a container for UvElements of a mesh. It stores some UvElements belonging to the
 * same uv island in sequence and the number of uvs per island so it is possible to access all uvs
 * belonging to an island directly by iterating through the buffer.
 */
typedef struct UvElementMap {
  /* address UvElements by their vertex */
  struct UvElement **vert;
  /* UvElement Store */
  struct UvElement *buf;
  /* Total number of UVs in the layer. Useful to know */
  int totalUVs;
  /* Number of Islands in the mesh */
  int totalIslands;
  /* Stores the starting index in buf where each island begins */
  int *islandIndices;
} UvElementMap;

/* Connectivity data */
typedef struct MeshElemMap {
  int *indices;
  int count;
} MeshElemMap;

/* mapping */
UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
                                       const struct MLoop *mloop,
                                       const struct MLoopUV *mloopuv,
                                       unsigned int totpoly,
                                       unsigned int totvert,
                                       const float limit[2],
                                       bool selected,
                                       bool use_winding);
UvMapVert *BKE_mesh_uv_vert_map_get_vert(UvVertMap *vmap, unsigned int v);
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap);

/**
 * Generates a map where the key is the vertex and the value
 * is a list of polys that use that vertex as a corner.
 * The lists are allocated from one memory pool.
 */
void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map,
                                   int **r_mem,
                                   const struct MPoly *mpoly,
                                   const struct MLoop *mloop,
                                   int totvert,
                                   int totpoly,
                                   int totloop);
/**
 * Generates a map where the key is the vertex and the value
 * is a list of loops that use that vertex as a corner.
 * The lists are allocated from one memory pool.
 */
void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map,
                                   int **r_mem,
                                   const struct MPoly *mpoly,
                                   const struct MLoop *mloop,
                                   int totvert,
                                   int totpoly,
                                   int totloop);
/**
 * Generates a map where the key is the edge and the value
 * is a list of looptris that use that edge.
 * The lists are allocated from one memory pool.
 */
void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
                                      int **r_mem,
                                      const struct MVert *mvert,
                                      int totvert,
                                      const struct MLoopTri *mlooptri,
                                      int totlooptri,
                                      const struct MLoop *mloop,
                                      int totloop);
/**
 * Generates a map where the key is the vertex and the value
 * is a list of edges that use that vertex as an endpoint.
 * The lists are allocated from one memory pool.
 */
void BKE_mesh_vert_edge_map_create(
    MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
/**
 * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly
 * (not their edges).
 */
void BKE_mesh_vert_edge_vert_map_create(
    MeshElemMap **r_map, int **r_mem, const struct MEdge *medge, int totvert, int totedge);
/**
 * Generates a map where the key is the edge and the value is a list of loops that use that edge.
 * Loops indices of a same poly are contiguous and in winding order.
 * The lists are allocated from one memory pool.
 */
void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
                                   int **r_mem,
                                   const struct MEdge *medge,
                                   int totedge,
                                   const struct MPoly *mpoly,
                                   int totpoly,
                                   const struct MLoop *mloop,
                                   int totloop);
/**
 * Generates a map where the key is the edge and the value
 * is a list of polygons that use that edge.
 * The lists are allocated from one memory pool.
 */
void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
                                   int **r_mem,
                                   const struct MEdge *medge,
                                   int totedge,
                                   const struct MPoly *mpoly,
                                   int totpoly,
                                   const struct MLoop *mloop,
                                   int totloop);
/**
 * This function creates a map so the source-data (vert/edge/loop/poly)
 * can loop over the destination data (using the destination arrays origindex).
 *
 * This has the advantage that it can operate on any data-types.
 *
 * \param totsource: The total number of elements that \a final_origindex points to.
 * \param totfinal: The size of \a final_origindex
 * \param final_origindex: The size of the final array.
 *
 * \note `totsource` could be `totpoly`,
 *       `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
 *       This would allow an MPoly to loop over its tessfaces.
 */
void BKE_mesh_origindex_map_create(
    MeshElemMap **r_map, int **r_mem, int totsource, const int *final_origindex, int totfinal);
/**
 * A version of #BKE_mesh_origindex_map_create that takes a looptri array.
 * Making a poly -> looptri map.
 */
void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
                                           int **r_mem,
                                           const struct MPoly *mpoly,
                                           int mpoly_num,
                                           const struct MLoopTri *looptri,
                                           int looptri_num);

/* islands */

/* Loop islands data helpers. */
enum {
  MISLAND_TYPE_NONE = 0,
  MISLAND_TYPE_VERT = 1,
  MISLAND_TYPE_EDGE = 2,
  MISLAND_TYPE_POLY = 3,
  MISLAND_TYPE_LOOP = 4,
};

typedef struct MeshIslandStore {
  short item_type;     /* MISLAND_TYPE_... */
  short island_type;   /* MISLAND_TYPE_... */
  short innercut_type; /* MISLAND_TYPE_... */

  int items_to_islands_num;
  int *items_to_islands; /* map the item to the island index */

  int islands_num;
  size_t islands_num_alloc;
  struct MeshElemMap **islands;   /* Array of pointers, one item per island. */
  struct MeshElemMap **innercuts; /* Array of pointers, one item per island. */

  struct MemArena *mem; /* Memory arena, internal use only. */
} MeshIslandStore;

void BKE_mesh_loop_islands_init(MeshIslandStore *island_store,
                                short item_type,
                                int items_num,
                                short island_type,
                                short innercut_type);
void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_free(MeshIslandStore *island_store);
void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
                               int item_num,
                               const int *items_indices,
                               int num_island_items,
                               int *island_item_indices,
                               int num_innercut_items,
                               int *innercut_item_indices);

typedef bool (*MeshRemapIslandsCalc)(struct MVert *verts,
                                     int totvert,
                                     struct MEdge *edges,
                                     int totedge,
                                     struct MPoly *polys,
                                     int totpoly,
                                     struct MLoop *loops,
                                     int totloop,
                                     struct MeshIslandStore *r_island_store);

/* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here.
 * So better keep them separated for now, I think. */

/**
 * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams),
 * not some UV layers coordinates.
 */
bool BKE_mesh_calc_islands_loop_poly_edgeseam(struct MVert *verts,
                                              int totvert,
                                              struct MEdge *edges,
                                              int totedge,
                                              struct MPoly *polys,
                                              int totpoly,
                                              struct MLoop *loops,
                                              int totloop,
                                              MeshIslandStore *r_island_store);

/**
 * Calculate UV islands.
 *
 * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
 * This has the advantages of simplicity, and being valid/common to all UV maps.
 * However, it means actual UV islands without matching UV seams will not be handled correctly.
 * If a valid UV layer is passed as \a luvs parameter,
 * UV coordinates are also used to detect islands boundaries.
 *
 * \note All this could be optimized.
 * Not sure it would be worth the more complex code, though,
 * those loops are supposed to be really quick to do.
 */
bool BKE_mesh_calc_islands_loop_poly_uvmap(struct MVert *verts,
                                           int totvert,
                                           struct MEdge *edges,
                                           int totedge,
                                           struct MPoly *polys,
                                           int totpoly,
                                           struct MLoop *loops,
                                           int totloop,
                                           const struct MLoopUV *luvs,
                                           MeshIslandStore *r_island_store);

/**
 * Calculate smooth groups from sharp edges.
 *
 * \param r_totgroup: The total number of groups, 1 or more.
 * \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
 * starting at 1 (0 being used as 'invalid' flag).
 * Note it's callers's responsibility to MEM_freeN returned array.
 */
int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
                                int totedge,
                                const struct MPoly *mpoly,
                                int totpoly,
                                const struct MLoop *mloop,
                                int totloop,
                                int *r_totgroup,
                                bool use_bitflags);

/* use on looptri vertex values */
#define BKE_MESH_TESSTRI_VINDEX_ORDER(_tri, _v) \
  ((CHECK_TYPE_ANY( \
        _tri, unsigned int *, int *, int[3], const unsigned int *, const int *, const int[3]), \
    CHECK_TYPE_ANY(_v, unsigned int, const unsigned int, int, const int)), \
   (((_tri)[0] == _v) ? 0 : \
    ((_tri)[1] == _v) ? 1 : \
    ((_tri)[2] == _v) ? 2 : \
                        -1))

#ifdef __cplusplus
}
#endif
