312 lines
13 KiB
C++
312 lines
13 KiB
C++
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
#pragma once
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*/
|
|
|
|
#include "BLI_array.hh"
|
|
#include "BLI_math_vector_types.hh"
|
|
#include "BLI_offset_indices.hh"
|
|
|
|
struct BMLoop;
|
|
struct MemArena;
|
|
|
|
/* UvVertMap */
|
|
#define STD_UV_CONNECT_LIMIT 0.0001f
|
|
|
|
struct UvMapVert {
|
|
UvMapVert *next;
|
|
unsigned int face_index;
|
|
unsigned short loop_of_face_index;
|
|
bool separate;
|
|
};
|
|
|
|
/** Map from UV vertex to face. Used by select linked, UV subdivision-surface and obj exporter. */
|
|
struct UvVertMap {
|
|
UvMapVert **vert;
|
|
UvMapVert *buf;
|
|
};
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
struct UvElement {
|
|
/** Next UvElement corresponding to same vertex */
|
|
UvElement *next;
|
|
/** Face the element belongs to */
|
|
BMLoop *l;
|
|
/** Index in loop. */
|
|
unsigned short loop_of_face_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;
|
|
};
|
|
|
|
/**
|
|
* UvElementMap is a container for UvElements of a BMesh.
|
|
*
|
|
* It simplifies access to UV information and ensures the
|
|
* different UV selection modes are respected.
|
|
*
|
|
* If islands are calculated, it also stores UvElements
|
|
* belonging to the same uv island in sequence and
|
|
* the number of uvs per island.
|
|
*
|
|
* \note in C++, #head_table and #unique_index_table would
|
|
* be `mutable`, as they are created on demand, and never
|
|
* changed after creation.
|
|
*/
|
|
struct UvElementMap {
|
|
/** UvElement Storage. */
|
|
UvElement *storage;
|
|
/** Total number of UVs. */
|
|
int total_uvs;
|
|
/** Total number of unique UVs. */
|
|
int total_unique_uvs;
|
|
|
|
/** If Non-NULL, address UvElements by `BM_elem_index_get(BMVert*)`. */
|
|
UvElement **vertex;
|
|
|
|
/** If Non-NULL, pointer to local head of each unique UV. */
|
|
UvElement **head_table;
|
|
|
|
/** If Non-NULL, pointer to index of each unique UV. */
|
|
int *unique_index_table;
|
|
|
|
/** Number of islands, or zero if not calculated. */
|
|
int total_islands;
|
|
/** Array of starting index in #storage where each island begins. */
|
|
int *island_indices;
|
|
/** Array of number of UVs in each island. */
|
|
int *island_total_uvs;
|
|
/** Array of number of unique UVs in each island. */
|
|
int *island_total_unique_uvs;
|
|
};
|
|
|
|
/* Connectivity data */
|
|
struct MeshElemMap {
|
|
int *indices;
|
|
int count;
|
|
};
|
|
|
|
/* mapping */
|
|
|
|
UvVertMap *BKE_mesh_uv_vert_map_create(blender::OffsetIndices<int> faces,
|
|
blender::Span<int> corner_verts,
|
|
blender::Span<blender::float2> uv_map,
|
|
int verts_num,
|
|
const blender::float2 &limit,
|
|
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 edge and the value
|
|
* is a list of corner_tris that use that edge.
|
|
* The lists are allocated from one memory pool.
|
|
*/
|
|
void BKE_mesh_vert_corner_tri_map_create(MeshElemMap **r_map,
|
|
int **r_mem,
|
|
int totvert,
|
|
const blender::int3 *corner_tris,
|
|
int tris_num,
|
|
const int *corner_verts,
|
|
int corners_num);
|
|
/**
|
|
* This function creates a map so the source-data (vert/edge/loop/face)
|
|
* 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 `faces_num`,
|
|
* `totfinal` could be `tottessface` and `final_origindex` its ORIGINDEX custom-data.
|
|
* This would allow a face 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 corner tri array.
|
|
* Making a face -> corner tri map.
|
|
*/
|
|
void BKE_mesh_origindex_map_create_corner_tri(MeshElemMap **r_map,
|
|
int **r_mem,
|
|
blender::OffsetIndices<int> faces,
|
|
const int *corner_tri_faces,
|
|
int corner_tris_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,
|
|
};
|
|
|
|
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;
|
|
MeshElemMap **islands; /* Array of pointers, one item per island. */
|
|
MeshElemMap **innercuts; /* Array of pointers, one item per island. */
|
|
|
|
MemArena *mem; /* Memory arena, internal use only. */
|
|
};
|
|
|
|
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);
|
|
|
|
using MeshRemapIslandsCalc = bool (*)(blender::Span<blender::float3> vert_positions,
|
|
blender::Span<blender::int2> edges,
|
|
blender::Span<bool> uv_seams,
|
|
blender::OffsetIndices<int> faces,
|
|
blender::Span<int> corner_verts,
|
|
blender::Span<int> corner_edges,
|
|
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.
|
|
*
|
|
* \param uv_seams: Optional (possibly empty) span.
|
|
*/
|
|
bool BKE_mesh_calc_islands_loop_face_edgeseam(blender::Span<blender::float3> vert_positions,
|
|
blender::Span<blender::int2> edges,
|
|
blender::Span<bool> uv_seams,
|
|
blender::OffsetIndices<int> faces,
|
|
blender::Span<int> corner_verts,
|
|
blender::Span<int> corner_edges,
|
|
MeshIslandStore *r_island_store);
|
|
|
|
/**
|
|
* Calculate smooth groups from sharp edges, using increasing numbers as identifier for each group.
|
|
*
|
|
* \param sharp_edges: Optional (possibly empty) span.
|
|
* \param sharp_faces: Optional (possibly empty) span.
|
|
* \param r_totgroup: The total number of groups, 1 or more.
|
|
* \return Face aligned array of group index values, starting at 1 (0 being used as 'invalid'
|
|
* flag). Note that it's the callers responsibility to MEM_freeN the returned array.
|
|
*/
|
|
int *BKE_mesh_calc_smoothgroups(int edges_num,
|
|
blender::OffsetIndices<int> faces,
|
|
blender::Span<int> corner_edges,
|
|
blender::Span<bool> sharp_edges,
|
|
blender::Span<bool> sharp_faces,
|
|
int *r_totgroup);
|
|
/**
|
|
* Same as #BKE_mesh_calc_smoothgroups, but use bit-flags instead of increasing numbers for each
|
|
* group.
|
|
*
|
|
* This means that the same value (bit) can be re-used for different groups, as long as they are
|
|
* not neighbors. Values of each group are always powers of two.
|
|
*
|
|
* By default, only groups that share a same sharp edge are considered neighbors, and therefore
|
|
* prevented to use the same bit-flag value.
|
|
*
|
|
* If #use_boundary_vertices_for_bitflags is set to `true`, then groups are also considered
|
|
* neighbors (and therefore cannot have the same bit-flag value) if they share a single vertex,
|
|
* even if they have no common edge. This behavior seems to be required by some DCCs to recompute
|
|
* correct normals, see e.g. #104434. It will however make it much more likely to run out of
|
|
* available bits with certain types of topology (e.g. large fans of sharp faces).
|
|
*
|
|
* \param sharp_edges: Optional (possibly empty) span.
|
|
* \param sharp_faces: Optional (possibly empty) span.
|
|
* \param r_totgroup: The total number of groups, 1 or more.
|
|
* \return Face aligned array of group bit-flags values (i.e. always powers of 2), starting at 1 (0
|
|
* being used as 'invalid' flag). Note that it's the callers responsibility to MEM_freeN the
|
|
* returned array.
|
|
*/
|
|
int *BKE_mesh_calc_smoothgroups_bitflags(int edges_num,
|
|
int verts_num,
|
|
blender::OffsetIndices<int> faces,
|
|
blender::Span<int> corner_edges,
|
|
blender::Span<int> corner_verts,
|
|
blender::Span<bool> sharp_edges,
|
|
blender::Span<bool> sharp_faces,
|
|
bool use_boundary_vertices_for_bitflags,
|
|
int *r_totgroup);
|
|
|
|
/* Use on corner_tri 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))
|
|
|
|
namespace blender::bke::mesh {
|
|
|
|
Array<int> build_corner_to_face_map(OffsetIndices<int> faces);
|
|
|
|
GroupedSpan<int> build_vert_to_edge_map(Span<int2> edges,
|
|
int verts_num,
|
|
Array<int> &r_offsets,
|
|
Array<int> &r_indices);
|
|
|
|
void build_vert_to_face_indices(OffsetIndices<int> faces,
|
|
Span<int> corner_verts,
|
|
OffsetIndices<int> offsets,
|
|
MutableSpan<int> face_indices);
|
|
GroupedSpan<int> build_vert_to_face_map(OffsetIndices<int> faces,
|
|
Span<int> corner_verts,
|
|
int verts_num,
|
|
Array<int> &r_offsets,
|
|
Array<int> &r_indices);
|
|
|
|
Array<int> build_vert_to_corner_indices(Span<int> corner_verts, OffsetIndices<int> offsets);
|
|
GroupedSpan<int> build_vert_to_corner_map(Span<int> corner_verts,
|
|
int verts_num,
|
|
Array<int> &r_offsets,
|
|
Array<int> &r_indices);
|
|
|
|
GroupedSpan<int> build_edge_to_corner_map(Span<int> corner_edges,
|
|
int edges_num,
|
|
Array<int> &r_offsets,
|
|
Array<int> &r_indices);
|
|
|
|
GroupedSpan<int> build_edge_to_face_map(OffsetIndices<int> faces,
|
|
Span<int> corner_edges,
|
|
int edges_num,
|
|
Array<int> &r_offsets,
|
|
Array<int> &r_indices);
|
|
|
|
} // namespace blender::bke::mesh
|