24 #define OUT_OF_CONTEXT (int)(-1)
26 #define ELEM_COLLAPSED (int)(-2)
28 #define ELEM_MERGED (int)(-2)
146 #ifdef USE_WELD_DEBUG
156 static void weld_assert_edge_kill_len(
Span<WeldEdge> wedge,
const int supposed_kill_len)
160 for (
int i = wedge.
size(); i--; we++) {
170 static void weld_assert_poly_and_loop_kill_len(WeldMesh *weld_mesh,
173 const int supposed_poly_kill_len,
174 const int supposed_loop_kill_len)
177 int loop_kills = mloop.size();
178 const MPoly *mp = &mpoly[0];
179 for (
int i = 0; i < mpoly.size(); i++, mp++) {
180 int poly_ctx = weld_mesh->poly_map[i];
182 const WeldPoly *wp = &weld_mesh->wpoly[poly_ctx];
183 WeldLoopOfPolyIter iter;
185 iter, *wp, weld_mesh->wloop, mloop, weld_mesh->loop_map,
nullptr)) {
194 int remain = wp->loop_len;
195 int l = wp->loop_start;
198 int loop_ctx = weld_mesh->loop_map[
l];
200 const WeldLoop *wl = &weld_mesh->wloop[loop_ctx];
202 l_next = wl->loop_skip_to;
222 for (
const int i : weld_mesh->wpoly.index_range().take_back(weld_mesh->wpoly_new_len)) {
223 const WeldPoly &wp = weld_mesh->wpoly[i];
228 int remain = wp.loop_len;
229 int l = wp.loop_start;
232 int loop_ctx = weld_mesh->loop_map[
l];
234 const WeldLoop *wl = &weld_mesh->wloop[loop_ctx];
236 l_next = wl->loop_skip_to;
251 BLI_assert(poly_kills == supposed_poly_kill_len);
252 BLI_assert(loop_kills == supposed_loop_kill_len);
255 static void weld_assert_poly_no_vert_repetition(
const WeldPoly &wp,
256 Span<WeldLoop> wloop,
260 const int loop_len = wp.loop_len;
261 Array<int, 64>
verts(loop_len);
262 WeldLoopOfPolyIter iter;
272 for (
int i = 0; i < loop_len; i++) {
274 for (
int j = i + 1; j < loop_len; j++) {
281 static void weld_assert_poly_len(
const WeldPoly *wp,
const Span<WeldLoop> wloop)
287 int loop_len = wp->loop_len;
288 const WeldLoop *wl = &wloop[wp->loops.ofs];
291 int end_wloop = wp->loops.ofs + wp->loops.len;
292 const WeldLoop *wl_end = &wloop[end_wloop - 1];
295 for (; wl <= wl_end; wl++) {
303 int max_len = wp->loop_end - wp->loop_start + 1;
316 const int vert_kill_len)
319 wvert.
reserve(std::min<int>(2 * vert_kill_len, vert_dest_map.
size()));
342 const int vert_dest = vert_dest_map[i];
344 if (vert_dest != i) {
348 r_vert_groups_map[i] = wgroups_len;
358 r_vert_groups.
fill({0, 0});
362 int group_index = r_vert_groups_map[wv.vert_dest];
363 wgroups[group_index].len++;
376 int group_index = r_vert_groups_map[wv.vert_dest];
377 r_vert_groups_buffer[wgroups[group_index].ofs++] = wv.vert_orig;
403 int v1 = medge[i].v1;
404 int v2 = medge[i].v2;
405 int v_dest_1 = vert_dest_map[
v1];
406 int v_dest_2 = vert_dest_map[
v2];
414 r_edge_dest_map[i] = i;
415 r_edge_ctx_map[i] = wedge_len++;
429 int *r_edge_kiil_len)
432 int edge_kill_len = 0;
437 int dst_vert_a = we.
vert_a;
438 int dst_vert_b = we.
vert_b;
440 if (dst_vert_a == dst_vert_b) {
448 v_links[dst_vert_a].len++;
449 v_links[dst_vert_b].len++;
467 int dst_vert_a = we.
vert_a;
468 int dst_vert_b = we.
vert_b;
470 link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
471 link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
487 int dst_vert_a = we.
vert_a;
488 int dst_vert_b = we.
vert_b;
490 struct WeldGroup *link_a = &v_links[dst_vert_a];
491 struct WeldGroup *link_b = &v_links[dst_vert_b];
493 int edges_len_a = link_a->
len;
494 int edges_len_b = link_b->
len;
496 if (edges_len_a <= 1 || edges_len_b <= 1) {
500 int *edges_ctx_a = &link_edge_buffer[link_a->
ofs];
501 int *edges_ctx_b = &link_edge_buffer[link_b->
ofs];
504 for (; edges_len_a--; edges_ctx_a++) {
505 int e_ctx_a = *edges_ctx_a;
509 while (edges_len_b && *edges_ctx_b < e_ctx_a) {
513 if (edges_len_b == 0) {
516 int e_ctx_b = *edges_ctx_b;
517 if (e_ctx_a == e_ctx_b) {
523 r_edge_dest_map[we_b->
edge_orig] = edge_orig;
530 #ifdef USE_WELD_DEBUG
531 weld_assert_edge_kill_len(r_wedge, edge_kill_len);
535 *r_edge_kiil_len = edge_kill_len;
539 const int edge_kill_len,
547 int wgroups_len = wedge.
size() - edge_kill_len;
549 r_edge_groups.
fill({{0}});
554 int edge_ctx = wedge_map[i];
564 wegroups[wgroups_len].v1 = we->
vert_a;
565 wegroups[wgroups_len].v2 = we->
vert_b;
566 r_edge_groups_map[i] = wgroups_len;
577 if (wgroups_len == 0) {
586 int group_index = r_edge_groups_map[we.
edge_dest];
587 wegroups[group_index].group.len++;
592 wegrp.group.ofs = ofs;
593 ofs += wegrp.group.len;
601 int group_index = r_edge_groups_map[we.
edge_dest];
602 r_edge_groups_buffer[wegroups[group_index].group.ofs++] = we.
edge_orig;
606 wegrp.group.ofs -= wegrp.group.len;
632 iter.
group = group_buffer;
637 int loop_start, loop_end,
l;
640 while (
l >= loop_start) {
641 const int loop_ctx = loop_map[
l];
643 const WeldLoop *wl = &wloop[loop_ctx];
652 group_len = loop_end -
l;
654 while (
l < loop_end) {
662 #ifdef USE_WELD_DEBUG
680 while (
l <= loop_end) {
682 const int loop_ctx = loop_map[
l];
684 const WeldLoop *wl = &wloop[loop_ctx];
695 #ifdef USE_WELD_DEBUG
704 #ifdef USE_WELD_DEBUG
732 int max_ctx_poly_len = 4;
740 int maybe_new_poly = 0;
743 const MPoly &mp = mpoly[i];
745 const int totloop = mp.
totloop;
747 int vert_ctx_len = 0;
749 int prev_wloop_len = wloop_len;
751 int v = mloop[i_loop].v;
752 int e = mloop[i_loop].e;
753 int v_dest = vert_dest_map[
v];
754 int e_dest = edge_dest_map[
e];
760 if (is_vert_ctx || is_edge_ctx) {
762 wl.
vert = is_vert_ctx ? v_dest :
v;
763 wl.edge = is_edge_ctx ? e_dest :
e;
764 wl.loop_orig = i_loop;
768 loop_map[i_loop] = wloop_len++;
774 if (wloop_len != prev_wloop_len) {
775 int loops_len = wloop_len - prev_wloop_len;
779 wp.loops.len = loops_len;
780 wp.loops.ofs = prev_wloop_len;
781 wp.loop_start = loopstart;
782 wp.loop_end = loopstart + totloop - 1;
783 wp.loop_len = totloop;
786 poly_map[i] = wpoly_len++;
787 if (totloop > 5 && vert_ctx_len > 1) {
788 int max_new = (totloop / 3) - 1;
790 maybe_new_poly +=
MIN2(max_new, vert_ctx_len);
801 r_weld_mesh->
wloop = std::move(wloop);
802 r_weld_mesh->
wpoly = std::move(wpoly);
804 r_weld_mesh->
loop_map = std::move(loop_map);
805 r_weld_mesh->
poly_map = std::move(poly_map);
810 #ifdef USE_WELD_DEBUG
820 if (poly_loop_len < 3 || ctx_verts_len < 1) {
824 const int ctx_loops_len = r_wp->
loops.
len;
825 const int ctx_loops_ofs = r_wp->
loops.
ofs;
830 WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
832 WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1];
836 const int la_len = ctx_loops_len - 1;
837 for (
int la = 0; la < la_len; la++, wla++) {
842 int vert_a = wla->
vert;
850 for (; lb < ctx_loops_len; lb++, wlb++) {
856 int vert_b = wlb->
vert;
860 if (vert_a == vert_b) {
862 const int dist_b = poly_loop_len - dist_a;
865 if (dist_a == 1 || dist_b == 1) {
881 if (wl_tmp !=
nullptr) {
895 if (wl_tmp ==
nullptr) {
896 const int new_loops_len = lb - la;
897 const int new_loops_ofs = ctx_loops_ofs + la;
899 r_weld_mesh->
wpoly.increase_size_by_unchecked(1);
910 #ifdef USE_WELD_DEBUG
919 poly_loop_len = dist_b;
945 *r_loop_kill += loop_kill;
947 #ifdef USE_WELD_DEBUG
948 weld_assert_poly_no_vert_repetition(*r_wp, wloop, mloop, r_weld_mesh->
loop_map);
953 #ifdef USE_WELD_DEBUG
958 const int remain_edge_ctx_len,
964 int poly_kill_len = 0;
965 int loop_kill_len = 0;
969 if (remain_edge_ctx_len) {
975 for (
const int i : wpoly_original_range) {
977 const int ctx_loops_len = wp.
loops.
len;
978 const int ctx_loops_ofs = wp.
loops.
ofs;
981 int ctx_verts_len = 0;
982 WeldLoop *wl = &wloop[ctx_loops_ofs];
983 for (
int l = ctx_loops_len;
l--; wl++) {
984 const int edge_dest = wl->
edge;
987 if (poly_loop_len == 3) {
998 const int vert_dst = wl->
vert;
1005 if (poly_loop_len) {
1007 #ifdef USE_WELD_DEBUG
1008 weld_assert_poly_len(&wp, wloop);
1012 #ifdef USE_WELD_DEBUG
1023 #ifdef USE_WELD_DEBUG
1024 weld_assert_poly_and_loop_kill_len(r_weld_mesh, mloop, mpoly, poly_kill_len, loop_kill_len);
1029 r_vlinks.
fill({0, 0});
1036 v_links[iter.
v].len++;
1043 v_links[i].ofs = link_len;
1044 link_len += v_links[i].len;
1055 link_poly_buffer[v_links[iter.
v].ofs++] = i;
1065 int polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
1066 polys_len_b = p_ctx_b = 0;
1080 polys_len_a = link_a->
len;
1081 if (polys_len_a == 1) {
1086 polys_ctx_a = &link_poly_buffer[link_a->
ofs];
1087 for (; polys_len_a--; polys_ctx_a++) {
1088 p_ctx_a = *polys_ctx_a;
1093 WeldPoly *wp_tmp = &wpoly[p_ctx_a];
1094 if (wp_tmp->
loop_len != wp_loop_len) {
1100 struct WeldGroup *link_b = &v_links[iter_b.
v];
1101 polys_len_b = link_b->
len;
1102 if (polys_len_b == 1) {
1108 polys_ctx_b = &link_poly_buffer[link_b->
ofs];
1109 for (; polys_len_b; polys_len_b--, polys_ctx_b++) {
1110 p_ctx_b = *polys_ctx_b;
1111 if (p_ctx_b < p_ctx_a) {
1114 if (p_ctx_b >= p_ctx_a) {
1115 if (p_ctx_b > p_ctx_a) {
1121 if (polys_len_b == 0) {
1125 if (polys_len_b == 0) {
1140 poly_kill_len = r_weld_mesh->
wpoly.size();
1141 loop_kill_len = r_weld_mesh->
wloop.size();
1148 #ifdef USE_WELD_DEBUG
1149 weld_assert_poly_and_loop_kill_len(r_weld_mesh, mloop, mpoly, poly_kill_len, loop_kill_len);
1164 const int vert_kill_len,
1185 #ifdef USE_WELD_DEBUG
1231 float co[3] = {0.0f, 0.0f, 0.0f};
1232 #ifdef USE_WELD_NORMALS
1233 float no[3] = {0.0f, 0.0f, 0.0f};
1241 for (src_i = 0; src_i < source->
totlayer; src_i++) {
1247 while (dest_i < dest->totlayer &&
dest->layers[dest_i].type <
type) {
1252 if (dest_i ==
dest->totlayer) {
1257 if (
dest->layers[dest_i].type ==
type) {
1261 for (j = 0; j <
count; j++) {
1262 MVert *mv_src = &((
MVert *)src_data)[src_indices[j]];
1264 #ifdef USE_WELD_NORMALS
1265 short *mv_src_no = mv_src->no;
1266 no[0] += mv_src_no[0];
1267 no[1] += mv_src_no[1];
1268 no[2] += mv_src_no[2];
1271 flag |= mv_src->
flag;
1275 for (j = 0; j <
count; j++) {
1276 MEdge *me_src = &((
MEdge *)src_data)[src_indices[j]];
1277 crease += me_src->
crease;
1279 flag |= me_src->
flag;
1288 void *dst_data =
dest->layers[dest_i].data;
1290 for (j = 0; j <
count; j++) {
1307 float fac = 1.0f /
count;
1309 for (dest_i = 0; dest_i <
dest->totlayer; dest_i++) {
1319 #ifdef USE_WELD_NORMALS
1321 short *mv_no =
mv->no;
1322 mv_no[0] = (short)no[0];
1323 mv_no[1] = (short)no[1];
1324 mv_no[2] = (short)no[2];
1327 mv->flag = (char)flag;
1328 mv->bweight = (char)bweight;
1337 me->
crease = (char)crease;
1346 void *dst_data = layer_dst->
data;
1361 const int removed_vertex_count)
1373 const int result_nverts = totvert - weld_mesh.
vert_kill_len;
1374 const int result_nedges = totedge - weld_mesh.
edge_kill_len;
1375 const int result_nloops = totloop - weld_mesh.
loop_kill_len;
1379 &
mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
1388 for (
int i = 0; i < totvert; i++) {
1389 int source_index = i;
1392 vert_final[i] = dest_index +
count;
1398 dest_index +=
count;
1410 vert_final[i] = dest_index;
1424 for (
int i = 0; i < totedge; i++) {
1425 const int source_index = i;
1428 edge_final[i] = dest_index +
count;
1435 dest_index +=
count;
1436 for (;
count--; me++) {
1437 me->
v1 = vert_final[me->
v1];
1438 me->
v2 = vert_final[me->
v2];
1452 me->
v1 = vert_final[wegrp->
v1];
1453 me->
v2 = vert_final[wegrp->
v2];
1458 edge_final[i] = dest_index;
1472 for (
const int i : mpoly.index_range()) {
1473 const MPoly &mp = mpoly[i];
1474 const int loop_start = loop_cur;
1475 const int poly_ctx = weld_mesh.
poly_map[i];
1479 loop_cur += mp_loop_len;
1480 for (; mp_loop_len--; r_ml++) {
1481 r_ml->
v = vert_final[r_ml->
v];
1482 r_ml->
e = edge_final[r_ml->
e];
1499 int v = vert_final[iter.
v];
1500 int e = edge_final[iter.
e];
1514 r_mp->
totloop = loop_cur - loop_start;
1520 for (
const int i : weld_mesh.
wpoly.index_range().take_back(weld_mesh.
wpoly_new_len)) {
1522 const int loop_start = loop_cur;
1534 int v = vert_final[iter.
v];
1535 int e = edge_final[iter.
e];
1547 r_mp->
totloop = loop_cur - loop_start;
1566 const float merge_distance)
1570 KDTree_3d *
tree = BLI_kdtree_3d_new(selection.
size());
1572 for (
const int i : selection) {
1576 BLI_kdtree_3d_balance(
tree);
1577 const int vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
1578 tree, merge_distance,
false, vert_dest_map.
data());
1579 BLI_kdtree_3d_free(
tree);
1581 if (vert_kill_len == 0) {
1582 return std::nullopt;
1595 const float merge_distance,
1596 const bool only_loose_edges)
1601 int vert_kill_len = 0;
1609 for (
const int i :
verts.index_range()) {
1614 const float merge_dist_sq =
square_f(merge_distance);
1619 for (
const int i : edges.index_range()) {
1620 int v1 = edges[i].v1;
1621 int v2 = edges[i].v2;
1623 if (only_loose_edges && (edges[i].flag &
ME_LOOSEEDGE) == 0) {
1626 while (
v1 != vert_dest_map[
v1]) {
1627 v1 = vert_dest_map[
v1];
1629 while (
v2 != vert_dest_map[
v2]) {
1630 v2 = vert_dest_map[
v2];
1635 if (!selection.
is_empty() && (!selection[
v1] || !selection[
v2])) {
1647 if (dist_sq <= merge_dist_sq) {
1653 vert_dest_map[
v2] =
v1;
1658 if (vert_kill_len == 0) {
1659 return std::nullopt;
1663 if (i == vert_dest_map[i]) {
1669 v = vert_dest_map[
v];
1671 vert_dest_map[
v] =
v;
1672 vert_dest_map[i] =
v;
CustomData interface, see also DNA_customdata_types.h.
void CustomData_copy_layer_type_data(const struct CustomData *source, struct CustomData *destination, int type, int source_index, int destination_index, int count)
bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
void CustomData_data_add(int type, void *data1, const void *data2)
void CustomData_interp(const struct CustomData *source, struct CustomData *dest, const int *src_indices, const float *weights, const float *sub_weights, int count, int dest_index)
void CustomData_data_multiply(int type, void *data, float fac)
int CustomData_sizeof(int type)
bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
void CustomData_copy_data(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count)
struct Mesh * BKE_mesh_new_nomain_from_template(const struct Mesh *me_src, int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
A KD-tree for nearest neighbor search.
MINLINE float square_f(float a)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void range_vn_i(int *array_tar, int size, int start)
MINLINE void add_v3_v3(float r[3], const float a[3])
#define POINTER_OFFSET(v, ofs)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
void fill(const T &value) const
void reinitialize(const int64_t new_size)
constexpr IndexRange slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr void fill(const T &value)
constexpr IndexRange index_range() const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void append(const T &value)
void reserve(const int64_t min_capacity)
std::optional< Mesh * > mesh_merge_by_distance_connected(const Mesh &mesh, Span< bool > selection, float merge_distance, bool only_loose_edges)
static Vector< WeldVert > weld_vert_ctx_alloc_and_setup(Span< int > vert_dest_map, const int vert_kill_len)
static void weld_poly_loop_ctx_alloc(Span< MPoly > mpoly, Span< MLoop > mloop, Span< int > vert_dest_map, Span< int > edge_dest_map, WeldMesh *r_weld_mesh)
static void weld_edge_groups_setup(const int medge_len, const int edge_kill_len, MutableSpan< WeldEdge > wedge, Span< int > wedge_map, MutableSpan< int > r_edge_groups_map, Array< int > &r_edge_groups_buffer, Array< WeldGroupEdge > &r_edge_groups)
static void weld_mesh_context_create(const Mesh &mesh, MutableSpan< int > vert_dest_map, const int vert_kill_len, WeldMesh *r_weld_mesh)
static void weld_poly_loop_ctx_setup(Span< MLoop > mloop, const int mvert_len, Span< int > vert_dest_map, const int remain_edge_ctx_len, MutableSpan< WeldGroup > r_vlinks, WeldMesh *r_weld_mesh)
std::optional< Mesh * > mesh_merge_by_distance_all(const Mesh &mesh, IndexMask selection, float merge_distance)
static void weld_edge_ctx_setup(MutableSpan< WeldGroup > r_vlinks, MutableSpan< int > r_edge_dest_map, MutableSpan< WeldEdge > r_wedge, int *r_edge_kiil_len)
static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter)
static void weld_vert_groups_setup(Span< WeldVert > wvert, Span< int > vert_dest_map, MutableSpan< int > r_vert_groups_map, Array< int > &r_vert_groups_buffer, Array< WeldGroup > &r_vert_groups)
static Vector< WeldEdge > weld_edge_ctx_alloc(Span< MEdge > medge, Span< int > vert_dest_map, MutableSpan< int > r_edge_dest_map, MutableSpan< int > r_edge_ctx_map)
static Mesh * create_merged_mesh(const Mesh &mesh, MutableSpan< int > vert_dest_map, const int removed_vertex_count)
static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter &iter, const WeldPoly &wp, Span< WeldLoop > wloop, Span< MLoop > mloop, Span< int > loop_map, int *group_buffer)
static void weld_poly_split_recursive(Span< int > vert_dest_map, int ctx_verts_len, WeldPoly *r_wp, WeldMesh *r_weld_mesh, int *r_poly_kill, int *r_loop_kill)
static void customdata_weld(const CustomData *source, CustomData *dest, const int *src_indices, int count, int dest_index)
Array< WeldGroup > vert_groups
Array< WeldGroupEdge > edge_groups
Array< int > vert_groups_buffer
Array< int > edge_groups_buffer
Array< int > edge_groups_map